@abedmurrar/objection 4.0.0-alpha.0 → 4.0.0-beta.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 (192) hide show
  1. package/README.md +103 -67
  2. package/lib/index.mjs +6 -0
  3. package/lib/initialize.js +6 -9
  4. package/lib/model/AjvValidator.js +235 -282
  5. package/lib/model/Model.js +653 -823
  6. package/lib/model/ModifierNotFoundError.js +5 -7
  7. package/lib/model/NotFoundError.js +14 -18
  8. package/lib/model/RelationDoesNotExistError.js +6 -9
  9. package/lib/model/ValidationError.js +33 -41
  10. package/lib/model/Validator.js +15 -21
  11. package/lib/model/getModel.js +1 -3
  12. package/lib/model/graph/ModelGraph.js +44 -64
  13. package/lib/model/graph/ModelGraphBuilder.js +164 -217
  14. package/lib/model/graph/ModelGraphEdge.js +31 -43
  15. package/lib/model/graph/ModelGraphNode.js +192 -231
  16. package/lib/model/inheritModel.js +9 -18
  17. package/lib/model/modelBindKnex.js +48 -62
  18. package/lib/model/modelClone.js +79 -98
  19. package/lib/model/modelColPropMap.js +16 -26
  20. package/lib/model/modelConcurrency.js +24 -0
  21. package/lib/model/modelId.js +44 -49
  22. package/lib/model/modelJsonAttributes.js +56 -76
  23. package/lib/model/modelParseRelations.js +68 -67
  24. package/lib/model/modelQueryProps.js +76 -107
  25. package/lib/model/modelSet.js +92 -112
  26. package/lib/model/modelTableMetadata.js +60 -72
  27. package/lib/model/modelToJson.js +120 -150
  28. package/lib/model/modelUtils.js +30 -37
  29. package/lib/model/modelValidate.js +34 -42
  30. package/lib/model/modelValues.js +78 -91
  31. package/lib/model/modelVisitor.js +22 -29
  32. package/lib/objection.js +42 -67
  33. package/lib/queryBuilder/FunctionBuilder.js +231 -279
  34. package/lib/queryBuilder/InternalOptions.js +19 -24
  35. package/lib/queryBuilder/JoinBuilder.js +116 -149
  36. package/lib/queryBuilder/QueryBuilder.js +1009 -1271
  37. package/lib/queryBuilder/QueryBuilderBase.js +647 -865
  38. package/lib/queryBuilder/QueryBuilderContext.js +14 -21
  39. package/lib/queryBuilder/QueryBuilderContextBase.js +20 -29
  40. package/lib/queryBuilder/QueryBuilderOperationSupport.js +462 -536
  41. package/lib/queryBuilder/QueryBuilderUserContext.js +19 -25
  42. package/lib/queryBuilder/RawBuilder.js +58 -73
  43. package/lib/queryBuilder/ReferenceBuilder.js +232 -270
  44. package/lib/queryBuilder/RelationExpression.js +322 -380
  45. package/lib/queryBuilder/StaticHookArguments.js +94 -106
  46. package/lib/queryBuilder/ValueBuilder.js +100 -112
  47. package/lib/queryBuilder/expressions.js +86 -116
  48. package/lib/queryBuilder/functions/mysql.js +642 -697
  49. package/lib/queryBuilder/graph/GraphAction.js +44 -59
  50. package/lib/queryBuilder/graph/GraphData.js +7 -9
  51. package/lib/queryBuilder/graph/GraphFetcher.js +115 -151
  52. package/lib/queryBuilder/graph/GraphNodeDbExistence.js +114 -152
  53. package/lib/queryBuilder/graph/GraphOperation.js +16 -22
  54. package/lib/queryBuilder/graph/GraphOptions.js +143 -185
  55. package/lib/queryBuilder/graph/GraphUpsert.js +167 -241
  56. package/lib/queryBuilder/graph/delete/GraphDelete.js +8 -13
  57. package/lib/queryBuilder/graph/delete/GraphDeleteAction.js +44 -62
  58. package/lib/queryBuilder/graph/insert/GraphInsert.js +99 -128
  59. package/lib/queryBuilder/graph/insert/GraphInsertAction.js +151 -193
  60. package/lib/queryBuilder/graph/insert/JoinRowGraphInsertAction.js +57 -79
  61. package/lib/queryBuilder/graph/patch/GraphPatch.js +8 -13
  62. package/lib/queryBuilder/graph/patch/GraphPatchAction.js +181 -234
  63. package/lib/queryBuilder/graph/recursiveUpsert/GraphRecursiveUpsert.js +16 -21
  64. package/lib/queryBuilder/graph/recursiveUpsert/GraphRecursiveUpsertAction.js +80 -110
  65. package/lib/queryBuilder/join/JoinResultColumn.js +14 -18
  66. package/lib/queryBuilder/join/JoinResultParser.js +88 -101
  67. package/lib/queryBuilder/join/RelationJoiner.js +205 -288
  68. package/lib/queryBuilder/join/TableNode.js +117 -144
  69. package/lib/queryBuilder/join/TableTree.js +60 -76
  70. package/lib/queryBuilder/join/utils.js +10 -16
  71. package/lib/queryBuilder/operations/DelegateOperation.js +93 -133
  72. package/lib/queryBuilder/operations/DeleteOperation.js +33 -37
  73. package/lib/queryBuilder/operations/FindByIdOperation.js +20 -28
  74. package/lib/queryBuilder/operations/FindByIdsOperation.js +17 -23
  75. package/lib/queryBuilder/operations/FindOperation.js +114 -131
  76. package/lib/queryBuilder/operations/FirstOperation.js +14 -19
  77. package/lib/queryBuilder/operations/FromOperation.js +69 -88
  78. package/lib/queryBuilder/operations/InsertAndFetchOperation.js +28 -39
  79. package/lib/queryBuilder/operations/InsertGraphAndFetchOperation.js +25 -35
  80. package/lib/queryBuilder/operations/InsertGraphOperation.js +77 -98
  81. package/lib/queryBuilder/operations/InsertOperation.js +132 -165
  82. package/lib/queryBuilder/operations/InstanceDeleteOperation.js +27 -36
  83. package/lib/queryBuilder/operations/InstanceFindOperation.js +9 -13
  84. package/lib/queryBuilder/operations/InstanceInsertOperation.js +13 -17
  85. package/lib/queryBuilder/operations/InstanceUpdateOperation.js +32 -46
  86. package/lib/queryBuilder/operations/JoinRelatedOperation.js +66 -86
  87. package/lib/queryBuilder/operations/KnexOperation.js +4 -7
  88. package/lib/queryBuilder/operations/MergeOperation.js +32 -45
  89. package/lib/queryBuilder/operations/ObjectionToKnexConvertingOperation.js +131 -150
  90. package/lib/queryBuilder/operations/OnBuildKnexOperation.js +17 -23
  91. package/lib/queryBuilder/operations/OnBuildOperation.js +17 -23
  92. package/lib/queryBuilder/operations/OnErrorOperation.js +17 -23
  93. package/lib/queryBuilder/operations/QueryBuilderOperation.js +231 -270
  94. package/lib/queryBuilder/operations/RangeOperation.js +30 -40
  95. package/lib/queryBuilder/operations/RelateOperation.js +14 -21
  96. package/lib/queryBuilder/operations/ReturningOperation.js +12 -18
  97. package/lib/queryBuilder/operations/RunAfterOperation.js +17 -23
  98. package/lib/queryBuilder/operations/RunBeforeOperation.js +17 -23
  99. package/lib/queryBuilder/operations/UnrelateOperation.js +12 -17
  100. package/lib/queryBuilder/operations/UpdateAndFetchOperation.js +48 -65
  101. package/lib/queryBuilder/operations/UpdateOperation.js +104 -129
  102. package/lib/queryBuilder/operations/UpsertGraphAndFetchOperation.js +25 -35
  103. package/lib/queryBuilder/operations/UpsertGraphOperation.js +36 -55
  104. package/lib/queryBuilder/operations/WhereCompositeOperation.js +30 -39
  105. package/lib/queryBuilder/operations/WhereInOperation.js +34 -36
  106. package/lib/queryBuilder/operations/eager/EagerOperation.js +37 -52
  107. package/lib/queryBuilder/operations/eager/JoinEagerOperation.js +34 -44
  108. package/lib/queryBuilder/operations/eager/NaiveEagerOperation.js +4 -7
  109. package/lib/queryBuilder/operations/eager/WhereInEagerOperation.js +193 -251
  110. package/lib/queryBuilder/operations/jsonApi/WhereJsonHasOperation.js +18 -25
  111. package/lib/queryBuilder/operations/jsonApi/WhereJsonNotObjectOperation.js +25 -41
  112. package/lib/queryBuilder/operations/jsonApi/WhereJsonOperation.js +19 -20
  113. package/lib/queryBuilder/operations/jsonApi/WhereJsonOverlapsOperation.js +23 -21
  114. package/lib/queryBuilder/operations/jsonApi/mysqlJsonApi.js +106 -118
  115. package/lib/queryBuilder/operations/jsonApi/postgresJsonApi.js +79 -108
  116. package/lib/queryBuilder/operations/select/SelectOperation.js +37 -53
  117. package/lib/queryBuilder/operations/select/Selection.js +94 -105
  118. package/lib/queryBuilder/operations/whereInComposite/WhereInCompositeMsSqlOperation.js +68 -101
  119. package/lib/queryBuilder/operations/whereInComposite/WhereInCompositeOperation.js +65 -75
  120. package/lib/queryBuilder/operations/whereInComposite/WhereInCompositeSqliteOperation.js +75 -84
  121. package/lib/queryBuilder/parsers/jsonFieldExpressionParser.js +760 -859
  122. package/lib/queryBuilder/parsers/relationExpressionParser.js +840 -952
  123. package/lib/queryBuilder/transformations/CompositeQueryTransformation.js +10 -15
  124. package/lib/queryBuilder/transformations/QueryTransformation.js +4 -6
  125. package/lib/queryBuilder/transformations/WrapMysqlModifySubqueryTransformation.js +35 -49
  126. package/lib/queryBuilder/transformations/index.js +3 -9
  127. package/lib/queryBuilder/whereScopes.js +158 -186
  128. package/lib/relations/Relation.js +279 -363
  129. package/lib/relations/RelationDeleteOperation.js +16 -22
  130. package/lib/relations/RelationFindOperation.js +100 -133
  131. package/lib/relations/RelationInsertOperation.js +19 -27
  132. package/lib/relations/RelationOwner.js +167 -204
  133. package/lib/relations/RelationProperty.js +177 -217
  134. package/lib/relations/RelationUpdateOperation.js +16 -23
  135. package/lib/relations/belongsToOne/BelongsToOneDeleteOperation.js +11 -16
  136. package/lib/relations/belongsToOne/BelongsToOneInsertOperation.js +24 -35
  137. package/lib/relations/belongsToOne/BelongsToOneRelateOperation.js +30 -41
  138. package/lib/relations/belongsToOne/BelongsToOneRelation.js +33 -41
  139. package/lib/relations/belongsToOne/BelongsToOneUnrelateOperation.js +38 -53
  140. package/lib/relations/hasMany/HasManyInsertOperation.js +35 -51
  141. package/lib/relations/hasMany/HasManyRelateOperation.js +38 -54
  142. package/lib/relations/hasMany/HasManyRelation.js +30 -38
  143. package/lib/relations/hasMany/HasManyUnrelateOperation.js +19 -26
  144. package/lib/relations/hasOne/HasOneRelation.js +4 -7
  145. package/lib/relations/hasOneThrough/HasOneThroughRelation.js +4 -7
  146. package/lib/relations/manyToMany/ManyToManyModifyMixin.js +67 -90
  147. package/lib/relations/manyToMany/ManyToManyRelation.js +349 -451
  148. package/lib/relations/manyToMany/ManyToManySqliteModifyMixin.js +19 -26
  149. package/lib/relations/manyToMany/delete/ManyToManyDeleteOperation.js +3 -5
  150. package/lib/relations/manyToMany/delete/ManyToManyDeleteOperationBase.js +14 -20
  151. package/lib/relations/manyToMany/delete/ManyToManyDeleteSqliteOperation.js +3 -7
  152. package/lib/relations/manyToMany/find/ManyToManyFindOperation.js +71 -94
  153. package/lib/relations/manyToMany/insert/ManyToManyInsertOperation.js +31 -43
  154. package/lib/relations/manyToMany/relate/ManyToManyRelateOperation.js +50 -67
  155. package/lib/relations/manyToMany/unrelate/ManyToManyUnrelateOperation.js +4 -7
  156. package/lib/relations/manyToMany/unrelate/ManyToManyUnrelateOperationBase.js +20 -27
  157. package/lib/relations/manyToMany/unrelate/ManyToManyUnrelateSqliteOperation.js +5 -10
  158. package/lib/relations/manyToMany/update/ManyToManyUpdateOperation.js +3 -5
  159. package/lib/relations/manyToMany/update/ManyToManyUpdateOperationBase.js +55 -72
  160. package/lib/relations/manyToMany/update/ManyToManyUpdateSqliteOperation.js +3 -7
  161. package/lib/transaction.js +53 -83
  162. package/lib/utils/assert.js +15 -21
  163. package/lib/utils/buildUtils.js +17 -19
  164. package/lib/utils/classUtils.js +7 -11
  165. package/lib/utils/cloneDeep.js +365 -0
  166. package/lib/utils/createModifier.js +36 -41
  167. package/lib/utils/deprecate.js +8 -12
  168. package/lib/utils/identifierMapping.js +153 -192
  169. package/lib/utils/internalPropUtils.js +4 -8
  170. package/lib/utils/knexUtils.js +61 -56
  171. package/lib/utils/mixin.js +16 -23
  172. package/lib/utils/mysqlJsonPath.js +55 -40
  173. package/lib/utils/normalizeIds.js +110 -127
  174. package/lib/utils/objectUtils.js +236 -338
  175. package/lib/utils/parseFieldExpression.js +66 -44
  176. package/lib/utils/postgresJsonPath.js +48 -62
  177. package/lib/utils/promiseUtils/after.js +10 -13
  178. package/lib/utils/promiseUtils/afterReturn.js +10 -13
  179. package/lib/utils/promiseUtils/index.js +15 -17
  180. package/lib/utils/promiseUtils/isPromise.js +6 -9
  181. package/lib/utils/promiseUtils/map.js +75 -89
  182. package/lib/utils/promiseUtils/mapAfterAllReturn.js +17 -23
  183. package/lib/utils/promiseUtils/try.js +15 -18
  184. package/lib/utils/resolveModel.js +91 -94
  185. package/lib/utils/tmpColumnUtils.js +4 -13
  186. package/package.json +50 -23
  187. package/typings/objection/index.d.mts +362 -0
  188. package/typings/objection/index.d.ts +36 -9
  189. package/lib/.eslintrc.json +0 -8
  190. package/lib/queryBuilder/parsers/jsonFieldExpressionParser.pegjs +0 -97
  191. package/lib/queryBuilder/parsers/relationExpressionParser.pegjs +0 -141
  192. package/lib/utils/clone.js +0 -2329
