UNPKG

neo4-js

Version:

Neo4j graphdb object graph mapper for javascript

274 lines (273 loc) 10.4 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 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) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); const lodash_1 = require("lodash"); const uuid = require("uuid"); const index_1 = require("./index"); const utils_1 = require("./utils"); function createModelInstance(model, props) { let instance; // @ts-ignore if (model.modelInstanceClass) { // @ts-ignore instance = new model.modelInstanceClass(props); } else { instance = new index_1.ModelInstance(props); } // @ts-ignore model.relations.forEach(r => (instance = r.addFunctionsToInstance(instance))); return instance; } exports.createModelInstance = createModelInstance; function createFakeModelInstance(model, charGenerator) { let instance; // @ts-ignore if (model.modelInstanceClass) { // @ts-ignore instance = new model.modelInstanceClass({}); } else { instance = new index_1.ModelInstance({ guid: null }); } // @ts-ignore model.relations.forEach(r => (instance = r.addFunctionsToInstance(instance, charGenerator))); return instance; } exports.createFakeModelInstance = createFakeModelInstance; const compareByGuid = (chainItem) => (a, b) => a[chainItem.variable].guid === b[chainItem.variable].guid; function addChildValues(parents, all, node) { if (!node) return parents; return parents.map(parent => { const children = addChildValues(lodash_1.uniqWith(all.filter(i => i[node.prev.variable].guid === parent.props.guid), compareByGuid(node)).map(i => { if (i[node.variable]) { // @ts-ignore const instance = node.model.afterFind(createModelInstance(node.model, i[node.variable])); if (i[node.relationVariable] && Object.keys(i[node.relationVariable]).length > 0) { instance.relationProps = i[node.relationVariable]; } return instance; } return null; }), all, node.next); parent[node.propertyName] = node.hasOne ? children.length > 0 ? children[0] : null : children; return parent; }); } class IncludesQuery { constructor(chainItem, charGenerator) { this.chainItem = chainItem; this.charGenerator = charGenerator; } include(fn) { const { chainItem } = this; // @ts-ignore chainItem.next = fn(chainItem.fakeInstance); chainItem.next.prev = chainItem; chainItem.next.first = chainItem.first; return new IncludesQuery(chainItem.next, this.charGenerator); } run() { let match = "MATCH "; let result = []; let params = {}; let chainItem = this.chainItem.first; while (chainItem) { if (chainItem.first === chainItem) { match += chainItem.match; } else { match += ` OPTIONAL MATCH (${chainItem.prev.variable})${chainItem.match}`; } result = [...result, ...chainItem.result]; params = Object.assign({}, params, chainItem.flatProps); chainItem = chainItem.next; } chainItem = this.chainItem.first; const query = match + " RETURN " + result.join(", "); return index_1.default.run(query, params).then(result => { // @ts-ignore const instances = addChildValues(lodash_1.uniqWith(result, compareByGuid(chainItem)).map(i => createModelInstance(chainItem.model, i[chainItem.variable])), result, chainItem.next); return chainItem.first.firstOne ? instances.length > 0 ? instances[0] : null : instances; }); } } exports.IncludesQuery = IncludesQuery; class Model { constructor(label) { this.label = label; this.relations = []; } beforeCreate(props) { return props; } afterCreate(instance) { return instance; } beforeFind(props) { return props; } afterFind(instance) { return instance; } beforeUpdate(props, newProps) { return { props, newProps }; } afterUpdate(instance) { return instance; } create(props) { return __awaiter(this, void 0, void 0, function* () { let defaultProps = lodash_1.mapValues(this.modelInstanceClass ? this.modelInstanceClass.prototype._defaultProps : {}, prop => (typeof prop === "function" ? prop() : prop)); let p = this.beforeCreate(Object.assign({ guid: uuid.v4() }, defaultProps, props)); p = Object.assign({}, p); const result = yield index_1.default.run(` CREATE (n:${this.label} {p}) RETURN n `, { p }); if (!result || result.length !== 1) { throw new Error(`Create didn't work, cmd: "CREATE (n:${this.label} {p}) RETURN n" with params: ${JSON.stringify({ p })}`); } return this.afterCreate(createModelInstance(this, result[0].n)); }); } findByGuidAndInclude(guid) { const charGenerator = new utils_1.CharGenerator(); const variable = charGenerator.next(); const { where, flatProps } = utils_1.prepareWhere({ guid }, variable, charGenerator); // @ts-ignore const chainItem = { model: this, fakeInstance: createFakeModelInstance(this, charGenerator), match: `(${variable}:${this.label}) ${where}`, flatProps, result: [variable], variable, firstOne: true, }; chainItem.first = chainItem; return new IncludesQuery(chainItem, charGenerator); } findByGuid(guid) { return __awaiter(this, void 0, void 0, function* () { const result = yield index_1.default.run(` MATCH (n:${this.label} {guid:{guid}}) RETURN n `, { guid }); if (!result || result.length > 1) { throw new Error(`Match didn't work, cmd: "MATCH (n:${this.label} {guid:{guid}}) RETURN n" with params: ${JSON.stringify({ guid, })}`); } if (result.length === 0) { return null; } return createModelInstance(this, result[0].n); }); } delete(props, detach = false) { return __awaiter(this, void 0, void 0, function* () { const { where, flatProps } = utils_1.prepareWhere(props, "n"); const result = yield index_1.default.run(` MATCH (n:${this.label}) ${where} ${detach ? " DETACH " : ""} DELETE n `, flatProps); return result._stats.nodesDeleted; }); } findAndInclude(props) { const charGenerator = new utils_1.CharGenerator(); const variable = charGenerator.next(); const { where, flatProps } = utils_1.prepareWhere(this.beforeFind(props), variable, charGenerator); // @ts-ignore const chainItem = { model: this, fakeInstance: createFakeModelInstance(this, charGenerator), match: `(${variable}:${this.label}) ${where}`, flatProps, result: [variable], variable, }; chainItem.first = chainItem; return new IncludesQuery(chainItem, charGenerator); } find(props) { return __awaiter(this, void 0, void 0, function* () { const p = this.beforeFind(props); const { where, flatProps } = utils_1.prepareWhere(p, "n"); const result = yield index_1.default.run(` MATCH (n:${this.label}) ${where} RETURN n `, flatProps); return result.map(p => this.afterFind(createModelInstance(this, p.n))); }); } findOneAndInclude(props) { const charGenerator = new utils_1.CharGenerator(); const variable = charGenerator.next(); const { where, flatProps } = utils_1.prepareWhere(this.beforeFind(props), variable, charGenerator); // @ts-ignore const chainItem = { model: this, fakeInstance: createFakeModelInstance(this, charGenerator), match: `(${variable}:${this.label}) ${where}`, flatProps, result: [variable], variable, firstOne: true, }; chainItem.first = chainItem; return new IncludesQuery(chainItem, charGenerator); } findOne(props) { return __awaiter(this, void 0, void 0, function* () { const p = this.beforeFind(props); const { where, flatProps } = utils_1.prepareWhere(p, "n"); const result = yield index_1.default.run(` MATCH (n:${this.label}) ${where} RETURN n `, flatProps); if (result.length) { return this.afterFind(createModelInstance(this, result[0].n)); } return Promise.resolve(null); }); } update(props, newProps) { return __awaiter(this, void 0, void 0, function* () { const params = this.beforeUpdate(props, newProps); const { where, flatProps } = utils_1.prepareWhere(params.props, "n"); const { str: setPropsStr, newProps: _newProps } = utils_1.prepareSet(params.newProps, "n"); let result = yield index_1.default.run(` MATCH (n:${this.label}) ${where} SET ${setPropsStr} RETURN n `, Object.assign({}, flatProps, _newProps)); return result.map(p => this.afterUpdate(createModelInstance(this, p.n))); }); } } exports.Model = Model;