@abedmurrar/objection 0.0.0-stage → 4.0.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +23 -0
- package/README.md +69 -2
- package/lib/.eslintrc.json +8 -0
- package/lib/initialize.js +14 -0
- package/lib/model/AjvValidator.js +325 -0
- package/lib/model/Model.js +942 -0
- package/lib/model/ModifierNotFoundError.js +12 -0
- package/lib/model/NotFoundError.js +23 -0
- package/lib/model/RelationDoesNotExistError.js +14 -0
- package/lib/model/ValidationError.js +54 -0
- package/lib/model/Validator.js +26 -0
- package/lib/model/getModel.js +9 -0
- package/lib/model/graph/ModelGraph.js +80 -0
- package/lib/model/graph/ModelGraphBuilder.js +241 -0
- package/lib/model/graph/ModelGraphEdge.js +52 -0
- package/lib/model/graph/ModelGraphNode.js +240 -0
- package/lib/model/inheritModel.js +28 -0
- package/lib/model/modelBindKnex.js +83 -0
- package/lib/model/modelClone.js +121 -0
- package/lib/model/modelColPropMap.js +34 -0
- package/lib/model/modelId.js +62 -0
- package/lib/model/modelJsonAttributes.js +92 -0
- package/lib/model/modelParseRelations.js +82 -0
- package/lib/model/modelQueryProps.js +147 -0
- package/lib/model/modelSet.js +136 -0
- package/lib/model/modelTableMetadata.js +83 -0
- package/lib/model/modelToJson.js +187 -0
- package/lib/model/modelUtils.js +47 -0
- package/lib/model/modelValidate.js +48 -0
- package/lib/model/modelValues.js +126 -0
- package/lib/model/modelVisitor.js +41 -0
- package/lib/objection.js +114 -0
- package/lib/queryBuilder/FunctionBuilder.js +339 -0
- package/lib/queryBuilder/InternalOptions.js +29 -0
- package/lib/queryBuilder/JoinBuilder.js +157 -0
- package/lib/queryBuilder/QueryBuilder.js +1398 -0
- package/lib/queryBuilder/QueryBuilderBase.js +884 -0
- package/lib/queryBuilder/QueryBuilderContext.js +27 -0
- package/lib/queryBuilder/QueryBuilderContextBase.js +35 -0
- package/lib/queryBuilder/QueryBuilderOperationSupport.js +558 -0
- package/lib/queryBuilder/QueryBuilderUserContext.js +31 -0
- package/lib/queryBuilder/RawBuilder.js +93 -0
- package/lib/queryBuilder/ReferenceBuilder.js +284 -0
- package/lib/queryBuilder/RelationExpression.js +431 -0
- package/lib/queryBuilder/StaticHookArguments.js +134 -0
- package/lib/queryBuilder/ValueBuilder.js +127 -0
- package/lib/queryBuilder/expressions.js +151 -0
- package/lib/queryBuilder/functions/mysql.js +817 -0
- package/lib/queryBuilder/graph/GraphAction.js +69 -0
- package/lib/queryBuilder/graph/GraphData.js +14 -0
- package/lib/queryBuilder/graph/GraphFetcher.js +191 -0
- package/lib/queryBuilder/graph/GraphNodeDbExistence.js +184 -0
- package/lib/queryBuilder/graph/GraphOperation.js +27 -0
- package/lib/queryBuilder/graph/GraphOptions.js +207 -0
- package/lib/queryBuilder/graph/GraphUpsert.js +305 -0
- package/lib/queryBuilder/graph/delete/GraphDelete.js +20 -0
- package/lib/queryBuilder/graph/delete/GraphDeleteAction.js +74 -0
- package/lib/queryBuilder/graph/insert/GraphInsert.js +145 -0
- package/lib/queryBuilder/graph/insert/GraphInsertAction.js +225 -0
- package/lib/queryBuilder/graph/insert/JoinRowGraphInsertAction.js +92 -0
- package/lib/queryBuilder/graph/patch/GraphPatch.js +20 -0
- package/lib/queryBuilder/graph/patch/GraphPatchAction.js +258 -0
- package/lib/queryBuilder/graph/recursiveUpsert/GraphRecursiveUpsert.js +31 -0
- package/lib/queryBuilder/graph/recursiveUpsert/GraphRecursiveUpsertAction.js +126 -0
- package/lib/queryBuilder/join/JoinResultColumn.js +23 -0
- package/lib/queryBuilder/join/JoinResultParser.js +119 -0
- package/lib/queryBuilder/join/RelationJoiner.js +341 -0
- package/lib/queryBuilder/join/TableNode.js +163 -0
- package/lib/queryBuilder/join/TableTree.js +85 -0
- package/lib/queryBuilder/join/utils.js +25 -0
- package/lib/queryBuilder/operations/DelegateOperation.js +141 -0
- package/lib/queryBuilder/operations/DeleteOperation.js +51 -0
- package/lib/queryBuilder/operations/FindByIdOperation.js +37 -0
- package/lib/queryBuilder/operations/FindByIdsOperation.js +29 -0
- package/lib/queryBuilder/operations/FindOperation.js +164 -0
- package/lib/queryBuilder/operations/FirstOperation.js +27 -0
- package/lib/queryBuilder/operations/FromOperation.js +110 -0
- package/lib/queryBuilder/operations/InsertAndFetchOperation.js +49 -0
- package/lib/queryBuilder/operations/InsertGraphAndFetchOperation.js +45 -0
- package/lib/queryBuilder/operations/InsertGraphOperation.js +108 -0
- package/lib/queryBuilder/operations/InsertOperation.js +206 -0
- package/lib/queryBuilder/operations/InstanceDeleteOperation.js +46 -0
- package/lib/queryBuilder/operations/InstanceFindOperation.js +21 -0
- package/lib/queryBuilder/operations/InstanceInsertOperation.js +24 -0
- package/lib/queryBuilder/operations/InstanceUpdateOperation.js +59 -0
- package/lib/queryBuilder/operations/JoinRelatedOperation.js +103 -0
- package/lib/queryBuilder/operations/KnexOperation.js +14 -0
- package/lib/queryBuilder/operations/MergeOperation.js +56 -0
- package/lib/queryBuilder/operations/ObjectionToKnexConvertingOperation.js +192 -0
- package/lib/queryBuilder/operations/OnBuildKnexOperation.js +29 -0
- package/lib/queryBuilder/operations/OnBuildOperation.js +29 -0
- package/lib/queryBuilder/operations/OnErrorOperation.js +29 -0
- package/lib/queryBuilder/operations/QueryBuilderOperation.js +297 -0
- package/lib/queryBuilder/operations/RangeOperation.js +47 -0
- package/lib/queryBuilder/operations/RelateOperation.js +27 -0
- package/lib/queryBuilder/operations/ReturningOperation.js +30 -0
- package/lib/queryBuilder/operations/RunAfterOperation.js +29 -0
- package/lib/queryBuilder/operations/RunBeforeOperation.js +29 -0
- package/lib/queryBuilder/operations/UnrelateOperation.js +23 -0
- package/lib/queryBuilder/operations/UpdateAndFetchOperation.js +80 -0
- package/lib/queryBuilder/operations/UpdateOperation.js +155 -0
- package/lib/queryBuilder/operations/UpsertGraphAndFetchOperation.js +45 -0
- package/lib/queryBuilder/operations/UpsertGraphOperation.js +66 -0
- package/lib/queryBuilder/operations/WhereCompositeOperation.js +57 -0
- package/lib/queryBuilder/operations/WhereInOperation.js +48 -0
- package/lib/queryBuilder/operations/eager/EagerOperation.js +61 -0
- package/lib/queryBuilder/operations/eager/JoinEagerOperation.js +51 -0
- package/lib/queryBuilder/operations/eager/NaiveEagerOperation.js +13 -0
- package/lib/queryBuilder/operations/eager/WhereInEagerOperation.js +285 -0
- package/lib/queryBuilder/operations/jsonApi/WhereJsonHasOperation.js +36 -0
- package/lib/queryBuilder/operations/jsonApi/WhereJsonNotObjectOperation.js +53 -0
- package/lib/queryBuilder/operations/jsonApi/WhereJsonOperation.js +31 -0
- package/lib/queryBuilder/operations/jsonApi/WhereJsonOverlapsOperation.js +31 -0
- package/lib/queryBuilder/operations/jsonApi/mysqlJsonApi.js +167 -0
- package/lib/queryBuilder/operations/jsonApi/postgresJsonApi.js +164 -0
- package/lib/queryBuilder/operations/select/SelectOperation.js +66 -0
- package/lib/queryBuilder/operations/select/Selection.js +123 -0
- package/lib/queryBuilder/operations/whereInComposite/WhereInCompositeMsSqlOperation.js +117 -0
- package/lib/queryBuilder/operations/whereInComposite/WhereInCompositeOperation.js +100 -0
- package/lib/queryBuilder/operations/whereInComposite/WhereInCompositeSqliteOperation.js +104 -0
- package/lib/queryBuilder/parsers/jsonFieldExpressionParser.js +886 -0
- package/lib/queryBuilder/parsers/jsonFieldExpressionParser.pegjs +97 -0
- package/lib/queryBuilder/parsers/relationExpressionParser.js +1042 -0
- package/lib/queryBuilder/parsers/relationExpressionParser.pegjs +141 -0
- package/lib/queryBuilder/transformations/CompositeQueryTransformation.js +22 -0
- package/lib/queryBuilder/transformations/QueryTransformation.js +11 -0
- package/lib/queryBuilder/transformations/WrapMysqlModifySubqueryTransformation.js +71 -0
- package/lib/queryBuilder/transformations/index.js +15 -0
- package/lib/queryBuilder/whereScopes.js +227 -0
- package/lib/relations/Relation.js +401 -0
- package/lib/relations/RelationDeleteOperation.js +29 -0
- package/lib/relations/RelationFindOperation.js +149 -0
- package/lib/relations/RelationInsertOperation.js +33 -0
- package/lib/relations/RelationOwner.js +236 -0
- package/lib/relations/RelationProperty.js +247 -0
- package/lib/relations/RelationUpdateOperation.js +30 -0
- package/lib/relations/belongsToOne/BelongsToOneDeleteOperation.js +23 -0
- package/lib/relations/belongsToOne/BelongsToOneInsertOperation.js +44 -0
- package/lib/relations/belongsToOne/BelongsToOneRelateOperation.js +50 -0
- package/lib/relations/belongsToOne/BelongsToOneRelation.js +53 -0
- package/lib/relations/belongsToOne/BelongsToOneUnrelateOperation.js +61 -0
- package/lib/relations/hasMany/HasManyInsertOperation.js +61 -0
- package/lib/relations/hasMany/HasManyRelateOperation.js +64 -0
- package/lib/relations/hasMany/HasManyRelation.js +49 -0
- package/lib/relations/hasMany/HasManyUnrelateOperation.js +33 -0
- package/lib/relations/hasOne/HasOneRelation.js +13 -0
- package/lib/relations/hasOneThrough/HasOneThroughRelation.js +13 -0
- package/lib/relations/manyToMany/ManyToManyModifyMixin.js +105 -0
- package/lib/relations/manyToMany/ManyToManyRelation.js +507 -0
- package/lib/relations/manyToMany/ManyToManySqliteModifyMixin.js +36 -0
- package/lib/relations/manyToMany/delete/ManyToManyDeleteOperation.js +10 -0
- package/lib/relations/manyToMany/delete/ManyToManyDeleteOperationBase.js +26 -0
- package/lib/relations/manyToMany/delete/ManyToManyDeleteSqliteOperation.js +12 -0
- package/lib/relations/manyToMany/find/ManyToManyFindOperation.js +105 -0
- package/lib/relations/manyToMany/insert/ManyToManyInsertOperation.js +52 -0
- package/lib/relations/manyToMany/relate/ManyToManyRelateOperation.js +81 -0
- package/lib/relations/manyToMany/unrelate/ManyToManyUnrelateOperation.js +14 -0
- package/lib/relations/manyToMany/unrelate/ManyToManyUnrelateOperationBase.js +34 -0
- package/lib/relations/manyToMany/unrelate/ManyToManyUnrelateSqliteOperation.js +16 -0
- package/lib/relations/manyToMany/update/ManyToManyUpdateOperation.js +10 -0
- package/lib/relations/manyToMany/update/ManyToManyUpdateOperationBase.js +82 -0
- package/lib/relations/manyToMany/update/ManyToManyUpdateSqliteOperation.js +12 -0
- package/lib/transaction.js +96 -0
- package/lib/utils/assert.js +25 -0
- package/lib/utils/buildUtils.js +21 -0
- package/lib/utils/classUtils.js +13 -0
- package/lib/utils/clone.js +2329 -0
- package/lib/utils/createModifier.js +42 -0
- package/lib/utils/deprecate.js +15 -0
- package/lib/utils/identifierMapping.js +227 -0
- package/lib/utils/internalPropUtils.js +11 -0
- package/lib/utils/knexUtils.js +76 -0
- package/lib/utils/mixin.js +25 -0
- package/lib/utils/mysqlJsonPath.js +55 -0
- package/lib/utils/normalizeIds.js +144 -0
- package/lib/utils/objectUtils.js +416 -0
- package/lib/utils/parseFieldExpression.js +51 -0
- package/lib/utils/postgresJsonPath.js +110 -0
- package/lib/utils/promiseUtils/after.js +17 -0
- package/lib/utils/promiseUtils/afterReturn.js +17 -0
- package/lib/utils/promiseUtils/index.js +17 -0
- package/lib/utils/promiseUtils/isPromise.js +11 -0
- package/lib/utils/promiseUtils/map.js +110 -0
- package/lib/utils/promiseUtils/mapAfterAllReturn.js +29 -0
- package/lib/utils/promiseUtils/try.js +22 -0
- package/lib/utils/resolveModel.js +107 -0
- package/lib/utils/tmpColumnUtils.js +16 -0
- package/package.json +86 -4
- package/typings/objection/index.d.ts +4104 -0
- package/typings/objection/relation-expression.d.ts +237 -0
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { ref } = require('../../queryBuilder/ReferenceBuilder');
|
|
4
|
+
const { isEmpty } = require('../../utils/objectUtils');
|
|
5
|
+
const { isKnexRaw, isKnexQueryBuilder } = require('../../utils/knexUtils');
|
|
6
|
+
const { toPgJsonPathLiteral, getJsonDialect } = require('../../utils/postgresJsonPath');
|
|
7
|
+
const { toMySqlJsonPath } = require('../../utils/mysqlJsonPath');
|
|
8
|
+
const { QueryBuilderOperation } = require('./QueryBuilderOperation');
|
|
9
|
+
const { StaticHookArguments } = require('../StaticHookArguments');
|
|
10
|
+
|
|
11
|
+
class UpdateOperation extends QueryBuilderOperation {
|
|
12
|
+
constructor(name, opt) {
|
|
13
|
+
super(name, opt);
|
|
14
|
+
|
|
15
|
+
this.model = null;
|
|
16
|
+
this.modelOptions = Object.assign({}, this.opt.modelOptions || {});
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
onAdd(builder, args) {
|
|
20
|
+
const json = args[0];
|
|
21
|
+
const modelClass = builder.modelClass();
|
|
22
|
+
|
|
23
|
+
this.model = modelClass.ensureModel(json, this.modelOptions);
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async onBefore2(builder, result) {
|
|
28
|
+
await callBeforeUpdate(builder, this.model, this.modelOptions);
|
|
29
|
+
return result;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
onBefore3(builder) {
|
|
33
|
+
const row = this.model.$toDatabaseJson(builder);
|
|
34
|
+
|
|
35
|
+
if (isEmpty(row)) {
|
|
36
|
+
// Resolve the query if there is nothing to update.
|
|
37
|
+
builder.resolve(0);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
onBuildKnex(knexBuilder, builder) {
|
|
42
|
+
const json = this.model.$toDatabaseJson(builder);
|
|
43
|
+
const convertedJson = convertFieldExpressionsToRaw(builder, this.model, json);
|
|
44
|
+
|
|
45
|
+
return knexBuilder.update(convertedJson);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
onAfter2(builder, numUpdated) {
|
|
49
|
+
return callAfterUpdate(builder, this.model, this.modelOptions, numUpdated);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
toFindOperation() {
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
clone() {
|
|
57
|
+
const clone = super.clone();
|
|
58
|
+
clone.model = this.model;
|
|
59
|
+
return clone;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async function callBeforeUpdate(builder, model, modelOptions) {
|
|
64
|
+
await callInstanceBeforeUpdate(builder, model, modelOptions);
|
|
65
|
+
return callStaticBeforeUpdate(builder);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function callInstanceBeforeUpdate(builder, model, modelOptions) {
|
|
69
|
+
return model.$beforeUpdate(modelOptions, builder.context());
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function callStaticBeforeUpdate(builder) {
|
|
73
|
+
const args = StaticHookArguments.create({ builder });
|
|
74
|
+
return builder.modelClass().beforeUpdate(args);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
async function callAfterUpdate(builder, model, modelOptions, result) {
|
|
78
|
+
await callInstanceAfterUpdate(builder, model, modelOptions);
|
|
79
|
+
return callStaticAfterUpdate(builder, result);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function callInstanceAfterUpdate(builder, model, modelOptions) {
|
|
83
|
+
return model.$afterUpdate(modelOptions, builder.context());
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
async function callStaticAfterUpdate(builder, result) {
|
|
87
|
+
const args = StaticHookArguments.create({ builder, result });
|
|
88
|
+
const maybeResult = await builder.modelClass().afterUpdate(args);
|
|
89
|
+
|
|
90
|
+
if (maybeResult === undefined) {
|
|
91
|
+
return result;
|
|
92
|
+
} else {
|
|
93
|
+
return maybeResult;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function convertFieldExpressionsToRaw(builder, model, json) {
|
|
98
|
+
const knex = builder.knex();
|
|
99
|
+
const convertedJson = {};
|
|
100
|
+
|
|
101
|
+
for (const key of Object.keys(json)) {
|
|
102
|
+
let val = json[key];
|
|
103
|
+
|
|
104
|
+
if (key.indexOf(':') > -1) {
|
|
105
|
+
// 'col:attr' : ref('other:lol') is transformed to
|
|
106
|
+
// "col" : raw(`jsonb_set(COALESCE("col", '{}'), '{attr}', to_jsonb("other"#>'{lol}'), true)`)
|
|
107
|
+
// on postgres and to
|
|
108
|
+
// `col` : raw("JSON_SET(COALESCE(`col`, JSON_OBJECT()), '$.\"attr\"', JSON_EXTRACT(`other`, '$.\"lol\"'))")
|
|
109
|
+
// on mysql. A NULL column is treated as an empty object (or array).
|
|
110
|
+
|
|
111
|
+
const parsed = ref(key);
|
|
112
|
+
const access = parsed.parsedExpr.access;
|
|
113
|
+
const isSqlValue = isKnexQueryBuilder(val) || isKnexRaw(val);
|
|
114
|
+
// When the column is set by an earlier key, that expression is used instead.
|
|
115
|
+
const target = convertedJson[parsed.column] || parsed.column;
|
|
116
|
+
const isFirstSet = !convertedJson[parsed.column];
|
|
117
|
+
|
|
118
|
+
if (!isSqlValue) {
|
|
119
|
+
val = JSON.stringify(val);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (getJsonDialect(knex, key) === 'mysql') {
|
|
123
|
+
const empty = access[0].type === 'array' ? 'JSON_ARRAY()' : 'JSON_OBJECT()';
|
|
124
|
+
const column = isFirstSet ? `COALESCE(??, ${empty})` : '??';
|
|
125
|
+
const value = isSqlValue ? '?' : 'CAST(? AS JSON)';
|
|
126
|
+
|
|
127
|
+
convertedJson[parsed.column] = knex.raw(`JSON_SET(${column}, ?, ${value})`, [
|
|
128
|
+
target,
|
|
129
|
+
toMySqlJsonPath(access),
|
|
130
|
+
val,
|
|
131
|
+
]);
|
|
132
|
+
} else {
|
|
133
|
+
const empty = access[0].type === 'array' ? `'[]'::jsonb` : `'{}'::jsonb`;
|
|
134
|
+
const column = isFirstSet ? `COALESCE(??, ${empty})` : '??';
|
|
135
|
+
const value = isSqlValue ? 'to_jsonb(?)' : '?';
|
|
136
|
+
|
|
137
|
+
convertedJson[parsed.column] = knex.raw(
|
|
138
|
+
`jsonb_set(${column}, ${toPgJsonPathLiteral(access)}, ${value}, true)`,
|
|
139
|
+
[target, val],
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
delete model[key];
|
|
144
|
+
} else {
|
|
145
|
+
convertedJson[key] = val;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return convertedJson;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
module.exports = {
|
|
153
|
+
UpdateOperation,
|
|
154
|
+
convertFieldExpressionsToRaw,
|
|
155
|
+
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { DelegateOperation } = require('./DelegateOperation');
|
|
4
|
+
const { UpsertGraphOperation } = require('./UpsertGraphOperation');
|
|
5
|
+
const { RelationExpression } = require('../RelationExpression');
|
|
6
|
+
|
|
7
|
+
class UpsertGraphAndFetchOperation extends DelegateOperation {
|
|
8
|
+
constructor(name, opt) {
|
|
9
|
+
super(name, opt);
|
|
10
|
+
|
|
11
|
+
if (!this.delegate.is(UpsertGraphOperation)) {
|
|
12
|
+
throw new Error('Invalid delegate');
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
get models() {
|
|
17
|
+
return this.delegate.models;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
get isArray() {
|
|
21
|
+
return this.delegate.isArray;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async onAfter3(builder) {
|
|
25
|
+
if (this.models.length === 0) {
|
|
26
|
+
return this.isArray ? [] : null;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const eager = RelationExpression.fromModelGraph(this.models);
|
|
30
|
+
const modelClass = this.models[0].constructor;
|
|
31
|
+
const ids = this.models.map((model) => model.$id());
|
|
32
|
+
|
|
33
|
+
const models = await modelClass
|
|
34
|
+
.query()
|
|
35
|
+
.childQueryOf(builder)
|
|
36
|
+
.findByIds(ids)
|
|
37
|
+
.withGraphFetched(eager);
|
|
38
|
+
|
|
39
|
+
return this.isArray ? models : models[0] || null;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
module.exports = {
|
|
44
|
+
UpsertGraphAndFetchOperation,
|
|
45
|
+
};
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { QueryBuilderOperation } = require('./QueryBuilderOperation');
|
|
4
|
+
const { GraphUpsert } = require('../graph/GraphUpsert');
|
|
5
|
+
const { RelationFindOperation } = require('../../relations/RelationFindOperation');
|
|
6
|
+
|
|
7
|
+
class UpsertGraphOperation extends QueryBuilderOperation {
|
|
8
|
+
constructor(name, opt) {
|
|
9
|
+
super(
|
|
10
|
+
name,
|
|
11
|
+
Object.assign({}, opt, {
|
|
12
|
+
upsertOptions: {},
|
|
13
|
+
}),
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
this.upsertOptions = opt.upsertOptions || {};
|
|
17
|
+
this.upsert = null;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
get models() {
|
|
21
|
+
return this.upsert.objects;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
get isArray() {
|
|
25
|
+
return this.upsert.isArray;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
onAdd(builder, args) {
|
|
29
|
+
const [objects] = args;
|
|
30
|
+
|
|
31
|
+
this.upsert = new GraphUpsert({
|
|
32
|
+
objects,
|
|
33
|
+
rootModelClass: builder.modelClass(),
|
|
34
|
+
upsertOptions: this.upsertOptions,
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
// Never execute this builder.
|
|
38
|
+
builder.resolve([]);
|
|
39
|
+
|
|
40
|
+
return true;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
onAfter1(builder) {
|
|
44
|
+
if (hasOtherSqlModifyingQueryBuilderCalls(builder)) {
|
|
45
|
+
throw new Error(
|
|
46
|
+
'upsertGraph query should contain no other query builder calls like `findById`, `where` or `$relatedQuery` that would affect the SQL. They have no effect.',
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return this.upsert.run(builder);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
clone() {
|
|
54
|
+
const clone = super.clone();
|
|
55
|
+
clone.upsert = this.upsert;
|
|
56
|
+
return clone;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function hasOtherSqlModifyingQueryBuilderCalls(builder) {
|
|
61
|
+
return builder.has(/where/) || builder.has(RelationFindOperation);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
module.exports = {
|
|
65
|
+
UpsertGraphOperation,
|
|
66
|
+
};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { ObjectionToKnexConvertingOperation } = require('./ObjectionToKnexConvertingOperation');
|
|
4
|
+
const { asSingle } = require('../../utils/objectUtils');
|
|
5
|
+
|
|
6
|
+
class WhereCompositeOperation extends ObjectionToKnexConvertingOperation {
|
|
7
|
+
onBuildKnex(knexBuilder, builder) {
|
|
8
|
+
const args = this.getKnexArgs(builder);
|
|
9
|
+
|
|
10
|
+
if (args.length === 2) {
|
|
11
|
+
// Convert whereComposite('foo', 1) into whereComposite('foo', '=', 1)
|
|
12
|
+
args.splice(1, 0, '=');
|
|
13
|
+
} else if (args.length !== 3) {
|
|
14
|
+
throw new Error(`invalid number of arguments ${args.length}`);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return knexBuilder.where(...buildWhereArgs(...args));
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function buildWhereArgs(cols, op, values) {
|
|
22
|
+
if (isNormalWhere(cols, values)) {
|
|
23
|
+
return buildNormalWhereArgs(cols, op, values);
|
|
24
|
+
} else if (isCompositeWhere(cols, values)) {
|
|
25
|
+
return buildCompositeWhereArgs(cols, op, values);
|
|
26
|
+
} else {
|
|
27
|
+
throw new Error(`both cols and values must have same dimensions`);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function isNormalWhere(cols, values) {
|
|
32
|
+
return (
|
|
33
|
+
(!Array.isArray(cols) || cols.length === 1) && (!Array.isArray(values) || values.length === 1)
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function buildNormalWhereArgs(cols, op, values) {
|
|
38
|
+
return [asSingle(cols), op, asSingle(values)];
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function isCompositeWhere(cols, values) {
|
|
42
|
+
return Array.isArray(cols) && Array.isArray(values) && cols.length === values.length;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function buildCompositeWhereArgs(cols, op, values) {
|
|
46
|
+
return [
|
|
47
|
+
(builder) => {
|
|
48
|
+
for (let i = 0, l = cols.length; i < l; ++i) {
|
|
49
|
+
builder.where(cols[i], op, values[i]);
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
];
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
module.exports = {
|
|
56
|
+
WhereCompositeOperation,
|
|
57
|
+
};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { ObjectionToKnexConvertingOperation } = require('./ObjectionToKnexConvertingOperation');
|
|
4
|
+
const { isKnexRaw } = require('../../utils/knexUtils');
|
|
5
|
+
|
|
6
|
+
// `whereIn`, `whereNotIn`, `onIn` etc. knex compiles the values before the column,
|
|
7
|
+
// so the bindings of a raw column (like `ref('data:a').castInt()` on MySQL or
|
|
8
|
+
// `fn.lower(ref('a'))`) end up after the values and the query uses the wrong
|
|
9
|
+
// bindings. In that case the condition is built as raw sql with the bindings in
|
|
10
|
+
// the right order.
|
|
11
|
+
class WhereInOperation extends ObjectionToKnexConvertingOperation {
|
|
12
|
+
onBuildKnex(knexBuilder, builder) {
|
|
13
|
+
const args = this.getKnexArgs(builder);
|
|
14
|
+
const [column, values] = args;
|
|
15
|
+
|
|
16
|
+
if (args.length !== 2 || !hasBindings(column) || isEmptyArray(values)) {
|
|
17
|
+
return knexBuilder[this.name].apply(knexBuilder, args);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const knex = builder.knex();
|
|
21
|
+
const not = this.opt.not ? 'not ' : '';
|
|
22
|
+
let sql;
|
|
23
|
+
let bindings;
|
|
24
|
+
|
|
25
|
+
if (Array.isArray(values)) {
|
|
26
|
+
sql = `? ${not}in (${values.map(() => '?').join(', ')})`;
|
|
27
|
+
bindings = [column, ...values];
|
|
28
|
+
} else {
|
|
29
|
+
// A subquery.
|
|
30
|
+
sql = `? ${not}in ?`;
|
|
31
|
+
bindings = [column, values];
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return knexBuilder[this.opt.rawMethod](knex.raw(sql, bindings));
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function hasBindings(column) {
|
|
39
|
+
return isKnexRaw(column) && Array.isArray(column.bindings) && column.bindings.length > 0;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function isEmptyArray(values) {
|
|
43
|
+
return Array.isArray(values) && values.length === 0;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
module.exports = {
|
|
47
|
+
WhereInOperation,
|
|
48
|
+
};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { QueryBuilderOperation } = require('../QueryBuilderOperation');
|
|
4
|
+
const { RelationExpression } = require('../../RelationExpression');
|
|
5
|
+
|
|
6
|
+
class EagerOperation extends QueryBuilderOperation {
|
|
7
|
+
constructor(name, opt) {
|
|
8
|
+
super(name, opt);
|
|
9
|
+
|
|
10
|
+
this.expression = RelationExpression.create();
|
|
11
|
+
this.modifiersAtPath = [];
|
|
12
|
+
this.graphOptions = this.opt.defaultGraphOptions;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
buildFinalExpression() {
|
|
16
|
+
const expression = this.expression.clone();
|
|
17
|
+
|
|
18
|
+
this.modifiersAtPath.forEach((modifier, i) => {
|
|
19
|
+
const modifierName = getModifierName(i);
|
|
20
|
+
|
|
21
|
+
expression.expressionsAtPath(modifier.path).forEach((expr) => {
|
|
22
|
+
expr.node.$modify.push(modifierName);
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
return expression;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
buildFinalModifiers(builder) {
|
|
30
|
+
// `modifiers()` returns a clone so we can modify it.
|
|
31
|
+
const modifiers = builder.modifiers();
|
|
32
|
+
|
|
33
|
+
this.modifiersAtPath.forEach((modifier, i) => {
|
|
34
|
+
const modifierName = getModifierName(i);
|
|
35
|
+
|
|
36
|
+
modifiers[modifierName] = modifier.modifier;
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
return modifiers;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
cloneFrom(eagerOp) {
|
|
43
|
+
this.expression = eagerOp.expression.clone();
|
|
44
|
+
this.modifiersAtPath = eagerOp.modifiersAtPath.slice();
|
|
45
|
+
this.graphOptions = Object.assign({}, eagerOp.graphOptions);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
clone() {
|
|
49
|
+
const clone = super.clone();
|
|
50
|
+
clone.cloneFrom(this);
|
|
51
|
+
return clone;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function getModifierName(index) {
|
|
56
|
+
return `_f${index}_`;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
module.exports = {
|
|
60
|
+
EagerOperation,
|
|
61
|
+
};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { EagerOperation } = require('./EagerOperation');
|
|
4
|
+
const { RelationJoiner } = require('../../join/RelationJoiner');
|
|
5
|
+
|
|
6
|
+
class JoinEagerOperation extends EagerOperation {
|
|
7
|
+
constructor(name, opt) {
|
|
8
|
+
super(name, opt);
|
|
9
|
+
this.joiner = null;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
onAdd(builder) {
|
|
13
|
+
builder.findOptions({ callAfterFindDeeply: true });
|
|
14
|
+
|
|
15
|
+
this.joiner = new RelationJoiner({
|
|
16
|
+
modelClass: builder.modelClass(),
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
return true;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
onBefore3(builder) {
|
|
23
|
+
return this.joiner
|
|
24
|
+
.setExpression(this.buildFinalExpression())
|
|
25
|
+
.setModifiers(this.buildFinalModifiers(builder))
|
|
26
|
+
.setOptions(this.graphOptions)
|
|
27
|
+
.fetchColumnInfo(builder);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
onBuild(builder) {
|
|
31
|
+
this.joiner
|
|
32
|
+
.setExpression(this.buildFinalExpression())
|
|
33
|
+
.setModifiers(this.buildFinalModifiers(builder))
|
|
34
|
+
.setOptions(this.graphOptions)
|
|
35
|
+
.build(builder);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
onRawResult(builder, rows) {
|
|
39
|
+
return this.joiner.parseResult(builder, rows);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
clone() {
|
|
43
|
+
const clone = super.clone();
|
|
44
|
+
clone.joiner = this.joiner;
|
|
45
|
+
return clone;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
module.exports = {
|
|
50
|
+
JoinEagerOperation,
|
|
51
|
+
};
|