UNPKG

jinaga

Version:

Data management for web and mobile applications.

225 lines 11.9 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.IndexedDBStore = exports.getPredecessors = void 0; const hydrate_1 = require("../fact/hydrate"); const sorter_1 = require("../fact/sorter"); const specification_runner_1 = require("../specification/specification-runner"); const fn_1 = require("../util/fn"); const driver_1 = require("./driver"); function getPredecessors(fact, role) { if (!fact) { return []; } const predecessors = fact.predecessors[role]; if (predecessors) { if (Array.isArray(predecessors)) { return predecessors; } else { return [predecessors]; } } else { return []; } } exports.getPredecessors = getPredecessors; function findAllAncestors(facts) { const sorter = new sorter_1.TopologicalSorter(); const ancestorSets = sorter.sort(facts, (predecessors, fact) => ({ key: (0, driver_1.factKey)(fact), ancestors: (0, fn_1.flatten)(predecessors, p => p.ancestors) .filter(fn_1.distinct) .concat([(0, driver_1.factKey)(fact)]) })); if (!sorter.finished()) { throw new Error(`Not all ancestors have been provided: ${JSON.stringify(facts, null, 2)}`); } return ancestorSets.reduce((obj, ancestorSet) => (Object.assign(Object.assign({}, obj), { [ancestorSet.key]: ancestorSet.ancestors })), {}); } function saveFact(factObjectStore, ancestorObjectStore, edgeObjectStore, ancestorMap, fact) { return __awaiter(this, void 0, void 0, function* () { const key = (0, driver_1.factKey)(fact); const edges = (0, fn_1.flatten)(Object.getOwnPropertyNames(fact.predecessors), role => getPredecessors(fact, role) .map(p => ({ successor: key, predecessor: (0, driver_1.factKey)(p), role }))); if (edges.length) { const edgeCount = yield ((0, driver_1.execRequest)(edgeObjectStore.index('all').count(key))); if (edgeCount !== edges.length) { yield Promise.all(edges.map(edge => (0, driver_1.execRequest)(edgeObjectStore.add(edge)))); } } const ancestorCount = yield (0, driver_1.execRequest)(ancestorObjectStore.count(key)); if (ancestorCount === 0) { yield (0, driver_1.execRequest)(ancestorObjectStore.add(ancestorMap[key], key)); } const factCount = yield (0, driver_1.execRequest)(factObjectStore.count(key)); if (factCount === 0) { yield (0, driver_1.execRequest)(factObjectStore.add(fact, key)); return fact; } return null; }); } class IndexedDBStore { constructor(indexName) { this.indexName = indexName; } close() { return Promise.resolve(); } save(envelopes) { const ancestorMap = findAllAncestors(envelopes.map(e => e.fact)); return (0, driver_1.withDatabase)(this.indexName, db => { return (0, driver_1.withTransaction)(db, ['fact', 'ancestor', 'edge'], 'readwrite', (tx) => __awaiter(this, void 0, void 0, function* () { const factObjectStore = tx.objectStore('fact'); const ancestorObjectStore = tx.objectStore('ancestor'); const edgeObjectStore = tx.objectStore('edge'); const saved = yield Promise.all(envelopes.map(envelope => saveFact(factObjectStore, ancestorObjectStore, edgeObjectStore, ancestorMap, envelope.fact))); return saved .filter(fact => fact) .map(fact => ({ signatures: [], fact })); })); }); } read(start, specification) { return (0, driver_1.withDatabase)(this.indexName, db => { return (0, driver_1.withTransaction)(db, ['edge', 'fact', 'ancestor'], 'readonly', tx => { const edgeObjectStore = tx.objectStore('edge'); const predecessorIndex = edgeObjectStore.index('predecessor'); const successorIndex = edgeObjectStore.index('successor'); const factObjectStore = tx.objectStore('fact'); const ancestorObjectStore = tx.objectStore('ancestor'); const runner = new specification_runner_1.SpecificationRunner({ getPredecessors(reference, name, predecessorType) { return __awaiter(this, void 0, void 0, function* () { const edges = yield (0, driver_1.execRequest)(successorIndex.getAll([(0, driver_1.factKey)(reference), name])); return edges .map(edge => (0, driver_1.keyToReference)(edge.predecessor)) .filter(reference => reference.type === predecessorType); }); }, getSuccessors(reference, name, successorType) { return __awaiter(this, void 0, void 0, function* () { const edges = yield (0, driver_1.execRequest)(predecessorIndex.getAll([(0, driver_1.factKey)(reference), name])); return edges .map(edge => (0, driver_1.keyToReference)(edge.successor)) .filter(reference => reference.type === successorType); }); }, findFact(reference) { return (0, driver_1.execRequest)(factObjectStore.get((0, driver_1.factKey)(reference))); }, hydrate(reference) { return __awaiter(this, void 0, void 0, function* () { const allAncestors = yield (0, driver_1.execRequest)(ancestorObjectStore.get((0, driver_1.factKey)(reference))); const distinctAncestors = allAncestors.filter(fn_1.distinct); const factRecords = yield Promise.all(distinctAncestors.map(key => (0, driver_1.execRequest)(factObjectStore.get(key)))); const facts = (0, hydrate_1.hydrateFromTree)([reference], factRecords); if (facts.length === 0) { return undefined; } if (facts.length > 1) { throw new Error(`The fact ${reference} is defined more than once.`); } return facts[0]; }); } }); return runner.read(start, specification); }); }); } feed(feed, start, bookmark) { throw new Error('Method not implemented.'); } whichExist(references) { return (0, driver_1.withDatabase)(this.indexName, db => { return (0, driver_1.withTransaction)(db, ['fact'], 'readonly', (tx) => __awaiter(this, void 0, void 0, function* () { const factObjectStore = tx.objectStore('fact'); const factKeys = references.map(driver_1.factKey); const factRecords = yield Promise.all(factKeys.map(key => (0, driver_1.execRequest)(factObjectStore.get(key)))); return factRecords .filter(fact => !!fact) .map(fact => (0, driver_1.keyToReference)((0, driver_1.factKey)(fact))); })); }); } load(references) { return (0, driver_1.withDatabase)(this.indexName, db => { return (0, driver_1.withTransaction)(db, ['fact', 'ancestor'], 'readonly', (tx) => __awaiter(this, void 0, void 0, function* () { const factObjectStore = tx.objectStore('fact'); const ancestorObjectStore = tx.objectStore('ancestor'); const allAncestors = yield (0, fn_1.flattenAsync)(references, reference => (0, driver_1.execRequest)(ancestorObjectStore.get((0, driver_1.factKey)(reference)))); const distinctAncestors = allAncestors .filter(fn_1.distinct); const factRecords = yield Promise.all(distinctAncestors.map((key) => __awaiter(this, void 0, void 0, function* () { return ({ fact: yield (0, driver_1.execRequest)(factObjectStore.get(key)), signatures: [] }); }))); return factRecords; })); }); } purge(purgeConditions) { // Not yet implemented return Promise.resolve(0); } purgeDescendants(purgeRoot, triggers) { // Not yet implemented return Promise.resolve(0); } loadBookmark(feed) { return (0, driver_1.withDatabase)(this.indexName, db => { return (0, driver_1.withTransaction)(db, ['bookmark'], 'readonly', (tx) => __awaiter(this, void 0, void 0, function* () { const bookmarkObjectStore = tx.objectStore('bookmark'); const bookmark = yield (0, driver_1.execRequest)(bookmarkObjectStore.get(feed)); return bookmark || ''; })); }); } saveBookmark(feed, bookmark) { return (0, driver_1.withDatabase)(this.indexName, db => { return (0, driver_1.withTransaction)(db, ['bookmark'], 'readwrite', (tx) => __awaiter(this, void 0, void 0, function* () { const bookmarkObjectStore = tx.objectStore('bookmark'); yield (0, driver_1.execRequest)(bookmarkObjectStore.put(bookmark, feed)); })); }); } getMruDate(specificationHash) { return (0, driver_1.withDatabase)(this.indexName, db => { return (0, driver_1.withTransaction)(db, ['specification'], 'readonly', (tx) => __awaiter(this, void 0, void 0, function* () { const specificationObjectStore = tx.objectStore('specification'); const mruDate = yield (0, driver_1.execRequest)(specificationObjectStore.get(specificationHash)); return mruDate || null; })); }); } setMruDate(specificationHash, mruDate) { return (0, driver_1.withDatabase)(this.indexName, db => { return (0, driver_1.withTransaction)(db, ['specification'], 'readwrite', (tx) => __awaiter(this, void 0, void 0, function* () { const specificationObjectStore = tx.objectStore('specification'); yield (0, driver_1.execRequest)(specificationObjectStore.put(mruDate, specificationHash)); // Remove specifications older than 30 days. const oldMruDate = new Date(mruDate.getTime() - 1000 * 60 * 60 * 24 * 30); const cursor = yield (0, driver_1.execRequest)(specificationObjectStore.openCursor(IDBKeyRange.upperBound(oldMruDate))); while (cursor) { yield (0, driver_1.execRequest)(cursor.delete()); yield cursor.continue(); } })); }); } } exports.IndexedDBStore = IndexedDBStore; //# sourceMappingURL=indexeddb-store.js.map