Reimplementing GPX imports.

This commit is contained in:
Eric van der Vlist 2022-11-14 18:35:04 +01:00
parent a2d0e8cf6a
commit 5fdd63103e
8 changed files with 148 additions and 5 deletions

View File

@ -96,7 +96,6 @@ export const setCenterAtom = atom(null, (get, set, center: geoPoint) => {
// initDb(db);
dispatch({ action: 'initDb' });
dispatch({ action: 'putNewTrk' });
/**
*

View File

@ -5,6 +5,9 @@ import GPX from '../../lib/gpx-parser-builder/src/gpx';
import css from './GpxImport.module.css';
import { IonIcon, IonItem } from '@ionic/react';
import { cloudUpload } from 'ionicons/icons';
import { findStartTime } from '../../lib/gpx';
import dispatch from '../../workers/dispatcher-main';
import { intToGpxId } from '../../lib/ids';
const GpxImport: React.FC<{}> = () => {
const onChangeHandler = (event: any) => {
@ -20,6 +23,11 @@ const GpxImport: React.FC<{}> = () => {
console.log(fileReader.result);
const gpx = GPX.parse(fileReader.result);
console.log(`gpx: ${JSON.stringify(gpx)}`);
const startTime = new Date(findStartTime(gpx)!);
dispatch({
action: 'pruneAndSaveImportedGpx',
params: { id: { gpx: intToGpxId(startTime.valueOf()) }, gpx: gpx },
});
// pushGpx(db, {
// gpx,
// metadata: {

View File

@ -1,4 +1,5 @@
import { putNewGpx } from './gpx';
import { initDb } from '.';
import { existsGpx, putNewGpx } from './gpx';
declare global {
var db: any;
var dbReady: boolean;
@ -60,3 +61,26 @@ describe('The gpx module', () => {
expect(id).toEqual({ gpx: 4320000000000000 });
});
});
describe('The gpx module with a real db', () => {
beforeEach(async () => {
await initDb({});
globalThis.Date.now = () => 0;
});
afterEach(async () => {
await db.destroy();
db = undefined;
globalThis.Date.now = originalDateNow;
});
test("existsGpx returns false if the GPX doesn't exist", async () => {
const exists = await existsGpx({ gpx: 1 });
expect(exists).toBeFalsy();
});
test('existsGpx returns false if the GPX exists', async () => {
const id = { gpx: 1 };
await putNewGpx(id);
const exists = await existsGpx(id);
expect(exists).toBeTruthy();
});
});

View File

@ -1,5 +1,6 @@
import { PureComponent } from 'react';
import getUri, { intToGpxId } from '../lib/ids';
import { put } from './lib';
import { get, put, putAll } from './lib';
const emptyGpx: Gpx = {
$: {
@ -46,3 +47,54 @@ export const putNewGpx = async (
);
return id;
};
export const existsGpx = async (id: IdGpx) => {
const uri = getUri('gpx', id);
try {
await get(uri);
return true;
} catch {
return false;
}
};
const prune = (id: any, object: any, docs: any[]) => {
if (typeof object === 'object') {
for (const key in object) {
if (
key === 'wpt' ||
key === 'rte' ||
key === 'rtept' ||
key === 'trk' ||
key === 'trkseg' ||
key === 'trkpt'
) {
const subObjects = object[key];
for (const index in subObjects) {
const subId = { ...id };
subId[key] = index;
docs.push({
_id: getUri(key, subId),
type: key,
doc: subObjects[index],
});
prune(subId, subObjects[index], docs);
}
object[key] = undefined;
} else prune(id, object[key], docs);
}
}
};
export const pruneAndSaveImportedGpx = async (params: any) => {
const { id, gpx } = params;
let docs: any[] = [{ _id: getUri('gpx', id), type: 'gpx', doc: gpx }];
prune(id, gpx, docs);
console.log(JSON.stringify(docs));
try {
const result = await putAll(docs);
console.log(JSON.stringify(result));
} catch (err) {
console.error(`error: ${err}`);
}
};

View File

@ -38,3 +38,11 @@ export const getFamily = async (key: string, options: any = {}) => {
...options,
});
};
export const get = async (id: string) => {
await db.get(id);
};
export const putAll = async (docs: any[]) => {
return await db.bulkDocs(docs);
};

33
src/lib/gpx.test.ts Normal file
View File

@ -0,0 +1,33 @@
import { assert } from 'console';
import { findStartTime } from './gpx';
describe('findStartTime', () => {
test('to be undefined for a string', () => {
const start = findStartTime('');
expect(start).toBeUndefined();
});
test('to be undefined for an object without time key', () => {
const start = findStartTime({ foo: 'foo', bar: 'bar' });
expect(start).toBeUndefined();
});
test('to be the time value for an object with a time key', () => {
const start = findStartTime({ foo: 'foo', time: 'bar' });
expect(start).toEqual('bar');
});
test('to be the lowest time value for an object with several time keys', () => {
const start = findStartTime({
foo: { time: 'foo' },
time: 'bar',
bar: { time: 'a' },
});
expect(start).toEqual('a');
});
test('to be the lowest time value for an array with several objects with time keys', () => {
const start = findStartTime({
foos: [{ time: 'foo' }, { time: '0' }],
time: 'bar',
bar: { time: 'a' },
});
expect(start).toEqual('0');
});
});

19
src/lib/gpx.ts Normal file
View File

@ -0,0 +1,19 @@
const min = (s1?: string, s2?: string) => {
return s1! < s2! ? s1 : s2;
};
export const findStartTime = (x: any, startTime?: string) => {
if (typeof x === 'object') {
let newStartTime = startTime;
for (const key in x) {
if (key === 'time') {
newStartTime = min(newStartTime, x[key]);
} else {
newStartTime = findStartTime(x[key], newStartTime);
}
}
return newStartTime;
}
else return startTime;
};

View File

@ -1,10 +1,10 @@
import { initDb } from '../db';
import { putNewGpx } from '../db/gpx';
import { putNewGpx, existsGpx, pruneAndSaveImportedGpx } from '../db/gpx';
import { putNewTrk } from '../db/trk';
const self = globalThis as unknown as SharedWorkerGlobalScope;
const actions = { initDb, putNewGpx, putNewTrk };
const actions = { initDb, putNewGpx, putNewTrk, existsGpx, pruneAndSaveImportedGpx };
self.onconnect = function (e) {
var port = e.ports[0];