@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,431 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const parser = require('./parsers/relationExpressionParser');
|
|
4
|
+
const { isObject, isNumber, isString, union } = require('../utils/objectUtils');
|
|
5
|
+
const { RelationDoesNotExistError } = require('../model/RelationDoesNotExistError');
|
|
6
|
+
|
|
7
|
+
class RelationExpressionParseError extends Error {}
|
|
8
|
+
class DuplicateRelationError extends RelationExpressionParseError {
|
|
9
|
+
constructor(relationName) {
|
|
10
|
+
super();
|
|
11
|
+
this.relationName = relationName;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
class RelationExpression {
|
|
16
|
+
constructor(node = newNode(), recursionDepth = 0) {
|
|
17
|
+
this.node = node;
|
|
18
|
+
this.recursionDepth = recursionDepth;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Create a relation expression from a string, a pojo or another
|
|
22
|
+
// RelationExpression instance.
|
|
23
|
+
static create(expr) {
|
|
24
|
+
if (isObject(expr)) {
|
|
25
|
+
if (expr.isObjectionRelationExpression) {
|
|
26
|
+
return expr;
|
|
27
|
+
} else {
|
|
28
|
+
return new RelationExpression(normalizeNode(expr));
|
|
29
|
+
}
|
|
30
|
+
} else if (isString(expr)) {
|
|
31
|
+
if (expr.trim().length === 0) {
|
|
32
|
+
return new RelationExpression();
|
|
33
|
+
} else {
|
|
34
|
+
try {
|
|
35
|
+
return new RelationExpression(parse(expr));
|
|
36
|
+
} catch (err) {
|
|
37
|
+
if (err.duplicateRelationName) {
|
|
38
|
+
throw new DuplicateRelationError(err.duplicateRelationName);
|
|
39
|
+
} else {
|
|
40
|
+
throw new RelationExpressionParseError(err.message);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
} else {
|
|
45
|
+
return new RelationExpression();
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Create a relation expression from a model graph.
|
|
50
|
+
static fromModelGraph(graph) {
|
|
51
|
+
if (!graph) {
|
|
52
|
+
return new RelationExpression();
|
|
53
|
+
} else {
|
|
54
|
+
return new RelationExpression(modelGraphToNode(graph, newNode()));
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
get maxRecursionDepth() {
|
|
59
|
+
if (isNumber(this.node.$recursive)) {
|
|
60
|
+
return this.node.$recursive;
|
|
61
|
+
} else {
|
|
62
|
+
return this.node.$recursive ? Number.MAX_SAFE_INTEGER : 0;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
get numChildren() {
|
|
67
|
+
return this.node.$childNames.length;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
get isEmpty() {
|
|
71
|
+
return this.numChildren === 0;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Merges this relation expression with another. `expr` can be a string,
|
|
75
|
+
// a pojo, or a RelationExpression instance.
|
|
76
|
+
merge(expr) {
|
|
77
|
+
expr = RelationExpression.create(expr);
|
|
78
|
+
|
|
79
|
+
if (this.isEmpty) {
|
|
80
|
+
// Nothing to merge.
|
|
81
|
+
return expr;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return new RelationExpression(mergeNodes(this.node, expr.node));
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Returns true if `expr` is contained by this expression. For example
|
|
88
|
+
// `a.b` is contained by `a.[b, c]`.
|
|
89
|
+
isSubExpression(expr) {
|
|
90
|
+
expr = RelationExpression.create(expr);
|
|
91
|
+
|
|
92
|
+
if (this.node.$allRecursive) {
|
|
93
|
+
return true;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (expr.node.$allRecursive) {
|
|
97
|
+
return this.node.$allRecursive;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (this.node.$relation !== expr.node.$relation) {
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const maxRecursionDepth = expr.maxRecursionDepth;
|
|
105
|
+
|
|
106
|
+
if (maxRecursionDepth > 0) {
|
|
107
|
+
return this.node.$allRecursive || this.maxRecursionDepth >= maxRecursionDepth;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
for (const childName of expr.node.$childNames) {
|
|
111
|
+
const ownSubExpression = this.childExpression(childName);
|
|
112
|
+
const subExpression = expr.childExpression(childName);
|
|
113
|
+
|
|
114
|
+
if (!ownSubExpression || !ownSubExpression.isSubExpression(subExpression)) {
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return true;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Returns a RelationExpression for a child node or null if there
|
|
123
|
+
// is no child with the given name `childName`.
|
|
124
|
+
childExpression(childName) {
|
|
125
|
+
if (
|
|
126
|
+
this.node.$allRecursive ||
|
|
127
|
+
(childName === this.node.$name && this.recursionDepth < this.maxRecursionDepth - 1)
|
|
128
|
+
) {
|
|
129
|
+
return new RelationExpression(this.node, this.recursionDepth + 1);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const child = this.node[childName];
|
|
133
|
+
|
|
134
|
+
if (child) {
|
|
135
|
+
return new RelationExpression(child);
|
|
136
|
+
} else {
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Loops throught all first level children.
|
|
142
|
+
forEachChildExpression(modelClass, cb) {
|
|
143
|
+
const maxRecursionDepth = this.maxRecursionDepth;
|
|
144
|
+
|
|
145
|
+
if (this.node.$allRecursive) {
|
|
146
|
+
for (const relationName of modelClass.getRelationNames()) {
|
|
147
|
+
const node = newNode(relationName, true);
|
|
148
|
+
const relation = modelClass.getRelationUnsafe(relationName);
|
|
149
|
+
const childExpr = new RelationExpression(node);
|
|
150
|
+
|
|
151
|
+
cb(childExpr, relation);
|
|
152
|
+
}
|
|
153
|
+
} else if (this.recursionDepth < maxRecursionDepth - 1) {
|
|
154
|
+
const relation = modelClass.getRelationUnsafe(this.node.$relation) || null;
|
|
155
|
+
const childExpr = new RelationExpression(this.node, this.recursionDepth + 1);
|
|
156
|
+
|
|
157
|
+
cb(childExpr, relation);
|
|
158
|
+
} else if (maxRecursionDepth === 0) {
|
|
159
|
+
for (const childName of this.node.$childNames) {
|
|
160
|
+
const node = this.node[childName];
|
|
161
|
+
const relation = modelClass.getRelationUnsafe(node.$relation);
|
|
162
|
+
|
|
163
|
+
if (!relation) {
|
|
164
|
+
throw new RelationDoesNotExistError(node.$relation);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const childExpr = new RelationExpression(node);
|
|
168
|
+
|
|
169
|
+
cb(childExpr, relation);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
expressionsAtPath(path) {
|
|
175
|
+
return findExpressionsAtPath(this, RelationExpression.create(path), []);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
clone() {
|
|
179
|
+
return new RelationExpression(cloneNode(this.node), this.recursionDepth);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
toString() {
|
|
183
|
+
return toString(this.node);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
toPojo() {
|
|
187
|
+
return cloneNode(this.node);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
toJSON() {
|
|
191
|
+
return this.toPojo();
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
const parseCache = new Map();
|
|
196
|
+
function parse(str) {
|
|
197
|
+
const cachedNode = parseCache.get(str);
|
|
198
|
+
|
|
199
|
+
if (cachedNode) {
|
|
200
|
+
return cloneNode(cachedNode);
|
|
201
|
+
} else {
|
|
202
|
+
const node = parser.parse(str);
|
|
203
|
+
parseCache.set(str, cloneNode(node));
|
|
204
|
+
return node;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// All enumerable properties of a node that don't start with `$`
|
|
209
|
+
// are child nodes.
|
|
210
|
+
function getChildNames(node) {
|
|
211
|
+
if (!node) {
|
|
212
|
+
return [];
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
const childNames = [];
|
|
216
|
+
|
|
217
|
+
for (const key of Object.keys(node)) {
|
|
218
|
+
if (key[0] !== '$') {
|
|
219
|
+
childNames.push(key);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
return childNames;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
function toString(node) {
|
|
227
|
+
const childNames = node.$childNames;
|
|
228
|
+
|
|
229
|
+
let childExpr = childNames.map((childName) => node[childName]).map(toString);
|
|
230
|
+
let str = node.$relation;
|
|
231
|
+
|
|
232
|
+
if (node.$recursive) {
|
|
233
|
+
if (isNumber(node.$recursive)) {
|
|
234
|
+
str += '.^' + node.$recursive;
|
|
235
|
+
} else {
|
|
236
|
+
str += '.^';
|
|
237
|
+
}
|
|
238
|
+
} else if (node.$allRecursive) {
|
|
239
|
+
str += '.*';
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
if (childExpr.length > 1) {
|
|
243
|
+
childExpr = `[${childExpr.join(', ')}]`;
|
|
244
|
+
} else {
|
|
245
|
+
childExpr = childExpr[0];
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
if (node.$modify.length) {
|
|
249
|
+
str += `(${node.$modify.join(', ')})`;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
if (node.$name !== node.$relation) {
|
|
253
|
+
str += ` as ${node.$name}`;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
if (childExpr) {
|
|
257
|
+
if (str) {
|
|
258
|
+
return `${str}.${childExpr}`;
|
|
259
|
+
} else {
|
|
260
|
+
return childExpr;
|
|
261
|
+
}
|
|
262
|
+
} else {
|
|
263
|
+
return str;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
function cloneNode(node) {
|
|
268
|
+
return normalizeNode(node);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
function modelGraphToNode(models, node) {
|
|
272
|
+
if (!models) {
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
if (Array.isArray(models)) {
|
|
277
|
+
for (let i = 0, l = models.length; i < l; ++i) {
|
|
278
|
+
modelToNode(models[i], node);
|
|
279
|
+
}
|
|
280
|
+
} else {
|
|
281
|
+
modelToNode(models, node);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
return node;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
function modelToNode(model, node) {
|
|
288
|
+
const modelClass = model.constructor;
|
|
289
|
+
const relationNames = modelClass.getRelationNames();
|
|
290
|
+
|
|
291
|
+
for (let r = 0, lr = relationNames.length; r < lr; ++r) {
|
|
292
|
+
const relName = relationNames[r];
|
|
293
|
+
|
|
294
|
+
if (model[relName] !== undefined) {
|
|
295
|
+
let childNode = node[relName];
|
|
296
|
+
|
|
297
|
+
if (!childNode) {
|
|
298
|
+
childNode = newNode(relName);
|
|
299
|
+
node[relName] = childNode;
|
|
300
|
+
node.$childNames.push(relName);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
modelGraphToNode(model[relName], childNode);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
function newNode(name = null, allRecusive = false) {
|
|
309
|
+
return normalizeNode(null, name, allRecusive);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
function normalizeNode(node = null, name = null, allRecusive = false) {
|
|
313
|
+
const normalized = {
|
|
314
|
+
$name: normalizeName(node, name),
|
|
315
|
+
$relation: normalizeRelation(node, name),
|
|
316
|
+
$modify: normalizeModify(node),
|
|
317
|
+
$recursive: normalizeRecursive(node),
|
|
318
|
+
$allRecursive: normalizeAllRecursive(node, allRecusive),
|
|
319
|
+
$childNames: normalizeChildNames(node),
|
|
320
|
+
};
|
|
321
|
+
|
|
322
|
+
for (const childName of normalized.$childNames) {
|
|
323
|
+
const childNode = node[childName];
|
|
324
|
+
|
|
325
|
+
if (isObject(childNode) || childNode === true) {
|
|
326
|
+
normalized[childName] = normalizeNode(childNode, childName);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
return normalized;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
function normalizeName(node, name) {
|
|
334
|
+
return (node && node.$name) || name || null;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
function normalizeRelation(node, name) {
|
|
338
|
+
return (node && node.$relation) || name || null;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
function normalizeModify(node) {
|
|
342
|
+
if (!node || !node.$modify) {
|
|
343
|
+
return [];
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
return Array.isArray(node.$modify) ? node.$modify.slice() : [node.$modify];
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
function normalizeRecursive(node) {
|
|
350
|
+
return (node && node.$recursive) || false;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
function normalizeAllRecursive(node, allRecusive) {
|
|
354
|
+
return (node && node.$allRecursive) || allRecusive || false;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
function normalizeChildNames(node) {
|
|
358
|
+
return (node && node.$childNames && node.$childNames.slice()) || getChildNames(node);
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
function findExpressionsAtPath(target, path, results) {
|
|
362
|
+
if (path.node.$childNames.length == 0) {
|
|
363
|
+
// Path leaf reached, add target node to result set.
|
|
364
|
+
results.push(target);
|
|
365
|
+
} else {
|
|
366
|
+
for (const childName of path.node.$childNames) {
|
|
367
|
+
const pathChild = path.childExpression(childName);
|
|
368
|
+
const targetChild = target.childExpression(childName);
|
|
369
|
+
|
|
370
|
+
if (targetChild) {
|
|
371
|
+
findExpressionsAtPath(targetChild, pathChild, results);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
return results;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
function mergeNodes(node1, node2) {
|
|
380
|
+
const node = {
|
|
381
|
+
$name: node1.$name,
|
|
382
|
+
$relation: node1.$relation,
|
|
383
|
+
$modify: union(node1.$modify, node2.$modify),
|
|
384
|
+
$recursive: mergeRecursion(node1.$recursive, node2.$recursive),
|
|
385
|
+
$allRecursive: node1.$allRecursive || node2.$allRecursive,
|
|
386
|
+
$childNames: null,
|
|
387
|
+
};
|
|
388
|
+
|
|
389
|
+
if (!node.$recursive && !node.$allRecursive) {
|
|
390
|
+
node.$childNames = union(node1.$childNames, node2.$childNames);
|
|
391
|
+
|
|
392
|
+
for (const childName of node.$childNames) {
|
|
393
|
+
const child1 = node1[childName];
|
|
394
|
+
const child2 = node2[childName];
|
|
395
|
+
|
|
396
|
+
if (child1 && child2) {
|
|
397
|
+
node[childName] = mergeNodes(child1, child2);
|
|
398
|
+
} else {
|
|
399
|
+
node[childName] = child1 || child2;
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
} else {
|
|
403
|
+
node.$childNames = [];
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
return node;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
function mergeRecursion(rec1, rec2) {
|
|
410
|
+
if (rec1 === true || rec2 === true) {
|
|
411
|
+
return true;
|
|
412
|
+
} else if (isNumber(rec1) && isNumber(rec2)) {
|
|
413
|
+
return Math.max(rec1, rec2);
|
|
414
|
+
} else {
|
|
415
|
+
return rec1 || rec2;
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
Object.defineProperties(RelationExpression.prototype, {
|
|
420
|
+
isObjectionRelationExpression: {
|
|
421
|
+
enumerable: false,
|
|
422
|
+
writable: false,
|
|
423
|
+
value: true,
|
|
424
|
+
},
|
|
425
|
+
});
|
|
426
|
+
|
|
427
|
+
module.exports = {
|
|
428
|
+
RelationExpression,
|
|
429
|
+
RelationExpressionParseError,
|
|
430
|
+
DuplicateRelationError,
|
|
431
|
+
};
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { asArray } = require('../utils/objectUtils');
|
|
4
|
+
|
|
5
|
+
const BUILDER_SYMBOL = Symbol();
|
|
6
|
+
|
|
7
|
+
class StaticHookArguments {
|
|
8
|
+
constructor({ builder, result = null }) {
|
|
9
|
+
// The builder should never be accessed through the arguments.
|
|
10
|
+
// Hide it as well as possible to discourage people from
|
|
11
|
+
// digging it out.
|
|
12
|
+
Object.defineProperty(this, BUILDER_SYMBOL, {
|
|
13
|
+
value: builder,
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
Object.defineProperty(this, 'result', {
|
|
17
|
+
value: asArray(result),
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
static create(args) {
|
|
22
|
+
return new StaticHookArguments(args);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
get asFindQuery() {
|
|
26
|
+
return () => {
|
|
27
|
+
return this[BUILDER_SYMBOL].toFindQuery().clearWithGraphFetched().runAfter(asArray);
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
get context() {
|
|
32
|
+
return this[BUILDER_SYMBOL].context();
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
get transaction() {
|
|
36
|
+
return this[BUILDER_SYMBOL].unsafeKnex();
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
get relation() {
|
|
40
|
+
const op = this[BUILDER_SYMBOL].findOperation(hasRelation);
|
|
41
|
+
|
|
42
|
+
if (op) {
|
|
43
|
+
return getRelation(op);
|
|
44
|
+
} else {
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
get modelOptions() {
|
|
50
|
+
const op = this[BUILDER_SYMBOL].findOperation(hasModelOptions);
|
|
51
|
+
|
|
52
|
+
if (op) {
|
|
53
|
+
return getModelOptions(op);
|
|
54
|
+
} else {
|
|
55
|
+
return undefined;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
get items() {
|
|
60
|
+
const op = this[BUILDER_SYMBOL].findOperation(hasItems);
|
|
61
|
+
|
|
62
|
+
if (op) {
|
|
63
|
+
return asArray(getItems(op));
|
|
64
|
+
} else {
|
|
65
|
+
return [];
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
get inputItems() {
|
|
70
|
+
const op = this[BUILDER_SYMBOL].findOperation(hasInputItems);
|
|
71
|
+
|
|
72
|
+
if (op) {
|
|
73
|
+
return asArray(getInputItems(op));
|
|
74
|
+
} else {
|
|
75
|
+
return [];
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
get cancelQuery() {
|
|
80
|
+
const args = this;
|
|
81
|
+
|
|
82
|
+
return (cancelValue) => {
|
|
83
|
+
const builder = this[BUILDER_SYMBOL];
|
|
84
|
+
|
|
85
|
+
if (cancelValue === undefined) {
|
|
86
|
+
if (builder.isInsert()) {
|
|
87
|
+
cancelValue = args.inputItems;
|
|
88
|
+
} else if (builder.isFind()) {
|
|
89
|
+
cancelValue = [];
|
|
90
|
+
} else {
|
|
91
|
+
cancelValue = 0;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
builder.resolve(cancelValue);
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function getRelation(op) {
|
|
101
|
+
return op.relation;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function hasRelation(op) {
|
|
105
|
+
return !!getRelation(op);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function getModelOptions(op) {
|
|
109
|
+
return op.modelOptions;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function hasModelOptions(op) {
|
|
113
|
+
return !!getModelOptions(op);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function getItems(op) {
|
|
117
|
+
return op.instance || (op.owner && op.owner.isModels && op.owner.modelArray);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function hasItems(op) {
|
|
121
|
+
return !!getItems(op);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function getInputItems(op) {
|
|
125
|
+
return op.models || op.model;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function hasInputItems(op) {
|
|
129
|
+
return !!getInputItems(op);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
module.exports = {
|
|
133
|
+
StaticHookArguments,
|
|
134
|
+
};
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { asArray, isObject } = require('../utils/objectUtils');
|
|
4
|
+
const { buildArg } = require('../utils/buildUtils');
|
|
5
|
+
const { isMySql } = require('../utils/knexUtils');
|
|
6
|
+
const { toMySqlCastType, isBooleanType } = require('../utils/mysqlJsonPath');
|
|
7
|
+
const { addExpressionMethods } = require('./expressions');
|
|
8
|
+
|
|
9
|
+
class ValueBuilder {
|
|
10
|
+
constructor(value) {
|
|
11
|
+
this._value = value;
|
|
12
|
+
this._cast = null;
|
|
13
|
+
// Cast objects and arrays to json by default.
|
|
14
|
+
this._toJson = isObject(value);
|
|
15
|
+
this._toArray = false;
|
|
16
|
+
this._alias = null;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
get cast() {
|
|
20
|
+
return this._cast;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
castText() {
|
|
24
|
+
return this.castTo('text');
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
castInt() {
|
|
28
|
+
return this.castTo('integer');
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
castBigInt() {
|
|
32
|
+
return this.castTo('bigint');
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
castFloat() {
|
|
36
|
+
return this.castTo('float');
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
castDecimal() {
|
|
40
|
+
return this.castTo('decimal');
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
castReal() {
|
|
44
|
+
return this.castTo('real');
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
castBool() {
|
|
48
|
+
return this.castTo('boolean');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
castJson() {
|
|
52
|
+
this._toArray = false;
|
|
53
|
+
this._toJson = true;
|
|
54
|
+
this._cast = 'jsonb';
|
|
55
|
+
return this;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
castTo(sqlType) {
|
|
59
|
+
this._cast = sqlType;
|
|
60
|
+
return this;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
asArray() {
|
|
64
|
+
this._toJson = false;
|
|
65
|
+
this._toArray = true;
|
|
66
|
+
return this;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
as(alias) {
|
|
70
|
+
this._alias = alias;
|
|
71
|
+
return this;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
toKnexRaw(builder) {
|
|
75
|
+
return builder.knex().raw(...this._createRawArgs(builder));
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
_createRawArgs(builder) {
|
|
79
|
+
let sql = null;
|
|
80
|
+
let bindings = [];
|
|
81
|
+
|
|
82
|
+
if (this._toJson) {
|
|
83
|
+
bindings.push(JSON.stringify(this._value));
|
|
84
|
+
sql = '?';
|
|
85
|
+
} else if (this._toArray) {
|
|
86
|
+
const values = asArray(this._value);
|
|
87
|
+
bindings.push(...values.map((it) => buildArg(it, builder)));
|
|
88
|
+
sql = `ARRAY[${values.map(() => '?').join(', ')}]`;
|
|
89
|
+
} else {
|
|
90
|
+
bindings.push(this._value);
|
|
91
|
+
sql = '?';
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const mysql = isMySql(builder.unsafeKnex());
|
|
95
|
+
|
|
96
|
+
if (this._toJson && !this._cast && mysql) {
|
|
97
|
+
// MySQL compares strings and JSON values as strings, so `{}` is never
|
|
98
|
+
// equal to a JSON column without the cast. Postgres casts it implicitly.
|
|
99
|
+
sql = `CAST(${sql} AS JSON)`;
|
|
100
|
+
} else if (this._cast && mysql) {
|
|
101
|
+
// MySQL can't cast to a boolean.
|
|
102
|
+
sql = isBooleanType(this._cast)
|
|
103
|
+
? `(${sql} <> 0)`
|
|
104
|
+
: `CAST(${sql} AS ${toMySqlCastType(this._cast)})`;
|
|
105
|
+
} else if (this._cast) {
|
|
106
|
+
sql = `CAST(${sql} AS ${this._cast})`;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (this._alias) {
|
|
110
|
+
bindings.push(this._alias);
|
|
111
|
+
sql = `${sql} as ??`;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return [sql, bindings];
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
addExpressionMethods(ValueBuilder.prototype);
|
|
119
|
+
|
|
120
|
+
function val(val) {
|
|
121
|
+
return new ValueBuilder(val);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
module.exports = {
|
|
125
|
+
ValueBuilder,
|
|
126
|
+
val,
|
|
127
|
+
};
|