@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,236 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { isObject, asArray, asSingle, uniqBy } = require('../utils/objectUtils');
|
|
4
|
+
const { normalizeIds } = require('../utils/normalizeIds');
|
|
5
|
+
|
|
6
|
+
const Type = {
|
|
7
|
+
Models: 'Models',
|
|
8
|
+
Reference: 'Reference',
|
|
9
|
+
QueryBuilder: 'QueryBuilder',
|
|
10
|
+
Identifiers: 'Identifiers',
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
class RelationOwner {
|
|
14
|
+
constructor(owner) {
|
|
15
|
+
this.owner = owner;
|
|
16
|
+
this.type = detectType(owner);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
static create(owner) {
|
|
20
|
+
return new RelationOwner(owner);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
static createParentReference(builder, relation) {
|
|
24
|
+
return this.create(relation.ownerProp.refs(findFirstNonPartialAncestorQuery(builder)));
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
get isModels() {
|
|
28
|
+
return this.type === Type.Models;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
get isReference() {
|
|
32
|
+
return this.type === Type.Reference;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
get isQueryBuilder() {
|
|
36
|
+
return this.type === Type.QueryBuilder;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
get isIdentifiers() {
|
|
40
|
+
return this.type === Type.Identifiers;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
get modelArray() {
|
|
44
|
+
return asArray(this.owner);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
get model() {
|
|
48
|
+
return asSingle(this.owner);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
get reference() {
|
|
52
|
+
return this.owner;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
get queryBuilder() {
|
|
56
|
+
return this.owner;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
get identifiers() {
|
|
60
|
+
return this.owner;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
buildFindQuery(builder, relation, relatedRefs) {
|
|
64
|
+
if (this.isReference) {
|
|
65
|
+
relatedRefs.forEach((relatedRef, i) => {
|
|
66
|
+
builder.where(relatedRef, this.reference[i]);
|
|
67
|
+
});
|
|
68
|
+
} else if (this.isModels || this.isIdentifiers || this.isQueryBuilder) {
|
|
69
|
+
const values = this.getProps(relation);
|
|
70
|
+
|
|
71
|
+
if (values) {
|
|
72
|
+
builder.whereInComposite(relatedRefs, values);
|
|
73
|
+
} else {
|
|
74
|
+
builder.where(false).resolve([]);
|
|
75
|
+
}
|
|
76
|
+
} else {
|
|
77
|
+
builder.where(false).resolve([]);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return builder;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
getProps(relation, ownerProp = relation.ownerProp) {
|
|
84
|
+
if (this.isModels) {
|
|
85
|
+
return this._getPropsFromModels(ownerProp);
|
|
86
|
+
} else if (this.isIdentifiers) {
|
|
87
|
+
return this._getPropsFromIdentifiers(relation, ownerProp);
|
|
88
|
+
} else if (this.isQueryBuilder) {
|
|
89
|
+
return this._getPropsFromQuery(relation, ownerProp);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
getSplitProps(builder, relation, ownerProp = relation.ownerProp) {
|
|
94
|
+
const values = this.getProps(relation, relation.ownerProp);
|
|
95
|
+
|
|
96
|
+
if (isQueryBuilder(values)) {
|
|
97
|
+
if (ownerProp.size === 1) {
|
|
98
|
+
return [[values]];
|
|
99
|
+
} else {
|
|
100
|
+
// For composite keys, we need to create a query builder for each
|
|
101
|
+
// key. Each query builder only select that key.
|
|
102
|
+
return [
|
|
103
|
+
Array.from({ length: ownerProp.size }).map((_, i) => {
|
|
104
|
+
return values.clone().clearSelect().select(ownerProp.ref(builder, i));
|
|
105
|
+
}),
|
|
106
|
+
];
|
|
107
|
+
}
|
|
108
|
+
} else {
|
|
109
|
+
return values;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
getNormalizedIdentifiers(ownerProp) {
|
|
114
|
+
return normalizeIds(this.identifiers, ownerProp, {
|
|
115
|
+
arrayOutput: true,
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
_getPropsFromModels(ownerProp) {
|
|
120
|
+
const props = this.modelArray.map((owner) => ownerProp.getProps(owner));
|
|
121
|
+
|
|
122
|
+
if (!containsNonNull(props)) {
|
|
123
|
+
return null;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return uniqBy(props, join);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
_getPropsFromIdentifiers(relation, ownerProp) {
|
|
130
|
+
const ids = this.getNormalizedIdentifiers(ownerProp);
|
|
131
|
+
|
|
132
|
+
if (isIdProp(ownerProp)) {
|
|
133
|
+
return ids;
|
|
134
|
+
} else {
|
|
135
|
+
const query = relation.ownerModelClass.query();
|
|
136
|
+
|
|
137
|
+
query.findByIds(ids);
|
|
138
|
+
query.select(ownerProp.refs(query));
|
|
139
|
+
|
|
140
|
+
return query;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
_getPropsFromQuery(relation, ownerProp) {
|
|
145
|
+
const query = this.queryBuilder.clone();
|
|
146
|
+
|
|
147
|
+
if (isOwnerModelClassQuery(query, relation)) {
|
|
148
|
+
query.clearSelect();
|
|
149
|
+
query.select(ownerProp.refs(query));
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
return query;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function detectType(owner) {
|
|
157
|
+
if (isModel(owner) || isModelArray(owner)) {
|
|
158
|
+
return Type.Models;
|
|
159
|
+
} else if (isReferenceArray(owner)) {
|
|
160
|
+
return Type.Reference;
|
|
161
|
+
} else if (isQueryBuilder(owner)) {
|
|
162
|
+
return Type.QueryBuilder;
|
|
163
|
+
} else {
|
|
164
|
+
return Type.Identifiers;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function isModel(item) {
|
|
169
|
+
return isObject(item) && !!item.$isObjectionModel;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function isModelArray(item) {
|
|
173
|
+
return Array.isArray(item) && isModel(item[0]);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function isReference(item) {
|
|
177
|
+
return isObject(item) && !!item.isObjectionReferenceBuilder;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function isReferenceArray(item) {
|
|
181
|
+
return Array.isArray(item) && isReference(item[0]);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function isQueryBuilder(item) {
|
|
185
|
+
return isObject(item) && !!item.isObjectionQueryBuilder;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function findFirstNonPartialAncestorQuery(builder) {
|
|
189
|
+
builder = builder.parentQuery();
|
|
190
|
+
if (!builder)
|
|
191
|
+
throw Error(
|
|
192
|
+
'query method `for` ommitted outside a subquery, can not figure out relation target',
|
|
193
|
+
);
|
|
194
|
+
while (builder.isPartial()) {
|
|
195
|
+
if (!builder.parentQuery()) {
|
|
196
|
+
break;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
builder = builder.parentQuery();
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
return builder;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
function containsNonNull(arr) {
|
|
206
|
+
for (let i = 0, l = arr.length; i < l; ++i) {
|
|
207
|
+
const val = arr[i];
|
|
208
|
+
|
|
209
|
+
if (Array.isArray(val)) {
|
|
210
|
+
if (containsNonNull(val)) {
|
|
211
|
+
return true;
|
|
212
|
+
}
|
|
213
|
+
} else if (val !== null && val !== undefined) {
|
|
214
|
+
return true;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
return false;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
function join(id) {
|
|
222
|
+
return id.map((x) => (Buffer.isBuffer(x) ? x.toString('hex') : x)).join(',');
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
function isIdProp(relationProp) {
|
|
226
|
+
const idProp = relationProp.modelClass.getIdRelationProperty();
|
|
227
|
+
return idProp.props.every((prop, i) => prop === relationProp.props[i]);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
function isOwnerModelClassQuery(query, relation) {
|
|
231
|
+
return query.modelClass().getTableName() === relation.ownerModelClass.getTableName();
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
module.exports = {
|
|
235
|
+
RelationOwner,
|
|
236
|
+
};
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { asArray, isObject, uniqBy, get, set } = require('../utils/objectUtils');
|
|
4
|
+
const { ref: createRef } = require('../queryBuilder/ReferenceBuilder');
|
|
5
|
+
const { propToStr, PROP_KEY_PREFIX } = require('../model/modelValues');
|
|
6
|
+
|
|
7
|
+
class ModelNotFoundError extends Error {
|
|
8
|
+
constructor(tableName) {
|
|
9
|
+
super();
|
|
10
|
+
this.name = this.constructor.name;
|
|
11
|
+
this.tableName = tableName;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
class InvalidReferenceError extends Error {
|
|
16
|
+
constructor() {
|
|
17
|
+
super();
|
|
18
|
+
this.name = this.constructor.name;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// A pair of these define how two tables are related to each other.
|
|
23
|
+
// Both the owner and the related table have one of these.
|
|
24
|
+
//
|
|
25
|
+
// A relation property can be a single column, an array of columns
|
|
26
|
+
// (composite key) a json column reference, an array of json column
|
|
27
|
+
// references or any combination of the above.
|
|
28
|
+
class RelationProperty {
|
|
29
|
+
// references must be a reference string like `Table.column:maybe.some.json[1].path`.
|
|
30
|
+
// or an array of such references (composite key).
|
|
31
|
+
//
|
|
32
|
+
// modelClassResolver must be a function that takes a table name
|
|
33
|
+
// and returns a model class.
|
|
34
|
+
constructor(references, modelClassResolver) {
|
|
35
|
+
const refs = createRefs(asArray(references));
|
|
36
|
+
const paths = createPaths(refs, modelClassResolver);
|
|
37
|
+
const modelClass = resolveModelClass(paths);
|
|
38
|
+
|
|
39
|
+
this._refs = refs.map((ref) => ref.model(modelClass));
|
|
40
|
+
this._modelClass = modelClass;
|
|
41
|
+
this._props = paths.map((it) => it.path[0]);
|
|
42
|
+
this._cols = refs.map((it) => it.column);
|
|
43
|
+
this._propGetters = paths.map((it) => createGetter(it.path));
|
|
44
|
+
this._propSetters = paths.map((it) => createSetter(it.path));
|
|
45
|
+
this._patchers = refs.map((it, i) => createPatcher(it, paths[i].path));
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
static get ModelNotFoundError() {
|
|
49
|
+
return ModelNotFoundError;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
static get InvalidReferenceError() {
|
|
53
|
+
return InvalidReferenceError;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// The number of columns.
|
|
57
|
+
get size() {
|
|
58
|
+
return this._refs.length;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// The model class that owns the property.
|
|
62
|
+
get modelClass() {
|
|
63
|
+
return this._modelClass;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// An array of property names. Contains multiple values in case of composite key.
|
|
67
|
+
// This may be different from `cols` if the model class has some kind of conversion
|
|
68
|
+
// between database and "external" formats, for example a snake_case to camelCase
|
|
69
|
+
// conversion.
|
|
70
|
+
get props() {
|
|
71
|
+
return this._props;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// An array of column names. Contains multiple values in case of composite key.
|
|
75
|
+
// This may be different from `props` if the model class has some kind of conversion
|
|
76
|
+
// between database and "external" formats, for example a snake_case to camelCase
|
|
77
|
+
// conversion.
|
|
78
|
+
get cols() {
|
|
79
|
+
return this._cols;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
forEach(callback) {
|
|
83
|
+
for (let i = 0, l = this.size; i < l; ++i) {
|
|
84
|
+
callback(i);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Creates a concatenated string from the property values of the given object.
|
|
89
|
+
propKey(obj) {
|
|
90
|
+
const size = this.size;
|
|
91
|
+
let key = PROP_KEY_PREFIX;
|
|
92
|
+
|
|
93
|
+
for (let i = 0; i < size; ++i) {
|
|
94
|
+
key += propToStr(this.getProp(obj, i));
|
|
95
|
+
|
|
96
|
+
if (i !== size - 1) {
|
|
97
|
+
key += ',';
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return key;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Returns the property values of the given object as an array.
|
|
105
|
+
getProps(obj) {
|
|
106
|
+
const size = this.size;
|
|
107
|
+
const props = new Array(size);
|
|
108
|
+
|
|
109
|
+
for (let i = 0; i < size; ++i) {
|
|
110
|
+
props[i] = this.getProp(obj, i);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return props;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Returns true if the given object has a non-null value in all properties.
|
|
117
|
+
hasProps(obj) {
|
|
118
|
+
const size = this.size;
|
|
119
|
+
|
|
120
|
+
for (let i = 0; i < size; ++i) {
|
|
121
|
+
const prop = this.getProp(obj, i);
|
|
122
|
+
|
|
123
|
+
if (prop === null || prop === undefined) {
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return true;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Returns the index:th property value of the given object.
|
|
132
|
+
getProp(obj, index) {
|
|
133
|
+
return this._propGetters[index](obj);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Sets the index:th property value of the given object.
|
|
137
|
+
setProp(obj, index, value) {
|
|
138
|
+
return this._propSetters[index](obj, value);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Returns an instance of ReferenceBuilder that points to the index:th
|
|
142
|
+
// value of a row.
|
|
143
|
+
ref(builder, index) {
|
|
144
|
+
const table = builder.tableRefFor(this.modelClass);
|
|
145
|
+
|
|
146
|
+
return this._refs[index].clone().table(table);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Returns an array of reference builders. `ref(builder, i)` for each i.
|
|
150
|
+
refs(builder) {
|
|
151
|
+
const refs = new Array(this.size);
|
|
152
|
+
|
|
153
|
+
for (let i = 0, l = refs.length; i < l; ++i) {
|
|
154
|
+
refs[i] = this.ref(builder, i);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return refs;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Appends an update operation for the index:th column into `patch` object.
|
|
161
|
+
patch(patch, index, value) {
|
|
162
|
+
return this._patchers[index](patch, value);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// String representation of this property's index:th column for logging.
|
|
166
|
+
propDescription(index) {
|
|
167
|
+
return this._refs[index].expression;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function createRefs(refs) {
|
|
172
|
+
try {
|
|
173
|
+
return refs.map((it) => {
|
|
174
|
+
if (!isObject(it) || !it.isObjectionReferenceBuilder) {
|
|
175
|
+
return createRef(it);
|
|
176
|
+
} else {
|
|
177
|
+
return it;
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
} catch (err) {
|
|
181
|
+
throw new InvalidReferenceError();
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function createPaths(refs, modelClassResolver) {
|
|
186
|
+
return refs.map((ref) => {
|
|
187
|
+
if (!ref.tableName) {
|
|
188
|
+
throw new InvalidReferenceError();
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const modelClass = modelClassResolver(ref.tableName);
|
|
192
|
+
|
|
193
|
+
if (!modelClass) {
|
|
194
|
+
throw new ModelNotFoundError(ref.tableName);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
const prop = modelClass.columnNameToPropertyName(ref.column);
|
|
198
|
+
const jsonPath = ref.parsedExpr.access.map((it) => it.ref);
|
|
199
|
+
|
|
200
|
+
return {
|
|
201
|
+
path: [prop].concat(jsonPath),
|
|
202
|
+
modelClass,
|
|
203
|
+
};
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function resolveModelClass(paths) {
|
|
208
|
+
const modelClasses = paths.map((it) => it.modelClass);
|
|
209
|
+
const uniqueModelClasses = uniqBy(modelClasses);
|
|
210
|
+
|
|
211
|
+
if (uniqueModelClasses.length !== 1) {
|
|
212
|
+
throw new InvalidReferenceError();
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
return modelClasses[0];
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
function createGetter(path) {
|
|
219
|
+
if (path.length === 1) {
|
|
220
|
+
const prop = path[0];
|
|
221
|
+
return (obj) => obj[prop];
|
|
222
|
+
} else {
|
|
223
|
+
return (obj) => get(obj, path);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
function createSetter(path) {
|
|
228
|
+
if (path.length === 1) {
|
|
229
|
+
const prop = path[0];
|
|
230
|
+
return (obj, value) => (obj[prop] = value);
|
|
231
|
+
} else {
|
|
232
|
+
return (obj, value) => set(obj, path, value);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
function createPatcher(ref, path) {
|
|
237
|
+
if (ref.isPlainColumnRef) {
|
|
238
|
+
return (patch, value) => (patch[path[0]] = value);
|
|
239
|
+
} else {
|
|
240
|
+
// Objection `patch`, `update` etc. methods understand field expressions.
|
|
241
|
+
return (patch, value) => (patch[ref.expression] = value);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
module.exports = {
|
|
246
|
+
RelationProperty,
|
|
247
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { UpdateOperation } = require('../queryBuilder/operations/UpdateOperation');
|
|
4
|
+
const { RelationFindOperation } = require('./RelationFindOperation');
|
|
5
|
+
|
|
6
|
+
class RelationUpdateOperation extends UpdateOperation {
|
|
7
|
+
constructor(name, opt) {
|
|
8
|
+
super(name, opt);
|
|
9
|
+
|
|
10
|
+
this.relation = opt.relation;
|
|
11
|
+
this.owner = opt.owner;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
onBuild(builder) {
|
|
15
|
+
super.onBuild(builder);
|
|
16
|
+
|
|
17
|
+
this.relation.findQuery(builder, this.owner);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
toFindOperation() {
|
|
21
|
+
return new RelationFindOperation('find', {
|
|
22
|
+
relation: this.relation,
|
|
23
|
+
owner: this.owner,
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
module.exports = {
|
|
29
|
+
RelationUpdateOperation,
|
|
30
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { RelationDeleteOperation } = require('../RelationDeleteOperation');
|
|
4
|
+
|
|
5
|
+
class BelongsToOneDeleteOperation extends RelationDeleteOperation {
|
|
6
|
+
onAfter1(_, result) {
|
|
7
|
+
if (this.owner.isModels) {
|
|
8
|
+
const ownerProp = this.relation.ownerProp;
|
|
9
|
+
|
|
10
|
+
for (const owner of this.owner.modelArray) {
|
|
11
|
+
ownerProp.forEach((i) => {
|
|
12
|
+
ownerProp.setProp(owner, i, null);
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return result;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
module.exports = {
|
|
22
|
+
BelongsToOneDeleteOperation,
|
|
23
|
+
};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { RelationInsertOperation } = require('../RelationInsertOperation');
|
|
4
|
+
const { BelongsToOneRelateOperation } = require('./BelongsToOneRelateOperation');
|
|
5
|
+
|
|
6
|
+
class BelongsToOneInsertOperation extends RelationInsertOperation {
|
|
7
|
+
onAdd(builder, args) {
|
|
8
|
+
const retVal = super.onAdd(builder, args);
|
|
9
|
+
|
|
10
|
+
if (this.models.length > 1) {
|
|
11
|
+
throw this.relation.createError('can only insert one model to a BelongsToOneRelation');
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return retVal;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
async onAfter1(builder, ret) {
|
|
18
|
+
const inserted = await super.onAfter1(builder, ret);
|
|
19
|
+
|
|
20
|
+
if (!builder.isExecutable()) {
|
|
21
|
+
return inserted;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const relateOp = new BelongsToOneRelateOperation('relate', {
|
|
25
|
+
relation: this.relation,
|
|
26
|
+
owner: this.owner,
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
if (this.assignResultToOwner && this.owner.isModels) {
|
|
30
|
+
for (const owner of this.owner.modelArray) {
|
|
31
|
+
owner.$setRelated(this.relation, inserted);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
relateOp.onAdd(builder, [inserted]);
|
|
36
|
+
await relateOp.queryExecutor(builder);
|
|
37
|
+
|
|
38
|
+
return inserted;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
module.exports = {
|
|
43
|
+
BelongsToOneInsertOperation,
|
|
44
|
+
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { normalizeIds } = require('../../utils/normalizeIds');
|
|
4
|
+
const { RelateOperation } = require('../../queryBuilder/operations/RelateOperation');
|
|
5
|
+
|
|
6
|
+
class BelongsToOneRelateOperation extends RelateOperation {
|
|
7
|
+
onAdd(_, args) {
|
|
8
|
+
this.input = args[0];
|
|
9
|
+
this.ids = normalizeIds(args[0], this.relation.relatedProp, { arrayOutput: true });
|
|
10
|
+
|
|
11
|
+
assertOneId(this.ids);
|
|
12
|
+
return true;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
queryExecutor(builder) {
|
|
16
|
+
const patch = {};
|
|
17
|
+
const ownerProp = this.relation.ownerProp;
|
|
18
|
+
|
|
19
|
+
ownerProp.forEach((i) => {
|
|
20
|
+
const relatedValue = this.ids[0][i];
|
|
21
|
+
|
|
22
|
+
if (this.owner.isModels) {
|
|
23
|
+
for (const owner of this.owner.modelArray) {
|
|
24
|
+
ownerProp.setProp(owner, i, relatedValue);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
ownerProp.patch(patch, i, relatedValue);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
const ownerIdProp = this.relation.ownerModelClass.getIdRelationProperty();
|
|
32
|
+
const ownerIds = this.owner.getProps(this.relation, ownerIdProp);
|
|
33
|
+
|
|
34
|
+
return this.relation.ownerModelClass
|
|
35
|
+
.query()
|
|
36
|
+
.childQueryOf(builder)
|
|
37
|
+
.patch(patch)
|
|
38
|
+
.whereInComposite(ownerIdProp.refs(builder), ownerIds);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function assertOneId(ids) {
|
|
43
|
+
if (ids.length > 1) {
|
|
44
|
+
throw new Error('can only relate one model to a BelongsToOneRelation');
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
module.exports = {
|
|
49
|
+
BelongsToOneRelateOperation,
|
|
50
|
+
};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { Relation } = require('../Relation');
|
|
4
|
+
const { BelongsToOneInsertOperation } = require('./BelongsToOneInsertOperation');
|
|
5
|
+
const { BelongsToOneDeleteOperation } = require('./BelongsToOneDeleteOperation');
|
|
6
|
+
const { BelongsToOneRelateOperation } = require('./BelongsToOneRelateOperation');
|
|
7
|
+
const { BelongsToOneUnrelateOperation } = require('./BelongsToOneUnrelateOperation');
|
|
8
|
+
|
|
9
|
+
class BelongsToOneRelation extends Relation {
|
|
10
|
+
isOneToOne() {
|
|
11
|
+
return true;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
insert(_, owner) {
|
|
15
|
+
return new BelongsToOneInsertOperation('insert', {
|
|
16
|
+
relation: this,
|
|
17
|
+
owner,
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
delete(_, owner) {
|
|
22
|
+
return new BelongsToOneDeleteOperation('delete', {
|
|
23
|
+
relation: this,
|
|
24
|
+
owner,
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
relate(_, owner) {
|
|
29
|
+
return new BelongsToOneRelateOperation('relate', {
|
|
30
|
+
relation: this,
|
|
31
|
+
owner,
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
unrelate(_, owner) {
|
|
36
|
+
return new BelongsToOneUnrelateOperation('unrelate', {
|
|
37
|
+
relation: this,
|
|
38
|
+
owner,
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
Object.defineProperties(BelongsToOneRelation.prototype, {
|
|
44
|
+
isObjectionBelongsToOneRelation: {
|
|
45
|
+
enumerable: false,
|
|
46
|
+
writable: false,
|
|
47
|
+
value: true,
|
|
48
|
+
},
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
module.exports = {
|
|
52
|
+
BelongsToOneRelation,
|
|
53
|
+
};
|