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 | 41x 41x 41x 41x 41x 24x 24x 24x 24x 24x 18x 18x 18x 3x 3x 3x 35x 41x 14x 14x 68x 68x 26x 42x 16x 14x 14x 14x 14x 14x | import { EMPTY, Observable, from } from 'rxjs'; import { Logger } from 'ts-log'; import { toPouchDbDoc } from './util'; import PouchDB from 'pouchdb'; const FETCH_ALL_PAGE_SIZE = 100; export abstract class PouchDbStore<T extends {}> { destroyed = false; protected idle: Promise<void> = Promise.resolve(); protected readonly logger: Logger; public readonly db: PouchDB.Database<T>; constructor(public dbName: string, logger: Logger) { this.logger = logger; this.db = new PouchDB<T>(dbName, { auto_compaction: true }); } /** * Only used internally and for cleaning up after tests. * If you need to use this for other purposes, consider adding clear() or destroy() to stores interfaces. */ async clearDB(): Promise<void> { const docs = await this.fetchAllDocs(); await this.db.bulkDocs( docs.map( (row) => ({ _deleted: true, _id: row.id, _rev: row.value.rev } as unknown as T) ) ); } /** Might all destroy other stores, if the underlying PouchDb database is shared. */ destroy(): Observable<void> { if (!this.destroyed) { this.destroyed = true; return from(this.db.destroy()); } return EMPTY; } protected toPouchDbDoc(obj: T): T { return toPouchDbDoc(obj) as T; } async #getRev(docId: string) { const existingDoc = await this.db.get(docId).catch(() => void 0); return existingDoc?._rev; } async fetchAllDocs( options?: Omit<Partial<PouchDB.Core.AllDocsWithinRangeOptions>, 'limit'> ): Promise<PouchDB.Core.AllDocsResponse<T>['rows']> { const response = await this.db.allDocs({ ...options, limit: FETCH_ALL_PAGE_SIZE }); if (response && response.rows.length > 0) { return [ ...response.rows, ...(await this.fetchAllDocs({ ...options, skip: 1, startkey: response.rows[response.rows.length - 1].id })) ]; } return response.rows || []; } protected forcePut(docId: string, doc: T) { if (this.destroyed) return EMPTY; const serializableDoc = this.toPouchDbDoc(doc); return from( (this.idle = this.idle .then(async () => { const pouchDbDoc = { _id: docId, _rev: await this.#getRev(docId), ...serializableDoc }; try { await this.db.put(pouchDbDoc, { force: true }); } catch (error) { this.logger.warn(`PouchDbStore(${this.dbName}): failed to forcePut`, pouchDbDoc, error); } }) .catch(() => void 0)) ); } } |