objection
Advanced tools
Comparing version 0.8.3 to 0.8.4
@@ -12,6 +12,8 @@ 'use strict'; | ||
this.ajv = new Ajv(Object.assign({ | ||
this.ajvOptions = Object.assign({ | ||
useDefaults: true | ||
}, conf.options)); | ||
}, conf.options); | ||
this.ajv = new Ajv(this.ajvOptions); | ||
this.ajvNoDefaults = new Ajv(Object.assign({}, conf.options, { | ||
@@ -35,3 +37,3 @@ useDefaults: false | ||
if (model.$beforeValidate !== model.objectionModelClass.prototype.$beforeValidate) { | ||
if (model.$beforeValidate !== model.$objectionModelClass.prototype.$beforeValidate) { | ||
ctx.jsonSchema = cloneDeep(ctx.jsonSchema); | ||
@@ -68,2 +70,5 @@ ctx.jsonSchema = model.$beforeValidate(ctx.jsonSchema, json, options); | ||
getValidator(ModelClass, jsonSchema, skipRequired) { | ||
// Use the AJV custom serializer if provided. | ||
const serialize = this.ajvOptions.serialize || JSON.stringify; | ||
// Optimization for the common case where jsonSchema is never modified. | ||
@@ -73,3 +78,3 @@ // In that case we don't need to call the costly JSON.stringify. | ||
? 'default' | ||
: JSON.stringify(jsonSchema); | ||
: serialize(jsonSchema); | ||
@@ -76,0 +81,0 @@ let validators = this.cache[key]; |
@@ -5,3 +5,3 @@ 'use strict'; | ||
module.exports = (ModelClass) => { | ||
function inheritModel(ModelClass) { | ||
let inherit = cache[ModelClass.name]; | ||
@@ -24,3 +24,7 @@ | ||
module.exports = { | ||
inheritModel | ||
}; | ||
'use strict'; | ||
const cloneDeep = require('lodash/cloneDeep'); | ||
const difference = require('lodash/difference'); | ||
const flattenDeep = require('lodash/flattenDeep'); | ||
const $id = require('./modelId').$id; | ||
const $set = require('./modelSet').$set; | ||
const $omit = require('./modelFilter').$omit; | ||
const $pick = require('./modelFilter').$pick; | ||
const $clone = require('./modelClone').$clone; | ||
const $toJson = require('./modelToJson').$toJson; | ||
const $values = require('./modelValues').$values; | ||
const $setJson = require('./modelSet').$setJson; | ||
const $propKey = require('./modelValues').$propKey; | ||
const $validate = require('./modelValidate').$validate; | ||
const $toDatabaseJson = require('./modelToJson').$toDatabaseJson; | ||
const $setDatabaseJson = require('./modelSet').$setDatabaseJson; | ||
const bindKnex = require('./modelBindKnex').bindKnex; | ||
const visitModels = require('./modelVisitor').visitModels; | ||
const AjvValidator = require('./AjvValidator'); | ||
const QueryBuilder = require('../queryBuilder/QueryBuilder'); | ||
const inheritModel = require('./inheritModel'); | ||
const NotFoundError = require('./NotFoundError'); | ||
const ValidationError = require('./ValidationError'); | ||
const getJsonAttributes = require('./modelJsonAttributes').getJsonAttributes; | ||
const parseJsonAttributes = require('./modelJsonAttributes').parseJsonAttributes; | ||
const formatJsonAttributes = require('./modelJsonAttributes').formatJsonAttributes; | ||
const idColumnToIdProperty = require('./modelColPropMap').idColumnToIdProperty; | ||
const columnNameToPropertyName = require('./modelColPropMap').columnNameToPropertyName; | ||
const propertyNameToColumnName = require('./modelColPropMap').propertyNameToColumnName; | ||
const defineNonEnumerableProperty = require('./modelUtils').defineNonEnumerableProperty; | ||
@@ -30,16 +46,2 @@ const Relation = require('../relations/Relation'); | ||
const staticHiddenProps = [ | ||
'$$knex', | ||
'$$validator', | ||
'$$jsonSchema', | ||
'$$colToProp', | ||
'$$propToCol', | ||
'$$idColumnArray', | ||
'$$fullIdColumn', | ||
'$$idPropertyArray', | ||
'$$idProperty', | ||
'$$relations', | ||
'$$relationArray' | ||
]; | ||
const JoinEagerAlgorithm = () => { | ||
@@ -59,7 +61,7 @@ return new JoinEagerOperation('eager'); | ||
get isObjectionModel() { | ||
get $isObjectionModel() { | ||
return true; | ||
} | ||
get objectionModelClass() { | ||
get $objectionModelClass() { | ||
return Model; | ||
@@ -69,7 +71,3 @@ } | ||
$id() { | ||
if (arguments.length > 0) { | ||
return setId(this, arguments[0]); | ||
} else { | ||
return getId(this); | ||
} | ||
return $id.apply(this, arguments); | ||
} | ||
@@ -146,30 +144,3 @@ | ||
$validate(json, options) { | ||
json = json || this; | ||
options = options || {}; | ||
if (json instanceof Model) { | ||
// Strip away relations and other internal stuff. | ||
json = clone(json, true, true); | ||
// We can mutate `json` now that we took a copy of it. | ||
options.mutable = true; | ||
} | ||
if (options.skipValidation) { | ||
return json; | ||
} | ||
const ModelClass = this.constructor; | ||
const validator = ModelClass.getValidator(); | ||
const args = { | ||
options: options, | ||
model: this, | ||
json: json, | ||
ctx: Object.create(null) | ||
}; | ||
validator.beforeValidate(args); | ||
json = validator.validate(args); | ||
validator.afterValidate(args); | ||
return json; | ||
return $validate.call(this, json, options); | ||
} | ||
@@ -182,43 +153,7 @@ | ||
$parseDatabaseJson(json) { | ||
const ModelClass = this.constructor; | ||
const jsonAttr = ModelClass.getJsonAttributes(); | ||
if (jsonAttr.length) { | ||
// JSON attributes may be returned as strings depending on the database and | ||
// the database client. Convert them to objects here. | ||
for (let i = 0, l = jsonAttr.length; i < l; ++i) { | ||
const attr = jsonAttr[i]; | ||
const value = json[attr]; | ||
if (typeof value === 'string') { | ||
const parsed = tryParseJson(value); | ||
// tryParseJson returns undefined if parsing failed. | ||
if (parsed !== undefined) { | ||
json[attr] = parsed; | ||
} | ||
} | ||
} | ||
} | ||
return json; | ||
return parseJsonAttributes(json, this.constructor); | ||
} | ||
$formatDatabaseJson(json) { | ||
const ModelClass = this.constructor; | ||
const jsonAttr = ModelClass.getJsonAttributes(); | ||
if (jsonAttr.length) { | ||
// All database clients want JSON columns as strings. Do the conversion here. | ||
for (let i = 0, l = jsonAttr.length; i < l; ++i) { | ||
const attr = jsonAttr[i]; | ||
const value = json[attr]; | ||
if (value && typeof value === 'object') { | ||
json[attr] = JSON.stringify(value); | ||
} | ||
} | ||
} | ||
return json; | ||
return formatJsonAttributes(json, this.constructor); | ||
} | ||
@@ -235,181 +170,81 @@ | ||
$setJson(json, options) { | ||
json = json || {}; | ||
options = options || {}; | ||
if (Object.prototype.toString.call(json) !== '[object Object]') { | ||
throw new Error('You should only pass objects to $setJson method. ' | ||
+ '$setJson method was given an invalid value ' | ||
+ json); | ||
} | ||
json = this.$parseJson(json, options); | ||
json = this.$validate(json, options); | ||
this.$set(json); | ||
if (!options.skipParseRelations) { | ||
parseRelationsIntoModelInstances(this, json, options); | ||
} | ||
return $setJson.call(this, json, options); | ||
} | ||
$setDatabaseJson(json) { | ||
json = this.$parseDatabaseJson(json); | ||
if (json) { | ||
const keys = Object.keys(json); | ||
for (let i = 0, l = keys.length; i < l; ++i) { | ||
const key = keys[i]; | ||
this[key] = json[key]; | ||
} | ||
} | ||
return this; | ||
return $setDatabaseJson.call(this, json); | ||
} | ||
$set(obj) { | ||
if (obj) { | ||
const keys = Object.keys(obj); | ||
for (let i = 0, l = keys.length; i < l; ++i) { | ||
const key = keys[i]; | ||
const value = obj[key]; | ||
if (key.charAt(0) !== '$' && typeof value !== 'function') { | ||
this[key] = value; | ||
} | ||
} | ||
} | ||
return this; | ||
return $set.call(this, obj); | ||
} | ||
$toJson(shallow) { | ||
const ModelClass = this.constructor; | ||
if (shallow) { | ||
return toJson(this, false, ModelClass.getRelations(), null); | ||
} else { | ||
return toJson(this, false, null, null); | ||
} | ||
return $toJson.call(this, shallow); | ||
} | ||
toJSON() { | ||
return this.$toJson(false); | ||
return $toJson.call(this, false); | ||
} | ||
$toDatabaseJson() { | ||
const ModelClass = this.constructor; | ||
const jsonSchema = ModelClass.getJsonSchema(); | ||
return $toDatabaseJson.call(this); | ||
} | ||
if (jsonSchema && ModelClass.pickJsonSchemaProperties) { | ||
return toJson(this, true, null, jsonSchema.properties); | ||
} else { | ||
return toJson(this, true, ModelClass.getRelations(), null); | ||
} | ||
$beforeInsert(queryContext) { | ||
// Do nothing by default. | ||
} | ||
$beforeInsert(queryContext) {} | ||
$afterInsert(queryContext) {} | ||
$beforeUpdate(opt, queryContext) {} | ||
$afterUpdate(opt, queryContext) {} | ||
$afterGet(queryContext) {} | ||
$beforeDelete(queryContext) {} | ||
$afterDelete(queryContext) {} | ||
$afterInsert(queryContext) { | ||
// Do nothing by default. | ||
} | ||
$traverse(filterConstructor, callback) { | ||
if (callback === undefined) { | ||
callback = filterConstructor; | ||
filterConstructor = null; | ||
} | ||
$beforeUpdate(opt, queryContext) { | ||
// Do nothing by default. | ||
} | ||
this.constructor.traverse(filterConstructor, this, callback); | ||
return this; | ||
$afterUpdate(opt, queryContext) { | ||
// Do nothing by default. | ||
} | ||
$omit() { | ||
if (arguments.length === 1 && arguments[0] && typeof arguments[0] === 'object') { | ||
const keys = arguments[0]; | ||
$afterGet(queryContext) { | ||
// Do nothing by default. | ||
} | ||
if (Array.isArray(keys)) { | ||
omitArray(this, keys); | ||
} else { | ||
omitObject(this, keys); | ||
} | ||
} else { | ||
const keys = new Array(arguments.length); | ||
$beforeDelete(queryContext) { | ||
// Do nothing by default. | ||
} | ||
for (let i = 0, l = keys.length; i < l; ++i) { | ||
keys[i] = arguments[i]; | ||
} | ||
$afterDelete(queryContext) { | ||
// Do nothing by default. | ||
} | ||
omitArray(this, keys); | ||
} | ||
return this; | ||
$omit() { | ||
return $omit.apply(this, arguments); | ||
} | ||
$pick() { | ||
if (arguments.length === 1 && arguments[0] && typeof arguments[0] === 'object') { | ||
const keys = arguments[0]; | ||
if (Array.isArray(keys)) { | ||
pickArray(this, keys); | ||
} else { | ||
pickObject(this, keys); | ||
} | ||
} else { | ||
const keys = new Array(arguments.length); | ||
for (let i = 0, l = keys.length; i < l; ++i) { | ||
keys[i] = arguments[i]; | ||
} | ||
pickArray(this, keys); | ||
} | ||
return this; | ||
return $pick.apply(this, arguments); | ||
} | ||
$values() { | ||
if (arguments.length === 0) { | ||
return Object.keys(this).map(key => this[key]); | ||
} else { | ||
if (arguments.length === 1 && Array.isArray(arguments[0])) { | ||
return values(this, arguments[0]); | ||
} else { | ||
const args = new Array(arguments.length); | ||
for (let i = 0, l = args.length; i < l; ++i) { | ||
args[i] = arguments[i]; | ||
} | ||
return values(this, args); | ||
} | ||
} | ||
return $values.apply(this, arguments); | ||
} | ||
$propKey(props) { | ||
switch (props.length) { | ||
case 1: return this[props[0]] + ''; | ||
case 2: return this[props[0]] + ',' + this[props[1]]; | ||
case 3: return this[props[0]] + ',' + this[props[1]] + ',' + this[props[2]]; | ||
default: { | ||
// Needs to be `var` instead of `let` to prevent a weird optimization bailout. | ||
var key = ''; | ||
return $propKey.apply(this, arguments); | ||
} | ||
for (let i = 0, l = props.length; i < l; ++i) { | ||
key += this[props[i]]; | ||
$clone(shallow) { | ||
return $clone.call(this, shallow); | ||
} | ||
if (i < props.length - 1) { | ||
key += ','; | ||
} | ||
} | ||
return key; | ||
} | ||
$traverse(filterConstructor, callback) { | ||
if (callback === undefined) { | ||
callback = filterConstructor; | ||
filterConstructor = null; | ||
} | ||
} | ||
$clone(shallow) { | ||
return clone(this, shallow, false); | ||
this.constructor.traverse(filterConstructor, this, callback); | ||
return this; | ||
} | ||
@@ -579,4 +414,6 @@ | ||
const mapping = relationMappings[relationName]; | ||
relations[relationName] = new mapping.relation(relationName, this); | ||
relations[relationName].setMapping(mapping); | ||
return relations; | ||
@@ -648,52 +485,7 @@ }, Object.create(null)); | ||
static bindKnex(knex) { | ||
const ModelClass = this; | ||
// These are defined here to prevent a ridiculous optimization bailout | ||
// because of "Unsupported phi use of const or let variable". | ||
let BoundModelClass, relations, boundRelations, boundRelationArray; | ||
if (!knex.$$objection) { | ||
defineNonEnumerableProperty(knex, '$$objection', { | ||
boundModels: Object.create(null) | ||
}); | ||
} | ||
// 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()]; | ||
} | ||
// Create a new subclass of this class. | ||
BoundModelClass = inheritModel(ModelClass); | ||
for (let i = 0, l = staticHiddenProps.length; i < l; ++i) { | ||
const prop = staticHiddenProps[i]; | ||
if (ModelClass.hasOwnProperty(prop)) { | ||
defineNonEnumerableProperty(BoundModelClass, prop, ModelClass[prop]); | ||
} | ||
} | ||
BoundModelClass.knex(knex); | ||
knex.$$objection.boundModels[ModelClass.uniqueTag()] = BoundModelClass; | ||
relations = ModelClass.getRelationArray(); | ||
boundRelations = Object.create(null); | ||
boundRelationArray = []; | ||
for (let i = 0, l = relations.length; i < l; ++i) { | ||
const relation = relations[i]; | ||
const boundRelation = relation.bindKnex(knex); | ||
boundRelations[relation.name] = boundRelation; | ||
boundRelationArray.push(boundRelation); | ||
} | ||
defineNonEnumerableProperty(BoundModelClass, '$$relations', boundRelations); | ||
defineNonEnumerableProperty(BoundModelClass, '$$relationArray', boundRelationArray); | ||
return BoundModelClass; | ||
return bindKnex(this, knex); | ||
} | ||
static bindTransaction(trx) { | ||
return this.bindKnex(trx); | ||
return bindKnex(this, trx); | ||
} | ||
@@ -783,35 +575,3 @@ | ||
static getJsonAttributes() { | ||
// If the jsonAttributes property is not set, try to create it based | ||
// on the jsonSchema. All properties that are objects or arrays must | ||
// be converted to JSON. | ||
if (!this.jsonAttributes && this.getJsonSchema()) { | ||
this.jsonAttributes = []; | ||
const props = this.getJsonSchema().properties || {}; | ||
const propNames = Object.keys(props); | ||
for (let i = 0, l = propNames.length; i < l; ++i) { | ||
const propName = propNames[i]; | ||
const prop = props[propName]; | ||
let types = ensureArray(prop.type).filter(it => !!it); | ||
if (types.length === 0 && Array.isArray(prop.anyOf)) { | ||
types = flattenDeep(prop.anyOf.map(it => it.type)); | ||
} | ||
if (types.length === 0 && Array.isArray(prop.oneOf)) { | ||
types = flattenDeep(prop.oneOf.map(it => it.type)); | ||
} | ||
if (types.indexOf('object') !== -1 || types.indexOf('array') !== -1) { | ||
this.jsonAttributes.push(propName); | ||
} | ||
} | ||
} | ||
if (!Array.isArray(this.jsonAttributes)) { | ||
this.jsonAttributes = []; | ||
} | ||
return this.jsonAttributes; | ||
return getJsonAttributes(this); | ||
} | ||
@@ -851,45 +611,2 @@ } | ||
function setId(model, id) { | ||
const idProp = model.constructor.getIdProperty(); | ||
const isArray = Array.isArray(idProp); | ||
if (Array.isArray(id)) { | ||
if (isArray) { | ||
if (id.length !== idProp.length) { | ||
throw new Error('trying to set an invalid identifier for a model'); | ||
} | ||
for (let i = 0; i < id.length; ++i) { | ||
model[idProp[i]] = id[i]; | ||
} | ||
} else { | ||
if (id.length !== 1) { | ||
throw new Error('trying to set an invalid identifier for a model'); | ||
} | ||
model[idProp] = id[0]; | ||
} | ||
} else { | ||
if (isArray) { | ||
if (idProp.length > 1) { | ||
throw new Error('trying to set an invalid identifier for a model'); | ||
} | ||
model[idProp[0]] = id; | ||
} else { | ||
model[idProp] = id; | ||
} | ||
} | ||
} | ||
function getId(model) { | ||
const idProp = model.constructor.getIdProperty(); | ||
if (Array.isArray(idProp)) { | ||
return model.$values(idProp); | ||
} else { | ||
return model[idProp]; | ||
} | ||
} | ||
function getIdColumnArray(ModelClass) { | ||
@@ -920,363 +637,2 @@ if (Array.isArray(ModelClass.idColumn)) { | ||
function parseRelationsIntoModelInstances(model, json, options) { | ||
const ModelClass = model.constructor; | ||
const relations = ModelClass.getRelationArray(); | ||
for (let i = 0, l = relations.length; i < l; ++i) { | ||
const relation = relations[i]; | ||
const relationName = relation.name; | ||
const relationJson = json[relationName]; | ||
if (relationJson !== undefined) { | ||
if (Array.isArray(relationJson)) { | ||
model[relationName] = relation.relatedModelClass.ensureModelArray(relationJson, options); | ||
} else if (relationJson) { | ||
model[relationName] = relation.relatedModelClass.ensureModel(relationJson, options); | ||
} else { | ||
model[relationName] = null; | ||
} | ||
} | ||
} | ||
} | ||
function tryParseJson(maybeJsonStr) { | ||
try { | ||
return JSON.parse(maybeJsonStr); | ||
} catch (err) { | ||
// Ignore error. | ||
} | ||
return undefined; | ||
} | ||
function toJson(model, createDbJson, omit, pick) { | ||
const json = toJsonImpl(model, createDbJson, omit, pick); | ||
if (createDbJson) { | ||
return model.$formatDatabaseJson(json); | ||
} else { | ||
return model.$formatJson(json); | ||
} | ||
} | ||
function toJsonImpl(model, createDbJson, omit, pick) { | ||
if (createDbJson) { | ||
return toDatabaseJsonImpl(model, omit, pick); | ||
} else { | ||
return toExternalJsonImpl(model, omit, pick); | ||
} | ||
} | ||
function toDatabaseJsonImpl(model, omit, pick) { | ||
const json = {}; | ||
const omitFromJson = model.$omitFromDatabaseJson(); | ||
const keys = Object.keys(model); | ||
for (let i = 0, l = keys.length; i < l; ++i) { | ||
const key = keys[i]; | ||
assignJsonValue(json, key, model[key], omit, pick, omitFromJson, true); | ||
} | ||
return json; | ||
} | ||
function toExternalJsonImpl(model, omit, pick) { | ||
const json = {}; | ||
const omitFromJson = model.$omitFromJson(); | ||
const keys = Object.keys(model); | ||
const vAttr = model.constructor.virtualAttributes; | ||
for (let i = 0, l = keys.length; i < l; ++i) { | ||
const key = keys[i]; | ||
const value = model[key]; | ||
assignJsonValue(json, key, value, omit, pick, omitFromJson, false); | ||
} | ||
if (vAttr) { | ||
assignVirtualAttributes(json, model, vAttr, omit, pick, omitFromJson); | ||
} | ||
return json; | ||
} | ||
function assignVirtualAttributes(json, model, vAttr, omit, pick, omitFromJson) { | ||
for (let i = 0, l = vAttr.length; i < l; ++i) { | ||
const key = vAttr[i]; | ||
let value = model[key]; | ||
if (typeof value === 'function') { | ||
value = value.call(model); | ||
} | ||
assignJsonValue(json, key, value, omit, pick, omitFromJson, false); | ||
} | ||
} | ||
function assignJsonValue(json, key, value, omit, pick, omitFromJson, createDbJson) { | ||
const type = typeof value; | ||
if (key.charAt(0) !== '$' | ||
&& type !== 'function' | ||
&& type !== 'undefined' | ||
&& (!omit || !omit[key]) | ||
&& (!pick || pick[key]) | ||
&& (!omitFromJson || !contains(omitFromJson, key))) { | ||
if (value !== null && type === 'object') { | ||
json[key] = toJsonObject(value, createDbJson); | ||
} else { | ||
json[key] = value; | ||
} | ||
} | ||
} | ||
function toJsonObject(value, createDbJson) { | ||
if (Array.isArray(value)) { | ||
return toJsonArray(value, createDbJson); | ||
} else if (value instanceof Model) { | ||
if (createDbJson) { | ||
return value.$toDatabaseJson(); | ||
} else { | ||
return value.$toJson(); | ||
} | ||
} else if (Buffer.isBuffer(value)) { | ||
return value; | ||
} else { | ||
return cloneDeep(value); | ||
} | ||
} | ||
function toJsonArray(value, createDbJson) { | ||
const ret = new Array(value.length); | ||
for (let i = 0, l = ret.length; i < l; ++i) { | ||
ret[i] = toJsonObject(value[i], createDbJson) | ||
} | ||
return ret; | ||
} | ||
function clone(model, shallow, stripInternal) { | ||
let clone = null; | ||
const omitFromJson = model.$omitFromJson(); | ||
const omitFromDatabaseJson = model.$omitFromDatabaseJson(); | ||
if (!shallow && !stripInternal) { | ||
clone = cloneSimple(model); | ||
} else { | ||
clone = cloneWithOpt(model, shallow, stripInternal); | ||
} | ||
if (omitFromJson) { | ||
clone.$omitFromJson(omitFromJson); | ||
} | ||
if (omitFromDatabaseJson) { | ||
clone.$omitFromDatabaseJson(omitFromDatabaseJson); | ||
} | ||
return clone; | ||
} | ||
function cloneSimple(model) { | ||
const clone = new model.constructor(); | ||
const keys = Object.keys(model); | ||
for (let i = 0, l = keys.length; i < l; ++i) { | ||
const key = keys[i]; | ||
const value = model[key]; | ||
if (value !== null && typeof value === 'object') { | ||
clone[key] = cloneObject(value); | ||
} else { | ||
clone[key] = value; | ||
} | ||
} | ||
return clone; | ||
} | ||
function cloneWithOpt(model, shallow, stripInternal) { | ||
const clone = new model.constructor(); | ||
const keys = Object.keys(model); | ||
const relations = model.constructor.getRelations(); | ||
for (let i = 0, l = keys.length; i < l; ++i) { | ||
const key = keys[i]; | ||
const value = model[key]; | ||
if (shallow && relations[key]) { | ||
continue; | ||
} | ||
if (stripInternal && key.charAt(0) === '$') { | ||
continue; | ||
} | ||
if (value !== null && typeof value === 'object') { | ||
clone[key] = cloneObject(value); | ||
} else { | ||
clone[key] = value; | ||
} | ||
} | ||
return clone; | ||
} | ||
function cloneObject(value) { | ||
if (Array.isArray(value)) { | ||
return cloneArray(value); | ||
} else if (value instanceof Model) { | ||
return clone(value, false, false); | ||
} else if (Buffer.isBuffer(value)) { | ||
return new Buffer(value); | ||
} else { | ||
return cloneDeep(value); | ||
} | ||
} | ||
function cloneArray(value) { | ||
const ret = new Array(value.length); | ||
for (let i = 0, l = ret.length; i < l; ++i) { | ||
ret[i] = cloneObject(value[i]) | ||
} | ||
return ret; | ||
} | ||
function omitObject(model, keyObj) { | ||
const ModelClass = model.constructor; | ||
const keys = Object.keys(keyObj); | ||
for (let i = 0, l = keys.length; i < l; ++i) { | ||
const key = keys[i]; | ||
const value = keyObj[key]; | ||
if (value && key.charAt(0) !== '$' && model.hasOwnProperty(key)) { | ||
ModelClass.omitImpl(model, key); | ||
} | ||
} | ||
} | ||
function omitArray(model, keys) { | ||
const ModelClass = model.constructor; | ||
for (let i = 0, l = keys.length; i < l; ++i) { | ||
const key = keys[i]; | ||
if (key.charAt(0) !== '$' && model.hasOwnProperty(key)) { | ||
ModelClass.omitImpl(model, key); | ||
} | ||
} | ||
} | ||
function pickObject(model, keyObj) { | ||
const ModelClass = model.constructor; | ||
const keys = Object.keys(model); | ||
for (let i = 0, l = keys.length; i < l; ++i) { | ||
const key = keys[i]; | ||
if (key.charAt(0) !== '$' && !keyObj[key]) { | ||
ModelClass.omitImpl(model, key); | ||
} | ||
} | ||
} | ||
function pickArray(model, pick) { | ||
const ModelClass = model.constructor; | ||
const keys = Object.keys(model); | ||
for (let i = 0, l = keys.length; i < l; ++i) { | ||
const key = keys[i]; | ||
if (key.charAt(0) !== '$' && !contains(pick, key)) { | ||
ModelClass.omitImpl(model, key); | ||
} | ||
} | ||
} | ||
function contains(arr, value) { | ||
for (let i = 0, l = arr.length; i < l; ++i) { | ||
if (arr[i] === value) { | ||
return true; | ||
} | ||
} | ||
return false; | ||
} | ||
function ensureArray(obj) { | ||
if (Array.isArray(obj)) { | ||
return obj; | ||
} else { | ||
return [obj]; | ||
} | ||
} | ||
function values(model, args) { | ||
switch (args.length) { | ||
case 1: return [model[args[0]]]; | ||
case 2: return [model[args[0]], model[args[1]]]; | ||
case 3: return [model[args[0]], model[args[1]], model[args[2]]]; | ||
default: { | ||
const ret = new Array(args.length); | ||
for (let i = 0, l = args.length; i < l; ++i) { | ||
ret[i] = model[args[i]]; | ||
} | ||
return ret; | ||
} | ||
} | ||
} | ||
function columnNameToPropertyName(ModelClass, columnName) { | ||
const model = new ModelClass(); | ||
const addedProps = Object.keys(model.$parseDatabaseJson({})); | ||
const row = {}; | ||
row[columnName] = null; | ||
const props = Object.keys(model.$parseDatabaseJson(row)); | ||
const propertyName = difference(props, addedProps)[0]; | ||
return propertyName || null; | ||
} | ||
function propertyNameToColumnName(ModelClass, propertyName) { | ||
const model = new ModelClass(); | ||
const addedCols = Object.keys(model.$formatDatabaseJson({})); | ||
const obj = {}; | ||
obj[propertyName] = null; | ||
const cols = Object.keys(model.$formatDatabaseJson(obj)); | ||
const columnName = difference(cols, addedCols)[0]; | ||
return columnName || null; | ||
} | ||
function idColumnToIdProperty(ModelClass, idColumn) { | ||
const idProperty = ModelClass.columnNameToPropertyName(idColumn); | ||
if (!idProperty) { | ||
throw new Error(ModelClass.name + '.$parseDatabaseJson probably changes the value of the id column `' + idColumn + '` which is a no-no.'); | ||
} | ||
return idProperty; | ||
} | ||
function defineNonEnumerableProperty(obj, prop, value) { | ||
Object.defineProperty(obj, prop, { | ||
enumerable: false, | ||
writable: true, | ||
configurable: true, | ||
value | ||
}); | ||
} | ||
module.exports = Model; |
@@ -9,2 +9,3 @@ 'use strict'; | ||
validate(args) { | ||
/* istanbul ignore next */ | ||
throw new Error('not implemented'); | ||
@@ -11,0 +12,0 @@ } |
@@ -48,3 +48,3 @@ 'use strict'; | ||
buildForModel(modelClass, model, parentNode, rel, allowedRelations) { | ||
if (!model || !model.isObjectionModel) { | ||
if (!model || !model.$isObjectionModel) { | ||
throw modelClass.createValidationError({notModel: 'not a model'}); | ||
@@ -228,3 +228,3 @@ } | ||
const relations = node.modelClass.getRelations(); | ||
const isModel = obj && obj.isObjectionModel; | ||
const isModel = obj && obj.$isObjectionModel; | ||
const keys = Object.keys(obj); | ||
@@ -231,0 +231,0 @@ |
@@ -22,28 +22,28 @@ 'use strict'; | ||
onBefore(builder, result) { | ||
return this.delegate.onBefore(builder, result); | ||
onBefore1(builder, result) { | ||
return this.delegate.onBefore1(builder, result); | ||
} | ||
hasOnBefore() { | ||
return this.onBefore !== DelegateOperation.prototype.onBefore || this.delegate.hasOnBefore(); | ||
hasOnBefore1() { | ||
return this.onBefore1 !== DelegateOperation.prototype.onBefore1 || this.delegate.hasOnBefore1(); | ||
} | ||
onBeforeInternal(builder, result) { | ||
return this.delegate.onBeforeInternal(builder, result); | ||
onBefore2(builder, result) { | ||
return this.delegate.onBefore2(builder, result); | ||
} | ||
hasOnBeforeInternal() { | ||
return this.onBeforeInternal !== DelegateOperation.prototype.onBeforeInternal || this.delegate.hasOnBeforeInternal(); | ||
hasOnBefore2() { | ||
return this.onBefore2 !== DelegateOperation.prototype.onBefore2 || this.delegate.hasOnBefore2(); | ||
} | ||
onBeforeBuild(builder) { | ||
return this.delegate.onBeforeBuild(builder); | ||
onBefore3(builder, result) { | ||
return this.delegate.onBefore3(builder, result); | ||
} | ||
hasOnBeforeBuild() { | ||
return this.onBeforeBuild !== DelegateOperation.prototype.onBeforeBuild || this.delegate.hasOnBeforeBuild(); | ||
hasOnBefore3() { | ||
return this.onBefore3 !== DelegateOperation.prototype.onBefore3 || this.delegate.hasOnBefore3(); | ||
} | ||
onBuild(knexBuilder, builder) { | ||
return this.delegate.onBuild(knexBuilder, builder); | ||
onBuild(builder) { | ||
return this.delegate.onBuild(builder); | ||
} | ||
@@ -55,2 +55,10 @@ | ||
onBuildKnex(knexBuilder, builder) { | ||
return this.delegate.onBuildKnex(knexBuilder, builder); | ||
} | ||
hasOnBuildKnex() { | ||
return this.onBuildKnex !== DelegateOperation.prototype.onBuildKnex || this.delegate.hasOnBuildKnex(); | ||
} | ||
onRawResult(builder, result) { | ||
@@ -64,24 +72,24 @@ return this.delegate.onRawResult(builder, result); | ||
onAfterQuery(builder, result) { | ||
return this.delegate.onAfterQuery(builder, result); | ||
onAfter1(builder, result) { | ||
return this.delegate.onAfter1(builder, result); | ||
} | ||
hasOnAfterQuery() { | ||
return this.onAfterQuery !== DelegateOperation.prototype.onAfterQuery || this.delegate.hasOnAfterQuery(); | ||
hasOnAfter1() { | ||
return this.onAfter1 !== DelegateOperation.prototype.onAfter1 || this.delegate.hasOnAfter1(); | ||
} | ||
onAfterInternal(builder, result) { | ||
return this.delegate.onAfterInternal(builder, result); | ||
onAfter2(builder, result) { | ||
return this.delegate.onAfter2(builder, result); | ||
} | ||
hasOnAfterInternal() { | ||
return this.onAfterInternal !== DelegateOperation.prototype.onAfterInternal || this.delegate.hasOnAfterInternal(); | ||
hasOnAfter2() { | ||
return this.onAfter2 !== DelegateOperation.prototype.onAfter2 || this.delegate.hasOnAfter2(); | ||
} | ||
onAfter(builder, result) { | ||
return this.delegate.onAfter(builder, result); | ||
onAfter3(builder, result) { | ||
return this.delegate.onAfter3(builder, result); | ||
} | ||
hasOnAfter() { | ||
return this.onAfter !== DelegateOperation.prototype.onAfter || this.delegate.hasOnAfter(); | ||
hasOnAfter3() { | ||
return this.onAfter3 !== DelegateOperation.prototype.onAfter3 || this.delegate.hasOnAfter3(); | ||
} | ||
@@ -88,0 +96,0 @@ |
@@ -17,3 +17,3 @@ 'use strict'; | ||
onBeforeBuild(builder) { | ||
onBuild(builder) { | ||
builder.whereComposite(builder.fullIdColumnFor(builder.modelClass()), this.id).delete(); | ||
@@ -20,0 +20,0 @@ } |
@@ -12,3 +12,3 @@ 'use strict'; | ||
onBuild(knexBuilder, builder) { | ||
onBuildKnex(knexBuilder) { | ||
knexBuilder.delete(); | ||
@@ -15,0 +15,0 @@ } |
@@ -41,7 +41,7 @@ 'use strict'; | ||
onBeforeInternal(builder) { | ||
onBefore2(builder) { | ||
return this.joinBuilder.fetchColumnInfo(builder); | ||
} | ||
onBeforeBuild(builder) { | ||
onBuild(builder) { | ||
builder.findOptions({ | ||
@@ -48,0 +48,0 @@ callAfterGetDeeply: true |
@@ -134,3 +134,3 @@ 'use strict'; | ||
if (!id) { | ||
if (id === null) { | ||
continue; | ||
@@ -525,3 +525,3 @@ } | ||
if (!val) { | ||
if (isNullOrUndefined(val)) { | ||
return null; | ||
@@ -542,3 +542,3 @@ } else { | ||
if (!val1 || !val2) { | ||
if (isNullOrUndefined(val1) || isNullOrUndefined(val2)) { | ||
return null; | ||
@@ -561,3 +561,3 @@ } else { | ||
if (!val1 || !val2 || !val3) { | ||
if (isNullOrUndefined(val1) || isNullOrUndefined(val2) || isNullOrUndefined(val3)) { | ||
return null; | ||
@@ -577,3 +577,3 @@ } else { | ||
if (!val) { | ||
if (isNullOrUndefined(val)) { | ||
return null; | ||
@@ -589,2 +589,6 @@ } | ||
function isNullOrUndefined(val) { | ||
return val === null || val === undefined; | ||
} | ||
function createFilterQuery(args) { | ||
@@ -591,0 +595,0 @@ const builder = args.builder; |
@@ -60,4 +60,4 @@ 'use strict'; | ||
onBeforeBuild(builder) { | ||
const addedSelects = {}; | ||
onBuild(builder) { | ||
const addedSelects = []; | ||
@@ -73,5 +73,5 @@ // Collect columns that need to be selected for the eager fetch | ||
if (!builder.hasSelectionAs(col, relation.ownerCol[c]) && !addedSelects[col]) { | ||
if (!builder.hasSelectionAs(col, relation.ownerCol[c]) && addedSelects.indexOf(col) === -1) { | ||
this.omitProps.push(relation.ownerProp[c]); | ||
addedSelects[col] = true; | ||
addedSelects.push(col); | ||
} | ||
@@ -81,12 +81,8 @@ } | ||
// This needs to be `var` instead of `let` or `const` to prevent | ||
// bailout because of "Unsupported phi use of const or let variable". | ||
var cols = Object.keys(addedSelects); | ||
if (cols.length) { | ||
builder.select(cols); | ||
if (addedSelects.length) { | ||
builder.select(addedSelects); | ||
} | ||
} | ||
onAfterInternal(builder, result) { | ||
onAfter2(builder, result) { | ||
const modelClass = builder.modelClass(); | ||
@@ -93,0 +89,0 @@ const promises = []; |
@@ -17,3 +17,3 @@ 'use strict'; | ||
onBeforeBuild(builder) { | ||
onBuild(builder) { | ||
builder.whereComposite(builder.fullIdColumnFor(builder.modelClass()), this.id).first(); | ||
@@ -20,0 +20,0 @@ } |
@@ -16,3 +16,3 @@ 'use strict'; | ||
onAfter(builder, results) { | ||
onAfter3(builder, results) { | ||
if (this.opt.dontCallAfterGet) { | ||
@@ -62,3 +62,3 @@ return results; | ||
function callAfterGetForOne(ctx, model, result, deep) { | ||
if (!model || !model.isObjectionModel) { | ||
if (!model || !model.$isObjectionModel) { | ||
return result; | ||
@@ -106,10 +106,10 @@ } | ||
function isRelation(value) { | ||
return (value && value.isObjectionModel) || (Array.isArray(value) | ||
return (value && value.$isObjectionModel) || (Array.isArray(value) | ||
&& value.length | ||
&& value[0] | ||
&& value[0].isObjectionModel); | ||
&& value[0].$isObjectionModel); | ||
} | ||
function doCallAfterGet(ctx, model, result) { | ||
if (model.$afterGet !== model.objectionModelClass.prototype.$afterGet) { | ||
if (model.$afterGet !== model.$objectionModelClass.prototype.$afterGet) { | ||
const maybePromise = model.$afterGet(ctx); | ||
@@ -116,0 +116,0 @@ |
@@ -38,4 +38,4 @@ 'use strict'; | ||
onBuild(builder) { | ||
builder.from.apply(builder, this.args); | ||
onBuildKnex(knexBuilder) { | ||
knexBuilder.from.apply(knexBuilder, this.args); | ||
} | ||
@@ -42,0 +42,0 @@ |
@@ -18,4 +18,4 @@ 'use strict'; | ||
onAfterInternal(builder, inserted) { | ||
const maybePromise = super.onAfterInternal(builder, inserted); | ||
onAfter2(builder, inserted) { | ||
const maybePromise = super.onAfter2(builder, inserted); | ||
@@ -22,0 +22,0 @@ return after(maybePromise, insertedModels => { |
@@ -25,3 +25,3 @@ 'use strict'; | ||
onAfterInternal(builder) { | ||
onAfter2(builder) { | ||
const eager = RelationExpression.fromGraph(this.models); | ||
@@ -28,0 +28,0 @@ const modelClass = this.models[0].constructor; |
@@ -19,3 +19,3 @@ 'use strict'; | ||
// Our delegate operation inherits from `InsertOperation`. Disable the call-time | ||
// validation. We do the validation in onAfterQuery instead. | ||
// validation. We do the validation in onAfter1 instead. | ||
this.delegate.modelOptions.skipValidation = true; | ||
@@ -49,7 +49,7 @@ | ||
onBefore() { | ||
onBefore1() { | ||
// Do nothing. | ||
} | ||
onBeforeInternal() { | ||
onBefore2() { | ||
// Do nothing. We override this with empty implementation so that | ||
@@ -59,3 +59,3 @@ // the $beforeInsert() hooks are not called twice for the root models. | ||
onBeforeBuild() { | ||
onBefore3() { | ||
// Do nothing. | ||
@@ -68,5 +68,9 @@ } | ||
onBuildKnex() { | ||
// Do nothing. | ||
} | ||
// We overrode all other hooks but this one and do all the work in here. | ||
// This is a bit hacky. | ||
onAfterQuery(builder) { | ||
onAfter1(builder) { | ||
// We split the query props from all the models in the graph in the | ||
@@ -91,7 +95,7 @@ // InsertOperation.call method. We need to set the queryProps option | ||
return graphInserter.execute(insertFunc).then(() => { | ||
return super.onAfterQuery(builder, this.models) | ||
return super.onAfter1(builder, this.models) | ||
}); | ||
} | ||
onAfterInternal() { | ||
onAfter2() { | ||
// We override this with empty implementation so that the $afterInsert() hooks | ||
@@ -98,0 +102,0 @@ // are not called twice for the root models. |
@@ -53,3 +53,3 @@ 'use strict'; | ||
onBeforeInternal(builder, result) { | ||
onBefore2(builder, result) { | ||
if (this.models.length > 1 && !isPostgres(builder.knex())) { | ||
@@ -62,3 +62,3 @@ throw new Error('batch insert only works with Postgresql'); | ||
onBuild(knexBuilder, builder) { | ||
onBuildKnex(knexBuilder, builder) { | ||
if (!builder.has(/returning/)) { | ||
@@ -88,3 +88,3 @@ // If the user hasn't specified a `returning` clause, we make sure | ||
onAfterQuery(builder, ret) { | ||
onAfter1(builder, ret) { | ||
if (!Array.isArray(ret) || !ret.length || ret === this.models) { | ||
@@ -117,3 +117,3 @@ // Early exit if there is nothing to do. | ||
onAfterInternal(builder, models) { | ||
onAfter2(builder, models) { | ||
const result = this.isArray ? models : (models[0] || null); | ||
@@ -120,0 +120,0 @@ return mapAfterAllReturn(models, model => model.$afterInsert(builder.context()), result); |
@@ -13,3 +13,3 @@ 'use strict'; | ||
onBeforeInternal(builder, result) { | ||
onBefore2(builder, result) { | ||
const maybePromise = this.instance.$beforeDelete(builder.context()); | ||
@@ -19,8 +19,8 @@ return afterReturn(maybePromise, result); | ||
onBeforeBuild(builder) { | ||
super.onBeforeBuild(builder); | ||
onBuild(builder) { | ||
super.onBuild(builder); | ||
builder.whereComposite(builder.fullIdColumnFor(builder.modelClass()), this.instance.$id()); | ||
} | ||
onAfterInternal(builder, result) { | ||
onAfter2(builder, result) { | ||
const maybePromise = this.instance.$afterDelete(builder.context()); | ||
@@ -27,0 +27,0 @@ return afterReturn(maybePromise, result); |
@@ -12,3 +12,3 @@ 'use strict'; | ||
onBeforeBuild(builder) { | ||
onBuild(builder) { | ||
builder.whereComposite(builder.fullIdColumnFor(builder.modelClass()), this.instance.$id()).first() | ||
@@ -15,0 +15,0 @@ } |
@@ -25,9 +25,9 @@ 'use strict'; | ||
onBeforeBuild(builder) { | ||
super.onBeforeBuild(builder); | ||
onBuild(builder) { | ||
super.onBuild(builder); | ||
builder.whereComposite(builder.fullIdColumnFor(builder.modelClass()), this.instance.$id()); | ||
} | ||
onAfterInternal(builder, numUpdated) { | ||
const maybePromise = super.onAfterInternal(builder, numUpdated); | ||
onAfter2(builder, numUpdated) { | ||
const maybePromise = super.onAfter2(builder, numUpdated); | ||
@@ -34,0 +34,0 @@ return after(maybePromise, result => { |
@@ -22,3 +22,3 @@ 'use strict'; | ||
onBeforeBuild(builder) { | ||
onBuild(builder) { | ||
const modelClass = builder.modelClass(); | ||
@@ -25,0 +25,0 @@ const opt = Object.assign({}, this.callOpt); |
@@ -21,3 +21,3 @@ 'use strict'; | ||
onBuild(knexBuilder) { | ||
onBuildKnex(knexBuilder) { | ||
if (this.opt.bool === 'or') { | ||
@@ -24,0 +24,0 @@ knexBuilder.orWhereRaw(this.sql); |
@@ -21,3 +21,3 @@ 'use strict'; | ||
onBuild(knexBuilder) { | ||
onBuildKnex(knexBuilder) { | ||
if (this.opt.bool === 'or') { | ||
@@ -24,0 +24,0 @@ knexBuilder.orWhereRaw(this.sql); |
@@ -8,3 +8,3 @@ 'use strict'; | ||
onBuild(knexBuilder, builder) { | ||
onBuildKnex(knexBuilder, builder) { | ||
this.whereJsonNotObject(knexBuilder, builder.knex(), this.args[0]); | ||
@@ -11,0 +11,0 @@ } |
@@ -25,3 +25,3 @@ 'use strict'; | ||
onBuild(knexBuilder) { | ||
onBuildKnex(knexBuilder) { | ||
if (this.opt.bool === 'or') { | ||
@@ -28,0 +28,0 @@ knexBuilder.orWhereRaw.apply(knexBuilder, this.rawArgs); |
@@ -7,4 +7,4 @@ 'use strict'; | ||
onBuild(builder) { | ||
builder[this.name].apply(builder, this.args); | ||
onBuildKnex(knexBuilder) { | ||
knexBuilder[this.name].apply(knexBuilder, this.args); | ||
} | ||
@@ -11,0 +11,0 @@ } |
@@ -12,3 +12,3 @@ 'use strict'; | ||
onBeforeBuild(builder) { | ||
onBuild(builder) { | ||
return this.func.call(builder, builder); | ||
@@ -15,0 +15,0 @@ } |
@@ -19,18 +19,18 @@ 'use strict'; | ||
onBefore(builder, result) {} | ||
hasOnBefore() { | ||
return this.onBefore !== QueryBuilderOperation.prototype.onBefore; | ||
onBefore1(builder, result) {} | ||
hasOnBefore1() { | ||
return this.onBefore1 !== QueryBuilderOperation.prototype.onBefore1; | ||
} | ||
onBeforeInternal(builder, result) {} | ||
hasOnBeforeInternal() { | ||
return this.onBeforeInternal !== QueryBuilderOperation.prototype.onBeforeInternal; | ||
onBefore2(builder, result) {} | ||
hasOnBefore2() { | ||
return this.onBefore2 !== QueryBuilderOperation.prototype.onBefore2; | ||
} | ||
onBeforeBuild(builder) {} | ||
hasOnBeforeBuild() { | ||
return this.onBeforeBuild !== QueryBuilderOperation.prototype.onBeforeBuild; | ||
onBefore3(builder, result) {} | ||
hasOnBefore3() { | ||
return this.onBefore3 !== QueryBuilderOperation.prototype.onBefore3; | ||
} | ||
onBuild(knexBuilder, builder) {} | ||
onBuild(builder) {} | ||
hasOnBuild() { | ||
@@ -40,2 +40,7 @@ return this.onBuild !== QueryBuilderOperation.prototype.onBuild; | ||
onBuildKnex(knexBuilder, builder) {} | ||
hasOnBuildKnex() { | ||
return this.onBuildKnex !== QueryBuilderOperation.prototype.onBuildKnex; | ||
} | ||
onRawResult(builder, rows) { return rows; } | ||
@@ -46,15 +51,15 @@ hasOnRawResult() { | ||
onAfterQuery(builder, result) {} | ||
hasOnAfterQuery() { | ||
return this.onAfterQuery !== QueryBuilderOperation.prototype.onAfterQuery; | ||
onAfter1(builder, result) { return result; } | ||
hasOnAfter1() { | ||
return this.onAfter1 !== QueryBuilderOperation.prototype.onAfter1; | ||
} | ||
onAfterInternal(builder, result) {} | ||
hasOnAfterInternal() { | ||
return this.onAfterInternal !== QueryBuilderOperation.prototype.onAfterInternal; | ||
onAfter2(builder, result) { return result; } | ||
hasOnAfter2() { | ||
return this.onAfter2 !== QueryBuilderOperation.prototype.onAfter2; | ||
} | ||
onAfter(builder, result) {} | ||
hasOnAfter() { | ||
return this.onAfter !== QueryBuilderOperation.prototype.onAfter; | ||
onAfter3(builder, result) { return result; } | ||
hasOnAfter3() { | ||
return this.onAfter3 !== QueryBuilderOperation.prototype.onAfter3 | ||
} | ||
@@ -61,0 +66,0 @@ |
@@ -17,3 +17,3 @@ 'use strict'; | ||
// Need to set these here instead of `onBuild` so that they | ||
// Need to set these here instead of `onBuildKnex` so that they | ||
// don't end up in the resultSize query. | ||
@@ -26,3 +26,3 @@ builder.limit(end - start + 1).offset(start); | ||
onBefore(builder) { | ||
onBefore1(builder) { | ||
// Don't return the promise so that it is executed | ||
@@ -34,3 +34,3 @@ // in parallel with the actual query. | ||
onAfter(builder, result) { | ||
onAfter3(builder, result) { | ||
return this.resultSizePromise.then(count => { | ||
@@ -37,0 +37,0 @@ return { |
@@ -25,3 +25,3 @@ 'use strict'; | ||
onBuild(knexBuilder) { | ||
onBuildKnex(knexBuilder) { | ||
// Always pass an array of columns to knex.returning. | ||
@@ -28,0 +28,0 @@ knexBuilder.returning(this.args); |
@@ -12,3 +12,3 @@ 'use strict'; | ||
onAfter(builder, result) { | ||
onAfter3(builder, result) { | ||
return this.func.call(builder, result, builder); | ||
@@ -15,0 +15,0 @@ } |
@@ -12,3 +12,3 @@ 'use strict'; | ||
onBefore(builder, result) { | ||
onBefore1(builder, result) { | ||
return this.func.call(builder, result, builder); | ||
@@ -15,0 +15,0 @@ } |
@@ -72,4 +72,4 @@ 'use strict'; | ||
onBuild(builder) { | ||
builder[this.name].apply(builder, this.args); | ||
onBuildKnex(knexBuilder) { | ||
knexBuilder[this.name].apply(knexBuilder, this.args); | ||
} | ||
@@ -76,0 +76,0 @@ |
@@ -28,11 +28,11 @@ 'use strict'; | ||
onBeforeBuild(builder) { | ||
super.onBeforeBuild(builder); | ||
onBuild(builder) { | ||
super.onBuild(builder); | ||
builder.whereComposite(builder.fullIdColumnFor(builder.modelClass()), this.id); | ||
} | ||
onAfterInternal(builder, numUpdated) { | ||
onAfter2(builder, numUpdated) { | ||
if (numUpdated == 0) { | ||
// If nothing was updated, we should fetch nothing. | ||
return afterReturn(super.onAfterInternal(builder, numUpdated), undefined); | ||
return afterReturn(super.onAfter2(builder, numUpdated), undefined); | ||
} | ||
@@ -53,3 +53,3 @@ | ||
return afterReturn(super.onAfterInternal(builder, numUpdated), retVal); | ||
return afterReturn(super.onAfter2(builder, numUpdated), retVal); | ||
}); | ||
@@ -56,0 +56,0 @@ } |
@@ -43,3 +43,3 @@ 'use strict'; | ||
onBeforeInternal(builder, result) { | ||
onBefore2(builder, result) { | ||
const maybePromise = this.model.$beforeUpdate(this.modelOptions, builder.context()); | ||
@@ -49,3 +49,3 @@ return afterReturn(maybePromise, result); | ||
onBuild(knexBuilder, builder) { | ||
onBuildKnex(knexBuilder, builder) { | ||
// Builder options can contain a queryProps map. Use it | ||
@@ -91,3 +91,3 @@ // if there isn't a local one. | ||
onAfterInternal(builder, numUpdated) { | ||
onAfter2(builder, numUpdated) { | ||
const maybePromise = this.model.$afterUpdate(this.modelOptions, builder.context()); | ||
@@ -94,0 +94,0 @@ return afterReturn(maybePromise, numUpdated); |
@@ -7,3 +7,3 @@ 'use strict'; | ||
onBuild(knexBuilder) { | ||
onBuildKnex(knexBuilder) { | ||
if (this.args.length === 2) { | ||
@@ -10,0 +10,0 @@ this.build(knexBuilder, this.args[0], '=', this.args[1]); |
@@ -7,3 +7,3 @@ 'use strict'; | ||
onBuild(knexBuilder) { | ||
onBuildKnex(knexBuilder) { | ||
this.build(knexBuilder, this.args[0], this.args[1]); | ||
@@ -10,0 +10,0 @@ } |
@@ -7,3 +7,3 @@ 'use strict'; | ||
onBuild(knexBuilder) { | ||
onBuildKnex(knexBuilder) { | ||
this.build(knexBuilder, this.args[0], this.args[1]); | ||
@@ -10,0 +10,0 @@ } |
@@ -7,3 +7,3 @@ 'use strict'; | ||
onBuild(knexBuilder) { | ||
onBuildKnex(knexBuilder) { | ||
if (this.args.length === 2) { | ||
@@ -10,0 +10,0 @@ this.whereRef(knexBuilder, this.args[0], '=', this.args[1]); |
@@ -154,3 +154,3 @@ 'use strict'; | ||
function isModel(item) { | ||
return item != null && item.isObjectionModel; | ||
return item != null && item.$isObjectionModel; | ||
} | ||
@@ -157,0 +157,0 @@ |
@@ -29,2 +29,3 @@ 'use strict'; | ||
const RangeOperation = require('./operations/RangeOperation'); | ||
const FirstOperation = require('./operations/FirstOperation'); | ||
const FromOperation = require('./operations/FromOperation'); | ||
@@ -122,2 +123,17 @@ | ||
modify() { | ||
if (typeof arguments[0] === 'string') { | ||
const namedFilters = this._modelClass.namedFilters; | ||
for (let i = 0, l = arguments.length; i < l; ++i) { | ||
const filter = namedFilters[arguments[i]]; | ||
filter(this); | ||
} | ||
return this; | ||
} else { | ||
return super.modify.apply(this, arguments); | ||
} | ||
} | ||
reject(error) { | ||
@@ -207,2 +223,10 @@ this._explicitRejectValue = error; | ||
joinEager(exp, filters) { | ||
return this.eagerAlgorithm(this._modelClass.JoinEagerAlgorithm).eager(exp, filters); | ||
} | ||
naiveEager(exp, filters) { | ||
return this.eagerAlgorithm(this._modelClass.NaiveEagerAlgorithm).eager(exp, filters); | ||
} | ||
mergeEager(exp, filters) { | ||
@@ -225,2 +249,10 @@ if (!this._eagerExpression) { | ||
mergeJoinEager(exp, filters) { | ||
return this.eagerAlgorithm(this._modelClass.JoinEagerAlgorithm).mergeEager(exp, filters); | ||
} | ||
mergeNaiveEager(exp, filters) { | ||
return this.eagerAlgorithm(this._modelClass.NaiveEagerAlgorithm).mergeEager(exp, filters); | ||
} | ||
allowEager(exp) { | ||
@@ -446,7 +478,9 @@ this._allowedEagerExpression = exp || null; | ||
promise = chainBeforeOperations(promise, builder._operations); | ||
promise = chainBefore1Operations(promise, builder._operations); | ||
promise = chainHooks(promise, context.runBefore); | ||
promise = chainHooks(promise, internalContext.runBefore); | ||
promise = chainBeforeInternalOperations(promise, builder._operations); | ||
promise = chainBefore2Operations(promise, builder._operations); | ||
promise = chainBefore3Operations(promise, builder._operations); | ||
// Resolve all before hooks before building and executing the query | ||
@@ -474,7 +508,8 @@ // and the rest of the hooks. | ||
promise = chainAfterQueryOperations(promise, builder._operations); | ||
promise = chainAfterInternalOperations(promise, builder._operations); | ||
promise = chainAfter1Operations(promise, builder._operations); | ||
promise = chainAfter2Operations(promise, builder._operations); | ||
promise = chainHooks(promise, context.runAfter); | ||
promise = chainHooks(promise, internalContext.runAfter); | ||
promise = chainAfterOperations(promise, builder._operations); | ||
promise = chainAfter3Operations(promise, builder._operations); | ||
@@ -495,12 +530,2 @@ return promise; | ||
first() { | ||
return this.runAfter(result => { | ||
if (Array.isArray(result)) { | ||
return result[0]; | ||
} else { | ||
return result; | ||
} | ||
}); | ||
} | ||
throwIfNotFound() { | ||
@@ -752,3 +777,8 @@ return this.runAfter((result, builder) => { | ||
findOne() { | ||
return this.where.apply(this, arguments).first(); | ||
} | ||
range(start, end) {} | ||
first() {} | ||
joinRelation(relationName) {} | ||
@@ -793,2 +823,5 @@ innerJoinRelation(relationName) {} | ||
}, { | ||
decorator: queryBuilderOperation(FirstOperation), | ||
properties: ['first'] | ||
}, { | ||
decorator: queryBuilderOperation([JoinRelationOperation, {joinOperation: 'join'}]), | ||
@@ -1018,2 +1051,10 @@ properties: ['joinRelation'] | ||
const chainBefore1Operations = createHookCaller('onBefore1'); | ||
const chainBefore2Operations = createHookCaller('onBefore2'); | ||
const chainBefore3Operations = createHookCaller('onBefore3'); | ||
const chainRawResultOperations = createHookCaller('onRawResult'); | ||
const chainAfter1Operations = createHookCaller('onAfter1'); | ||
const chainAfter2Operations = createHookCaller('onAfter2'); | ||
const chainAfter3Operations = createHookCaller('onAfter3'); | ||
function createOperationFactory(OperationClass, name, options) { | ||
@@ -1025,9 +1066,2 @@ return () => { | ||
const chainBeforeOperations = createHookCaller('onBefore'); | ||
const chainBeforeInternalOperations = createHookCaller('onBeforeInternal'); | ||
const chainRawResultOperations = createHookCaller('onRawResult'); | ||
const chainAfterQueryOperations = createHookCaller('onAfterQuery'); | ||
const chainAfterInternalOperations = createHookCaller('onAfterInternal'); | ||
const chainAfterOperations = createHookCaller('onAfter'); | ||
const findOperationFactory = createOperationFactory(FindOperation, 'find'); | ||
@@ -1034,0 +1068,0 @@ const insertOperationFactory = createOperationFactory(InsertOperation, 'insert'); |
@@ -30,3 +30,5 @@ 'use strict'; | ||
modify(func) { | ||
modify() { | ||
const func = arguments[0]; | ||
if (!func) { | ||
@@ -33,0 +35,0 @@ return this; |
@@ -181,7 +181,7 @@ 'use strict'; | ||
op.onBeforeBuild(this); | ||
op.onBuild(this); | ||
const numNew = this._operations.length - ln; | ||
// onBeforeBuild may call methods that add more operations. If | ||
// onBuild may call methods that add more operations. If | ||
// this was the case, move the operations to be executed next. | ||
@@ -212,9 +212,9 @@ if (numNew > 0) { | ||
// onBuild operations should never add new operations. They should only call | ||
// onBuildKnex operations should never add new operations. They should only call | ||
// methods on the knex query builder. | ||
for (let i = 0, l = this._operations.length; i < l; ++i) { | ||
this._operations[i].onBuild(knexBuilder, this); | ||
this._operations[i].onBuildKnex(knexBuilder, this); | ||
if (this._operations.length !== l) { | ||
throw new Error('onBuild should only call query building methods on the knex builder'); | ||
throw new Error('onBuildKnex should only call query building methods on the knex builder'); | ||
} | ||
@@ -221,0 +221,0 @@ } |
@@ -188,3 +188,3 @@ 'use strict'; | ||
const relationName = relationNames[i]; | ||
const node = newNode(relation.name, this.children, this.numChildren); | ||
const node = newNode(relationName, this.children, this.numChildren); | ||
const relation = allRelations[relationName]; | ||
@@ -191,0 +191,0 @@ const childExpr = new RelationExpression(node, 0, this._filters); |
@@ -25,4 +25,4 @@ 'use strict'; | ||
onAfterQuery(builder, inserted) { | ||
const maybePromise = super.onAfterQuery(builder, inserted); | ||
onAfter1(builder, inserted) { | ||
const maybePromise = super.onAfter1(builder, inserted); | ||
@@ -29,0 +29,0 @@ return after(maybePromise, inserted => { |
@@ -32,4 +32,4 @@ 'use strict'; | ||
onAfterQuery(builder, inserted) { | ||
const maybePromise = super.onAfterQuery(builder, inserted); | ||
onAfter1(builder, inserted) { | ||
const maybePromise = super.onAfter1(builder, inserted); | ||
@@ -36,0 +36,0 @@ const isOneToOne = this.relation.isOneToOne(); |
@@ -25,3 +25,3 @@ 'use strict'; | ||
queryExecutor(builder) { | ||
var patch = {}; | ||
const patch = {}; | ||
@@ -28,0 +28,0 @@ for (let i = 0, l = this.relation.relatedProp.length; i < l; ++i) { |
@@ -17,3 +17,3 @@ 'use strict'; | ||
queryExecutor(builder) { | ||
var patch = {}; | ||
const patch = {}; | ||
@@ -20,0 +20,0 @@ for (let i = 0, l = this.relation.relatedProp.length; i < l; ++i) { |
'use strict'; | ||
const DeleteOperation = require('../../queryBuilder/operations/DeleteOperation'); | ||
const ManyToManyHelpersMixin = require('./ManyToManyHelpersMixin'); | ||
class ManyToManyDeleteOperation extends DeleteOperation { | ||
class ManyToManyDeleteOperation extends ManyToManyHelpersMixin(DeleteOperation) { | ||
@@ -14,5 +15,5 @@ constructor(name, opt) { | ||
onBeforeBuild(builder) { | ||
super.onBeforeBuild(builder); | ||
this.relation.selectForModify(builder, this.owner).modify(this.relation.modify); | ||
onBuild(builder) { | ||
super.onBuild(builder); | ||
this.selectForModify(builder, this.owner).modify(this.relation.modify); | ||
} | ||
@@ -19,0 +20,0 @@ } |
'use strict'; | ||
const DeleteOperation = require('../../queryBuilder/operations/DeleteOperation'); | ||
const ManyToManySqliteHelpersMixin = require('./ManyToManySqliteHelpersMixin'); | ||
class ManyToManyDeleteSqliteOperation extends DeleteOperation { | ||
class ManyToManyDeleteSqliteOperation extends ManyToManySqliteHelpersMixin(DeleteOperation) { | ||
@@ -14,5 +15,5 @@ constructor(name, opt) { | ||
onBeforeBuild(builder) { | ||
super.onBeforeBuild(builder); | ||
this.relation.selectForModifySqlite(builder, this.owner).modify(this.relation.modify); | ||
onBuild(builder) { | ||
super.onBuild(builder); | ||
this.selectForModify(builder, this.owner).modify(this.relation.modify); | ||
} | ||
@@ -19,0 +20,0 @@ } |
@@ -27,3 +27,3 @@ 'use strict'; | ||
onBeforeBuild(builder) { | ||
onBuild(builder) { | ||
const relatedModelClass = this.relation.relatedModelClass; | ||
@@ -69,3 +69,3 @@ const ids = new Array(this.owners.length); | ||
onAfterInternal(builder, related) { | ||
onAfter2(builder, related) { | ||
const isOneToOne = this.relation.isOneToOne(); | ||
@@ -72,0 +72,0 @@ const relatedByOwnerId = Object.create(null); |
@@ -18,3 +18,3 @@ 'use strict'; | ||
this.relation.omitExtraProps(this.models); | ||
this.relation.omitExtraProps(this.models, this.queryProps); | ||
@@ -24,4 +24,4 @@ return retVal; | ||
onAfterQuery(builder, inserted) { | ||
const maybePromise = super.onAfterQuery(builder, inserted); | ||
onAfter1(builder, inserted) { | ||
const maybePromise = super.onAfter1(builder, inserted); | ||
@@ -33,4 +33,4 @@ const isOneToOne = this.relation.isOneToOne(); | ||
return after(maybePromise, inserted => { | ||
let ownerId = this.owner.$values(this.relation.ownerProp); | ||
let joinModels = this.relation.createJoinModels(ownerId, inserted); | ||
const ownerId = this.owner.$values(this.relation.ownerProp); | ||
const joinModels = this.relation.createJoinModels(ownerId, inserted); | ||
@@ -37,0 +37,0 @@ if (isOneToOne) { |
'use strict'; | ||
const Relation = require('../Relation'); | ||
const inheritModel = require('../../model/inheritModel'); | ||
const inheritModel = require('../../model/inheritModel').inheritModel; | ||
const resolveModel = require('../../utils/resolveModel').resolveModel | ||
@@ -117,2 +117,4 @@ const isSqlite = require('../../utils/knexUtils').isSqlite; | ||
findQuery(builder, opt) { | ||
const fullJoinTableOwnerCol = this.fullJoinTableOwnerCol(builder); | ||
builder.join(this.joinTable, join => { | ||
@@ -128,24 +130,9 @@ const fullRelatedCol = this.fullRelatedCol(builder); | ||
if (opt.isColumnRef) { | ||
const fullJoinTableOwnerCol = this.fullJoinTableOwnerCol(builder); | ||
for (let i = 0, l = fullJoinTableOwnerCol.length; i < l; ++i) { | ||
builder.whereRef(fullJoinTableOwnerCol[i], opt.ownerIds[i]); | ||
} | ||
} else if (containsNonNull(opt.ownerIds)) { | ||
builder.whereInComposite(fullJoinTableOwnerCol, opt.ownerIds); | ||
} else { | ||
let hasIds = false; | ||
for (let i = 0, l = opt.ownerIds.length; i < l; ++i) { | ||
const id = opt.ownerIds[i]; | ||
if (id) { | ||
hasIds = true; | ||
break; | ||
} | ||
} | ||
if (hasIds) { | ||
builder.whereInComposite(this.fullJoinTableOwnerCol(builder), opt.ownerIds); | ||
} else { | ||
builder.resolve([]); | ||
} | ||
builder.resolve([]); | ||
} | ||
@@ -181,2 +168,3 @@ | ||
const ownerCol = `${opt.ownerTable}.${this.ownerCol[i]}`; | ||
join.on(joinTableOwnerCol, ownerCol); | ||
@@ -189,2 +177,3 @@ } | ||
const relatedCol = `${opt.relatedTableAlias}.${this.relatedCol[i]}`; | ||
join.on(joinTableRelatedCol, relatedCol); | ||
@@ -274,38 +263,2 @@ } | ||
selectForModify(builder, owner) { | ||
let ownerId = owner.$values(this.ownerProp); | ||
let idQuery = this.joinTableModelClass(builder.knex()) | ||
.query() | ||
.childQueryOf(builder) | ||
.select(this.fullJoinTableRelatedCol(builder)) | ||
.whereComposite(this.fullJoinTableOwnerCol(builder), ownerId); | ||
return builder.whereInComposite(this.fullRelatedCol(builder), idQuery); | ||
} | ||
selectForModifySqlite(builder, owner) { | ||
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}`; | ||
const selectRelatedQuery = this.joinTableModelClass(builder.knex()) | ||
.query() | ||
.childQueryOf(builder) | ||
.select(relatedTableAliasRowId) | ||
.whereComposite(this.fullJoinTableOwnerCol(builder), owner.$values(this.ownerProp)) | ||
.join(relatedTableAsAlias, join => { | ||
const fullJoinTableRelatedCols = this.fullJoinTableRelatedCol(builder); | ||
const fullRelatedCol = this.fullRelatedCol(builder); | ||
for (let i = 0, l = fullJoinTableRelatedCols.length; i < l; ++i) { | ||
join.on(fullJoinTableRelatedCols[i], fullRelatedCol[i]); | ||
} | ||
}); | ||
return builder.whereInComposite(relatedTableRowId, selectRelatedQuery); | ||
} | ||
createJoinModels(ownerId, related) { | ||
@@ -341,3 +294,3 @@ const joinModels = new Array(related.length); | ||
omitExtraProps(models) { | ||
omitExtraProps(models, queryProps) { | ||
if (this.joinTableExtras && this.joinTableExtras.length) { | ||
@@ -347,3 +300,19 @@ const props = this.joinTableExtras.map(extra => extra.aliasProp); | ||
for (let i = 0, l = models.length; i < l; ++i) { | ||
// Don't delete the extra properties from the models so that they can | ||
// be used in the `$before` and `$after` hooks. | ||
models[i].$omitFromDatabaseJson(props); | ||
if (queryProps) { | ||
const propObj = queryProps.get(models[i]); | ||
if (propObj) { | ||
for (let j = 0; j < props.length; ++j) { | ||
const prop = props[j]; | ||
if (prop in propObj) { | ||
delete propObj[prop]; | ||
} | ||
} | ||
} | ||
} | ||
} | ||
@@ -374,2 +343,16 @@ } | ||
function containsNonNull(arr) { | ||
for (let i = 0, l = arr.length; i < l; ++i) { | ||
const val = arr[i]; | ||
if (Array.isArray(val) && containsNonNull(val)) { | ||
return true; | ||
} else if (val !== null && val !== undefined) { | ||
return true; | ||
} | ||
} | ||
return false; | ||
} | ||
module.exports = ManyToManyRelation; |
@@ -16,6 +16,6 @@ 'use strict'; | ||
queryExecutor(builder) { | ||
let selectRelatedColQuery = this.relation.relatedModelClass | ||
const selectRelatedColQuery = this.relation.relatedModelClass | ||
.query() | ||
.childQueryOf(builder) | ||
.copyFrom(builder, /where/i) | ||
.copyFrom(builder, builder.constructor.WhereSelector) | ||
.select(this.relation.fullRelatedCol(builder)) | ||
@@ -22,0 +22,0 @@ .modify(this.relation.modify); |
@@ -17,11 +17,11 @@ 'use strict'; | ||
queryExecutor(builder) { | ||
let joinTableAlias = this.relation.joinTableAlias(builder); | ||
let joinTableAsAlias = this.relation.joinTable + ' as ' + joinTableAlias; | ||
let joinTableAliasRowId = joinTableAlias + '.' + SQLITE_BUILTIN_ROW_ID; | ||
let joinTableRowId = this.relation.joinTable + '.' + SQLITE_BUILTIN_ROW_ID; | ||
const joinTableAlias = this.relation.joinTableAlias(builder); | ||
const joinTableAsAlias = this.relation.joinTable + ' as ' + joinTableAlias; | ||
const joinTableAliasRowId = joinTableAlias + '.' + SQLITE_BUILTIN_ROW_ID; | ||
const joinTableRowId = this.relation.joinTable + '.' + SQLITE_BUILTIN_ROW_ID; | ||
let ownerId = this.owner.$values(this.relation.ownerProp); | ||
let fullRelatedCol = this.relation.fullRelatedCol(builder); | ||
const ownerId = this.owner.$values(this.relation.ownerProp); | ||
const fullRelatedCol = this.relation.fullRelatedCol(builder); | ||
let selectRelatedQuery = this.relation.relatedModelClass | ||
const selectRelatedQuery = this.relation.relatedModelClass | ||
.query() | ||
@@ -28,0 +28,0 @@ .childQueryOf(builder) |
'use strict'; | ||
const UpdateOperation = require('../../queryBuilder/operations/UpdateOperation'); | ||
const ManyToManyUpdateOperationBase = require('./ManyToManyUpdateOperationBase'); | ||
const ManyToManyHelpersMixin = require('./ManyToManyHelpersMixin'); | ||
class ManyToManyUpdateOperation extends UpdateOperation { | ||
class ManyToManyUpdateOperation extends ManyToManyHelpersMixin(ManyToManyUpdateOperationBase) { | ||
constructor(name, opt) { | ||
super(name, opt); | ||
onBuild(builder) { | ||
if (this.hasExtraProps) { | ||
// Create the join table patch filter query here before we add our | ||
// own where clauses to it. At this point `builder` should only have | ||
// the user's own wheres. | ||
this.joinTablePatchFilterQuery = this.relation.relatedModelClass | ||
.query() | ||
.childQueryOf(builder) | ||
.select(this.relation.fullRelatedCol(builder)) | ||
.copyFrom(builder, builder.constructor.WhereSelector) | ||
.modify(this.relation.modify); | ||
} | ||
this.relation = opt.relation; | ||
this.owner = opt.owner; | ||
super.onBuild(builder); | ||
this.selectForModify(builder, this.owner).modify(this.relation.modify); | ||
} | ||
onBeforeBuild(builder) { | ||
super.onBeforeBuild(builder); | ||
this.relation.selectForModify(builder, this.owner).modify(this.relation.modify); | ||
onAfter1(builder, result) { | ||
if (this.hasExtraProps) { | ||
return this.relation.joinTableModelClass(builder.knex()) | ||
.query() | ||
.childQueryOf(builder) | ||
.whereComposite(this.relation.fullJoinTableOwnerCol(builder), this.owner.$id()) | ||
.whereInComposite(this.relation.fullJoinTableRelatedCol(builder), this.joinTablePatchFilterQuery) | ||
.patch(this.joinTablePatch) | ||
.return(result); | ||
} else { | ||
return result; | ||
} | ||
} | ||
@@ -18,0 +38,0 @@ } |
'use strict'; | ||
const UpdateOperation = require('../../queryBuilder/operations/UpdateOperation'); | ||
const ManyToManyUpdateOperationBase = require('./ManyToManyUpdateOperationBase'); | ||
const ManyToManySqliteHelpersMixin = require('./ManyToManySqliteHelpersMixin'); | ||
const SQLITE_BUILTIN_ROW_ID = '_rowid_'; | ||
class ManyToManyUpdateSqliteOperation extends UpdateOperation { | ||
class ManyToManyUpdateSqliteOperation extends ManyToManySqliteHelpersMixin(ManyToManyUpdateOperationBase) { | ||
constructor(name, opt) { | ||
super(name, opt); | ||
onBuild(builder) { | ||
if (this.hasExtraProps) { | ||
const joinTableModelClass = this.relation.joinTableModelClass(builder.knex()); | ||
const joinTableName = builder.tableNameFor(joinTableModelClass); | ||
const joinTableAlias = builder.tableRefFor(joinTableModelClass); | ||
const joinTableAsAlias = `${joinTableName} as ${joinTableAlias}`; | ||
this.relation = opt.relation; | ||
this.owner = opt.owner; | ||
// Create the join table patch filter query here before we add our | ||
// own where clauses to it. At this point `builder` should only have | ||
// the user's own wheres. | ||
this.joinTablePatchFilterQuery = this.relation.relatedModelClass | ||
.query() | ||
.childQueryOf(builder) | ||
.select(`${joinTableAlias}.${SQLITE_BUILTIN_ROW_ID}`) | ||
.copyFrom(builder, builder.constructor.WhereSelector) | ||
.join(joinTableAsAlias, join => { | ||
const fullJoinTableRelatedCols = this.relation.fullJoinTableRelatedCol(builder); | ||
const fullRelatedCol = this.relation.fullRelatedCol(builder); | ||
for (let i = 0, l = fullJoinTableRelatedCols.length; i < l; ++i) { | ||
join.on(fullJoinTableRelatedCols[i], fullRelatedCol[i]); | ||
} | ||
}) | ||
.modify(this.relation.modify); | ||
} | ||
super.onBuild(builder); | ||
this.selectForModify(builder, this.owner).modify(this.relation.modify); | ||
} | ||
onBeforeBuild(builder) { | ||
super.onBeforeBuild(builder); | ||
this.relation.selectForModifySqlite(builder, this.owner).modify(this.relation.modify); | ||
onAfter1(builder, result) { | ||
if (this.hasExtraProps) { | ||
const joinTableModelClass = this.relation.joinTableModelClass(builder.knex()); | ||
const joinTableName = builder.tableRefFor(joinTableModelClass); | ||
return joinTableModelClass | ||
.query() | ||
.childQueryOf(builder) | ||
.whereComposite(this.relation.fullJoinTableOwnerCol(builder), this.owner.$id()) | ||
.whereIn(`${joinTableName}.${SQLITE_BUILTIN_ROW_ID}`, this.joinTablePatchFilterQuery) | ||
.patch(this.joinTablePatch) | ||
.return(result); | ||
} else { | ||
return result; | ||
} | ||
} | ||
@@ -18,0 +55,0 @@ } |
@@ -212,2 +212,3 @@ 'use strict'; | ||
const ownerCol = `${opt.ownerTable}.${this.ownerCol[i]}`; | ||
join.on(relatedCol, '=', ownerCol); | ||
@@ -214,0 +215,0 @@ } |
@@ -14,4 +14,4 @@ 'use strict'; | ||
onBeforeBuild(builder) { | ||
super.onBeforeBuild(builder); | ||
onBuild(builder) { | ||
super.onBuild(builder); | ||
@@ -18,0 +18,0 @@ this.relation.findQuery(builder, { |
@@ -30,3 +30,3 @@ 'use strict'; | ||
onBeforeBuild(builder) { | ||
onBuild(builder) { | ||
let ids = new Array(this.owners.length); | ||
@@ -45,8 +45,3 @@ | ||
onAfter(builder, related) { | ||
this.omitImplicitJoinProps(related); | ||
return super.onAfter(builder, related); | ||
} | ||
onAfterInternal(builder, related) { | ||
onAfter2(builder, related) { | ||
const owners = this.owners; | ||
@@ -88,6 +83,10 @@ const isOneToOne = this.relation.isOneToOne(); | ||
onAfter3(builder, related) { | ||
this.omitImplicitJoinProps(related); | ||
return super.onAfter3(builder, related); | ||
} | ||
selectMissingJoinColumns(builder) { | ||
const addedSelects = {}; | ||
const cols = this.relation.fullRelatedCol(builder); | ||
let selects; | ||
const addedSelects = []; | ||
@@ -97,14 +96,10 @@ for (let c = 0, lc = cols.length; c < lc; ++c) { | ||
if (!builder.hasSelectionAs(col, this.relation.relatedCol[c]) && !addedSelects[col]) { | ||
if (!builder.hasSelectionAs(col, this.relation.relatedCol[c]) && addedSelects.indexOf(col) === -1) { | ||
this.omitProps.push(this.relation.relatedProp[c]); | ||
addedSelects[col] = true; | ||
addedSelects.push(col); | ||
} | ||
} | ||
// Don't move the `let` or `const` here to prevent an optimization | ||
// bailout because of "Unsupported phi use of const or let variable". | ||
selects = Object.keys(addedSelects); | ||
if (selects.length) { | ||
builder.select(selects); | ||
if (addedSelects.length) { | ||
builder.select(addedSelects); | ||
} | ||
@@ -111,0 +106,0 @@ } |
@@ -14,4 +14,4 @@ 'use strict'; | ||
onBeforeBuild(builder) { | ||
super.onBeforeBuild(builder); | ||
onBuild(builder) { | ||
super.onBuild(builder); | ||
@@ -18,0 +18,0 @@ this.relation.findQuery(builder, { |
{ | ||
"name": "objection", | ||
"version": "0.8.3", | ||
"version": "0.8.4", | ||
"description": "An SQL-friendly ORM for Node.js", | ||
@@ -5,0 +5,0 @@ "main": "lib/objection.js", |
@@ -531,2 +531,4 @@ // Type definitions for objection v0.6.1 | ||
<T>(knex: knex, callback: (trx: Transaction) => Promise<T>): Promise<T>; | ||
} | ||
@@ -533,0 +535,0 @@ |
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
369089
127
10740