import { cloneDeep, debounce, memoize, property, wrap } from 'lodash'; import getUri from '../lib/ids'; import { putNewGpx } from './gpx'; import { getFamily, put } from './lib'; export const emptyRte: Rte = { name: undefined, cmt: undefined, desc: undefined, src: undefined, link: undefined, number: 0, type: undefined, extensions: undefined, rtept: undefined, }; export const putNewRte = async (id?: IdRte | IdGpx) => { let finalId = { ...id }; if (!('rte' in finalId)) { const gpxId = await putNewGpx(id); finalId = { ...gpxId, rte: 0 }; } const uri = getUri('rte', finalId); await put( uri, 'rte', (rte) => { return rte; }, emptyRte ); return finalId as IdRte; }; // See https://stackoverflow.com/questions/28787436/debounce-a-function-with-argument export const debounceByParam = ( targetFunc: (params: any) => any, resolver: (params: any) => any, ...debounceParams: any ) => wrap( memoize(() => debounce(targetFunc, ...debounceParams), resolver), (getMemoizedFunc, ...params) => getMemoizedFunc(...params)(...params) ); export const compactRteOrTrkseg = async (params: any) => { const { getDocs } = params; const { docs, rte, trkseg } = await getDocs(params); if (docs.rows.length > 1) { const compactedDocs = docs.rows.map((row: any) => { if (['rte', 'trkseg'].includes(row.doc.type)) { return { ...row.doc, doc: rte || trkseg }; } return { ...row.doc, doc: undefined, _deleted: true }; }); console.log({ caller: 'compactRteOrTrkseg', params, compactedDocs, firstDoc: compactedDocs[0].doc, firstDocWpt: compactedDocs[0].doc.trkpt[0], date: new Date().toISOString(), }); await db.bulkDocs(compactedDocs); } }; export const compactRteOrTrksegDebounced = debounceByParam( compactRteOrTrkseg, property('id'), 60 * 60 * 1000 * (1 + Math.random()) ); export const getRteDocs: ({ id, }: { id: string; }) => Promise<{ docs: any; rte: Rte }> = async (params) => { const { id } = params; const docs = await getFamily(id, { include_docs: true }); let rte: Rte; if (docs.rows.length === 1) { rte = docs.rows[0].doc.doc; } else { rte = cloneDeep(docs.rows[0].doc.doc); if (!rte.rtept) { rte.rtept = []; } docs.rows.slice(1).forEach((row: any) => { rte.rtept.push(row.doc.doc); }); } // console.log({ // caller: 'getRteDocs', // id, // docs, // nbRteptIn: docs.rows[0].doc.doc.rtept?.length, // nbRteptTotal: rte?.rtept?.length, // }); return { docs, rte }; }; export const getRte = async (params: any) => { const { id } = params; const { docs, rte } = await getRteDocs(params); if (docs.rows.length > 1) { console.log({ caller: 'getRte compactRteOrTrksegDebounced required', id, }); compactRteOrTrksegDebounced({ id, getDocs: getRteDocs }); } return rte; }; export const putRte = async (params: any) => { const { id, rte } = params; await put(id, 'rte', (doc) => rte, rte); return rte; }; export const deleteRte = async (params: any) => { const { id } = params; const docs = await getFamily(id, { include_docs: false }); console.log({ caller: 'deleteRte' }, id, docs); const deletedDocs = docs.rows.reverse().map((doc: any) => ({ _deleted: true, _id: doc.id, _rev: doc.value.rev, })); console.log({ caller: 'deleteRte' }, id, docs, deletedDocs); await db.bulkDocs(deletedDocs); return id; };