@@ -1,401 +1,317 @@
1
1
  'use strict';
2
-
3
2
  const { withWhereScope } = require('../queryBuilder/whereScopes');
4
3
  const { RelationProperty } = require('./RelationProperty');
5
-
6
4
  const { RelationFindOperation } = require('./RelationFindOperation');
7
5
  const { RelationUpdateOperation } = require('./RelationUpdateOperation');
8
6
  const { RelationDeleteOperation } = require('./RelationDeleteOperation');
9
-
10
7
  const { resolveModel } = require('../utils/resolveModel');
11
8
  const { get, isFunction } = require('../utils/objectUtils');
12
9
  const { mapAfterAllReturn } = require('../utils/promiseUtils');
13
10
  const { createModifier } = require('../utils/createModifier');
14
-
15
11
  class Relation {
16
- constructor(relationName, OwnerClass) {
17
- this.name = relationName;
18
- this.ownerModelClass = OwnerClass;
19
- this.relatedModelClass = null;
20
-
21
- this.ownerProp = null;
22
- this.relatedProp = null;
23
-
24
- this.joinTableModelClass = null;
25
- this.joinTableOwnerProp = null;
26
- this.joinTableRelatedProp = null;
27
- this.joinTableBeforeInsert = null;
28
- this.joinTableExtras = [];
29
-
30
- this.modify = null;
31
- this.beforeInsert = null;
32
- }
33
-
34
- setMapping(mapping) {
35
- let ctx = {
36
- name: this.name,
37
- mapping,
38
- ownerModelClass: this.ownerModelClass,
39
- relatedModelClass: null,
40
- relatedProp: null,
41
- ownerProp: null,
42
- modify: null,
43
- beforeInsert: null,
44
- forbiddenMappingProperties: this.forbiddenMappingProperties,
45
- createError: (msg) => this.createError(msg),
46
- };
47
-
48
- ctx = checkForbiddenProperties(ctx);
49
- ctx = checkOwnerModelClass(ctx);
50
- ctx = checkRelatedModelClass(ctx);
51
- ctx = resolveRelatedModelClass(ctx);
52
- ctx = checkRelation(ctx);
53
- ctx = createJoinProperties(ctx);
54
- ctx = parseModify(ctx);
55
- ctx = parseBeforeInsert(ctx);
56
-
57
- this.relatedModelClass = ctx.relatedModelClass;
58
- this.ownerProp = ctx.ownerProp;
59
- this.relatedProp = ctx.relatedProp;
60
- this.modify = ctx.modify;
61
- this.beforeInsert = ctx.beforeInsert;
62
- }
63
-
64
- get forbiddenMappingProperties() {
65
- return ['join.through'];
66
- }
67
-
68
- get joinTable() {
69
- return this.joinTableModelClass ? this.joinTableModelClass.getTableName() : null;
70
- }
71
-
72
- get joinModelClass() {
73
- return this.getJoinModelClass(this.ownerModelClass.knex());
74
- }
75
-
76
- getJoinModelClass(knex) {
77
- return this.joinTableModelClass && knex !== this.joinTableModelClass.knex()
78
- ? this.joinTableModelClass.bindKnex(knex)
79
- : this.joinTableModelClass;
80
- }
81
-
82
- isOneToOne() {
83
- return false;
84
- }
85
-
86
- clone() {
87
- const relation = new this.constructor(this.name, this.ownerModelClass);
88
-
89
- relation.relatedModelClass = this.relatedModelClass;
90
- relation.ownerProp = this.ownerProp;
91
- relation.relatedProp = this.relatedProp;
92
- relation.modify = this.modify;
93
- relation.beforeInsert = this.beforeInsert;
94
-
95
- relation.joinTableModelClass = this.joinTableModelClass;
96
- relation.joinTableOwnerProp = this.joinTableOwnerProp;
97
- relation.joinTableRelatedProp = this.joinTableRelatedProp;
98
- relation.joinTableBeforeInsert = this.joinTableBeforeInsert;
99
- relation.joinTableExtras = this.joinTableExtras;
100
-
101
- return relation;
102
- }
103
-
104
- bindKnex(knex) {
105
- const bound = this.clone();
106
-
107
- bound.relatedModelClass = this.relatedModelClass.bindKnex(knex);
108
- bound.ownerModelClass = this.ownerModelClass.bindKnex(knex);
109
-
110
- if (this.joinTableModelClass) {
111
- bound.joinTableModelClass = this.joinTableModelClass.bindKnex(knex);
112
- }
113
-
114
- return bound;
115
- }
116
-
117
- findQuery(builder, owner) {
118
- const relatedRefs = this.relatedProp.refs(builder);
119
-
120
- withWhereScope(builder, () => {
121
- owner.buildFindQuery(builder, this, relatedRefs);
122
- });
123
-
124
- return this.applyModify(builder);
125
- }
126
-
127
- applyModify(builder) {
128
- try {
129
- // The relation's `modify` gets its own scope so that an `orWhere`
130
- // in it can't escape the owner condition.
131
- return withWhereScope(builder, () => builder.modify(this.modify));
132
- } catch (err) {
133
- if (err instanceof this.relatedModelClass.ModifierNotFoundError) {
134
- throw this.createError(err.message);
135
- } else {
136
- throw err;
137
- }
138
- }
139
- }
140
-
141
- join(
142
- builder,
143
- {
144
- joinOperation = 'join',
145
- relatedTableAlias = builder.tableRefFor(this.relatedModelClass),
146
- relatedJoinSelectQuery = this.relatedModelClass.query().childQueryOf(builder),
147
- relatedTable = builder.tableNameFor(this.relatedModelClass),
148
- ownerTable = builder.tableRefFor(this.ownerModelClass),
149
- } = {},
150
- ) {
151
- let relatedJoinSelect = this.applyModify(relatedJoinSelectQuery).as(relatedTableAlias);
152
-
153
- if (relatedJoinSelect.isSelectAll()) {
154
- // No need to join a subquery if the query is `select * from "RelatedTable"`.
155
- relatedJoinSelect = aliasedTableName(relatedTable, relatedTableAlias);
156
- }
157
-
158
- return builder[joinOperation](relatedJoinSelect, (join) => {
159
- const relatedProp = this.relatedProp;
160
- const ownerProp = this.ownerProp;
161
-
162
- relatedProp.forEach((i) => {
163
- const relatedRef = relatedProp.ref(builder, i).table(relatedTableAlias);
164
- const ownerRef = ownerProp.ref(builder, i).table(ownerTable);
165
-
166
- join.on(relatedRef, ownerRef);
167
- });
168
- });
169
- }
170
-
171
- find(_, owner) {
172
- return new RelationFindOperation('find', {
173
- relation: this,
174
- owner,
175
- });
176
- }
177
-
178
- insert(_, owner) {
179
- /* istanbul ignore next */
180
- throw this.createError('not implemented');
181
- }
182
-
183
- update(_, owner) {
184
- return new RelationUpdateOperation('update', {
185
- relation: this,
186
- owner,
187
- });
188
- }
189
-
190
- patch(_, owner) {
191
- return new RelationUpdateOperation('patch', {
192
- relation: this,
193
- owner,
194
- modelOptions: { patch: true },
195
- });
196
- }
197
-
198
- delete(_, owner) {
199
- return new RelationDeleteOperation('delete', {
200
- relation: this,
201
- owner,
202
- });
203
- }
204
-
205
- relate() {
206
- /* istanbul ignore next */
207
- throw this.createError('not implemented');
208
- }
209
-
210
- unrelate() {
211
- /* istanbul ignore next */
212
- throw this.createError('not implemented');
213
- }
214
-
215
- hasRelateProp(model) {
216
- return model.$hasProps(this.relatedProp.props);
217
- }
218
-
219
- setRelateProp(model, values) {
220
- this.relatedProp.forEach((i) => {
221
- this.relatedProp.setProp(model, i, values[i]);
222
- });
223
- }
224
-
225
- executeBeforeInsert(models, queryContext, result) {
226
- return mapAfterAllReturn(models, (model) => this.beforeInsert(model, queryContext), result);
227
- }
228
-
229
- createError(message) {
230
- if (this.ownerModelClass && this.ownerModelClass.name && this.name) {
231
- return new Error(`${this.ownerModelClass.name}.relationMappings.${this.name}: ${message}`);
232
- } else {
233
- return new Error(`${this.constructor.name}: ${message}`);
234
- }
235
- }
12
+ constructor(relationName, OwnerClass) {
13
+ this.name = relationName;
14
+ this.ownerModelClass = OwnerClass;
15
+ this.relatedModelClass = null;
16
+ this.ownerProp = null;
17
+ this.relatedProp = null;
18
+ this.joinTableModelClass = null;
19
+ this.joinTableOwnerProp = null;
20
+ this.joinTableRelatedProp = null;
21
+ this.joinTableBeforeInsert = null;
22
+ this.joinTableExtras = [];
23
+ this.modify = null;
24
+ this.beforeInsert = null;
25
+ }
26
+ setMapping(mapping) {
27
+ let ctx = {
28
+ name: this.name,
29
+ mapping,
30
+ ownerModelClass: this.ownerModelClass,
31
+ relatedModelClass: null,
32
+ relatedProp: null,
33
+ ownerProp: null,
34
+ modify: null,
35
+ beforeInsert: null,
36
+ forbiddenMappingProperties: this.forbiddenMappingProperties,
37
+ createError: (msg) => this.createError(msg),
38
+ };
39
+ ctx = checkForbiddenProperties(ctx);
40
+ ctx = checkOwnerModelClass(ctx);
41
+ ctx = checkRelatedModelClass(ctx);
42
+ ctx = resolveRelatedModelClass(ctx);
43
+ ctx = checkRelation(ctx);
44
+ ctx = createJoinProperties(ctx);
45
+ ctx = parseModify(ctx);
46
+ ctx = parseBeforeInsert(ctx);
47
+ this.relatedModelClass = ctx.relatedModelClass;
48
+ this.ownerProp = ctx.ownerProp;
49
+ this.relatedProp = ctx.relatedProp;
50
+ this.modify = ctx.modify;
51
+ this.beforeInsert = ctx.beforeInsert;
52
+ }
53
+ get forbiddenMappingProperties() {
54
+ return ['join.through'];
55
+ }
56
+ get joinTable() {
57
+ return this.joinTableModelClass ? this.joinTableModelClass.getTableName() : null;
58
+ }
59
+ get joinModelClass() {
60
+ return this.getJoinModelClass(this.ownerModelClass.knex());
61
+ }
62
+ getJoinModelClass(knex) {
63
+ return this.joinTableModelClass && knex !== this.joinTableModelClass.knex()
64
+ ? this.joinTableModelClass.bindKnex(knex)
65
+ : this.joinTableModelClass;
66
+ }
67
+ isOneToOne() {
68
+ return false;
69
+ }
70
+ clone() {
71
+ const relation = new this.constructor(this.name, this.ownerModelClass);
72
+ relation.relatedModelClass = this.relatedModelClass;
73
+ relation.ownerProp = this.ownerProp;
74
+ relation.relatedProp = this.relatedProp;
75
+ relation.modify = this.modify;
76
+ relation.beforeInsert = this.beforeInsert;
77
+ relation.joinTableModelClass = this.joinTableModelClass;
78
+ relation.joinTableOwnerProp = this.joinTableOwnerProp;
79
+ relation.joinTableRelatedProp = this.joinTableRelatedProp;
80
+ relation.joinTableBeforeInsert = this.joinTableBeforeInsert;
81
+ relation.joinTableExtras = this.joinTableExtras;
82
+ return relation;
83
+ }
84
+ bindKnex(knex) {
85
+ const bound = this.clone();
86
+ bound.relatedModelClass = this.relatedModelClass.bindKnex(knex);
87
+ bound.ownerModelClass = this.ownerModelClass.bindKnex(knex);
88
+ if (this.joinTableModelClass) {
89
+ bound.joinTableModelClass = this.joinTableModelClass.bindKnex(knex);
90
+ }
91
+ return bound;
92
+ }
93
+ findQuery(builder, owner) {
94
+ const relatedRefs = this.relatedProp.refs(builder);
95
+ withWhereScope(builder, () => {
96
+ owner.buildFindQuery(builder, this, relatedRefs);
97
+ });
98
+ return this.applyModify(builder);
99
+ }
100
+ applyModify(builder) {
101
+ try {
102
+ // The relation's `modify` gets its own scope so that an `orWhere`
103
+ // in it can't escape the owner condition.
104
+ return withWhereScope(builder, () => builder.modify(this.modify));
105
+ }
106
+ catch (err) {
107
+ if (err instanceof this.relatedModelClass.ModifierNotFoundError) {
108
+ throw this.createError(err.message);
109
+ }
110
+ else {
111
+ throw err;
112
+ }
113
+ }
114
+ }
115
+ join(builder, { joinOperation = 'join', relatedTableAlias = builder.tableRefFor(this.relatedModelClass), relatedJoinSelectQuery = this.relatedModelClass.query().childQueryOf(builder), relatedTable = builder.tableNameFor(this.relatedModelClass), ownerTable = builder.tableRefFor(this.ownerModelClass), } = {}) {
116
+ let relatedJoinSelect = this.applyModify(relatedJoinSelectQuery).as(relatedTableAlias);
117
+ if (relatedJoinSelect.isSelectAll()) {
118
+ // No need to join a subquery if the query is `select * from "RelatedTable"`.
119
+ relatedJoinSelect = aliasedTableName(relatedTable, relatedTableAlias);
120
+ }
121
+ return builder[joinOperation](relatedJoinSelect, (join) => {
122
+ const relatedProp = this.relatedProp;
123
+ const ownerProp = this.ownerProp;
124
+ relatedProp.forEach((i) => {
125
+ const relatedRef = relatedProp.ref(builder, i).table(relatedTableAlias);
126
+ const ownerRef = ownerProp.ref(builder, i).table(ownerTable);
127
+ join.on(relatedRef, ownerRef);
128
+ });
129
+ });
130
+ }
131
+ find(_, owner) {
132
+ return new RelationFindOperation('find', {
133
+ relation: this,
134
+ owner,
135
+ });
136
+ }
137
+ insert(_, owner) {
138
+ /* istanbul ignore next */
139
+ throw this.createError('not implemented');
140
+ }
141
+ update(_, owner) {
142
+ return new RelationUpdateOperation('update', {
143
+ relation: this,
144
+ owner,
145
+ });
146
+ }
147
+ patch(_, owner) {
148
+ return new RelationUpdateOperation('patch', {
149
+ relation: this,
150
+ owner,
151
+ modelOptions: { patch: true },
152
+ });
153
+ }
154
+ delete(_, owner) {
155
+ return new RelationDeleteOperation('delete', {
156
+ relation: this,
157
+ owner,
158
+ });
159
+ }
160
+ relate() {
161
+ /* istanbul ignore next */
162
+ throw this.createError('not implemented');
163
+ }
164
+ unrelate() {
165
+ /* istanbul ignore next */
166
+ throw this.createError('not implemented');
167
+ }
168
+ hasRelateProp(model) {
169
+ return model.$hasProps(this.relatedProp.props);
170
+ }
171
+ setRelateProp(model, values) {
172
+ this.relatedProp.forEach((i) => {
173
+ this.relatedProp.setProp(model, i, values[i]);
174
+ });
175
+ }
176
+ executeBeforeInsert(models, queryContext, result) {
177
+ return mapAfterAllReturn(models, (model) => this.beforeInsert(model, queryContext), result);
178
+ }
179
+ createError(message) {
180
+ if (this.ownerModelClass && this.ownerModelClass.name && this.name) {
181
+ return new Error(`${this.ownerModelClass.name}.relationMappings.${this.name}: ${message}`);
182
+ }
183
+ else {
184
+ return new Error(`${this.constructor.name}: ${message}`);
185
+ }
186
+ }
236
187
  }
