@abedmurrar/objection 0.0.0-stage → 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 (190) hide show
  1. package/LICENSE +23 -0
  2. package/README.md +105 -2
  3. package/lib/index.mjs +6 -0
  4. package/lib/initialize.js +11 -0
  5. package/lib/model/AjvValidator.js +278 -0
  6. package/lib/model/Model.js +772 -0
  7. package/lib/model/ModifierNotFoundError.js +10 -0
  8. package/lib/model/NotFoundError.js +19 -0
  9. package/lib/model/RelationDoesNotExistError.js +11 -0
  10. package/lib/model/ValidationError.js +46 -0
  11. package/lib/model/Validator.js +20 -0
  12. package/lib/model/getModel.js +7 -0
  13. package/lib/model/graph/ModelGraph.js +60 -0
  14. package/lib/model/graph/ModelGraphBuilder.js +188 -0
  15. package/lib/model/graph/ModelGraphEdge.js +40 -0
  16. package/lib/model/graph/ModelGraphNode.js +201 -0
  17. package/lib/model/inheritModel.js +19 -0
  18. package/lib/model/modelBindKnex.js +69 -0
  19. package/lib/model/modelClone.js +102 -0
  20. package/lib/model/modelColPropMap.js +24 -0
  21. package/lib/model/modelConcurrency.js +24 -0
  22. package/lib/model/modelId.js +57 -0
  23. package/lib/model/modelJsonAttributes.js +72 -0
  24. package/lib/model/modelParseRelations.js +83 -0
  25. package/lib/model/modelQueryProps.js +116 -0
  26. package/lib/model/modelSet.js +116 -0
  27. package/lib/model/modelTableMetadata.js +71 -0
  28. package/lib/model/modelToJson.js +157 -0
  29. package/lib/model/modelUtils.js +40 -0
  30. package/lib/model/modelValidate.js +40 -0
  31. package/lib/model/modelValues.js +113 -0
  32. package/lib/model/modelVisitor.js +34 -0
  33. package/lib/objection.js +89 -0
  34. package/lib/queryBuilder/FunctionBuilder.js +291 -0
  35. package/lib/queryBuilder/InternalOptions.js +24 -0
  36. package/lib/queryBuilder/JoinBuilder.js +124 -0
  37. package/lib/queryBuilder/QueryBuilder.js +1136 -0
  38. package/lib/queryBuilder/QueryBuilderBase.js +666 -0
  39. package/lib/queryBuilder/QueryBuilderContext.js +20 -0
  40. package/lib/queryBuilder/QueryBuilderContextBase.js +26 -0
  41. package/lib/queryBuilder/QueryBuilderOperationSupport.js +484 -0
  42. package/lib/queryBuilder/QueryBuilderUserContext.js +25 -0
  43. package/lib/queryBuilder/RawBuilder.js +78 -0
  44. package/lib/queryBuilder/ReferenceBuilder.js +246 -0
  45. package/lib/queryBuilder/RelationExpression.js +373 -0
  46. package/lib/queryBuilder/StaticHookArguments.js +122 -0
  47. package/lib/queryBuilder/ValueBuilder.js +115 -0
  48. package/lib/queryBuilder/expressions.js +121 -0
  49. package/lib/queryBuilder/functions/mysql.js +762 -0
  50. package/lib/queryBuilder/graph/GraphAction.js +54 -0
  51. package/lib/queryBuilder/graph/GraphData.js +12 -0
  52. package/lib/queryBuilder/graph/GraphFetcher.js +155 -0
  53. package/lib/queryBuilder/graph/GraphNodeDbExistence.js +146 -0
  54. package/lib/queryBuilder/graph/GraphOperation.js +21 -0
  55. package/lib/queryBuilder/graph/GraphOptions.js +165 -0
  56. package/lib/queryBuilder/graph/GraphUpsert.js +231 -0
  57. package/lib/queryBuilder/graph/delete/GraphDelete.js +15 -0
  58. package/lib/queryBuilder/graph/delete/GraphDeleteAction.js +56 -0
  59. package/lib/queryBuilder/graph/insert/GraphInsert.js +116 -0
  60. package/lib/queryBuilder/graph/insert/GraphInsertAction.js +183 -0
  61. package/lib/queryBuilder/graph/insert/JoinRowGraphInsertAction.js +70 -0
  62. package/lib/queryBuilder/graph/patch/GraphPatch.js +15 -0
  63. package/lib/queryBuilder/graph/patch/GraphPatchAction.js +205 -0
  64. package/lib/queryBuilder/graph/recursiveUpsert/GraphRecursiveUpsert.js +26 -0
  65. package/lib/queryBuilder/graph/recursiveUpsert/GraphRecursiveUpsertAction.js +96 -0
  66. package/lib/queryBuilder/join/JoinResultColumn.js +19 -0
  67. package/lib/queryBuilder/join/JoinResultParser.js +106 -0
  68. package/lib/queryBuilder/join/RelationJoiner.js +258 -0
  69. package/lib/queryBuilder/join/TableNode.js +136 -0
  70. package/lib/queryBuilder/join/TableTree.js +69 -0
  71. package/lib/queryBuilder/join/utils.js +19 -0
  72. package/lib/queryBuilder/operations/DelegateOperation.js +101 -0
  73. package/lib/queryBuilder/operations/DeleteOperation.js +47 -0
  74. package/lib/queryBuilder/operations/FindByIdOperation.js +29 -0
  75. package/lib/queryBuilder/operations/FindByIdsOperation.js +23 -0
  76. package/lib/queryBuilder/operations/FindOperation.js +147 -0
  77. package/lib/queryBuilder/operations/FirstOperation.js +22 -0
  78. package/lib/queryBuilder/operations/FromOperation.js +91 -0
  79. package/lib/queryBuilder/operations/InsertAndFetchOperation.js +38 -0
  80. package/lib/queryBuilder/operations/InsertGraphAndFetchOperation.js +35 -0
  81. package/lib/queryBuilder/operations/InsertGraphOperation.js +87 -0
  82. package/lib/queryBuilder/operations/InsertOperation.js +173 -0
  83. package/lib/queryBuilder/operations/InstanceDeleteOperation.js +37 -0
  84. package/lib/queryBuilder/operations/InstanceFindOperation.js +17 -0
  85. package/lib/queryBuilder/operations/InstanceInsertOperation.js +20 -0
  86. package/lib/queryBuilder/operations/InstanceUpdateOperation.js +45 -0
  87. package/lib/queryBuilder/operations/JoinRelatedOperation.js +83 -0
  88. package/lib/queryBuilder/operations/KnexOperation.js +11 -0
  89. package/lib/queryBuilder/operations/MergeOperation.js +43 -0
  90. package/lib/queryBuilder/operations/ObjectionToKnexConvertingOperation.js +173 -0
  91. package/lib/queryBuilder/operations/OnBuildKnexOperation.js +23 -0
  92. package/lib/queryBuilder/operations/OnBuildOperation.js +23 -0
  93. package/lib/queryBuilder/operations/OnErrorOperation.js +23 -0
  94. package/lib/queryBuilder/operations/QueryBuilderOperation.js +258 -0
  95. package/lib/queryBuilder/operations/RangeOperation.js +37 -0
  96. package/lib/queryBuilder/operations/RelateOperation.js +20 -0
  97. package/lib/queryBuilder/operations/ReturningOperation.js +24 -0
  98. package/lib/queryBuilder/operations/RunAfterOperation.js +23 -0
  99. package/lib/queryBuilder/operations/RunBeforeOperation.js +23 -0
  100. package/lib/queryBuilder/operations/UnrelateOperation.js +18 -0
  101. package/lib/queryBuilder/operations/UpdateAndFetchOperation.js +63 -0
  102. package/lib/queryBuilder/operations/UpdateOperation.js +130 -0
  103. package/lib/queryBuilder/operations/UpsertGraphAndFetchOperation.js +35 -0
  104. package/lib/queryBuilder/operations/UpsertGraphOperation.js +47 -0
  105. package/lib/queryBuilder/operations/WhereCompositeOperation.js +48 -0
  106. package/lib/queryBuilder/operations/WhereInOperation.js +46 -0
  107. package/lib/queryBuilder/operations/eager/EagerOperation.js +46 -0
  108. package/lib/queryBuilder/operations/eager/JoinEagerOperation.js +41 -0
  109. package/lib/queryBuilder/operations/eager/NaiveEagerOperation.js +10 -0
  110. package/lib/queryBuilder/operations/eager/WhereInEagerOperation.js +227 -0
  111. package/lib/queryBuilder/operations/jsonApi/WhereJsonHasOperation.js +29 -0
  112. package/lib/queryBuilder/operations/jsonApi/WhereJsonNotObjectOperation.js +37 -0
  113. package/lib/queryBuilder/operations/jsonApi/WhereJsonOperation.js +30 -0
  114. package/lib/queryBuilder/operations/jsonApi/WhereJsonOverlapsOperation.js +33 -0
  115. package/lib/queryBuilder/operations/jsonApi/mysqlJsonApi.js +155 -0
  116. package/lib/queryBuilder/operations/jsonApi/postgresJsonApi.js +135 -0
  117. package/lib/queryBuilder/operations/select/SelectOperation.js +50 -0
  118. package/lib/queryBuilder/operations/select/Selection.js +112 -0
  119. package/lib/queryBuilder/operations/whereInComposite/WhereInCompositeMsSqlOperation.js +84 -0
  120. package/lib/queryBuilder/operations/whereInComposite/WhereInCompositeOperation.js +90 -0
  121. package/lib/queryBuilder/operations/whereInComposite/WhereInCompositeSqliteOperation.js +95 -0
  122. package/lib/queryBuilder/parsers/jsonFieldExpressionParser.js +787 -0
  123. package/lib/queryBuilder/parsers/relationExpressionParser.js +930 -0
  124. package/lib/queryBuilder/transformations/CompositeQueryTransformation.js +17 -0
  125. package/lib/queryBuilder/transformations/QueryTransformation.js +9 -0
  126. package/lib/queryBuilder/transformations/WrapMysqlModifySubqueryTransformation.js +57 -0
  127. package/lib/queryBuilder/transformations/index.js +9 -0
  128. package/lib/queryBuilder/whereScopes.js +199 -0
  129. package/lib/relations/Relation.js +317 -0
  130. package/lib/relations/RelationDeleteOperation.js +23 -0
  131. package/lib/relations/RelationFindOperation.js +116 -0
  132. package/lib/relations/RelationInsertOperation.js +25 -0
  133. package/lib/relations/RelationOwner.js +199 -0
  134. package/lib/relations/RelationProperty.js +207 -0
  135. package/lib/relations/RelationUpdateOperation.js +23 -0
  136. package/lib/relations/belongsToOne/BelongsToOneDeleteOperation.js +18 -0
  137. package/lib/relations/belongsToOne/BelongsToOneInsertOperation.js +33 -0
  138. package/lib/relations/belongsToOne/BelongsToOneRelateOperation.js +39 -0
  139. package/lib/relations/belongsToOne/BelongsToOneRelation.js +45 -0
  140. package/lib/relations/belongsToOne/BelongsToOneUnrelateOperation.js +46 -0
  141. package/lib/relations/hasMany/HasManyInsertOperation.js +45 -0
  142. package/lib/relations/hasMany/HasManyRelateOperation.js +48 -0
  143. package/lib/relations/hasMany/HasManyRelation.js +41 -0
  144. package/lib/relations/hasMany/HasManyUnrelateOperation.js +26 -0
  145. package/lib/relations/hasOne/HasOneRelation.js +10 -0
  146. package/lib/relations/hasOneThrough/HasOneThroughRelation.js +10 -0
  147. package/lib/relations/manyToMany/ManyToManyModifyMixin.js +82 -0
  148. package/lib/relations/manyToMany/ManyToManyRelation.js +405 -0
  149. package/lib/relations/manyToMany/ManyToManySqliteModifyMixin.js +29 -0
  150. package/lib/relations/manyToMany/delete/ManyToManyDeleteOperation.js +8 -0
  151. package/lib/relations/manyToMany/delete/ManyToManyDeleteOperationBase.js +20 -0
  152. package/lib/relations/manyToMany/delete/ManyToManyDeleteSqliteOperation.js +8 -0
  153. package/lib/relations/manyToMany/find/ManyToManyFindOperation.js +82 -0
  154. package/lib/relations/manyToMany/insert/ManyToManyInsertOperation.js +40 -0
  155. package/lib/relations/manyToMany/relate/ManyToManyRelateOperation.js +64 -0
  156. package/lib/relations/manyToMany/unrelate/ManyToManyUnrelateOperation.js +11 -0
  157. package/lib/relations/manyToMany/unrelate/ManyToManyUnrelateOperationBase.js +27 -0
  158. package/lib/relations/manyToMany/unrelate/ManyToManyUnrelateSqliteOperation.js +11 -0
  159. package/lib/relations/manyToMany/update/ManyToManyUpdateOperation.js +8 -0
  160. package/lib/relations/manyToMany/update/ManyToManyUpdateOperationBase.js +65 -0
  161. package/lib/relations/manyToMany/update/ManyToManyUpdateSqliteOperation.js +8 -0
  162. package/lib/transaction.js +66 -0
  163. package/lib/utils/assert.js +19 -0
  164. package/lib/utils/buildUtils.js +19 -0
  165. package/lib/utils/classUtils.js +9 -0
  166. package/lib/utils/cloneDeep.js +365 -0
  167. package/lib/utils/createModifier.js +37 -0
  168. package/lib/utils/deprecate.js +11 -0
  169. package/lib/utils/identifierMapping.js +188 -0
  170. package/lib/utils/internalPropUtils.js +7 -0
  171. package/lib/utils/knexUtils.js +81 -0
  172. package/lib/utils/mixin.js +18 -0
  173. package/lib/utils/mysqlJsonPath.js +70 -0
  174. package/lib/utils/normalizeIds.js +127 -0
  175. package/lib/utils/objectUtils.js +314 -0
  176. package/lib/utils/parseFieldExpression.js +73 -0
  177. package/lib/utils/postgresJsonPath.js +96 -0
  178. package/lib/utils/promiseUtils/after.js +14 -0
  179. package/lib/utils/promiseUtils/afterReturn.js +14 -0
  180. package/lib/utils/promiseUtils/index.js +15 -0
  181. package/lib/utils/promiseUtils/isPromise.js +8 -0
  182. package/lib/utils/promiseUtils/map.js +96 -0
  183. package/lib/utils/promiseUtils/mapAfterAllReturn.js +23 -0
  184. package/lib/utils/promiseUtils/try.js +19 -0
  185. package/lib/utils/resolveModel.js +104 -0
  186. package/lib/utils/tmpColumnUtils.js +7 -0
  187. package/package.json +113 -4
  188. package/typings/objection/index.d.mts +362 -0
  189. package/typings/objection/index.d.ts +4131 -0
  190. package/typings/objection/relation-expression.d.ts +237 -0
