Press n or j to go to the next uncovered block, b, p or k for the previous block.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 | 41x 41x 41x 41x 41x 41x 12x 12x 12x 12x 12x 11x 10x 10x 10x 10x 10x 15x 14x 14x 19x 14x 14x 19x 19x 4x 14x 6x 14x 2x 14x 13x 1x 1x 1x | import { CollectionStore } from '../types'; import { EMPTY, Observable, Subject, from } from 'rxjs'; import { Logger } from 'ts-log'; import { PouchDbStore } from './PouchDbStore'; import { observeAll } from '../util'; import { sanitizePouchDbDoc } from './util'; import { v4 } from 'uuid'; export type ComputePouchDbDocId<T> = (doc: T) => string; export interface PouchDbCollectionStoreProps<T> { dbName: string; computeDocId?: ComputePouchDbDocId<T>; } /** PouchDB database that implements CollectionStore. Supports sorting by custom document _id */ export class PouchDbCollectionStore<T extends {}> extends PouchDbStore<T> implements CollectionStore<T> { readonly #computeDocId: ComputePouchDbDocId<T>; readonly #updates$ = new Subject<T[]>(); observeAll: CollectionStore<T>['observeAll']; /** * @param props store properties * @param props.dbName PouchDB database name * @param props.computeDocId used for document sort order * @param logger will silently swallow the errors if not set */ constructor({ dbName, computeDocId }: PouchDbCollectionStoreProps<T>, logger: Logger) { // Using a db per collection super(dbName, logger); this.observeAll = observeAll(this, this.#updates$); this.#computeDocId = computeDocId ?? (() => v4()); } getAll(): Observable<T[]> { if (this.destroyed) return EMPTY; return new Observable((observer) => { this.fetchAllDocs({ include_docs: true }) .then((result) => { const docs = result.map(({ doc }) => sanitizePouchDbDoc(doc!)); if (docs.length > 0) observer.next(docs); observer.complete(); }) .catch(observer.complete.bind(observer)); }); } setAll(docs: T[]): Observable<void> { if (this.destroyed) return EMPTY; return from( (this.idle = this.idle.then(async (): Promise<void> => { try { const newDocsWithId = docs.map((doc) => ({ ...this.toPouchDbDoc(doc), _id: this.#computeDocId(doc) })); const existingDocs = await this.fetchAllDocs(); const newDocsWithRev = newDocsWithId.map((newDoc): T & { _id: string; _rev?: string } => { const existingDoc = existingDocs.find((doc) => doc.id === newDoc._id); if (!existingDoc) return newDoc; return { ...newDoc, _rev: existingDoc.value.rev }; }); const docsToDelete = existingDocs.filter( (existingDoc) => !newDocsWithId.some((newDoc) => newDoc._id === existingDoc.id) ); await this.db.bulkDocs( docsToDelete.map( ({ id, value: { rev } }) => ({ _deleted: true, _id: id, _rev: rev } as unknown as T) ) ); await this.db.bulkDocs(newDocsWithRev); this.#updates$.next(docs); } catch (error) { this.logger.error(`PouchDbCollectionStore(${this.dbName}): failed to setAll`, docs, error); } })) ); } destroy(): Observable<void> { this.#updates$.complete(); return super.destroy(); } } |