237
-
238
188
  Object.defineProperties(Relation, {
239
- isObjectionRelationClass: {
240
- enumerable: false,
241
- writable: false,
242
- value: true,
243
- },
189
+ isObjectionRelationClass: {
190
+ enumerable: false,
191
+ writable: false,
192
+ value: true,
193
+ },
244
194
  });
245
-
246
195
  Object.defineProperties(Relation.prototype, {
247
- isObjectionRelation: {
248
- enumerable: false,
249
- writable: false,
250
- value: true,
251
- },
196
+ isObjectionRelation: {
197
+ enumerable: false,
198
+ writable: false,
199
+ value: true,
200
+ },
252
201
  });
253
-
254
202
  function checkForbiddenProperties(ctx) {
255
- ctx.forbiddenMappingProperties.forEach((prop) => {
256
- if (get(ctx.mapping, prop.split('.')) !== undefined) {
257
- throw ctx.createError(`Property ${prop} is not supported for this relation type.`);
258
- }
259
- });
260
-
261
- return ctx;
203
+ ctx.forbiddenMappingProperties.forEach((prop) => {
204
+ if (get(ctx.mapping, prop.split('.')) !== undefined) {
205
+ throw ctx.createError(`Property ${prop} is not supported for this relation type.`);
206
+ }
207
+ });
208
+ return ctx;
262
209
  }
