objection 3.9.1 → 4.0.0-rc.2

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 (250) hide show
  1. package/lib/dbErrors/LICENSE +21 -0
  2. package/lib/dbErrors/errorCodes/mssql.js +19 -0
  3. package/lib/dbErrors/errorCodes/mysql.js +805 -0
  4. package/lib/dbErrors/errorCodes/postgres.js +241 -0
  5. package/lib/dbErrors/errors/CheckViolationError.js +10 -0
  6. package/lib/dbErrors/errors/ConstraintViolationError.js +3 -0
  7. package/lib/dbErrors/errors/DBError.js +9 -0
  8. package/lib/dbErrors/errors/DataError.js +3 -0
  9. package/lib/dbErrors/errors/ForeignKeyViolationError.js +11 -0
  10. package/lib/dbErrors/errors/NotNullViolationError.js +12 -0
  11. package/lib/dbErrors/errors/UniqueViolationError.js +12 -0
  12. package/lib/dbErrors/index.js +59 -0
  13. package/lib/dbErrors/parsers/mssql/DBError/CheckViolationError/parser.js +28 -0
  14. package/lib/dbErrors/parsers/mssql/DBError/DataError/parser.js +25 -0
  15. package/lib/dbErrors/parsers/mssql/DBError/ForeignKeyViolationError/parser.js +39 -0
  16. package/lib/dbErrors/parsers/mssql/DBError/NotNullViolationError/parser.js +30 -0
  17. package/lib/dbErrors/parsers/mssql/DBError/UniqueViolationError/parser.js +53 -0
  18. package/lib/dbErrors/parsers/mssql/DBError/parser.js +51 -0
  19. package/lib/dbErrors/parsers/mssql/DBError/util.js +16 -0
  20. package/lib/dbErrors/parsers/mysql/DBError/ConstraintViolationError/ForeignKeyViolationError/parser.js +43 -0
  21. package/lib/dbErrors/parsers/mysql/DBError/ConstraintViolationError/NotNullViolationError/parser.js +29 -0
  22. package/lib/dbErrors/parsers/mysql/DBError/ConstraintViolationError/UniqueViolationError/parser.js +27 -0
  23. package/lib/dbErrors/parsers/mysql/DBError/ConstraintViolationError/parser.js +23 -0
  24. package/lib/dbErrors/parsers/mysql/DBError/DataError/parser.js +24 -0
  25. package/lib/dbErrors/parsers/mysql/DBError/parser.js +28 -0
  26. package/lib/dbErrors/parsers/postgres/DBError/ConstraintViolationError/CheckViolationError/parser.js +18 -0
  27. package/lib/dbErrors/parsers/postgres/DBError/ConstraintViolationError/ForeignKeyViolationError/parser.js +18 -0
  28. package/lib/dbErrors/parsers/postgres/DBError/ConstraintViolationError/NotNullViolationError/parser.js +18 -0
  29. package/lib/dbErrors/parsers/postgres/DBError/ConstraintViolationError/UniqueViolationError/parser.js +40 -0
  30. package/lib/dbErrors/parsers/postgres/DBError/ConstraintViolationError/parser.js +25 -0
  31. package/lib/dbErrors/parsers/postgres/DBError/DataError/parser.js +16 -0
  32. package/lib/dbErrors/parsers/postgres/DBError/parser.js +27 -0
  33. package/lib/dbErrors/parsers/sqlite/DBError/ConstraintViolationError/CheckViolationError/parser.js +20 -0
  34. package/lib/dbErrors/parsers/sqlite/DBError/ConstraintViolationError/ForeignKeyViolationError/parser.js +20 -0
  35. package/lib/dbErrors/parsers/sqlite/DBError/ConstraintViolationError/NotNullViolationError/parser.js +27 -0
  36. package/lib/dbErrors/parsers/sqlite/DBError/ConstraintViolationError/UniqueViolationError/parser.js +28 -0
  37. package/lib/dbErrors/parsers/sqlite/DBError/ConstraintViolationError/parser.js +24 -0
  38. package/lib/dbErrors/parsers/sqlite/DBError/parser.js +23 -0
  39. package/lib/dbErrors/utils/sqlState.js +3 -0
  40. package/lib/initialize.js +1 -7
  41. package/lib/model/AjvValidator.js +51 -117
  42. package/lib/model/Model.js +84 -59
  43. package/lib/model/ModifierNotFoundError.js +1 -7
  44. package/lib/model/NotFoundError.js +1 -7
  45. package/lib/model/RelationDoesNotExistError.js +1 -7
  46. package/lib/model/ValidationError.js +3 -10
  47. package/lib/model/Validator.js +1 -7
  48. package/lib/model/getModel.js +7 -6
  49. package/lib/model/inheritModel.js +1 -7
  50. package/lib/model/modelBindKnex.js +4 -10
  51. package/lib/model/modelClone.js +5 -11
  52. package/lib/model/modelColPropMap.js +3 -10
  53. package/lib/model/modelId.js +3 -10
  54. package/lib/model/modelJsonAttributes.js +35 -16
  55. package/lib/model/modelParseRelations.js +2 -8
  56. package/lib/model/modelQueryProps.js +11 -23
  57. package/lib/model/modelSet.js +89 -41
  58. package/lib/model/modelTableMetadata.js +4 -11
  59. package/lib/model/modelToJson.js +6 -13
  60. package/lib/model/modelUtils.js +14 -13
  61. package/lib/model/modelValidate.js +3 -9
  62. package/lib/model/modelValues.js +5 -14
  63. package/lib/model/modelVisitor.js +1 -7
  64. package/lib/objection.js +33 -71
  65. package/lib/queryBuilder/FunctionBuilder.js +4 -11
  66. package/lib/queryBuilder/InternalOptions.js +4 -9
  67. package/lib/queryBuilder/JoinBuilder.js +5 -8
  68. package/lib/queryBuilder/QueryBuilder.js +126 -95
  69. package/lib/queryBuilder/QueryBuilderBase.js +41 -123
  70. package/lib/queryBuilder/QueryBuilderContext.js +2 -8
  71. package/lib/queryBuilder/QueryBuilderContextBase.js +2 -8
  72. package/lib/queryBuilder/QueryBuilderOperationSupport.js +7 -21
  73. package/lib/queryBuilder/QueryBuilderUserContext.js +1 -7
  74. package/lib/queryBuilder/RawBuilder.js +5 -13
  75. package/lib/queryBuilder/ReferenceBuilder.js +20 -48
  76. package/lib/queryBuilder/RelationExpression.js +18 -16
  77. package/lib/queryBuilder/StaticHookArguments.js +74 -16
  78. package/lib/queryBuilder/ValueBuilder.js +11 -13
  79. package/lib/queryBuilder/getJoinBuilder.js +10 -0
  80. package/lib/queryBuilder/graph/GraphLoader.js +314 -0
  81. package/lib/queryBuilder/graph/GraphNode.js +241 -0
  82. package/lib/queryBuilder/graph/GraphOptions.js +55 -248
  83. package/lib/queryBuilder/graph/GraphPlan.js +431 -0
  84. package/lib/queryBuilder/graph/GraphSchedule.js +513 -0
  85. package/lib/queryBuilder/graph/GraphUpsert.js +519 -412
  86. package/lib/queryBuilder/graph/GraphWriter.js +508 -0
  87. package/lib/queryBuilder/graph/graphKeys.js +929 -0
  88. package/lib/queryBuilder/join/JoinResultColumn.js +1 -7
  89. package/lib/queryBuilder/join/JoinResultParser.js +6 -11
  90. package/lib/queryBuilder/join/RelationJoiner.js +66 -84
  91. package/lib/queryBuilder/join/TableNode.js +2 -8
  92. package/lib/queryBuilder/join/TableTree.js +3 -9
  93. package/lib/queryBuilder/join/utils.js +5 -15
  94. package/lib/queryBuilder/jsonDialects/JsonDialect.js +51 -0
  95. package/lib/queryBuilder/jsonDialects/MySqlJsonDialect.js +81 -0
  96. package/lib/queryBuilder/jsonDialects/PostgresJsonDialect.js +45 -0
  97. package/lib/queryBuilder/jsonDialects/SqliteJsonDialect.js +67 -0
  98. package/lib/queryBuilder/jsonDialects/index.js +44 -0
  99. package/lib/queryBuilder/operations/DelegateOperation.js +2 -8
  100. package/lib/queryBuilder/operations/DeleteOperation.js +10 -39
  101. package/lib/queryBuilder/operations/FindByIdOperation.js +7 -12
  102. package/lib/queryBuilder/operations/FindByIdsOperation.js +4 -8
  103. package/lib/queryBuilder/operations/FindOperation.js +14 -34
  104. package/lib/queryBuilder/operations/FirstOperation.js +6 -10
  105. package/lib/queryBuilder/operations/FromOperation.js +3 -9
  106. package/lib/queryBuilder/operations/InsertAndFetchOperation.js +13 -12
  107. package/lib/queryBuilder/operations/InsertGraphAndFetchOperation.js +4 -10
  108. package/lib/queryBuilder/operations/InsertGraphOperation.js +7 -18
  109. package/lib/queryBuilder/operations/InsertOperation.js +118 -45
  110. package/lib/queryBuilder/operations/InstanceDeleteOperation.js +5 -12
  111. package/lib/queryBuilder/operations/InstanceFindOperation.js +4 -11
  112. package/lib/queryBuilder/operations/InstanceInsertOperation.js +2 -8
  113. package/lib/queryBuilder/operations/InstanceUpdateOperation.js +7 -14
  114. package/lib/queryBuilder/operations/JoinRelatedOperation.js +5 -11
  115. package/lib/queryBuilder/operations/KnexOperation.js +2 -8
  116. package/lib/queryBuilder/operations/LimitPerParentOperation.js +7 -69
  117. package/lib/queryBuilder/operations/MergeOperation.js +5 -11
  118. package/lib/queryBuilder/operations/NoneOperation.js +2 -8
  119. package/lib/queryBuilder/operations/ObjectionToKnexConvertingOperation.js +20 -49
  120. package/lib/queryBuilder/operations/OnBuildKnexOperation.js +2 -8
  121. package/lib/queryBuilder/operations/OnBuildOperation.js +2 -8
  122. package/lib/queryBuilder/operations/OnErrorOperation.js +2 -8
  123. package/lib/queryBuilder/operations/QueryBuilderOperation.js +1 -7
  124. package/lib/queryBuilder/operations/RangeOperation.js +11 -26
  125. package/lib/queryBuilder/operations/RelateOperation.js +2 -8
  126. package/lib/queryBuilder/operations/ReturningOperation.js +3 -9
  127. package/lib/queryBuilder/operations/RunAfterOperation.js +2 -12
  128. package/lib/queryBuilder/operations/RunBeforeOperation.js +2 -8
  129. package/lib/queryBuilder/operations/UnrelateOperation.js +2 -8
  130. package/lib/queryBuilder/operations/UpdateAndFetchOperation.js +14 -17
  131. package/lib/queryBuilder/operations/UpdateOperation.js +32 -132
  132. package/lib/queryBuilder/operations/UpsertGraphAndFetchOperation.js +8 -11
  133. package/lib/queryBuilder/operations/UpsertGraphOperation.js +6 -12
  134. package/lib/queryBuilder/operations/WhereCompositeOperation.js +3 -9
  135. package/lib/queryBuilder/operations/WhereGroupOperation.js +2 -8
  136. package/lib/queryBuilder/operations/eager/EagerOperation.js +3 -9
  137. package/lib/queryBuilder/operations/eager/JoinEagerOperation.js +72 -10
  138. package/lib/queryBuilder/operations/eager/NaiveEagerOperation.js +2 -8
  139. package/lib/queryBuilder/operations/eager/WhereInEagerOperation.js +23 -44
  140. package/lib/queryBuilder/operations/fieldExpressions.js +122 -0
  141. package/lib/queryBuilder/operations/jsonApi/WhereJsonHasOperation.js +20 -0
  142. package/lib/queryBuilder/operations/jsonApi/WhereJsonOperation.js +44 -0
  143. package/lib/queryBuilder/operations/jsonApi/WhereJsonTypeOperation.js +14 -0
  144. package/lib/queryBuilder/operations/select/SelectOperation.js +11 -21
  145. package/lib/queryBuilder/operations/select/Selection.js +19 -17
  146. package/lib/queryBuilder/operations/whereInComposite/WhereInCompositeMsSqlOperation.js +4 -10
  147. package/lib/queryBuilder/operations/whereInComposite/WhereInCompositeOperation.js +4 -10
  148. package/lib/queryBuilder/operations/whereInComposite/WhereInCompositeSqliteOperation.js +4 -10
  149. package/lib/queryBuilder/operations/windowOrder.js +56 -0
  150. package/lib/queryBuilder/parsers/jsonFieldExpressionParser.js +3 -7
  151. package/lib/queryBuilder/parsers/relationExpressionParser.js +42 -43
  152. package/lib/queryBuilder/parsers/relationExpressionParser.pegjs +39 -36
  153. package/lib/queryBuilder/transformations/CompositeQueryTransformation.js +2 -8
  154. package/lib/queryBuilder/transformations/QueryTransformation.js +1 -7
  155. package/lib/queryBuilder/transformations/WrapMysqlModifySubqueryTransformation.js +3 -9
  156. package/lib/queryBuilder/transformations/index.js +3 -11
  157. package/lib/queryBuilder/whereGroups.js +9 -24
  158. package/lib/queryBuilder/withoutOrder.js +4 -11
  159. package/lib/relations/Relation.js +47 -28
  160. package/lib/relations/RelationDeleteOperation.js +4 -14
  161. package/lib/relations/RelationFindOperation.js +119 -90
  162. package/lib/relations/RelationInsertOperation.js +2 -8
  163. package/lib/relations/RelationOwner.js +5 -11
  164. package/lib/relations/RelationProperty.js +4 -10
  165. package/lib/relations/RelationUpdateOperation.js +4 -14
  166. package/lib/relations/RelationWriteResultOperation.js +15 -0
  167. package/lib/relations/belongsToMany/BelongsToManyDeleteOperation.js +23 -0
  168. package/lib/relations/belongsToMany/BelongsToManyFindOperation.js +35 -0
  169. package/lib/relations/belongsToMany/BelongsToManyInsertOperation.js +28 -0
  170. package/lib/relations/belongsToMany/BelongsToManyRelateOperation.js +16 -0
  171. package/lib/relations/belongsToMany/BelongsToManyRelation.js +276 -0
  172. package/lib/relations/belongsToMany/BelongsToManyUnrelateOperation.js +11 -0
  173. package/lib/relations/belongsToOne/BelongsToOneDeleteOperation.js +2 -8
  174. package/lib/relations/belongsToOne/BelongsToOneInsertOperation.js +6 -11
  175. package/lib/relations/belongsToOne/BelongsToOneRelateOperation.js +3 -9
  176. package/lib/relations/belongsToOne/BelongsToOneRelation.js +8 -19
  177. package/lib/relations/belongsToOne/BelongsToOneUnrelateOperation.js +53 -27
  178. package/lib/relations/hasMany/HasManyInsertOperation.js +5 -10
  179. package/lib/relations/hasMany/HasManyRelateOperation.js +5 -11
  180. package/lib/relations/hasMany/HasManyRelation.js +9 -11
  181. package/lib/relations/hasMany/HasManyUnrelateOperation.js +3 -9
  182. package/lib/relations/hasOne/HasOneRelation.js +2 -8
  183. package/lib/relations/hasOneThrough/HasOneThroughRelation.js +2 -8
  184. package/lib/relations/manyToMany/ManyToManyModifyMixin.js +10 -15
  185. package/lib/relations/manyToMany/ManyToManyMySqlModifyMixin.js +2 -8
  186. package/lib/relations/manyToMany/ManyToManyRelation.js +82 -50
  187. package/lib/relations/manyToMany/ManyToManySqliteModifyMixin.js +2 -8
  188. package/lib/relations/manyToMany/delete/ManyToManyDeleteOperation.js +5 -9
  189. package/lib/relations/manyToMany/delete/ManyToManyDeleteOperationBase.js +2 -8
  190. package/lib/relations/manyToMany/delete/ManyToManyDeleteSqliteOperation.js +3 -9
  191. package/lib/relations/manyToMany/find/ManyToManyFindOperation.js +20 -59
  192. package/lib/relations/manyToMany/insert/ManyToManyInsertOperation.js +6 -11
  193. package/lib/relations/manyToMany/relate/ManyToManyRelateOperation.js +4 -10
  194. package/lib/relations/manyToMany/unrelate/ManyToManyUnrelateMySqlOperation.js +3 -9
  195. package/lib/relations/manyToMany/unrelate/ManyToManyUnrelateOperation.js +5 -9
  196. package/lib/relations/manyToMany/unrelate/ManyToManyUnrelateOperationBase.js +3 -9
  197. package/lib/relations/manyToMany/unrelate/ManyToManyUnrelateSqliteOperation.js +3 -9
  198. package/lib/relations/manyToMany/update/ManyToManyUpdateMySqlOperation.js +3 -9
  199. package/lib/relations/manyToMany/update/ManyToManyUpdateOperation.js +5 -9
  200. package/lib/relations/manyToMany/update/ManyToManyUpdateOperationBase.js +64 -72
  201. package/lib/relations/manyToMany/update/ManyToManyUpdateSqliteOperation.js +3 -9
  202. package/lib/transaction.js +3 -9
  203. package/lib/utils/assert.js +3 -11
  204. package/lib/utils/buildUtils.js +2 -8
  205. package/lib/utils/classUtils.js +1 -7
  206. package/lib/utils/createModifier.js +2 -8
  207. package/lib/utils/identifierMapping.js +23 -27
  208. package/lib/utils/internalPropUtils.js +1 -7
  209. package/lib/utils/knexUtils.js +84 -40
  210. package/lib/utils/mixin.js +3 -10
  211. package/lib/utils/normalizeIds.js +2 -8
  212. package/lib/utils/objectUtils.js +41 -60
  213. package/lib/utils/parseFieldExpression.js +16 -16
  214. package/lib/utils/promiseUtils/after.js +2 -8
  215. package/lib/utils/promiseUtils/afterReturn.js +2 -8
  216. package/lib/utils/promiseUtils/index.js +7 -16
  217. package/lib/utils/promiseUtils/isPromise.js +2 -8
  218. package/lib/utils/promiseUtils/map.js +2 -8
  219. package/lib/utils/promiseUtils/mapAfterAllReturn.js +2 -8
  220. package/lib/utils/promiseUtils/try.js +2 -8
  221. package/lib/utils/resolveModel.js +10 -17
  222. package/lib/utils/tmpColumnUtils.js +2 -9
  223. package/lib/utils/warnings.js +2 -14
  224. package/package.json +25 -17
  225. package/typings/objection/index.d.ts +3217 -2179
  226. package/lib/.eslintrc.json +0 -8
  227. package/lib/model/graph/ModelGraph.js +0 -80
  228. package/lib/model/graph/ModelGraphBuilder.js +0 -241
  229. package/lib/model/graph/ModelGraphEdge.js +0 -52
  230. package/lib/model/graph/ModelGraphNode.js +0 -238
  231. package/lib/queryBuilder/graph/GraphAction.js +0 -69
  232. package/lib/queryBuilder/graph/GraphData.js +0 -53
  233. package/lib/queryBuilder/graph/GraphFetcher.js +0 -197
  234. package/lib/queryBuilder/graph/GraphNodeDbExistence.js +0 -184
  235. package/lib/queryBuilder/graph/GraphOperation.js +0 -27
  236. package/lib/queryBuilder/graph/delete/GraphDelete.js +0 -73
  237. package/lib/queryBuilder/graph/delete/GraphDeleteAction.js +0 -88
  238. package/lib/queryBuilder/graph/insert/DeferredRelationGraphInsertAction.js +0 -58
  239. package/lib/queryBuilder/graph/insert/GraphInsert.js +0 -296
  240. package/lib/queryBuilder/graph/insert/GraphInsertAction.js +0 -233
  241. package/lib/queryBuilder/graph/insert/JoinRowGraphInsertAction.js +0 -92
  242. package/lib/queryBuilder/graph/patch/GraphPatch.js +0 -20
  243. package/lib/queryBuilder/graph/patch/GraphPatchAction.js +0 -289
  244. package/lib/queryBuilder/graph/recursiveUpsert/GraphRecursiveUpsert.js +0 -31
  245. package/lib/queryBuilder/graph/recursiveUpsert/GraphRecursiveUpsertAction.js +0 -126
  246. package/lib/queryBuilder/operations/jsonApi/WhereJsonHasPostgresOperation.js +0 -30
  247. package/lib/queryBuilder/operations/jsonApi/WhereJsonNotObjectPostgresOperation.js +0 -37
  248. package/lib/queryBuilder/operations/jsonApi/WhereJsonPostgresOperation.js +0 -62
  249. package/lib/queryBuilder/operations/jsonApi/postgresJsonApi.js +0 -192
  250. package/lib/utils/wrapDbError.js +0 -64