@@ -0,0 +1,405 @@
1
+ 'use strict';
2
+ const { withWhereScope } = require('../../queryBuilder/whereScopes');
3
+ const { getModel } = require('../../model/getModel');
4
+ const { Relation } = require('../Relation');
5
+ const { RelationProperty } = require('../RelationProperty');
6
+ const { isSqlite } = require('../../utils/knexUtils');
7
+ const { inheritModel } = require('../../model/inheritModel');
8
+ const { resolveModel } = require('../../utils/resolveModel');
9
+ const { mapAfterAllReturn } = require('../../utils/promiseUtils');
10
+ const { isFunction, isObject, isString } = require('../../utils/objectUtils');
11
+ const { createModifier } = require('../../utils/createModifier');
12
+ const { ManyToManyFindOperation } = require('./find/ManyToManyFindOperation');
13
+ const { ManyToManyInsertOperation } = require('./insert/ManyToManyInsertOperation');
14
+ const { ManyToManyRelateOperation } = require('./relate/ManyToManyRelateOperation');
15
+ const { ManyToManyUnrelateOperation } = require('./unrelate/ManyToManyUnrelateOperation');
16
+ const { ManyToManyUnrelateSqliteOperation, } = require('./unrelate/ManyToManyUnrelateSqliteOperation');
17
+ const { ManyToManyUpdateOperation } = require('./update/ManyToManyUpdateOperation');
18
+ const { ManyToManyUpdateSqliteOperation } = require('./update/ManyToManyUpdateSqliteOperation');
19
+ const { ManyToManyDeleteOperation } = require('./delete/ManyToManyDeleteOperation');
20
+ const { ManyToManyDeleteSqliteOperation } = require('./delete/ManyToManyDeleteSqliteOperation');
21
+ class ManyToManyRelation extends Relation {
22
+ setMapping(mapping) {
23
+ const retVal = super.setMapping(mapping);
24
+ let ctx = {
25
+ mapping,
26
+ ownerModelClass: this.ownerModelClass,
27
+ relatedModelClass: this.relatedModelClass,
28
+ ownerProp: this.ownerProp,
29
+ relatedProp: this.relatedProp,
30
+ joinTableModelClass: null,
31
+ joinTableOwnerProp: null,
32
+ joinTableRelatedProp: null,
33
+ joinTableBeforeInsert: null,
34
+ joinTableExtras: [],
35
+ createError: (msg) => this.createError(msg),
36
+ };
37
+ ctx = checkThroughObject(ctx);
38
+ ctx = resolveJoinModelClassIfDefined(ctx);
39
+ ctx = createJoinProperties(ctx);
40
+ ctx = parseExtras(ctx);
41
+ ctx = parseModify(ctx);
42
+ ctx = parseBeforeInsert(ctx);
43
+ ctx = finalizeJoinModelClass(ctx);
44
+ this.joinTableExtras = ctx.joinTableExtras;
45
+ this.joinTableModify = ctx.joinTableModify;
46
+ this.joinTableModelClass = ctx.joinTableModelClass;
47
+ this.joinTableOwnerProp = ctx.joinTableOwnerProp;
48
+ this.joinTableRelatedProp = ctx.joinTableRelatedProp;
49
+ this.joinTableBeforeInsert = ctx.joinTableBeforeInsert;
50
+ return retVal;
51
+ }
52
+ get forbiddenMappingProperties() {
53
+ return [];
54
+ }
55
+ findQuery(builder, owner) {
56
+ const joinTableOwnerRefs = this.joinTableOwnerProp.refs(builder);
57
+ const joinTable = builder.tableNameFor(this.joinTable);
58
+ const joinTableAlias = builder.tableRefFor(this.joinTable);
59
+ let joinTableSelect = this.joinTableModelClass
60
+ .query()
61
+ .childQueryOf(builder)
62
+ .modify(this.joinTableModify)
63
+ .as(joinTableAlias);
64
+ if (joinTableSelect.isSelectAll()) {
65
+ joinTableSelect = aliasedTableName(joinTable, joinTableAlias);
66
+ }
67
+ builder.join(joinTableSelect, (join) => {
68
+ this.relatedProp.forEach((i) => {
69
+ const relatedRef = this.relatedProp.ref(builder, i);
70
+ const joinTableRelatedRef = this.joinTableRelatedProp.ref(builder, i);
71
+ join.on(relatedRef, joinTableRelatedRef);
72
+ });
73
+ });
74
+ withWhereScope(builder, () => {
75
+ owner.buildFindQuery(builder, this, joinTableOwnerRefs);
76
+ });
77
+ return this.applyModify(builder);
78
+ }
79
+ join(builder, { joinOperation = defaultJoinOperation(this, builder), relatedTableAlias = defaultRelatedTableAlias(this, builder), relatedJoinSelectQuery = defaultRelatedJoinSelectQuery(this, builder), relatedTable = defaultRelatedTable(this, builder), ownerTable = defaultOwnerTable(this, builder), joinTableAlias = defaultJoinTableAlias(this, relatedTableAlias, builder), } = {}) {
80
+ let relatedJoinSelect = this.applyModify(relatedJoinSelectQuery).as(relatedTableAlias);
81
+ if (relatedJoinSelect.isSelectAll()) {
82
+ // No need to join a subquery if the query is `select * from "RelatedTable"`.
83
+ relatedJoinSelect = aliasedTableName(relatedTable, relatedTableAlias);
84
+ }
85
+ let joinTableSelect = this.joinTableModelClass
86
+ .query()
87
+ .childQueryOf(builder)
88
+ .modify(this.joinTableModify)
89
+ .as(joinTableAlias);
90
+ if (joinTableSelect.isSelectAll()) {
91
+ joinTableSelect = aliasedTableName(this.joinTable, joinTableAlias);
92
+ }
93
+ return builder[joinOperation](joinTableSelect, (join) => {
94
+ const ownerProp = this.ownerProp;
95
+ const joinTableOwnerProp = this.joinTableOwnerProp;
96
+ ownerProp.forEach((i) => {
97
+ const joinTableOwnerRef = joinTableOwnerProp.ref(builder, i).table(joinTableAlias);
98
+ const ownerRef = ownerProp.ref(builder, i).table(ownerTable);
99
+ join.on(joinTableOwnerRef, ownerRef);
100
+ });
101
+ })[joinOperation](relatedJoinSelect, (join) => {
102
+ const relatedProp = this.relatedProp;
103
+ const joinTableRelatedProp = this.joinTableRelatedProp;
104
+ relatedProp.forEach((i) => {
105
+ const joinTableRelatedRef = joinTableRelatedProp.ref(builder, i).table(joinTableAlias);
106
+ const relatedRef = relatedProp.ref(builder, i).table(relatedTableAlias);
107
+ join.on(joinTableRelatedRef, relatedRef);
108
+ });
109
+ });
110
+ }
111
+ find(_, owner) {
112
+ return new ManyToManyFindOperation('find', {
113
+ relation: this,
114
+ owner,
115
+ });
116
+ }
117
+ insert(_, owner) {
118
+ return new ManyToManyInsertOperation('insert', {
119
+ relation: this,
120
+ owner,
121
+ });
122
+ }
123
+ update(builder, owner) {
124
+ if (isSqlite(builder.knex())) {
125
+ return new ManyToManyUpdateSqliteOperation('update', {
126
+ relation: this,
127
+ owner,
128
+ });
129
+ }
130
+ else {
131
+ return new ManyToManyUpdateOperation('update', {
132
+ relation: this,
133
+ owner,
134
+ });
135
+ }
136
+ }
137
+ patch(builder, owner) {
138
+ if (isSqlite(builder.knex())) {
139
+ return new ManyToManyUpdateSqliteOperation('patch', {
140
+ modelOptions: { patch: true },
141
+ relation: this,
142
+ owner,
143
+ });
144
+ }
145
+ else {
146
+ return new ManyToManyUpdateOperation('patch', {
147
+ modelOptions: { patch: true },
148
+ relation: this,
149
+ owner,
150
+ });
151
+ }
152
+ }
153
+ delete(builder, owner) {
154
+ if (isSqlite(builder.knex())) {
155
+ return new ManyToManyDeleteSqliteOperation('delete', {
156
+ relation: this,
157
+ owner,
158
+ });
159
+ }
160
+ else {
161
+ return new ManyToManyDeleteOperation('delete', {
162
+ relation: this,
163
+ owner,
164
+ });
165
+ }
166
+ }
167
+ relate(builder, owner) {
168
+ return new ManyToManyRelateOperation('relate', {
169
+ relation: this,
170
+ owner,
171
+ });
172
+ }
173
+ unrelate(builder, owner) {
174
+ if (isSqlite(builder.knex())) {
175
+ return new ManyToManyUnrelateSqliteOperation('unrelate', {
176
+ relation: this,
177
+ owner,
178
+ });
179
+ }
180
+ else {
181
+ return new ManyToManyUnrelateOperation('unrelate', {
182
+ relation: this,
183
+ owner,
184
+ });
185
+ }
186
+ }
187
+ createJoinModels(ownerId, related) {
188
+ return related.map((related) => this.createJoinModel(ownerId, related));
189
+ }
190
+ createJoinModel(ownerId, rel) {
191
+ const joinModel = {};
192
+ for (let j = 0, lp = this.joinTableOwnerProp.size; j < lp; ++j) {
193
+ this.joinTableOwnerProp.setProp(joinModel, j, ownerId[j]);
194
+ }
195
+ for (let j = 0, lp = this.joinTableRelatedProp.size; j < lp; ++j) {
196
+ const value = this.relatedProp.getProp(rel, j);
197
+ if (value !== undefined) {
198
+ this.joinTableRelatedProp.setProp(joinModel, j, value);
199
+ }
200
+ }
201
+ for (const extra of this.joinTableExtras) {
202
+ let extraValue = rel[extra.aliasProp];
203
+ if (extraValue === undefined && rel.$$queryProps) {
204
+ extraValue = rel.$$queryProps[extra.aliasProp];
205
+ }
206
+ if (extraValue !== undefined) {
207
+ joinModel[extra.joinTableProp] = extraValue;
208
+ }
209
+ }
210
+ return joinModel;
211
+ }
212
+ omitExtraProps(models) {
213
+ if (this.joinTableExtras && this.joinTableExtras.length) {
214
+ const props = this.joinTableExtras.map((extra) => extra.aliasProp);
215
+ for (const model of models) {
216
+ // Omit extra properties instead of deleting them from the models so that they can
217
+ // be used in the `$before` and `$after` hooks.
218
+ model.$omitFromDatabaseJson(props);
219
+ }
220
+ }
221
+ }
222
+ executeJoinTableBeforeInsert(models, queryContext, result) {
223
+ return mapAfterAllReturn(models, (model) => this.joinTableBeforeInsert(model, queryContext), result);
224
+ }
225
+ }
226
+ Object.defineProperties(ManyToManyRelation.prototype, {
227
+ isObjectionManyToManyRelation: {
228
+ enumerable: false,
229
+ writable: false,
230
+ value: true,
231
+ },
232
+ });
233
+ function defaultJoinOperation() {
234
+ return 'join';
235
+ }
236
+ function defaultRelatedTableAlias(relation, builder) {
237
+ return builder.tableRefFor(relation.relatedModelClass);
238
+ }
239
+ function defaultRelatedJoinSelectQuery(relation, builder) {
240
+ return relation.relatedModelClass.query().childQueryOf(builder);
241
+ }
242
+ function defaultRelatedTable(relation, builder) {
243
+ return builder.tableNameFor(relation.relatedModelClass);
244
+ }
245
+ function defaultOwnerTable(relation, builder) {
246
+ return builder.tableRefFor(relation.ownerModelClass);
247
+ }
248
+ function defaultJoinTableAlias(relation, relatedTableAlias, builder) {
249
+ const alias = builder.tableRefFor(relation.joinTable);
250
+ if (alias === relation.joinTable) {
251
+ return relation.ownerModelClass.joinTableAlias(relatedTableAlias);
252
+ }
253
+ else {
254
+ return alias;
255
+ }
256
+ }
257
+ function aliasedTableName(tableName, alias) {
258
+ if (tableName === alias) {
259
+ return tableName;
260
+ }
261
+ else {
262
+ return `${tableName} as ${alias}`;
263
+ }
264
+ }
265
+ function checkThroughObject(ctx) {
266
+ const mapping = ctx.mapping;
267
+ if (!isObject(mapping.join.through)) {
268
+ throw ctx.createError('join must have a `through` object that describes the join table.');
269
+ }
270
+ if (!mapping.join.through.from || !mapping.join.through.to) {
271
+ throw ctx.createError('join.through must be an object that describes the join table. For example: {from: "JoinTable.someId", to: "JoinTable.someOtherId"}');
272
+ }
273
+ return ctx;
274
+ }
275
+ function resolveJoinModelClassIfDefined(ctx) {
276
+ let joinTableModelClass = null;
277
+ if (ctx.mapping.join.through.modelClass) {
278
+ try {
279
+ joinTableModelClass = resolveModel(ctx.mapping.join.through.modelClass, ctx.ownerModelClass.modelPaths, 'join.through.modelClass');
280
+ }
281
+ catch (err) {
282
+ throw ctx.createError(err.message);
283
+ }
284
+ }
285
+ return Object.assign(ctx, { joinTableModelClass });
286
+ }
287
+ function createJoinProperties(ctx) {
288
+ let ret;
289
+ let fromProp;
290
+ let toProp;
291
+ let relatedProp;
292
+ let ownerProp;
293
+ ret = createRelationProperty(ctx, ctx.mapping.join.through.from, 'join.through.from');
294
+ fromProp = ret.prop;
295
+ ctx = ret.ctx;
296
+ ret = createRelationProperty(ctx, ctx.mapping.join.through.to, 'join.through.to');
297
+ toProp = ret.prop;
298
+ ctx = ret.ctx;
299
+ if (fromProp.modelClass.getTableName() !== toProp.modelClass.getTableName()) {
300
+ throw ctx.createError('join.through `from` and `to` must point to the same join table.');
301
+ }
302
+ if (ctx.relatedProp.modelClass.getTableName() === fromProp.modelClass.getTableName()) {
303
+ relatedProp = fromProp;
304
+ ownerProp = toProp;
305
+ }
306
+ else {
307
+ relatedProp = toProp;
308
+ ownerProp = fromProp;
309
+ }
310
+ return Object.assign(ctx, {
311
+ joinTableOwnerProp: ownerProp,
312
+ joinTableRelatedProp: relatedProp,
313
+ });
314
+ }
315
+ function createRelationProperty(ctx, refString, messagePrefix) {
316
+ let prop = null;
317
+ let joinTableModelClass = ctx.joinTableModelClass;
318
+ const resolveModelClass = (table) => {
319
+ if (joinTableModelClass === null) {
320
+ joinTableModelClass = inheritModel(getModel());
321
+ joinTableModelClass.tableName = table;
322
+ joinTableModelClass.idColumn = null;
323
+ joinTableModelClass.concurrency = ctx.ownerModelClass.concurrency;
324
+ }
325
+ if (joinTableModelClass.getTableName() === table) {
326
+ return joinTableModelClass;
327
+ }
328
+ else {
329
+ return null;
330
+ }
331
+ };
332
+ try {
333
+ prop = new RelationProperty(refString, resolveModelClass);
334
+ }
335
+ catch (err) {
336
+ if (err instanceof RelationProperty.ModelNotFoundError) {
337
+ throw ctx.createError('join.through `from` and `to` must point to the same join table.');
338
+ }
339
+ else {
340
+ throw ctx.createError(`${messagePrefix} must have format JoinTable.columnName. For example "JoinTable.someId" or in case of composite key ["JoinTable.a", "JoinTable.b"].`);
341
+ }
342
+ }
343
+ return {
344
+ ctx: Object.assign(ctx, { joinTableModelClass }),
345
+ prop,
346
+ };
347
+ }
348
+ function parseExtras(ctx) {
349
+ let extraDef = ctx.mapping.join.through.extra;
350
+ if (!extraDef) {
351
+ return ctx;
352
+ }
353
+ if (isString(extraDef)) {
354
+ extraDef = {
355
+ [extraDef]: extraDef,
356
+ };
357
+ }
358
+ else if (Array.isArray(extraDef)) {
359
+ extraDef = extraDef.reduce((extraDef, col) => {
360
+ extraDef[col] = col;
361
+ return extraDef;
362
+ }, {});
363
+ }
364
+ const joinTableExtras = Object.keys(extraDef).map((key) => {
365
+ const val = extraDef[key];
366
+ return {
367
+ joinTableCol: val,
368
+ joinTableProp: ctx.joinTableModelClass.columnNameToPropertyName(val),
369
+ aliasCol: key,
370
+ aliasProp: ctx.joinTableModelClass.columnNameToPropertyName(key),
371
+ };
372
+ });
373
+ return Object.assign(ctx, { joinTableExtras });
374
+ }
375
+ function parseModify(ctx) {
376
+ const mapping = ctx.mapping.join.through;
377
+ const modifier = mapping.modify || mapping.filter;
378
+ const joinTableModify = modifier &&
379
+ createModifier({
380
+ modifier,
381
+ modelClass: ctx.relatedModelClass,
382
+ });
383
+ return Object.assign(ctx, { joinTableModify });
384
+ }
385
+ function parseBeforeInsert(ctx) {
386
+ let joinTableBeforeInsert;
387
+ if (isFunction(ctx.mapping.join.through.beforeInsert)) {
388
+ joinTableBeforeInsert = ctx.mapping.join.through.beforeInsert;
389
+ }
390
+ else {
391
+ joinTableBeforeInsert = (model) => model;
392
+ }
393
+ return Object.assign(ctx, { joinTableBeforeInsert });
394
+ }
395
+ function finalizeJoinModelClass(ctx) {
396
+ if (ctx.joinTableModelClass.getIdColumn() === null) {
397
+ // We cannot know if the join table has a primary key. Therefore we set some
398
+ // known column as the idColumn so that inserts will work.
399
+ ctx.joinTableModelClass.idColumn = ctx.joinTableRelatedProp.cols;
400
+ }
401
+ return ctx;
402
+ }
403
+ module.exports = {
404
+ ManyToManyRelation,
405
+ };
@@ -0,0 +1,29 @@
1
+ 'use strict';
2
+ const { ManyToManyModifyMixin } = require('./ManyToManyModifyMixin');
3
+ const SQLITE_BUILTIN_ROW_ID = '_rowid_';
4
+ // We need to override this mixin for sqlite because sqlite doesn't support
5
+ // multi-column where in statements with subqueries. We need to use the
6
+ // internal _rowid_ column instead.
7
+ const ManyToManySqliteModifyMixin = (Operation) => {
8
+ return class extends ManyToManyModifyMixin(Operation) {
9
+ applyModifyFilterForRelatedTable(builder) {
10
+ const tableRef = builder.tableRefFor(this.relation.relatedModelClass);
11
+ const rowIdRef = `${tableRef}.${SQLITE_BUILTIN_ROW_ID}`;
12
+ const subquery = this.modifyFilterSubquery.clone().select(rowIdRef);
13
+ return builder.whereInComposite(rowIdRef, subquery);
14
+ }
15
+ applyModifyFilterForJoinTable(builder) {
16
+ const joinTableOwnerRefs = this.relation.joinTableOwnerProp.refs(builder);
17
+ const tableRef = builder.tableRefFor(this.relation.getJoinModelClass(builder));
18
+ const rowIdRef = `${tableRef}.${SQLITE_BUILTIN_ROW_ID}`;
19
+ const ownerValues = this.owner.getProps(this.relation);
20
+ const subquery = this.modifyFilterSubquery.clone().select(rowIdRef);
21
+ return builder
22
+ .whereInComposite(rowIdRef, subquery)
23
+ .whereInComposite(joinTableOwnerRefs, ownerValues);
24
+ }
25
+ };
26
+ };
27
+ module.exports = {
28
+ ManyToManySqliteModifyMixin,
29
+ };
@@ -0,0 +1,8 @@
1
+ 'use strict';
2
+ const { ManyToManyDeleteOperationBase } = require('./ManyToManyDeleteOperationBase');
3
+ const { ManyToManyModifyMixin } = require('../ManyToManyModifyMixin');
4
+ class ManyToManyDeleteOperation extends ManyToManyModifyMixin(ManyToManyDeleteOperationBase) {
5
+ }
6
+ module.exports = {
7
+ ManyToManyDeleteOperation,
8
+ };
@@ -0,0 +1,20 @@
1
+ 'use strict';
2
+ const { DeleteOperation } = require('../../../queryBuilder/operations/DeleteOperation');
3
+ class ManyToManyDeleteOperationBase extends DeleteOperation {
4
+ constructor(name, opt) {
5
+ super(name, opt);
6
+ this.relation = opt.relation;
7
+ this.owner = opt.owner;
8
+ }
9
+ /* istanbul ignore next */
10
+ applyModifyFilterForRelatedTable(builder) {
11
+ throw new Error('not implemented');
12
+ }
13
+ /* istanbul ignore next */
14
+ applyModifyFilterForJoinTable(builder) {
15
+ throw new Error('not implemented');
16
+ }
17
+ }
18
+ module.exports = {
19
+ ManyToManyDeleteOperationBase,
20
+ };
@@ -0,0 +1,8 @@
1
+ 'use strict';
2
+ const { ManyToManyDeleteOperationBase } = require('./ManyToManyDeleteOperationBase');
3
+ const { ManyToManySqliteModifyMixin } = require('../ManyToManySqliteModifyMixin');
4
+ class ManyToManyDeleteSqliteOperation extends ManyToManySqliteModifyMixin(ManyToManyDeleteOperationBase) {
5
+ }
6
+ module.exports = {
7
+ ManyToManyDeleteSqliteOperation,
8
+ };
@@ -0,0 +1,82 @@
1
+ 'use strict';
2
+ const { RelationFindOperation } = require('../../RelationFindOperation');
3
+ const { getTempColumn } = require('../../../utils/tmpColumnUtils');
4
+ class ManyToManyFindOperation extends RelationFindOperation {
5
+ constructor(name, opt) {
6
+ super(name, opt);
7
+ this.ownerJoinColumnAlias = new Array(this.relation.joinTableOwnerProp.size);
8
+ for (let i = 0, l = this.ownerJoinColumnAlias.length; i < l; ++i) {
9
+ this.ownerJoinColumnAlias[i] = getTempColumn(i);
10
+ }
11
+ }
12
+ onBuild(builder) {
13
+ const relatedModelClass = this.relation.relatedModelClass;
14
+ this.maybeApplyAlias(builder);
15
+ this.relation.findQuery(builder, this.owner);
16
+ if (!builder.hasSelects()) {
17
+ const table = builder.tableRefFor(relatedModelClass);
18
+ // If the user hasn't specified a select clause, select the related model's columns.
19
+ // If we don't do this we also get the join table's columns.
20
+ builder.select(`${table}.*`);
21
+ // Also select all extra columns.
22
+ for (const extra of this.relation.joinTableExtras) {
23
+ const joinTable = builder.tableRefFor(this.relation.joinTable);
24
+ builder.select(`${joinTable}.${extra.joinTableCol} as ${extra.aliasCol}`);
25
+ }
26
+ }
27
+ if (this.assignResultToOwner && this.owner.isModels) {
28
+ this.selectMissingJoinColumns(builder);
29
+ }
30
+ }
31
+ onAfter2(_, related) {
32
+ const isOneToOne = this.relation.isOneToOne();
33
+ if (this.assignResultToOwner && this.owner.isModels) {
34
+ const owners = this.owner.modelArray;
35
+ const ownerProp = this.relation.ownerProp;
36
+ const relatedByOwnerId = new Map();
37
+ for (let i = 0, l = related.length; i < l; ++i) {
38
+ const rel = related[i];
39
+ const key = rel.$propKey(this.ownerJoinColumnAlias);
40
+ let arr = relatedByOwnerId.get(key);
41
+ if (!arr) {
42
+ arr = [];
43
+ relatedByOwnerId.set(key, arr);
44
+ }
45
+ arr.push(rel);
46
+ }
47
+ for (let i = 0, l = owners.length; i < l; ++i) {
48
+ const own = owners[i];
49
+ const key = ownerProp.propKey(own);
50
+ const related = relatedByOwnerId.get(key);
51
+ if (isOneToOne) {
52
+ own[this.relationProperty] = (related && related[0]) || null;
53
+ }
54
+ else {
55
+ own[this.relationProperty] = related || [];
56
+ }
57
+ }
58
+ }
59
+ return related;
60
+ }
61
+ clone() {
62
+ const clone = super.clone();
63
+ clone.ownerJoinColumnAlias = this.ownerJoinColumnAlias.slice();
64
+ return clone;
65
+ }
66
+ selectMissingJoinColumns(builder) {
67
+ const { relatedModelClass, joinTableOwnerProp } = this.relation;
68
+ // We must select the owner join columns so that we know for which owner model the related
69
+ // models belong to after the requests.
70
+ joinTableOwnerProp.forEach((i) => {
71
+ const joinTableOwnerRef = joinTableOwnerProp.ref(builder, i);
72
+ const propName = relatedModelClass.columnNameToPropertyName(this.ownerJoinColumnAlias[i]);
73
+ builder.select(joinTableOwnerRef.as(this.ownerJoinColumnAlias[i]));
74
+ // Mark them to be omitted later.
75
+ this.omitProps.push(propName);
76
+ });
77
+ super.selectMissingJoinColumns(builder);
78
+ }
79
+ }
80
+ module.exports = {
81
+ ManyToManyFindOperation,
82
+ };
@@ -0,0 +1,40 @@
1
+ 'use strict';
2
+ const { RelationInsertOperation } = require('../../RelationInsertOperation');
3
+ const { ManyToManyRelateOperation } = require('../relate/ManyToManyRelateOperation');
4
+ class ManyToManyInsertOperation extends RelationInsertOperation {
5
+ onAdd(builder, args) {
6
+ const retVal = super.onAdd(builder, args);
7
+ // Omit extra properties so that we don't try to insert
8
+ // them to the related table. We don't actually remove them
9
+ // from the objects, but simply mark them to be removed
10
+ // from the inserted row.
11
+ this.relation.omitExtraProps(this.models);
12
+ return retVal;
13
+ }
14
+ async onAfter1(builder, ret) {
15
+ const inserted = await super.onAfter1(builder, ret);
16
+ const relateOp = new ManyToManyRelateOperation('relate', {
17
+ dontCopyReturning: true,
18
+ dontCopyOnConflict: true,
19
+ relation: this.relation,
20
+ owner: this.owner,
21
+ });
22
+ const modelsToRelate = inserted.filter((it) => {
23
+ return this.relation.relatedProp.hasProps(it);
24
+ });
25
+ if (this.assignResultToOwner && this.owner.isModels) {
26
+ for (const owner of this.owner.modelArray) {
27
+ owner.$appendRelated(this.relation, inserted);
28
+ }
29
+ }
30
+ if (modelsToRelate.length === 0) {
31
+ return inserted;
32
+ }
33
+ relateOp.onAdd(builder, [modelsToRelate]);
34
+ await relateOp.queryExecutor(builder);
35
+ return inserted;
36
+ }
37
+ }
38
+ module.exports = {
39
+ ManyToManyInsertOperation,
40
+ };
@@ -0,0 +1,64 @@
1
+ 'use strict';
2
+ const { isPostgres } = require('../../../utils/knexUtils');
3
+ const { normalizeIds } = require('../../../utils/normalizeIds');
4
+ const { RelateOperation } = require('../../../queryBuilder/operations/RelateOperation');
5
+ class ManyToManyRelateOperation extends RelateOperation {
6
+ onAdd(builder, args) {
7
+ this.input = args[0];
8
+ this.ids = normalizeIds(args[0], this.relation.relatedProp);
9
+ assertOwnerIsSingleItem(builder, this.owner, this.relation);
10
+ return true;
11
+ }
12
+ queryExecutor(builder) {
13
+ const joinModelClass = this.relation.getJoinModelClass(builder.knex());
14
+ const ownerValues = this.owner.getSplitProps(builder, this.relation);
15
+ const joinModels = [];
16
+ for (const ownerValue of ownerValues) {
17
+ for (const relatedValue of this.ids) {
18
+ joinModels.push(joinModelClass.fromJson(this.relation.createJoinModel(ownerValue, relatedValue)));
19
+ }
20
+ }
21
+ return joinModelClass
22
+ .query()
23
+ .childQueryOf(builder)
24
+ .modify((query) => {
25
+ if (!this.opt.dontCopyReturning) {
26
+ query.copyFrom(builder, /returning/);
27
+ }
28
+ if (!this.opt.dontCopyOnConflict) {
29
+ query.copyFrom(builder, /onConflict|ignore|merge/);
30
+ }
31
+ })
32
+ .runBefore((_, builder) => {
33
+ return this.relation.executeJoinTableBeforeInsert(joinModels, builder.context(), null);
34
+ })
35
+ .insert(joinModels)
36
+ .runAfter((models) => {
37
+ return Array.isArray(models) ? models.length : 1;
38
+ });
39
+ }
40
+ }
41
+ function assertOwnerIsSingleItem(builder, owner, relation) {
42
+ const { isModels, isIdentifiers, isQueryBuilder } = owner;
43
+ const { ownerProp } = relation;
44
+ const singleModel = isModels && owner.modelArray.length === 1;
45
+ const singleId = isIdentifiers && owner.getNormalizedIdentifiers(ownerProp).length === 1;
46
+ if (isPostgres(builder.unsafeKnex())) {
47
+ if (!isModels && !isIdentifiers && !isQueryBuilder) {
48
+ throw new Error('Parent must be a list of identifiers or a list of models when relating a ManyToManyRelation');
49
+ }
50
+ }
51
+ else {
52
+ if (!singleModel && !singleId && !isQueryBuilder) {
53
+ throw new Error([
54
+ 'Can only relate items for one parent at a time in case of ManyToManyRelation.',
55
+ 'Otherwise multiple insert queries would need to be created.',
56
+ 'If you need to relate items for multiple parents, simply loop through them.',
57
+ `That's the most performant way.`,
58
+ ].join(' '));
59
+ }
60
+ }
61
+ }
62
+ module.exports = {
63
+ ManyToManyRelateOperation,
64
+ };
@@ -0,0 +1,11 @@
1
+ 'use strict';
2
+ const { ManyToManyUnrelateOperationBase } = require('./ManyToManyUnrelateOperationBase');
3
+ const { ManyToManyModifyMixin } = require('../ManyToManyModifyMixin');
4
+ class ManyToManyUnrelateOperation extends ManyToManyModifyMixin(ManyToManyUnrelateOperationBase) {
5
+ get modifyMainQuery() {
6
+ return false;
7
+ }
8
+ }
9
+ module.exports = {
10
+ ManyToManyUnrelateOperation,
11
+ };