263
-
264
210
  function checkOwnerModelClass(ctx) {
265
- if (!isFunction(ctx.ownerModelClass) || !ctx.ownerModelClass.isObjectionModelClass) {
266
- throw ctx.createError(`Relation's owner is not a subclass of Model`);
267
- }
268
-
269
- return ctx;
211
+ if (!isFunction(ctx.ownerModelClass) || !ctx.ownerModelClass.isObjectionModelClass) {
212
+ throw ctx.createError(`Relation's owner is not a subclass of Model`);
213
+ }
214
+ return ctx;
270
215
  }
271
-
272
216
  function checkRelatedModelClass(ctx) {
273
- if (!ctx.mapping.modelClass) {
274
- throw ctx.createError('modelClass is not defined');
275
- }
276
-
277
- return ctx;
217
+ if (!ctx.mapping.modelClass) {
218
+ throw ctx.createError('modelClass is not defined');
219
+ }
220
+ return ctx;
278
221
  }
279
-
280
222
  function resolveRelatedModelClass(ctx) {
281
- let relatedModelClass;
282
-
283
- try {
284
- relatedModelClass = resolveModel(
285
- ctx.mapping.modelClass,
286
- ctx.ownerModelClass.modelPaths,
287
- 'modelClass',
288
- );
289
- } catch (err) {
290
- throw ctx.createError(err.message);
291
- }
292
-
293
- return Object.assign(ctx, { relatedModelClass });
223
+ let relatedModelClass;
224
+ try {
225
+ relatedModelClass = resolveModel(ctx.mapping.modelClass, ctx.ownerModelClass.modelPaths, 'modelClass');
226
+ }
227
+ catch (err) {
228
+ throw ctx.createError(err.message);
229
+ }
230
+ return Object.assign(ctx, { relatedModelClass });
294
231
  }
