objection
Advanced tools
Comparing version 2.0.0-rc.1 to 2.0.0-rc.2
@@ -121,3 +121,3 @@ 'use strict'; | ||
if (!refNode) { | ||
throw createReferenceFoundError(node, ref); | ||
throw createReferenceNotFoundError(ref); | ||
} | ||
@@ -134,22 +134,7 @@ | ||
for (const node of this.nodes) { | ||
const relationNames = node.modelClass.getRelationNames(); | ||
for (const prop of Object.keys(node.obj)) { | ||
if (relationNames.includes(prop)) { | ||
continue; | ||
} | ||
this._buildPropertyReference(nodesByUid, node, prop); | ||
} | ||
} | ||
} | ||
_buildPropertyReference(nodesByUid, node, prop) { | ||
visitStrings(node.obj[prop], [prop], (str, path) => { | ||
forEachMatch(node.modelClass.propRefRegex, str, match => { | ||
const [_, ref, refPath] = match; | ||
forEachPropertyReference(node.obj, ({ path, refMatch, ref, refPath }) => { | ||
const refNode = nodesByUid.get(ref); | ||
if (!refNode) { | ||
throw createReferenceFoundError(node, ref); | ||
throw createReferenceNotFoundError(ref); | ||
} | ||
@@ -160,9 +145,9 @@ | ||
edge.refType = ModelGraphEdge.ReferenceType.Property; | ||
edge.refMatch = match[0]; | ||
edge.refMatch = refMatch; | ||
edge.refOwnerDataPath = path.slice(); | ||
edge.refRelatedDataPath = refPath.split('.'); | ||
edge.refRelatedDataPath = refPath; | ||
this._addEdge(node, refNode, edge); | ||
}); | ||
}); | ||
} | ||
} | ||
@@ -183,2 +168,20 @@ | ||
function forEachPropertyReference(obj, callback) { | ||
const modelClass = obj.constructor; | ||
const relationNames = modelClass.getRelationNames(); | ||
for (const prop of Object.keys(obj)) { | ||
if (relationNames.includes(prop)) { | ||
continue; | ||
} | ||
visitStrings(obj[prop], [prop], (str, path) => { | ||
forEachMatch(modelClass.propRefRegex, str, match => { | ||
const [refMatch, ref, refPath] = match; | ||
callback({ path, refMatch, ref, refPath: refPath.trim().split('.') }); | ||
}); | ||
}); | ||
} | ||
} | ||
function visitStrings(value, path, visit) { | ||
@@ -219,4 +222,12 @@ if (Array.isArray(value)) { | ||
function createReferenceFoundError(node, ref) { | ||
return new Error('no reference found'); | ||
function createReferenceNotFoundError(ref) { | ||
return new Error( | ||
[ | ||
`could not resolve reference ${ref} in a graph.`, | ||
`If you are sure the #id exist in the same graph,`, | ||
`this may be due to a limitation that a subgraph under a related item`, | ||
`cannot reference an item in a subgraph under another related item.`, | ||
`If you run into this limitation, please open an issue in objection github.` | ||
].join(' ') | ||
); | ||
} | ||
@@ -233,3 +244,4 @@ | ||
ModelGraphBuilder, | ||
createNotModelError | ||
createNotModelError, | ||
forEachPropertyReference | ||
}; |
@@ -5,2 +5,3 @@ 'use strict'; | ||
const { isNumber } = require('../../utils/objectUtils'); | ||
const NOT_CALCULATED = {}; | ||
@@ -14,3 +15,4 @@ | ||
this.userData = {}; | ||
this.hadIdOriginally = obj.$hasId(); | ||
this.hasId = obj.$hasId(); | ||
this.uid = obj[modelClass.uidProp]; | ||
@@ -49,6 +51,2 @@ // These are also included in `edges`. These are simply | ||
get uid() { | ||
return this.obj[this.modelClass.uidProp]; | ||
} | ||
get parentNode() { | ||
@@ -55,0 +53,0 @@ if (this.parentEdge) { |
@@ -20,2 +20,3 @@ 'use strict'; | ||
const { transaction } = require('./transaction'); | ||
const { initialize } = require('./initialize'); | ||
@@ -82,2 +83,3 @@ const { | ||
transaction, | ||
initialize, | ||
compose, | ||
@@ -84,0 +86,0 @@ mixin, |
@@ -9,9 +9,6 @@ 'use strict'; | ||
return [ | ||
new GraphDeleteAction({ | ||
new GraphDeleteAction(this.graphData, { | ||
nodes: this.currentGraph.nodes.filter(currentNode => | ||
this.graphOptions.shouldDeleteOrUnrelate(currentNode, this.graph) | ||
), | ||
graph: this.graph, | ||
graphOptions: this.graphOptions | ||
this.graphOptions.shouldDeleteOrUnrelate(currentNode, this.graphData) | ||
) | ||
}) | ||
@@ -18,0 +15,0 @@ ]; |
@@ -8,9 +8,6 @@ 'use strict'; | ||
class GraphDeleteAction extends GraphAction { | ||
constructor({ nodes, graph, graphOptions }) { | ||
super(); | ||
constructor(graphData, { nodes }) { | ||
super(graphData); | ||
// Nodes to delete. | ||
this.nodes = nodes; | ||
this.graph = graph; | ||
this.graphOptions = graphOptions; | ||
} | ||
@@ -33,3 +30,3 @@ | ||
return !( | ||
this.graphOptions.shouldUnrelate(node, this.graph) && | ||
this.graphOptions.shouldUnrelate(node, this.graphData) && | ||
node.parentEdge.relation.isObjectionBelongsToOneRelation | ||
@@ -48,3 +45,3 @@ ); | ||
nodesByParent.forEach((nodes, parentNode) => { | ||
const shouldUnrelate = this.graphOptions.shouldUnrelate(nodes[0], this.graph); | ||
const shouldUnrelate = this.graphOptions.shouldUnrelate(nodes[0], this.graphData); | ||
@@ -51,0 +48,0 @@ const builder = parentNode.obj.$relatedQuery(relation.name).childQueryOf(parentBuilder); |
@@ -9,2 +9,6 @@ 'use strict'; | ||
class GraphAction { | ||
constructor(graphData) { | ||
this.graphData = graphData; | ||
} | ||
static get ReturningAllSelector() { | ||
@@ -17,2 +21,20 @@ return op => { | ||
static getConcurrency(builder, nodes) { | ||
return nodes.reduce((minConcurrency, node) => { | ||
return Math.min(minConcurrency, node.modelClass.getConcurrency(builder.unsafeKnex())); | ||
}, MAX_CONCURRENCY); | ||
} | ||
get graph() { | ||
return this.graphData.graph; | ||
} | ||
get currentGraph() { | ||
return this.graphData.currentGraph; | ||
} | ||
get graphOptions() { | ||
return this.graphData.graphOptions; | ||
} | ||
run(builder) { | ||
@@ -23,5 +45,3 @@ return null; | ||
_getConcurrency(builder, nodes) { | ||
return nodes.reduce((minConcurrency, node) => { | ||
return Math.min(minConcurrency, node.modelClass.getConcurrency(builder.unsafeKnex())); | ||
}, MAX_CONCURRENCY); | ||
return GraphAction.getConcurrency(builder, nodes); | ||
} | ||
@@ -28,0 +48,0 @@ |
'use strict'; | ||
const { asArray, groupBy } = require('../../utils/objectUtils'); | ||
const { ModelGraph } = require('../../model/graph/ModelGraph'); | ||
const { FetchStrategy } = require('./GraphOptions'); | ||
const { RelationExpression } = require('../RelationExpression'); | ||
class GraphOperation { | ||
constructor({ graph, currentGraph, graphOptions }) { | ||
this.graph = graph; | ||
this.currentGraph = currentGraph; | ||
this.graphOptions = graphOptions; | ||
constructor(graphData) { | ||
this.graphData = graphData; | ||
} | ||
static fetchCurrentGraph({ builder, graph, graphOptions }) { | ||
const rootObjects = graph.rootObjects; | ||
const rootIds = getRootIds(rootObjects); | ||
const modelClass = builder.modelClass(); | ||
get graph() { | ||
return this.graphData.graph; | ||
} | ||
if (rootIds.length === 0) { | ||
return Promise.resolve(ModelGraph.create(modelClass, [])); | ||
} | ||
get currentGraph() { | ||
return this.graphData.currentGraph; | ||
} | ||
const eagerExpr = RelationExpression.fromModelGraph(rootObjects); | ||
return modelClass | ||
.query() | ||
.childQueryOf(builder, childQueryOptions()) | ||
.modify(propagateMethodCallsFromQuery(builder)) | ||
.modify(buildFetchQuerySelects(graph, graphOptions, eagerExpr)) | ||
.findByIds(rootIds) | ||
.withGraphFetched(eagerExpr) | ||
.internalOptions(fetchQueryInternalOptions()) | ||
.then(models => ModelGraph.create(modelClass, models)); | ||
get graphOptions() { | ||
return this.graphData.graphOptions; | ||
} | ||
@@ -40,167 +23,6 @@ | ||
} | ||
shouldRelateAncestor(node) { | ||
if (!node.parentNode) { | ||
return false; | ||
} | ||
return ( | ||
this.graphOptions.shouldRelate(node.parentNode, this.currentGraph) || | ||
this.shouldRelateAncestor(node.parentNode) | ||
); | ||
} | ||
} | ||
function getRootIds(graph) { | ||
return asArray(graph) | ||
.filter(it => it.$hasId()) | ||
.map(root => root.$id()); | ||
} | ||
function propagateMethodCallsFromQuery(builder) { | ||
return fetchBuilder => { | ||
// Propagate some method calls from the root query. | ||
for (const method of ['forUpdate', 'forShare']) { | ||
if (builder.has(method)) { | ||
fetchBuilder[method](); | ||
} | ||
} | ||
}; | ||
} | ||
function buildFetchQuerySelects(graph, graphOptions, eagerExpr) { | ||
return builder => { | ||
const nodesByRelationPath = groupNodesByRelationPath(graph, eagerExpr); | ||
for (const [relationPath, nodes] of nodesByRelationPath.entries()) { | ||
const selectModifier = createFetchSelectModifier(nodes, graphOptions); | ||
if (!relationPath) { | ||
builder.modify(selectModifier); | ||
} else { | ||
builder.modifyEager(relationPath, selectModifier); | ||
} | ||
} | ||
}; | ||
} | ||
function groupNodesByRelationPath(graph, eagerExpr) { | ||
const nodesByRelationPath = groupBy(graph.nodes, node => node.relationPathKey); | ||
// Not all relation paths have nodes. Relations with nulls or empty arrays | ||
// don't have nodes, but will still need to be fetched. Add these to the | ||
// map as empty arrays. | ||
forEachPath(eagerExpr.node, relationPath => { | ||
if (!nodesByRelationPath.has(relationPath)) { | ||
nodesByRelationPath.set(relationPath, []); | ||
} | ||
}); | ||
return nodesByRelationPath; | ||
} | ||
function createFetchSelectModifier(nodes, graphOptions) { | ||
if (graphOptions.isFetchStrategy(FetchStrategy.OnlyIdentifiers)) { | ||
return createIdentifierSelector(); | ||
} else if (graphOptions.isFetchStrategy(FetchStrategy.OnlyNeeded)) { | ||
return createInputColumnSelector(nodes); | ||
} else { | ||
return () => {}; | ||
} | ||
} | ||
// Returns a function that only selects the id column. | ||
function createIdentifierSelector() { | ||
return builder => { | ||
builder.select(builder.fullIdColumn()); | ||
}; | ||
} | ||
// Returns a function that only selects the columns that exist in the input. | ||
function createInputColumnSelector(nodes) { | ||
return builder => { | ||
const selects = new Map(); | ||
for (const node of nodes) { | ||
const databaseJson = node.obj.$toDatabaseJson(builder); | ||
for (const column of Object.keys(databaseJson)) { | ||
if (!shouldSelectColumn(column, selects, node)) { | ||
continue; | ||
} | ||
const selection = | ||
createManyToManyExtraSelectionIfNeeded(builder, column, node) || | ||
createSelection(builder, column, node); | ||
selects.set(column, selection); | ||
} | ||
} | ||
const selectArr = Array.from(selects.values()); | ||
const idColumn = builder.fullIdColumn(); | ||
if (!selectArr.includes(idColumn)) { | ||
// Always select the identifer. | ||
selectArr.push(idColumn); | ||
} | ||
builder.select(selectArr); | ||
}; | ||
} | ||
function shouldSelectColumn(column, selects, node) { | ||
const modelClass = node.modelClass; | ||
return ( | ||
!selects.has(column) && | ||
column !== modelClass.propertyNameToColumnName(modelClass.dbRefProp) && | ||
column !== modelClass.propertyNameToColumnName(modelClass.uidRefProp) && | ||
column !== modelClass.propertyNameToColumnName(modelClass.uidProp) | ||
); | ||
} | ||
function createManyToManyExtraSelectionIfNeeded(builder, column, node) { | ||
if (node.parentEdge && node.parentEdge.relation.isObjectionManyToManyRelation) { | ||
const relation = node.parentEdge.relation; | ||
const extra = relation.joinTableExtras.find(extra => extra.aliasCol === column); | ||
if (extra) { | ||
return `${builder.tableRefFor(relation.joinModelClass)}.${extra.joinTableCol} as ${ | ||
extra.aliasCol | ||
}`; | ||
} | ||
} | ||
return null; | ||
} | ||
function createSelection(builder, column, node) { | ||
return `${builder.tableRefFor(node.modelClass)}.${column}`; | ||
} | ||
function childQueryOptions() { | ||
return { | ||
fork: true, | ||
isInternalQuery: true | ||
}; | ||
} | ||
function fetchQueryInternalOptions() { | ||
return { | ||
keepImplicitJoinProps: true | ||
}; | ||
} | ||
function forEachPath(eagerExprNode, cb, path = []) { | ||
for (const relation of eagerExprNode.$childNames) { | ||
path.push(relation); | ||
cb(path.join('.')); | ||
forEachPath(eagerExprNode[relation], cb, path); | ||
path.pop(); | ||
} | ||
} | ||
module.exports = { | ||
GraphOperation | ||
}; |
@@ -46,2 +46,3 @@ 'use strict'; | ||
// relate things that can be related using inserts. | ||
// TODO: Use a special key for this. | ||
return [NO_DELETE, NO_UPDATE, NO_UNRELATE, INSERT_MISSING].every(opt => { | ||
@@ -53,3 +54,3 @@ return this.options[opt] === true; | ||
// Like `shouldRelate` but ignores settings that explicitly disable relate operations. | ||
shouldRelateIgnoreDisable(node, currentGraph) { | ||
shouldRelateIgnoreDisable(node, graphData) { | ||
if (node.isReference || node.isDbReference) { | ||
@@ -60,31 +61,36 @@ return true; | ||
return ( | ||
!getCurrentNode(node, currentGraph) && | ||
this._hasOption(node, RELATE) && | ||
!getCurrentNode(node, graphData) && | ||
!!node.parentEdge && | ||
!!node.parentEdge.relation && | ||
node.parentEdge.relation.hasRelateProp(node.obj) | ||
node.parentEdge.relation.hasRelateProp(node.obj) && | ||
graphData.nodeDbExistence.doesNodeExistInDb(node) | ||
); | ||
} | ||
shouldRelate(node, currentGraph) { | ||
return !this._hasOption(node, NO_RELATE) && this.shouldRelateIgnoreDisable(node, currentGraph); | ||
shouldRelate(node, graphData) { | ||
return !this._hasOption(node, NO_RELATE) && this.shouldRelateIgnoreDisable(node, graphData); | ||
} | ||
// Like `shouldInsert` but ignores settings that explicitly disable insert operations. | ||
shouldInsertIgnoreDisable(node, currentGraph) { | ||
shouldInsertIgnoreDisable(node, graphData) { | ||
return ( | ||
!getCurrentNode(node, currentGraph) && | ||
!this.shouldRelateIgnoreDisable(node, currentGraph) && | ||
(!node.hadIdOriginally || this._hasOption(node, INSERT_MISSING)) | ||
!getCurrentNode(node, graphData) && | ||
!this.shouldRelateIgnoreDisable(node, graphData) && | ||
(!node.hasId || this.shouldInsertMissing(node)) | ||
); | ||
} | ||
shouldInsert(node, currentGraph) { | ||
return !this._hasOption(node, NO_INSERT) && this.shouldInsertIgnoreDisable(node, currentGraph); | ||
shouldInsert(node, graphData) { | ||
return !this._hasOption(node, NO_INSERT) && this.shouldInsertIgnoreDisable(node, graphData); | ||
} | ||
shouldInsertMissing(node) { | ||
return this._hasOption(node, INSERT_MISSING); | ||
} | ||
// Like `shouldPatch() || shouldUpdate()` but ignores settings that explicitly disable | ||
// update or patch operations. | ||
shouldPatchOrUpdateIgnoreDisable(node, currentGraph) { | ||
if (this.shouldRelate(node)) { | ||
shouldPatchOrUpdateIgnoreDisable(node, graphData) { | ||
if (this.shouldRelate(node, graphData)) { | ||
// We should update all nodes that are going to be related. Note that | ||
@@ -96,8 +102,8 @@ // we don't actually update anything unless there is something to update | ||
return !!getCurrentNode(node, currentGraph); | ||
return !!getCurrentNode(node, graphData); | ||
} | ||
shouldPatch(node, currentGraph) { | ||
shouldPatch(node, graphData) { | ||
return ( | ||
this.shouldPatchOrUpdateIgnoreDisable(node, currentGraph) && | ||
this.shouldPatchOrUpdateIgnoreDisable(node, graphData) && | ||
!this._hasOption(node, NO_UPDATE) && | ||
@@ -108,5 +114,5 @@ !this._hasOption(node, UPDATE) | ||
shouldUpdate(node, currentGraph) { | ||
shouldUpdate(node, graphData) { | ||
return ( | ||
this.shouldPatchOrUpdateIgnoreDisable(node, currentGraph) && | ||
this.shouldPatchOrUpdateIgnoreDisable(node, graphData) && | ||
!this._hasOption(node, NO_UPDATE) && | ||
@@ -122,5 +128,5 @@ this._hasOption(node, UPDATE) | ||
shouldUnrelate(currentNode, graph) { | ||
shouldUnrelate(currentNode, graphData) { | ||
return ( | ||
!getNode(currentNode, graph) && | ||
!getNode(currentNode, graphData.graph) && | ||
!this._hasOption(currentNode, NO_UNRELATE) && | ||
@@ -131,5 +137,5 @@ this.shouldUnrelateIgnoreDisable(currentNode) | ||
shouldDelete(currentNode, graph) { | ||
shouldDelete(currentNode, graphData) { | ||
return ( | ||
!getNode(currentNode, graph) && | ||
!getNode(currentNode, graphData.graph) && | ||
!this._hasOption(currentNode, NO_DELETE) && | ||
@@ -140,8 +146,8 @@ !this.shouldUnrelateIgnoreDisable(currentNode) | ||
shouldInsertOrRelate(node, currentGraph) { | ||
return this.shouldInsert(node, currentGraph) || this.shouldRelate(node, currentGraph); | ||
shouldInsertOrRelate(node, graphData) { | ||
return this.shouldInsert(node, graphData) || this.shouldRelate(node, graphData); | ||
} | ||
shouldDeleteOrUnrelate(currentNode, graph) { | ||
return this.shouldDelete(currentNode, graph) || this.shouldUnrelate(currentNode, graph); | ||
shouldDeleteOrUnrelate(currentNode, graphData) { | ||
return this.shouldDelete(currentNode, graphData) || this.shouldUnrelate(currentNode, graphData); | ||
} | ||
@@ -190,8 +196,8 @@ | ||
function getCurrentNode(node, currentGraph) { | ||
if (!currentGraph || !node) { | ||
function getCurrentNode(node, graphData) { | ||
if (!graphData || !node) { | ||
return null; | ||
} | ||
return currentGraph.nodeForNode(node); | ||
return graphData.currentGraph.nodeForNode(node); | ||
} | ||
@@ -198,0 +204,0 @@ |
@@ -6,10 +6,12 @@ 'use strict'; | ||
const { createNotModelError } = require('../../model/graph/ModelGraphBuilder'); | ||
const { GraphOperation } = require('../graph/GraphOperation'); | ||
const { GraphInsert } = require('../graph/insert/GraphInsert'); | ||
const { GraphPatch } = require('../graph/patch/GraphPatch'); | ||
const { GraphDelete } = require('../graph/delete/GraphDelete'); | ||
const { GraphRecursiveUpsert } = require('../graph/recursiveUpsert/GraphRecursiveUpsert'); | ||
const { GraphOptions } = require('../graph/GraphOptions'); | ||
const { GraphFetcher } = require('../graph/GraphFetcher'); | ||
const { GraphInsert } = require('./insert/GraphInsert'); | ||
const { GraphPatch } = require('./patch/GraphPatch'); | ||
const { GraphDelete } = require('./delete/GraphDelete'); | ||
const { GraphRecursiveUpsert } = require('./recursiveUpsert/GraphRecursiveUpsert'); | ||
const { GraphOptions } = require('./GraphOptions'); | ||
const { ValidationErrorType } = require('../../model/ValidationError'); | ||
const { RelationExpression } = require('../RelationExpression'); | ||
const { GraphNodeDbExistence } = require('./GraphNodeDbExistence'); | ||
const { GraphData } = require('./GraphData'); | ||
const { uniqBy, asArray, isObject } = require('../../utils/objectUtils'); | ||
@@ -37,6 +39,6 @@ | ||
return fetchCurrentGraph(builder, graphOptions, graph) | ||
.then(pruneGraphs(graph, graphOptions)) | ||
.then(checkForErrors(graph, graphOptions, builder)) | ||
.then(executeOperations(graph, graphOptions, builder)) | ||
return createGraphData(builder, graphOptions, graph) | ||
.then(checkForErrors(builder)) | ||
.then(pruneGraphs()) | ||
.then(executeOperations(builder)) | ||
.then(returnResult(this.objects, this.isArray)); | ||
@@ -64,2 +66,15 @@ } | ||
async function createGraphData(builder, graphOptions, graph) { | ||
const currentGraph = await fetchCurrentGraph(builder, graphOptions, graph); | ||
const nodeDbExistence = await GraphNodeDbExistence.create({ | ||
builder, | ||
graph, | ||
graphOptions, | ||
currentGraph | ||
}); | ||
return new GraphData({ graph, currentGraph, graphOptions, nodeDbExistence }); | ||
} | ||
function fetchCurrentGraph(builder, graphOptions, graph) { | ||
@@ -69,3 +84,3 @@ if (graphOptions.isInsertOnly()) { | ||
} else { | ||
return GraphOperation.fetchCurrentGraph({ builder, graph, graphOptions }); | ||
return GraphFetcher.fetchCurrentGraph({ builder, graph, graphOptions }); | ||
} | ||
@@ -77,25 +92,28 @@ } | ||
// deleted or unrelated. We never delete recursively. | ||
function pruneGraphs(graph, graphOptions) { | ||
return currentGraph => { | ||
pruneRelatedBranches(graph, currentGraph, graphOptions); | ||
function pruneGraphs() { | ||
return graphData => { | ||
pruneRelatedBranches(graphData); | ||
if (!graphOptions.isInsertOnly()) { | ||
pruneDeletedBranches(graph, currentGraph); | ||
if (!graphData.graphOptions.isInsertOnly()) { | ||
pruneDeletedBranches(graphData); | ||
} | ||
return currentGraph; | ||
return graphData; | ||
}; | ||
} | ||
function pruneRelatedBranches(graph, currentGraph, graphOptions) { | ||
const relateNodes = graph.nodes.filter(node => { | ||
function pruneRelatedBranches(graphData) { | ||
const relateNodes = graphData.graph.nodes.filter(node => { | ||
return ( | ||
!currentGraph.nodeForNode(node) && !graphOptions.shouldInsertIgnoreDisable(node, currentGraph) | ||
!graphData.currentGraph.nodeForNode(node) && | ||
!graphData.graphOptions.shouldInsertIgnoreDisable(node, graphData) | ||
); | ||
}); | ||
removeBranchesFromGraph(findRoots(relateNodes), graph); | ||
removeBranchesFromGraph(findRoots(relateNodes), graphData.graph); | ||
} | ||
function pruneDeletedBranches(graph, currentGraph) { | ||
function pruneDeletedBranches(graphData) { | ||
const { graph, currentGraph } = graphData; | ||
const deleteNodes = currentGraph.nodes.filter(currentNode => !graph.nodeForNode(currentNode)); | ||
@@ -177,22 +195,24 @@ const roots = findRoots(deleteNodes); | ||
function checkForErrors(graph, graphOptions, builder) { | ||
return currentGraph => { | ||
checkForNotFoundErrors(graph, currentGraph, graphOptions, builder); | ||
checkForUnallowedRelationErrors(graph, builder); | ||
checkForUnallowedReferenceErrors(graph, graphOptions, builder); | ||
function checkForErrors(builder) { | ||
return graphData => { | ||
checkForNotFoundErrors(graphData, builder); | ||
checkForUnallowedRelationErrors(graphData, builder); | ||
checkForUnallowedReferenceErrors(graphData, builder); | ||
if (graphOptions.isInsertOnly()) { | ||
checkForHasManyRelateErrors(graph, currentGraph, graphOptions); | ||
if (graphData.graphOptions.isInsertOnly()) { | ||
checkForHasManyRelateErrors(graphData); | ||
} | ||
return currentGraph; | ||
return graphData; | ||
}; | ||
} | ||
function checkForNotFoundErrors(graph, currentGraph, graphOptions, builder) { | ||
function checkForNotFoundErrors(graphData, builder) { | ||
const { graphOptions, currentGraph, graph } = graphData; | ||
for (const node of graph.nodes) { | ||
if ( | ||
node.obj.$hasId() && | ||
!graphOptions.shouldInsertIgnoreDisable(node, currentGraph) && | ||
!graphOptions.shouldRelateIgnoreDisable(node, currentGraph) && | ||
!graphOptions.shouldInsertIgnoreDisable(node, graphData) && | ||
!graphOptions.shouldRelateIgnoreDisable(node, graphData) && | ||
!currentGraph.nodeForNode(node) | ||
@@ -215,3 +235,4 @@ ) { | ||
function checkForUnallowedRelationErrors(graph, builder) { | ||
function checkForUnallowedRelationErrors(graphData, builder) { | ||
const { graph } = graphData; | ||
const allowedExpression = builder.allowedGraphExpression(); | ||
@@ -232,3 +253,5 @@ | ||
function checkForUnallowedReferenceErrors(graph, graphOptions, builder) { | ||
function checkForUnallowedReferenceErrors(graphData, builder) { | ||
const { graph, graphOptions } = graphData; | ||
if (graphOptions.allowRefs()) { | ||
@@ -247,6 +270,8 @@ return; | ||
function checkForHasManyRelateErrors(graph, currentGraph, graphOptions) { | ||
function checkForHasManyRelateErrors(graphData) { | ||
const { graph, graphOptions } = graphData; | ||
for (const node of graph.nodes) { | ||
if ( | ||
graphOptions.shouldRelate(node, currentGraph) && | ||
graphOptions.shouldRelate(node, graphData) && | ||
node.parentEdge.relation.isObjectionHasManyRelation | ||
@@ -261,10 +286,10 @@ ) { | ||
function executeOperations(graph, graphOptions, builder) { | ||
const operations = graphOptions.isInsertOnly() | ||
? [GraphInsert] | ||
: [GraphDelete, GraphInsert, GraphPatch, GraphRecursiveUpsert]; | ||
function executeOperations(builder) { | ||
return graphData => { | ||
const operations = graphData.graphOptions.isInsertOnly() | ||
? [GraphInsert] | ||
: [GraphDelete, GraphInsert, GraphPatch, GraphRecursiveUpsert]; | ||
return currentGraph => { | ||
return operations.reduce((promise, Operation) => { | ||
const operation = new Operation({ graph, currentGraph, graphOptions }); | ||
const operation = new Operation(graphData); | ||
const actions = operation.createActions(); | ||
@@ -271,0 +296,0 @@ |
@@ -77,7 +77,5 @@ 'use strict'; | ||
actions.push( | ||
new GraphInsertAction({ | ||
new GraphInsertAction(this.graphData, { | ||
nodes: nodesToInsert, | ||
currentGraph: this.currentGraph, | ||
dependencies: this.dependencies, | ||
graphOptions: this.graphOptions | ||
dependencies: this.dependencies | ||
}) | ||
@@ -133,3 +131,3 @@ ); | ||
return [ | ||
new JoinRowGraphInsertAction({ | ||
new JoinRowGraphInsertAction(this.graphData, { | ||
nodes: this.graph.nodes.filter(node => { | ||
@@ -141,6 +139,3 @@ return ( | ||
); | ||
}), | ||
currentGraph: this.currentGraph, | ||
graphOptions: this.graphOptions | ||
}) | ||
}) | ||
@@ -147,0 +142,0 @@ ]; |
@@ -17,10 +17,8 @@ 'use strict'; | ||
class GraphInsertAction extends GraphAction { | ||
constructor({ nodes, currentGraph, dependencies, graphOptions }) { | ||
super(); | ||
constructor(graphData, { nodes, dependencies }) { | ||
super(graphData); | ||
// Nodes to insert. | ||
this.nodes = nodes; | ||
this.currentGraph = currentGraph; | ||
this.dependencies = dependencies; | ||
this.graphOptions = graphOptions; | ||
} | ||
@@ -49,6 +47,6 @@ | ||
_insertBatch(parentBuilder, nodes) { | ||
return this._beforeInsert(nodes) | ||
.then(() => this._insert(parentBuilder, nodes)) | ||
.then(() => this._afterInsert(nodes)); | ||
async _insertBatch(parentBuilder, nodes) { | ||
await this._beforeInsert(nodes); | ||
await this._insert(parentBuilder, nodes); | ||
await this._afterInsert(nodes); | ||
} | ||
@@ -176,3 +174,3 @@ | ||
nodes = nodes.filter(node => { | ||
return this.graphOptions.shouldInsert(node, this.currentGraph); | ||
return this.graphOptions.shouldInsert(node, this.graphData); | ||
}); | ||
@@ -179,0 +177,0 @@ |
@@ -8,8 +8,5 @@ 'use strict'; | ||
class JoinRowGraphInsertAction extends GraphAction { | ||
constructor({ nodes, currentGraph, graphOptions }) { | ||
super(); | ||
constructor(graphData, { nodes }) { | ||
super(graphData); | ||
this.nodes = nodes; | ||
this.currentGraph = currentGraph; | ||
this.graphOptions = graphOptions; | ||
} | ||
@@ -41,3 +38,3 @@ | ||
.filter(node => { | ||
return this.graphOptions.shouldRelate(node, this.currentGraph) || node.userData.inserted; | ||
return this.graphOptions.shouldRelate(node, this.graphData) || node.userData.inserted; | ||
}) | ||
@@ -44,0 +41,0 @@ .map(node => ({ |
@@ -9,10 +9,6 @@ 'use strict'; | ||
return [ | ||
new GraphPatchAction({ | ||
new GraphPatchAction(this.graphData, { | ||
nodes: this.graph.nodes.filter(node => | ||
this.graphOptions.shouldPatchOrUpdateIgnoreDisable(node, this.currentGraph) | ||
), | ||
graph: this.graph, | ||
currentGraph: this.currentGraph, | ||
graphOptions: this.graphOptions | ||
this.graphOptions.shouldPatchOrUpdateIgnoreDisable(node, this.graphData) | ||
) | ||
}) | ||
@@ -19,0 +15,0 @@ ]; |
@@ -9,10 +9,6 @@ 'use strict'; | ||
class GraphPatchAction extends GraphAction { | ||
constructor({ nodes, graph, currentGraph, graphOptions }) { | ||
super(); | ||
constructor(graphData, { nodes }) { | ||
super(graphData); | ||
// Nodes to patch. | ||
this.nodes = nodes; | ||
this.graph = graph; | ||
this.currentGraph = currentGraph; | ||
this.graphOptions = graphOptions; | ||
} | ||
@@ -27,4 +23,4 @@ | ||
_runForNode(builder, node) { | ||
const shouldPatch = this.graphOptions.shouldPatch(node, this.currentGraph); | ||
const shouldUpdate = this.graphOptions.shouldUpdate(node, this.currentGraph); | ||
const shouldPatch = this.graphOptions.shouldPatch(node, this.graphData); | ||
const shouldUpdate = this.graphOptions.shouldUpdate(node, this.graphData); | ||
@@ -130,3 +126,3 @@ // BelongsToOneRelation inserts and relates change the parent object's | ||
node.obj[edge.relation.name] === null && | ||
this.graphOptions.shouldDeleteOrUnrelate(edge.relatedNode, this.graph) | ||
this.graphOptions.shouldDeleteOrUnrelate(edge.relatedNode, this.graphData) | ||
) { | ||
@@ -133,0 +129,0 @@ const { relation } = edge; |
@@ -9,10 +9,7 @@ 'use strict'; | ||
return [ | ||
new GraphRecursiveUpsertAction({ | ||
new GraphRecursiveUpsertAction(this.graphData, { | ||
nodes: this.graph.nodes.filter(node => { | ||
const shouldRelate = this.graphOptions.shouldRelate(node, this.currentGraph); | ||
const shouldRelate = this.graphOptions.shouldRelate(node, this.graphData); | ||
return shouldRelate && hasRelations(node.obj); | ||
}), | ||
currentGraph: this.currentGraph, | ||
graphOptions: this.graphOptions | ||
}) | ||
}) | ||
@@ -19,0 +16,0 @@ ]; |
'use strict'; | ||
const { GraphAction } = require('../GraphAction'); | ||
const { groupBy } = require('../../../utils/objectUtils'); | ||
const { groupBy, get, set } = require('../../../utils/objectUtils'); | ||
const { forEachPropertyReference } = require('../../../model/graph/ModelGraphBuilder'); | ||
const promiseUtils = require('../../../utils/promiseUtils'); | ||
class GraphRecursiveUpsertAction extends GraphAction { | ||
constructor({ nodes, graph, graphOptions }) { | ||
super(); | ||
constructor(graphData, { nodes }) { | ||
super(graphData); | ||
// Nodes to upsert. | ||
this.nodes = nodes; | ||
this.graph = graph; | ||
this.graphOptions = graphOptions; | ||
} | ||
@@ -34,2 +32,3 @@ | ||
for (const node of nodes) { | ||
this._resolveReferences(node); | ||
node.userData.upserted = true; | ||
@@ -53,2 +52,65 @@ } | ||
} | ||
/** | ||
* The nodes inside the subgraph we are about to recursively upsert may | ||
* have references outside that graph that won't be available during the | ||
* recursive upsertGraph call. This method resolves the references. | ||
* | ||
* TODO: This doesn't work if a recursively upserted node refers to | ||
* a node inside another recursively upsertable graph. | ||
*/ | ||
_resolveReferences(node) { | ||
node.obj.$traverse(obj => this._resolveReferencesForObject(obj)); | ||
} | ||
_resolveReferencesForObject(obj) { | ||
this._resolveObjectReference(obj); | ||
this._resolvePropertyReferences(obj); | ||
} | ||
_resolveObjectReference(obj) { | ||
const modelClass = obj.constructor; | ||
const ref = obj[modelClass.uidRefProp]; | ||
if (!ref) { | ||
return; | ||
} | ||
const referencedNode = this.graph.nodes.find(it => it.uid === ref); | ||
if (!referencedNode) { | ||
return; | ||
} | ||
const relationNames = referencedNode.modelClass.getRelationNames(); | ||
for (const prop of Object.keys(referencedNode.obj)) { | ||
if (relationNames.includes(prop)) { | ||
continue; | ||
} | ||
obj[prop] = referencedNode.obj[prop]; | ||
} | ||
delete obj[modelClass.uidRefProp]; | ||
} | ||
_resolvePropertyReferences(obj) { | ||
forEachPropertyReference(obj, ({ path, refMatch, ref, refPath }) => { | ||
const referencedNode = this.graph.nodes.find(it => it.uid === ref); | ||
if (!referencedNode) { | ||
return; | ||
} | ||
const referencedValue = get(referencedNode.obj, refPath); | ||
const value = get(obj, path); | ||
if (value === refMatch) { | ||
set(obj, path, referencedValue); | ||
} else { | ||
set(obj, path, value.replace(refMatch, referencedValue)); | ||
} | ||
}); | ||
} | ||
} | ||
@@ -55,0 +117,0 @@ |
@@ -284,4 +284,11 @@ 'use strict'; | ||
const table = builder.tableNameFor(tableNode.modelClass); | ||
const tableMeta = tableNode.modelClass.tableMetadata({ table }); | ||
return tableNode.modelClass.tableMetadata({ table }).columns.map(columnName => { | ||
if (!tableMeta) { | ||
throw new Error( | ||
'table metadata has not been fetched. Are you trying to call toKnexQuery() for a withGraphJoined query? To make sure the table metadata is fetched see the objection.initialize function.' | ||
); | ||
} | ||
return tableMeta.columns.map(columnName => { | ||
return new Selection( | ||
@@ -288,0 +295,0 @@ tableNode.alias, |
@@ -53,3 +53,3 @@ 'use strict'; | ||
onAfter2(builder, result) { | ||
async onAfter2(builder, result) { | ||
const modelClass = builder.resultModelClass(); | ||
@@ -67,3 +67,3 @@ | ||
const promise = promiseUtils.map( | ||
await promiseUtils.map( | ||
this.relationsToFetch, | ||
@@ -74,24 +74,22 @@ it => this.fetchRelation(builder, models, it.relation, it.childExpression), | ||
return promise.then(() => { | ||
const intOpt = builder.internalOptions(); | ||
const intOpt = builder.internalOptions(); | ||
if (!this.omitProps.length || intOpt.keepImplicitJoinProps) { | ||
return result; | ||
} | ||
if (!this.omitProps.length || intOpt.keepImplicitJoinProps) { | ||
return result; | ||
} | ||
// Now that relations have been fetched for `models` we can omit the | ||
// columns that were implicitly selected by this class. | ||
for (let i = 0, l = result.length; i < l; ++i) { | ||
const model = result[i]; | ||
// Now that relations have been fetched for `models` we can omit the | ||
// columns that were implicitly selected by this class. | ||
for (let i = 0, l = result.length; i < l; ++i) { | ||
const model = result[i]; | ||
for (let c = 0, lc = this.omitProps.length; c < lc; ++c) { | ||
modelClass.omitImpl(model, this.omitProps[c]); | ||
} | ||
for (let c = 0, lc = this.omitProps.length; c < lc; ++c) { | ||
modelClass.omitImpl(model, this.omitProps[c]); | ||
} | ||
} | ||
return result; | ||
}); | ||
return result; | ||
} | ||
fetchRelation(builder, models, relation, expr) { | ||
async fetchRelation(builder, models, relation, expr) { | ||
const modelClass = builder.resultModelClass(); | ||
@@ -101,7 +99,11 @@ const batchSize = this.batchSize(builder.knex()); | ||
return promiseUtils | ||
.map(modelBatches, batch => this.fetchRelationBatch(builder, batch, relation, expr), { | ||
const result = await promiseUtils.map( | ||
modelBatches, | ||
batch => this.fetchRelationBatch(builder, batch, relation, expr), | ||
{ | ||
concurrency: modelClass.getConcurrency(builder.unsafeKnex()) | ||
}) | ||
.then(flatten); | ||
} | ||
); | ||
return flatten(result); | ||
} | ||
@@ -108,0 +110,0 @@ |
@@ -24,3 +24,3 @@ 'use strict'; | ||
onAfter2(builder) { | ||
async onAfter2(builder) { | ||
if (this.models.length === 0) { | ||
@@ -34,10 +34,9 @@ return this.isArray ? [] : null; | ||
return modelClass | ||
const models = await modelClass | ||
.query() | ||
.childQueryOf(builder) | ||
.findByIds(ids) | ||
.withGraphFetched(eager) | ||
.then(models => { | ||
return this.isArray ? models : models[0] || null; | ||
}); | ||
.withGraphFetched(eager); | ||
return this.isArray ? models : models[0] || null; | ||
} | ||
@@ -44,0 +43,0 @@ } |
@@ -73,4 +73,5 @@ 'use strict'; | ||
// This is a bit hacky. | ||
onAfter1(builder, ...restArgs) { | ||
return this.upsert.run(builder).then(() => super.onAfter1(builder, ...restArgs)); | ||
async onAfter1(builder, ...restArgs) { | ||
await this.upsert.run(builder); | ||
return await super.onAfter1(builder, ...restArgs); | ||
} | ||
@@ -77,0 +78,0 @@ |
@@ -29,9 +29,9 @@ 'use strict'; | ||
onAfter3(_, results) { | ||
return this.resultSizeBuilder.resultSize().then(resultSize => { | ||
return { | ||
results, | ||
total: parseInt(resultSize, 10) | ||
}; | ||
}); | ||
async onAfter3(_, results) { | ||
const resultSize = await this.resultSizeBuilder.resultSize(); | ||
return { | ||
results, | ||
total: parseInt(resultSize) | ||
}; | ||
} | ||
@@ -38,0 +38,0 @@ |
@@ -24,3 +24,3 @@ 'use strict'; | ||
onAfter3(builder) { | ||
async onAfter3(builder) { | ||
if (this.models.length === 0) { | ||
@@ -34,10 +34,9 @@ return this.isArray ? [] : null; | ||
return modelClass | ||
const models = await modelClass | ||
.query() | ||
.childQueryOf(builder) | ||
.findByIds(ids) | ||
.withGraphFetched(eager) | ||
.then(models => { | ||
return this.isArray ? models : models[0] || null; | ||
}); | ||
.withGraphFetched(eager); | ||
return this.isArray ? models : models[0] || null; | ||
} | ||
@@ -44,0 +43,0 @@ } |
@@ -547,13 +547,5 @@ 'use strict'; | ||
toString() { | ||
try { | ||
return this.toKnexQuery().toString(); | ||
} catch (err) { | ||
return `This query cannot be built synchronously. Consider using debug() method instead.`; | ||
} | ||
return '[object QueryBuilder]'; | ||
} | ||
toSql() { | ||
return this.toString(); | ||
} | ||
toFindQuery() { | ||
@@ -652,3 +644,3 @@ return this.clone().clear( | ||
resultSize() { | ||
async resultSize() { | ||
const knex = this.knex(); | ||
@@ -665,5 +657,4 @@ const builder = this.clone().clear(/orderBy|offset|limit/); | ||
return countQuery.then(result => | ||
result[0] && result[0].count ? parseInt(result[0].count, 10) : 0 | ||
); | ||
const result = await countQuery; | ||
return result[0] && result[0].count ? parseInt(result[0].count) : 0; | ||
} | ||
@@ -1597,11 +1588,13 @@ | ||
// Set the table only if it hasn't been explicitly set yet. | ||
if (!builder.isPartial() && !fromOperation) { | ||
setDefaultTable(builder, knexBuilder); | ||
} | ||
if (!builder.isPartial()) { | ||
// Set the table only if it hasn't been explicitly set yet. | ||
if (!fromOperation) { | ||
setDefaultTable(builder, knexBuilder); | ||
} | ||
// Only add `table.*` select if there are no explicit selects | ||
// and `from` is a table name and not a subquery. | ||
if (!builder.isPartial() && !hasSelects && (!fromOperation || fromOperation.table)) { | ||
setDefaultSelect(builder, knexBuilder); | ||
// Only add `table.*` select if there are no explicit selects | ||
// and `from` is a table name and not a subquery. | ||
if (!hasSelects && (!fromOperation || fromOperation.table)) { | ||
setDefaultSelect(builder, knexBuilder); | ||
} | ||
} | ||
@@ -1629,3 +1622,3 @@ | ||
function chainHooks(promise, builder, func) { | ||
async function chainHooks(promise, builder, func) { | ||
return promise.then(result => { | ||
@@ -1632,0 +1625,0 @@ let promise = Promise.resolve(result); |
'use strict'; | ||
const promiseUtils = require('../utils/promiseUtils'); | ||
const { deprecate } = require('../utils/deprecate'); | ||
@@ -358,3 +356,3 @@ const { isString, isFunction, isRegExp, last } = require('../utils/objectUtils'); | ||
callAsyncOperationMethod(operation, hookName, args) { | ||
async callAsyncOperationMethod(operation, hookName, args) { | ||
operation.removeChildOperationsByHookName(hookName); | ||
@@ -367,12 +365,7 @@ | ||
return promiseUtils | ||
.try(() => operation[hookName](...args)) | ||
.then(result => { | ||
this._activeOperations.pop(); | ||
return result; | ||
}) | ||
.catch(err => { | ||
this._activeOperations.pop(); | ||
return Promise.reject(err); | ||
}); | ||
try { | ||
return await operation[hookName](...args); | ||
} finally { | ||
this._activeOperations.pop(); | ||
} | ||
} | ||
@@ -379,0 +372,0 @@ |
{ | ||
"name": "objection", | ||
"version": "2.0.0-rc.1", | ||
"version": "2.0.0-rc.2", | ||
"description": "An SQL-friendly ORM for Node.js", | ||
@@ -71,24 +71,22 @@ "main": "lib/objection.js", | ||
"devDependencies": { | ||
"@babel/polyfill": "^7.4.4", | ||
"@types/node": "^12.6.9", | ||
"babel-eslint": "^10.0.2", | ||
"@types/node": "^12.12.12", | ||
"chai": "^4.2.0", | ||
"chai-subset": "^1.6.0", | ||
"coveralls": "^3.0.6", | ||
"cross-env": "^6.0.0", | ||
"eslint": "^6.1.0", | ||
"eslint-plugin-prettier": "^3.1.0", | ||
"coveralls": "^3.0.8", | ||
"cross-env": "^6.0.3", | ||
"eslint": "^6.7.0", | ||
"eslint-plugin-prettier": "^3.1.1", | ||
"expect.js": "^0.3.1", | ||
"fs-extra": "^8.1.0", | ||
"glob": "^7.1.4", | ||
"husky": "^3.0.8", | ||
"glob": "^7.1.6", | ||
"husky": "^3.1.0", | ||
"knex": "0.20.2", | ||
"lint-staged": "^9.4.1", | ||
"mocha": "^6.2.0", | ||
"lint-staged": "^9.4.3", | ||
"mocha": "^6.2.2", | ||
"mysql": "^2.17.1", | ||
"nyc": "^14.1.1", | ||
"pg": "^7.12.1", | ||
"pg": "^7.14.0", | ||
"prettier": "1.19.1", | ||
"sqlite3": "^4.1.0", | ||
"typescript": "^3.6.3", | ||
"typescript": "^3.7.2", | ||
"vuepress": "1.2.0" | ||
@@ -95,0 +93,0 @@ }, |
@@ -14,3 +14,3 @@ [![Build Status](https://travis-ci.org/Vincit/objection.js.svg?branch=master)](https://travis-ci.org/Vincit/objection.js) [![Coverage Status](https://coveralls.io/repos/github/Vincit/objection.js/badge.svg?branch=master&service=github)](https://coveralls.io/github/Vincit/objection.js?branch=master) [![Join the chat at https://gitter.im/Vincit/objection.js](https://badges.gitter.im/Vincit/objection.js.svg)](https://gitter.im/Vincit/objection.js?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) | ||
- **An easy declarative way of [defining models](/guide/models.html) and relationships between them** | ||
- **Simple and fun way to [fetch, insert, update and delete](/guide/query-examples.html#basic-queries) objects using the full power of SQL** | ||
- **Simple and fun way to [fetch, insert, update and delete](/guide/query-examples.html) objects using the full power of SQL** | ||
- **Powerful mechanisms for [eager loading](/guide/query-examples.html#eager-loading), [inserting](/guide/query-examples.html#graph-inserts) and [upserting](/guide/query-examples.html#graph-upserts) object graphs** | ||
@@ -17,0 +17,0 @@ - **Easy to use [transactions](/guide/transactions.html)** |
@@ -18,2 +18,3 @@ /// <reference types="node" /> | ||
import * as knex from 'knex'; | ||
import Knex = require('knex'); | ||
@@ -38,2 +39,3 @@ // Export the entire Objection namespace. | ||
const transaction: transaction; | ||
const initialize: initialize; | ||
@@ -192,2 +194,9 @@ const DBError: typeof dbErrors.DBError; | ||
/** | ||
* A Pojo version of model. | ||
*/ | ||
type ModelObject<T extends Model> = { | ||
[K in NonFunctionPropertyNames<T>]: T[K]; | ||
}; | ||
/** | ||
* Any object that has some of the properties of model class T match this type. | ||
@@ -588,2 +597,3 @@ */ | ||
(insert: PartialModelObject<ModelType<QB>>[]): ArrayQueryBuilder<QB>; | ||
(): SingleQueryBuilder<QB>; | ||
} | ||
@@ -652,2 +662,6 @@ | ||
interface ToKnexQueryMethod<QB extends AnyQueryBuilder> { | ||
<T = ModelObject<QB['ModelType']>>(): Knex.QueryBuilder<T, T[]>; | ||
} | ||
interface AliasForMethod<QB extends AnyQueryBuilder> { | ||
@@ -1100,4 +1114,3 @@ (modelClassOrTableName: string | ModelClass<any>, alias: string): QB; | ||
tableRefFor: TableRefForMethod; | ||
toSql: StringReturningMethod; | ||
toString: StringReturningMethod; | ||
toKnexQuery: ToKnexQueryMethod<this>; | ||
reject: OneArgMethod<any, this>; | ||
@@ -1754,2 +1767,7 @@ resolve: OneArgMethod<any, this>; | ||
interface initialize { | ||
(knex: Knex, modelClasses: ModelClass<any>[]): Promise<void>; | ||
(modelClasses: ModelClass<any>[]): Promise<void>; | ||
} | ||
/** | ||
@@ -1756,0 +1774,0 @@ * JSON Schema 7 |
632219
21
180
19693