@@ -1,10 +1,8 @@
1
- 'use strict';
2
-
3
- const { QueryBuilderOperation } = require('./QueryBuilderOperation');
1
+ import { QueryBuilderOperation } from './QueryBuilderOperation.js';
4
2
 
5
3
  // Operation that simply delegates all calls to the operation passed
6
4
  // to to the constructor in `opt.delegate`.
7
- class DelegateOperation extends QueryBuilderOperation {
5
+ export class DelegateOperation extends QueryBuilderOperation {
8
6
  constructor(name, opt) {
9
7
  super(name, opt);
10
8
 
@@ -157,7 +155,3 @@ class DelegateOperation extends QueryBuilderOperation {
157
155
  return clone;
158
156
  }
159
157
  }
160
-
161
- module.exports = {
162
- DelegateOperation,
163
- };
@@ -1,30 +1,24 @@
1
- 'use strict';
1
+ import { QueryBuilderOperation } from './QueryBuilderOperation.js';
2
+ import { StaticHookArguments } from '../StaticHookArguments.js';
3
+ import { isMySql } from '../../utils/knexUtils.js';
2
4
 
3
- const { QueryBuilderOperation } = require('./QueryBuilderOperation');
4
- const { StaticHookArguments } = require('../StaticHookArguments');
5
- const { isMySql } = require('../../utils/knexUtils');
6
- const { warnOnce } = require('../../utils/warnings');
7
-
8
- class DeleteOperation extends QueryBuilderOperation {
5
+ export class DeleteOperation extends QueryBuilderOperation {
9
6
  async onBefore2(builder, result) {
10
7
  await callBeforeDelete(builder);
11
8
  return result;
12
9
  }
13
10
 
14
11
  // knex leaves the offset out of deletes. On MySQL, it leaves out the order as
15
- // well, but keeps the limit, so the order doesn't pick the deleted rows. Warn
16
- // when the query is executed.
12
+ // well, but keeps the limit, so the order doesn't pick the deleted rows.
13
+ // Throw when the query is executed.
17
14
  onAfterBuild(builder) {
18
15
  if (builder.has('offset')) {
19
- warnOnce(
20
- 'offset() has no effect in delete queries, so no rows are skipped. ' +
21
- 'This will throw an error in objection 4.0.',
22
- );
16
+ throw new Error('offset() is not supported in delete queries, as knex leaves it out.');
23
17
  }
24
18
  if (isMySql(builder.knex()) && builder.has('limit') && builder.has(/^orderBy/)) {
25
- warnOnce(
26
- 'orderBy() has no effect in delete queries with limit() on MySQL, so the limit ' +
27
- 'deletes rows in any order. This will throw an error in objection 4.0.',
19
+ throw new Error(
20
+ 'orderBy() is not supported in delete queries with limit() on MySQL, ' +
21
+ 'as knex leaves out the order.',
28
22
  );
29
23
  }
30
24
  }
@@ -33,10 +27,6 @@ class DeleteOperation extends QueryBuilderOperation {
33
27
  return knexBuilder.delete();
34
28
  }
35
29
 
36
- onAfter2(builder, result) {
37
- return callAfterDelete(builder, result);
38
- }
39
-
40
30
  toFindOperation() {
41
31
  return null;
42
32
  }
@@ -50,22 +40,3 @@ function callStaticBeforeDelete(builder) {
50
40
  const args = StaticHookArguments.create({ builder });
51
41
  return builder.modelClass().beforeDelete(args);
52
42
  }
53
-
54
- function callAfterDelete(builder, result) {
55
- return callStaticAfterDelete(builder, result);
56
- }
57
-
58
- async function callStaticAfterDelete(builder, result) {
59
- const args = StaticHookArguments.create({ builder, result });
60
- const maybeResult = await builder.modelClass().afterDelete(args);
61
-
62
- if (maybeResult === undefined) {
63
- return result;
64
- } else {
65
- return maybeResult;
66
- }
67
- }
68
-
69
- module.exports = {
70
- DeleteOperation,
71
- };
@@ -1,12 +1,13 @@
1
- 'use strict';
1
+ import { QueryBuilderOperation } from './QueryBuilderOperation.js';
2
+ import { assertIdNotUndefined } from '../../utils/assert.js';
2
3
 
3
- const { QueryBuilderOperation } = require('./QueryBuilderOperation');
4
- const { assertIdNotUndefined } = require('../../utils/assert');
5
-
6
- class FindByIdOperation extends QueryBuilderOperation {
4
+ export class FindByIdOperation extends QueryBuilderOperation {
7
5
  constructor(name, opt) {
8
6
  super(name, opt);
9
7
  this.id = this.opt.id;
8
+ // Keep the id condition in its own where group, so that it applies to
9
+ // whatever the user adds, `orWhere()` included. See `whereGroups.js`.
10
+ this.whereGroup = {};
10
11
  }
11
12
 
12
13
  onAdd(builder, args) {
@@ -18,9 +19,7 @@ class FindByIdOperation extends QueryBuilderOperation {
18
19
  }
19
20
 
20
21
  onBuild(builder) {
21
- if (!builder.internalOptions().skipUndefined) {
22
- assertIdNotUndefined(this.id, `undefined was passed to ${this.name}`);
23
- }
22
+ assertIdNotUndefined(this.id, `undefined was passed to ${this.name}`);
24
23
 
25
24
  builder.whereComposite(builder.fullIdColumn(), this.id);
26
25
  }
@@ -31,7 +30,3 @@ class FindByIdOperation extends QueryBuilderOperation {
31
30
  return clone;
32
31
  }
33
32
  }
34
-
35
- module.exports = {
36
- FindByIdOperation,
37
- };
@@ -1,11 +1,11 @@
1
- 'use strict';
1
+ import { QueryBuilderOperation } from './QueryBuilderOperation.js';
2
2
 
3
- const { QueryBuilderOperation } = require('./QueryBuilderOperation');
4
-
5
- class FindByIdsOperation extends QueryBuilderOperation {
3
+ export class FindByIdsOperation extends QueryBuilderOperation {
6
4
  constructor(name, opt) {
7
5
  super(name, opt);
8
6
  this.ids = null;
7
+ // Its own where group, like `FindByIdOperation`.
8
+ this.whereGroup = {};
9
9
  }
10
10
 
11
11
  onAdd(builder, args) {
@@ -23,7 +23,3 @@ class FindByIdsOperation extends QueryBuilderOperation {
23
23
  return clone;
24
24
  }
25
25
  }
26
-
27
- module.exports = {
28
- FindByIdsOperation,
29
- };
@@ -1,22 +1,26 @@
1
- 'use strict';
1
+ import { QueryBuilderOperation } from './QueryBuilderOperation.js';
2
+ import { StaticHookArguments, isGraphQuery } from '../StaticHookArguments.js';
3
+ import { isPromise, afterReturn } from '../../utils/promiseUtils/index.js';
4
+ import { isObject } from '../../utils/objectUtils.js';
2
5
 
3
- const { QueryBuilderOperation } = require('./QueryBuilderOperation');
4
- const { StaticHookArguments } = require('../StaticHookArguments');
5
- const { isPromise, after, afterReturn } = require('../../utils/promiseUtils');
6
- const { isObject } = require('../../utils/objectUtils');
7
-
8
- class FindOperation extends QueryBuilderOperation {
6
+ export class FindOperation extends QueryBuilderOperation {
9
7
  onBefore2(builder, result) {
10
- return afterReturn(callStaticBeforeFind(builder), result);
8
+ if (isGraphQuery(builder) || builder.findOptions().dontCallFindHooks) {
9
+ return result;
10
+ } else {
11
+ return afterReturn(callStaticBeforeFind(builder), result);
12
+ }
11
13
  }
12
14
 
13
15
  onAfter3(builder, results) {
14
16
  const opt = builder.findOptions();
15
17
 
16
- if (opt.dontCallFindHooks) {
18
+ // The outer queries of `insertGraph()` and `upsertGraph()` return the
19
+ // input models, unless they read the written rows back with `returning()`:
20
+ if ((isGraphQuery(builder) && !builder.has('returning')) || opt.dontCallFindHooks) {
17
21
  return results;
18
22
  } else {
19
- return callAfterFind(builder, results);
23
+ return callInstanceAfterFind(builder.context(), results, opt.callAfterFindDeeply);
20
24
  }
21
25
  }
22
26
  }
@@ -26,26 +30,6 @@ function callStaticBeforeFind(builder) {
26
30
  return builder.modelClass().beforeFind(args);
27
31
  }
28
32
 
29
- function callAfterFind(builder, result) {
30
- const opt = builder.findOptions();
31
- const maybePromise = callInstanceAfterFind(builder.context(), result, opt.callAfterFindDeeply);
32
-
33
- return after(maybePromise, () => callStaticAfterFind(builder, result));
34
- }
35
-
36
- function callStaticAfterFind(builder, result) {
37
- const args = StaticHookArguments.create({ builder, result });
38
- const maybePromise = builder.modelClass().afterFind(args);
39
-
40
- return after(maybePromise, (maybeResult) => {
41
- if (maybeResult === undefined) {
42
- return result;
43
- } else {
44
- return maybeResult;
45
- }
46
- });
47
- }
48
-
49
33
  function callInstanceAfterFind(ctx, results, deep) {
50
34
  if (Array.isArray(results)) {
51
35
  if (results.length === 1) {
@@ -158,7 +142,3 @@ function getAfterFindHook(model) {
158
142
  return null;
159
143
  }
160
144
  }
161
-
162
- module.exports = {
163
- FindOperation,
164
- };
@@ -1,8 +1,7 @@
1
- 'use strict';
1
+ import { QueryBuilderOperation } from './QueryBuilderOperation.js';
2
+ import { LimitPerParentOperation } from './LimitPerParentOperation.js';
2
3
 
3
- const { QueryBuilderOperation } = require('./QueryBuilderOperation');
4
-
5
- class FirstOperation extends QueryBuilderOperation {
4
+ export class FirstOperation extends QueryBuilderOperation {
6
5
  shouldLimit(builder) {
7
6
  return builder.isFind() && builder.modelClass().useLimitInFirst;
8
7
  }
@@ -15,15 +14,12 @@ class FirstOperation extends QueryBuilderOperation {
15
14
  return knexBuilder;
16
15
  }
17
16
 
18
- onAfter3(_, result) {
19
- if (Array.isArray(result)) {
17
+ onAfter3(builder, result) {
18
+ // Limited per parent, the query still returns the models of all parents:
19
+ if (Array.isArray(result) && !builder.has(LimitPerParentOperation)) {
20
20
  return result[0];
21
21
  } else {
22
22
  return result;
23
23
  }
24
24
  }
25
25
  }
26
-
27
- module.exports = {
28
- FirstOperation,
29
- };
@@ -1,7 +1,5 @@
1
- 'use strict';
2
-
3
- const { ObjectionToKnexConvertingOperation } = require('./ObjectionToKnexConvertingOperation');
4
- const { isPlainObject, isString } = require('../../utils/objectUtils');
1
+ import { ObjectionToKnexConvertingOperation } from './ObjectionToKnexConvertingOperation.js';
2
+ import { isPlainObject, isString } from '../../utils/objectUtils.js';
5
3
 
6
4
  const ALIAS_REGEX = /\s+as\s+/i;
7
5
 
@@ -9,7 +7,7 @@ const ALIAS_REGEX = /\s+as\s+/i;
9
7
  // knex, but we first try to parse the arguments so that we can determine which
10
8
  // tables have been mentioned in a query's from clause. We only parse string
11
9
  // references and not `raw` or `ref` etc. references at this point thouhg.
12
- class FromOperation extends ObjectionToKnexConvertingOperation {
10
+ export class FromOperation extends ObjectionToKnexConvertingOperation {
13
11
  constructor(name, opt) {
14
12
  super(name, opt);
15
13
 
@@ -95,7 +93,3 @@ function parseTableAndAliasFromObject(arg, builder) {
95
93
  `one of the tables in ${JSON.stringify(arg)} must be the query's model class's table.`,
96
94
  );
97
95
  }
98
-
99
- module.exports = {
100
- FromOperation,
101
- };
@@ -1,11 +1,9 @@
1
- 'use strict';
1
+ import { InsertOperation } from './InsertOperation.js';
2
+ import { DelegateOperation } from './DelegateOperation.js';
3
+ import { keyByProps } from '../../model/modelUtils.js';
4
+ import { asArray } from '../../utils/objectUtils.js';
2
5
 
3
- const { InsertOperation } = require('./InsertOperation');
4
- const { DelegateOperation } = require('./DelegateOperation');
5
- const { keyByProps } = require('../../model/modelUtils');
6
- const { asArray } = require('../../utils/objectUtils');
7
-
8
- class InsertAndFetchOperation extends DelegateOperation {
6
+ export class InsertAndFetchOperation extends DelegateOperation {
9
7
  constructor(name, opt) {
10
8
  super(name, opt);
11
9
 
@@ -24,7 +22,7 @@ class InsertAndFetchOperation extends DelegateOperation {
24
22
 
25
23
  // Models without identifiers can't be fetched. This happens when a row
26
24
  // with a database generated identifier is ignored by `onConflict()`.
27
- const insertedModelArray = asArray(insertedModels).filter((model) => model && model.$hasId());
25
+ const insertedModelArray = asArray(insertedModels).filter((model) => model.$hasId());
28
26
  const idProps = modelClass.getIdPropertyArray();
29
27
  const ids = insertedModelArray.map((model) => model.$id());
30
28
 
@@ -38,6 +36,13 @@ class InsertAndFetchOperation extends DelegateOperation {
38
36
  .findByIds(ids)
39
37
  .castTo(builder.resultModelClass());
40
38
 
39
+ if (!Array.isArray(fetchedModels) || !fetchedModels.every((model) => model.$isObjectionModel)) {
40
+ throw new Error(
41
+ `Unable to merge the result of ${modelClass.name}.afterFind() in ` +
42
+ `${this.name}(): expected an array of models.`,
43
+ );
44
+ }
45
+
41
46
  const modelsById = keyByProps(fetchedModels, idProps);
42
47
 
43
48
  // Instead of returning the freshly fetched models, update the input
@@ -49,7 +54,3 @@ class InsertAndFetchOperation extends DelegateOperation {
49
54
  return insertedModels;
50
55
  }
51
56
  }
52
-
53
- module.exports = {
54
- InsertAndFetchOperation,
55
- };
@@ -1,10 +1,8 @@
1
- 'use strict';
1
+ import { DelegateOperation } from './DelegateOperation.js';
2
+ import { InsertGraphOperation } from './InsertGraphOperation.js';
3
+ import { RelationExpression } from '../RelationExpression.js';
2
4
 
3
- const { DelegateOperation } = require('./DelegateOperation');
4
- const { InsertGraphOperation } = require('./InsertGraphOperation');
5
- const { RelationExpression } = require('../RelationExpression');
6
-
7
- class InsertGraphAndFetchOperation extends DelegateOperation {
5
+ export class InsertGraphAndFetchOperation extends DelegateOperation {
8
6
  constructor(name, opt) {
9
7
  super(name, opt);
10
8
 
@@ -39,7 +37,3 @@ class InsertGraphAndFetchOperation extends DelegateOperation {
39
37
  return this.isArray ? models : models[0] || null;
40
38
  }
41
39
  }
42
-
43
- module.exports = {
44
- InsertGraphAndFetchOperation,
45
- };
@@ -1,10 +1,8 @@
1
- 'use strict';
1
+ import { DelegateOperation } from './DelegateOperation.js';
2
+ import { InsertOperation } from './InsertOperation.js';
3
+ import { GraphUpsert } from '../graph/GraphUpsert.js';
2
4
 
3
- const { DelegateOperation } = require('./DelegateOperation');
4
- const { InsertOperation } = require('./InsertOperation');
5
- const { GraphUpsert } = require('../graph/GraphUpsert');
6
-
7
- class InsertGraphOperation extends DelegateOperation {
5
+ export class InsertGraphOperation extends DelegateOperation {
8
6
  constructor(name, opt = null) {
9
7
  super(name, opt);
10
8
 
@@ -33,15 +31,10 @@ class InsertGraphOperation extends DelegateOperation {
33
31
  const retVal = super.onAdd(builder, args);
34
32
 
35
33
  this.upsert = new GraphUpsert({
36
- objects: this.models,
34
+ objects: this.isArray ? this.models : this.models[0],
37
35
  rootModelClass: builder.modelClass(),
38
36
 
39
- upsertOptions: Object.assign({}, this.upsertOptions, {
40
- noUpdate: true,
41
- noDelete: true,
42
- noUnrelate: true,
43
- insertMissing: true,
44
- }),
37
+ upsertOptions: this.upsertOptions,
45
38
  insertOnly: true,
46
39
  });
47
40
 
@@ -53,7 +46,7 @@ class InsertGraphOperation extends DelegateOperation {
53
46
  }
54
47
 
55
48
  onBefore1(builder, result) {
56
- GraphUpsert.warnOnConflict(builder, this.name);
49
+ GraphUpsert.checkForOnConflict(builder, this.name);
57
50
  return result;
58
51
  }
59
52
 
@@ -108,7 +101,3 @@ class InsertGraphOperation extends DelegateOperation {
108
101
  return clone;
109
102
  }
110
103
  }
111
-
112
- module.exports = {
113
- InsertGraphOperation,
114
- };
@@ -1,18 +1,24 @@
1
- 'use strict';
2
-
3
- const { QueryBuilderOperation } = require('./QueryBuilderOperation');
4
- const { StaticHookArguments } = require('../StaticHookArguments');
5
- const { after, mapAfterAllReturn } = require('../../utils/promiseUtils');
6
- const { isSqlite, isMySql, hasBatchInsert } = require('../../utils/knexUtils');
7
- const { isObject, isString } = require('../../utils/objectUtils');
8
- const { removeOverriddenValues } = require('../../model/modelQueryProps');
1
+ import { QueryBuilderOperation } from './QueryBuilderOperation.js';
2
+ import { StaticHookArguments } from '../StaticHookArguments.js';
3
+ import { after, mapAfterAllReturn } from '../../utils/promiseUtils/index.js';
4
+ import {
5
+ isSqlite,
6
+ isMySql,
7
+ hasBatchInsert,
8
+ hasBatchInsertDefaults,
9
+ getMaxInsertRows,
10
+ } from '../../utils/knexUtils.js';
11
+ import { chunk, groupBy, isObject, isPlainObject, isString } from '../../utils/objectUtils.js';
12
+ import { removeOverriddenValues } from '../../model/modelQueryProps.js';
13
+ import { checkFieldExpressions } from './fieldExpressions.js';
9
14
 
10
15
  // Base class for all insert operations.
11
- class InsertOperation extends QueryBuilderOperation {
16
+ export class InsertOperation extends QueryBuilderOperation {
12
17
  constructor(name, opt) {
13
18
  super(name, opt);
14
19
 
15
20
  this.models = null;
21
+ this.batches = null;
16
22
  this.isArray = false;
17
23
  this.modelOptions = Object.assign({}, this.opt.modelOptions || {});
18
24
  }
@@ -28,13 +34,58 @@ class InsertOperation extends QueryBuilderOperation {
28
34
  }
29
35
 
30
36
  async onBefore2(builder, result) {
31
- if (this.models.length > 1 && !hasBatchInsert(builder.knex())) {
32
- throw new Error('batch insert only works with Postgresql and SQL Server');
33
- } else {
34
- await callBeforeInsert(builder, this.models);
35
- this.models.forEach(removeOverriddenValues);
36
- return result;
37
+ await callBeforeInsert(builder, this.models);
38
+
39
+ // Without ids to return, rows can be inserted in batches on all databases.
40
+ // The hooks may give the models their ids, or cancel the query.
41
+ if (
42
+ this.models.length > 1 &&
43
+ !hasBatchInsert(builder.knex()) &&
44
+ !builder.isExplicitlyResolvedOrRejected() &&
45
+ this._hasIdsToReturn(builder)
46
+ ) {
47
+ throw new Error(
48
+ 'batch insert only works with Postgresql, SQL Server and SQLite, or with models that have their ids or no idColumn',
49
+ );
50
+ }
51
+
52
+ this.models.forEach(removeOverriddenValues);
53
+ return result;
54
+ }
55
+
56
+ // Insert the models in several queries if they don't fit into one: Models
57
+ // without any column can't be inserted in batches (#1694), where the database
58
+ // doesn't fill in defaults (SQLite) the rows of a batch need the same columns,
59
+ // and a query can only bind so many values. The queries run in the caller's
60
+ // transaction, if there is one. Without it they are not atomic.
61
+ queryBatches(builder) {
62
+ const models = this.models;
63
+ this.batches = null;
64
+
65
+ if (models.length < 2) {
66
+ return null;
67
+ }
68
+
69
+ const knex = builder.knex();
70
+ const columnsByModel = new Map(
71
+ models.map((model) => [model, Object.keys(model.$toDatabaseJson(builder))]),
72
+ );
73
+ const batches = [];
74
+
75
+ for (const group of groupBy(models, (model) =>
76
+ getColumnsKey(knex, columnsByModel.get(model)),
77
+ ).values()) {
78
+ const columnCount = Math.max(...group.map((model) => columnsByModel.get(model).length));
79
+
80
+ if (columnCount === 0) {
81
+ batches.push(...group.map((model) => [model]));
82
+ } else {
83
+ batches.push(...chunk(group, getMaxInsertRows(knex, columnCount)));
84
+ }
37
85
  }
86
+
87
+ this.batches = batches.length > 1 ? batches : null;
88
+ return this.batches;
38
89
  }
39
90
 
40
91
  onBuildKnex(knexBuilder, builder) {
@@ -49,15 +100,37 @@ class InsertOperation extends QueryBuilderOperation {
49
100
  // conflict columns are returned too, so that the returned rows can
50
101
  // be matched to the models when some of the rows are ignored.
51
102
  knexBuilder = knexBuilder.returning(defaultReturning);
52
- } else if (isSqlite(knex) && builder.has('onConflict')) {
103
+ } else if (
104
+ isSqlite(knex) &&
105
+ (builder.has('onConflict') || (this.models.length > 1 && this._hasIdsToReturn(builder)))
106
+ ) {
53
107
  // Without a `returning` clause, SQLite returns the id of the last
54
108
  // inserted row, which belongs to a previous insert if the row was
55
- // ignored. Use `returning` to find out what was actually inserted.
109
+ // ignored, and only one id for batch inserts. Use `returning` to find
110
+ // out what was actually inserted.
56
111
  knexBuilder = knexBuilder.returning(defaultReturning);
57
112
  }
58
113
  }
59
114
 
60
- return knexBuilder.insert(this.models.map((model) => model.$toDatabaseJson(builder)));
115
+ const modelClass = builder.modelClass();
116
+ // knex leaves arrays unserialized in SQLite inserts, and also objects when
117
+ // it inserts several rows with `select ... union all`.
118
+ const shouldSerialize = isSqlite(knex);
119
+
120
+ return knexBuilder.insert(
121
+ (builder._queryBatch || this.models).map((model) => {
122
+ checkFieldExpressions(modelClass, model, 'insert');
123
+ const json = model.$toDatabaseJson(builder);
124
+ return shouldSerialize ? serializeObjects(json) : json;
125
+ }),
126
+ );
127
+ }
128
+
129
+ _hasIdsToReturn(builder) {
130
+ return (
131
+ builder.modelClass().getIdColumnArray().length > 0 &&
132
+ !this.models.every((model) => model.$hasId())
133
+ );
61
134
  }
62
135
 
63
136
  onAfter1(builder, ret) {
@@ -67,6 +140,8 @@ class InsertOperation extends QueryBuilderOperation {
67
140
  }
68
141
 
69
142
  const isOnConflict = builder.has('onConflict');
143
+ // The results of the batches are in the order of the batches.
144
+ const models = this.batches ? this.batches.flat() : this.models;
70
145
 
71
146
  if (isObject(ret[0])) {
72
147
  if (isOnConflict && ret.length !== this.models.length) {
@@ -77,14 +152,15 @@ class InsertOperation extends QueryBuilderOperation {
77
152
  } else {
78
153
  // If the user specified a `returning` clause the result may be an array of objects.
79
154
  // Merge all values of the objects to our models.
80
- for (let i = 0, l = this.models.length; i < l; ++i) {
81
- this.models[i].$setDatabaseJson(ret[i]);
155
+ const options = { knex: builder.knex() };
156
+ for (let i = 0, l = models.length; i < l; ++i) {
157
+ models[i].$setDatabaseJson(ret[i], options);
82
158
  }
83
159
  }
84
160
  } else if (builder.modelClass().getIdColumnArray().length > 0) {
85
161
  // If the return value is not an array of objects, we assume it is an array of identifiers.
86
- for (let i = 0, l = this.models.length; i < l; ++i) {
87
- const model = this.models[i];
162
+ for (let i = 0, l = models.length; i < l; ++i) {
163
+ const model = models[i];
88
164
 
89
165
  // Don't set the id if the model already has one. MySQL and Sqlite don't return the correct
90
166
  // primary key value if the id is not generated in db, but given explicitly. With
@@ -98,9 +174,9 @@ class InsertOperation extends QueryBuilderOperation {
98
174
  return this.models;
99
175
  }
100
176
 
101
- onAfter2(builder, models) {
102
- const result = this.isArray ? models : models[0] || null;
103
- return callAfterInsert(builder, this.models, result);
177
+ async onAfter2(builder, models) {
178
+ await callInstanceAfterInsert(builder, this.models);
179
+ return this.isArray ? models : models[0] || null;
104
180
  }
105
181
 
106
182
  toFindOperation() {
@@ -111,12 +187,19 @@ class InsertOperation extends QueryBuilderOperation {
111
187
  const clone = super.clone();
112
188
 
113
189
  clone.models = this.models;
190
+ clone.batches = this.batches;
114
191
  clone.isArray = this.isArray;
115
192
 
116
193
  return clone;
117
194
  }
118
195
  }
119
196
 
197
+ // Rows are only grouped where the database doesn't fill in the defaults of the
198
+ // columns that a row leaves out.
199
+ function getColumnsKey(knex, columns) {
200
+ return hasBatchInsertDefaults(knex) ? '' : JSON.stringify([...columns].sort());
201
+ }
202
+
120
203
  // Returns `null` if there's nothing to return, e.g. for models without an `idColumn`.
121
204
  function getDefaultReturning(builder) {
122
205
  const idColumns = builder.modelClass().getIdColumnArray();
@@ -180,6 +263,8 @@ function mergeMatchingRows(builder, models, rows) {
180
263
  }
181
264
  });
182
265
 
266
+ const options = { knex: builder.knex() };
267
+
183
268
  for (const row of rows) {
184
269
  const indices = indicesByKey.get(createKey(row));
185
270
  const index = indices ? indices.shift() : undefined;
@@ -188,7 +273,7 @@ function mergeMatchingRows(builder, models, rows) {
188
273
  throw createMatchError();
189
274
  }
190
275
 
191
- models[index].$setDatabaseJson(row);
276
+ models[index].$setDatabaseJson(row, options);
192
277
  }
193
278
  }
194
279
 
@@ -224,28 +309,16 @@ function callStaticBeforeInsert(builder) {
224
309
  return builder.modelClass().beforeInsert(args);
225
310
  }
226
311
 
227
- function callAfterInsert(builder, models, result) {
228
- const maybePromise = callInstanceAfterInsert(builder, models);
229
- return after(maybePromise, () => callStaticAfterInsert(builder, result));
230
- }
231
-
232
312
  function callInstanceAfterInsert(builder, models) {
233
313
  return mapAfterAllReturn(models, (model) => model.$afterInsert(builder.context()), models);
234
314
  }
235
315
 
236
- function callStaticAfterInsert(builder, result) {
237
- const args = StaticHookArguments.create({ builder, result });
238
- const maybePromise = builder.modelClass().afterInsert(args);
239
-
240
- return after(maybePromise, (maybeResult) => {
241
- if (maybeResult === undefined) {
242
- return result;
243
- } else {
244
- return maybeResult;
316
+ function serializeObjects(json) {
317
+ for (const [key, value] of Object.entries(json)) {
318
+ if (isPlainObject(value) || Array.isArray(value)) {
319
+ json[key] = JSON.stringify(value);
245
320
  }
246
- });
247
- }
321
+ }
248
322
 
249
- module.exports = {
250
- InsertOperation,
251
- };
323
+ return json;
324
+ }