295
-
296
232
  function checkRelation(ctx) {
297
- if (!ctx.mapping.relation) {
298
- throw ctx.createError('relation is not defined');
299
- }
300
-
301
- if (!isFunction(ctx.mapping.relation) || !ctx.mapping.relation.isObjectionRelationClass) {
302
- throw ctx.createError('relation is not a subclass of Relation');
303
- }
304
-
305
- return ctx;
233
+ if (!ctx.mapping.relation) {
234
+ throw ctx.createError('relation is not defined');
235
+ }
236
+ if (!isFunction(ctx.mapping.relation) || !ctx.mapping.relation.isObjectionRelationClass) {
237
+ throw ctx.createError('relation is not a subclass of Relation');
238
+ }
239
+ return ctx;
306
240
  }
307
-
308
241
  function createJoinProperties(ctx) {
309
- const mapping = ctx.mapping;
310
-
311
- if (!mapping.join || !mapping.join.from || !mapping.join.to) {
312
- throw ctx.createError(
313
- 'join must be an object that maps the columns of the related models together. For example: {from: "SomeTable.id", to: "SomeOtherTable.someModelId"}',
314
- );
315
- }
316
-
317
- const fromProp = createRelationProperty(ctx, mapping.join.from, 'join.from');
318
- const toProp = createRelationProperty(ctx, mapping.join.to, 'join.to');
319
-
320
- let ownerProp;
321
- let relatedProp;
322
-
323
- if (fromProp.modelClass.getTableName() === ctx.ownerModelClass.getTableName()) {
324
- ownerProp = fromProp;
325
- relatedProp = toProp;
326
- } else if (toProp.modelClass.getTableName() === ctx.ownerModelClass.getTableName()) {
327
- ownerProp = toProp;
328
- relatedProp = fromProp;
329
- } else {
330
- throw ctx.createError('join: either `from` or `to` must point to the owner model table.');
331
- }
332
-
333
- if (ownerProp.props.some((it) => it === ctx.name)) {
334
- throw ctx.createError(
335
- `join: relation name and join property '${ctx.name}' cannot have the same name. If you cannot change one or the other, you can use $parseDatabaseJson and $formatDatabaseJson methods to convert the column name.`,
336
- );
337
- }
338
-
339
- if (relatedProp.modelClass.getTableName() !== ctx.relatedModelClass.getTableName()) {
340
- throw ctx.createError('join: either `from` or `to` must point to the related model table.');
341
- }
342
-
343
- return Object.assign(ctx, { ownerProp, relatedProp });
242
+ const mapping = ctx.mapping;
243
+ if (!mapping.join || !mapping.join.from || !mapping.join.to) {
244
+ throw ctx.createError('join must be an object that maps the columns of the related models together. For example: {from: "SomeTable.id", to: "SomeOtherTable.someModelId"}');
245
+ }
246
+ const fromProp = createRelationProperty(ctx, mapping.join.from, 'join.from');
247
+ const toProp = createRelationProperty(ctx, mapping.join.to, 'join.to');
248
+ let ownerProp;
249
+ let relatedProp;
250
+ if (fromProp.modelClass.getTableName() === ctx.ownerModelClass.getTableName()) {
251
+ ownerProp = fromProp;
252
+ relatedProp = toProp;
253
+ }
254
+ else if (toProp.modelClass.getTableName() === ctx.ownerModelClass.getTableName()) {
255
+ ownerProp = toProp;
256
+ relatedProp = fromProp;
257
+ }
258
+ else {
259
+ throw ctx.createError('join: either `from` or `to` must point to the owner model table.');
260
+ }
261
+ if (ownerProp.props.some((it) => it === ctx.name)) {
262
+ throw ctx.createError(`join: relation name and join property '${ctx.name}' cannot have the same name. If you cannot change one or the other, you can use $parseDatabaseJson and $formatDatabaseJson methods to convert the column name.`);
263
+ }
264
+ if (relatedProp.modelClass.getTableName() !== ctx.relatedModelClass.getTableName()) {
265
+ throw ctx.createError('join: either `from` or `to` must point to the related model table.');
266
+ }
267
+ return Object.assign(ctx, { ownerProp, relatedProp });
344
268
  }
