@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.
Files changed (190) hide show
  1. package/LICENSE +23 -0
  2. package/README.md +69 -2
  3. package/lib/.eslintrc.json +8 -0
  4. package/lib/initialize.js +14 -0
  5. package/lib/model/AjvValidator.js +325 -0
  6. package/lib/model/Model.js +942 -0
  7. package/lib/model/ModifierNotFoundError.js +12 -0
  8. package/lib/model/NotFoundError.js +23 -0
  9. package/lib/model/RelationDoesNotExistError.js +14 -0
  10. package/lib/model/ValidationError.js +54 -0
  11. package/lib/model/Validator.js +26 -0
  12. package/lib/model/getModel.js +9 -0
  13. package/lib/model/graph/ModelGraph.js +80 -0
  14. package/lib/model/graph/ModelGraphBuilder.js +241 -0
  15. package/lib/model/graph/ModelGraphEdge.js +52 -0
  16. package/lib/model/graph/ModelGraphNode.js +240 -0
  17. package/lib/model/inheritModel.js +28 -0
  18. package/lib/model/modelBindKnex.js +83 -0
  19. package/lib/model/modelClone.js +121 -0
  20. package/lib/model/modelColPropMap.js +34 -0
  21. package/lib/model/modelId.js +62 -0
  22. package/lib/model/modelJsonAttributes.js +92 -0
  23. package/lib/model/modelParseRelations.js +82 -0
  24. package/lib/model/modelQueryProps.js +147 -0
  25. package/lib/model/modelSet.js +136 -0
  26. package/lib/model/modelTableMetadata.js +83 -0
  27. package/lib/model/modelToJson.js +187 -0
  28. package/lib/model/modelUtils.js +47 -0
  29. package/lib/model/modelValidate.js +48 -0
  30. package/lib/model/modelValues.js +126 -0
  31. package/lib/model/modelVisitor.js +41 -0
  32. package/lib/objection.js +114 -0
  33. package/lib/queryBuilder/FunctionBuilder.js +339 -0
  34. package/lib/queryBuilder/InternalOptions.js +29 -0
  35. package/lib/queryBuilder/JoinBuilder.js +157 -0
  36. package/lib/queryBuilder/QueryBuilder.js +1398 -0
  37. package/lib/queryBuilder/QueryBuilderBase.js +884 -0
  38. package/lib/queryBuilder/QueryBuilderContext.js +27 -0
  39. package/lib/queryBuilder/QueryBuilderContextBase.js +35 -0
  40. package/lib/queryBuilder/QueryBuilderOperationSupport.js +558 -0
  41. package/lib/queryBuilder/QueryBuilderUserContext.js +31 -0
  42. package/lib/queryBuilder/RawBuilder.js +93 -0
  43. package/lib/queryBuilder/ReferenceBuilder.js +284 -0
  44. package/lib/queryBuilder/RelationExpression.js +431 -0
  45. package/lib/queryBuilder/StaticHookArguments.js +134 -0
  46. package/lib/queryBuilder/ValueBuilder.js +127 -0
  47. package/lib/queryBuilder/expressions.js +151 -0
  48. package/lib/queryBuilder/functions/mysql.js +817 -0
  49. package/lib/queryBuilder/graph/GraphAction.js +69 -0
  50. package/lib/queryBuilder/graph/GraphData.js +14 -0
  51. package/lib/queryBuilder/graph/GraphFetcher.js +191 -0
  52. package/lib/queryBuilder/graph/GraphNodeDbExistence.js +184 -0
  53. package/lib/queryBuilder/graph/GraphOperation.js +27 -0
  54. package/lib/queryBuilder/graph/GraphOptions.js +207 -0
  55. package/lib/queryBuilder/graph/GraphUpsert.js +305 -0
  56. package/lib/queryBuilder/graph/delete/GraphDelete.js +20 -0
  57. package/lib/queryBuilder/graph/delete/GraphDeleteAction.js +74 -0
  58. package/lib/queryBuilder/graph/insert/GraphInsert.js +145 -0
  59. package/lib/queryBuilder/graph/insert/GraphInsertAction.js +225 -0
  60. package/lib/queryBuilder/graph/insert/JoinRowGraphInsertAction.js +92 -0
  61. package/lib/queryBuilder/graph/patch/GraphPatch.js +20 -0
  62. package/lib/queryBuilder/graph/patch/GraphPatchAction.js +258 -0
  63. package/lib/queryBuilder/graph/recursiveUpsert/GraphRecursiveUpsert.js +31 -0
  64. package/lib/queryBuilder/graph/recursiveUpsert/GraphRecursiveUpsertAction.js +126 -0
  65. package/lib/queryBuilder/join/JoinResultColumn.js +23 -0
  66. package/lib/queryBuilder/join/JoinResultParser.js +119 -0
  67. package/lib/queryBuilder/join/RelationJoiner.js +341 -0
  68. package/lib/queryBuilder/join/TableNode.js +163 -0
  69. package/lib/queryBuilder/join/TableTree.js +85 -0
  70. package/lib/queryBuilder/join/utils.js +25 -0
  71. package/lib/queryBuilder/operations/DelegateOperation.js +141 -0
  72. package/lib/queryBuilder/operations/DeleteOperation.js +51 -0
  73. package/lib/queryBuilder/operations/FindByIdOperation.js +37 -0
  74. package/lib/queryBuilder/operations/FindByIdsOperation.js +29 -0
  75. package/lib/queryBuilder/operations/FindOperation.js +164 -0
  76. package/lib/queryBuilder/operations/FirstOperation.js +27 -0
  77. package/lib/queryBuilder/operations/FromOperation.js +110 -0
  78. package/lib/queryBuilder/operations/InsertAndFetchOperation.js +49 -0
  79. package/lib/queryBuilder/operations/InsertGraphAndFetchOperation.js +45 -0
  80. package/lib/queryBuilder/operations/InsertGraphOperation.js +108 -0
  81. package/lib/queryBuilder/operations/InsertOperation.js +206 -0
  82. package/lib/queryBuilder/operations/InstanceDeleteOperation.js +46 -0
  83. package/lib/queryBuilder/operations/InstanceFindOperation.js +21 -0
  84. package/lib/queryBuilder/operations/InstanceInsertOperation.js +24 -0
  85. package/lib/queryBuilder/operations/InstanceUpdateOperation.js +59 -0
  86. package/lib/queryBuilder/operations/JoinRelatedOperation.js +103 -0
  87. package/lib/queryBuilder/operations/KnexOperation.js +14 -0
  88. package/lib/queryBuilder/operations/MergeOperation.js +56 -0
  89. package/lib/queryBuilder/operations/ObjectionToKnexConvertingOperation.js +192 -0
  90. package/lib/queryBuilder/operations/OnBuildKnexOperation.js +29 -0
  91. package/lib/queryBuilder/operations/OnBuildOperation.js +29 -0
  92. package/lib/queryBuilder/operations/OnErrorOperation.js +29 -0
  93. package/lib/queryBuilder/operations/QueryBuilderOperation.js +297 -0
  94. package/lib/queryBuilder/operations/RangeOperation.js +47 -0
  95. package/lib/queryBuilder/operations/RelateOperation.js +27 -0
  96. package/lib/queryBuilder/operations/ReturningOperation.js +30 -0
  97. package/lib/queryBuilder/operations/RunAfterOperation.js +29 -0
  98. package/lib/queryBuilder/operations/RunBeforeOperation.js +29 -0
  99. package/lib/queryBuilder/operations/UnrelateOperation.js +23 -0
  100. package/lib/queryBuilder/operations/UpdateAndFetchOperation.js +80 -0
  101. package/lib/queryBuilder/operations/UpdateOperation.js +155 -0
  102. package/lib/queryBuilder/operations/UpsertGraphAndFetchOperation.js +45 -0
  103. package/lib/queryBuilder/operations/UpsertGraphOperation.js +66 -0
  104. package/lib/queryBuilder/operations/WhereCompositeOperation.js +57 -0
  105. package/lib/queryBuilder/operations/WhereInOperation.js +48 -0
  106. package/lib/queryBuilder/operations/eager/EagerOperation.js +61 -0
  107. package/lib/queryBuilder/operations/eager/JoinEagerOperation.js +51 -0
  108. package/lib/queryBuilder/operations/eager/NaiveEagerOperation.js +13 -0
  109. package/lib/queryBuilder/operations/eager/WhereInEagerOperation.js +285 -0
  110. package/lib/queryBuilder/operations/jsonApi/WhereJsonHasOperation.js +36 -0
  111. package/lib/queryBuilder/operations/jsonApi/WhereJsonNotObjectOperation.js +53 -0
  112. package/lib/queryBuilder/operations/jsonApi/WhereJsonOperation.js +31 -0
  113. package/lib/queryBuilder/operations/jsonApi/WhereJsonOverlapsOperation.js +31 -0
  114. package/lib/queryBuilder/operations/jsonApi/mysqlJsonApi.js +167 -0
  115. package/lib/queryBuilder/operations/jsonApi/postgresJsonApi.js +164 -0
  116. package/lib/queryBuilder/operations/select/SelectOperation.js +66 -0
  117. package/lib/queryBuilder/operations/select/Selection.js +123 -0
  118. package/lib/queryBuilder/operations/whereInComposite/WhereInCompositeMsSqlOperation.js +117 -0
  119. package/lib/queryBuilder/operations/whereInComposite/WhereInCompositeOperation.js +100 -0
  120. package/lib/queryBuilder/operations/whereInComposite/WhereInCompositeSqliteOperation.js +104 -0
  121. package/lib/queryBuilder/parsers/jsonFieldExpressionParser.js +886 -0
  122. package/lib/queryBuilder/parsers/jsonFieldExpressionParser.pegjs +97 -0
  123. package/lib/queryBuilder/parsers/relationExpressionParser.js +1042 -0
  124. package/lib/queryBuilder/parsers/relationExpressionParser.pegjs +141 -0
  125. package/lib/queryBuilder/transformations/CompositeQueryTransformation.js +22 -0
  126. package/lib/queryBuilder/transformations/QueryTransformation.js +11 -0
  127. package/lib/queryBuilder/transformations/WrapMysqlModifySubqueryTransformation.js +71 -0
  128. package/lib/queryBuilder/transformations/index.js +15 -0
  129. package/lib/queryBuilder/whereScopes.js +227 -0
  130. package/lib/relations/Relation.js +401 -0
  131. package/lib/relations/RelationDeleteOperation.js +29 -0
  132. package/lib/relations/RelationFindOperation.js +149 -0
  133. package/lib/relations/RelationInsertOperation.js +33 -0
  134. package/lib/relations/RelationOwner.js +236 -0
  135. package/lib/relations/RelationProperty.js +247 -0
  136. package/lib/relations/RelationUpdateOperation.js +30 -0
  137. package/lib/relations/belongsToOne/BelongsToOneDeleteOperation.js +23 -0
  138. package/lib/relations/belongsToOne/BelongsToOneInsertOperation.js +44 -0
  139. package/lib/relations/belongsToOne/BelongsToOneRelateOperation.js +50 -0
  140. package/lib/relations/belongsToOne/BelongsToOneRelation.js +53 -0
  141. package/lib/relations/belongsToOne/BelongsToOneUnrelateOperation.js +61 -0
  142. package/lib/relations/hasMany/HasManyInsertOperation.js +61 -0
  143. package/lib/relations/hasMany/HasManyRelateOperation.js +64 -0
  144. package/lib/relations/hasMany/HasManyRelation.js +49 -0
  145. package/lib/relations/hasMany/HasManyUnrelateOperation.js +33 -0
  146. package/lib/relations/hasOne/HasOneRelation.js +13 -0
  147. package/lib/relations/hasOneThrough/HasOneThroughRelation.js +13 -0
  148. package/lib/relations/manyToMany/ManyToManyModifyMixin.js +105 -0
  149. package/lib/relations/manyToMany/ManyToManyRelation.js +507 -0
  150. package/lib/relations/manyToMany/ManyToManySqliteModifyMixin.js +36 -0
  151. package/lib/relations/manyToMany/delete/ManyToManyDeleteOperation.js +10 -0
  152. package/lib/relations/manyToMany/delete/ManyToManyDeleteOperationBase.js +26 -0
  153. package/lib/relations/manyToMany/delete/ManyToManyDeleteSqliteOperation.js +12 -0
  154. package/lib/relations/manyToMany/find/ManyToManyFindOperation.js +105 -0
  155. package/lib/relations/manyToMany/insert/ManyToManyInsertOperation.js +52 -0
  156. package/lib/relations/manyToMany/relate/ManyToManyRelateOperation.js +81 -0
  157. package/lib/relations/manyToMany/unrelate/ManyToManyUnrelateOperation.js +14 -0
  158. package/lib/relations/manyToMany/unrelate/ManyToManyUnrelateOperationBase.js +34 -0
  159. package/lib/relations/manyToMany/unrelate/ManyToManyUnrelateSqliteOperation.js +16 -0
  160. package/lib/relations/manyToMany/update/ManyToManyUpdateOperation.js +10 -0
  161. package/lib/relations/manyToMany/update/ManyToManyUpdateOperationBase.js +82 -0
  162. package/lib/relations/manyToMany/update/ManyToManyUpdateSqliteOperation.js +12 -0
  163. package/lib/transaction.js +96 -0
  164. package/lib/utils/assert.js +25 -0
  165. package/lib/utils/buildUtils.js +21 -0
  166. package/lib/utils/classUtils.js +13 -0
  167. package/lib/utils/clone.js +2329 -0
  168. package/lib/utils/createModifier.js +42 -0
  169. package/lib/utils/deprecate.js +15 -0
  170. package/lib/utils/identifierMapping.js +227 -0
  171. package/lib/utils/internalPropUtils.js +11 -0
  172. package/lib/utils/knexUtils.js +76 -0
  173. package/lib/utils/mixin.js +25 -0
  174. package/lib/utils/mysqlJsonPath.js +55 -0
  175. package/lib/utils/normalizeIds.js +144 -0
  176. package/lib/utils/objectUtils.js +416 -0
  177. package/lib/utils/parseFieldExpression.js +51 -0
  178. package/lib/utils/postgresJsonPath.js +110 -0
  179. package/lib/utils/promiseUtils/after.js +17 -0
  180. package/lib/utils/promiseUtils/afterReturn.js +17 -0
  181. package/lib/utils/promiseUtils/index.js +17 -0
  182. package/lib/utils/promiseUtils/isPromise.js +11 -0
  183. package/lib/utils/promiseUtils/map.js +110 -0
  184. package/lib/utils/promiseUtils/mapAfterAllReturn.js +29 -0
  185. package/lib/utils/promiseUtils/try.js +22 -0
  186. package/lib/utils/resolveModel.js +107 -0
  187. package/lib/utils/tmpColumnUtils.js +16 -0
  188. package/package.json +86 -4
  189. package/typings/objection/index.d.ts +4104 -0
  190. package/typings/objection/relation-expression.d.ts +237 -0
