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.
- package/lib/dbErrors/LICENSE +21 -0
- package/lib/dbErrors/errorCodes/mssql.js +19 -0
- package/lib/dbErrors/errorCodes/mysql.js +805 -0
- package/lib/dbErrors/errorCodes/postgres.js +241 -0
- package/lib/dbErrors/errors/CheckViolationError.js +10 -0
- package/lib/dbErrors/errors/ConstraintViolationError.js +3 -0
- package/lib/dbErrors/errors/DBError.js +9 -0
- package/lib/dbErrors/errors/DataError.js +3 -0
- package/lib/dbErrors/errors/ForeignKeyViolationError.js +11 -0
- package/lib/dbErrors/errors/NotNullViolationError.js +12 -0
- package/lib/dbErrors/errors/UniqueViolationError.js +12 -0
- package/lib/dbErrors/index.js +59 -0
- package/lib/dbErrors/parsers/mssql/DBError/CheckViolationError/parser.js +28 -0
- package/lib/dbErrors/parsers/mssql/DBError/DataError/parser.js +25 -0
- package/lib/dbErrors/parsers/mssql/DBError/ForeignKeyViolationError/parser.js +39 -0
- package/lib/dbErrors/parsers/mssql/DBError/NotNullViolationError/parser.js +30 -0
- package/lib/dbErrors/parsers/mssql/DBError/UniqueViolationError/parser.js +53 -0
- package/lib/dbErrors/parsers/mssql/DBError/parser.js +51 -0
- package/lib/dbErrors/parsers/mssql/DBError/util.js +16 -0
- package/lib/dbErrors/parsers/mysql/DBError/ConstraintViolationError/ForeignKeyViolationError/parser.js +43 -0
- package/lib/dbErrors/parsers/mysql/DBError/ConstraintViolationError/NotNullViolationError/parser.js +29 -0
- package/lib/dbErrors/parsers/mysql/DBError/ConstraintViolationError/UniqueViolationError/parser.js +27 -0
- package/lib/dbErrors/parsers/mysql/DBError/ConstraintViolationError/parser.js +23 -0
- package/lib/dbErrors/parsers/mysql/DBError/DataError/parser.js +24 -0
- package/lib/dbErrors/parsers/mysql/DBError/parser.js +28 -0
- package/lib/dbErrors/parsers/postgres/DBError/ConstraintViolationError/CheckViolationError/parser.js +18 -0
- package/lib/dbErrors/parsers/postgres/DBError/ConstraintViolationError/ForeignKeyViolationError/parser.js +18 -0
- package/lib/dbErrors/parsers/postgres/DBError/ConstraintViolationError/NotNullViolationError/parser.js +18 -0
- package/lib/dbErrors/parsers/postgres/DBError/ConstraintViolationError/UniqueViolationError/parser.js +40 -0
- package/lib/dbErrors/parsers/postgres/DBError/ConstraintViolationError/parser.js +25 -0
- package/lib/dbErrors/parsers/postgres/DBError/DataError/parser.js +16 -0
- package/lib/dbErrors/parsers/postgres/DBError/parser.js +27 -0
- package/lib/dbErrors/parsers/sqlite/DBError/ConstraintViolationError/CheckViolationError/parser.js +20 -0
- package/lib/dbErrors/parsers/sqlite/DBError/ConstraintViolationError/ForeignKeyViolationError/parser.js +20 -0
- package/lib/dbErrors/parsers/sqlite/DBError/ConstraintViolationError/NotNullViolationError/parser.js +27 -0
- package/lib/dbErrors/parsers/sqlite/DBError/ConstraintViolationError/UniqueViolationError/parser.js +28 -0
- package/lib/dbErrors/parsers/sqlite/DBError/ConstraintViolationError/parser.js +24 -0
- package/lib/dbErrors/parsers/sqlite/DBError/parser.js +23 -0
- package/lib/dbErrors/utils/sqlState.js +3 -0
- package/lib/initialize.js +1 -7
- package/lib/model/AjvValidator.js +51 -117
- package/lib/model/Model.js +84 -59
- package/lib/model/ModifierNotFoundError.js +1 -7
- package/lib/model/NotFoundError.js +1 -7
- package/lib/model/RelationDoesNotExistError.js +1 -7
- package/lib/model/ValidationError.js +3 -10
- package/lib/model/Validator.js +1 -7
- package/lib/model/getModel.js +7 -6
- package/lib/model/inheritModel.js +1 -7
- package/lib/model/modelBindKnex.js +4 -10
- package/lib/model/modelClone.js +5 -11
- package/lib/model/modelColPropMap.js +3 -10
- package/lib/model/modelId.js +3 -10
- package/lib/model/modelJsonAttributes.js +35 -16
- package/lib/model/modelParseRelations.js +2 -8
- package/lib/model/modelQueryProps.js +11 -23
- package/lib/model/modelSet.js +89 -41
- package/lib/model/modelTableMetadata.js +4 -11
- package/lib/model/modelToJson.js +6 -13
- package/lib/model/modelUtils.js +14 -13
- package/lib/model/modelValidate.js +3 -9
- package/lib/model/modelValues.js +5 -14
- package/lib/model/modelVisitor.js +1 -7
- package/lib/objection.js +33 -71
- package/lib/queryBuilder/FunctionBuilder.js +4 -11
- package/lib/queryBuilder/InternalOptions.js +4 -9
- package/lib/queryBuilder/JoinBuilder.js +5 -8
- package/lib/queryBuilder/QueryBuilder.js +126 -95
- package/lib/queryBuilder/QueryBuilderBase.js +41 -123
- package/lib/queryBuilder/QueryBuilderContext.js +2 -8
- package/lib/queryBuilder/QueryBuilderContextBase.js +2 -8
- package/lib/queryBuilder/QueryBuilderOperationSupport.js +7 -21
- package/lib/queryBuilder/QueryBuilderUserContext.js +1 -7
- package/lib/queryBuilder/RawBuilder.js +5 -13
- package/lib/queryBuilder/ReferenceBuilder.js +20 -48
- package/lib/queryBuilder/RelationExpression.js +18 -16
- package/lib/queryBuilder/StaticHookArguments.js +74 -16
- package/lib/queryBuilder/ValueBuilder.js +11 -13
- package/lib/queryBuilder/getJoinBuilder.js +10 -0
- package/lib/queryBuilder/graph/GraphLoader.js +314 -0
- package/lib/queryBuilder/graph/GraphNode.js +241 -0
- package/lib/queryBuilder/graph/GraphOptions.js +55 -248
- package/lib/queryBuilder/graph/GraphPlan.js +431 -0
- package/lib/queryBuilder/graph/GraphSchedule.js +513 -0
- package/lib/queryBuilder/graph/GraphUpsert.js +519 -412
- package/lib/queryBuilder/graph/GraphWriter.js +508 -0
- package/lib/queryBuilder/graph/graphKeys.js +929 -0
- package/lib/queryBuilder/join/JoinResultColumn.js +1 -7
- package/lib/queryBuilder/join/JoinResultParser.js +6 -11
- package/lib/queryBuilder/join/RelationJoiner.js +66 -84
- package/lib/queryBuilder/join/TableNode.js +2 -8
- package/lib/queryBuilder/join/TableTree.js +3 -9
- package/lib/queryBuilder/join/utils.js +5 -15
- package/lib/queryBuilder/jsonDialects/JsonDialect.js +51 -0
- package/lib/queryBuilder/jsonDialects/MySqlJsonDialect.js +81 -0
- package/lib/queryBuilder/jsonDialects/PostgresJsonDialect.js +45 -0
- package/lib/queryBuilder/jsonDialects/SqliteJsonDialect.js +67 -0
- package/lib/queryBuilder/jsonDialects/index.js +44 -0
- package/lib/queryBuilder/operations/DelegateOperation.js +2 -8
- package/lib/queryBuilder/operations/DeleteOperation.js +10 -39
- package/lib/queryBuilder/operations/FindByIdOperation.js +7 -12
- package/lib/queryBuilder/operations/FindByIdsOperation.js +4 -8
- package/lib/queryBuilder/operations/FindOperation.js +14 -34
- package/lib/queryBuilder/operations/FirstOperation.js +6 -10
- package/lib/queryBuilder/operations/FromOperation.js +3 -9
- package/lib/queryBuilder/operations/InsertAndFetchOperation.js +13 -12
- package/lib/queryBuilder/operations/InsertGraphAndFetchOperation.js +4 -10
- package/lib/queryBuilder/operations/InsertGraphOperation.js +7 -18
- package/lib/queryBuilder/operations/InsertOperation.js +118 -45
- package/lib/queryBuilder/operations/InstanceDeleteOperation.js +5 -12
- package/lib/queryBuilder/operations/InstanceFindOperation.js +4 -11
- package/lib/queryBuilder/operations/InstanceInsertOperation.js +2 -8
- package/lib/queryBuilder/operations/InstanceUpdateOperation.js +7 -14
- package/lib/queryBuilder/operations/JoinRelatedOperation.js +5 -11
- package/lib/queryBuilder/operations/KnexOperation.js +2 -8
- package/lib/queryBuilder/operations/LimitPerParentOperation.js +7 -69
- package/lib/queryBuilder/operations/MergeOperation.js +5 -11
- package/lib/queryBuilder/operations/NoneOperation.js +2 -8
- package/lib/queryBuilder/operations/ObjectionToKnexConvertingOperation.js +20 -49
- package/lib/queryBuilder/operations/OnBuildKnexOperation.js +2 -8
- package/lib/queryBuilder/operations/OnBuildOperation.js +2 -8
- package/lib/queryBuilder/operations/OnErrorOperation.js +2 -8
- package/lib/queryBuilder/operations/QueryBuilderOperation.js +1 -7
- package/lib/queryBuilder/operations/RangeOperation.js +11 -26
- package/lib/queryBuilder/operations/RelateOperation.js +2 -8
- package/lib/queryBuilder/operations/ReturningOperation.js +3 -9
- package/lib/queryBuilder/operations/RunAfterOperation.js +2 -12
- package/lib/queryBuilder/operations/RunBeforeOperation.js +2 -8
- package/lib/queryBuilder/operations/UnrelateOperation.js +2 -8
- package/lib/queryBuilder/operations/UpdateAndFetchOperation.js +14 -17
- package/lib/queryBuilder/operations/UpdateOperation.js +32 -132
- package/lib/queryBuilder/operations/UpsertGraphAndFetchOperation.js +8 -11
- package/lib/queryBuilder/operations/UpsertGraphOperation.js +6 -12
- package/lib/queryBuilder/operations/WhereCompositeOperation.js +3 -9
- package/lib/queryBuilder/operations/WhereGroupOperation.js +2 -8
- package/lib/queryBuilder/operations/eager/EagerOperation.js +3 -9
- package/lib/queryBuilder/operations/eager/JoinEagerOperation.js +72 -10
- package/lib/queryBuilder/operations/eager/NaiveEagerOperation.js +2 -8
- package/lib/queryBuilder/operations/eager/WhereInEagerOperation.js +23 -44
- package/lib/queryBuilder/operations/fieldExpressions.js +122 -0
- package/lib/queryBuilder/operations/jsonApi/WhereJsonHasOperation.js +20 -0
- package/lib/queryBuilder/operations/jsonApi/WhereJsonOperation.js +44 -0
- package/lib/queryBuilder/operations/jsonApi/WhereJsonTypeOperation.js +14 -0
- package/lib/queryBuilder/operations/select/SelectOperation.js +11 -21
- package/lib/queryBuilder/operations/select/Selection.js +19 -17
- package/lib/queryBuilder/operations/whereInComposite/WhereInCompositeMsSqlOperation.js +4 -10
- package/lib/queryBuilder/operations/whereInComposite/WhereInCompositeOperation.js +4 -10
- package/lib/queryBuilder/operations/whereInComposite/WhereInCompositeSqliteOperation.js +4 -10
- package/lib/queryBuilder/operations/windowOrder.js +56 -0
- package/lib/queryBuilder/parsers/jsonFieldExpressionParser.js +3 -7
- package/lib/queryBuilder/parsers/relationExpressionParser.js +42 -43
- package/lib/queryBuilder/parsers/relationExpressionParser.pegjs +39 -36
- package/lib/queryBuilder/transformations/CompositeQueryTransformation.js +2 -8
- package/lib/queryBuilder/transformations/QueryTransformation.js +1 -7
- package/lib/queryBuilder/transformations/WrapMysqlModifySubqueryTransformation.js +3 -9
- package/lib/queryBuilder/transformations/index.js +3 -11
- package/lib/queryBuilder/whereGroups.js +9 -24
- package/lib/queryBuilder/withoutOrder.js +4 -11
- package/lib/relations/Relation.js +47 -28
- package/lib/relations/RelationDeleteOperation.js +4 -14
- package/lib/relations/RelationFindOperation.js +119 -90
- package/lib/relations/RelationInsertOperation.js +2 -8
- package/lib/relations/RelationOwner.js +5 -11
- package/lib/relations/RelationProperty.js +4 -10
- package/lib/relations/RelationUpdateOperation.js +4 -14
- package/lib/relations/RelationWriteResultOperation.js +15 -0
- package/lib/relations/belongsToMany/BelongsToManyDeleteOperation.js +23 -0
- package/lib/relations/belongsToMany/BelongsToManyFindOperation.js +35 -0
- package/lib/relations/belongsToMany/BelongsToManyInsertOperation.js +28 -0
- package/lib/relations/belongsToMany/BelongsToManyRelateOperation.js +16 -0
- package/lib/relations/belongsToMany/BelongsToManyRelation.js +276 -0
- package/lib/relations/belongsToMany/BelongsToManyUnrelateOperation.js +11 -0
- package/lib/relations/belongsToOne/BelongsToOneDeleteOperation.js +2 -8
- package/lib/relations/belongsToOne/BelongsToOneInsertOperation.js +6 -11
- package/lib/relations/belongsToOne/BelongsToOneRelateOperation.js +3 -9
- package/lib/relations/belongsToOne/BelongsToOneRelation.js +8 -19
- package/lib/relations/belongsToOne/BelongsToOneUnrelateOperation.js +53 -27
- package/lib/relations/hasMany/HasManyInsertOperation.js +5 -10
- package/lib/relations/hasMany/HasManyRelateOperation.js +5 -11
- package/lib/relations/hasMany/HasManyRelation.js +9 -11
- package/lib/relations/hasMany/HasManyUnrelateOperation.js +3 -9
- package/lib/relations/hasOne/HasOneRelation.js +2 -8
- package/lib/relations/hasOneThrough/HasOneThroughRelation.js +2 -8
- package/lib/relations/manyToMany/ManyToManyModifyMixin.js +10 -15
- package/lib/relations/manyToMany/ManyToManyMySqlModifyMixin.js +2 -8
- package/lib/relations/manyToMany/ManyToManyRelation.js +82 -50
- package/lib/relations/manyToMany/ManyToManySqliteModifyMixin.js +2 -8
- package/lib/relations/manyToMany/delete/ManyToManyDeleteOperation.js +5 -9
- package/lib/relations/manyToMany/delete/ManyToManyDeleteOperationBase.js +2 -8
- package/lib/relations/manyToMany/delete/ManyToManyDeleteSqliteOperation.js +3 -9
- package/lib/relations/manyToMany/find/ManyToManyFindOperation.js +20 -59
- package/lib/relations/manyToMany/insert/ManyToManyInsertOperation.js +6 -11
- package/lib/relations/manyToMany/relate/ManyToManyRelateOperation.js +4 -10
- package/lib/relations/manyToMany/unrelate/ManyToManyUnrelateMySqlOperation.js +3 -9
- package/lib/relations/manyToMany/unrelate/ManyToManyUnrelateOperation.js +5 -9
- package/lib/relations/manyToMany/unrelate/ManyToManyUnrelateOperationBase.js +3 -9
- package/lib/relations/manyToMany/unrelate/ManyToManyUnrelateSqliteOperation.js +3 -9
- package/lib/relations/manyToMany/update/ManyToManyUpdateMySqlOperation.js +3 -9
- package/lib/relations/manyToMany/update/ManyToManyUpdateOperation.js +5 -9
- package/lib/relations/manyToMany/update/ManyToManyUpdateOperationBase.js +64 -72
- package/lib/relations/manyToMany/update/ManyToManyUpdateSqliteOperation.js +3 -9
- package/lib/transaction.js +3 -9
- package/lib/utils/assert.js +3 -11
- package/lib/utils/buildUtils.js +2 -8
- package/lib/utils/classUtils.js +1 -7
- package/lib/utils/createModifier.js +2 -8
- package/lib/utils/identifierMapping.js +23 -27
- package/lib/utils/internalPropUtils.js +1 -7
- package/lib/utils/knexUtils.js +84 -40
- package/lib/utils/mixin.js +3 -10
- package/lib/utils/normalizeIds.js +2 -8
- package/lib/utils/objectUtils.js +41 -60
- package/lib/utils/parseFieldExpression.js +16 -16
- package/lib/utils/promiseUtils/after.js +2 -8
- package/lib/utils/promiseUtils/afterReturn.js +2 -8
- package/lib/utils/promiseUtils/index.js +7 -16
- package/lib/utils/promiseUtils/isPromise.js +2 -8
- package/lib/utils/promiseUtils/map.js +2 -8
- package/lib/utils/promiseUtils/mapAfterAllReturn.js +2 -8
- package/lib/utils/promiseUtils/try.js +2 -8
- package/lib/utils/resolveModel.js +10 -17
- package/lib/utils/tmpColumnUtils.js +2 -9
- package/lib/utils/warnings.js +2 -14
- package/package.json +25 -17
- package/typings/objection/index.d.ts +3217 -2179
- package/lib/.eslintrc.json +0 -8
- package/lib/model/graph/ModelGraph.js +0 -80
- package/lib/model/graph/ModelGraphBuilder.js +0 -241
- package/lib/model/graph/ModelGraphEdge.js +0 -52
- package/lib/model/graph/ModelGraphNode.js +0 -238
- package/lib/queryBuilder/graph/GraphAction.js +0 -69
- package/lib/queryBuilder/graph/GraphData.js +0 -53
- package/lib/queryBuilder/graph/GraphFetcher.js +0 -197
- package/lib/queryBuilder/graph/GraphNodeDbExistence.js +0 -184
- package/lib/queryBuilder/graph/GraphOperation.js +0 -27
- package/lib/queryBuilder/graph/delete/GraphDelete.js +0 -73
- package/lib/queryBuilder/graph/delete/GraphDeleteAction.js +0 -88
- package/lib/queryBuilder/graph/insert/DeferredRelationGraphInsertAction.js +0 -58
- package/lib/queryBuilder/graph/insert/GraphInsert.js +0 -296
- package/lib/queryBuilder/graph/insert/GraphInsertAction.js +0 -233
- package/lib/queryBuilder/graph/insert/JoinRowGraphInsertAction.js +0 -92
- package/lib/queryBuilder/graph/patch/GraphPatch.js +0 -20
- package/lib/queryBuilder/graph/patch/GraphPatchAction.js +0 -289
- package/lib/queryBuilder/graph/recursiveUpsert/GraphRecursiveUpsert.js +0 -31
- package/lib/queryBuilder/graph/recursiveUpsert/GraphRecursiveUpsertAction.js +0 -126
- package/lib/queryBuilder/operations/jsonApi/WhereJsonHasPostgresOperation.js +0 -30
- package/lib/queryBuilder/operations/jsonApi/WhereJsonNotObjectPostgresOperation.js +0 -37
- package/lib/queryBuilder/operations/jsonApi/WhereJsonPostgresOperation.js +0 -62
- package/lib/queryBuilder/operations/jsonApi/postgresJsonApi.js +0 -192
- package/lib/utils/wrapDbError.js +0 -64
|
@@ -1,19 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
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)$/;
|
|
13
7
|
// Without underscores, so that column name mappers don't change it.
|
|
14
8
|
const relatedPropColumn = 'objectiontmprelated';
|
|
15
9
|
|
|
16
|
-
class ManyToManyUpdateOperationBase extends UpdateOperation {
|
|
10
|
+
export class ManyToManyUpdateOperationBase extends UpdateOperation {
|
|
17
11
|
constructor(name, opt) {
|
|
18
12
|
super(name, opt);
|
|
19
13
|
|
|
@@ -39,9 +33,15 @@ class ManyToManyUpdateOperationBase extends UpdateOperation {
|
|
|
39
33
|
// table. On MySQL, concurrent updates with that subquery deadlock (#135).
|
|
40
34
|
this.skipRelationFilter = builder.internalOptions().skipRelationFilter;
|
|
41
35
|
|
|
42
|
-
// Copy
|
|
36
|
+
// Copy the extra properties to the `joinTablePatch` object, or the ones
|
|
37
|
+
// that `upsertGraph()` writes:
|
|
38
|
+
const { joinTableExtras } = builder.internalOptions();
|
|
39
|
+
|
|
43
40
|
for (const extra of this.relation.joinTableExtras) {
|
|
44
|
-
if (
|
|
41
|
+
if (
|
|
42
|
+
extra.aliasProp in obj &&
|
|
43
|
+
(!joinTableExtras || joinTableExtras.includes(extra.aliasProp))
|
|
44
|
+
) {
|
|
45
45
|
this.hasExtraProps = true;
|
|
46
46
|
this.joinTablePatch[extra.joinTableProp] = obj[extra.aliasProp];
|
|
47
47
|
}
|
|
@@ -76,7 +76,6 @@ class ManyToManyUpdateOperationBase extends UpdateOperation {
|
|
|
76
76
|
// `onAfterBuild()`.
|
|
77
77
|
this.relatedIdsQuery = this.createRelatedIdsQuery(builder, hasLimit);
|
|
78
78
|
if (hasLimit) {
|
|
79
|
-
this.relatedIdsQuery.copyFrom(builder, LimitSelector);
|
|
80
79
|
builder.clear(LimitSelector);
|
|
81
80
|
}
|
|
82
81
|
}
|
|
@@ -84,33 +83,47 @@ class ManyToManyUpdateOperationBase extends UpdateOperation {
|
|
|
84
83
|
return super.onBuild(builder);
|
|
85
84
|
}
|
|
86
85
|
|
|
87
|
-
//
|
|
88
|
-
//
|
|
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.
|
|
89
90
|
createRelatedIdsQuery(builder, hasLimit) {
|
|
90
91
|
const { relatedModelClass, relatedProp } = this.relation;
|
|
92
|
+
const idProperty = relatedModelClass.getIdRelationProperty();
|
|
93
|
+
const filterQuery = this.modifyFilterSubquery.clone();
|
|
94
|
+
const idRefs = idProperty.refs(filterQuery);
|
|
91
95
|
|
|
92
96
|
if (hasLimit) {
|
|
93
|
-
// The
|
|
94
|
-
//
|
|
95
|
-
//
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
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)$/);
|
|
107
125
|
} else {
|
|
108
|
-
|
|
109
|
-
// table by them again lets Postgres pick plans that run the subquery
|
|
110
|
-
// once per related row, which takes minutes for a few thousand (#161).
|
|
111
|
-
const relatedIdsQuery = this.modifyFilterSubquery.clone();
|
|
112
|
-
const idRefs = relatedModelClass.getIdRelationProperty().refs(relatedIdsQuery);
|
|
113
|
-
return relatedIdsQuery.distinct(idRefs);
|
|
126
|
+
return filterQuery.distinct(idRefs);
|
|
114
127
|
}
|
|
115
128
|
}
|
|
116
129
|
|
|
@@ -119,7 +132,7 @@ class ManyToManyUpdateOperationBase extends UpdateOperation {
|
|
|
119
132
|
// `none()`, leaves the join rows untouched too.
|
|
120
133
|
async onAfterBuild(builder) {
|
|
121
134
|
// An offset that `onBuild()` moved to the ids query is honoured, and
|
|
122
|
-
// doesn't
|
|
135
|
+
// doesn't throw.
|
|
123
136
|
super.onAfterBuild(builder);
|
|
124
137
|
if (this.hasExtraProps && !this.isResolvedWithoutUpdate(builder)) {
|
|
125
138
|
let relatedValues = null;
|
|
@@ -130,22 +143,15 @@ class ManyToManyUpdateOperationBase extends UpdateOperation {
|
|
|
130
143
|
const values = rows.map((row) => Object.values(row));
|
|
131
144
|
const { size } = this.relation.relatedModelClass.getIdRelationProperty();
|
|
132
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.
|
|
133
149
|
if (this.relatedIdsQuery.has(/^(limit|offset)$/)) {
|
|
134
150
|
relatedValues = values.map((row) => row.slice(size));
|
|
135
151
|
}
|
|
136
152
|
}
|
|
137
153
|
|
|
138
|
-
|
|
139
|
-
if (relatedValues) {
|
|
140
|
-
// The filters match the join rows of more related rows than the limit
|
|
141
|
-
// picks, so only update the join rows of the picked ones, by the
|
|
142
|
-
// `relatedProp` values that follow their ids.
|
|
143
|
-
for (const values of chunkKeys(relatedValues, this.relation.relatedProp.size)) {
|
|
144
|
-
await this.updateJoinRows(builder, values);
|
|
145
|
-
}
|
|
146
|
-
} else {
|
|
147
|
-
numJoinRowsUpdated = await this.updateJoinRows(builder);
|
|
148
|
-
}
|
|
154
|
+
const numJoinRowsUpdated = await this.updateJoinRows(builder, relatedValues);
|
|
149
155
|
|
|
150
156
|
if (this.hasNothingToUpdate) {
|
|
151
157
|
// Only the join rows change, so count the related rows that they
|
|
@@ -157,6 +163,14 @@ class ManyToManyUpdateOperationBase extends UpdateOperation {
|
|
|
157
163
|
}
|
|
158
164
|
}
|
|
159
165
|
|
|
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
|
+
|
|
160
174
|
updateJoinRows(builder, relatedValues = null) {
|
|
161
175
|
const joinTableUpdateQuery = this.relation
|
|
162
176
|
.getJoinModelClass(builder.knex())
|
|
@@ -171,7 +185,8 @@ class ManyToManyUpdateOperationBase extends UpdateOperation {
|
|
|
171
185
|
);
|
|
172
186
|
if (relatedValues) {
|
|
173
187
|
addWhereGroup(joinTableUpdateQuery, () =>
|
|
174
|
-
|
|
188
|
+
whereInKeys(
|
|
189
|
+
joinTableUpdateQuery,
|
|
175
190
|
this.relation.joinTableRelatedProp.refs(joinTableUpdateQuery),
|
|
176
191
|
relatedValues,
|
|
177
192
|
),
|
|
@@ -184,21 +199,6 @@ class ManyToManyUpdateOperationBase extends UpdateOperation {
|
|
|
184
199
|
return joinTableUpdateQuery;
|
|
185
200
|
}
|
|
186
201
|
|
|
187
|
-
// Update the related rows in batches of their ids, as databases limit the
|
|
188
|
-
// number of values in one statement.
|
|
189
|
-
queryBatches(builder) {
|
|
190
|
-
if (this.relatedIds) {
|
|
191
|
-
const batches = chunkKeys(
|
|
192
|
-
this.relatedIds,
|
|
193
|
-
this.relation.relatedModelClass.getIdRelationProperty().size,
|
|
194
|
-
);
|
|
195
|
-
// Without ids, still execute the query once for the dialect's result:
|
|
196
|
-
return batches.length > 0 ? batches : [[]];
|
|
197
|
-
} else {
|
|
198
|
-
return null;
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
|
|
202
202
|
// Filters the join rows by the ids of the owner and the updated model.
|
|
203
203
|
applyIdFilterForJoinTable(builder) {
|
|
204
204
|
return builder
|
|
@@ -234,11 +234,3 @@ class ManyToManyUpdateOperationBase extends UpdateOperation {
|
|
|
234
234
|
return clone;
|
|
235
235
|
}
|
|
236
236
|
}
|
|
237
|
-
|
|
238
|
-
function chunkKeys(keys, size) {
|
|
239
|
-
return chunk(keys, Math.floor(maxBatchValues / size));
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
module.exports = {
|
|
243
|
-
ManyToManyUpdateOperationBase,
|
|
244
|
-
};
|
|
@@ -1,12 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
import { ManyToManyUpdateOperationBase } from './ManyToManyUpdateOperationBase.js';
|
|
2
|
+
import { ManyToManySqliteModifyMixin } from '../ManyToManySqliteModifyMixin.js';
|
|
2
3
|
|
|
3
|
-
|
|
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
|
-
};
|
package/lib/transaction.js
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
|
|
1
|
+
import * as promiseUtils from './utils/promiseUtils/index.js';
|
|
2
|
+
import { isFunction } from './utils/objectUtils.js';
|
|
2
3
|
|
|
3
|
-
|
|
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
|
-
};
|
package/lib/utils/assert.js
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
|
-
|
|
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
|
-
};
|
package/lib/utils/buildUtils.js
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
import { isObject, isFunction } from './objectUtils.js';
|
|
2
2
|
|
|
3
|
-
|
|
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
|
-
};
|
package/lib/utils/classUtils.js
CHANGED
|
@@ -1,13 +1,7 @@
|
|
|
1
|
-
|
|
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
|
-
|
|
1
|
+
import { asArray, isString, isFunction, isPlainObject } from './objectUtils.js';
|
|
2
2
|
|
|
3
|
-
|
|
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
|
-
|
|
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
|
|
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.
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
238
|
-
|
|
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));
|
package/lib/utils/knexUtils.js
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
import { isObject, isFunction, isString, isNumber, asSingle } from '../utils/objectUtils.js';
|
|
2
2
|
|
|
3
|
-
|
|
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
|
-
//
|
|
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
|
-
//
|
|
46
|
-
//
|
|
47
|
-
function
|
|
48
|
-
|
|
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
|
-
|
|
51
|
-
|
|
52
|
-
|
|
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
|
|
99
|
+
return builder.whereInComposite(refs, keys);
|
|
55
100
|
}
|
|
56
101
|
}
|
|
57
102
|
|
|
58
|
-
|
|
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
|
-
};
|