345
-
346
269
  function createRelationProperty(ctx, refString, propName) {
347
- try {
348
- return new RelationProperty(refString, (table) => {
349
- return [ctx.ownerModelClass, ctx.relatedModelClass].find((it) => it.getTableName() === table);
350
- });
351
- } catch (err) {
352
- if (err instanceof RelationProperty.ModelNotFoundError) {
353
- throw ctx.createError(
354
- `join: either \`from\` or \`to\` must point to the owner model table and the other one to the related table. It might be that specified table '${err.tableName}' is not correct`,
355
- );
356
- } else if (err instanceof RelationProperty.InvalidReferenceError) {
357
- throw ctx.createError(
358
- `${propName} must have format TableName.columnName. For example "SomeTable.id" or in case of composite key ["SomeTable.a", "SomeTable.b"].`,
359
- );
360
- } else {
361
- throw err;
362
- }
363
- }
270
+ try {
271
+ return new RelationProperty(refString, (table) => {
272
+ return [ctx.ownerModelClass, ctx.relatedModelClass].find((it) => it.getTableName() === table);
273
+ });
274
+ }
275
+ catch (err) {
276
+ if (err instanceof RelationProperty.ModelNotFoundError) {
277
+ throw ctx.createError(`join: either \`from\` or \`to\` must point to the owner model table and the other one to the related table. It might be that specified table '${err.tableName}' is not correct`);
278
+ }
279
+ else if (err instanceof RelationProperty.InvalidReferenceError) {
280
+ throw ctx.createError(`${propName} must have format TableName.columnName. For example "SomeTable.id" or in case of composite key ["SomeTable.a", "SomeTable.b"].`);
281
+ }
282
+ else {
283
+ throw err;
284
+ }
285
+ }
364
286
  }
