objection 3.9.0 → 4.0.0-rc.1

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 (248) 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 +43 -27
  57. package/lib/model/modelSet.js +89 -41
  58. package/lib/model/modelTableMetadata.js +4 -11
  59. package/lib/model/modelToJson.js +8 -23
  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 +304 -0
  81. package/lib/queryBuilder/graph/GraphNode.js +235 -0
  82. package/lib/queryBuilder/graph/GraphOptions.js +55 -248
  83. package/lib/queryBuilder/graph/GraphPlan.js +395 -0
  84. package/lib/queryBuilder/graph/GraphUpsert.js +466 -410
  85. package/lib/queryBuilder/graph/GraphWriter.js +1263 -0
  86. package/lib/queryBuilder/join/JoinResultColumn.js +1 -7
  87. package/lib/queryBuilder/join/JoinResultParser.js +6 -11
  88. package/lib/queryBuilder/join/RelationJoiner.js +66 -84
  89. package/lib/queryBuilder/join/TableNode.js +2 -8
  90. package/lib/queryBuilder/join/TableTree.js +3 -9
  91. package/lib/queryBuilder/join/utils.js +5 -15
  92. package/lib/queryBuilder/jsonDialects/JsonDialect.js +51 -0
  93. package/lib/queryBuilder/jsonDialects/MySqlJsonDialect.js +81 -0
  94. package/lib/queryBuilder/jsonDialects/PostgresJsonDialect.js +45 -0
  95. package/lib/queryBuilder/jsonDialects/SqliteJsonDialect.js +67 -0
  96. package/lib/queryBuilder/jsonDialects/index.js +44 -0
  97. package/lib/queryBuilder/operations/DelegateOperation.js +2 -8
  98. package/lib/queryBuilder/operations/DeleteOperation.js +13 -35
  99. package/lib/queryBuilder/operations/FindByIdOperation.js +7 -12
  100. package/lib/queryBuilder/operations/FindByIdsOperation.js +4 -8
  101. package/lib/queryBuilder/operations/FindOperation.js +14 -34
  102. package/lib/queryBuilder/operations/FirstOperation.js +6 -10
  103. package/lib/queryBuilder/operations/FromOperation.js +3 -9
  104. package/lib/queryBuilder/operations/InsertAndFetchOperation.js +13 -12
  105. package/lib/queryBuilder/operations/InsertGraphAndFetchOperation.js +4 -10
  106. package/lib/queryBuilder/operations/InsertGraphOperation.js +7 -18
  107. package/lib/queryBuilder/operations/InsertOperation.js +118 -43
  108. package/lib/queryBuilder/operations/InstanceDeleteOperation.js +5 -12
  109. package/lib/queryBuilder/operations/InstanceFindOperation.js +4 -11
  110. package/lib/queryBuilder/operations/InstanceInsertOperation.js +2 -8
  111. package/lib/queryBuilder/operations/InstanceUpdateOperation.js +7 -14
  112. package/lib/queryBuilder/operations/JoinRelatedOperation.js +5 -11
  113. package/lib/queryBuilder/operations/KnexOperation.js +2 -8
  114. package/lib/queryBuilder/operations/LimitPerParentOperation.js +7 -69
  115. package/lib/queryBuilder/operations/MergeOperation.js +5 -11
  116. package/lib/queryBuilder/operations/NoneOperation.js +2 -8
  117. package/lib/queryBuilder/operations/ObjectionToKnexConvertingOperation.js +20 -49
  118. package/lib/queryBuilder/operations/OnBuildKnexOperation.js +2 -8
  119. package/lib/queryBuilder/operations/OnBuildOperation.js +2 -8
  120. package/lib/queryBuilder/operations/OnErrorOperation.js +2 -8
  121. package/lib/queryBuilder/operations/QueryBuilderOperation.js +1 -7
  122. package/lib/queryBuilder/operations/RangeOperation.js +11 -26
  123. package/lib/queryBuilder/operations/RelateOperation.js +2 -8
  124. package/lib/queryBuilder/operations/ReturningOperation.js +3 -9
  125. package/lib/queryBuilder/operations/RunAfterOperation.js +2 -12
  126. package/lib/queryBuilder/operations/RunBeforeOperation.js +2 -8
  127. package/lib/queryBuilder/operations/UnrelateOperation.js +2 -8
  128. package/lib/queryBuilder/operations/UpdateAndFetchOperation.js +14 -17
  129. package/lib/queryBuilder/operations/UpdateOperation.js +39 -125
  130. package/lib/queryBuilder/operations/UpsertGraphAndFetchOperation.js +8 -11
  131. package/lib/queryBuilder/operations/UpsertGraphOperation.js +6 -12
  132. package/lib/queryBuilder/operations/WhereCompositeOperation.js +3 -9
  133. package/lib/queryBuilder/operations/WhereGroupOperation.js +2 -8
  134. package/lib/queryBuilder/operations/eager/EagerOperation.js +3 -9
  135. package/lib/queryBuilder/operations/eager/JoinEagerOperation.js +72 -10
  136. package/lib/queryBuilder/operations/eager/NaiveEagerOperation.js +2 -8
  137. package/lib/queryBuilder/operations/eager/WhereInEagerOperation.js +23 -44
  138. package/lib/queryBuilder/operations/fieldExpressions.js +122 -0
  139. package/lib/queryBuilder/operations/jsonApi/WhereJsonHasOperation.js +20 -0
  140. package/lib/queryBuilder/operations/jsonApi/WhereJsonOperation.js +44 -0
  141. package/lib/queryBuilder/operations/jsonApi/WhereJsonTypeOperation.js +14 -0
  142. package/lib/queryBuilder/operations/select/SelectOperation.js +11 -21
  143. package/lib/queryBuilder/operations/select/Selection.js +19 -17
  144. package/lib/queryBuilder/operations/whereInComposite/WhereInCompositeMsSqlOperation.js +4 -10
  145. package/lib/queryBuilder/operations/whereInComposite/WhereInCompositeOperation.js +4 -10
  146. package/lib/queryBuilder/operations/whereInComposite/WhereInCompositeSqliteOperation.js +4 -10
  147. package/lib/queryBuilder/operations/windowOrder.js +56 -0
  148. package/lib/queryBuilder/parsers/jsonFieldExpressionParser.js +3 -7
  149. package/lib/queryBuilder/parsers/relationExpressionParser.js +42 -43
  150. package/lib/queryBuilder/parsers/relationExpressionParser.pegjs +39 -36
  151. package/lib/queryBuilder/transformations/CompositeQueryTransformation.js +2 -8
  152. package/lib/queryBuilder/transformations/QueryTransformation.js +1 -7
  153. package/lib/queryBuilder/transformations/WrapMysqlModifySubqueryTransformation.js +3 -9
  154. package/lib/queryBuilder/transformations/index.js +3 -11
  155. package/lib/queryBuilder/whereGroups.js +9 -24
  156. package/lib/queryBuilder/withoutOrder.js +4 -11
  157. package/lib/relations/Relation.js +47 -28
  158. package/lib/relations/RelationDeleteOperation.js +4 -14
  159. package/lib/relations/RelationFindOperation.js +119 -90
  160. package/lib/relations/RelationInsertOperation.js +2 -8
  161. package/lib/relations/RelationOwner.js +5 -11
  162. package/lib/relations/RelationProperty.js +4 -10
  163. package/lib/relations/RelationUpdateOperation.js +4 -14
  164. package/lib/relations/RelationWriteResultOperation.js +15 -0
  165. package/lib/relations/belongsToMany/BelongsToManyDeleteOperation.js +23 -0
  166. package/lib/relations/belongsToMany/BelongsToManyFindOperation.js +35 -0
  167. package/lib/relations/belongsToMany/BelongsToManyInsertOperation.js +28 -0
  168. package/lib/relations/belongsToMany/BelongsToManyRelateOperation.js +16 -0
  169. package/lib/relations/belongsToMany/BelongsToManyRelation.js +276 -0
  170. package/lib/relations/belongsToMany/BelongsToManyUnrelateOperation.js +11 -0
  171. package/lib/relations/belongsToOne/BelongsToOneDeleteOperation.js +2 -8
  172. package/lib/relations/belongsToOne/BelongsToOneInsertOperation.js +6 -11
  173. package/lib/relations/belongsToOne/BelongsToOneRelateOperation.js +3 -9
  174. package/lib/relations/belongsToOne/BelongsToOneRelation.js +8 -19
  175. package/lib/relations/belongsToOne/BelongsToOneUnrelateOperation.js +53 -27
  176. package/lib/relations/hasMany/HasManyInsertOperation.js +8 -9
  177. package/lib/relations/hasMany/HasManyRelateOperation.js +5 -11
  178. package/lib/relations/hasMany/HasManyRelation.js +9 -11
  179. package/lib/relations/hasMany/HasManyUnrelateOperation.js +3 -9
  180. package/lib/relations/hasOne/HasOneRelation.js +2 -8
  181. package/lib/relations/hasOneThrough/HasOneThroughRelation.js +2 -8
  182. package/lib/relations/manyToMany/ManyToManyModifyMixin.js +10 -15
  183. package/lib/relations/manyToMany/ManyToManyMySqlModifyMixin.js +2 -8
  184. package/lib/relations/manyToMany/ManyToManyRelation.js +82 -50
  185. package/lib/relations/manyToMany/ManyToManySqliteModifyMixin.js +2 -8
  186. package/lib/relations/manyToMany/delete/ManyToManyDeleteOperation.js +5 -9
  187. package/lib/relations/manyToMany/delete/ManyToManyDeleteOperationBase.js +2 -8
  188. package/lib/relations/manyToMany/delete/ManyToManyDeleteSqliteOperation.js +3 -9
  189. package/lib/relations/manyToMany/find/ManyToManyFindOperation.js +20 -59
  190. package/lib/relations/manyToMany/insert/ManyToManyInsertOperation.js +6 -11
  191. package/lib/relations/manyToMany/relate/ManyToManyRelateOperation.js +4 -10
  192. package/lib/relations/manyToMany/unrelate/ManyToManyUnrelateMySqlOperation.js +3 -9
  193. package/lib/relations/manyToMany/unrelate/ManyToManyUnrelateOperation.js +5 -9
  194. package/lib/relations/manyToMany/unrelate/ManyToManyUnrelateOperationBase.js +3 -9
  195. package/lib/relations/manyToMany/unrelate/ManyToManyUnrelateSqliteOperation.js +3 -9
  196. package/lib/relations/manyToMany/update/ManyToManyUpdateMySqlOperation.js +3 -9
  197. package/lib/relations/manyToMany/update/ManyToManyUpdateOperation.js +5 -9
  198. package/lib/relations/manyToMany/update/ManyToManyUpdateOperationBase.js +79 -64
  199. package/lib/relations/manyToMany/update/ManyToManyUpdateSqliteOperation.js +3 -9
  200. package/lib/transaction.js +3 -9
  201. package/lib/utils/assert.js +3 -11
  202. package/lib/utils/buildUtils.js +2 -8
  203. package/lib/utils/classUtils.js +1 -7
  204. package/lib/utils/createModifier.js +2 -8
  205. package/lib/utils/identifierMapping.js +23 -27
  206. package/lib/utils/internalPropUtils.js +1 -7
  207. package/lib/utils/knexUtils.js +84 -40
  208. package/lib/utils/mixin.js +3 -10
  209. package/lib/utils/normalizeIds.js +2 -8
  210. package/lib/utils/objectUtils.js +41 -60
  211. package/lib/utils/parseFieldExpression.js +29 -14
  212. package/lib/utils/promiseUtils/after.js +2 -8
  213. package/lib/utils/promiseUtils/afterReturn.js +2 -8
  214. package/lib/utils/promiseUtils/index.js +7 -16
  215. package/lib/utils/promiseUtils/isPromise.js +2 -8
  216. package/lib/utils/promiseUtils/map.js +25 -14
  217. package/lib/utils/promiseUtils/mapAfterAllReturn.js +2 -8
  218. package/lib/utils/promiseUtils/try.js +2 -8
  219. package/lib/utils/resolveModel.js +10 -17
  220. package/lib/utils/tmpColumnUtils.js +2 -9
  221. package/lib/utils/warnings.js +2 -14
  222. package/package.json +25 -17
  223. package/typings/objection/index.d.ts +3217 -2179
  224. package/lib/.eslintrc.json +0 -8
  225. package/lib/model/graph/ModelGraph.js +0 -80
  226. package/lib/model/graph/ModelGraphBuilder.js +0 -241
  227. package/lib/model/graph/ModelGraphEdge.js +0 -52
  228. package/lib/model/graph/ModelGraphNode.js +0 -253
  229. package/lib/queryBuilder/graph/GraphAction.js +0 -69
  230. package/lib/queryBuilder/graph/GraphData.js +0 -53
  231. package/lib/queryBuilder/graph/GraphFetcher.js +0 -199
  232. package/lib/queryBuilder/graph/GraphNodeDbExistence.js +0 -184
  233. package/lib/queryBuilder/graph/GraphOperation.js +0 -27
  234. package/lib/queryBuilder/graph/delete/GraphDelete.js +0 -73
  235. package/lib/queryBuilder/graph/delete/GraphDeleteAction.js +0 -88
  236. package/lib/queryBuilder/graph/insert/DeferredRelationGraphInsertAction.js +0 -57
  237. package/lib/queryBuilder/graph/insert/GraphInsert.js +0 -257
  238. package/lib/queryBuilder/graph/insert/GraphInsertAction.js +0 -238
  239. package/lib/queryBuilder/graph/insert/JoinRowGraphInsertAction.js +0 -92
  240. package/lib/queryBuilder/graph/patch/GraphPatch.js +0 -20
  241. package/lib/queryBuilder/graph/patch/GraphPatchAction.js +0 -277
  242. package/lib/queryBuilder/graph/recursiveUpsert/GraphRecursiveUpsert.js +0 -31
  243. package/lib/queryBuilder/graph/recursiveUpsert/GraphRecursiveUpsertAction.js +0 -126
  244. package/lib/queryBuilder/operations/jsonApi/WhereJsonHasPostgresOperation.js +0 -30
  245. package/lib/queryBuilder/operations/jsonApi/WhereJsonNotObjectPostgresOperation.js +0 -37
  246. package/lib/queryBuilder/operations/jsonApi/WhereJsonPostgresOperation.js +0 -62
  247. package/lib/queryBuilder/operations/jsonApi/postgresJsonApi.js +0 -192
  248. package/lib/utils/wrapDbError.js +0 -50
