objection
Advanced tools
Comparing version 0.8.1 to 0.8.2
@@ -438,2 +438,6 @@ 'use strict'; | ||
static get objectionModelClass() { | ||
return Model; | ||
} | ||
static fromJson(json, options) { | ||
@@ -535,12 +539,2 @@ const model = new this(); | ||
static getFullIdColumn() { | ||
// Memoize getFullIdColumn but only for this class. The hasOwnProperty check | ||
// will fail for subclasses and the value gets recreated. | ||
if (!this.hasOwnProperty('$$fullIdColumn')) { | ||
defineNonEnumerableProperty(this, '$$fullIdColumn', getFullIdColumn(this)); | ||
} | ||
return this.$$fullIdColumn; | ||
} | ||
static getIdPropertyArray() { | ||
@@ -635,6 +629,2 @@ // Memoize getIdPropertyArray but only for this class. The hasOwnProperty check | ||
static uniqueTag() { | ||
return this.tableName; | ||
} | ||
static bindKnex(knex) { | ||
@@ -648,3 +638,3 @@ const ModelClass = this; | ||
defineNonEnumerableProperty(knex, '$$objection', { | ||
boundModels: Object.create(null) | ||
boundModels: new Map() | ||
}); | ||
@@ -654,4 +644,4 @@ } | ||
// Check if this model class has already been bound to the given knex. | ||
if (knex.$$objection.boundModels[ModelClass.uniqueTag()]) { | ||
return knex.$$objection.boundModels[ModelClass.uniqueTag()]; | ||
if (knex.$$objection.boundModels.has(ModelClass)) { | ||
return knex.$$objection.boundModels.get(ModelClass); | ||
} | ||
@@ -671,3 +661,3 @@ | ||
BoundModelClass.knex(knex); | ||
knex.$$objection.boundModels[ModelClass.uniqueTag()] = BoundModelClass; | ||
knex.$$objection.boundModels.set(ModelClass, BoundModelClass); | ||
@@ -732,3 +722,3 @@ relations = ModelClass.getRelationArray(); | ||
if (!relation) { | ||
throw new Error(`A model class (tableName = ${this.tableName}) doesn't have relation ${name}`); | ||
throw new Error(`A model class ${this.name} doesn't have relation ${name}`); | ||
} | ||
@@ -845,2 +835,3 @@ | ||
Model.defaultEagerOptions = null; | ||
Model.namedFilters = null; | ||
@@ -898,10 +889,2 @@ function setId(model, id) { | ||
function getFullIdColumn(ModelClass) { | ||
if (Array.isArray(ModelClass.idColumn)) { | ||
return ModelClass.idColumn.map(col => `${ModelClass.tableName}.${col}`); | ||
} else { | ||
return `${ModelClass.tableName}.${ModelClass.idColumn}`; | ||
} | ||
} | ||
function getIdPropertyArray(ModelClass) { | ||
@@ -1211,2 +1194,3 @@ return ModelClass.getIdColumnArray().map(col => idColumnToIdProperty(ModelClass, col)); | ||
} | ||
return false; | ||
@@ -1241,10 +1225,10 @@ } | ||
function columnNameToPropertyName(ModelClass, columnName) { | ||
let model = new ModelClass(); | ||
let addedProps = Object.keys(model.$parseDatabaseJson({})); | ||
const model = new ModelClass(); | ||
const addedProps = Object.keys(model.$parseDatabaseJson({})); | ||
let row = {}; | ||
const row = {}; | ||
row[columnName] = null; | ||
let props = Object.keys(model.$parseDatabaseJson(row)); | ||
let propertyName = difference(props, addedProps)[0]; | ||
const props = Object.keys(model.$parseDatabaseJson(row)); | ||
const propertyName = difference(props, addedProps)[0]; | ||
@@ -1255,10 +1239,10 @@ return propertyName || null; | ||
function propertyNameToColumnName(ModelClass, propertyName) { | ||
let model = new ModelClass(); | ||
let addedCols = Object.keys(model.$formatDatabaseJson({})); | ||
const model = new ModelClass(); | ||
const addedCols = Object.keys(model.$formatDatabaseJson({})); | ||
let obj = {}; | ||
const obj = {}; | ||
obj[propertyName] = null; | ||
let cols = Object.keys(model.$formatDatabaseJson(obj)); | ||
let columnName = difference(cols, addedCols)[0]; | ||
const cols = Object.keys(model.$formatDatabaseJson(obj)); | ||
const columnName = difference(cols, addedCols)[0]; | ||
@@ -1269,6 +1253,6 @@ return columnName || null; | ||
function idColumnToIdProperty(ModelClass, idColumn) { | ||
let idProperty = ModelClass.columnNameToPropertyName(idColumn); | ||
const idProperty = ModelClass.columnNameToPropertyName(idColumn); | ||
if (!idProperty) { | ||
throw new Error(ModelClass.tableName + '.$parseDatabaseJson probably changes the value of the id column `' + idColumn + '` which is a no-no.'); | ||
throw new Error(ModelClass.name + '.$parseDatabaseJson probably changes the value of the id column `' + idColumn + '` which is a no-no.'); | ||
} | ||
@@ -1275,0 +1259,0 @@ |
@@ -9,3 +9,2 @@ 'use strict'; | ||
super(node); | ||
this.relation = relation; | ||
@@ -12,0 +11,0 @@ } |
@@ -65,24 +65,27 @@ 'use strict'; | ||
if (rel instanceof HasManyRelation) { | ||
if (rel) { | ||
if (rel instanceof HasManyRelation) { | ||
node.needs.push(new HasManyDependency(parentNode, rel)); | ||
parentNode.isNeededBy.push(new HasManyDependency(node, rel)); | ||
node.needs.push(new HasManyDependency(parentNode, rel)); | ||
parentNode.isNeededBy.push(new HasManyDependency(node, rel)); | ||
} else if (rel instanceof BelongsToOneRelation) { | ||
} else if (rel instanceof BelongsToOneRelation) { | ||
node.isNeededBy.push(new BelongsToOneDependency(parentNode, rel)); | ||
parentNode.needs.push(new BelongsToOneDependency(node, rel)); | ||
node.isNeededBy.push(new BelongsToOneDependency(parentNode, rel)); | ||
parentNode.needs.push(new BelongsToOneDependency(node, rel)); | ||
} else if (rel instanceof ManyToManyRelation) { | ||
} else if (rel instanceof ManyToManyRelation) { | ||
// ManyToManyRelations create no dependencies since we can create the | ||
// join table rows after everything else has been inserted. | ||
parentNode.manyToManyConnections.push(new ManyToManyConnection(node, rel)); | ||
// ManyToManyRelations create no dependencies since we can create the | ||
// join table rows after everything else has been inserted. | ||
parentNode.manyToManyConnections.push(new ManyToManyConnection(node, rel)); | ||
} | ||
} | ||
this.buildForRelations(modelClass, model, node, allowedRelations); | ||
this.buildForRelations(modelClass, node, allowedRelations); | ||
} | ||
buildForRelations(modelClass, model, node, allowedRelations) { | ||
buildForRelations(modelClass, node, allowedRelations) { | ||
const model = node.model; | ||
const relations = modelClass.getRelationArray(); | ||
@@ -92,4 +95,3 @@ | ||
const rel = relations[i]; | ||
const relName = rel.name; | ||
const relModels = model[relName]; | ||
const relModels = model[rel.name]; | ||
@@ -99,3 +101,3 @@ let nextAllowed = null; | ||
if (relModels && allowedRelations instanceof RelationExpression) { | ||
nextAllowed = allowedRelations.childExpression(relName); | ||
nextAllowed = allowedRelations.childExpression(rel.name); | ||
@@ -134,3 +136,3 @@ if (!nextAllowed) { | ||
solveReferences() { | ||
let refMap = Object.create(null); | ||
const refMap = Object.create(null); | ||
@@ -146,3 +148,3 @@ // First merge all reference nodes into the actual node. | ||
for (let n = 0, ln = this.nodes.length; n < ln; ++n) { | ||
let refNode = this.nodes[n]; | ||
const refNode = this.nodes[n]; | ||
let ref; | ||
@@ -157,3 +159,3 @@ | ||
if (ref) { | ||
let actualNode = this.nodesById[ref]; | ||
const actualNode = this.nodesById[ref]; | ||
let d, ld; | ||
@@ -185,3 +187,3 @@ | ||
for (let n = 0, ln = this.nodes.length; n < ln; ++n) { | ||
let node = this.nodes[n]; | ||
const node = this.nodes[n]; | ||
let d, ld, dep, actualNode; | ||
@@ -208,3 +210,3 @@ | ||
for (let m = 0, lm = node.manyToManyConnections.length; m < lm; ++m) { | ||
let conn = node.manyToManyConnections[m]; | ||
const conn = node.manyToManyConnections[m]; | ||
actualNode = refMap[conn.node.id]; | ||
@@ -222,3 +224,3 @@ | ||
for (let n = 0, ln = this.nodes.length; n < ln; ++n) { | ||
let node = this.nodes[n]; | ||
const node = this.nodes[n]; | ||
@@ -250,6 +252,6 @@ if (!node.handled) { | ||
allMatches(propRefRegex, value, matchResult => { | ||
let match = matchResult[0]; | ||
let refId = matchResult[1]; | ||
let refProp = matchResult[2]; | ||
let refNode = this.nodesById[refId]; | ||
const match = matchResult[0]; | ||
const refId = matchResult[1]; | ||
const refProp = matchResult[2]; | ||
const refNode = this.nodesById[refId]; | ||
@@ -256,0 +258,0 @@ if (!refNode) { |
@@ -19,4 +19,16 @@ 'use strict'; | ||
get hasUnresolvedDependencies() { | ||
return this.numHandledNeeds < this.needs.length; | ||
} | ||
markAsHandled() { | ||
for (let nb = 0, lnb = this.isNeededBy.length; nb < lnb; ++nb) { | ||
const dependency = this.isNeededBy[nb]; | ||
dependency.node.numHandledNeeds++; | ||
} | ||
this.handled = true; | ||
} | ||
} | ||
module.exports = DependencyNode; |
'use strict'; | ||
const _ = require('lodash'); | ||
const uniqBy = require('lodash/uniqBy'); | ||
const Promise = require('bluebird'); | ||
@@ -12,46 +12,50 @@ | ||
constructor(args) { | ||
this.allowedRelations = args.allowedRelations || null; | ||
this.modelClass = args.modelClass; | ||
this.models = args.models; | ||
this.allowedRelations = args.allowedRelations || null; | ||
this.done = false; | ||
this.knex = args.knex; | ||
this.graph = this._buildDependencyGraph(); | ||
this.knex = args.knex; | ||
} | ||
execute(inserter) { | ||
return this._executeNextBatch(inserter); | ||
return Promise.try(() => { | ||
return this._executeNormalBatches(inserter); | ||
}).then(() => { | ||
return this._executeJoinRowBatch(inserter); | ||
}).then(() => { | ||
return this._finalize(); | ||
}); | ||
} | ||
_buildDependencyGraph() { | ||
let graph = new DependencyGraph(this.allowedRelations); | ||
const graph = new DependencyGraph(this.allowedRelations); | ||
graph.build(this.modelClass, this.models); | ||
return graph; | ||
} | ||
_executeNormalBatches(inserter) { | ||
return this._executeNextBatch(inserter); | ||
} | ||
_executeNextBatch(inserter) { | ||
let batch = this._nextBatch(); | ||
const batch = this._nextBatch(); | ||
if (!batch) { | ||
// If we get here, we are done. All we need to do now is to finalize the object graph | ||
// and return it as the final output. | ||
return this._finalize(); | ||
// No more normal batches to execute. | ||
return null; | ||
} | ||
// Insert the batch using the `inserter` function. | ||
// Insert the batch one table at a time. | ||
return Promise.all(Object.keys(batch).map(tableName => { | ||
const tableInsertion = batch[tableName]; | ||
let uids; | ||
// We need to omit the uid properties so that they don't get inserted | ||
// into the database. | ||
const uids = this._omitUids(tableInsertion); | ||
if (!tableInsertion.isJoinTableInsertion) { | ||
// We need to omit the uid properties so that they don't get inserted | ||
// into the database. Join table insertions never have uids. | ||
uids = this._omitUids(tableInsertion); | ||
} | ||
return inserter(tableInsertion).then(() => { | ||
if (!tableInsertion.isJoinTableInsertion) { | ||
// Resolve dependencies to the inserted objects. Join table insertions | ||
// never resolve any dependencies. | ||
this._resolveDepsForInsertion(tableInsertion, uids); | ||
} | ||
// Resolve dependencies to the inserted objects. | ||
return this._resolveDepsForInsertion(tableInsertion, uids); | ||
}); | ||
@@ -64,25 +68,20 @@ })).then(() => { | ||
_nextBatch() { | ||
if (this.done) { | ||
return null; | ||
} | ||
const batch = this._createBatch(); | ||
let batch = this._createBatch(); | ||
if (_.isEmpty(batch)) { | ||
this.done = true; | ||
return this._createManyToManyRelationJoinRowBatch(); | ||
} else { | ||
if (batch) { | ||
this._markBatchHandled(batch); | ||
return batch; | ||
} | ||
return batch; | ||
} | ||
_createBatch() { | ||
let batch = Object.create(null); | ||
let nodes = this.graph.nodes; | ||
const batch = Object.create(null); | ||
const nodes = this.graph.nodes; | ||
let empty = true; | ||
for (let n = 0, ln = nodes.length; n < ln; ++n) { | ||
let node = nodes[n]; | ||
const node = nodes[n]; | ||
if (!node.handled && node.needs.length === node.numHandledNeeds) { | ||
if (!node.handled && !node.hasUnresolvedDependencies) { | ||
let tableInsertion = batch[node.modelClass.tableName]; | ||
@@ -97,38 +96,49 @@ | ||
tableInsertion.isInputModel.push(!!this.graph.inputNodesById[node.id]); | ||
empty = false; | ||
} | ||
} | ||
return batch; | ||
if (empty) { | ||
return null; | ||
} else { | ||
return batch; | ||
} | ||
} | ||
_markBatchHandled(batch) { | ||
let models = _.flatten(_.map(batch, 'models')); | ||
let nodes = this.graph.nodesById; | ||
const tableNames = Object.keys(batch); | ||
const nodes = this.graph.nodesById; | ||
for (let m = 0, lm = models.length; m < lm; ++m) { | ||
let id = models[m][models[m].constructor.uidProp]; | ||
let node = nodes[id]; | ||
for (let t = 0, lt = tableNames.length; t < lt; ++t) { | ||
const tableInsertion = batch[tableNames[t]]; | ||
const modelClass = tableInsertion.modelClass; | ||
const models = tableInsertion.models; | ||
for (let nb = 0, lnb = node.isNeededBy.length; nb < lnb; ++nb) { | ||
let dep = node.isNeededBy[nb]; | ||
dep.node.numHandledNeeds++; | ||
for (let m = 0, lm = models.length; m < lm; ++m) { | ||
nodes[models[m][modelClass.uidProp]].markAsHandled(); | ||
} | ||
node.handled = true; | ||
} | ||
} | ||
_createManyToManyRelationJoinRowBatch() { | ||
let batch = Object.create(null); | ||
let modelNames; | ||
_executeJoinRowBatch(inserter) { | ||
const batch = this._createJoinRowBatch(); | ||
// Insert the batch one table at a time. | ||
return Promise.all(Object.keys(batch).map(tableName => { | ||
return inserter(batch[tableName]); | ||
})); | ||
} | ||
_createJoinRowBatch() { | ||
const batch = Object.create(null); | ||
for (let n = 0, ln = this.graph.nodes.length; n < ln; ++n) { | ||
let node = this.graph.nodes[n]; | ||
const node = this.graph.nodes[n]; | ||
for (let m = 0, lm = node.manyToManyConnections.length; m < lm; ++m) { | ||
let conn = node.manyToManyConnections[m]; | ||
const conn = node.manyToManyConnections[m]; | ||
let tableInsertion = batch[conn.relation.joinTable]; | ||
let ownerProp = node.model.$values(conn.relation.ownerProp); | ||
let modelClass = conn.relation.joinTableModelClass(this.knex); | ||
const ownerProp = node.model.$values(conn.relation.ownerProp); | ||
const modelClass = conn.relation.joinTableModelClass(this.knex); | ||
let joinModel = conn.relation.createJoinModels(ownerProp, [conn.node.model])[0]; | ||
@@ -139,5 +149,5 @@ | ||
for (let k = 0, lk = conn.relation.joinTableExtras.length; k < lk; ++k) { | ||
let extra = conn.relation.joinTableExtras[k]; | ||
const extra = conn.relation.joinTableExtras[k]; | ||
if (!_.isUndefined(conn.refNode.model[extra.aliasProp])) { | ||
if (conn.refNode.model[extra.aliasProp] !== undefined) { | ||
joinModel[extra.joinTableProp] = conn.refNode.model[extra.aliasProp]; | ||
@@ -160,13 +170,34 @@ } | ||
modelNames = Object.keys(batch); | ||
// Remove duplicates. | ||
for (let i = 0, l = modelNames.length; i < l; ++i) { | ||
const modelName = modelNames[i]; | ||
const tableInsertion = batch[modelName]; | ||
return this._removeJoinRowDuplicatesFromBatch(batch); | ||
} | ||
_removeJoinRowDuplicatesFromBatch(batch) { | ||
const tableNames = Object.keys(batch); | ||
for (let t = 0, lt = tableNames.length; t < lt; ++t) { | ||
const tableName = tableNames[t]; | ||
const tableInsertion = batch[tableName]; | ||
if (tableInsertion.models.length) { | ||
const keys = _.uniq(_.flatMap(tableInsertion.models, _.keys)); | ||
const models = tableInsertion.models; | ||
const keyHash = Object.create(null); | ||
const keys = []; | ||
tableInsertion.models = _.uniqBy(tableInsertion.models, model => model.$propKey(keys)); | ||
tableInsertion.isInputModel = _.times(tableInsertion.models.length, _.constant(false)); | ||
for (let m = 0, lm = models.length; m < lm; ++m) { | ||
const model = models[m]; | ||
const modelKeys = Object.keys(model); | ||
for (let k = 0, lk = modelKeys.length; k < lk; ++k) { | ||
const key = modelKeys[k]; | ||
if (!keyHash[key]) { | ||
keyHash[modelKeys[k]] = true; | ||
keys.push(key); | ||
} | ||
} | ||
} | ||
tableInsertion.models = uniqBy(models, model => model.$propKey(keys)); | ||
tableInsertion.isInputModel = new Array(tableInsertion.models.length); | ||
tableInsertion.isInputModel.fill(false); | ||
} | ||
@@ -179,6 +210,11 @@ } | ||
_omitUids(tableInsertion) { | ||
let ids = _.map(tableInsertion.models, tableInsertion.modelClass.uidProp); | ||
const ids = new Array(tableInsertion.models.length); | ||
const modelClass = tableInsertion.modelClass; | ||
const uidProp = modelClass.uidProp; | ||
for (let m = 0, lm = tableInsertion.models.length; m < lm; ++m) { | ||
tableInsertion.models[m].$omit(tableInsertion.modelClass.uidProp); | ||
const model = tableInsertion.models[m]; | ||
ids[m] = model[uidProp]; | ||
modelClass.omitImpl(model, uidProp); | ||
} | ||
@@ -191,4 +227,4 @@ | ||
for (let m = 0, lm = tableInsertion.models.length; m < lm; ++m) { | ||
let node = this.graph.nodesById[uids[m]]; | ||
let model = tableInsertion.models[m]; | ||
const node = this.graph.nodesById[uids[m]]; | ||
const model = tableInsertion.models[m]; | ||
@@ -203,4 +239,5 @@ for (let d = 0, ld = node.isNeededBy.length; d < ld; ++d) { | ||
for (let n = 0, ln = this.graph.nodes.length; n < ln; ++n) { | ||
let refNode = this.graph.nodes[n]; | ||
let ref = refNode.model[refNode.modelClass.uidRefProp]; | ||
const refNode = this.graph.nodes[n]; | ||
const modelClass = refNode.modelClass; | ||
const ref = refNode.model[modelClass.uidRefProp]; | ||
@@ -217,3 +254,3 @@ if (ref) { | ||
if (!relations[key] && !_.isFunction(value)) { | ||
if (!relations[key] && typeof value !== 'function') { | ||
refNode.model[key] = value; | ||
@@ -223,3 +260,7 @@ } | ||
refNode.model.$omit(refNode.modelClass.uidProp, refNode.modelClass.uidRefProp); | ||
modelClass.omitImpl(refNode.model, modelClass.uidProp); | ||
modelClass.omitImpl(refNode.model, modelClass.uidRefProp); | ||
} else if (refNode.model[modelClass.uidProp]) { | ||
// Make sure the model no longer has an uid. | ||
modelClass.omitImpl(refNode.model, modelClass.uidProp); | ||
} | ||
@@ -226,0 +267,0 @@ } |
@@ -12,5 +12,4 @@ 'use strict'; | ||
} | ||
} | ||
module.exports = ManyToManyConnection; |
@@ -42,3 +42,3 @@ 'use strict'; | ||
onBeforeInternal(builder) { | ||
return this.joinBuilder.fetchColumnInfo(builder.knex()); | ||
return this.joinBuilder.fetchColumnInfo(builder); | ||
} | ||
@@ -45,0 +45,0 @@ |
'use strict'; | ||
const _ = require('lodash'); | ||
const uniq = require('lodash/uniq'); | ||
const uniqBy = require('lodash/uniqBy'); | ||
const values = require('lodash/values'); | ||
const groupBy = require('lodash/groupBy'); | ||
const uniqWith = require('lodash/uniqWith'); | ||
const Promise = require('bluebird'); | ||
@@ -21,7 +25,7 @@ | ||
this.opt = _.defaults(args.opt, { | ||
this.opt = Object.assign({ | ||
minimize: false, | ||
separator: ':', | ||
aliases: {} | ||
}); | ||
}, args.opt); | ||
} | ||
@@ -52,3 +56,4 @@ | ||
*/ | ||
fetchColumnInfo(knex) { | ||
fetchColumnInfo(builder) { | ||
const knex = builder.knex(); | ||
const columnInfo = RelationJoinBuilder.columnInfo; | ||
@@ -58,3 +63,3 @@ const allModelClasses = findAllModels(this.expression, this.rootModelClass); | ||
return Promise.all(allModelClasses.map(ModelClass => { | ||
const table = ModelClass.tableName; | ||
const table = builder.tableNameFor(ModelClass); | ||
@@ -93,4 +98,6 @@ if (columnInfo[table]) { | ||
const builderClone = builder.clone(); | ||
const tableName = builder.tableNameFor(this.rootModelClass); | ||
const tableAlias = builder.tableRefFor(this.rootModelClass); | ||
builder.table(`${this.rootModelClass.tableName} as ${this.rootModelClass.tableName}`); | ||
builder.table(`${tableName} as ${tableAlias}`); | ||
@@ -112,3 +119,3 @@ this.doBuild({ | ||
rowsToTree(rows) { | ||
if (_.isEmpty(rows)) { | ||
if (!Array.isArray(rows) || rows.length === 0) { | ||
return rows; | ||
@@ -118,3 +125,3 @@ } | ||
const keyInfoByPath = this.createKeyInfo(rows); | ||
const pathInfo = _.values(this.pathInfo); | ||
const pathInfo = values(this.pathInfo); | ||
@@ -158,3 +165,3 @@ const tree = Object.create(null); | ||
return this.finalize(pathInfo[0], _.values(tree)); | ||
return this.finalize(pathInfo[0], values(tree)); | ||
} | ||
@@ -189,3 +196,3 @@ | ||
return _.groupBy(keyInfo, kInfo => kInfo.pInfo.encPath); | ||
return groupBy(keyInfo, kInfo => kInfo.pInfo.encPath); | ||
} | ||
@@ -339,4 +346,5 @@ | ||
const idCols = modelClass.getIdColumnArray(); | ||
const rootTable = this.rootModelClass.tableName; | ||
const columns = RelationJoinBuilder.columnInfo[modelClass.tableName].columns; | ||
const rootTable = builder.tableRefFor(this.rootModelClass); | ||
const table = builder.tableNameFor(modelClass); | ||
const columns = RelationJoinBuilder.columnInfo[table].columns; | ||
@@ -477,3 +485,3 @@ for (let i = 0, l = columns.length; i < l; ++i) { | ||
return _.uniqBy(models, 'tableName'); | ||
return uniqBy(models, 'tableName'); | ||
} | ||
@@ -494,3 +502,3 @@ | ||
return _.uniqWith(relations, (lhs, rhs) => lhs === rhs); | ||
return uniqWith(relations, (lhs, rhs) => lhs === rhs); | ||
} | ||
@@ -596,2 +604,3 @@ | ||
const relation = args.relation; | ||
const modelNamedFilters = relation.relatedModelClass.namedFilters || {}; | ||
const filterQuery = relation.relatedModelClass | ||
@@ -603,3 +612,3 @@ .query() | ||
const filterName = expr.args[i]; | ||
const filter = expr.filters[filterName]; | ||
const filter = expr.filters[filterName] || modelNamedFilters[filterName]; | ||
@@ -638,7 +647,7 @@ if (typeof filter !== 'function') { | ||
allRelations.forEach(rel => { | ||
if (rel.relatedModelClass.tableName === modelClass.tableName) { | ||
if (rel.relatedModelClass === modelClass) { | ||
rel.relatedCol.forEach(col => foreignKeys.push(col)); | ||
} | ||
if (rel.ownerModelClass.tableName === modelClass.tableName) { | ||
if (rel.ownerModelClass === modelClass) { | ||
rel.ownerCol.forEach(col => foreignKeys.push(col)); | ||
@@ -648,3 +657,3 @@ } | ||
return _.uniq(foreignKeys); | ||
return uniq(foreignKeys); | ||
} | ||
@@ -700,3 +709,3 @@ | ||
finalizeBranch(branch, parentModel) { | ||
const relModels = _.values(branch); | ||
const relModels = values(branch); | ||
parentModel[this.relation.name] = relModels; | ||
@@ -703,0 +712,0 @@ return relModels; |
@@ -68,3 +68,3 @@ 'use strict'; | ||
const relation = this.relationsToFetch[i].relation; | ||
const cols = relation.fullOwnerCol; | ||
const cols = relation.fullOwnerCol(builder); | ||
@@ -153,2 +153,3 @@ for (let c = 0, lc = cols.length; c < lc; ++c) { | ||
const findOperation = relation.find(queryBuilder, models); | ||
const modelNamedFilters = relation.relatedModelClass.namedFilters || {}; | ||
@@ -160,3 +161,3 @@ findOperation.alwaysReturnArray = true; | ||
const filterName = childExpression.args[i]; | ||
const filter = childExpression.filters[filterName]; | ||
const filter = childExpression.filters[filterName] || modelNamedFilters[filterName]; | ||
@@ -163,0 +164,0 @@ if (typeof filter !== 'function') { |
@@ -28,3 +28,3 @@ 'use strict'; | ||
.childQueryOf(builder) | ||
.whereInComposite(builder.modelClass().getFullIdColumn(), insertedModelArray.map(model => model.$id())) | ||
.whereInComposite(builder.fullIdColumnFor(builder.modelClass()), insertedModelArray.map(model => model.$id())) | ||
.then(fetchedModels => { | ||
@@ -31,0 +31,0 @@ fetchedModels = keyBy(fetchedModels, model => model.$propKey(idProps)); |
@@ -37,3 +37,3 @@ 'use strict'; | ||
.childQueryOf(builder) | ||
.whereIn(modelClass.getFullIdColumn(), ids) | ||
.whereIn(builder.fullIdColumnFor(modelClass), ids) | ||
.eager(eager) | ||
@@ -40,0 +40,0 @@ .then(models => { |
'use strict'; | ||
const QueryBuilderOperation = require('./QueryBuilderOperation'); | ||
const fromJson = require('../../model/modelFactory').fromJson; | ||
const mapAfterAllReturn = require('../../utils/promiseUtils').mapAfterAllReturn; | ||
const toDatabaseJson = require('../../model/modelFactory').toDatabaseJson; | ||
const mapAfterAllReturn = require('../../utils/promiseUtils').mapAfterAllReturn; | ||
const isPostgres = require('../../utils/knexUtils').isPostgres; | ||
const fromJson = require('../../model/modelFactory').fromJson; | ||
@@ -9,0 +9,0 @@ class InsertOperation extends QueryBuilderOperation { |
@@ -20,3 +20,3 @@ 'use strict'; | ||
super.onBeforeBuild(builder); | ||
builder.whereComposite(builder.modelClass().getFullIdColumn(), this.instance.$id()); | ||
builder.whereComposite(builder.fullIdColumnFor(builder.modelClass()), this.instance.$id()); | ||
} | ||
@@ -23,0 +23,0 @@ |
@@ -13,3 +13,3 @@ 'use strict'; | ||
onBeforeBuild(builder) { | ||
builder.whereComposite(builder.modelClass().getFullIdColumn(), this.instance.$id()).first() | ||
builder.whereComposite(builder.fullIdColumnFor(builder.modelClass()), this.instance.$id()).first() | ||
} | ||
@@ -16,0 +16,0 @@ } |
@@ -27,3 +27,3 @@ 'use strict'; | ||
super.onBeforeBuild(builder); | ||
builder.whereComposite(builder.modelClass().getFullIdColumn(), this.instance.$id()); | ||
builder.whereComposite(builder.fullIdColumnFor(builder.modelClass()), this.instance.$id()); | ||
} | ||
@@ -30,0 +30,0 @@ |
@@ -42,3 +42,3 @@ 'use strict'; | ||
if (opt.alias === false) { | ||
alias = relation.relatedModelClass.tableName; | ||
alias = builder.tableRefFor(relation.relatedModelClass); | ||
} else if (opt.alias === true || !opt.alias) { | ||
@@ -45,0 +45,0 @@ alias = relation.name; |
'use strict'; | ||
const _ = require('lodash'); | ||
const jsonFieldExpressionParser = require('../../parsers/jsonFieldExpressionParser'); | ||
@@ -47,3 +46,3 @@ | ||
let parsed = jsonFieldExpressionParser.parse(expression); | ||
let jsonRefs = _(parsed.access).map('ref').value().join(","); | ||
let jsonRefs = parsed.access.map(it => it.ref).join(","); | ||
let extractor = extractAsText ? '#>>' : '#>'; | ||
@@ -62,3 +61,3 @@ let middleQuotedColumnName = parsed.columnName.split('.').join('"."'); | ||
if (_.isString(jsonObjectOrFieldExpression)) { | ||
if (typeof jsonObjectOrFieldExpression === 'string') { | ||
let rightHandReference = parseFieldExpression(jsonObjectOrFieldExpression); | ||
@@ -70,3 +69,3 @@ let refRefQuery = ["(", fieldReference, ")::jsonb", operator, "(", rightHandReference, ")::jsonb"]; | ||
return [refRefQuery.join(" ")]; | ||
} else if (_.isObject(jsonObjectOrFieldExpression)) { | ||
} else if (jsonObjectOrFieldExpression && typeof jsonObjectOrFieldExpression === 'object') { | ||
let refValQuery = ["(", fieldReference, ")::jsonb", operator, "?::jsonb"]; | ||
@@ -85,6 +84,6 @@ if (queryPrefix) { | ||
let fieldReference = parseFieldExpression(fieldExpression); | ||
keys = _.isArray(keys) ? keys : [keys]; | ||
keys = Array.isArray(keys) ? keys : [keys]; | ||
let questionMarksArray = _.map(keys, function (key) { | ||
if (!_.isString(key)) { | ||
let questionMarksArray = keys.map(key => { | ||
if (typeof key !== 'string') { | ||
throw new Error("All keys to find must be strings."); | ||
@@ -108,9 +107,11 @@ } | ||
let escapedValue = knex.raw(" ?", [value]); | ||
if (_.isNumber(value)) { | ||
let type = typeof value; | ||
if (type === 'number') { | ||
cast = "::NUMERIC"; | ||
} else if (_.isBoolean(value)) { | ||
} else if (type === 'boolean') { | ||
cast = "::BOOLEAN"; | ||
} else if (_.isString(value)) { | ||
} else if (type === 'string') { | ||
cast = "::TEXT"; | ||
} else if (_.isNull(value)) { | ||
} else if (value === null) { | ||
cast = "::TEXT"; | ||
@@ -117,0 +118,0 @@ escapedValue = 'NULL'; |
@@ -30,3 +30,3 @@ 'use strict'; | ||
super.onBeforeBuild(builder); | ||
builder.whereComposite(builder.modelClass().getFullIdColumn(), this.id); | ||
builder.whereComposite(builder.fullIdColumnFor(builder.modelClass()), this.id); | ||
} | ||
@@ -43,3 +43,3 @@ | ||
.childQueryOf(builder) | ||
.whereComposite(builder.modelClass().getFullIdColumn(), this.id) | ||
.whereComposite(builder.fullIdColumnFor(builder.modelClass()), this.id) | ||
.first() | ||
@@ -46,0 +46,0 @@ .then(fetched => { |
@@ -21,4 +21,6 @@ 'use strict'; | ||
const InsertGraphOperation = require('./operations/InsertGraphOperation'); | ||
const DeleteByIdOperation = require('./operations/DeleteByIdOperation'); | ||
const RunBeforeOperation = require('./operations/RunBeforeOperation'); | ||
const RunAfterOperation = require('./operations/RunAfterOperation'); | ||
const FindByIdOperation = require('./operations/FindByIdOperation'); | ||
const OnBuildOperation = require('./operations/OnBuildOperation'); | ||
@@ -28,2 +30,3 @@ const SelectOperation = require('./operations/SelectOperation'); | ||
const RangeOperation = require('./operations/RangeOperation'); | ||
const FromOperation = require('./operations/FromOperation'); | ||
@@ -65,2 +68,42 @@ class QueryBuilder extends QueryBuilderBase { | ||
tableRefFor(modelClass) { | ||
const ctx = this.internalContext(); | ||
const aliasMap = ctx.aliasMap; | ||
return (aliasMap && aliasMap[modelClass.tableName]) || this.tableNameFor(modelClass); | ||
} | ||
tableNameFor(modelClass) { | ||
const ctx = this.internalContext(); | ||
const tableMap = ctx.tableMap; | ||
return (tableMap && tableMap[modelClass.tableName]) || modelClass.tableName; | ||
} | ||
alias(alias) { | ||
const ctx = this.internalContext(); | ||
ctx.aliasMap = ctx.aliasMap || Object.create(null); | ||
ctx.aliasMap[this._modelClass.tableName] = alias; | ||
return this; | ||
} | ||
fullIdColumnFor(modelClass) { | ||
const tableName = this.tableRefFor(modelClass); | ||
const idColumn = modelClass.idColumn; | ||
if (Array.isArray(idColumn)) { | ||
const id = new Array(idColumn.length); | ||
for (let i = 0, l = idColumn.length; i < l; ++i) { | ||
id[i] = `${tableName}.${idColumn[i]}`; | ||
} | ||
return id; | ||
} else { | ||
return `${tableName}.${idColumn}`; | ||
} | ||
} | ||
childQueryOf(query) { | ||
@@ -243,2 +286,6 @@ if (query) { | ||
isEagerQuery() { | ||
return !!this._eagerExpression; | ||
} | ||
toString() { | ||
@@ -357,3 +404,3 @@ return this.build().toString(); | ||
if (builder._eagerExpression) { | ||
if (builder.isEagerQuery()) { | ||
callEagerFetchOperation(builder); | ||
@@ -389,3 +436,3 @@ } | ||
if (builder._eagerExpression) { | ||
if (builder.isEagerQuery()) { | ||
callEagerFetchOperation(builder); | ||
@@ -466,3 +513,3 @@ } | ||
const table = this._modelClass.tableName; | ||
const table = this.tableRefFor(this._modelClass); | ||
let noSelectStatements = true; | ||
@@ -540,6 +587,2 @@ | ||
findById(id) { | ||
return this.whereComposite(this._modelClass.getFullIdColumn(), id).first(); | ||
} | ||
withSchema(schema) { | ||
@@ -668,6 +711,2 @@ this.internalContext().onBuild.push(builder => { | ||
deleteById(id) { | ||
return this.delete().whereComposite(this._modelClass.getFullIdColumn(), id); | ||
} | ||
relate(ids) { | ||
@@ -708,2 +747,4 @@ const relateOperation = this._relateOperationFactory(this); | ||
fullOuterJoinRelation(relationName) {} | ||
deleteById(id) {} | ||
findById(id) {} | ||
runBefore(runBefore) {} | ||
@@ -770,2 +811,11 @@ onBuild(onBuild) {} | ||
properties: ['runAfter'] | ||
}, { | ||
decorator: queryBuilderOperation(FindByIdOperation), | ||
properties: ['findById'] | ||
}, { | ||
decorator: queryBuilderOperation(DeleteByIdOperation), | ||
properties: ['deleteById'] | ||
}, { | ||
decorator: queryBuilderOperation(FromOperation), | ||
properties: ['from', 'table'] | ||
}]); | ||
@@ -884,13 +934,25 @@ | ||
if (!builder.has(QueryBuilderBase.FromSelector)) { | ||
const table = builder.modelClass().tableName; | ||
const fromOperation = builder.findLastOperation(QueryBuilderBase.FromSelector); | ||
const hasSelects = builder.has(QueryBuilderBase.SelectSelector); | ||
if (!fromOperation) { | ||
const table = builder.tableNameFor(builder.modelClass()); | ||
const tableRef = builder.tableRefFor(builder.modelClass()); | ||
// Set the table only if it hasn't been explicitly set yet. | ||
knexBuilder.table(table); | ||
if (!builder.has(QueryBuilderBase.SelectSelector)) { | ||
knexBuilder.select(`${table}.*`); | ||
if (table === tableRef) { | ||
knexBuilder.table(table); | ||
} else { | ||
knexBuilder.table(`${table} as ${tableRef}`); | ||
} | ||
} | ||
if (!hasSelects && (!fromOperation || fromOperation.table)) { | ||
const tableRef = builder.tableRefFor(builder.modelClass()); | ||
// Only add `table.*` select if there are no explicit selects | ||
// and `from` is a table name and not a subquery. | ||
knexBuilder.select(`${tableRef}.*`); | ||
} | ||
return knexBuilder; | ||
@@ -897,0 +959,0 @@ } |
@@ -13,2 +13,5 @@ 'use strict'; | ||
this.onBuild = []; | ||
this.aliasMap = null; | ||
this.tableMap = null; | ||
} | ||
@@ -23,2 +26,5 @@ | ||
ctx.aliasMap = this.aliasMap; | ||
ctx.tableMap = this.tableMap; | ||
return ctx; | ||
@@ -25,0 +31,0 @@ } |
@@ -109,2 +109,22 @@ 'use strict'; | ||
indexOfLastOperation(operationSelector) { | ||
let idx = -1; | ||
this.forEachOperation(operationSelector, (op, i) => { | ||
idx = i; | ||
}); | ||
return idx; | ||
} | ||
findLastOperation(operationSelector) { | ||
const idx = this.indexOfLastOperation(operationSelector); | ||
if (idx !== -1) { | ||
return this._operations[idx]; | ||
} else { | ||
return null; | ||
} | ||
} | ||
forEachOperation(operationSelector, callback, match) { | ||
@@ -111,0 +131,0 @@ match = (match == null) ? true : match; |
'use strict'; | ||
const _ = require('lodash'); | ||
const merge = require('lodash/merge'); | ||
const clone = require('lodash/clone'); | ||
const values = require('lodash/values'); | ||
const cloneDeep = require('lodash/cloneDeep'); | ||
const parser = require('./parsers/relationExpressionParser'); | ||
@@ -62,5 +65,5 @@ | ||
merged.numChildren += expr.numChildren; | ||
merged.children = _.merge(merged.children, expr.children); | ||
merged.args = _.merge(merged.args, expr.args); | ||
merged.filters = _.merge(merged.filters, expr.filters); | ||
merged.children = merge(merged.children, expr.children); | ||
merged.args = merge(merged.args, expr.args); | ||
merged.filters = merge(merged.filters, expr.filters); | ||
@@ -173,6 +176,6 @@ // Handle recursive and all recursive nodes. | ||
numChildren: this.numChildren, | ||
children: _.cloneDeep(this.children) | ||
children: cloneDeep(this.children) | ||
}; | ||
const filters = _.clone(this._filters); | ||
const filters = clone(this._filters); | ||
return new RelationExpression(node, this._recursionDepth, filters); | ||
@@ -256,3 +259,3 @@ } | ||
function toString(node) { | ||
let childExpr = _.values(node.children).map(toString); | ||
let childExpr = values(node.children).map(toString); | ||
let str = node.name; | ||
@@ -259,0 +262,0 @@ |
@@ -45,3 +45,3 @@ 'use strict'; | ||
.patch(patch) | ||
.whereComposite(this.relation.ownerModelClass.getFullIdColumn(), this.owner.$id()) | ||
.whereComposite(builder.fullIdColumnFor(this.relation.ownerModelClass), this.owner.$id()) | ||
.return(inserted); | ||
@@ -48,0 +48,0 @@ }); |
@@ -44,3 +44,3 @@ 'use strict'; | ||
.patch(patch) | ||
.whereComposite(this.relation.ownerModelClass.getFullIdColumn(), this.owner.$id()); | ||
.whereComposite(builder.fullIdColumnFor(this.relation.ownerModelClass), this.owner.$id()); | ||
} | ||
@@ -47,0 +47,0 @@ } |
@@ -39,3 +39,3 @@ 'use strict'; | ||
.copyFrom(builder, /where/i) | ||
.whereInComposite(this.relation.relatedModelClass.getFullIdColumn(), this.ids) | ||
.whereInComposite(builder.fullIdColumnFor(this.relation.relatedModelClass), this.ids) | ||
.modify(this.relation.modify); | ||
@@ -42,0 +42,0 @@ } |
'use strict'; | ||
const Relation = require('../Relation'); | ||
const HasManyInsertOperation = require('./HasManyInsertOperation'); | ||
@@ -6,0 +5,0 @@ const HasManyRelateOperation = require('./HasManyRelateOperation'); |
@@ -28,3 +28,3 @@ 'use strict'; | ||
.copyFrom(builder, /where/i) | ||
.whereComposite(this.relation.fullRelatedCol, this.owner.$values(this.relation.ownerProp)) | ||
.whereComposite(this.relation.fullRelatedCol(builder), this.owner.$values(this.relation.ownerProp)) | ||
.modify(this.relation.modify); | ||
@@ -31,0 +31,0 @@ } |
@@ -5,5 +5,4 @@ 'use strict'; | ||
const RelationFindOperation = require('../RelationFindOperation'); | ||
const OWNER_JOIN_COLUMN_ALIAS_PREFIX = 'objectiontmpjoin'; | ||
const ownerJoinColumnAliasPrefix = 'objectiontmpjoin'; | ||
class ManyToManyFindOperation extends RelationFindOperation { | ||
@@ -17,3 +16,3 @@ | ||
for (let i = 0, l = this.relation.joinTableOwnerCol.length; i < l; ++i) { | ||
this.ownerJoinColumnAlias[i] = ownerJoinColumnAliasPrefix + i; | ||
this.ownerJoinColumnAlias[i] = OWNER_JOIN_COLUMN_ALIAS_PREFIX + i; | ||
} | ||
@@ -39,5 +38,7 @@ } | ||
if (!builder.has(builder.constructor.SelectSelector)) { | ||
const table = builder.tableRefFor(relatedModelClass); | ||
// If the user hasn't specified a select clause, select the related model's columns. | ||
// If we don't do this we also get the join table's columns. | ||
builder.select(relatedModelClass.tableName + '.*'); | ||
builder.select(`${table}.*`); | ||
@@ -57,7 +58,7 @@ // Also select all extra columns. | ||
const fullJoinTableOwnerCol = this.relation.fullJoinTableOwnerCol; | ||
const fullJoinTableOwnerCol = this.relation.fullJoinTableOwnerCol(builder); | ||
// We must select the owner join columns so that we know for which owner model the related | ||
// models belong to after the requests. | ||
for (let i = 0, l = fullJoinTableOwnerCol.length; i < l; ++i) { | ||
builder.select(fullJoinTableOwnerCol[i] + ' as ' + this.ownerJoinColumnAlias[i]); | ||
builder.select(`${fullJoinTableOwnerCol[i]} as ${this.ownerJoinColumnAlias[i]}`); | ||
@@ -64,0 +65,0 @@ // Mark them to be omitted later. |
@@ -5,3 +5,5 @@ 'use strict'; | ||
const inheritModel = require('../../model/inheritModel'); | ||
const resolveModel = require('../../utils/resolveModel').resolveModel | ||
const isSqlite = require('../../utils/knexUtils').isSqlite; | ||
const getModel = () => require('../../model/Model'); | ||
@@ -18,3 +20,3 @@ const ManyToManyFindOperation = require('./ManyToManyFindOperation'); | ||
const sqliteBuiltInRowId = '_rowid_'; | ||
const SQLITE_BUILTIN_ROW_ID = '_rowid_'; | ||
@@ -25,12 +27,10 @@ class ManyToManyRelation extends Relation { | ||
let retVal = super.setMapping(mapping); | ||
let Model = getModel(); | ||
// Avoid require loop and import here. | ||
let Model = require(__dirname + '/../../model/Model'); | ||
if (!mapping.join.through || typeof mapping.join.through !== 'object') { | ||
this.throwError('join must have the `through` that describes the join table.'); | ||
throw this.createError('join must have a `through` object that describes the join table.'); | ||
} | ||
if (!mapping.join.through.from || !mapping.join.through.to) { | ||
this.throwError('join.through must be an object that describes the join table. For example: {from: "JoinTable.someId", to: "JoinTable.someOtherId"}'); | ||
throw this.createError('join.through must be an object that describes the join table. For example: {from: "JoinTable.someId", to: "JoinTable.someOtherId"}'); | ||
} | ||
@@ -44,11 +44,11 @@ | ||
if (!joinTableFrom.table || !joinTableFrom.columns.length) { | ||
this.throwError('join.through.from must have format JoinTable.columnName. For example "JoinTable.someId" or in case of composite key ["JoinTable.a", "JoinTable.b"].'); | ||
throw this.createError('join.through.from must have format JoinTable.columnName. For example "JoinTable.someId" or in case of composite key ["JoinTable.a", "JoinTable.b"].'); | ||
} | ||
if (!joinTableTo.table || !joinTableTo.columns.length) { | ||
this.throwError('join.through.to must have format JoinTable.columnName. For example "JoinTable.someId" or in case of composite key ["JoinTable.a", "JoinTable.b"].'); | ||
throw this.createError('join.through.to must have format JoinTable.columnName. For example "JoinTable.someId" or in case of composite key ["JoinTable.a", "JoinTable.b"].'); | ||
} | ||
if (joinTableFrom.table !== joinTableTo.table) { | ||
this.throwError('join.through `from` and `to` must point to the same join table.'); | ||
throw this.createError('join.through `from` and `to` must point to the same join table.'); | ||
} | ||
@@ -67,3 +67,7 @@ | ||
if (mapping.join.through.modelClass) { | ||
this._joinTableModelClass = this.resolveModel(Model, mapping.join.through.modelClass, 'join.through.modelClass'); | ||
try { | ||
this._joinTableModelClass = resolveModel(mapping.join.through.modelClass, this.ownerModelClass.modelPaths, 'join.through.modelClass'); | ||
} catch (err) { | ||
throw this.createError(err.message); | ||
} | ||
} else { | ||
@@ -81,12 +85,32 @@ this._joinTableModelClass = inheritModel(Model); | ||
this.fullJoinTableOwnerCol = this.joinTableOwnerCol.map(col => `${this.joinTable}.${col}`); | ||
this.fullJoinTableRelatedCol = this.joinTableRelatedCol.map(col => `${this.joinTable}.${col}`); | ||
return retVal; | ||
} | ||
joinTableAlias() { | ||
return this.joinTable + '_rel_' + this.name; | ||
joinTableAlias(builder) { | ||
const table = builder.tableRefFor(this._joinTableModelClass); | ||
return `${table}_rel_${this.name}`; | ||
} | ||
fullJoinTableRelatedCol(builder) { | ||
const table = builder.tableRefFor(this._joinTableModelClass); | ||
const col = new Array(this.joinTableRelatedCol.length); | ||
for (let i = 0, l = col.length; i < l; ++i) { | ||
col[i] = `${table}.${this.joinTableRelatedCol[i]}`; | ||
} | ||
return col; | ||
} | ||
fullJoinTableOwnerCol(builder) { | ||
const table = builder.tableRefFor(this._joinTableModelClass); | ||
const col = new Array(this.joinTableOwnerCol.length); | ||
for (let i = 0, l = col.length; i < l; ++i) { | ||
col[i] = `${table}.${this.joinTableOwnerCol[i]}`; | ||
} | ||
return col; | ||
} | ||
bindKnex(knex) { | ||
@@ -100,4 +124,4 @@ let bound = super.bindKnex(knex); | ||
builder.join(this.joinTable, join => { | ||
const fullRelatedCol = this.fullRelatedCol; | ||
const fullJoinTableRelatedCol = this.fullJoinTableRelatedCol; | ||
const fullRelatedCol = this.fullRelatedCol(builder); | ||
const fullJoinTableRelatedCol = this.fullJoinTableRelatedCol(builder); | ||
@@ -110,3 +134,3 @@ for (let i = 0, l = fullJoinTableRelatedCol.length; i < l; ++i) { | ||
if (opt.isColumnRef) { | ||
const fullJoinTableOwnerCol = this.fullJoinTableOwnerCol; | ||
const fullJoinTableOwnerCol = this.fullJoinTableOwnerCol(builder); | ||
@@ -129,3 +153,3 @@ for (let i = 0, l = fullJoinTableOwnerCol.length; i < l; ++i) { | ||
if (hasIds) { | ||
builder.whereInComposite(this.fullJoinTableOwnerCol, opt.ownerIds); | ||
builder.whereInComposite(this.fullJoinTableOwnerCol(builder), opt.ownerIds); | ||
} else { | ||
@@ -143,15 +167,9 @@ builder.resolve([]); | ||
opt.joinOperation = opt.joinOperation || 'join'; | ||
opt.relatedTableAlias = opt.relatedTableAlias || this.relatedTableAlias; | ||
opt.relatedTableAlias = opt.relatedTableAlias || this.relatedTableAlias(builder); | ||
opt.relatedJoinSelectQuery = opt.relatedJoinSelectQuery || this.relatedModelClass.query().childQueryOf(builder); | ||
opt.relatedTable = opt.relatedTable || this.relatedModelClass.tableName; | ||
opt.ownerTable = opt.ownerTable || this.ownerModelClass.tableName; | ||
opt.relatedTable = opt.relatedTable || builder.tableNameFor(this.relatedModelClass); | ||
opt.ownerTable = opt.ownerTable || builder.tableRefFor(this.ownerModelClass); | ||
opt.joinTableAlias = opt.joinTableAlias || `${opt.relatedTableAlias}_join`; | ||
const joinTableAsAlias = `${this.joinTable} as ${opt.joinTableAlias}`; | ||
const joinTableOwnerCol = this.joinTableOwnerCol.map(col => `${opt.joinTableAlias}.${col}`); | ||
const joinTableRelatedCol = this.joinTableRelatedCol.map(col => `${opt.joinTableAlias}.${col}`); | ||
const relatedCol = this.relatedCol.map(col => `${opt.relatedTableAlias}.${col}`); | ||
const ownerCol = this.ownerCol.map(col => `${opt.ownerTable}.${col}`); | ||
let relatedJoinSelect = opt.relatedJoinSelectQuery | ||
@@ -163,3 +181,3 @@ .modify(this.modify) | ||
// No need to join a subquery if the query is `select * from "RelatedTable"`. | ||
relatedJoinSelect = `${this.relatedModelClass.tableName} as ${opt.relatedTableAlias}` | ||
relatedJoinSelect = `${opt.relatedTable} as ${opt.relatedTableAlias}`; | ||
} | ||
@@ -169,9 +187,13 @@ | ||
[opt.joinOperation](joinTableAsAlias, join => { | ||
for (let i = 0, l = joinTableOwnerCol.length; i < l; ++i) { | ||
join.on(joinTableOwnerCol[i], ownerCol[i]); | ||
for (let i = 0, l = this.joinTableOwnerCol.length; i < l; ++i) { | ||
const joinTableOwnerCol = `${opt.joinTableAlias}.${this.joinTableOwnerCol[i]}`; | ||
const ownerCol = `${opt.ownerTable}.${this.ownerCol[i]}`; | ||
join.on(joinTableOwnerCol, ownerCol); | ||
} | ||
}) | ||
[opt.joinOperation](relatedJoinSelect, join => { | ||
for (let i = 0, l = joinTableRelatedCol.length; i < l; ++i) { | ||
join.on(joinTableRelatedCol[i], relatedCol[i]); | ||
for (let i = 0, l = this.joinTableRelatedCol.length; i < l; ++i) { | ||
const joinTableRelatedCol = `${opt.joinTableAlias}.${this.joinTableRelatedCol[i]}`; | ||
const relatedCol = `${opt.relatedTableAlias}.${this.relatedCol[i]}`; | ||
join.on(joinTableRelatedCol, relatedCol); | ||
} | ||
@@ -266,14 +288,14 @@ }); | ||
.childQueryOf(builder) | ||
.select(this.fullJoinTableRelatedCol) | ||
.whereComposite(this.fullJoinTableOwnerCol, ownerId); | ||
.select(this.fullJoinTableRelatedCol(builder)) | ||
.whereComposite(this.fullJoinTableOwnerCol(builder), ownerId); | ||
return builder.whereInComposite(this.fullRelatedCol, idQuery); | ||
return builder.whereInComposite(this.fullRelatedCol(builder), idQuery); | ||
} | ||
selectForModifySqlite(builder, owner) { | ||
const relatedTable = this.relatedModelClass.tableName; | ||
const relatedTableAlias = this.relatedTableAlias; | ||
const relatedTableAsAlias = relatedTable + ' as ' + relatedTableAlias; | ||
const relatedTableAliasRowId = relatedTableAlias + '.' + sqliteBuiltInRowId; | ||
const relatedTableRowId = relatedTable + '.' + sqliteBuiltInRowId; | ||
const relatedTable = builder.tableNameFor(this.relatedModelClass); | ||
const relatedTableAlias = this.relatedTableAlias(builder); | ||
const relatedTableAsAlias = `${relatedTable} as ${relatedTableAlias}`; | ||
const relatedTableAliasRowId = `${relatedTableAlias}.${SQLITE_BUILTIN_ROW_ID}`; | ||
const relatedTableRowId = `${relatedTable}.${SQLITE_BUILTIN_ROW_ID}`; | ||
@@ -284,6 +306,6 @@ const selectRelatedQuery = this.joinTableModelClass(builder.knex()) | ||
.select(relatedTableAliasRowId) | ||
.whereComposite(this.fullJoinTableOwnerCol, owner.$values(this.ownerProp)) | ||
.whereComposite(this.fullJoinTableOwnerCol(builder), owner.$values(this.ownerProp)) | ||
.join(relatedTableAsAlias, join => { | ||
const fullJoinTableRelatedCols = this.fullJoinTableRelatedCol; | ||
const fullRelatedCol = this.fullRelatedCol; | ||
const fullJoinTableRelatedCols = this.fullJoinTableRelatedCol(builder); | ||
const fullRelatedCol = this.fullRelatedCol(builder); | ||
@@ -290,0 +312,0 @@ for (let i = 0, l = fullJoinTableRelatedCols.length; i < l; ++i) { |
@@ -20,3 +20,3 @@ 'use strict'; | ||
.copyFrom(builder, /where/i) | ||
.select(this.relation.fullRelatedCol) | ||
.select(this.relation.fullRelatedCol(builder)) | ||
.modify(this.relation.modify); | ||
@@ -28,4 +28,4 @@ | ||
.delete() | ||
.whereComposite(this.relation.fullJoinTableOwnerCol, this.owner.$values(this.relation.ownerProp)) | ||
.whereInComposite(this.relation.fullJoinTableRelatedCol, selectRelatedColQuery); | ||
.whereComposite(this.relation.fullJoinTableOwnerCol(builder), this.owner.$values(this.relation.ownerProp)) | ||
.whereInComposite(this.relation.fullJoinTableRelatedCol(builder), selectRelatedColQuery); | ||
} | ||
@@ -32,0 +32,0 @@ } |
'use strict'; | ||
const QueryBuilderOperation = require('../../queryBuilder/operations/QueryBuilderOperation'); | ||
const sqliteBuiltInRowId = '_rowid_'; | ||
const SQLITE_BUILTIN_ROW_ID = '_rowid_'; | ||
@@ -17,9 +17,9 @@ class ManyToManyUnrelateSqliteOperation extends QueryBuilderOperation { | ||
queryExecutor(builder) { | ||
let joinTableAlias = this.relation.joinTableAlias(); | ||
let joinTableAlias = this.relation.joinTableAlias(builder); | ||
let joinTableAsAlias = this.relation.joinTable + ' as ' + joinTableAlias; | ||
let joinTableAliasRowId = joinTableAlias + '.' + sqliteBuiltInRowId; | ||
let joinTableRowId = this.relation.joinTable + '.' + sqliteBuiltInRowId; | ||
let joinTableAliasRowId = joinTableAlias + '.' + SQLITE_BUILTIN_ROW_ID; | ||
let joinTableRowId = this.relation.joinTable + '.' + SQLITE_BUILTIN_ROW_ID; | ||
let ownerId = this.owner.$values(this.relation.ownerProp); | ||
let fullRelatedCol = this.relation.fullRelatedCol; | ||
let fullRelatedCol = this.relation.fullRelatedCol(builder); | ||
@@ -32,5 +32,5 @@ let selectRelatedQuery = this.relation.relatedModelClass | ||
.modify(this.relation.modify) | ||
.whereComposite(this.relation.fullJoinTableOwnerCol, ownerId) | ||
.whereComposite(this.relation.fullJoinTableOwnerCol(builder), ownerId) | ||
.join(joinTableAsAlias, join => { | ||
const fullJoinTableRelatedCol = this.relation.fullJoinTableRelatedCol; | ||
const fullJoinTableRelatedCol = this.relation.fullJoinTableRelatedCol(builder); | ||
@@ -37,0 +37,0 @@ for (let i = 0, l = fullJoinTableRelatedCol.length; i < l; ++i) { |
'use strict'; | ||
const _ = require('lodash'); | ||
const path = require('path'); | ||
const sortBy = require('lodash/sortBy'); | ||
const values = require('lodash/values'); | ||
const compact = require('lodash/compact'); | ||
const isEmpty = require('lodash/isEmpty'); | ||
const isSubclassOf = require('../utils/classUtils').isSubclassOf; | ||
const resolveModel = require('../utils/resolveModel').resolveModel | ||
const QueryBuilder = require('../queryBuilder/QueryBuilder'); | ||
const getModel = () => require('../model/Model'); | ||
@@ -24,5 +29,2 @@ const RelationFindOperation = require('./RelationFindOperation'); | ||
this.relatedProp = null; | ||
this.fullRelatedCol = null; | ||
this.fullOwnerCol = null; | ||
this.relatedTableAlias = null; | ||
@@ -35,4 +37,2 @@ this.joinTable = null; | ||
this.joinTableExtras = []; | ||
this.fullJoinTableOwnerCol = null; | ||
this.fullJoinTableRelatedCol = null; | ||
@@ -43,25 +43,28 @@ this.modify = null; | ||
setMapping(mapping) { | ||
// Avoid require loop and import here. | ||
let Model = require(__dirname + '/../model/Model'); | ||
const Model = getModel(); | ||
if (!isSubclassOf(this.ownerModelClass, Model)) { | ||
this.throwError('Relation\'s owner is not a subclass of Model'); | ||
throw this.createError('Relation\'s owner is not a subclass of Model'); | ||
} | ||
if (!mapping.modelClass) { | ||
this.throwError('modelClass is not defined'); | ||
throw this.createError('modelClass is not defined'); | ||
} | ||
this.relatedModelClass = this.resolveModel(Model, mapping.modelClass, 'modelClass'); | ||
try { | ||
this.relatedModelClass = resolveModel(mapping.modelClass, this.ownerModelClass.modelPaths, 'modelClass'); | ||
} catch (err) { | ||
throw this.createError(err.message); | ||
} | ||
if (!mapping.relation) { | ||
this.throwError('relation is not defined'); | ||
throw this.createError('relation is not defined'); | ||
} | ||
if (!isSubclassOf(mapping.relation, Relation)) { | ||
this.throwError('relation is not a subclass of Relation'); | ||
throw this.createError('relation is not a subclass of Relation'); | ||
} | ||
if (!mapping.join || !mapping.join.from || !mapping.join.to) { | ||
this.throwError('join must be an object that maps the columns of the related models together. For example: {from: "SomeTable.id", to: "SomeOtherTable.someModelId"}'); | ||
throw this.createError('join must be an object that maps the columns of the related models together. For example: {from: "SomeTable.id", to: "SomeOtherTable.someModelId"}'); | ||
} | ||
@@ -75,8 +78,8 @@ | ||
if (!joinFrom.table || _.isEmpty(joinFrom.columns)) { | ||
this.throwError('join.from must have format TableName.columnName. For example "SomeTable.id" or in case of composite key ["SomeTable.a", "SomeTable.b"].'); | ||
if (!joinFrom.table || isEmpty(joinFrom.columns)) { | ||
throw this.createError('join.from must have format TableName.columnName. For example "SomeTable.id" or in case of composite key ["SomeTable.a", "SomeTable.b"].'); | ||
} | ||
if (!joinTo.table || _.isEmpty(joinTo.columns)) { | ||
this.throwError('join.to must have format TableName.columnName. For example "SomeTable.id" or in case of composite key ["SomeTable.a", "SomeTable.b"].'); | ||
if (!joinTo.table || isEmpty(joinTo.columns)) { | ||
throw this.createError('join.to must have format TableName.columnName. For example "SomeTable.id" or in case of composite key ["SomeTable.a", "SomeTable.b"].'); | ||
} | ||
@@ -91,7 +94,7 @@ | ||
} else { | ||
this.throwError('join: either `from` or `to` must point to the owner model table.'); | ||
throw this.createError('join: either `from` or `to` must point to the owner model table.'); | ||
} | ||
if (joinRelated.table !== this.relatedModelClass.tableName) { | ||
this.throwError('join: either `from` or `to` must point to the related model table.'); | ||
throw this.createError('join: either `from` or `to` must point to the related model table.'); | ||
} | ||
@@ -104,8 +107,31 @@ | ||
this.modify = this.parseModify(mapping); | ||
} | ||
this.fullRelatedCol = this.relatedCol.map(col => this.relatedModelClass.tableName + '.' + col); | ||
this.fullOwnerCol = this.ownerCol.map(col => this.ownerModelClass.tableName + '.' + col); | ||
this.relatedTableAlias = this.relatedModelClass.tableName + '_rel_' + this.name; | ||
fullRelatedCol(builder) { | ||
const table = builder.tableRefFor(this.relatedModelClass); | ||
const col = new Array(this.relatedCol.length); | ||
for (let i = 0, l = col.length; i < l; ++i) { | ||
col[i] = `${table}.${this.relatedCol[i]}`; | ||
} | ||
return col; | ||
} | ||
fullOwnerCol(builder) { | ||
const table = builder.tableRefFor(this.ownerModelClass); | ||
const col = new Array(this.ownerCol.length); | ||
for (let i = 0, l = col.length; i < l; ++i) { | ||
col[i] = `${table}.${this.ownerCol[i]}`; | ||
} | ||
return col; | ||
} | ||
relatedTableAlias(builder) { | ||
const tableRef = builder.tableRefFor(this.relatedModelClass); | ||
return `${tableRef}_rel_${this.name}`; | ||
} | ||
isOneToOne() { | ||
@@ -131,5 +157,2 @@ return false; | ||
relation.relatedProp = this.relatedProp; | ||
relation.fullRelatedCol = this.fullRelatedCol; | ||
relation.fullOwnerCol = this.fullOwnerCol; | ||
relation.relatedTableAlias = this.relatedTableAlias; | ||
relation.modify = this.modify; | ||
@@ -144,4 +167,2 @@ | ||
relation.joinTableExtras = this.joinTableExtras; | ||
relation.fullJoinTableOwnerCol = this.fullJoinTableOwnerCol; | ||
relation.fullJoinTableRelatedCol = this.fullJoinTableRelatedCol; | ||
@@ -161,3 +182,3 @@ return relation; | ||
findQuery(builder, opt) { | ||
const fullRelatedCol = this.fullRelatedCol; | ||
const fullRelatedCol = this.fullRelatedCol(builder); | ||
@@ -181,10 +202,7 @@ if (opt.isColumnRef) { | ||
opt.joinOperation = opt.joinOperation || 'join'; | ||
opt.relatedTableAlias = opt.relatedTableAlias || this.relatedTableAlias; | ||
opt.relatedTableAlias = opt.relatedTableAlias || this.relatedTableAlias(builder); | ||
opt.relatedJoinSelectQuery = opt.relatedJoinSelectQuery || this.relatedModelClass.query().childQueryOf(builder); | ||
opt.relatedTable = opt.relatedTable || this.relatedModelClass.tableName; | ||
opt.ownerTable = opt.ownerTable || this.ownerModelClass.tableName; | ||
opt.relatedTable = opt.relatedTable || builder.tableNameFor(this.relatedModelClass); | ||
opt.ownerTable = opt.ownerTable || builder.tableRefFor(this.ownerModelClass); | ||
const relatedCol = this.relatedCol.map(col => `${opt.relatedTableAlias}.${col}`); | ||
const ownerCol = this.ownerCol.map(col => `${opt.ownerTable}.${col}`); | ||
let relatedSelect = opt.relatedJoinSelectQuery | ||
@@ -196,3 +214,3 @@ .modify(this.modify) | ||
// No need to join a subquery if the query is `select * from "RelatedTable"`. | ||
relatedSelect = `${this.relatedModelClass.tableName} as ${opt.relatedTableAlias}` | ||
relatedSelect = `${opt.relatedTable} as ${opt.relatedTableAlias}`; | ||
} | ||
@@ -202,4 +220,6 @@ | ||
[opt.joinOperation](relatedSelect, join => { | ||
for (let i = 0, l = relatedCol.length; i < l; ++i) { | ||
join.on(relatedCol[i], '=', ownerCol[i]); | ||
for (let i = 0, l = this.relatedCol.length; i < l; ++i) { | ||
const relatedCol = `${opt.relatedTableAlias}.${this.relatedCol[i]}`; | ||
const ownerCol = `${opt.ownerTable}.${this.ownerCol[i]}`; | ||
join.on(relatedCol, '=', ownerCol); | ||
} | ||
@@ -211,3 +231,3 @@ }); | ||
insert(builder, owner) { | ||
this.throwError('not implemented'); | ||
throw this.createError('not implemented'); | ||
} | ||
@@ -246,3 +266,3 @@ | ||
relate(builder, owner) { | ||
this.throwError('not implemented'); | ||
throw this.createError('not implemented'); | ||
} | ||
@@ -252,3 +272,3 @@ | ||
unrelate(builder, owner) { | ||
this.throwError('not implemented'); | ||
throw this.createError('not implemented'); | ||
} | ||
@@ -264,3 +284,3 @@ | ||
' This is a no-no because ' + column + | ||
' is needed in the relation ' + this.ownerModelClass.tableName + '.' + this.name); | ||
' is needed in the relation ' + this.ownerModelClass.name + '.' + this.name); | ||
} | ||
@@ -274,11 +294,12 @@ | ||
let modify = mapping.modify || mapping.filter; | ||
let type = typeof modify; | ||
if (_.isFunction(modify)) { | ||
if (type === 'function') { | ||
return modify; | ||
} else if (_.isObject(modify)) { | ||
return function (queryBuilder) { | ||
} else if (modify && type === 'object') { | ||
return (queryBuilder) => { | ||
queryBuilder.where(modify); | ||
}; | ||
} else { | ||
return _.noop; | ||
return () => {}; | ||
} | ||
@@ -288,3 +309,3 @@ } | ||
parseReference(ref) { | ||
if (!_.isArray(ref)) { | ||
if (!Array.isArray(ref)) { | ||
ref = [ref]; | ||
@@ -324,10 +345,10 @@ } | ||
models1 = _.compact(models1); | ||
models2 = _.compact(models2); | ||
models1 = compact(models1); | ||
models2 = compact(models2); | ||
if (_.isEmpty(models1) && _.isEmpty(models2)) { | ||
if (isEmpty(models1) && isEmpty(models2)) { | ||
return []; | ||
} | ||
if (!_.isEmpty(models1)) { | ||
if (!isEmpty(models1)) { | ||
modelClass = models1[0].constructor; | ||
@@ -355,63 +376,10 @@ } else { | ||
return _.sortBy(_.values(modelsById), idProperty); | ||
return sortBy(values(modelsById), idProperty); | ||
} | ||
resolveModel(Model, modelClass, logPrefix) { | ||
const requireModel = (path) => { | ||
let ModelClass; | ||
try { | ||
// babel 6 style of exposing es6 exports to commonjs https://github.com/babel/babel/issues/2683 | ||
let module = require(path); | ||
ModelClass = isSubclassOf(module.default, Model) | ||
? module.default | ||
: module; | ||
} catch (err) { | ||
return null; | ||
} | ||
if (!isSubclassOf(ModelClass, Model)) { | ||
return null; | ||
} | ||
return ModelClass; | ||
}; | ||
if (_.isString(modelClass)) { | ||
let ModelClass = null; | ||
if (isAbsolutePath(modelClass)) { | ||
ModelClass = requireModel(modelClass); | ||
} else { | ||
// If the path is not a absolute, try the modelPaths of the owner model class. | ||
_.each(this.ownerModelClass.modelPaths, modelPath => { | ||
ModelClass = requireModel(path.join(modelPath, modelClass)); | ||
if (isSubclassOf(ModelClass, Model)) { | ||
// Break the loop. | ||
return false; | ||
} | ||
}); | ||
} | ||
if (!isSubclassOf(ModelClass, Model)) { | ||
this.throwError(`${logPrefix}: ${modelClass} is an invalid file path to a model class`); | ||
} | ||
return ModelClass; | ||
} else { | ||
if (!isSubclassOf(modelClass, Model)) { | ||
this.throwError(`${logPrefix} is not a subclass of Model or a file path to a module that exports one.`); | ||
} | ||
return modelClass; | ||
} | ||
} | ||
throwError(message) { | ||
createError(message) { | ||
if (this.ownerModelClass && this.ownerModelClass.name && this.name) { | ||
throw new Error(`${this.ownerModelClass.name}.relationMappings.${this.name}: ${message}`); | ||
return new Error(`${this.ownerModelClass.name}.relationMappings.${this.name}: ${message}`); | ||
} else { | ||
throw new Error(`${this.constructor.name}: ${message}`); | ||
return new Error(`${this.constructor.name}: ${message}`); | ||
} | ||
@@ -421,6 +389,2 @@ } | ||
function isAbsolutePath(pth) { | ||
return path.normalize(pth + '/') === path.normalize(path.resolve(pth) + '/'); | ||
} | ||
function containsNonNull(arr) { | ||
@@ -427,0 +391,0 @@ for (let i = 0, l = arr.length; i < l; ++i) { |
@@ -86,3 +86,3 @@ 'use strict'; | ||
const addedSelects = {}; | ||
const cols = this.relation.fullRelatedCol; | ||
const cols = this.relation.fullRelatedCol(builder); | ||
let selects; | ||
@@ -89,0 +89,0 @@ |
'use strict'; | ||
const _ = require('lodash'); | ||
const Promise = require('bluebird'); | ||
@@ -20,4 +19,4 @@ const Model = require('./model/Model'); | ||
if (!isSubclassOf(args[0], Model) && _.isFunction(args[0].transaction)) { | ||
let knex = _.first(args); | ||
if (!isSubclassOf(args[0], Model) && typeof args[0].transaction === 'function') { | ||
let knex = args[0]; | ||
args = args.slice(1); | ||
@@ -33,4 +32,4 @@ | ||
// The last argument should be the callback and all other Model subclasses. | ||
let callback = _.last(args); | ||
let modelClasses = _.take(args, args.length - 1); | ||
let callback = args[args.length - 1]; | ||
let modelClasses = args.slice(0, args.length - 1); | ||
let i; | ||
@@ -44,3 +43,3 @@ | ||
let knex = _.first(modelClasses).knex(); | ||
let knex = modelClasses[0].knex(); | ||
for (i = 0; i < modelClasses.length; ++i) { | ||
@@ -80,3 +79,3 @@ if (modelClasses[i].knex() !== knex) { | ||
if (!knex || !_.isFunction(knex.transaction)) { | ||
if (!knex || typeof knex.transaction !== 'function') { | ||
return Promise.reject(new Error('objection.transaction.start: first argument must be a model class or a knex instance')); | ||
@@ -83,0 +82,0 @@ } |
'use strict'; | ||
const _ = require('lodash'); | ||
const isObject = require('lodash/isObject'); | ||
const zipObject = require('lodash/zipObject'); | ||
@@ -35,3 +36,3 @@ module.exports = (ids, expectedProperties, opt) => { | ||
} | ||
} else if (_.isObject(ids[0])) { | ||
} else if (isObject(ids[0])) { | ||
ret = new Array(ids.length); | ||
@@ -47,3 +48,3 @@ | ||
} | ||
} else if (_.isObject(ids)) { | ||
} else if (isObject(ids)) { | ||
// 2. | ||
@@ -63,3 +64,3 @@ ret = [ids]; | ||
if (Array.isArray(ids)) { | ||
if (_.isObject(ids[0])) { | ||
if (isObject(ids[0])) { | ||
ret = new Array(ids.length); | ||
@@ -79,3 +80,3 @@ | ||
} | ||
} else if (_.isObject(ids)) { | ||
} else if (isObject(ids)) { | ||
// 2. | ||
@@ -109,7 +110,7 @@ ret = [ids]; | ||
return _.zipObject(expectedProperties, ids); | ||
return zipObject(expectedProperties, ids); | ||
} | ||
function ensureObject(ids) { | ||
if (_.isObject(ids)) { | ||
if (isObject(ids)) { | ||
return ids; | ||
@@ -116,0 +117,0 @@ } else { |
{ | ||
"name": "objection", | ||
"version": "0.8.1", | ||
"version": "0.8.2", | ||
"description": "An SQL-friendly ORM for Node.js", | ||
@@ -32,3 +32,3 @@ "main": "lib/objection.js", | ||
"engines": { | ||
"node" : ">=4.0.0" | ||
"node": ">=4.0.0" | ||
}, | ||
@@ -35,0 +35,0 @@ "keywords": [ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
347992
108
10073
1