365
-
366
287
  function parseModify(ctx) {
367
- const mapping = ctx.mapping;
368
- const modifier = mapping.modify || mapping.filter;
369
- const modify =
370
- modifier &&
371
- createModifier({
372
- modifier,
373
- modelClass: ctx.relatedModelClass,
374
- });
375
-
376
- return Object.assign(ctx, { modify });
288
+ const mapping = ctx.mapping;
289
+ const modifier = mapping.modify || mapping.filter;
290
+ const modify = modifier &&
291
+ createModifier({
292
+ modifier,
293
+ modelClass: ctx.relatedModelClass,
294
+ });
295
+ return Object.assign(ctx, { modify });
377
296
  }
378
-
379
297
  function parseBeforeInsert(ctx) {
380
- let beforeInsert;
381
-
382
- if (isFunction(ctx.mapping.beforeInsert)) {
383
- beforeInsert = ctx.mapping.beforeInsert;
384
- } else {
385
- beforeInsert = (model) => model;
386
- }
387
-
388
- return Object.assign(ctx, { beforeInsert });
298
+ let beforeInsert;
299
+ if (isFunction(ctx.mapping.beforeInsert)) {
300
+ beforeInsert = ctx.mapping.beforeInsert;
301
+ }
302
+ else {
303
+ beforeInsert = (model) => model;
304
+ }
305
+ return Object.assign(ctx, { beforeInsert });
389
306
  }
390
-
391
307
  function aliasedTableName(tableName, alias) {
392
- if (tableName === alias) {
393
- return tableName;
394
- } else {
395
- return `${tableName} as ${alias}`;
396
- }
308
+ if (tableName === alias) {
309
+ return tableName;
310
+ }
311
+ else {
312
+ return `${tableName} as ${alias}`;
313
+ }
397
314
  }
398
-
399
315
  module.exports = {
400
- Relation,
316
+ Relation,
401
317
  };