@@ -0,0 +1,942 @@
1
+ 'use strict';
2
+
3
+ const { clone } = require('./modelClone');
4
+ const { bindKnex } = require('./modelBindKnex');
5
+ const { validate } = require('./modelValidate');
6
+ const { isMsSql, isMySql } = require('../utils/knexUtils');
7
+ const { visitModels } = require('./modelVisitor');
8
+ const { hasId, getSetId } = require('./modelId');
9
+ const { map: promiseMap } = require('../utils/promiseUtils');
10
+ const { toJson, toDatabaseJson } = require('./modelToJson');
11
+ const { values, propKey, hasProps } = require('./modelValues');
12
+ const { defineNonEnumerableProperty } = require('./modelUtils');
13
+ const { parseRelationsIntoModelInstances } = require('./modelParseRelations');
14
+ const { fetchTableMetadata, tableMetadata } = require('./modelTableMetadata');
15
+ const { asArray, isFunction, isString, asSingle } = require('../utils/objectUtils');
16
+ const { setJson, setFast, setRelated, appendRelated, setDatabaseJson } = require('./modelSet');
17
+ const {
18
+ getJsonAttributes,
19
+ parseJsonAttributes,
20
+ formatJsonAttributes,
21
+ } = require('./modelJsonAttributes');
22
+ const { columnNameToPropertyName, propertyNameToColumnName } = require('./modelColPropMap');
23
+
24
+ const { raw } = require('../queryBuilder/RawBuilder');
25
+ const { ref } = require('../queryBuilder/ReferenceBuilder');
26
+ const { fn } = require('../queryBuilder/FunctionBuilder');
27
+
28
+ const { AjvValidator } = require('./AjvValidator');
29
+ const { QueryBuilder } = require('../queryBuilder/QueryBuilder');
30
+ const { NotFoundError } = require('./NotFoundError');
31
+ const { ValidationError } = require('./ValidationError');
32
+ const { ModifierNotFoundError } = require('./ModifierNotFoundError');
33
+ const { RelationProperty } = require('../relations/RelationProperty');
34
+ const { RelationOwner } = require('../relations/RelationOwner');
35
+
36
+ const { HasOneRelation } = require('../relations/hasOne/HasOneRelation');
37
+ const { HasManyRelation } = require('../relations/hasMany/HasManyRelation');
38
+ const { ManyToManyRelation } = require('../relations/manyToMany/ManyToManyRelation');
39
+ const { BelongsToOneRelation } = require('../relations/belongsToOne/BelongsToOneRelation');
40
+ const { HasOneThroughRelation } = require('../relations/hasOneThrough/HasOneThroughRelation');
41
+
42
+ const { InstanceFindOperation } = require('../queryBuilder/operations/InstanceFindOperation');
43
+ const { InstanceInsertOperation } = require('../queryBuilder/operations/InstanceInsertOperation');
44
+ const { InstanceUpdateOperation } = require('../queryBuilder/operations/InstanceUpdateOperation');
45
+ const { InstanceDeleteOperation } = require('../queryBuilder/operations/InstanceDeleteOperation');
46
+
47
+ class Model {
48
+ get $modelClass() {
49
+ return this.constructor;
50
+ }
51
+
52
+ $id(maybeId) {
53
+ return getSetId(this, maybeId);
54
+ }
55
+
56
+ $hasId() {
57
+ return hasId(this);
58
+ }
59
+
60
+ $hasProps(props) {
61
+ return hasProps(this, props);
62
+ }
63
+
64
+ $query(trx) {
65
+ return instanceQuery({
66
+ instance: this,
67
+ transaction: trx,
68
+ });
69
+ }
70
+
71
+ $relatedQuery(relationName, trx) {
72
+ return relatedQuery({
73
+ modelClass: this.constructor,
74
+ relationName,
75
+ transaction: trx,
76
+ alwaysReturnArray: false,
77
+ }).for(this);
78
+ }
79
+
80
+ $fetchGraph(relationExpression, options) {
81
+ return this.constructor.fetchGraph(this, relationExpression, options);
82
+ }
83
+
84
+ $beforeValidate(jsonSchema, json, options) {
85
+ /* istanbul ignore next */
86
+ return jsonSchema;
87
+ }
88
+
89
+ $validate(json, options) {
90
+ return validate(this, json, options);
91
+ }
92
+
93
+ $afterValidate(json, options) {
94
+ // Do nothing by default.
95
+ }
96
+
97
+ $parseDatabaseJson(json) {
98
+ const columnNameMappers = this.constructor.getColumnNameMappers();
99
+
100
+ if (columnNameMappers) {
101
+ json = columnNameMappers.parse(json);
102
+ }
103
+
104
+ return parseJsonAttributes(json, this.constructor);
105
+ }
106
+
107
+ $formatDatabaseJson(json) {
108
+ const columnNameMappers = this.constructor.getColumnNameMappers();
109
+
110
+ json = formatJsonAttributes(json, this.constructor);
111
+
112
+ if (columnNameMappers) {
113
+ json = columnNameMappers.format(json);
114
+ }
115
+
116
+ return json;
117
+ }
118
+
119
+ $parseJson(json, options) {
120
+ return json;
121
+ }
122
+
123
+ $formatJson(json) {
124
+ return json;
125
+ }
126
+
127
+ $setJson(json, options) {
128
+ return setJson(this, json, options);
129
+ }
130
+
131
+ $setDatabaseJson(json) {
132
+ return setDatabaseJson(this, json);
133
+ }
134
+
135
+ $set(obj) {
136
+ return setFast(this, obj);
137
+ }
138
+
139
+ $setRelated(relation, models) {
140
+ return setRelated(this, relation, models);
141
+ }
142
+
143
+ $appendRelated(relation, models) {
144
+ return appendRelated(this, relation, models);
145
+ }
146
+
147
+ $toJson(opt) {
148
+ return toJson(this, opt);
149
+ }
150
+
151
+ toJSON(opt) {
152
+ return this.$toJson(opt);
153
+ }
154
+
155
+ $toDatabaseJson(builder) {
156
+ return toDatabaseJson(this, builder);
157
+ }
158
+
159
+ $beforeInsert(queryContext) {
160
+ // Do nothing by default.
161
+ }
162
+
163
+ $afterInsert(queryContext) {
164
+ // Do nothing by default.
165
+ }
166
+
167
+ $beforeUpdate(opt, queryContext) {
168
+ // Do nothing by default.
169
+ }
170
+
171
+ $afterUpdate(opt, queryContext) {
172
+ // Do nothing by default.
173
+ }
174
+
175
+ $afterFind(queryContext) {
176
+ // Do nothing by default.
177
+ }
178
+
179
+ $beforeDelete(queryContext) {
180
+ // Do nothing by default.
181
+ }
182
+
183
+ $afterDelete(queryContext) {
184
+ // Do nothing by default.
185
+ }
186
+
187
+ $values(props) {
188
+ return values(this, props);
189
+ }
190
+
191
+ $propKey(props) {
192
+ return propKey(this, props);
193
+ }
194
+
195
+ $idKey() {
196
+ return this.$propKey(this.constructor.getIdPropertyArray());
197
+ }
198
+
199
+ $clone(opt) {
200
+ return clone(this, !!(opt && opt.shallow), false);
201
+ }
202
+
203
+ $traverse(filterConstructor, callback) {
204
+ if (callback === undefined) {
205
+ callback = filterConstructor;
206
+ filterConstructor = null;
207
+ }
208
+
209
+ this.constructor.traverse(filterConstructor, this, callback);
210
+ return this;
211
+ }
212
+
213
+ $traverseAsync(filterConstructor, callback) {
214
+ if (callback === undefined) {
215
+ callback = filterConstructor;
216
+ filterConstructor = null;
217
+ }
218
+
219
+ return this.constructor.traverseAsync(filterConstructor, this, callback);
220
+ }
221
+
222
+ $omitFromJson(...props) {
223
+ if (arguments.length === 0) {
224
+ return this.$$omitFromJson;
225
+ } else {
226
+ if (!this.hasOwnProperty('$$omitFromJson')) {
227
+ defineNonEnumerableProperty(this, '$$omitFromJson', []);
228
+ }
229
+ this.$$omitFromJson = this.$$omitFromJson.concat(asPropsArray(props));
230
+ return this;
231
+ }
232
+ }
233
+
234
+ $omitFromDatabaseJson(...props) {
235
+ if (arguments.length === 0) {
236
+ return this.$$omitFromDatabaseJson;
237
+ } else {
238
+ if (!this.hasOwnProperty('$$omitFromDatabaseJson')) {
239
+ defineNonEnumerableProperty(this, '$$omitFromDatabaseJson', []);
240
+ }
241
+ this.$$omitFromDatabaseJson = this.$$omitFromDatabaseJson.concat(asPropsArray(props));
242
+ return this;
243
+ }
244
+ }
245
+
246
+ $knex() {
247
+ return this.constructor.knex();
248
+ }
249
+
250
+ $transaction(...args) {
251
+ return this.constructor.transaction(...args);
252
+ }
253
+
254
+ get $ref() {
255
+ return this.constructor.ref;
256
+ }
257
+
258
+ static get objectionModelClass() {
259
+ return Model;
260
+ }
261
+
262
+ static fromJson(json, options) {
263
+ const model = new this();
264
+ model.$setJson(json || {}, options);
265
+ return model;
266
+ }
267
+
268
+ static fromDatabaseJson(json) {
269
+ const model = new this();
270
+ model.$setDatabaseJson(json || {});
271
+ return model;
272
+ }
273
+
274
+ static onCreateQuery(builder) {
275
+ // Do nothing by default.
276
+ }
277
+
278
+ static beforeFind(args) {
279
+ // Do nothing by default.
280
+ }
281
+
282
+ static afterFind(args) {
283
+ // Do nothing by default.
284
+ }
285
+
286
+ static beforeInsert(args) {
287
+ // Do nothing by default.
288
+ }
289
+
290
+ static afterInsert(args) {
291
+ // Do nothing by default.
292
+ }
293
+
294
+ static beforeUpdate(args) {
295
+ // Do nothing by default.
296
+ }
297
+
298
+ static afterUpdate(args) {
299
+ // Do nothing by default.
300
+ }
301
+
302
+ static beforeDelete(args) {
303
+ // Do nothing by default.
304
+ }
305
+
306
+ static afterDelete(args) {
307
+ // Do nothing by default.
308
+ }
309
+
310
+ static omitImpl(obj, prop) {
311
+ delete obj[prop];
312
+ }
313
+
314
+ static joinTableAlias(relationPath) {
315
+ return `${relationPath}_join`;
316
+ }
317
+
318
+ static createValidator() {
319
+ return new AjvValidator({
320
+ options: {
321
+ allErrors: true,
322
+ validateSchema: false,
323
+ ownProperties: true,
324
+ v5: true,
325
+ },
326
+ });
327
+ }
328
+
329
+ static modifierNotFound(builder, modifier) {
330
+ throw new this.ModifierNotFoundError(modifier);
331
+ }
332
+
333
+ static createNotFoundError(queryContext, props) {
334
+ return new this.NotFoundError({ ...props, modelClass: this });
335
+ }
336
+
337
+ static createValidationError(props) {
338
+ return new this.ValidationError({ ...props, modelClass: this });
339
+ }
340
+
341
+ static getTableName() {
342
+ let tableName = this.tableName;
343
+
344
+ if (isFunction(tableName)) {
345
+ tableName = this.tableName();
346
+ }
347
+
348
+ if (!isString(tableName)) {
349
+ throw new Error(`Model ${this.name} must have a static property tableName`);
350
+ }
351
+
352
+ return tableName;
353
+ }
354
+
355
+ static getIdColumn() {
356
+ let idColumn = this.idColumn;
357
+
358
+ if (isFunction(idColumn)) {
359
+ idColumn = this.idColumn();
360
+ }
361
+
362
+ return idColumn;
363
+ }
364
+
365
+ static getValidator() {
366
+ return cachedGet(this, '$$validator', getValidator);
367
+ }
368
+
369
+ static getJsonSchema() {
370
+ return cachedGet(this, '$$jsonSchema', getJsonSchema);
371
+ }
372
+
373
+ static getJsonAttributes() {
374
+ return cachedGet(this, '$$jsonAttributes', getJsonAttributes);
375
+ }
376
+
377
+ static getColumnNameMappers() {
378
+ return cachedGet(this, '$$columnNameMappers', getColumnNameMappers);
379
+ }
380
+
381
+ static getConcurrency(knex) {
382
+ const DEFAULT_CONCURRENCY = 4;
383
+
384
+ if (this.concurrency === null) {
385
+ if (!knex) {
386
+ return DEFAULT_CONCURRENCY;
387
+ }
388
+
389
+ // The mssql driver is shit, and we cannot have concurrent queries.
390
+ // On MySQL, concurrent graph updates and deletes deadlock: MySQL needs
391
+ // them wrapped in a subquery, which locks the rows of the join tables
392
+ // it reads.
393
+ if (isMsSql(knex) || isMySql(knex)) {
394
+ return 1;
395
+ } else {
396
+ return DEFAULT_CONCURRENCY;
397
+ }
398
+ } else {
399
+ if (isFunction(this.concurrency)) {
400
+ return this.concurrency();
401
+ } else {
402
+ return this.concurrency;
403
+ }
404
+ }
405
+ }
406
+
407
+ static getModifiers() {
408
+ return this.modifiers || {};
409
+ }
410
+
411
+ static columnNameToPropertyName(columnName) {
412
+ let colToProp = cachedGet(this, '$$colToProp', () => new Map());
413
+ let propertyName = colToProp.get(columnName);
414
+
415
+ if (!propertyName) {
416
+ propertyName = columnNameToPropertyName(this, columnName);
417
+ colToProp.set(columnName, propertyName);
418
+ }
419
+
420
+ return propertyName;
421
+ }
422
+
423
+ static propertyNameToColumnName(propertyName) {
424
+ let propToCol = cachedGet(this, '$$propToCol', () => new Map());
425
+ let columnName = propToCol.get(propertyName);
426
+
427
+ if (!columnName) {
428
+ columnName = propertyNameToColumnName(this, propertyName);
429
+ propToCol.set(propertyName, columnName);
430
+ }
431
+
432
+ return columnName;
433
+ }
434
+
435
+ static getReadOnlyAttributes() {
436
+ return cachedGet(this, '$$readOnlyAttributes', getReadOnlyAttributes);
437
+ }
438
+
439
+ static getIdRelationProperty() {
440
+ return cachedGet(this, '$$idRelationProperty', getIdRelationProperty);
441
+ }
442
+
443
+ static getIdColumnArray() {
444
+ return this.getIdRelationProperty().cols;
445
+ }
446
+
447
+ static getIdPropertyArray() {
448
+ return this.getIdRelationProperty().props;
449
+ }
450
+
451
+ static getIdProperty() {
452
+ const idProps = this.getIdPropertyArray();
453
+
454
+ if (idProps.length === 1) {
455
+ return idProps[0];
456
+ } else {
457
+ return idProps;
458
+ }
459
+ }
460
+
461
+ static getRelationMappings() {
462
+ return cachedGet(this, '$$relationMappings', getRelationMappings);
463
+ }
464
+
465
+ static getRelations() {
466
+ const relations = Object.create(null);
467
+
468
+ for (const relationName of this.getRelationNames()) {
469
+ relations[relationName] = this.getRelation(relationName);
470
+ }
471
+
472
+ return relations;
473
+ }
474
+
475
+ static getRelationNames() {
476
+ return cachedGet(this, '$$relationNames', getRelationNames);
477
+ }
478
+
479
+ static getVirtualAttributes() {
480
+ return cachedGet(this, '$$virtualAttributes', getVirtualAttributes);
481
+ }
482
+
483
+ static getDefaultGraphOptions() {
484
+ return this.defaultGraphOptions;
485
+ }
486
+
487
+ static getRelatedFindQueryMutates() {
488
+ return this.relatedFindQueryMutates;
489
+ }
490
+
491
+ static getRelatedInsertQueryMutates() {
492
+ return this.relatedInsertQueryMutates;
493
+ }
494
+
495
+ static query(trx) {
496
+ const query = this.QueryBuilder.forClass(this).transacting(trx);
497
+ this.onCreateQuery(query);
498
+ return query;
499
+ }
500
+
501
+ static relatedQuery(relationName, trx) {
502
+ return relatedQuery({
503
+ modelClass: this,
504
+ relationName,
505
+ transaction: trx,
506
+ alwaysReturnArray: true,
507
+ });
508
+ }
509
+
510
+ static fetchTableMetadata(opt) {
511
+ return fetchTableMetadata(this, opt);
512
+ }
513
+
514
+ static tableMetadata(opt) {
515
+ return tableMetadata(this, opt);
516
+ }
517
+
518
+ static knex(...args) {
519
+ if (args.length) {
520
+ defineNonEnumerableProperty(this, '$$knex', args[0]);
521
+ } else {
522
+ return this.$$knex;
523
+ }
524
+ }
525
+
526
+ static transaction(knexOrTrx, cb) {
527
+ if (!cb) {
528
+ cb = knexOrTrx;
529
+ knexOrTrx = null;
530
+ }
531
+
532
+ return (knexOrTrx || this.knex()).transaction(cb);
533
+ }
534
+
535
+ static startTransaction(knexOrTrx) {
536
+ const { transaction } = require('../transaction');
537
+ return transaction.start(knexOrTrx || this.knex());
538
+ }
539
+
540
+ static get raw() {
541
+ return raw;
542
+ }
543
+
544
+ static get ref() {
545
+ return (...args) => {
546
+ return ref(...args).model(this);
547
+ };
548
+ }
549
+
550
+ static get fn() {
551
+ return fn;
552
+ }
553
+
554
+ static knexQuery() {
555
+ return this.knex().table(this.getTableName());
556
+ }
557
+
558
+ static uniqueTag() {
559
+ if (this.name) {
560
+ return `${this.getTableName()}_${this.name}`;
561
+ } else {
562
+ return this.getTableName();
563
+ }
564
+ }
565
+
566
+ static bindKnex(knex) {
567
+ return bindKnex(this, knex);
568
+ }
569
+
570
+ static bindTransaction(trx) {
571
+ return bindKnex(this, trx);
572
+ }
573
+
574
+ static ensureModel(model, options) {
575
+ const modelClass = this;
576
+
577
+ if (!model) {
578
+ return null;
579
+ }
580
+
581
+ if (model instanceof modelClass) {
582
+ return parseRelationsIntoModelInstances(model, model, options);
583
+ } else {
584
+ return modelClass.fromJson(model, options);
585
+ }
586
+ }
587
+
588
+ static ensureModelArray(input, options) {
589
+ if (!input) {
590
+ return [];
591
+ }
592
+
593
+ if (Array.isArray(input)) {
594
+ const models = new Array(input.length);
595
+
596
+ for (let i = 0, l = input.length; i < l; ++i) {
597
+ models[i] = this.ensureModel(input[i], options);
598
+ }
599
+
600
+ return models;
601
+ } else {
602
+ return [this.ensureModel(input, options)];
603
+ }
604
+ }
605
+
606
+ static getRelationUnsafe(name) {
607
+ const mapping = this.getRelationMappings()[name];
608
+
609
+ if (!mapping) {
610
+ return null;
611
+ }
612
+
613
+ if (!this.hasOwnProperty('$$relations')) {
614
+ defineNonEnumerableProperty(this, '$$relations', Object.create(null));
615
+ }
616
+
617
+ if (!this.$$relations[name]) {
618
+ this.$$relations[name] = new mapping.relation(name, this);
619
+ this.$$relations[name].setMapping(mapping);
620
+ }
621
+
622
+ return this.$$relations[name];
623
+ }
624
+
625
+ static getRelation(name) {
626
+ const relation = this.getRelationUnsafe(name);
627
+
628
+ if (!relation) {
629
+ throw new Error(`A model class ${this.name} doesn't have relation ${name}`);
630
+ }
631
+
632
+ return relation;
633
+ }
634
+
635
+ static fetchGraph($models, expression, options = {}) {
636
+ return this.query(options.transaction)
637
+ .resolve(this.ensureModelArray($models))
638
+ .findOptions({ dontCallFindHooks: true })
639
+ .withGraphFetched(expression, options)
640
+ .runAfter((models) => (Array.isArray($models) ? models : models[0]));
641
+ }
642
+
643
+ static traverse(...args) {
644
+ const { traverser, models, filterConstructor } = getTraverseArgs(...args);
645
+
646
+ if (!asSingle(models)) {
647
+ return;
648
+ }
649
+
650
+ const modelClass = asSingle(models).constructor;
651
+
652
+ visitModels(models, modelClass, (model, _, parent, relation) => {
653
+ if (!filterConstructor || model instanceof filterConstructor) {
654
+ traverser(model, parent, relation && relation.name);
655
+ }
656
+ });
657
+
658
+ return this;
659
+ }
660
+
661
+ static traverseAsync(...args) {
662
+ const { traverser, models, filterConstructor } = getTraverseArgs(...args);
663
+
664
+ if (!asSingle(models)) {
665
+ return Promise.resolve();
666
+ }
667
+
668
+ const modelClass = asSingle(models).constructor;
669
+ const promises = [];
670
+
671
+ visitModels(models, modelClass, (model, _, parent, relation) => {
672
+ if (!filterConstructor || model instanceof filterConstructor) {
673
+ const maybePromise = traverser(model, parent, relation && relation.name);
674
+ promises.push(maybePromise);
675
+ }
676
+ });
677
+
678
+ return promiseMap(promises, (it) => it, { concurrency: this.getConcurrency(this.knex()) });
679
+ }
680
+ }
681
+
682
+ Object.defineProperties(Model, {
683
+ isObjectionModelClass: {
684
+ enumerable: false,
685
+ writable: false,
686
+ value: true,
687
+ },
688
+ });
689
+
690
+ Object.defineProperties(Model.prototype, {
691
+ $isObjectionModel: {
692
+ enumerable: false,
693
+ writable: false,
694
+ value: true,
695
+ },
696
+
697
+ $objectionModelClass: {
698
+ enumerable: false,
699
+ writable: false,
700
+ value: Model,
701
+ },
702
+ });
703
+
704
+ Model.QueryBuilder = QueryBuilder;
705
+
706
+ Model.HasOneRelation = HasOneRelation;
707
+ Model.HasManyRelation = HasManyRelation;
708
+ Model.ManyToManyRelation = ManyToManyRelation;
709
+ Model.BelongsToOneRelation = BelongsToOneRelation;
710
+ Model.HasOneThroughRelation = HasOneThroughRelation;
711
+
712
+ Model.JoinEagerAlgorithm = 'JoinEagerAlgorithm';
713
+ Model.NaiveEagerAlgorithm = 'NaiveEagerAlgorithm';
714
+ Model.WhereInEagerAlgorithm = 'WhereInEagerAlgorithm';
715
+
716
+ Model.ValidationError = ValidationError;
717
+ Model.NotFoundError = NotFoundError;
718
+ Model.ModifierNotFoundError = ModifierNotFoundError;
719
+
720
+ Model.tableName = null;
721
+ Model.jsonSchema = null;
722
+ Model.idColumn = 'id';
723
+ Model.uidProp = '#id';
724
+ Model.uidRefProp = '#ref';
725
+ Model.dbRefProp = '#dbRef';
726
+ Model.propRefRegex = /#ref{([^\.]+)\.([^}]+)}/g;
727
+ Model.jsonAttributes = null;
728
+ Model.cloneObjectAttributes = true;
729
+ Model.virtualAttributes = null;
730
+ Model.relationMappings = null;
731
+ Model.modelPaths = [];
732
+ Model.pickJsonSchemaProperties = false;
733
+ Model.defaultGraphOptions = null;
734
+ Model.defaultFindOptions = Object.freeze({});
735
+ Model.modifiers = null;
736
+ Model.useLimitInFirst = false;
737
+ Model.columnNameMappers = null;
738
+ Model.relatedFindQueryMutates = false;
739
+ Model.relatedInsertQueryMutates = false;
740
+ Model.concurrency = null;
741
+
742
+ function instanceQuery({ instance, transaction }) {
743
+ const modelClass = instance.constructor;
744
+
745
+ return modelClass
746
+ .query(transaction)
747
+ .findOperationFactory(() => {
748
+ return new InstanceFindOperation('find', { instance });
749
+ })
750
+ .insertOperationFactory(() => {
751
+ return new InstanceInsertOperation('insert', { instance });
752
+ })
753
+ .updateOperationFactory(() => {
754
+ return new InstanceUpdateOperation('update', { instance });
755
+ })
756
+ .patchOperationFactory(() => {
757
+ return new InstanceUpdateOperation('patch', {
758
+ instance,
759
+ modelOptions: { patch: true },
760
+ });
761
+ })
762
+ .deleteOperationFactory(() => {
763
+ return new InstanceDeleteOperation('delete', { instance });
764
+ })
765
+ .relateOperationFactory(() => {
766
+ throw new Error('`relate` makes no sense in this context');
767
+ })
768
+ .unrelateOperationFactory(() => {
769
+ throw new Error('`unrelate` makes no sense in this context');
770
+ });
771
+ }
772
+
773
+ function relatedQuery({ modelClass, relationName, transaction, alwaysReturnArray } = {}) {
774
+ const relation = modelClass.getRelation(relationName);
775
+ const relatedModelClass = relation.relatedModelClass;
776
+
777
+ const query = relatedModelClass
778
+ .query(transaction)
779
+ .findOperationFactory((builder) => {
780
+ const isSubQuery = !builder.for();
781
+ const owner = isSubQuery
782
+ ? RelationOwner.createParentReference(builder, relation)
783
+ : RelationOwner.create(builder.for());
784
+
785
+ const operation = relation.find(builder, owner);
786
+
787
+ operation.assignResultToOwner = modelClass.getRelatedFindQueryMutates();
788
+ operation.alwaysReturnArray = alwaysReturnArray;
789
+ operation.alias = isSubQuery ? relation.name : null;
790
+
791
+ return operation;
792
+ })
793
+ .insertOperationFactory((builder) => {
794
+ const owner = writeOperationOwner(builder, 'insert');
795
+ const operation = relation.insert(builder, owner);
796
+
797
+ operation.assignResultToOwner = modelClass.getRelatedInsertQueryMutates();
798
+ return operation;
799
+ })
800
+ .updateOperationFactory((builder) => {
801
+ const owner = writeOperationOwner(builder, 'update');
802
+ return relation.update(builder, owner);
803
+ })
804
+ .patchOperationFactory((builder) => {
805
+ const owner = writeOperationOwner(builder, 'patch');
806
+ return relation.patch(builder, owner);
807
+ })
808
+ .deleteOperationFactory((builder) => {
809
+ const owner = writeOperationOwner(builder, 'delete');
810
+ return relation.delete(builder, owner);
811
+ })
812
+ .relateOperationFactory((builder) => {
813
+ const owner = writeOperationOwner(builder, 'relate');
814
+ return relation.relate(builder, owner);
815
+ })
816
+ .unrelateOperationFactory((builder) => {
817
+ const owner = writeOperationOwner(builder, 'unrelate');
818
+ return relation.unrelate(builder, owner);
819
+ });
820
+
821
+ query._isRelatedQuery = true;
822
+ return query;
823
+ }
824
+
825
+ function writeOperationOwner(builder, method) {
826
+ const owner = builder.for();
827
+
828
+ if ((owner === null || owner === undefined) && builder._forError === null) {
829
+ // Without an owner the write would silently do nothing or, in the case
830
+ // of inserts, create rows with null foreign keys. The error is thrown
831
+ // when the query is built or executed.
832
+ builder._forError = new Error(`relatedQuery(): for() must be called before ${method}()`);
833
+ }
834
+
835
+ return RelationOwner.create(owner);
836
+ }
837
+
838
+ function cachedGet(target, hiddenPropertyName, creator) {
839
+ if (!target.hasOwnProperty(hiddenPropertyName)) {
840
+ defineNonEnumerableProperty(target, hiddenPropertyName, creator(target));
841
+ }
842
+
843
+ return target[hiddenPropertyName];
844
+ }
845
+
846
+ function getValidator(modelClass) {
847
+ return modelClass.createValidator();
848
+ }
849
+
850
+ function getJsonSchema(modelClass) {
851
+ return modelClass.jsonSchema;
852
+ }
853
+
854
+ function getColumnNameMappers(modelClass) {
855
+ return modelClass.columnNameMappers;
856
+ }
857
+
858
+ function getIdRelationProperty(modelClass) {
859
+ const idColumn = asArray(modelClass.getIdColumn());
860
+
861
+ return new RelationProperty(
862
+ idColumn.map((idCol) => `${modelClass.getTableName()}.${idCol}`),
863
+ () => modelClass,
864
+ );
865
+ }
866
+
867
+ function getReadOnlyAttributes(modelClass) {
868
+ return [...new Set(getReadOnlyAttributesRecursively(modelClass))];
869
+ }
870
+
871
+ function getReadOnlyAttributesRecursively(modelClass) {
872
+ if (modelClass === Model || modelClass.prototype == undefined) {
873
+ // Stop recursion to the model class or its prototype is null or undefined.
874
+ return [];
875
+ }
876
+
877
+ const propertyNames = Object.getOwnPropertyNames(modelClass.prototype);
878
+
879
+ return [
880
+ ...getReadOnlyAttributes(Object.getPrototypeOf(modelClass)),
881
+ ...propertyNames.filter((propName) => {
882
+ const desc = Object.getOwnPropertyDescriptor(modelClass.prototype, propName);
883
+ return (desc.get && !desc.set) || desc.writable === false || isFunction(desc.value);
884
+ }),
885
+ ];
886
+ }
887
+
888
+ function getRelationMappings(modelClass) {
889
+ let relationMappings = modelClass.relationMappings;
890
+
891
+ if (isFunction(relationMappings)) {
892
+ relationMappings = relationMappings.call(modelClass);
893
+ }
894
+
895
+ return relationMappings || {};
896
+ }
897
+
898
+ function getRelationNames(modelClass) {
899
+ return Object.keys(modelClass.getRelationMappings());
900
+ }
901
+
902
+ function getVirtualAttributes(modelClass) {
903
+ return modelClass.virtualAttributes || [];
904
+ }
905
+
906
+ function getTraverseArgs(filterConstructor, models, traverser) {
907
+ filterConstructor = filterConstructor || null;
908
+
909
+ if (traverser === undefined) {
910
+ traverser = models;
911
+ models = filterConstructor;
912
+ filterConstructor = null;
913
+ }
914
+
915
+ if (!isFunction(traverser)) {
916
+ throw new Error('traverser must be a function');
917
+ }
918
+
919
+ return {
920
+ traverser,
921
+ models,
922
+ filterConstructor,
923
+ };
924
+ }
925
+
926
+ function asPropsArray(props) {
927
+ if (props.length === 1) {
928
+ const arg = props[0];
929
+ if (Array.isArray(arg)) {
930
+ return arg;
931
+ } else if (arg && typeof arg === 'object') {
932
+ return Object.entries(arg)
933
+ .filter(([, value]) => value)
934
+ .map(([key]) => key);
935
+ }
936
+ }
937
+ return props;
938
+ }
939
+
940
+ module.exports = {
941
+ Model,
942
+ };