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,17 +1,13 @@
1
- 'use strict';
2
-
3
- const { UpdateOperation } = require('../../../queryBuilder/operations/UpdateOperation');
4
- const { addWhereGroup } = require('../../../queryBuilder/whereGroups');
5
- const { chunk } = require('../../../utils/objectUtils');
6
- const { isMySql, isMsSql } = require('../../../utils/knexUtils');
7
-
8
- // Stay below the limits of bound values per statement of SQLite before 3.32
9
- // (999) and SQL Server (2100), leaving room for the patched values:
10
- const maxBatchValues = 500;
1
+ import { UpdateOperation } from '../../../queryBuilder/operations/UpdateOperation.js';
2
+ import { addWhereGroup } from '../../../queryBuilder/whereGroups.js';
3
+ import { isMySql, isMsSql, whereInKeys } from '../../../utils/knexUtils.js';
4
+ import { getWindowOrder, rowNumberColumn } from '../../../queryBuilder/operations/windowOrder.js';
11
5
 
12
6
  const LimitSelector = /^(orderBy\w*|limit|offset)$/;
7
+ // Without underscores, so that column name mappers don't change it.
8
+ const relatedPropColumn = 'objectiontmprelated';
13
9
 
14
- class ManyToManyUpdateOperationBase extends UpdateOperation {
10
+ export class ManyToManyUpdateOperationBase extends UpdateOperation {
15
11
  constructor(name, opt) {
16
12
  super(name, opt);
17
13
 
@@ -37,9 +33,15 @@ class ManyToManyUpdateOperationBase extends UpdateOperation {
37
33
  // table. On MySQL, concurrent updates with that subquery deadlock (#135).
38
34
  this.skipRelationFilter = builder.internalOptions().skipRelationFilter;
39
35
 
40
- // Copy all extra properties to the `joinTablePatch` object.
36
+ // Copy the extra properties to the `joinTablePatch` object, or the ones
37
+ // that `upsertGraph()` writes:
38
+ const { joinTableExtras } = builder.internalOptions();
39
+
41
40
  for (const extra of this.relation.joinTableExtras) {
42
- if (extra.aliasProp in obj) {
41
+ if (
42
+ extra.aliasProp in obj &&
43
+ (!joinTableExtras || joinTableExtras.includes(extra.aliasProp))
44
+ ) {
43
45
  this.hasExtraProps = true;
44
46
  this.joinTablePatch[extra.joinTableProp] = obj[extra.aliasProp];
45
47
  }
@@ -74,7 +76,6 @@ class ManyToManyUpdateOperationBase extends UpdateOperation {
74
76
  // `onAfterBuild()`.
75
77
  this.relatedIdsQuery = this.createRelatedIdsQuery(builder, hasLimit);
76
78
  if (hasLimit) {
77
- this.relatedIdsQuery.copyFrom(builder, LimitSelector);
78
79
  builder.clear(LimitSelector);
79
80
  }
80
81
  }
@@ -82,24 +83,47 @@ class ManyToManyUpdateOperationBase extends UpdateOperation {
82
83
  return super.onBuild(builder);
83
84
  }
84
85
 
85
- // Selects the ids of the related rows to update. Fetch raw rows, so that no
86
- // hooks run for them.
86
+ // Select the ids of the related rows to update from the filter subquery
87
+ // itself. Filtering the related table by them again lets Postgres pick plans
88
+ // that run the subquery once per related row, which takes minutes for a few
89
+ // thousand (#161). Fetch raw rows, so that no hooks run for them.
87
90
  createRelatedIdsQuery(builder, hasLimit) {
88
- const { relatedModelClass } = this.relation;
91
+ const { relatedModelClass, relatedProp } = this.relation;
92
+ const idProperty = relatedModelClass.getIdRelationProperty();
93
+ const filterQuery = this.modifyFilterSubquery.clone();
94
+ const idRefs = idProperty.refs(filterQuery);
89
95
 
90
96
  if (hasLimit) {
91
- // The limit picks related rows, not join rows, so filter the related
92
- // table by the ids of the matching join rows:
93
- const relatedIdsQuery = relatedModelClass.query().childQueryOf(builder);
94
- const idRefs = relatedModelClass.getIdRelationProperty().refs(relatedIdsQuery);
95
- return this.applyModifyFilterForRelatedTable(relatedIdsQuery).select(idRefs);
97
+ // The join rows refer to the related rows by their `relatedProp`, which
98
+ // isn't necessarily their id (#360). We select it after the ids, aliased
99
+ // as it can be the same columns:
100
+ const relatedPropColumns = relatedProp.cols.map((_, index) => `${relatedPropColumn}${index}`);
101
+ const columns = [...idProperty.cols, ...relatedPropColumns];
102
+
103
+ // The filter subquery returns a row per join row, and `distinct` can't
104
+ // order by columns that it doesn't select. So we number the rows in the
105
+ // order of the query, and the limit picks the related rows by their
106
+ // first row:
107
+ const order = getWindowOrder(builder, builder.knex(), builder.tableRef());
108
+ const numberedQuery = filterQuery
109
+ .select([
110
+ ...idRefs,
111
+ ...relatedProp.refs(filterQuery).map((ref, index) => ref.as(relatedPropColumns[index])),
112
+ ])
113
+ .onBuildKnex((knexBuilder) =>
114
+ knexBuilder.rowNumber(rowNumberColumn, (window) => window.orderBy(order)),
115
+ );
116
+
117
+ return relatedModelClass
118
+ .query()
119
+ .childQueryOf(builder)
120
+ .from(numberedQuery.as(rowNumberColumn))
121
+ .select(columns)
122
+ .groupBy(columns)
123
+ .orderByRaw('min(??)', [rowNumberColumn])
124
+ .copyFrom(builder, /^(limit|offset)$/);
96
125
  } else {
97
- // Select the ids from the filter subquery itself. Filtering the related
98
- // table by them again lets Postgres pick plans that run the subquery
99
- // once per related row, which takes minutes for a few thousand (#161).
100
- const relatedIdsQuery = this.modifyFilterSubquery.clone();
101
- const idRefs = relatedModelClass.getIdRelationProperty().refs(relatedIdsQuery);
102
- return relatedIdsQuery.distinct(idRefs);
126
+ return filterQuery.distinct(idRefs);
103
127
  }
104
128
  }
105
129
 
@@ -107,25 +131,28 @@ class ManyToManyUpdateOperationBase extends UpdateOperation {
107
131
  // match them (#161). A query resolved without updating anything, e.g. with
108
132
  // `none()`, leaves the join rows untouched too.
109
133
  async onAfterBuild(builder) {
134
+ // An offset that `onBuild()` moved to the ids query is honoured, and
135
+ // doesn't throw.
136
+ super.onAfterBuild(builder);
110
137
  if (this.hasExtraProps && !this.isResolvedWithoutUpdate(builder)) {
138
+ let relatedValues = null;
111
139
  if (this.relatedIdsQuery) {
112
140
  // The filters can also reference the extras that the join rows change,
113
141
  // so identify the related rows to modify first.
114
142
  const rows = await this.relatedIdsQuery.toKnexQuery();
115
- this.relatedIds = rows.map((row) => Object.values(row));
116
- }
117
-
118
- let numJoinRowsUpdated;
119
- if (this.relatedIdsQuery?.has(/^(limit|offset)$/)) {
120
- // The filters match the join rows of more related rows than the limit
121
- // picks, so only update the join rows of the picked ones.
122
- for (const ids of this.relatedIdBatches()) {
123
- await this.updateJoinRows(builder, ids);
143
+ const values = rows.map((row) => Object.values(row));
144
+ const { size } = this.relation.relatedModelClass.getIdRelationProperty();
145
+ this.relatedIds = values.map((row) => row.slice(0, size));
146
+ // With a limit, the filters match the join rows of more related rows
147
+ // than the limit picks, so only update the join rows of the picked
148
+ // ones, by the `relatedProp` values that follow their ids.
149
+ if (this.relatedIdsQuery.has(/^(limit|offset)$/)) {
150
+ relatedValues = values.map((row) => row.slice(size));
124
151
  }
125
- } else {
126
- numJoinRowsUpdated = await this.updateJoinRows(builder);
127
152
  }
128
153
 
154
+ const numJoinRowsUpdated = await this.updateJoinRows(builder, relatedValues);
155
+
129
156
  if (this.hasNothingToUpdate) {
130
157
  // Only the join rows change, so count the related rows that they
131
158
  // belong to, as the update of the related rows does. Without their
@@ -136,7 +163,15 @@ class ManyToManyUpdateOperationBase extends UpdateOperation {
136
163
  }
137
164
  }
138
165
 
139
- updateJoinRows(builder, relatedIds = null) {
166
+ // Changes of only the extras still write the join rows, see `onAfterBuild()`.
167
+ // @override
168
+ isResolvedWithoutWrite(builder) {
169
+ return (
170
+ super.isResolvedWithoutWrite(builder) && !(this.hasExtraProps && this.hasNothingToUpdate)
171
+ );
172
+ }
173
+
174
+ updateJoinRows(builder, relatedValues = null) {
140
175
  const joinTableUpdateQuery = this.relation
141
176
  .getJoinModelClass(builder.knex())
142
177
  .query()
@@ -148,11 +183,12 @@ class ManyToManyUpdateOperationBase extends UpdateOperation {
148
183
  ? this.applyIdFilterForJoinTable(joinTableUpdateQuery)
149
184
  : this.applyModifyFilterForJoinTable(joinTableUpdateQuery),
150
185
  );
151
- if (relatedIds) {
186
+ if (relatedValues) {
152
187
  addWhereGroup(joinTableUpdateQuery, () =>
153
- joinTableUpdateQuery.whereInComposite(
188
+ whereInKeys(
189
+ joinTableUpdateQuery,
154
190
  this.relation.joinTableRelatedProp.refs(joinTableUpdateQuery),
155
- relatedIds,
191
+ relatedValues,
156
192
  ),
157
193
  );
158
194
  }
@@ -163,23 +199,6 @@ class ManyToManyUpdateOperationBase extends UpdateOperation {
163
199
  return joinTableUpdateQuery;
164
200
  }
165
201
 
166
- // Update the related rows in batches of their ids, as databases limit the
167
- // number of values in one statement.
168
- queryBatches(builder) {
169
- if (this.relatedIds) {
170
- const batches = this.relatedIdBatches();
171
- // Without ids, still execute the query once for the dialect's result:
172
- return batches.length > 0 ? batches : [[]];
173
- } else {
174
- return null;
175
- }
176
- }
177
-
178
- relatedIdBatches() {
179
- const idSize = this.relation.relatedModelClass.getIdRelationProperty().size;
180
- return chunk(this.relatedIds, Math.floor(maxBatchValues / idSize));
181
- }
182
-
183
202
  // Filters the join rows by the ids of the owner and the updated model.
184
203
  applyIdFilterForJoinTable(builder) {
185
204
  return builder
@@ -215,7 +234,3 @@ class ManyToManyUpdateOperationBase extends UpdateOperation {
215
234
  return clone;
216
235
  }
217
236
  }
218
-
219
- module.exports = {
220
- ManyToManyUpdateOperationBase,
221
- };
@@ -1,12 +1,6 @@
1
- 'use strict';
1
+ import { ManyToManyUpdateOperationBase } from './ManyToManyUpdateOperationBase.js';
2
+ import { ManyToManySqliteModifyMixin } from '../ManyToManySqliteModifyMixin.js';
2
3
 
3
- const { ManyToManyUpdateOperationBase } = require('./ManyToManyUpdateOperationBase');
4
- const { ManyToManySqliteModifyMixin } = require('../ManyToManySqliteModifyMixin');
5
-
6
- class ManyToManyUpdateSqliteOperation extends ManyToManySqliteModifyMixin(
4
+ export class ManyToManyUpdateSqliteOperation extends ManyToManySqliteModifyMixin(
7
5
  ManyToManyUpdateOperationBase,
8
6
  ) {}
9
-
10
- module.exports = {
11
- ManyToManyUpdateSqliteOperation,
12
- };
@@ -1,9 +1,7 @@
1
- 'use strict';
1
+ import * as promiseUtils from './utils/promiseUtils/index.js';
2
+ import { isFunction } from './utils/objectUtils.js';
2
3
 
3
- const promiseUtils = require('./utils/promiseUtils');
4
- const { isFunction } = require('./utils/objectUtils');
5
-
6
- function transaction() {
4
+ export function transaction() {
7
5
  // There must be at least one model class and the callback.
8
6
  if (arguments.length < 2) {
9
7
  return Promise.reject(
@@ -90,7 +88,3 @@ transaction.start = function (modelClassOrKnex) {
90
88
  function isModelClass(maybeModel) {
91
89
  return isFunction(maybeModel) && maybeModel.isObjectionModelClass;
92
90
  }
93
-
94
- module.exports = {
95
- transaction,
96
- };
@@ -1,12 +1,10 @@
1
- 'use strict';
2
-
3
- function assertHasIdColumn(modelClass) {
1
+ export function assertHasIdColumn(modelClass) {
4
2
  if (modelClass.getIdColumnArray().length === 0) {
5
3
  throw new Error(`model ${modelClass.name} has no idColumn`);
6
4
  }
7
5
  }
8
6
 
9
- function assertHasId(model) {
7
+ export function assertHasId(model) {
10
8
  assertHasIdColumn(model.constructor);
11
9
 
12
10
  if (!model.$hasId()) {
@@ -19,16 +17,10 @@ function assertHasId(model) {
19
17
  }
20
18
  }
21
19
 
22
- function assertIdNotUndefined(id, message) {
20
+ export function assertIdNotUndefined(id, message) {
23
21
  if (Array.isArray(id)) {
24
22
  id.forEach((id) => assertIdNotUndefined(id, message));
25
23
  } else if (id === undefined) {
26
24
  throw Error(message);
27
25
  }
28
26
  }
29
-
30
- module.exports = {
31
- assertHasId,
32
- assertHasIdColumn,
33
- assertIdNotUndefined,
34
- };
@@ -1,8 +1,6 @@
1
- 'use strict';
1
+ import { isObject, isFunction } from './objectUtils.js';
2
2
 
3
- const { isObject, isFunction } = require('./objectUtils');
4
-
5
- function buildArg(arg, builder) {
3
+ export function buildArg(arg, builder) {
6
4
  if (!isObject(arg)) {
7
5
  return arg;
8
6
  }
@@ -15,7 +13,3 @@ function buildArg(arg, builder) {
15
13
  return arg;
16
14
  }
17
15
  }
18
-
19
- module.exports = {
20
- buildArg,
21
- };
@@ -1,13 +1,7 @@
1
- 'use strict';
2
-
3
- function inherit(Constructor, BaseConstructor) {
1
+ export function inherit(Constructor, BaseConstructor) {
4
2
  Constructor.prototype = Object.create(BaseConstructor.prototype);
5
3
  Constructor.prototype.constructor = BaseConstructor;
6
4
  Object.setPrototypeOf(Constructor, BaseConstructor);
7
5
 
8
6
  return Constructor;
9
7
  }
10
-
11
- module.exports = {
12
- inherit,
13
- };
@@ -1,8 +1,6 @@
1
- 'use strict';
1
+ import { asArray, isString, isFunction, isPlainObject } from './objectUtils.js';
2
2
 
3
- const { asArray, isString, isFunction, isPlainObject } = require('./objectUtils');
4
-
5
- function createModifier({ modelClass, modifier, modifiers }) {
3
+ export function createModifier({ modelClass, modifier, modifiers }) {
6
4
  const modelModifiers = modelClass ? modelClass.getModifiers() : {};
7
5
 
8
6
  const modifierFunctions = asArray(modifier).map((modifier) => {
@@ -36,7 +34,3 @@ function createModifier({ modelClass, modifier, modifiers }) {
36
34
  }
37
35
  };
38
36
  }
39
-
40
- module.exports = {
41
- createModifier,
42
- };
@@ -1,6 +1,5 @@
1
- 'use strict';
2
-
3
- const { isObject } = require('./objectUtils');
1
+ import { isObject } from './objectUtils.js';
2
+ import { isFieldExpressionKey } from './parseFieldExpression.js';
4
3
 
5
4
  // Super fast memoize for single argument functions.
6
5
  function memoize(func) {
@@ -21,7 +20,7 @@ function memoize(func) {
21
20
  // camelCase to snake_case converter that also works with non-ascii characters
22
21
  // This is needed especially so that aliases containing the `:` character,
23
22
  // objection uses internally, work.
24
- function snakeCase(
23
+ export function snakeCase(
25
24
  str,
26
25
  {
27
26
  upperCase = false,
@@ -90,7 +89,7 @@ function snakeCase(
90
89
 
91
90
  // snake_case to camelCase converter that simply reverses
92
91
  // the actions done by `snakeCase` function.
93
- function camelCase(str, { upperCase = false } = {}) {
92
+ export function camelCase(str, { upperCase = false } = {}) {
94
93
  if (str.length === 0) {
95
94
  return str;
96
95
  }
@@ -149,9 +148,10 @@ function mapLastPart(mapper, separator) {
149
148
  }
150
149
 
151
150
  // Returns a function that takes an object as an input and maps the object's keys
152
- // using `mapper`. If the input is not an object, the input is returned unchanged.
151
+ // using `mapper`, passing on `arg`. If the input is not an object, the input is
152
+ // returned unchanged.
153
153
  function keyMapper(mapper) {
154
- return (obj) => {
154
+ return (obj, arg) => {
155
155
  if (!isObject(obj) || Array.isArray(obj)) {
156
156
  return obj;
157
157
  }
@@ -161,7 +161,7 @@ function keyMapper(mapper) {
161
161
 
162
162
  for (let i = 0, l = keys.length; i < l; ++i) {
163
163
  const key = keys[i];
164
- out[mapper(key)] = obj[key];
164
+ out[mapper(key, arg)] = obj[key];
165
165
  }
166
166
 
167
167
  return out;
@@ -171,8 +171,7 @@ function keyMapper(mapper) {
171
171
  // Returns a function that only calls `mapper` for the part of the input string
172
172
  // before the first `separator`, and leaves the rest untouched. For field
173
173
  // expressions like `jsonColumn:some.jsonPath` this maps the column but keeps
174
- // the json path as is. The mapper doesn't know the schema, so the first `:`
175
- // marks the boundary also in a declared column name like `ns:name`.
174
+ // the json path as is.
176
175
  function mapFirstPart(mapper, separator) {
177
176
  return (str) => {
178
177
  const idx = str.indexOf(separator);
@@ -180,16 +179,22 @@ function mapFirstPart(mapper, separator) {
180
179
  };
181
180
  }
182
181
 
183
- function snakeCaseMappers(opt = {}) {
184
- const format = (str) => snakeCase(str, opt);
182
+ export function snakeCaseMappers(opt = {}) {
183
+ const { preserveJsonKeys = true } = opt;
184
+ const formatColumn = memoize((str) => snakeCase(str, opt));
185
+ const formatFieldExpression = memoize(mapFirstPart(formatColumn, ':'));
185
186
 
186
187
  return {
187
188
  parse: keyMapper(memoize((str) => camelCase(str, opt))),
188
- format: keyMapper(memoize(opt.preserveJsonKeys ? mapFirstPart(format, ':') : format)),
189
+ // Models pass `isFieldExpression()`, which knows the columns with a `:` that
190
+ // their schema declares, like `ns:fooBar`. These are converted as a whole.
191
+ format: keyMapper((key, isFieldExpression = isFieldExpressionKey) =>
192
+ preserveJsonKeys && isFieldExpression(key) ? formatFieldExpression(key) : formatColumn(key),
193
+ ),
189
194
  };
190
195
  }
191
196
 
192
- function knexIdentifierMappers({ parse, format, idSeparator = ':' } = {}) {
197
+ export function knexIdentifierMappers({ parse, format, idSeparator = ':' } = {}) {
193
198
  const formatId = memoize(mapLastPart(format, idSeparator));
194
199
  const parseId = memoize(mapLastPart(parse, idSeparator));
195
200
  const parseKeys = keyMapper(parseId);
@@ -215,14 +220,14 @@ function knexIdentifierMappers({ parse, format, idSeparator = ':' } = {}) {
215
220
  };
216
221
  }
217
222
 
218
- function knexSnakeCaseMappers(opt = {}) {
223
+ export function knexSnakeCaseMappers(opt = {}) {
219
224
  return knexIdentifierMappers({
220
225
  parse: (str) => camelCase(str, opt),
221
226
  format: (str) => snakeCase(str, opt),
222
227
  });
223
228
  }
224
229
 
225
- function knexIdentifierMapping(colToProp) {
230
+ export function knexIdentifierMapping(colToProp) {
226
231
  const propToCol = Object.keys(colToProp).reduce((propToCol, column) => {
227
232
  propToCol[colToProp[column]] = column;
228
233
  return propToCol;
@@ -234,14 +239,5 @@ function knexIdentifierMapping(colToProp) {
234
239
  });
235
240
  }
236
241
 
237
- module.exports = {
238
- snakeCase,
239
- camelCase,
240
- snakeCaseMappers,
241
- knexSnakeCaseMappers,
242
- knexIdentifierMappers,
243
- knexIdentifierMapping,
244
-
245
- camelCaseKeys: keyMapper(memoize(camelCase)),
246
- snakeCaseKeys: keyMapper(memoize(snakeCase)),
247
- };
242
+ export const camelCaseKeys = keyMapper(memoize(camelCase));
243
+ export const snakeCaseKeys = keyMapper(memoize(snakeCase));
@@ -1,11 +1,5 @@
1
- 'use strict';
2
-
3
1
  const INTERNAL_PROP_PREFIX = '$';
4
2
 
5
- function isInternalProp(propName) {
3
+ export function isInternalProp(propName) {
6
4
  return propName[0] === INTERNAL_PROP_PREFIX;
7
5
  }
8
-
9
- module.exports = {
10
- isInternalProp,
11
- };
@@ -1,8 +1,6 @@
1
- 'use strict';
1
+ import { isObject, isFunction, isString, isNumber, asSingle } from '../utils/objectUtils.js';
2
2
 
3
- const { isObject, isFunction } = require('../utils/objectUtils');
4
-
5
- function getDialect(knex) {
3
+ export function getDialect(knex) {
6
4
  const type = typeof knex;
7
5
 
8
6
  return (
@@ -14,48 +12,109 @@ function getDialect(knex) {
14
12
  );
15
13
  }
16
14
 
17
- function isPostgres(knex) {
15
+ export function isPostgres(knex) {
18
16
  return getDialect(knex) === 'postgresql';
19
17
  }
20
18
 
21
- function isOracle(knex) {
19
+ export function isOracle(knex) {
22
20
  const dialect = getDialect(knex);
23
21
  return dialect === 'oracle' || dialect === 'oracledb';
24
22
  }
25
23
 
26
- function isMySql(knex) {
24
+ export function isMySql(knex) {
27
25
  const dialect = getDialect(knex);
28
26
  return dialect === 'mysql' || dialect === 'mysql2';
29
27
  }
30
28
 
31
- function isSqlite(knex) {
29
+ export function isSqlite(knex) {
32
30
  return getDialect(knex) === 'sqlite3';
33
31
  }
34
32
 
35
- function isMsSql(knex) {
33
+ export function isMsSql(knex) {
36
34
  return getDialect(knex) === 'mssql';
37
35
  }
38
36
 
39
- // Only Postgres and SQL Server return the identifiers of all the rows inserted
40
- // by one query.
41
- function hasBatchInsert(knex) {
42
- return isPostgres(knex) || isMsSql(knex);
37
+ // Postgres, SQL Server and SQLite (through `returning`, since SQLite 3.35)
38
+ // return the identifiers of all the rows inserted by one query.
39
+ export function hasBatchInsert(knex) {
40
+ return isPostgres(knex) || isMsSql(knex) || isSqlite(knex);
43
41
  }
44
42
 
45
- // MySQL supports window functions since 8.0, MariaDB since 10.2. Without a
46
- // version, knex assumes the latest one, and so do we.
47
- function hasWindowFunctions(knex) {
48
- const { version, isMariaDB } = knex.client;
43
+ // knex inserts the rows of a SQLite batch with `select ... union all`, which
44
+ // fills the columns that a row leaves out with NULL, not with their defaults.
45
+ export function hasBatchInsertDefaults(knex) {
46
+ return !isSqlite(knex);
47
+ }
49
48
 
50
- if (isMySql(knex) && version) {
51
- const [major, minor] = version.split('.').map(Number);
52
- return isMariaDB ? major > 10 || (major === 10 && minor >= 2) : major >= 8;
49
+ // The number of rows that fit into one query if each binds `parameters` values.
50
+ // SQL Server binds 2100 values, Postgres 65535 and SQLite 999 (32766 since 3.32,
51
+ // but builds may be older), and we leave a margin for the values that aren't
52
+ // rows. The MySQL drivers inline the values in the query.
53
+ export function getMaxRows(knex, parameters) {
54
+ const maxParameters = isMsSql(knex)
55
+ ? 2000
56
+ : isPostgres(knex)
57
+ ? 65000
58
+ : isSqlite(knex)
59
+ ? 900
60
+ : Infinity;
61
+ return Math.max(1, Math.floor(maxParameters / parameters));
62
+ }
63
+
64
+ // Filter the columns of `refs` by a list of keys, which are arrays of values for
65
+ // composite keys, with as few bound values as possible, see `getMaxRows()`:
66
+ // Postgres binds single keys as one array, SQLite and SQL Server (2016 or newer
67
+ // for `openjson`) all keys as one JSON array, and the MySQL drivers inline the
68
+ // values. Composite keys on Postgres and keys that JSON can't represent, like
69
+ // binary ids, bind one value per column.
70
+ export function whereInKeys(builder, refs, keys) {
71
+ const knex = builder.knex();
72
+ const isComposite = refs.length > 1;
73
+ const values = isComposite ? keys : keys.map(asSingle);
74
+ const json = values.flat().every((value) => isString(value) || isNumber(value))
75
+ ? JSON.stringify(values)
76
+ : null;
77
+
78
+ if (isPostgres(knex) && !isComposite) {
79
+ return builder.whereRaw('? = any(?)', [refs[0], values]);
80
+ } else if (json && isSqlite(knex) && isComposite) {
81
+ const columns = refs.map(() => '?').join(', ');
82
+ const selects = refs.map((_, index) => `json_extract(value, '$[${index}]')`).join(', ');
83
+ return builder.whereRaw(`(${columns}) in (select ${selects} from json_each(?))`, [
84
+ ...refs,
85
+ json,
86
+ ]);
87
+ } else if (json && isSqlite(knex)) {
88
+ return builder.whereRaw('? in (select value from json_each(?))', [refs[0], json]);
89
+ } else if (json && isMsSql(knex) && isComposite) {
90
+ // SQL Server doesn't support row values in `in`:
91
+ const conditions = refs.map((_, index) => `? = json_value(value, '$[${index}]')`).join(' and ');
92
+ return builder.whereRaw(`exists (select 1 from openjson(?) where ${conditions})`, [
93
+ json,
94
+ ...refs,
95
+ ]);
96
+ } else if (json && isMsSql(knex)) {
97
+ return builder.whereRaw('? in (select value from openjson(?))', [refs[0], json]);
53
98
  } else {
54
- return true;
99
+ return builder.whereInComposite(refs, keys);
55
100
  }
56
101
  }
57
102
 
58
- function isKnexQueryBuilder(value) {
103
+ // The number of rows that one insert query can take: `getMaxRows()`, and the
104
+ // limits on rows: SQLite compiles the rows to `select ... union all`, and limits
105
+ // a compound select to 500 terms, and SQL Server limits `values` to 1000 rows.
106
+ export function getMaxInsertRows(knex, parameters) {
107
+ const maxRows = isSqlite(knex) ? 500 : isMsSql(knex) ? 1000 : Infinity;
108
+ return Math.min(maxRows, getMaxRows(knex, parameters));
109
+ }
110
+
111
+ // The `pg` drivers return `json` and `jsonb` columns parsed, and `text` columns
112
+ // as text.
113
+ export function isJsonParsedByDriver(knex) {
114
+ return ['pg', 'pgnative', 'cockroachdb'].includes(knex.client.driverName);
115
+ }
116
+
117
+ export function isKnexQueryBuilder(value) {
59
118
  return (
60
119
  hasConstructor(value) &&
61
120
  isFunction(value.select) &&
@@ -65,33 +124,18 @@ function isKnexQueryBuilder(value) {
65
124
  );
66
125
  }
67
126
 
68
- function isKnexJoinBuilder(value) {
127
+ export function isKnexJoinBuilder(value) {
69
128
  return hasConstructor(value) && value.grouping === 'join' && 'joinType' in value;
70
129
  }
71
130
 
72
- function isKnexRaw(value) {
131
+ export function isKnexRaw(value) {
73
132
  return hasConstructor(value) && value.isRawInstance && 'client' in value;
74
133
  }
75
134
 
76
- function isKnexTransaction(knex) {
135
+ export function isKnexTransaction(knex) {
77
136
  return !!getDialect(knex) && isFunction(knex.commit) && isFunction(knex.rollback);
78
137
  }
79
138
 
80
139
  function hasConstructor(value) {
81
140
  return isObject(value) && isFunction(value.constructor);
82
141
  }
83
-
84
- module.exports = {
85
- getDialect,
86
- isPostgres,
87
- isMySql,
88
- isSqlite,
89
- isMsSql,
90
- isOracle,
91
- hasBatchInsert,
92
- hasWindowFunctions,
93
- isKnexQueryBuilder,
94
- isKnexJoinBuilder,
95
- isKnexRaw,
96
- isKnexTransaction,
97
- };