@@ -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,23 +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
- // knex leaves the order out of deletes on MySQL, but keeps their limit, so
15
- // the order doesn't pick the deleted rows. Warn when the query is executed.
11
+ // knex leaves the offset out of deletes. On MySQL, it leaves out the order as
12
+ // well, but keeps the limit, so the order doesn't pick the deleted rows.
13
+ // Throw when the query is executed.
16
14
  onAfterBuild(builder) {
15
+ if (builder.has('offset')) {
16
+ throw new Error('offset() is not supported in delete queries, as knex leaves it out.');
17
+ }
17
18
  if (isMySql(builder.knex()) && builder.has('limit') && builder.has(/^orderBy/)) {
18
- warnOnce(
19
- 'orderBy() has no effect in delete queries with limit() on MySQL, so the limit ' +
20
- '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.',
21
22
  );
22
23
  }
23
24
  }
@@ -26,10 +27,6 @@ class DeleteOperation extends QueryBuilderOperation {
26
27
  return knexBuilder.delete();
27
28
  }
28
29
 
29
- onAfter2(builder, result) {
30
- return callAfterDelete(builder, result);
31
- }
32
-
33
30
  toFindOperation() {
34
31
  return null;
35
32
  }
@@ -43,22 +40,3 @@ function callStaticBeforeDelete(builder) {
43
40
  const args = StaticHookArguments.create({ builder });
44
41
  return builder.modelClass().beforeDelete(args);
45
42
  }
