Socket
Socket
Sign inDemoInstall

objection

Package Overview
Dependencies
2
Maintainers
2
Versions
200
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 2.0.0-rc.1 to 2.0.0-rc.2

lib/initialize.js

60

lib/model/graph/ModelGraphBuilder.js

@@ -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
};

8

lib/model/graph/ModelGraphNode.js

@@ -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

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Packages

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc