UNPKG

tabel

Version:

A simple orm for PostgreSQL which works with simple javascript objects and arrays

186 lines (151 loc) 5.32 kB
const {assign, isString} = require('lodash'); const Relation = require('./Relation'); class MorphTo extends Relation { constructor(ownerTable, toTables, typeField, foreignKey) { super(ownerTable); assign(this, {fromTable: ownerTable.fork(), toTables, typeField, foreignKey}); } initRelation(fromModels=[]) { return fromModels.map((m) => assign(m, {[this.relationName]: null})); } getRelated(...args) { if (args.length === 0) { if (this.activeModel !== null) { return this.getRelated([this.activeModel]) .then((results) => { return results .filter((r) => r.type === this.activeModel[this.typeField]) .map(({models}) => models); }) .then(([relatedModel]) => relatedModel); } else { return Promise.resolve(null); } } const [fromModels] = args; const {toTables, typeField, foreignKey} = this; if (fromModels.length === 0) { return Promise.resolve([]); } else { return Promise.all(toTables.map((table) => { const fromKeys = fromModels .filter((m) => m[typeField] === table.tableName()) .map((m) => m[foreignKey]) ; return this.constraints.apply(table.fork()) .whereIn(table.key(), fromKeys).all() .then((models) => ({type: table.tableName(), models})); })); } } matchModels(fromModels=[], relatedModels=[]) { const {relationName, toTables, typeField, foreignKey} = this; const tableKeyDict = relatedModels.reduce((dict, {type, models}) => { const table = toTables.filter((t) => t.tableName() === type)[0]; return assign(dict, { [type]: models.reduce((keyDict, model) => { return assign(keyDict, {[model[table.key()]]: model}); }, {}) }); }, {}); return fromModels.map((m) => { if (m[typeField] in tableKeyDict && m[foreignKey] in tableKeyDict[m[typeField]]) { return assign(m, { [relationName]: tableKeyDict[m[typeField]][m[foreignKey]] }); } else { return assign(m, {[relationName]: null}); } }); } associate(...args) { if (args.length < 2) { throw new Error('bad method call'); } if (args.length === 2) { return this.associate(this.activeModel, ...args); } const [fromModel, relatedModel, tableName] = args; const table = this.toTables.filter((t) => t.tableName() === tableName)[0]; return this.fromTable.fork().whereKey(fromModel).update({ [this.typeField]: tableName, [this.foreignKey]: relatedModel[table.key()] }); } dissociate(...args) { if (args.length === 0) { return this.dissociate(this.activeModel); } const [fromModel] = args; return this.fromTable.fork().whereKey(fromModel).update({ [this.typeField]: null, [this.foreignKey]: null }); } update(...args) { if (args.length === 0) { throw new Error('bad method call'); } if (args.length === 1) { return this.update(this.activeModel, ...args); } const [fromModel, values] = args; const table = this.toTables.filter((t) => t.tableName() === fromModel[this.typeField])[0]; return this.constraints.apply(table.fork()) .whereKey(fromModel[this.foreignKey]) .update(values) ; } del(...args) { if (args.length === 0) { return this.del(this.activeModel); } const [fromModel] = args; const table = this.toTables.filter((t) => t.tableName() === fromModel[this.typeField])[0]; return this.constraints.apply(table.fork()) .whereKey(fromModel[this.foreignKey]) .del() ; } join(tableName, joiner=(() => {}), label=null) { if (this.toTables.map((t) => t.tableName()).indexOf(tableName) === -1) { return this.ownerTable; } label = this.jointLabel(`${tableName}${isString(label) ? `.${label}` : ''}`, {}); const toTable = this.toTables.filter((t) => t.tableName() === tableName)[0]; const {fromTable, typeField, foreignKey} = this; if (this.ownerTable.scopeTrack.hasJoint(label)) { return this.ownerTable; } else { return this.ownerTable.joint((q) => { q.join(toTable.tableName(), (j) => { j.on(fromTable.c(typeField), '=', toTable.raw('?', [toTable.tableName()])) .on(fromTable.c(foreignKey), '=', toTable.keyCol()); joiner(j); }); }); } } leftJoin(tableName, joiner=(() => {}), label=null) { if (this.toTables.map((t) => t.tableName()).indexOf(tableName) === -1) { return this.ownerTable; } label = this.jointLabel(`${tableName}${isString(label) ? `.${label}` : ''}`, { isLeftJoin: true }); const toTable = this.toTables.filter((t) => t.tableName() === tableName)[0]; const {fromTable, typeField, foreignKey} = this; if (this.ownerTable.scopeTrack.hasJoint(label)) { return this.ownerTable; } else { return this.ownerTable.joint((q) => { q.leftJoin(toTable.tableName(), (j) => { j.on(fromTable.c(typeField), '=', toTable.raw('?', [toTable.tableName()])) .on(fromTable.c(foreignKey), '=', toTable.keyCol()); joiner(j); }); }); } } } module.exports = MorphTo;