46
-
47
- function callAfterDelete(builder, result) {
48
- return callStaticAfterDelete(builder, result);
49
- }
50
-
51
- async function callStaticAfterDelete(builder, result) {
52
- const args = StaticHookArguments.create({ builder, result });
53
- const maybeResult = await builder.modelClass().afterDelete(args);
54
-
55
- if (maybeResult === undefined) {
56
- return result;
57
- } else {
58
- return maybeResult;
59
- }
60
- }
61
-
62
- module.exports = {
63
- DeleteOperation,
64
- };
@@ -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,17 +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');
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';
8
14
 
9
15
  // Base class for all insert operations.
10
- class InsertOperation extends QueryBuilderOperation {
16
+ export class InsertOperation extends QueryBuilderOperation {
11
17
  constructor(name, opt) {
12
18
  super(name, opt);
13
19
 
14
20
  this.models = null;
21
+ this.batches = null;
15
22
  this.isArray = false;
16
23
  this.modelOptions = Object.assign({}, this.opt.modelOptions || {});
17
24
  }
@@ -27,12 +34,58 @@ class InsertOperation extends QueryBuilderOperation {
27
34
  }
28
35
 
29
36
  async onBefore2(builder, result) {
30
- if (this.models.length > 1 && !hasBatchInsert(builder.knex())) {
31
- throw new Error('batch insert only works with Postgresql and SQL Server');
32
- } else {
33
- await callBeforeInsert(builder, this.models);
34
- 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
+ }
35
85
  }
86
+
87
+ this.batches = batches.length > 1 ? batches : null;
88
+ return this.batches;
36
89
  }
37
90
 
38
91
  onBuildKnex(knexBuilder, builder) {
@@ -47,15 +100,37 @@ class InsertOperation extends QueryBuilderOperation {
47
100
  // conflict columns are returned too, so that the returned rows can
48
101
  // be matched to the models when some of the rows are ignored.
49
102
  knexBuilder = knexBuilder.returning(defaultReturning);
50
- } 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
+ ) {
51
107
  // Without a `returning` clause, SQLite returns the id of the last
52
108
  // inserted row, which belongs to a previous insert if the row was
53
- // 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.
54
111
  knexBuilder = knexBuilder.returning(defaultReturning);
55
112
  }
56
113
  }
