@strapi/database 5.0.0-beta.13 → 5.0.0-beta.14
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/dist/entity-manager/regular-relations.d.ts.map +1 -1
- package/dist/index.js +204 -123
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +204 -123
- package/dist/index.mjs.map +1 -1
- package/dist/query/helpers/order-by.d.ts +9 -1
- package/dist/query/helpers/order-by.d.ts.map +1 -1
- package/dist/query/helpers/streams/readable.d.ts +1 -1
- package/dist/query/query-builder.d.ts +3 -2
- package/dist/query/query-builder.d.ts.map +1 -1
- package/package.json +5 -5
package/dist/index.mjs
CHANGED
|
@@ -5,11 +5,11 @@ import _, { isNil, castArray, prop, omit, isInteger, snakeCase, partition, sumBy
|
|
|
5
5
|
import crypto from "crypto";
|
|
6
6
|
import crypto$1 from "node:crypto";
|
|
7
7
|
import * as dateFns from "date-fns";
|
|
8
|
-
import {
|
|
8
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
9
9
|
import KnexBuilder from "knex/lib/query/querybuilder";
|
|
10
10
|
import KnexRaw from "knex/lib/raw";
|
|
11
|
+
import { isOperatorOfType, isOperator } from "@strapi/utils";
|
|
11
12
|
import { Readable } from "stream";
|
|
12
|
-
import { AsyncLocalStorage } from "node:async_hooks";
|
|
13
13
|
import _$1 from "lodash";
|
|
14
14
|
import { Umzug } from "umzug";
|
|
15
15
|
import { createId } from "@paralleldrive/cuid2";
|
|
@@ -2895,6 +2895,68 @@ const createField = (attribute) => {
|
|
|
2895
2895
|
}
|
|
2896
2896
|
throw new Error(`Undefined field for type ${type}`);
|
|
2897
2897
|
};
|
|
2898
|
+
const storage = new AsyncLocalStorage();
|
|
2899
|
+
const transactionCtx = {
|
|
2900
|
+
async run(trx, cb) {
|
|
2901
|
+
const store = storage.getStore();
|
|
2902
|
+
return storage.run(
|
|
2903
|
+
{
|
|
2904
|
+
trx,
|
|
2905
|
+
// Fill with existing callbacks if nesting transactions
|
|
2906
|
+
commitCallbacks: store?.commitCallbacks || [],
|
|
2907
|
+
rollbackCallbacks: store?.rollbackCallbacks || []
|
|
2908
|
+
},
|
|
2909
|
+
cb
|
|
2910
|
+
);
|
|
2911
|
+
},
|
|
2912
|
+
get() {
|
|
2913
|
+
const store = storage.getStore();
|
|
2914
|
+
return store?.trx;
|
|
2915
|
+
},
|
|
2916
|
+
async commit(trx) {
|
|
2917
|
+
const store = storage.getStore();
|
|
2918
|
+
if (store?.trx) {
|
|
2919
|
+
store.trx = null;
|
|
2920
|
+
}
|
|
2921
|
+
await trx.commit();
|
|
2922
|
+
if (!store?.commitCallbacks.length) {
|
|
2923
|
+
return;
|
|
2924
|
+
}
|
|
2925
|
+
store.commitCallbacks.forEach((cb) => cb());
|
|
2926
|
+
store.commitCallbacks = [];
|
|
2927
|
+
},
|
|
2928
|
+
async rollback(trx) {
|
|
2929
|
+
const store = storage.getStore();
|
|
2930
|
+
if (store?.trx) {
|
|
2931
|
+
store.trx = null;
|
|
2932
|
+
}
|
|
2933
|
+
await trx.rollback();
|
|
2934
|
+
if (!store?.rollbackCallbacks.length) {
|
|
2935
|
+
return;
|
|
2936
|
+
}
|
|
2937
|
+
store.rollbackCallbacks.forEach((cb) => cb());
|
|
2938
|
+
store.rollbackCallbacks = [];
|
|
2939
|
+
},
|
|
2940
|
+
onCommit(cb) {
|
|
2941
|
+
const store = storage.getStore();
|
|
2942
|
+
if (store?.commitCallbacks) {
|
|
2943
|
+
store.commitCallbacks.push(cb);
|
|
2944
|
+
}
|
|
2945
|
+
},
|
|
2946
|
+
onRollback(cb) {
|
|
2947
|
+
const store = storage.getStore();
|
|
2948
|
+
if (store?.rollbackCallbacks) {
|
|
2949
|
+
store.rollbackCallbacks.push(cb);
|
|
2950
|
+
}
|
|
2951
|
+
}
|
|
2952
|
+
};
|
|
2953
|
+
function isKnexQuery(value) {
|
|
2954
|
+
return value instanceof KnexBuilder || value instanceof KnexRaw;
|
|
2955
|
+
}
|
|
2956
|
+
const addSchema = (db, tableName) => {
|
|
2957
|
+
const schemaName = db.getSchemaName();
|
|
2958
|
+
return schemaName ? `${schemaName}.${tableName}` : tableName;
|
|
2959
|
+
};
|
|
2898
2960
|
const fromSingleRow = (meta, row) => {
|
|
2899
2961
|
const { attributes } = meta;
|
|
2900
2962
|
if (_.isNil(row)) {
|
|
@@ -3017,7 +3079,7 @@ const escapeQuery = (query, charsToEscape, escapeChar = "\\") => {
|
|
|
3017
3079
|
""
|
|
3018
3080
|
);
|
|
3019
3081
|
};
|
|
3020
|
-
const createPivotJoin = (ctx, { alias, refAlias, joinTable, targetMeta }) => {
|
|
3082
|
+
const createPivotJoin = (ctx, { alias: alias2, refAlias, joinTable, targetMeta }) => {
|
|
3021
3083
|
const { qb } = ctx;
|
|
3022
3084
|
const joinAlias = qb.getAlias();
|
|
3023
3085
|
qb.join({
|
|
@@ -3025,7 +3087,7 @@ const createPivotJoin = (ctx, { alias, refAlias, joinTable, targetMeta }) => {
|
|
|
3025
3087
|
referencedTable: joinTable.name,
|
|
3026
3088
|
referencedColumn: joinTable.joinColumn.name,
|
|
3027
3089
|
rootColumn: joinTable.joinColumn.referencedColumn,
|
|
3028
|
-
rootTable:
|
|
3090
|
+
rootTable: alias2,
|
|
3029
3091
|
on: joinTable.on
|
|
3030
3092
|
});
|
|
3031
3093
|
const subAlias = refAlias || qb.getAlias();
|
|
@@ -3038,7 +3100,7 @@ const createPivotJoin = (ctx, { alias, refAlias, joinTable, targetMeta }) => {
|
|
|
3038
3100
|
});
|
|
3039
3101
|
return subAlias;
|
|
3040
3102
|
};
|
|
3041
|
-
const createJoin = (ctx, { alias, refAlias, attributeName, attribute }) => {
|
|
3103
|
+
const createJoin = (ctx, { alias: alias2, refAlias, attributeName, attribute }) => {
|
|
3042
3104
|
const { db, qb, uid } = ctx;
|
|
3043
3105
|
if (attribute.type !== "relation") {
|
|
3044
3106
|
throw new Error(`Cannot join on non relational field ${attributeName}`);
|
|
@@ -3054,7 +3116,7 @@ const createJoin = (ctx, { alias, refAlias, attributeName, attribute }) => {
|
|
|
3054
3116
|
referencedTable: targetMeta.tableName,
|
|
3055
3117
|
referencedColumn: morphColumn.idColumn.name,
|
|
3056
3118
|
rootColumn: morphColumn.idColumn.referencedColumn,
|
|
3057
|
-
rootTable:
|
|
3119
|
+
rootTable: alias2,
|
|
3058
3120
|
on: {
|
|
3059
3121
|
[morphColumn.typeColumn.name]: uid,
|
|
3060
3122
|
...morphColumn.on
|
|
@@ -3069,7 +3131,7 @@ const createJoin = (ctx, { alias, refAlias, attributeName, attribute }) => {
|
|
|
3069
3131
|
referencedTable: joinTable2.name,
|
|
3070
3132
|
referencedColumn: joinTable2.morphColumn.idColumn.name,
|
|
3071
3133
|
rootColumn: joinTable2.morphColumn.idColumn.referencedColumn,
|
|
3072
|
-
rootTable:
|
|
3134
|
+
rootTable: alias2,
|
|
3073
3135
|
on: {
|
|
3074
3136
|
[joinTable2.morphColumn.typeColumn.name]: uid,
|
|
3075
3137
|
field: attributeName
|
|
@@ -3085,7 +3147,7 @@ const createJoin = (ctx, { alias, refAlias, attributeName, attribute }) => {
|
|
|
3085
3147
|
});
|
|
3086
3148
|
return subAlias;
|
|
3087
3149
|
}
|
|
3088
|
-
return
|
|
3150
|
+
return alias2;
|
|
3089
3151
|
}
|
|
3090
3152
|
const { joinColumn } = attribute;
|
|
3091
3153
|
if (joinColumn) {
|
|
@@ -3095,20 +3157,20 @@ const createJoin = (ctx, { alias, refAlias, attributeName, attribute }) => {
|
|
|
3095
3157
|
referencedTable: targetMeta.tableName,
|
|
3096
3158
|
referencedColumn: joinColumn.referencedColumn,
|
|
3097
3159
|
rootColumn: joinColumn.name,
|
|
3098
|
-
rootTable:
|
|
3160
|
+
rootTable: alias2
|
|
3099
3161
|
});
|
|
3100
3162
|
return subAlias;
|
|
3101
3163
|
}
|
|
3102
3164
|
const { joinTable } = attribute;
|
|
3103
3165
|
if (joinTable) {
|
|
3104
|
-
return createPivotJoin(ctx, { alias, refAlias, joinTable, targetMeta });
|
|
3166
|
+
return createPivotJoin(ctx, { alias: alias2, refAlias, joinTable, targetMeta });
|
|
3105
3167
|
}
|
|
3106
|
-
return
|
|
3168
|
+
return alias2;
|
|
3107
3169
|
};
|
|
3108
3170
|
const applyJoin = (qb, join) => {
|
|
3109
3171
|
const {
|
|
3110
3172
|
method = "leftJoin",
|
|
3111
|
-
alias,
|
|
3173
|
+
alias: alias2,
|
|
3112
3174
|
referencedTable,
|
|
3113
3175
|
referencedColumn,
|
|
3114
3176
|
rootColumn,
|
|
@@ -3118,26 +3180,28 @@ const applyJoin = (qb, join) => {
|
|
|
3118
3180
|
on,
|
|
3119
3181
|
orderBy
|
|
3120
3182
|
} = join;
|
|
3121
|
-
qb[method](`${referencedTable} as ${
|
|
3122
|
-
inner.on(`${rootTable}.${rootColumn}`, `${
|
|
3183
|
+
qb[method](`${referencedTable} as ${alias2}`, (inner) => {
|
|
3184
|
+
inner.on(`${rootTable}.${rootColumn}`, `${alias2}.${referencedColumn}`);
|
|
3123
3185
|
if (on) {
|
|
3124
3186
|
for (const key of Object.keys(on)) {
|
|
3125
|
-
inner.onVal(`${
|
|
3187
|
+
inner.onVal(`${alias2}.${key}`, on[key]);
|
|
3126
3188
|
}
|
|
3127
3189
|
}
|
|
3128
3190
|
});
|
|
3129
3191
|
if (orderBy) {
|
|
3130
3192
|
Object.keys(orderBy).forEach((column) => {
|
|
3131
3193
|
const direction = orderBy[column];
|
|
3132
|
-
qb.orderBy(`${
|
|
3194
|
+
qb.orderBy(`${alias2}.${column}`, direction);
|
|
3133
3195
|
});
|
|
3134
3196
|
}
|
|
3135
3197
|
};
|
|
3136
3198
|
const applyJoins = (qb, joins) => {
|
|
3137
3199
|
return joins.forEach((join) => applyJoin(qb, join));
|
|
3138
3200
|
};
|
|
3201
|
+
const COL_STRAPI_ROW_NUMBER = "__strapi_row_number";
|
|
3202
|
+
const COL_STRAPI_ORDER_BY_PREFIX = "__strapi_order_by";
|
|
3139
3203
|
const processOrderBy = (orderBy, ctx) => {
|
|
3140
|
-
const { db, uid, qb, alias } = ctx;
|
|
3204
|
+
const { db, uid, qb, alias: alias2 } = ctx;
|
|
3141
3205
|
const meta = db.metadata.get(uid);
|
|
3142
3206
|
const { attributes } = meta;
|
|
3143
3207
|
if (typeof orderBy === "string") {
|
|
@@ -3146,7 +3210,7 @@ const processOrderBy = (orderBy, ctx) => {
|
|
|
3146
3210
|
throw new Error(`Attribute ${orderBy} not found on model ${uid}`);
|
|
3147
3211
|
}
|
|
3148
3212
|
const columnName = toColumnName(meta, orderBy);
|
|
3149
|
-
return [{ column: qb.aliasColumn(columnName,
|
|
3213
|
+
return [{ column: qb.aliasColumn(columnName, alias2) }];
|
|
3150
3214
|
}
|
|
3151
3215
|
if (Array.isArray(orderBy)) {
|
|
3152
3216
|
return orderBy.flatMap((value) => processOrderBy(value, ctx));
|
|
@@ -3160,11 +3224,11 @@ const processOrderBy = (orderBy, ctx) => {
|
|
|
3160
3224
|
}
|
|
3161
3225
|
if (isScalar(attribute.type)) {
|
|
3162
3226
|
const columnName = toColumnName(meta, key);
|
|
3163
|
-
return { column: qb.aliasColumn(columnName,
|
|
3227
|
+
return { column: qb.aliasColumn(columnName, alias2), order: direction };
|
|
3164
3228
|
}
|
|
3165
3229
|
if (attribute.type === "relation" && "target" in attribute) {
|
|
3166
3230
|
const subAlias = createJoin(ctx, {
|
|
3167
|
-
alias:
|
|
3231
|
+
alias: alias2 || qb.alias,
|
|
3168
3232
|
attributeName: key,
|
|
3169
3233
|
attribute
|
|
3170
3234
|
});
|
|
@@ -3180,6 +3244,75 @@ const processOrderBy = (orderBy, ctx) => {
|
|
|
3180
3244
|
}
|
|
3181
3245
|
throw new Error("Invalid orderBy syntax");
|
|
3182
3246
|
};
|
|
3247
|
+
const getStrapiOrderColumnAlias = (column) => {
|
|
3248
|
+
const trimmedColumnName = column.replaceAll(".", "_");
|
|
3249
|
+
return `${COL_STRAPI_ORDER_BY_PREFIX}__${trimmedColumnName}`;
|
|
3250
|
+
};
|
|
3251
|
+
const wrapWithDeepSort = (originalQuery, ctx) => {
|
|
3252
|
+
const { db, qb, uid } = ctx;
|
|
3253
|
+
const { tableName } = db.metadata.get(uid);
|
|
3254
|
+
const orderBy = _.cloneDeep(qb.state.orderBy);
|
|
3255
|
+
const resultQueryAlias = qb.getAlias();
|
|
3256
|
+
const aliasedTableName = qb.mustUseAlias() ? alias(resultQueryAlias, tableName) : tableName;
|
|
3257
|
+
const resultQuery = db.getConnection(aliasedTableName);
|
|
3258
|
+
const baseQuery = originalQuery.clone();
|
|
3259
|
+
const baseQueryAlias = qb.getAlias();
|
|
3260
|
+
baseQuery.clear("select").clear("order").clear("limit").clear("offset");
|
|
3261
|
+
baseQuery.select(
|
|
3262
|
+
// Always select the row id for future manipulation
|
|
3263
|
+
prefix(qb.alias, "id"),
|
|
3264
|
+
...orderBy.map(
|
|
3265
|
+
(orderByClause) => alias(getStrapiOrderColumnAlias(orderByClause.column), orderByClause.column)
|
|
3266
|
+
)
|
|
3267
|
+
);
|
|
3268
|
+
const partitionedQueryAlias = qb.getAlias();
|
|
3269
|
+
const selectRowsAsNumberedPartitions = (partitionedQuery) => {
|
|
3270
|
+
const prefixedOrderBy = orderBy.map((orderByClause) => ({
|
|
3271
|
+
column: prefix(baseQueryAlias, getStrapiOrderColumnAlias(orderByClause.column)),
|
|
3272
|
+
order: orderByClause.order
|
|
3273
|
+
}));
|
|
3274
|
+
const orderByColumns = prefixedOrderBy.map(_.prop("column"));
|
|
3275
|
+
partitionedQuery.select(
|
|
3276
|
+
// Always select baseQuery.id
|
|
3277
|
+
prefix(baseQueryAlias, "id"),
|
|
3278
|
+
...orderByColumns
|
|
3279
|
+
).rowNumber(COL_STRAPI_ROW_NUMBER, (subQuery) => {
|
|
3280
|
+
for (const orderByClause of prefixedOrderBy) {
|
|
3281
|
+
subQuery.orderBy(orderByClause.column, orderByClause.order, "last");
|
|
3282
|
+
}
|
|
3283
|
+
subQuery.partitionBy(`${baseQueryAlias}.id`);
|
|
3284
|
+
}).from(baseQuery.as(baseQueryAlias)).as(partitionedQueryAlias);
|
|
3285
|
+
};
|
|
3286
|
+
const originalSelect = _.difference(
|
|
3287
|
+
qb.state.select,
|
|
3288
|
+
// Remove order by columns from the initial select
|
|
3289
|
+
qb.state.orderBy.map(_.prop("column"))
|
|
3290
|
+
).map(prefix(resultQueryAlias));
|
|
3291
|
+
resultQuery.select(originalSelect).innerJoin(selectRowsAsNumberedPartitions, function() {
|
|
3292
|
+
this.on(`${partitionedQueryAlias}.id`, `${resultQueryAlias}.id`).andOnVal(`${partitionedQueryAlias}.${COL_STRAPI_ROW_NUMBER}`, "=", 1);
|
|
3293
|
+
});
|
|
3294
|
+
if (qb.state.limit) {
|
|
3295
|
+
resultQuery.limit(qb.state.limit);
|
|
3296
|
+
}
|
|
3297
|
+
if (qb.state.offset) {
|
|
3298
|
+
resultQuery.offset(qb.state.offset);
|
|
3299
|
+
}
|
|
3300
|
+
if (qb.state.first) {
|
|
3301
|
+
resultQuery.first();
|
|
3302
|
+
}
|
|
3303
|
+
resultQuery.orderBy([
|
|
3304
|
+
// Transform "order by" clause to their T alias and prefix them with T alias
|
|
3305
|
+
...orderBy.map((orderByClause) => ({
|
|
3306
|
+
column: prefix(partitionedQueryAlias, getStrapiOrderColumnAlias(orderByClause.column)),
|
|
3307
|
+
order: orderByClause.order
|
|
3308
|
+
})),
|
|
3309
|
+
// Add T.id to the order by clause to get consistent results in case several rows have the exact same order
|
|
3310
|
+
{ column: `${partitionedQueryAlias}.id`, order: "asc" }
|
|
3311
|
+
]);
|
|
3312
|
+
return resultQuery;
|
|
3313
|
+
};
|
|
3314
|
+
const alias = _.curry((alias2, value) => `${value} as ${alias2}`);
|
|
3315
|
+
const prefix = _.curry((prefix2, value) => `${prefix2}.${value}`);
|
|
3183
3316
|
const joinColPrefix = "__strapi";
|
|
3184
3317
|
const XtoOne = async (input, ctx) => {
|
|
3185
3318
|
const { attribute, attributeName, results, populateValue, targetMeta, isCount } = input;
|
|
@@ -3207,8 +3340,8 @@ const XtoOne = async (input, ctx) => {
|
|
|
3207
3340
|
const { joinTable } = attribute;
|
|
3208
3341
|
const qb2 = db.entityManager.createQueryBuilder(targetMeta.uid);
|
|
3209
3342
|
const { name: joinColumnName, referencedColumn: referencedColumnName } = joinTable.joinColumn;
|
|
3210
|
-
const
|
|
3211
|
-
const joinColAlias = `${
|
|
3343
|
+
const alias2 = qb2.getAlias();
|
|
3344
|
+
const joinColAlias = `${alias2}.${joinColumnName}`;
|
|
3212
3345
|
const joinColRenameAs = `${joinColPrefix}${joinColumnName}`;
|
|
3213
3346
|
const joinColSelect = `${joinColAlias} as ${joinColRenameAs}`;
|
|
3214
3347
|
const referencedValues = _.uniq(
|
|
@@ -3222,7 +3355,7 @@ const XtoOne = async (input, ctx) => {
|
|
|
3222
3355
|
return;
|
|
3223
3356
|
}
|
|
3224
3357
|
const rows2 = await qb2.init(populateValue).join({
|
|
3225
|
-
alias,
|
|
3358
|
+
alias: alias2,
|
|
3226
3359
|
referencedTable: joinTable.name,
|
|
3227
3360
|
referencedColumn: joinTable.inverseJoinColumn.name,
|
|
3228
3361
|
rootColumn: joinTable.inverseJoinColumn.referencedColumn,
|
|
@@ -3248,7 +3381,7 @@ const XtoOne = async (input, ctx) => {
|
|
|
3248
3381
|
return;
|
|
3249
3382
|
}
|
|
3250
3383
|
const rows = await qb2.init(populateValue).join({
|
|
3251
|
-
alias,
|
|
3384
|
+
alias: alias2,
|
|
3252
3385
|
referencedTable: joinTable.name,
|
|
3253
3386
|
referencedColumn: joinTable.inverseJoinColumn.name,
|
|
3254
3387
|
rootColumn: joinTable.inverseJoinColumn.referencedColumn,
|
|
@@ -3288,8 +3421,8 @@ const oneToMany = async (input, ctx) => {
|
|
|
3288
3421
|
const { joinTable } = attribute;
|
|
3289
3422
|
const qb2 = db.entityManager.createQueryBuilder(targetMeta.uid);
|
|
3290
3423
|
const { name: joinColumnName, referencedColumn: referencedColumnName } = joinTable.joinColumn;
|
|
3291
|
-
const
|
|
3292
|
-
const joinColAlias = `${
|
|
3424
|
+
const alias2 = qb2.getAlias();
|
|
3425
|
+
const joinColAlias = `${alias2}.${joinColumnName}`;
|
|
3293
3426
|
const joinColRenameAs = `${joinColPrefix}${joinColumnName}`;
|
|
3294
3427
|
const joinColSelect = `${joinColAlias} as ${joinColRenameAs}`;
|
|
3295
3428
|
const referencedValues = _.uniq(
|
|
@@ -3303,7 +3436,7 @@ const oneToMany = async (input, ctx) => {
|
|
|
3303
3436
|
return;
|
|
3304
3437
|
}
|
|
3305
3438
|
const rows2 = await qb2.init(populateValue).join({
|
|
3306
|
-
alias,
|
|
3439
|
+
alias: alias2,
|
|
3307
3440
|
referencedTable: joinTable.name,
|
|
3308
3441
|
referencedColumn: joinTable.inverseJoinColumn.name,
|
|
3309
3442
|
rootColumn: joinTable.inverseJoinColumn.referencedColumn,
|
|
@@ -3329,7 +3462,7 @@ const oneToMany = async (input, ctx) => {
|
|
|
3329
3462
|
return;
|
|
3330
3463
|
}
|
|
3331
3464
|
const rows = await qb2.init(populateValue).join({
|
|
3332
|
-
alias,
|
|
3465
|
+
alias: alias2,
|
|
3333
3466
|
referencedTable: joinTable.name,
|
|
3334
3467
|
referencedColumn: joinTable.inverseJoinColumn.name,
|
|
3335
3468
|
rootColumn: joinTable.inverseJoinColumn.referencedColumn,
|
|
@@ -3350,8 +3483,8 @@ const manyToMany = async (input, ctx) => {
|
|
|
3350
3483
|
const { joinTable } = attribute;
|
|
3351
3484
|
const populateQb = db.entityManager.createQueryBuilder(targetMeta.uid);
|
|
3352
3485
|
const { name: joinColumnName, referencedColumn: referencedColumnName } = joinTable.joinColumn;
|
|
3353
|
-
const
|
|
3354
|
-
const joinColAlias = `${
|
|
3486
|
+
const alias2 = populateQb.getAlias();
|
|
3487
|
+
const joinColAlias = `${alias2}.${joinColumnName}`;
|
|
3355
3488
|
const joinColRenameAs = `${joinColPrefix}${joinColumnName}`;
|
|
3356
3489
|
const joinColSelect = `${joinColAlias} as ${joinColRenameAs}`;
|
|
3357
3490
|
const referencedValues = _.uniq(
|
|
@@ -3365,7 +3498,7 @@ const manyToMany = async (input, ctx) => {
|
|
|
3365
3498
|
return;
|
|
3366
3499
|
}
|
|
3367
3500
|
const rows2 = await populateQb.init(populateValue).join({
|
|
3368
|
-
alias,
|
|
3501
|
+
alias: alias2,
|
|
3369
3502
|
referencedTable: joinTable.name,
|
|
3370
3503
|
referencedColumn: joinTable.inverseJoinColumn.name,
|
|
3371
3504
|
rootColumn: joinTable.inverseJoinColumn.referencedColumn,
|
|
@@ -3391,7 +3524,7 @@ const manyToMany = async (input, ctx) => {
|
|
|
3391
3524
|
return;
|
|
3392
3525
|
}
|
|
3393
3526
|
const rows = await populateQb.init(populateValue).join({
|
|
3394
|
-
alias,
|
|
3527
|
+
alias: alias2,
|
|
3395
3528
|
referencedTable: joinTable.name,
|
|
3396
3529
|
referencedColumn: joinTable.inverseJoinColumn.name,
|
|
3397
3530
|
rootColumn: joinTable.inverseJoinColumn.referencedColumn,
|
|
@@ -3442,9 +3575,9 @@ const morphX = async (input, ctx) => {
|
|
|
3442
3575
|
return;
|
|
3443
3576
|
}
|
|
3444
3577
|
const qb = db.entityManager.createQueryBuilder(target);
|
|
3445
|
-
const
|
|
3578
|
+
const alias2 = qb.getAlias();
|
|
3446
3579
|
const rows = await qb.init(populateValue).join({
|
|
3447
|
-
alias,
|
|
3580
|
+
alias: alias2,
|
|
3448
3581
|
referencedTable: joinTable.name,
|
|
3449
3582
|
referencedColumn: joinColumn.name,
|
|
3450
3583
|
rootColumn: joinColumn.referencedColumn,
|
|
@@ -3454,9 +3587,9 @@ const morphX = async (input, ctx) => {
|
|
|
3454
3587
|
field: attributeName
|
|
3455
3588
|
},
|
|
3456
3589
|
orderBy: _.mapValues((v) => populateValue.ordering || v, joinTable.orderBy)
|
|
3457
|
-
}).addSelect([`${
|
|
3458
|
-
[`${
|
|
3459
|
-
[`${
|
|
3590
|
+
}).addSelect([`${alias2}.${idColumn.name}`, `${alias2}.${typeColumn.name}`]).where({
|
|
3591
|
+
[`${alias2}.${idColumn.name}`]: referencedValues,
|
|
3592
|
+
[`${alias2}.${typeColumn.name}`]: uid
|
|
3460
3593
|
}).execute({ mapResults: false });
|
|
3461
3594
|
const map2 = _.groupBy(idColumn.name)(rows);
|
|
3462
3595
|
results.forEach((result) => {
|
|
@@ -3705,13 +3838,6 @@ const processPopulate = (populate, ctx) => {
|
|
|
3705
3838
|
}
|
|
3706
3839
|
return finalPopulate;
|
|
3707
3840
|
};
|
|
3708
|
-
function isKnexQuery(value) {
|
|
3709
|
-
return value instanceof KnexBuilder || value instanceof KnexRaw;
|
|
3710
|
-
}
|
|
3711
|
-
const addSchema = (db, tableName) => {
|
|
3712
|
-
const schemaName = db.getSchemaName();
|
|
3713
|
-
return schemaName ? `${schemaName}.${tableName}` : tableName;
|
|
3714
|
-
};
|
|
3715
3841
|
const isRecord$1 = (value) => isPlainObject(value);
|
|
3716
3842
|
const castValue = (value, attribute) => {
|
|
3717
3843
|
if (!attribute) {
|
|
@@ -3753,8 +3879,8 @@ const processNested = (where, ctx) => {
|
|
|
3753
3879
|
return processWhere(where, ctx);
|
|
3754
3880
|
};
|
|
3755
3881
|
const processRelationWhere = (where, ctx) => {
|
|
3756
|
-
const { qb, alias } = ctx;
|
|
3757
|
-
const idAlias = qb.aliasColumn("id",
|
|
3882
|
+
const { qb, alias: alias2 } = ctx;
|
|
3883
|
+
const idAlias = qb.aliasColumn("id", alias2);
|
|
3758
3884
|
if (!isRecord$1(where)) {
|
|
3759
3885
|
return { [idAlias]: where };
|
|
3760
3886
|
}
|
|
@@ -3784,7 +3910,7 @@ function processWhere(where, ctx) {
|
|
|
3784
3910
|
if (isArray(where)) {
|
|
3785
3911
|
return where.map((sub) => processWhere(sub, ctx));
|
|
3786
3912
|
}
|
|
3787
|
-
const { db, uid, qb, alias } = ctx;
|
|
3913
|
+
const { db, uid, qb, alias: alias2 } = ctx;
|
|
3788
3914
|
const meta = db.metadata.get(uid);
|
|
3789
3915
|
const filters = {};
|
|
3790
3916
|
for (const key of Object.keys(where)) {
|
|
@@ -3807,12 +3933,12 @@ function processWhere(where, ctx) {
|
|
|
3807
3933
|
}
|
|
3808
3934
|
const attribute = meta.attributes[key];
|
|
3809
3935
|
if (!attribute) {
|
|
3810
|
-
filters[qb.aliasColumn(key,
|
|
3936
|
+
filters[qb.aliasColumn(key, alias2)] = processAttributeWhere(null, value);
|
|
3811
3937
|
continue;
|
|
3812
3938
|
}
|
|
3813
3939
|
if (isRelation(attribute.type) && "target" in attribute) {
|
|
3814
3940
|
const subAlias = createJoin(ctx, {
|
|
3815
|
-
alias:
|
|
3941
|
+
alias: alias2 || qb.alias,
|
|
3816
3942
|
attributeName: key,
|
|
3817
3943
|
attribute
|
|
3818
3944
|
});
|
|
@@ -3827,7 +3953,7 @@ function processWhere(where, ctx) {
|
|
|
3827
3953
|
}
|
|
3828
3954
|
if (isScalar(attribute.type)) {
|
|
3829
3955
|
const columnName = toColumnName(meta, key);
|
|
3830
|
-
const aliasedColumnName = qb.aliasColumn(columnName,
|
|
3956
|
+
const aliasedColumnName = qb.aliasColumn(columnName, alias2);
|
|
3831
3957
|
filters[aliasedColumnName] = processAttributeWhere(attribute, value);
|
|
3832
3958
|
continue;
|
|
3833
3959
|
}
|
|
@@ -4055,7 +4181,7 @@ class ReadableStrapiQuery extends Readable {
|
|
|
4055
4181
|
* Custom ._read() implementation
|
|
4056
4182
|
*
|
|
4057
4183
|
* NOTE: Here "size" means the number of entities to be read from the database.
|
|
4058
|
-
* Not the actual byte size, as it would
|
|
4184
|
+
* Not the actual byte size, as it would mean that we need to return partial entities.
|
|
4059
4185
|
*
|
|
4060
4186
|
*/
|
|
4061
4187
|
async _read(size) {
|
|
@@ -4118,61 +4244,6 @@ class ReadableStrapiQuery extends Readable {
|
|
|
4118
4244
|
}
|
|
4119
4245
|
}
|
|
4120
4246
|
}
|
|
4121
|
-
const storage = new AsyncLocalStorage();
|
|
4122
|
-
const transactionCtx = {
|
|
4123
|
-
async run(trx, cb) {
|
|
4124
|
-
const store = storage.getStore();
|
|
4125
|
-
return storage.run(
|
|
4126
|
-
{
|
|
4127
|
-
trx,
|
|
4128
|
-
// Fill with existing callbacks if nesting transactions
|
|
4129
|
-
commitCallbacks: store?.commitCallbacks || [],
|
|
4130
|
-
rollbackCallbacks: store?.rollbackCallbacks || []
|
|
4131
|
-
},
|
|
4132
|
-
cb
|
|
4133
|
-
);
|
|
4134
|
-
},
|
|
4135
|
-
get() {
|
|
4136
|
-
const store = storage.getStore();
|
|
4137
|
-
return store?.trx;
|
|
4138
|
-
},
|
|
4139
|
-
async commit(trx) {
|
|
4140
|
-
const store = storage.getStore();
|
|
4141
|
-
if (store?.trx) {
|
|
4142
|
-
store.trx = null;
|
|
4143
|
-
}
|
|
4144
|
-
await trx.commit();
|
|
4145
|
-
if (!store?.commitCallbacks.length) {
|
|
4146
|
-
return;
|
|
4147
|
-
}
|
|
4148
|
-
store.commitCallbacks.forEach((cb) => cb());
|
|
4149
|
-
store.commitCallbacks = [];
|
|
4150
|
-
},
|
|
4151
|
-
async rollback(trx) {
|
|
4152
|
-
const store = storage.getStore();
|
|
4153
|
-
if (store?.trx) {
|
|
4154
|
-
store.trx = null;
|
|
4155
|
-
}
|
|
4156
|
-
await trx.rollback();
|
|
4157
|
-
if (!store?.rollbackCallbacks.length) {
|
|
4158
|
-
return;
|
|
4159
|
-
}
|
|
4160
|
-
store.rollbackCallbacks.forEach((cb) => cb());
|
|
4161
|
-
store.rollbackCallbacks = [];
|
|
4162
|
-
},
|
|
4163
|
-
onCommit(cb) {
|
|
4164
|
-
const store = storage.getStore();
|
|
4165
|
-
if (store?.commitCallbacks) {
|
|
4166
|
-
store.commitCallbacks.push(cb);
|
|
4167
|
-
}
|
|
4168
|
-
},
|
|
4169
|
-
onRollback(cb) {
|
|
4170
|
-
const store = storage.getStore();
|
|
4171
|
-
if (store?.rollbackCallbacks) {
|
|
4172
|
-
store.rollbackCallbacks.push(cb);
|
|
4173
|
-
}
|
|
4174
|
-
}
|
|
4175
|
-
};
|
|
4176
4247
|
const createQueryBuilder = (uid, db, initialState = {}) => {
|
|
4177
4248
|
const meta = db.metadata.get(uid);
|
|
4178
4249
|
const { tableName } = meta;
|
|
@@ -4205,9 +4276,9 @@ const createQueryBuilder = (uid, db, initialState = {}) => {
|
|
|
4205
4276
|
initialState
|
|
4206
4277
|
);
|
|
4207
4278
|
const getAlias = () => {
|
|
4208
|
-
const
|
|
4279
|
+
const alias2 = `t${state.aliasCounter}`;
|
|
4209
4280
|
state.aliasCounter += 1;
|
|
4210
|
-
return
|
|
4281
|
+
return alias2;
|
|
4211
4282
|
};
|
|
4212
4283
|
return {
|
|
4213
4284
|
alias: getAlias(),
|
|
@@ -4374,15 +4445,15 @@ const createQueryBuilder = (uid, db, initialState = {}) => {
|
|
|
4374
4445
|
mustUseAlias() {
|
|
4375
4446
|
return ["select", "count"].includes(state.type);
|
|
4376
4447
|
},
|
|
4377
|
-
aliasColumn(key,
|
|
4448
|
+
aliasColumn(key, alias2) {
|
|
4378
4449
|
if (typeof key !== "string") {
|
|
4379
4450
|
return key;
|
|
4380
4451
|
}
|
|
4381
4452
|
if (key.indexOf(".") >= 0) {
|
|
4382
4453
|
return key;
|
|
4383
4454
|
}
|
|
4384
|
-
if (!_.isNil(
|
|
4385
|
-
return `${
|
|
4455
|
+
if (!_.isNil(alias2)) {
|
|
4456
|
+
return `${alias2}.${key}`;
|
|
4386
4457
|
}
|
|
4387
4458
|
return this.mustUseAlias() ? `${this.alias}.${key}` : key;
|
|
4388
4459
|
},
|
|
@@ -4417,6 +4488,20 @@ const createQueryBuilder = (uid, db, initialState = {}) => {
|
|
|
4417
4488
|
shouldUseDistinct() {
|
|
4418
4489
|
return state.joins.length > 0 && _.isEmpty(state.groupBy);
|
|
4419
4490
|
},
|
|
4491
|
+
shouldUseDeepSort() {
|
|
4492
|
+
return state.orderBy.filter(({ column }) => column.indexOf(".") >= 0).filter(({ column }) => {
|
|
4493
|
+
const col = column.split(".");
|
|
4494
|
+
for (let i = 0; i < col.length - 1; i += 1) {
|
|
4495
|
+
const el = col[i];
|
|
4496
|
+
const isRelationAttribute = meta.attributes[el]?.type === "relation";
|
|
4497
|
+
const isAliasedRelation = Object.values(state.joins).map((join) => join.alias).includes(el);
|
|
4498
|
+
if (isRelationAttribute || isAliasedRelation) {
|
|
4499
|
+
return true;
|
|
4500
|
+
}
|
|
4501
|
+
}
|
|
4502
|
+
return false;
|
|
4503
|
+
}).length > 0;
|
|
4504
|
+
},
|
|
4420
4505
|
processSelect() {
|
|
4421
4506
|
state.select = state.select.map((field) => {
|
|
4422
4507
|
if (isKnexQuery(field)) {
|
|
@@ -4534,6 +4619,9 @@ const createQueryBuilder = (uid, db, initialState = {}) => {
|
|
|
4534
4619
|
if (state.joins.length > 0) {
|
|
4535
4620
|
applyJoins(qb, state.joins);
|
|
4536
4621
|
}
|
|
4622
|
+
if (this.shouldUseDeepSort()) {
|
|
4623
|
+
return wrapWithDeepSort(qb, { qb: this, db, uid });
|
|
4624
|
+
}
|
|
4537
4625
|
return qb;
|
|
4538
4626
|
},
|
|
4539
4627
|
async execute({ mapResults = true } = {}) {
|
|
@@ -4743,11 +4831,10 @@ const getDocumentSiblingIdsQuery = (tableName, id) => {
|
|
|
4743
4831
|
if (!isContentType) {
|
|
4744
4832
|
return [id];
|
|
4745
4833
|
}
|
|
4746
|
-
return (
|
|
4747
|
-
|
|
4748
|
-
"document_id",
|
|
4749
|
-
|
|
4750
|
-
);
|
|
4834
|
+
return function(query) {
|
|
4835
|
+
query.select("id").from(tableName).whereIn("document_id", (documentIDSubQuery) => {
|
|
4836
|
+
documentIDSubQuery.from(tableName).select("document_id").where("id", id);
|
|
4837
|
+
});
|
|
4751
4838
|
};
|
|
4752
4839
|
};
|
|
4753
4840
|
const deletePreviousOneToAnyRelations = async ({
|
|
@@ -4765,11 +4852,7 @@ const deletePreviousOneToAnyRelations = async ({
|
|
|
4765
4852
|
const { joinTable } = attribute;
|
|
4766
4853
|
const { joinColumn, inverseJoinColumn } = joinTable;
|
|
4767
4854
|
const con = db.getConnection();
|
|
4768
|
-
await con.delete().from(joinTable.name).whereNotIn(
|
|
4769
|
-
// @ts-expect-error - knex incorrectly expects a string array
|
|
4770
|
-
joinColumn.name,
|
|
4771
|
-
getDocumentSiblingIdsQuery(joinColumn.referencedTable, id)
|
|
4772
|
-
).whereIn(inverseJoinColumn.name, relIdsToadd).where(joinTable.on || {}).transacting(trx);
|
|
4855
|
+
await con.delete().from(joinTable.name).whereNotIn(joinColumn.name, getDocumentSiblingIdsQuery(joinColumn.referencedTable, id)).whereIn(inverseJoinColumn.name, relIdsToadd).where(joinTable.on || {}).transacting(trx);
|
|
4773
4856
|
await cleanOrderColumns({ attribute, db, inverseRelIds: relIdsToadd, transaction: trx });
|
|
4774
4857
|
};
|
|
4775
4858
|
const deletePreviousAnyToOneRelations = async ({
|
|
@@ -4787,7 +4870,6 @@ const deletePreviousAnyToOneRelations = async ({
|
|
|
4787
4870
|
}
|
|
4788
4871
|
if (isManyToAny(attribute)) {
|
|
4789
4872
|
const relsToDelete = await con.select(inverseJoinColumn.name).from(joinTable.name).where(joinColumn.name, id).whereNotIn(
|
|
4790
|
-
// @ts-expect-error - knex incorrectly expects a string array
|
|
4791
4873
|
inverseJoinColumn.name,
|
|
4792
4874
|
getDocumentSiblingIdsQuery(inverseJoinColumn.referencedTable, relIdToadd)
|
|
4793
4875
|
).where(joinTable.on || {}).transacting(trx);
|
|
@@ -4799,7 +4881,6 @@ const deletePreviousAnyToOneRelations = async ({
|
|
|
4799
4881
|
await cleanOrderColumns({ attribute, db, inverseRelIds: relIdsToDelete, transaction: trx });
|
|
4800
4882
|
} else {
|
|
4801
4883
|
await con.delete().from(joinTable.name).where(joinColumn.name, id).whereNotIn(
|
|
4802
|
-
// @ts-expect-error - knex incorrectly expects a string array
|
|
4803
4884
|
inverseJoinColumn.name,
|
|
4804
4885
|
getDocumentSiblingIdsQuery(inverseJoinColumn.referencedTable, relIdToadd)
|
|
4805
4886
|
).where(joinTable.on || {}).transacting(trx);
|