UNPKG

jinaga

Version:

Data management for web and mobile applications.

198 lines 9.09 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.SpecificationRunner = void 0; const storage_1 = require("../storage"); const fn_1 = require("../util/fn"); class SpecificationRunner { constructor(source) { this.source = source; } read(start, specification) { return __awaiter(this, void 0, void 0, function* () { if (start.length !== specification.given.length) { throw new Error(`The number of start references (${start.length}) must match the number of given facts (${specification.given.length}).`); } const references = start.reduce((references, reference, index) => (Object.assign(Object.assign({}, references), { [specification.given[index].name]: { type: reference.type, hash: reference.hash } })), {}); const products = yield this.executeMatchesAndProjection(references, specification.matches, specification.projection); return products; }); } executeMatchesAndProjection(references, matches, projection) { return __awaiter(this, void 0, void 0, function* () { const tuples = yield this.executeMatches(references, matches); const products = (0, fn_1.mapAsync)(tuples, tuple => this.createProduct(tuple, projection)); return products; }); } executeMatches(references, matches) { return __awaiter(this, void 0, void 0, function* () { let results = [references]; for (const match of matches) { results = yield (0, fn_1.flattenAsync)(results, tuple => this.executeMatch(tuple, match)); } return results; }); } executeMatch(references, match) { return __awaiter(this, void 0, void 0, function* () { let results = []; if (match.conditions.length === 0) { throw new Error("A match must have at least one condition."); } const firstCondition = match.conditions[0]; if (firstCondition.type === "path") { const result = yield this.executePathCondition(references, match.unknown, firstCondition); results = result.map(reference => (Object.assign(Object.assign({}, references), { [match.unknown.name]: { type: reference.type, hash: reference.hash } }))); } else { throw new Error("The first condition must be a path condition."); } const remainingConditions = match.conditions.slice(1); for (const condition of remainingConditions) { results = yield this.filterByCondition(references, match.unknown, results, condition); } return results; }); } executePathCondition(references, unknown, pathCondition) { return __awaiter(this, void 0, void 0, function* () { if (!references.hasOwnProperty(pathCondition.labelRight)) { throw new Error(`The label ${pathCondition.labelRight} is not defined.`); } const start = references[pathCondition.labelRight]; let results = [start]; for (const role of pathCondition.rolesRight) { results = yield this.executePredecessorStep(results, role.name, role.predecessorType); } const invertedRoles = invertRoles(pathCondition.rolesLeft, unknown.type); for (const role of invertedRoles) { results = yield this.executeSuccessorStep(results, role.name, role.successorType); } return results; }); } executePredecessorStep(set, name, predecessorType) { return (0, fn_1.flattenAsync)(set, reference => this.source.getPredecessors(reference, name, predecessorType)); } executeSuccessorStep(set, name, successorType) { return (0, fn_1.flattenAsync)(set, reference => this.source.getSuccessors(reference, name, successorType)); } filterByCondition(references, unknown, results, condition) { return __awaiter(this, void 0, void 0, function* () { if (condition.type === "path") { const otherResults = yield this.executePathCondition(references, unknown, condition); return results.filter(result => otherResults.some((0, storage_1.factReferenceEquals)(result[unknown.name]))); } else if (condition.type === "existential") { const matchingReferences = []; for (const result of results) { const matches = yield this.executeMatches(result, condition.matches); const include = condition.exists ? matches.length > 0 : matches.length === 0; if (include) { matchingReferences.push(result); } } return matchingReferences; } else { const _exhaustiveCheck = condition; throw new Error(`Unknown condition type: ${_exhaustiveCheck.type}`); } }); } createProduct(tuple, projection) { return __awaiter(this, void 0, void 0, function* () { if (projection.type === "composite") { let result = {}; for (const component of projection.components) { result = Object.assign(Object.assign({}, result), { [component.name]: yield this.createComponent(tuple, component) }); } return { tuple, result }; } else { const result = yield this.createSingularProduct(tuple, projection); return { tuple, result }; } }); } createComponent(tuple, component) { return __awaiter(this, void 0, void 0, function* () { if (component.type === "specification") { return yield this.executeMatchesAndProjection(tuple, component.matches, component.projection); } else { return yield this.createSingularProduct(tuple, component); } }); } createSingularProduct(tuple, projection) { return __awaiter(this, void 0, void 0, function* () { if (projection.type === "fact") { if (!tuple.hasOwnProperty(projection.label)) { throw new Error(`The label ${projection.label} is not defined.`); } const reference = tuple[projection.label]; return yield this.source.hydrate(reference); } else if (projection.type === "field") { if (!tuple.hasOwnProperty(projection.label)) { throw new Error(`The label ${projection.label} is not defined.`); } const reference = tuple[projection.label]; const fact = yield this.source.findFact(reference); if (fact === null) { throw new Error(`The fact ${reference} is not defined.`); } const value = fact.fields[projection.field]; return value; } else if (projection.type === "hash") { if (!tuple.hasOwnProperty(projection.label)) { throw new Error(`The label ${projection.label} is not defined.`); } const reference = tuple[projection.label]; return reference.hash; } else { const _exhaustiveCheck = projection; throw new Error(`Unexpected child projection type: ${_exhaustiveCheck}`); } }); } } exports.SpecificationRunner = SpecificationRunner; function invertRoles(roles, type) { const results = []; for (const role of roles) { results.push({ name: role.name, successorType: type }); type = role.predecessorType; } return results.reverse(); } //# sourceMappingURL=specification-runner.js.map