57
114
 
58
- 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
+ );
59
134
  }
60
135
 
61
136
  onAfter1(builder, ret) {
@@ -65,6 +140,8 @@ class InsertOperation extends QueryBuilderOperation {
65
140
  }
66
141
 
67
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;
68
145
 
69
146
  if (isObject(ret[0])) {
70
147
  if (isOnConflict && ret.length !== this.models.length) {
@@ -75,14 +152,15 @@ class InsertOperation extends QueryBuilderOperation {
75
152
  } else {
76
153
  // If the user specified a `returning` clause the result may be an array of objects.
77
154
  // Merge all values of the objects to our models.
78
- for (let i = 0, l = this.models.length; i < l; ++i) {
79
- 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);
80
158
  }
81
159
  }
82
160
  } else if (builder.modelClass().getIdColumnArray().length > 0) {
83
161
  // If the return value is not an array of objects, we assume it is an array of identifiers.
84
- for (let i = 0, l = this.models.length; i < l; ++i) {
85
- const model = this.models[i];
162
+ for (let i = 0, l = models.length; i < l; ++i) {
163
+ const model = models[i];
86
164
 
87
165
  // Don't set the id if the model already has one. MySQL and Sqlite don't return the correct
88
166
  // primary key value if the id is not generated in db, but given explicitly. With
@@ -96,9 +174,9 @@ class InsertOperation extends QueryBuilderOperation {
96
174
  return this.models;
97
175
  }
98
176
 
99
- onAfter2(builder, models) {
100
- const result = this.isArray ? models : models[0] || null;
101
- 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;
102
180
  }
103
181
 
104
182
  toFindOperation() {
@@ -109,12 +187,19 @@ class InsertOperation extends QueryBuilderOperation {
109
187
  const clone = super.clone();
110
188
 
111
189
  clone.models = this.models;
190
+ clone.batches = this.batches;
112
191
  clone.isArray = this.isArray;
113
192
 
114
193
  return clone;
115
194
  }
116
195
  }
117
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
+
118
203
  // Returns `null` if there's nothing to return, e.g. for models without an `idColumn`.
119
204
  function getDefaultReturning(builder) {
120
205
  const idColumns = builder.modelClass().getIdColumnArray();
@@ -178,6 +263,8 @@ function mergeMatchingRows(builder, models, rows) {
178
263
  }
179
264
  });
180
265
 
266
+ const options = { knex: builder.knex() };
267
+
181
268
  for (const row of rows) {
182
269
  const indices = indicesByKey.get(createKey(row));
183
270
  const index = indices ? indices.shift() : undefined;
@@ -186,7 +273,7 @@ function mergeMatchingRows(builder, models, rows) {
186
273
  throw createMatchError();
187
274
  }
188
275
 
189
- models[index].$setDatabaseJson(row);
276
+ models[index].$setDatabaseJson(row, options);
190
277
  }
191
278
  }
192
279
 
@@ -222,28 +309,16 @@ function callStaticBeforeInsert(builder) {
222
309
  return builder.modelClass().beforeInsert(args);
223
310
  }
224
311
 
225
- function callAfterInsert(builder, models, result) {
226
- const maybePromise = callInstanceAfterInsert(builder, models);
227
- return after(maybePromise, () => callStaticAfterInsert(builder, result));
228
- }
229
-
230
312
  function callInstanceAfterInsert(builder, models) {
231
313
  return mapAfterAllReturn(models, (model) => model.$afterInsert(builder.context()), models);
232
314
  }
233
315
 
234
- function callStaticAfterInsert(builder, result) {
235
- const args = StaticHookArguments.create({ builder, result });
236
- const maybePromise = builder.modelClass().afterInsert(args);
237
-
238
- return after(maybePromise, (maybeResult) => {
239
- if (maybeResult === undefined) {
240
- return result;
241
- } else {
242
- 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);
243
320
  }
244
- });
245
- }
321
+ }
246
322
 
247
- module.exports = {
248
- InsertOperation,
249
- };
323
+ return json;
324
+ }