@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,240 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { ModelGraphEdge } = require('./ModelGraphEdge');
|
|
4
|
+
const { isNumber } = require('../../utils/objectUtils');
|
|
5
|
+
|
|
6
|
+
const NOT_CALCULATED = {};
|
|
7
|
+
|
|
8
|
+
class ModelGraphNode {
|
|
9
|
+
constructor(modelClass, obj) {
|
|
10
|
+
this.modelClass = modelClass;
|
|
11
|
+
this.obj = obj;
|
|
12
|
+
this.edges = [];
|
|
13
|
+
this.userData = {};
|
|
14
|
+
this.hasId = obj.$hasId();
|
|
15
|
+
this.uid = obj[modelClass.uidProp];
|
|
16
|
+
|
|
17
|
+
// These are also included in `edges`. These are simply
|
|
18
|
+
// shortcuts for commonly used edges.
|
|
19
|
+
this.refEdges = [];
|
|
20
|
+
this.parentEdge = null;
|
|
21
|
+
|
|
22
|
+
// These are calculated lazily.
|
|
23
|
+
this._relationPath = NOT_CALCULATED;
|
|
24
|
+
this._relationPathKey = NOT_CALCULATED;
|
|
25
|
+
|
|
26
|
+
this._dataPath = NOT_CALCULATED;
|
|
27
|
+
this._dataPathKey = NOT_CALCULATED;
|
|
28
|
+
|
|
29
|
+
this._idPath = NOT_CALCULATED;
|
|
30
|
+
this._idPathKey = NOT_CALCULATED;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
get isReference() {
|
|
34
|
+
return this.reference !== undefined;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
get isDbReference() {
|
|
38
|
+
return this.dbReference !== undefined;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
get reference() {
|
|
42
|
+
return this.obj[this.modelClass.uidRefProp];
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
get dbReference() {
|
|
46
|
+
return this.obj[this.modelClass.dbRefProp];
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
get parentNode() {
|
|
50
|
+
if (this.parentEdge) {
|
|
51
|
+
return this.parentEdge.ownerNode;
|
|
52
|
+
} else {
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
get indexInRelation() {
|
|
58
|
+
if (this.parentEdge) {
|
|
59
|
+
return this.parentEdge.relationIndex;
|
|
60
|
+
} else {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
get relationName() {
|
|
66
|
+
if (this.parentEdge) {
|
|
67
|
+
return this.parentEdge.relation.name;
|
|
68
|
+
} else {
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
get relationPath() {
|
|
74
|
+
if (this._relationPath === NOT_CALCULATED) {
|
|
75
|
+
this._relationPath = this._createRelationPath();
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return this._relationPath;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
get relationPathKey() {
|
|
82
|
+
if (this._relationPathKey === NOT_CALCULATED) {
|
|
83
|
+
this._relationPathKey = this._createRelationPathKey();
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return this._relationPathKey;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
get dataPath() {
|
|
90
|
+
if (this._dataPath === NOT_CALCULATED) {
|
|
91
|
+
this._dataPath = this._createDataPath();
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return this._dataPath;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
get dataPathKey() {
|
|
98
|
+
if (this._dataPathKey === NOT_CALCULATED) {
|
|
99
|
+
this._dataPathKey = this._createDataPathKey();
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return this._dataPathKey;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
get idPath() {
|
|
106
|
+
if (this._idPath === NOT_CALCULATED) {
|
|
107
|
+
this._idPath = this._createIdPath();
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return this._idPath;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
get idPathKey() {
|
|
114
|
+
if (this._idPathKey === NOT_CALCULATED) {
|
|
115
|
+
this._idPathKey = this._createIdPathKey();
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return this._idPathKey;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* If this node is a reference, returns the referred node.
|
|
123
|
+
*/
|
|
124
|
+
get referencedNode() {
|
|
125
|
+
for (const edge of this.refEdges) {
|
|
126
|
+
if (edge.refType === ModelGraphEdge.ReferenceType.Object && edge.isOwnerNode(this)) {
|
|
127
|
+
return edge.relatedNode;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return null;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Returns all nodes that are references to this node.
|
|
136
|
+
*/
|
|
137
|
+
get referencingNodes() {
|
|
138
|
+
const nodes = [];
|
|
139
|
+
|
|
140
|
+
for (const edge of this.refEdges) {
|
|
141
|
+
if (edge.refType === ModelGraphEdge.ReferenceType.Object && edge.isRelatedNode(this)) {
|
|
142
|
+
nodes.push(edge.ownerNode);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return nodes;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
get descendantRelationNodes() {
|
|
150
|
+
return this._collectDescendantRelationNodes([]);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
removeEdge(edge) {
|
|
154
|
+
// Don't allow removing parent edges for now. It would
|
|
155
|
+
// cause all kinds of cache invalidation.
|
|
156
|
+
if (edge === this.parentEdge) {
|
|
157
|
+
throw new Error('cannot remove parent edge');
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
this.edges = this.edges.filter((it) => it !== edge);
|
|
161
|
+
this.refEdges = this.refEdges.filter((it) => it !== edge);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
_collectDescendantRelationNodes(nodes) {
|
|
165
|
+
for (const edge of this.edges) {
|
|
166
|
+
if (edge.type === ModelGraphEdge.Type.Relation && edge.isOwnerNode(this)) {
|
|
167
|
+
nodes.push(edge.relatedNode);
|
|
168
|
+
edge.relatedNode._collectDescendantRelationNodes(nodes);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return nodes;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
_createRelationPath() {
|
|
176
|
+
if (this.parentNode === null) {
|
|
177
|
+
return [];
|
|
178
|
+
} else {
|
|
179
|
+
return [...this.parentNode.relationPath, this.relationName];
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
_createRelationPathKey() {
|
|
184
|
+
return this.relationPath.join('.');
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
_createDataPath() {
|
|
188
|
+
if (this.parentEdge === null) {
|
|
189
|
+
return [];
|
|
190
|
+
} else if (this.parentEdge.relation.isOneToOne()) {
|
|
191
|
+
return [...this.parentNode.dataPath, this.relationName];
|
|
192
|
+
} else {
|
|
193
|
+
return [...this.parentNode.dataPath, this.relationName, this.indexInRelation];
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
_createDataPathKey() {
|
|
198
|
+
const dataPathKey = this.dataPath.reduce((key, it) => {
|
|
199
|
+
if (isNumber(it)) {
|
|
200
|
+
return `${key}[${it}]`;
|
|
201
|
+
} else {
|
|
202
|
+
return key ? `${key}.${it}` : it;
|
|
203
|
+
}
|
|
204
|
+
}, '');
|
|
205
|
+
|
|
206
|
+
return dataPathKey ? '.' + dataPathKey : dataPathKey;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
_createIdPath() {
|
|
210
|
+
if (!this.obj.$hasId()) {
|
|
211
|
+
return null;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
if (this.parentEdge === null) {
|
|
215
|
+
return [this.obj.$idKey()];
|
|
216
|
+
} else {
|
|
217
|
+
const path = this.parentNode.idPath;
|
|
218
|
+
|
|
219
|
+
if (path === null) {
|
|
220
|
+
return null;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
return [...path, this.relationName, this.obj.$idKey()];
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
_createIdPathKey() {
|
|
228
|
+
const idPath = this.idPath;
|
|
229
|
+
|
|
230
|
+
if (idPath) {
|
|
231
|
+
return this.idPath.join('.');
|
|
232
|
+
} else {
|
|
233
|
+
return null;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
module.exports = {
|
|
239
|
+
ModelGraphNode,
|
|
240
|
+
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const cache = new Map();
|
|
4
|
+
|
|
5
|
+
function inheritModel(modelClass) {
|
|
6
|
+
let inherit = cache.get(modelClass.name);
|
|
7
|
+
|
|
8
|
+
if (!inherit) {
|
|
9
|
+
inherit = createClassInheritor(modelClass.name);
|
|
10
|
+
cache.set(modelClass.name, inherit);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
return inherit(modelClass);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function createClassInheritor(className) {
|
|
17
|
+
return new Function(
|
|
18
|
+
'BaseClass',
|
|
19
|
+
`
|
|
20
|
+
'use strict';
|
|
21
|
+
return class ${className} extends BaseClass {}
|
|
22
|
+
`,
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
module.exports = {
|
|
27
|
+
inheritModel,
|
|
28
|
+
};
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { inheritModel } = require('./inheritModel');
|
|
4
|
+
const { staticHiddenProps } = require('./modelUtils');
|
|
5
|
+
const { defineNonEnumerableProperty } = require('./modelUtils');
|
|
6
|
+
|
|
7
|
+
function bindKnex(modelClass, knex) {
|
|
8
|
+
let BoundModelClass = getBoundModelFromCache(modelClass, knex);
|
|
9
|
+
|
|
10
|
+
if (BoundModelClass === null) {
|
|
11
|
+
BoundModelClass = inheritModel(modelClass);
|
|
12
|
+
BoundModelClass = copyHiddenProperties(modelClass, BoundModelClass);
|
|
13
|
+
|
|
14
|
+
BoundModelClass.knex(knex);
|
|
15
|
+
|
|
16
|
+
BoundModelClass = putBoundModelToCache(modelClass, BoundModelClass, knex);
|
|
17
|
+
BoundModelClass = bindRelations(modelClass, BoundModelClass, knex);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return BoundModelClass;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function getBoundModelFromCache(modelClass, knex) {
|
|
24
|
+
const cache = getCache(knex);
|
|
25
|
+
const cacheKey = modelClass.uniqueTag();
|
|
26
|
+
|
|
27
|
+
return cache.get(cacheKey) || null;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function getCache(knex) {
|
|
31
|
+
if (!knex.$$objection) {
|
|
32
|
+
createCache(knex);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return knex.$$objection.boundModels;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function createCache(knex) {
|
|
39
|
+
defineNonEnumerableProperty(knex, '$$objection', {
|
|
40
|
+
boundModels: new Map(),
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function copyHiddenProperties(modelClass, BoundModelClass) {
|
|
45
|
+
for (const prop of staticHiddenProps) {
|
|
46
|
+
// $$relations and $$relationArray are handled in separately.
|
|
47
|
+
if (modelClass.hasOwnProperty(prop) && prop !== '$$relations' && prop !== '$$relationArray') {
|
|
48
|
+
defineNonEnumerableProperty(BoundModelClass, prop, modelClass[prop]);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return BoundModelClass;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function putBoundModelToCache(modelClass, BoundModelClass, knex) {
|
|
56
|
+
const cache = getCache(knex);
|
|
57
|
+
const cacheKey = modelClass.uniqueTag();
|
|
58
|
+
|
|
59
|
+
cache.set(cacheKey, BoundModelClass);
|
|
60
|
+
return BoundModelClass;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function bindRelations(modelClass, BoundModelClass, knex) {
|
|
64
|
+
const boundRelations = Object.create(null);
|
|
65
|
+
const boundRelationArray = [];
|
|
66
|
+
|
|
67
|
+
for (const relationName of modelClass.getRelationNames()) {
|
|
68
|
+
const relation = modelClass.getRelation(relationName);
|
|
69
|
+
const boundRelation = relation.bindKnex(knex);
|
|
70
|
+
|
|
71
|
+
boundRelations[relation.name] = boundRelation;
|
|
72
|
+
boundRelationArray.push(boundRelation);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
defineNonEnumerableProperty(BoundModelClass, '$$relations', boundRelations);
|
|
76
|
+
defineNonEnumerableProperty(BoundModelClass, '$$relationArray', boundRelationArray);
|
|
77
|
+
|
|
78
|
+
return BoundModelClass;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
module.exports = {
|
|
82
|
+
bindKnex,
|
|
83
|
+
};
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { isObject, cloneDeep } = require('../utils/objectUtils');
|
|
4
|
+
const { hiddenProps } = require('./modelUtils');
|
|
5
|
+
const { defineNonEnumerableProperty } = require('./modelUtils');
|
|
6
|
+
const { isInternalProp } = require('../utils/internalPropUtils');
|
|
7
|
+
|
|
8
|
+
function clone(model, shallow, stripInternal) {
|
|
9
|
+
let clone = null;
|
|
10
|
+
|
|
11
|
+
const omitFromJson = model.$omitFromJson();
|
|
12
|
+
const omitFromDatabaseJson = model.$omitFromDatabaseJson();
|
|
13
|
+
|
|
14
|
+
if (!shallow && !stripInternal) {
|
|
15
|
+
clone = cloneSimple(model);
|
|
16
|
+
} else {
|
|
17
|
+
clone = cloneWithOpt(model, shallow, stripInternal);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (omitFromJson) {
|
|
21
|
+
clone.$omitFromJson(omitFromJson);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (omitFromDatabaseJson) {
|
|
25
|
+
clone.$omitFromDatabaseJson(omitFromDatabaseJson);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
clone = copyHiddenProps(model, clone);
|
|
29
|
+
return clone;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function cloneSimple(model) {
|
|
33
|
+
const clone = new model.constructor();
|
|
34
|
+
const keys = Object.keys(model);
|
|
35
|
+
|
|
36
|
+
for (let i = 0, l = keys.length; i < l; ++i) {
|
|
37
|
+
const key = keys[i];
|
|
38
|
+
const value = model[key];
|
|
39
|
+
|
|
40
|
+
if (isObject(value)) {
|
|
41
|
+
clone[key] = cloneObject(value);
|
|
42
|
+
} else {
|
|
43
|
+
clone[key] = value;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return clone;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function cloneWithOpt(model, shallow, stripInternal) {
|
|
51
|
+
const clone = new model.constructor();
|
|
52
|
+
const keys = Object.keys(model);
|
|
53
|
+
const relationNames = model.constructor.getRelationNames();
|
|
54
|
+
|
|
55
|
+
for (let i = 0, l = keys.length; i < l; ++i) {
|
|
56
|
+
const key = keys[i];
|
|
57
|
+
const value = model[key];
|
|
58
|
+
|
|
59
|
+
if (shallow && relationNames.includes(key)) {
|
|
60
|
+
// The constructor may have given default values for relations.
|
|
61
|
+
delete clone[key];
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (stripInternal && isInternalProp(key)) {
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (isObject(value)) {
|
|
70
|
+
clone[key] = cloneObject(value);
|
|
71
|
+
} else {
|
|
72
|
+
clone[key] = value;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return clone;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function cloneObject(value) {
|
|
80
|
+
if (Array.isArray(value)) {
|
|
81
|
+
return cloneArray(value);
|
|
82
|
+
} else if (value.$isObjectionModel) {
|
|
83
|
+
return clone(value, false, false);
|
|
84
|
+
} else if (Buffer.isBuffer(value)) {
|
|
85
|
+
return new Buffer(value);
|
|
86
|
+
} else {
|
|
87
|
+
return cloneDeep(value);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function cloneArray(value) {
|
|
92
|
+
const ret = new Array(value.length);
|
|
93
|
+
|
|
94
|
+
for (let i = 0, l = ret.length; i < l; ++i) {
|
|
95
|
+
const item = value[i];
|
|
96
|
+
|
|
97
|
+
if (isObject(item)) {
|
|
98
|
+
ret[i] = cloneObject(item);
|
|
99
|
+
} else {
|
|
100
|
+
ret[i] = item;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return ret;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function copyHiddenProps(model, clone) {
|
|
108
|
+
for (let i = 0, l = hiddenProps.length; i < l; ++i) {
|
|
109
|
+
const prop = hiddenProps[i];
|
|
110
|
+
|
|
111
|
+
if (model.hasOwnProperty(prop)) {
|
|
112
|
+
defineNonEnumerableProperty(clone, prop, model[prop]);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return clone;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
module.exports = {
|
|
120
|
+
clone,
|
|
121
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { difference } = require('../utils/objectUtils');
|
|
4
|
+
|
|
5
|
+
function columnNameToPropertyName(modelClass, columnName) {
|
|
6
|
+
const model = new modelClass();
|
|
7
|
+
const addedProps = Object.keys(model.$parseDatabaseJson({}));
|
|
8
|
+
|
|
9
|
+
const row = {};
|
|
10
|
+
row[columnName] = null;
|
|
11
|
+
|
|
12
|
+
const props = Object.keys(model.$parseDatabaseJson(row));
|
|
13
|
+
const propertyName = difference(props, addedProps)[0];
|
|
14
|
+
|
|
15
|
+
return propertyName || columnName;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function propertyNameToColumnName(modelClass, propertyName) {
|
|
19
|
+
const model = new modelClass();
|
|
20
|
+
const addedCols = Object.keys(model.$formatDatabaseJson({}));
|
|
21
|
+
|
|
22
|
+
const obj = {};
|
|
23
|
+
obj[propertyName] = null;
|
|
24
|
+
|
|
25
|
+
const cols = Object.keys(model.$formatDatabaseJson(obj));
|
|
26
|
+
const columnName = difference(cols, addedCols)[0];
|
|
27
|
+
|
|
28
|
+
return columnName || propertyName;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
module.exports = {
|
|
32
|
+
columnNameToPropertyName,
|
|
33
|
+
propertyNameToColumnName,
|
|
34
|
+
};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
function getSetId(model, maybeId) {
|
|
4
|
+
if (maybeId !== undefined) {
|
|
5
|
+
return setId(model, maybeId);
|
|
6
|
+
} else {
|
|
7
|
+
return getId(model);
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function hasId(model) {
|
|
12
|
+
return model.$hasProps(model.constructor.getIdPropertyArray());
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function setId(model, id) {
|
|
16
|
+
const idProp = model.constructor.getIdProperty();
|
|
17
|
+
const isCompositeId = Array.isArray(idProp);
|
|
18
|
+
|
|
19
|
+
if (Array.isArray(id)) {
|
|
20
|
+
if (isCompositeId) {
|
|
21
|
+
if (id.length !== idProp.length) {
|
|
22
|
+
throw new Error('trying to set an invalid identifier for a model');
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
for (let i = 0; i < id.length; ++i) {
|
|
26
|
+
model[idProp[i]] = id[i];
|
|
27
|
+
}
|
|
28
|
+
} else {
|
|
29
|
+
if (id.length !== 1) {
|
|
30
|
+
throw new Error('trying to set an invalid identifier for a model');
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
model[idProp] = id[0];
|
|
34
|
+
}
|
|
35
|
+
} else {
|
|
36
|
+
if (isCompositeId) {
|
|
37
|
+
if (idProp.length > 1) {
|
|
38
|
+
throw new Error('trying to set an invalid identifier for a model');
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
model[idProp[0]] = id;
|
|
42
|
+
} else {
|
|
43
|
+
model[idProp] = id;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function getId(model) {
|
|
49
|
+
const idProp = model.constructor.getIdProperty();
|
|
50
|
+
const isCompositeId = Array.isArray(idProp);
|
|
51
|
+
|
|
52
|
+
if (isCompositeId) {
|
|
53
|
+
return model.$values(idProp);
|
|
54
|
+
} else {
|
|
55
|
+
return model[idProp];
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
module.exports = {
|
|
60
|
+
getSetId,
|
|
61
|
+
hasId,
|
|
62
|
+
};
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { asArray, isObject, flatten, isString } = require('../utils/objectUtils');
|
|
4
|
+
|
|
5
|
+
function parseJsonAttributes(json, modelClass) {
|
|
6
|
+
const jsonAttr = modelClass.getJsonAttributes();
|
|
7
|
+
|
|
8
|
+
if (jsonAttr.length) {
|
|
9
|
+
// JSON attributes may be returned as strings depending on the database and
|
|
10
|
+
// the database client. Convert them to objects here.
|
|
11
|
+
for (let i = 0, l = jsonAttr.length; i < l; ++i) {
|
|
12
|
+
const attr = jsonAttr[i];
|
|
13
|
+
const value = json[attr];
|
|
14
|
+
|
|
15
|
+
if (isString(value)) {
|
|
16
|
+
const parsed = tryParseJson(value);
|
|
17
|
+
|
|
18
|
+
// tryParseJson returns undefined if parsing failed.
|
|
19
|
+
if (parsed !== undefined) {
|
|
20
|
+
json[attr] = parsed;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return json;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function formatJsonAttributes(json, modelClass) {
|
|
30
|
+
const jsonAttr = modelClass.getJsonAttributes();
|
|
31
|
+
|
|
32
|
+
if (jsonAttr.length) {
|
|
33
|
+
// All database clients want JSON columns as strings. Do the conversion here.
|
|
34
|
+
for (let i = 0, l = jsonAttr.length; i < l; ++i) {
|
|
35
|
+
const attr = jsonAttr[i];
|
|
36
|
+
const value = json[attr];
|
|
37
|
+
|
|
38
|
+
if (value != null) {
|
|
39
|
+
json[attr] = JSON.stringify(value);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return json;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function getJsonAttributes(modelClass) {
|
|
48
|
+
let jsonAttributes = modelClass.jsonAttributes;
|
|
49
|
+
|
|
50
|
+
if (Array.isArray(jsonAttributes)) {
|
|
51
|
+
return jsonAttributes;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
jsonAttributes = [];
|
|
55
|
+
|
|
56
|
+
if (modelClass.getJsonSchema()) {
|
|
57
|
+
const props = modelClass.getJsonSchema().properties || {};
|
|
58
|
+
|
|
59
|
+
for (const propName of Object.keys(props)) {
|
|
60
|
+
const prop = props[propName];
|
|
61
|
+
let types = asArray(prop.type).filter((it) => !!it);
|
|
62
|
+
|
|
63
|
+
if (types.length === 0 && Array.isArray(prop.anyOf)) {
|
|
64
|
+
types = flatten(prop.anyOf.map((it) => it.type));
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (types.length === 0 && Array.isArray(prop.oneOf)) {
|
|
68
|
+
types = flatten(prop.oneOf.map((it) => it.type));
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (types.indexOf('object') !== -1 || types.indexOf('array') !== -1) {
|
|
72
|
+
jsonAttributes.push(propName);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return jsonAttributes;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function tryParseJson(maybeJsonStr) {
|
|
81
|
+
try {
|
|
82
|
+
return JSON.parse(maybeJsonStr);
|
|
83
|
+
} catch (err) {
|
|
84
|
+
return undefined;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
module.exports = {
|
|
89
|
+
parseJsonAttributes,
|
|
90
|
+
formatJsonAttributes,
|
|
91
|
+
getJsonAttributes,
|
|
92
|
+
};
|