@strapi/database 5.0.0-beta.9 → 5.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.
- package/LICENSE +18 -3
- package/dist/entity-manager/regular-relations.d.ts.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +395 -179
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +395 -179
- package/dist/index.mjs.map +1 -1
- package/dist/migrations/internal-migrations/5.0.0-03-locale.d.ts.map +1 -1
- package/dist/migrations/internal-migrations/5.0.0-04-published-at.d.ts +3 -0
- package/dist/migrations/internal-migrations/5.0.0-04-published-at.d.ts.map +1 -0
- package/dist/migrations/internal-migrations/5.0.0-05-drop-slug-unique-index.d.ts +3 -0
- package/dist/migrations/internal-migrations/5.0.0-05-drop-slug-unique-index.d.ts.map +1 -0
- package/dist/migrations/internal-migrations/index.d.ts.map +1 -1
- package/dist/migrations/internal.d.ts.map +1 -1
- package/dist/migrations/logger.d.ts +10 -0
- package/dist/migrations/logger.d.ts.map +1 -0
- package/dist/migrations/users.d.ts.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/dist/schema/diff.d.ts +6 -1
- package/dist/schema/diff.d.ts.map +1 -1
- package/dist/schema/index.d.ts.map +1 -1
- package/dist/schema/storage.d.ts +6 -1
- package/dist/schema/storage.d.ts.map +1 -1
- package/package.json +7 -6
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";
|
|
@@ -1087,7 +1087,7 @@ const createHelpers = (db) => {
|
|
|
1087
1087
|
}
|
|
1088
1088
|
}
|
|
1089
1089
|
};
|
|
1090
|
-
const
|
|
1090
|
+
const dropIndex2 = (tableBuilder, index2) => {
|
|
1091
1091
|
if (!db.config.settings?.forceMigration) {
|
|
1092
1092
|
return;
|
|
1093
1093
|
}
|
|
@@ -1164,13 +1164,13 @@ const createHelpers = (db) => {
|
|
|
1164
1164
|
for (const removedIndex of table.indexes.removed) {
|
|
1165
1165
|
if (!ignoreForeignKeyNames.includes(removedIndex.name)) {
|
|
1166
1166
|
debug$2(`Dropping index ${removedIndex.name} on ${table.name}`);
|
|
1167
|
-
|
|
1167
|
+
dropIndex2(tableBuilder, removedIndex);
|
|
1168
1168
|
}
|
|
1169
1169
|
}
|
|
1170
1170
|
for (const updatedIndex of table.indexes.updated) {
|
|
1171
1171
|
if (!ignoreForeignKeyNames.includes(updatedIndex.name)) {
|
|
1172
1172
|
debug$2(`Dropping updated index ${updatedIndex.name} on ${table.name}`);
|
|
1173
|
-
|
|
1173
|
+
dropIndex2(tableBuilder, updatedIndex.object);
|
|
1174
1174
|
}
|
|
1175
1175
|
}
|
|
1176
1176
|
for (const updatedColumn of table.columns.updated) {
|
|
@@ -1356,27 +1356,28 @@ const createSchemaDiff = (db) => {
|
|
|
1356
1356
|
}
|
|
1357
1357
|
};
|
|
1358
1358
|
};
|
|
1359
|
-
const diffTableColumns = (
|
|
1359
|
+
const diffTableColumns = (diffCtx) => {
|
|
1360
|
+
const { databaseTable, userSchemaTable, previousTable } = diffCtx;
|
|
1360
1361
|
const addedColumns = [];
|
|
1361
1362
|
const updatedColumns = [];
|
|
1362
1363
|
const unchangedColumns = [];
|
|
1363
1364
|
const removedColumns = [];
|
|
1364
|
-
for (const
|
|
1365
|
-
const
|
|
1366
|
-
if (
|
|
1367
|
-
const { status, diff } = diffColumns(
|
|
1365
|
+
for (const userSchemaColumn of userSchemaTable.columns) {
|
|
1366
|
+
const databaseColumn = helpers.findColumn(databaseTable, userSchemaColumn.name);
|
|
1367
|
+
if (databaseColumn) {
|
|
1368
|
+
const { status, diff } = diffColumns(databaseColumn, userSchemaColumn);
|
|
1368
1369
|
if (status === statuses.CHANGED) {
|
|
1369
1370
|
updatedColumns.push(diff);
|
|
1370
1371
|
} else {
|
|
1371
|
-
unchangedColumns.push(
|
|
1372
|
+
unchangedColumns.push(databaseColumn);
|
|
1372
1373
|
}
|
|
1373
1374
|
} else {
|
|
1374
|
-
addedColumns.push(
|
|
1375
|
+
addedColumns.push(userSchemaColumn);
|
|
1375
1376
|
}
|
|
1376
1377
|
}
|
|
1377
|
-
for (const
|
|
1378
|
-
if (!helpers.hasColumn(
|
|
1379
|
-
removedColumns.push(
|
|
1378
|
+
for (const databaseColumn of databaseTable.columns) {
|
|
1379
|
+
if (!helpers.hasColumn(userSchemaTable, databaseColumn.name) && previousTable && helpers.hasColumn(previousTable, databaseColumn.name)) {
|
|
1380
|
+
removedColumns.push(databaseColumn);
|
|
1380
1381
|
}
|
|
1381
1382
|
}
|
|
1382
1383
|
const hasChanged = [addedColumns, updatedColumns, removedColumns].some((arr) => arr.length > 0);
|
|
@@ -1390,27 +1391,28 @@ const createSchemaDiff = (db) => {
|
|
|
1390
1391
|
}
|
|
1391
1392
|
};
|
|
1392
1393
|
};
|
|
1393
|
-
const diffTableIndexes = (
|
|
1394
|
+
const diffTableIndexes = (diffCtx) => {
|
|
1395
|
+
const { databaseTable, userSchemaTable, previousTable } = diffCtx;
|
|
1394
1396
|
const addedIndexes = [];
|
|
1395
1397
|
const updatedIndexes = [];
|
|
1396
1398
|
const unchangedIndexes = [];
|
|
1397
1399
|
const removedIndexes = [];
|
|
1398
|
-
for (const
|
|
1399
|
-
const
|
|
1400
|
-
if (
|
|
1401
|
-
const { status, diff } = diffIndexes(
|
|
1400
|
+
for (const userSchemaIndex of userSchemaTable.indexes) {
|
|
1401
|
+
const databaseIndex = helpers.findIndex(databaseTable, userSchemaIndex.name);
|
|
1402
|
+
if (databaseIndex) {
|
|
1403
|
+
const { status, diff } = diffIndexes(databaseIndex, userSchemaIndex);
|
|
1402
1404
|
if (status === statuses.CHANGED) {
|
|
1403
1405
|
updatedIndexes.push(diff);
|
|
1404
1406
|
} else {
|
|
1405
|
-
unchangedIndexes.push(
|
|
1407
|
+
unchangedIndexes.push(databaseIndex);
|
|
1406
1408
|
}
|
|
1407
1409
|
} else {
|
|
1408
|
-
addedIndexes.push(
|
|
1410
|
+
addedIndexes.push(userSchemaIndex);
|
|
1409
1411
|
}
|
|
1410
1412
|
}
|
|
1411
|
-
for (const
|
|
1412
|
-
if (!helpers.hasIndex(
|
|
1413
|
-
removedIndexes.push(
|
|
1413
|
+
for (const databaseIndex of databaseTable.indexes) {
|
|
1414
|
+
if (!helpers.hasIndex(userSchemaTable, databaseIndex.name) && previousTable && helpers.hasIndex(previousTable, databaseIndex.name)) {
|
|
1415
|
+
removedIndexes.push(databaseIndex);
|
|
1414
1416
|
}
|
|
1415
1417
|
}
|
|
1416
1418
|
const hasChanged = [addedIndexes, updatedIndexes, removedIndexes].some((arr) => arr.length > 0);
|
|
@@ -1424,7 +1426,8 @@ const createSchemaDiff = (db) => {
|
|
|
1424
1426
|
}
|
|
1425
1427
|
};
|
|
1426
1428
|
};
|
|
1427
|
-
const diffTableForeignKeys = (
|
|
1429
|
+
const diffTableForeignKeys = (diffCtx) => {
|
|
1430
|
+
const { databaseTable, userSchemaTable, previousTable } = diffCtx;
|
|
1428
1431
|
const addedForeignKeys = [];
|
|
1429
1432
|
const updatedForeignKeys = [];
|
|
1430
1433
|
const unchangedForeignKeys = [];
|
|
@@ -1440,22 +1443,22 @@ const createSchemaDiff = (db) => {
|
|
|
1440
1443
|
}
|
|
1441
1444
|
};
|
|
1442
1445
|
}
|
|
1443
|
-
for (const
|
|
1444
|
-
const
|
|
1445
|
-
if (
|
|
1446
|
-
const { status, diff } = diffForeignKeys(
|
|
1446
|
+
for (const userSchemaForeignKeys of userSchemaTable.foreignKeys) {
|
|
1447
|
+
const databaseForeignKeys = helpers.findForeignKey(databaseTable, userSchemaForeignKeys.name);
|
|
1448
|
+
if (databaseForeignKeys) {
|
|
1449
|
+
const { status, diff } = diffForeignKeys(databaseForeignKeys, userSchemaForeignKeys);
|
|
1447
1450
|
if (status === statuses.CHANGED) {
|
|
1448
1451
|
updatedForeignKeys.push(diff);
|
|
1449
1452
|
} else {
|
|
1450
|
-
unchangedForeignKeys.push(
|
|
1453
|
+
unchangedForeignKeys.push(databaseForeignKeys);
|
|
1451
1454
|
}
|
|
1452
1455
|
} else {
|
|
1453
|
-
addedForeignKeys.push(
|
|
1456
|
+
addedForeignKeys.push(userSchemaForeignKeys);
|
|
1454
1457
|
}
|
|
1455
1458
|
}
|
|
1456
|
-
for (const
|
|
1457
|
-
if (!helpers.hasForeignKey(
|
|
1458
|
-
removedForeignKeys.push(
|
|
1459
|
+
for (const databaseForeignKeys of databaseTable.foreignKeys) {
|
|
1460
|
+
if (!helpers.hasForeignKey(userSchemaTable, databaseForeignKeys.name) && previousTable && helpers.hasForeignKey(previousTable, databaseForeignKeys.name)) {
|
|
1461
|
+
removedForeignKeys.push(databaseForeignKeys);
|
|
1459
1462
|
}
|
|
1460
1463
|
}
|
|
1461
1464
|
const hasChanged = [addedForeignKeys, updatedForeignKeys, removedForeignKeys].some(
|
|
@@ -1471,37 +1474,44 @@ const createSchemaDiff = (db) => {
|
|
|
1471
1474
|
}
|
|
1472
1475
|
};
|
|
1473
1476
|
};
|
|
1474
|
-
const diffTables = (
|
|
1475
|
-
const
|
|
1476
|
-
const
|
|
1477
|
-
const
|
|
1477
|
+
const diffTables = (diffCtx) => {
|
|
1478
|
+
const { databaseTable } = diffCtx;
|
|
1479
|
+
const columnsDiff = diffTableColumns(diffCtx);
|
|
1480
|
+
const indexesDiff = diffTableIndexes(diffCtx);
|
|
1481
|
+
const foreignKeysDiff = diffTableForeignKeys(diffCtx);
|
|
1478
1482
|
const hasChanged = [columnsDiff, indexesDiff, foreignKeysDiff].some(hasChangedStatus);
|
|
1479
1483
|
return {
|
|
1480
1484
|
status: hasChanged ? statuses.CHANGED : statuses.UNCHANGED,
|
|
1481
1485
|
diff: {
|
|
1482
|
-
name:
|
|
1486
|
+
name: databaseTable.name,
|
|
1483
1487
|
indexes: indexesDiff.diff,
|
|
1484
1488
|
foreignKeys: foreignKeysDiff.diff,
|
|
1485
1489
|
columns: columnsDiff.diff
|
|
1486
1490
|
}
|
|
1487
1491
|
};
|
|
1488
1492
|
};
|
|
1489
|
-
const diffSchemas = async (
|
|
1493
|
+
const diffSchemas = async (schemaDiffCtx) => {
|
|
1494
|
+
const { previousSchema, databaseSchema, userSchema } = schemaDiffCtx;
|
|
1490
1495
|
const addedTables = [];
|
|
1491
1496
|
const updatedTables = [];
|
|
1492
1497
|
const unchangedTables = [];
|
|
1493
1498
|
const removedTables = [];
|
|
1494
|
-
for (const
|
|
1495
|
-
const
|
|
1496
|
-
|
|
1497
|
-
|
|
1499
|
+
for (const userSchemaTable of userSchema.tables) {
|
|
1500
|
+
const databaseTable = helpers.findTable(databaseSchema, userSchemaTable.name);
|
|
1501
|
+
const previousTable = previousSchema && helpers.findTable(previousSchema, userSchemaTable.name);
|
|
1502
|
+
if (databaseTable) {
|
|
1503
|
+
const { status, diff } = diffTables({
|
|
1504
|
+
previousTable,
|
|
1505
|
+
databaseTable,
|
|
1506
|
+
userSchemaTable
|
|
1507
|
+
});
|
|
1498
1508
|
if (status === statuses.CHANGED) {
|
|
1499
1509
|
updatedTables.push(diff);
|
|
1500
1510
|
} else {
|
|
1501
|
-
unchangedTables.push(
|
|
1511
|
+
unchangedTables.push(databaseTable);
|
|
1502
1512
|
}
|
|
1503
1513
|
} else {
|
|
1504
|
-
addedTables.push(
|
|
1514
|
+
addedTables.push(userSchemaTable);
|
|
1505
1515
|
}
|
|
1506
1516
|
}
|
|
1507
1517
|
const parsePersistedTable = (persistedTable) => {
|
|
@@ -1510,23 +1520,34 @@ const createSchemaDiff = (db) => {
|
|
|
1510
1520
|
}
|
|
1511
1521
|
return persistedTable.name;
|
|
1512
1522
|
};
|
|
1513
|
-
const persistedTables = helpers.hasTable(
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1523
|
+
const persistedTables = helpers.hasTable(databaseSchema, "strapi_core_store_settings") ? (
|
|
1524
|
+
// TODO: replace with low level db query instead
|
|
1525
|
+
await strapi.store.get({
|
|
1526
|
+
type: "core",
|
|
1527
|
+
key: "persisted_tables"
|
|
1528
|
+
}) ?? []
|
|
1529
|
+
) : [];
|
|
1517
1530
|
const reservedTables = [...RESERVED_TABLE_NAMES, ...persistedTables.map(parsePersistedTable)];
|
|
1518
|
-
for (const
|
|
1519
|
-
|
|
1531
|
+
for (const databaseTable of databaseSchema.tables) {
|
|
1532
|
+
const isInUserSchema = helpers.hasTable(userSchema, databaseTable.name);
|
|
1533
|
+
const wasTracked = previousSchema && helpers.hasTable(previousSchema, databaseTable.name);
|
|
1534
|
+
const isReserved = reservedTables.includes(databaseTable.name);
|
|
1535
|
+
if (!isInUserSchema && !wasTracked) {
|
|
1536
|
+
continue;
|
|
1537
|
+
}
|
|
1538
|
+
if (!isInUserSchema && wasTracked && !isReserved) {
|
|
1520
1539
|
const dependencies = persistedTables.filter((table) => {
|
|
1521
1540
|
const dependsOn = table?.dependsOn;
|
|
1522
1541
|
if (!_.isArray(dependsOn)) {
|
|
1523
1542
|
return;
|
|
1524
1543
|
}
|
|
1525
|
-
return dependsOn.some((table2) => table2.name ===
|
|
1544
|
+
return dependsOn.some((table2) => table2.name === databaseTable.name);
|
|
1526
1545
|
}).map((dependsOnTable) => {
|
|
1527
|
-
return
|
|
1546
|
+
return databaseSchema.tables.find(
|
|
1547
|
+
(databaseTable2) => databaseTable2.name === dependsOnTable.name
|
|
1548
|
+
);
|
|
1528
1549
|
}).filter((table) => !_.isNil(table));
|
|
1529
|
-
removedTables.push(
|
|
1550
|
+
removedTables.push(databaseTable, ...dependencies);
|
|
1530
1551
|
}
|
|
1531
1552
|
}
|
|
1532
1553
|
const hasChanged = [addedTables, updatedTables, removedTables].some((arr) => arr.length > 0);
|
|
@@ -2172,8 +2193,13 @@ const createSchemaProvider = (db) => {
|
|
|
2172
2193
|
},
|
|
2173
2194
|
async syncSchema() {
|
|
2174
2195
|
debug$1("Synchronizing database schema");
|
|
2175
|
-
const
|
|
2176
|
-
const
|
|
2196
|
+
const databaseSchema = await db.dialect.schemaInspector.getSchema();
|
|
2197
|
+
const storedSchema = await this.schemaStorage.read();
|
|
2198
|
+
const { status, diff } = await this.schemaDiff.diff({
|
|
2199
|
+
previousSchema: storedSchema?.schema,
|
|
2200
|
+
databaseSchema,
|
|
2201
|
+
userSchema: this.schema
|
|
2202
|
+
});
|
|
2177
2203
|
if (status === "CHANGED") {
|
|
2178
2204
|
await this.builder.updateSchema(diff);
|
|
2179
2205
|
}
|
|
@@ -2895,6 +2921,68 @@ const createField = (attribute) => {
|
|
|
2895
2921
|
}
|
|
2896
2922
|
throw new Error(`Undefined field for type ${type}`);
|
|
2897
2923
|
};
|
|
2924
|
+
const storage = new AsyncLocalStorage();
|
|
2925
|
+
const transactionCtx = {
|
|
2926
|
+
async run(trx, cb) {
|
|
2927
|
+
const store = storage.getStore();
|
|
2928
|
+
return storage.run(
|
|
2929
|
+
{
|
|
2930
|
+
trx,
|
|
2931
|
+
// Fill with existing callbacks if nesting transactions
|
|
2932
|
+
commitCallbacks: store?.commitCallbacks || [],
|
|
2933
|
+
rollbackCallbacks: store?.rollbackCallbacks || []
|
|
2934
|
+
},
|
|
2935
|
+
cb
|
|
2936
|
+
);
|
|
2937
|
+
},
|
|
2938
|
+
get() {
|
|
2939
|
+
const store = storage.getStore();
|
|
2940
|
+
return store?.trx;
|
|
2941
|
+
},
|
|
2942
|
+
async commit(trx) {
|
|
2943
|
+
const store = storage.getStore();
|
|
2944
|
+
if (store?.trx) {
|
|
2945
|
+
store.trx = null;
|
|
2946
|
+
}
|
|
2947
|
+
await trx.commit();
|
|
2948
|
+
if (!store?.commitCallbacks.length) {
|
|
2949
|
+
return;
|
|
2950
|
+
}
|
|
2951
|
+
store.commitCallbacks.forEach((cb) => cb());
|
|
2952
|
+
store.commitCallbacks = [];
|
|
2953
|
+
},
|
|
2954
|
+
async rollback(trx) {
|
|
2955
|
+
const store = storage.getStore();
|
|
2956
|
+
if (store?.trx) {
|
|
2957
|
+
store.trx = null;
|
|
2958
|
+
}
|
|
2959
|
+
await trx.rollback();
|
|
2960
|
+
if (!store?.rollbackCallbacks.length) {
|
|
2961
|
+
return;
|
|
2962
|
+
}
|
|
2963
|
+
store.rollbackCallbacks.forEach((cb) => cb());
|
|
2964
|
+
store.rollbackCallbacks = [];
|
|
2965
|
+
},
|
|
2966
|
+
onCommit(cb) {
|
|
2967
|
+
const store = storage.getStore();
|
|
2968
|
+
if (store?.commitCallbacks) {
|
|
2969
|
+
store.commitCallbacks.push(cb);
|
|
2970
|
+
}
|
|
2971
|
+
},
|
|
2972
|
+
onRollback(cb) {
|
|
2973
|
+
const store = storage.getStore();
|
|
2974
|
+
if (store?.rollbackCallbacks) {
|
|
2975
|
+
store.rollbackCallbacks.push(cb);
|
|
2976
|
+
}
|
|
2977
|
+
}
|
|
2978
|
+
};
|
|
2979
|
+
function isKnexQuery(value) {
|
|
2980
|
+
return value instanceof KnexBuilder || value instanceof KnexRaw;
|
|
2981
|
+
}
|
|
2982
|
+
const addSchema = (db, tableName) => {
|
|
2983
|
+
const schemaName = db.getSchemaName();
|
|
2984
|
+
return schemaName ? `${schemaName}.${tableName}` : tableName;
|
|
2985
|
+
};
|
|
2898
2986
|
const fromSingleRow = (meta, row) => {
|
|
2899
2987
|
const { attributes } = meta;
|
|
2900
2988
|
if (_.isNil(row)) {
|
|
@@ -3017,7 +3105,7 @@ const escapeQuery = (query, charsToEscape, escapeChar = "\\") => {
|
|
|
3017
3105
|
""
|
|
3018
3106
|
);
|
|
3019
3107
|
};
|
|
3020
|
-
const createPivotJoin = (ctx, { alias, refAlias, joinTable, targetMeta }) => {
|
|
3108
|
+
const createPivotJoin = (ctx, { alias: alias2, refAlias, joinTable, targetMeta }) => {
|
|
3021
3109
|
const { qb } = ctx;
|
|
3022
3110
|
const joinAlias = qb.getAlias();
|
|
3023
3111
|
qb.join({
|
|
@@ -3025,7 +3113,7 @@ const createPivotJoin = (ctx, { alias, refAlias, joinTable, targetMeta }) => {
|
|
|
3025
3113
|
referencedTable: joinTable.name,
|
|
3026
3114
|
referencedColumn: joinTable.joinColumn.name,
|
|
3027
3115
|
rootColumn: joinTable.joinColumn.referencedColumn,
|
|
3028
|
-
rootTable:
|
|
3116
|
+
rootTable: alias2,
|
|
3029
3117
|
on: joinTable.on
|
|
3030
3118
|
});
|
|
3031
3119
|
const subAlias = refAlias || qb.getAlias();
|
|
@@ -3038,7 +3126,7 @@ const createPivotJoin = (ctx, { alias, refAlias, joinTable, targetMeta }) => {
|
|
|
3038
3126
|
});
|
|
3039
3127
|
return subAlias;
|
|
3040
3128
|
};
|
|
3041
|
-
const createJoin = (ctx, { alias, refAlias, attributeName, attribute }) => {
|
|
3129
|
+
const createJoin = (ctx, { alias: alias2, refAlias, attributeName, attribute }) => {
|
|
3042
3130
|
const { db, qb, uid } = ctx;
|
|
3043
3131
|
if (attribute.type !== "relation") {
|
|
3044
3132
|
throw new Error(`Cannot join on non relational field ${attributeName}`);
|
|
@@ -3054,7 +3142,7 @@ const createJoin = (ctx, { alias, refAlias, attributeName, attribute }) => {
|
|
|
3054
3142
|
referencedTable: targetMeta.tableName,
|
|
3055
3143
|
referencedColumn: morphColumn.idColumn.name,
|
|
3056
3144
|
rootColumn: morphColumn.idColumn.referencedColumn,
|
|
3057
|
-
rootTable:
|
|
3145
|
+
rootTable: alias2,
|
|
3058
3146
|
on: {
|
|
3059
3147
|
[morphColumn.typeColumn.name]: uid,
|
|
3060
3148
|
...morphColumn.on
|
|
@@ -3069,7 +3157,7 @@ const createJoin = (ctx, { alias, refAlias, attributeName, attribute }) => {
|
|
|
3069
3157
|
referencedTable: joinTable2.name,
|
|
3070
3158
|
referencedColumn: joinTable2.morphColumn.idColumn.name,
|
|
3071
3159
|
rootColumn: joinTable2.morphColumn.idColumn.referencedColumn,
|
|
3072
|
-
rootTable:
|
|
3160
|
+
rootTable: alias2,
|
|
3073
3161
|
on: {
|
|
3074
3162
|
[joinTable2.morphColumn.typeColumn.name]: uid,
|
|
3075
3163
|
field: attributeName
|
|
@@ -3085,7 +3173,7 @@ const createJoin = (ctx, { alias, refAlias, attributeName, attribute }) => {
|
|
|
3085
3173
|
});
|
|
3086
3174
|
return subAlias;
|
|
3087
3175
|
}
|
|
3088
|
-
return
|
|
3176
|
+
return alias2;
|
|
3089
3177
|
}
|
|
3090
3178
|
const { joinColumn } = attribute;
|
|
3091
3179
|
if (joinColumn) {
|
|
@@ -3095,20 +3183,20 @@ const createJoin = (ctx, { alias, refAlias, attributeName, attribute }) => {
|
|
|
3095
3183
|
referencedTable: targetMeta.tableName,
|
|
3096
3184
|
referencedColumn: joinColumn.referencedColumn,
|
|
3097
3185
|
rootColumn: joinColumn.name,
|
|
3098
|
-
rootTable:
|
|
3186
|
+
rootTable: alias2
|
|
3099
3187
|
});
|
|
3100
3188
|
return subAlias;
|
|
3101
3189
|
}
|
|
3102
3190
|
const { joinTable } = attribute;
|
|
3103
3191
|
if (joinTable) {
|
|
3104
|
-
return createPivotJoin(ctx, { alias, refAlias, joinTable, targetMeta });
|
|
3192
|
+
return createPivotJoin(ctx, { alias: alias2, refAlias, joinTable, targetMeta });
|
|
3105
3193
|
}
|
|
3106
|
-
return
|
|
3194
|
+
return alias2;
|
|
3107
3195
|
};
|
|
3108
3196
|
const applyJoin = (qb, join) => {
|
|
3109
3197
|
const {
|
|
3110
3198
|
method = "leftJoin",
|
|
3111
|
-
alias,
|
|
3199
|
+
alias: alias2,
|
|
3112
3200
|
referencedTable,
|
|
3113
3201
|
referencedColumn,
|
|
3114
3202
|
rootColumn,
|
|
@@ -3118,26 +3206,28 @@ const applyJoin = (qb, join) => {
|
|
|
3118
3206
|
on,
|
|
3119
3207
|
orderBy
|
|
3120
3208
|
} = join;
|
|
3121
|
-
qb[method](`${referencedTable} as ${
|
|
3122
|
-
inner.on(`${rootTable}.${rootColumn}`, `${
|
|
3209
|
+
qb[method](`${referencedTable} as ${alias2}`, (inner) => {
|
|
3210
|
+
inner.on(`${rootTable}.${rootColumn}`, `${alias2}.${referencedColumn}`);
|
|
3123
3211
|
if (on) {
|
|
3124
3212
|
for (const key of Object.keys(on)) {
|
|
3125
|
-
inner.onVal(`${
|
|
3213
|
+
inner.onVal(`${alias2}.${key}`, on[key]);
|
|
3126
3214
|
}
|
|
3127
3215
|
}
|
|
3128
3216
|
});
|
|
3129
3217
|
if (orderBy) {
|
|
3130
3218
|
Object.keys(orderBy).forEach((column) => {
|
|
3131
3219
|
const direction = orderBy[column];
|
|
3132
|
-
qb.orderBy(`${
|
|
3220
|
+
qb.orderBy(`${alias2}.${column}`, direction);
|
|
3133
3221
|
});
|
|
3134
3222
|
}
|
|
3135
3223
|
};
|
|
3136
3224
|
const applyJoins = (qb, joins) => {
|
|
3137
3225
|
return joins.forEach((join) => applyJoin(qb, join));
|
|
3138
3226
|
};
|
|
3227
|
+
const COL_STRAPI_ROW_NUMBER = "__strapi_row_number";
|
|
3228
|
+
const COL_STRAPI_ORDER_BY_PREFIX = "__strapi_order_by";
|
|
3139
3229
|
const processOrderBy = (orderBy, ctx) => {
|
|
3140
|
-
const { db, uid, qb, alias } = ctx;
|
|
3230
|
+
const { db, uid, qb, alias: alias2 } = ctx;
|
|
3141
3231
|
const meta = db.metadata.get(uid);
|
|
3142
3232
|
const { attributes } = meta;
|
|
3143
3233
|
if (typeof orderBy === "string") {
|
|
@@ -3146,7 +3236,7 @@ const processOrderBy = (orderBy, ctx) => {
|
|
|
3146
3236
|
throw new Error(`Attribute ${orderBy} not found on model ${uid}`);
|
|
3147
3237
|
}
|
|
3148
3238
|
const columnName = toColumnName(meta, orderBy);
|
|
3149
|
-
return [{ column: qb.aliasColumn(columnName,
|
|
3239
|
+
return [{ column: qb.aliasColumn(columnName, alias2) }];
|
|
3150
3240
|
}
|
|
3151
3241
|
if (Array.isArray(orderBy)) {
|
|
3152
3242
|
return orderBy.flatMap((value) => processOrderBy(value, ctx));
|
|
@@ -3160,11 +3250,11 @@ const processOrderBy = (orderBy, ctx) => {
|
|
|
3160
3250
|
}
|
|
3161
3251
|
if (isScalar(attribute.type)) {
|
|
3162
3252
|
const columnName = toColumnName(meta, key);
|
|
3163
|
-
return { column: qb.aliasColumn(columnName,
|
|
3253
|
+
return { column: qb.aliasColumn(columnName, alias2), order: direction };
|
|
3164
3254
|
}
|
|
3165
3255
|
if (attribute.type === "relation" && "target" in attribute) {
|
|
3166
3256
|
const subAlias = createJoin(ctx, {
|
|
3167
|
-
alias:
|
|
3257
|
+
alias: alias2 || qb.alias,
|
|
3168
3258
|
attributeName: key,
|
|
3169
3259
|
attribute
|
|
3170
3260
|
});
|
|
@@ -3180,6 +3270,75 @@ const processOrderBy = (orderBy, ctx) => {
|
|
|
3180
3270
|
}
|
|
3181
3271
|
throw new Error("Invalid orderBy syntax");
|
|
3182
3272
|
};
|
|
3273
|
+
const getStrapiOrderColumnAlias = (column) => {
|
|
3274
|
+
const trimmedColumnName = column.replaceAll(".", "_");
|
|
3275
|
+
return `${COL_STRAPI_ORDER_BY_PREFIX}__${trimmedColumnName}`;
|
|
3276
|
+
};
|
|
3277
|
+
const wrapWithDeepSort = (originalQuery, ctx) => {
|
|
3278
|
+
const { db, qb, uid } = ctx;
|
|
3279
|
+
const { tableName } = db.metadata.get(uid);
|
|
3280
|
+
const orderBy = _.cloneDeep(qb.state.orderBy);
|
|
3281
|
+
const resultQueryAlias = qb.getAlias();
|
|
3282
|
+
const aliasedTableName = qb.mustUseAlias() ? alias(resultQueryAlias, tableName) : tableName;
|
|
3283
|
+
const resultQuery = db.getConnection(aliasedTableName);
|
|
3284
|
+
const baseQuery = originalQuery.clone();
|
|
3285
|
+
const baseQueryAlias = qb.getAlias();
|
|
3286
|
+
baseQuery.clear("select").clear("order").clear("limit").clear("offset");
|
|
3287
|
+
baseQuery.select(
|
|
3288
|
+
// Always select the row id for future manipulation
|
|
3289
|
+
prefix(qb.alias, "id"),
|
|
3290
|
+
...orderBy.map(
|
|
3291
|
+
(orderByClause) => alias(getStrapiOrderColumnAlias(orderByClause.column), orderByClause.column)
|
|
3292
|
+
)
|
|
3293
|
+
);
|
|
3294
|
+
const partitionedQueryAlias = qb.getAlias();
|
|
3295
|
+
const selectRowsAsNumberedPartitions = (partitionedQuery) => {
|
|
3296
|
+
const prefixedOrderBy = orderBy.map((orderByClause) => ({
|
|
3297
|
+
column: prefix(baseQueryAlias, getStrapiOrderColumnAlias(orderByClause.column)),
|
|
3298
|
+
order: orderByClause.order
|
|
3299
|
+
}));
|
|
3300
|
+
const orderByColumns = prefixedOrderBy.map(_.prop("column"));
|
|
3301
|
+
partitionedQuery.select(
|
|
3302
|
+
// Always select baseQuery.id
|
|
3303
|
+
prefix(baseQueryAlias, "id"),
|
|
3304
|
+
...orderByColumns
|
|
3305
|
+
).rowNumber(COL_STRAPI_ROW_NUMBER, (subQuery) => {
|
|
3306
|
+
for (const orderByClause of prefixedOrderBy) {
|
|
3307
|
+
subQuery.orderBy(orderByClause.column, orderByClause.order, "last");
|
|
3308
|
+
}
|
|
3309
|
+
subQuery.partitionBy(`${baseQueryAlias}.id`);
|
|
3310
|
+
}).from(baseQuery.as(baseQueryAlias)).as(partitionedQueryAlias);
|
|
3311
|
+
};
|
|
3312
|
+
const originalSelect = _.difference(
|
|
3313
|
+
qb.state.select,
|
|
3314
|
+
// Remove order by columns from the initial select
|
|
3315
|
+
qb.state.orderBy.map(_.prop("column"))
|
|
3316
|
+
).map(prefix(resultQueryAlias));
|
|
3317
|
+
resultQuery.select(originalSelect).innerJoin(selectRowsAsNumberedPartitions, function() {
|
|
3318
|
+
this.on(`${partitionedQueryAlias}.id`, `${resultQueryAlias}.id`).andOnVal(`${partitionedQueryAlias}.${COL_STRAPI_ROW_NUMBER}`, "=", 1);
|
|
3319
|
+
});
|
|
3320
|
+
if (qb.state.limit) {
|
|
3321
|
+
resultQuery.limit(qb.state.limit);
|
|
3322
|
+
}
|
|
3323
|
+
if (qb.state.offset) {
|
|
3324
|
+
resultQuery.offset(qb.state.offset);
|
|
3325
|
+
}
|
|
3326
|
+
if (qb.state.first) {
|
|
3327
|
+
resultQuery.first();
|
|
3328
|
+
}
|
|
3329
|
+
resultQuery.orderBy([
|
|
3330
|
+
// Transform "order by" clause to their T alias and prefix them with T alias
|
|
3331
|
+
...orderBy.map((orderByClause) => ({
|
|
3332
|
+
column: prefix(partitionedQueryAlias, getStrapiOrderColumnAlias(orderByClause.column)),
|
|
3333
|
+
order: orderByClause.order
|
|
3334
|
+
})),
|
|
3335
|
+
// Add T.id to the order by clause to get consistent results in case several rows have the exact same order
|
|
3336
|
+
{ column: `${partitionedQueryAlias}.id`, order: "asc" }
|
|
3337
|
+
]);
|
|
3338
|
+
return resultQuery;
|
|
3339
|
+
};
|
|
3340
|
+
const alias = _.curry((alias2, value) => `${value} as ${alias2}`);
|
|
3341
|
+
const prefix = _.curry((prefix2, value) => `${prefix2}.${value}`);
|
|
3183
3342
|
const joinColPrefix = "__strapi";
|
|
3184
3343
|
const XtoOne = async (input, ctx) => {
|
|
3185
3344
|
const { attribute, attributeName, results, populateValue, targetMeta, isCount } = input;
|
|
@@ -3207,8 +3366,8 @@ const XtoOne = async (input, ctx) => {
|
|
|
3207
3366
|
const { joinTable } = attribute;
|
|
3208
3367
|
const qb2 = db.entityManager.createQueryBuilder(targetMeta.uid);
|
|
3209
3368
|
const { name: joinColumnName, referencedColumn: referencedColumnName } = joinTable.joinColumn;
|
|
3210
|
-
const
|
|
3211
|
-
const joinColAlias = `${
|
|
3369
|
+
const alias2 = qb2.getAlias();
|
|
3370
|
+
const joinColAlias = `${alias2}.${joinColumnName}`;
|
|
3212
3371
|
const joinColRenameAs = `${joinColPrefix}${joinColumnName}`;
|
|
3213
3372
|
const joinColSelect = `${joinColAlias} as ${joinColRenameAs}`;
|
|
3214
3373
|
const referencedValues = _.uniq(
|
|
@@ -3222,7 +3381,7 @@ const XtoOne = async (input, ctx) => {
|
|
|
3222
3381
|
return;
|
|
3223
3382
|
}
|
|
3224
3383
|
const rows2 = await qb2.init(populateValue).join({
|
|
3225
|
-
alias,
|
|
3384
|
+
alias: alias2,
|
|
3226
3385
|
referencedTable: joinTable.name,
|
|
3227
3386
|
referencedColumn: joinTable.inverseJoinColumn.name,
|
|
3228
3387
|
rootColumn: joinTable.inverseJoinColumn.referencedColumn,
|
|
@@ -3248,7 +3407,7 @@ const XtoOne = async (input, ctx) => {
|
|
|
3248
3407
|
return;
|
|
3249
3408
|
}
|
|
3250
3409
|
const rows = await qb2.init(populateValue).join({
|
|
3251
|
-
alias,
|
|
3410
|
+
alias: alias2,
|
|
3252
3411
|
referencedTable: joinTable.name,
|
|
3253
3412
|
referencedColumn: joinTable.inverseJoinColumn.name,
|
|
3254
3413
|
rootColumn: joinTable.inverseJoinColumn.referencedColumn,
|
|
@@ -3288,8 +3447,8 @@ const oneToMany = async (input, ctx) => {
|
|
|
3288
3447
|
const { joinTable } = attribute;
|
|
3289
3448
|
const qb2 = db.entityManager.createQueryBuilder(targetMeta.uid);
|
|
3290
3449
|
const { name: joinColumnName, referencedColumn: referencedColumnName } = joinTable.joinColumn;
|
|
3291
|
-
const
|
|
3292
|
-
const joinColAlias = `${
|
|
3450
|
+
const alias2 = qb2.getAlias();
|
|
3451
|
+
const joinColAlias = `${alias2}.${joinColumnName}`;
|
|
3293
3452
|
const joinColRenameAs = `${joinColPrefix}${joinColumnName}`;
|
|
3294
3453
|
const joinColSelect = `${joinColAlias} as ${joinColRenameAs}`;
|
|
3295
3454
|
const referencedValues = _.uniq(
|
|
@@ -3303,7 +3462,7 @@ const oneToMany = async (input, ctx) => {
|
|
|
3303
3462
|
return;
|
|
3304
3463
|
}
|
|
3305
3464
|
const rows2 = await qb2.init(populateValue).join({
|
|
3306
|
-
alias,
|
|
3465
|
+
alias: alias2,
|
|
3307
3466
|
referencedTable: joinTable.name,
|
|
3308
3467
|
referencedColumn: joinTable.inverseJoinColumn.name,
|
|
3309
3468
|
rootColumn: joinTable.inverseJoinColumn.referencedColumn,
|
|
@@ -3329,7 +3488,7 @@ const oneToMany = async (input, ctx) => {
|
|
|
3329
3488
|
return;
|
|
3330
3489
|
}
|
|
3331
3490
|
const rows = await qb2.init(populateValue).join({
|
|
3332
|
-
alias,
|
|
3491
|
+
alias: alias2,
|
|
3333
3492
|
referencedTable: joinTable.name,
|
|
3334
3493
|
referencedColumn: joinTable.inverseJoinColumn.name,
|
|
3335
3494
|
rootColumn: joinTable.inverseJoinColumn.referencedColumn,
|
|
@@ -3350,8 +3509,8 @@ const manyToMany = async (input, ctx) => {
|
|
|
3350
3509
|
const { joinTable } = attribute;
|
|
3351
3510
|
const populateQb = db.entityManager.createQueryBuilder(targetMeta.uid);
|
|
3352
3511
|
const { name: joinColumnName, referencedColumn: referencedColumnName } = joinTable.joinColumn;
|
|
3353
|
-
const
|
|
3354
|
-
const joinColAlias = `${
|
|
3512
|
+
const alias2 = populateQb.getAlias();
|
|
3513
|
+
const joinColAlias = `${alias2}.${joinColumnName}`;
|
|
3355
3514
|
const joinColRenameAs = `${joinColPrefix}${joinColumnName}`;
|
|
3356
3515
|
const joinColSelect = `${joinColAlias} as ${joinColRenameAs}`;
|
|
3357
3516
|
const referencedValues = _.uniq(
|
|
@@ -3365,7 +3524,7 @@ const manyToMany = async (input, ctx) => {
|
|
|
3365
3524
|
return;
|
|
3366
3525
|
}
|
|
3367
3526
|
const rows2 = await populateQb.init(populateValue).join({
|
|
3368
|
-
alias,
|
|
3527
|
+
alias: alias2,
|
|
3369
3528
|
referencedTable: joinTable.name,
|
|
3370
3529
|
referencedColumn: joinTable.inverseJoinColumn.name,
|
|
3371
3530
|
rootColumn: joinTable.inverseJoinColumn.referencedColumn,
|
|
@@ -3391,7 +3550,7 @@ const manyToMany = async (input, ctx) => {
|
|
|
3391
3550
|
return;
|
|
3392
3551
|
}
|
|
3393
3552
|
const rows = await populateQb.init(populateValue).join({
|
|
3394
|
-
alias,
|
|
3553
|
+
alias: alias2,
|
|
3395
3554
|
referencedTable: joinTable.name,
|
|
3396
3555
|
referencedColumn: joinTable.inverseJoinColumn.name,
|
|
3397
3556
|
rootColumn: joinTable.inverseJoinColumn.referencedColumn,
|
|
@@ -3442,9 +3601,9 @@ const morphX = async (input, ctx) => {
|
|
|
3442
3601
|
return;
|
|
3443
3602
|
}
|
|
3444
3603
|
const qb = db.entityManager.createQueryBuilder(target);
|
|
3445
|
-
const
|
|
3604
|
+
const alias2 = qb.getAlias();
|
|
3446
3605
|
const rows = await qb.init(populateValue).join({
|
|
3447
|
-
alias,
|
|
3606
|
+
alias: alias2,
|
|
3448
3607
|
referencedTable: joinTable.name,
|
|
3449
3608
|
referencedColumn: joinColumn.name,
|
|
3450
3609
|
rootColumn: joinColumn.referencedColumn,
|
|
@@ -3454,9 +3613,9 @@ const morphX = async (input, ctx) => {
|
|
|
3454
3613
|
field: attributeName
|
|
3455
3614
|
},
|
|
3456
3615
|
orderBy: _.mapValues((v) => populateValue.ordering || v, joinTable.orderBy)
|
|
3457
|
-
}).addSelect([`${
|
|
3458
|
-
[`${
|
|
3459
|
-
[`${
|
|
3616
|
+
}).addSelect([`${alias2}.${idColumn.name}`, `${alias2}.${typeColumn.name}`]).where({
|
|
3617
|
+
[`${alias2}.${idColumn.name}`]: referencedValues,
|
|
3618
|
+
[`${alias2}.${typeColumn.name}`]: uid
|
|
3460
3619
|
}).execute({ mapResults: false });
|
|
3461
3620
|
const map2 = _.groupBy(idColumn.name)(rows);
|
|
3462
3621
|
results.forEach((result) => {
|
|
@@ -3705,13 +3864,6 @@ const processPopulate = (populate, ctx) => {
|
|
|
3705
3864
|
}
|
|
3706
3865
|
return finalPopulate;
|
|
3707
3866
|
};
|
|
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
3867
|
const isRecord$1 = (value) => isPlainObject(value);
|
|
3716
3868
|
const castValue = (value, attribute) => {
|
|
3717
3869
|
if (!attribute) {
|
|
@@ -3753,8 +3905,8 @@ const processNested = (where, ctx) => {
|
|
|
3753
3905
|
return processWhere(where, ctx);
|
|
3754
3906
|
};
|
|
3755
3907
|
const processRelationWhere = (where, ctx) => {
|
|
3756
|
-
const { qb, alias } = ctx;
|
|
3757
|
-
const idAlias = qb.aliasColumn("id",
|
|
3908
|
+
const { qb, alias: alias2 } = ctx;
|
|
3909
|
+
const idAlias = qb.aliasColumn("id", alias2);
|
|
3758
3910
|
if (!isRecord$1(where)) {
|
|
3759
3911
|
return { [idAlias]: where };
|
|
3760
3912
|
}
|
|
@@ -3784,7 +3936,7 @@ function processWhere(where, ctx) {
|
|
|
3784
3936
|
if (isArray(where)) {
|
|
3785
3937
|
return where.map((sub) => processWhere(sub, ctx));
|
|
3786
3938
|
}
|
|
3787
|
-
const { db, uid, qb, alias } = ctx;
|
|
3939
|
+
const { db, uid, qb, alias: alias2 } = ctx;
|
|
3788
3940
|
const meta = db.metadata.get(uid);
|
|
3789
3941
|
const filters = {};
|
|
3790
3942
|
for (const key of Object.keys(where)) {
|
|
@@ -3807,12 +3959,12 @@ function processWhere(where, ctx) {
|
|
|
3807
3959
|
}
|
|
3808
3960
|
const attribute = meta.attributes[key];
|
|
3809
3961
|
if (!attribute) {
|
|
3810
|
-
filters[qb.aliasColumn(key,
|
|
3962
|
+
filters[qb.aliasColumn(key, alias2)] = processAttributeWhere(null, value);
|
|
3811
3963
|
continue;
|
|
3812
3964
|
}
|
|
3813
3965
|
if (isRelation(attribute.type) && "target" in attribute) {
|
|
3814
3966
|
const subAlias = createJoin(ctx, {
|
|
3815
|
-
alias:
|
|
3967
|
+
alias: alias2 || qb.alias,
|
|
3816
3968
|
attributeName: key,
|
|
3817
3969
|
attribute
|
|
3818
3970
|
});
|
|
@@ -3827,7 +3979,7 @@ function processWhere(where, ctx) {
|
|
|
3827
3979
|
}
|
|
3828
3980
|
if (isScalar(attribute.type)) {
|
|
3829
3981
|
const columnName = toColumnName(meta, key);
|
|
3830
|
-
const aliasedColumnName = qb.aliasColumn(columnName,
|
|
3982
|
+
const aliasedColumnName = qb.aliasColumn(columnName, alias2);
|
|
3831
3983
|
filters[aliasedColumnName] = processAttributeWhere(attribute, value);
|
|
3832
3984
|
continue;
|
|
3833
3985
|
}
|
|
@@ -4055,7 +4207,7 @@ class ReadableStrapiQuery extends Readable {
|
|
|
4055
4207
|
* Custom ._read() implementation
|
|
4056
4208
|
*
|
|
4057
4209
|
* NOTE: Here "size" means the number of entities to be read from the database.
|
|
4058
|
-
* Not the actual byte size, as it would
|
|
4210
|
+
* Not the actual byte size, as it would mean that we need to return partial entities.
|
|
4059
4211
|
*
|
|
4060
4212
|
*/
|
|
4061
4213
|
async _read(size) {
|
|
@@ -4118,61 +4270,6 @@ class ReadableStrapiQuery extends Readable {
|
|
|
4118
4270
|
}
|
|
4119
4271
|
}
|
|
4120
4272
|
}
|
|
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
4273
|
const createQueryBuilder = (uid, db, initialState = {}) => {
|
|
4177
4274
|
const meta = db.metadata.get(uid);
|
|
4178
4275
|
const { tableName } = meta;
|
|
@@ -4205,9 +4302,9 @@ const createQueryBuilder = (uid, db, initialState = {}) => {
|
|
|
4205
4302
|
initialState
|
|
4206
4303
|
);
|
|
4207
4304
|
const getAlias = () => {
|
|
4208
|
-
const
|
|
4305
|
+
const alias2 = `t${state.aliasCounter}`;
|
|
4209
4306
|
state.aliasCounter += 1;
|
|
4210
|
-
return
|
|
4307
|
+
return alias2;
|
|
4211
4308
|
};
|
|
4212
4309
|
return {
|
|
4213
4310
|
alias: getAlias(),
|
|
@@ -4374,15 +4471,15 @@ const createQueryBuilder = (uid, db, initialState = {}) => {
|
|
|
4374
4471
|
mustUseAlias() {
|
|
4375
4472
|
return ["select", "count"].includes(state.type);
|
|
4376
4473
|
},
|
|
4377
|
-
aliasColumn(key,
|
|
4474
|
+
aliasColumn(key, alias2) {
|
|
4378
4475
|
if (typeof key !== "string") {
|
|
4379
4476
|
return key;
|
|
4380
4477
|
}
|
|
4381
4478
|
if (key.indexOf(".") >= 0) {
|
|
4382
4479
|
return key;
|
|
4383
4480
|
}
|
|
4384
|
-
if (!_.isNil(
|
|
4385
|
-
return `${
|
|
4481
|
+
if (!_.isNil(alias2)) {
|
|
4482
|
+
return `${alias2}.${key}`;
|
|
4386
4483
|
}
|
|
4387
4484
|
return this.mustUseAlias() ? `${this.alias}.${key}` : key;
|
|
4388
4485
|
},
|
|
@@ -4417,6 +4514,20 @@ const createQueryBuilder = (uid, db, initialState = {}) => {
|
|
|
4417
4514
|
shouldUseDistinct() {
|
|
4418
4515
|
return state.joins.length > 0 && _.isEmpty(state.groupBy);
|
|
4419
4516
|
},
|
|
4517
|
+
shouldUseDeepSort() {
|
|
4518
|
+
return state.orderBy.filter(({ column }) => column.indexOf(".") >= 0).filter(({ column }) => {
|
|
4519
|
+
const col = column.split(".");
|
|
4520
|
+
for (let i = 0; i < col.length - 1; i += 1) {
|
|
4521
|
+
const el = col[i];
|
|
4522
|
+
const isRelationAttribute = meta.attributes[el]?.type === "relation";
|
|
4523
|
+
const isAliasedRelation = Object.values(state.joins).map((join) => join.alias).includes(el);
|
|
4524
|
+
if (isRelationAttribute || isAliasedRelation) {
|
|
4525
|
+
return true;
|
|
4526
|
+
}
|
|
4527
|
+
}
|
|
4528
|
+
return false;
|
|
4529
|
+
}).length > 0;
|
|
4530
|
+
},
|
|
4420
4531
|
processSelect() {
|
|
4421
4532
|
state.select = state.select.map((field) => {
|
|
4422
4533
|
if (isKnexQuery(field)) {
|
|
@@ -4534,6 +4645,9 @@ const createQueryBuilder = (uid, db, initialState = {}) => {
|
|
|
4534
4645
|
if (state.joins.length > 0) {
|
|
4535
4646
|
applyJoins(qb, state.joins);
|
|
4536
4647
|
}
|
|
4648
|
+
if (this.shouldUseDeepSort()) {
|
|
4649
|
+
return wrapWithDeepSort(qb, { qb: this, db, uid });
|
|
4650
|
+
}
|
|
4537
4651
|
return qb;
|
|
4538
4652
|
},
|
|
4539
4653
|
async execute({ mapResults = true } = {}) {
|
|
@@ -4735,7 +4849,7 @@ const deleteRelatedMorphOneRelationsAfterMorphToManyUpdate = async (rows, {
|
|
|
4735
4849
|
await createQueryBuilder(joinTable.name, db).delete().where({ $or: orWhere }).transacting(trx).execute();
|
|
4736
4850
|
}
|
|
4737
4851
|
};
|
|
4738
|
-
const getDocumentSiblingIdsQuery = (
|
|
4852
|
+
const getDocumentSiblingIdsQuery = (tableName, id) => {
|
|
4739
4853
|
const models = Array.from(strapi.db.metadata.values());
|
|
4740
4854
|
const isContentType = models.find((model) => {
|
|
4741
4855
|
return model.tableName === tableName && model.attributes.documentId;
|
|
@@ -4743,10 +4857,11 @@ const getDocumentSiblingIdsQuery = (con, tableName, id) => {
|
|
|
4743
4857
|
if (!isContentType) {
|
|
4744
4858
|
return [id];
|
|
4745
4859
|
}
|
|
4746
|
-
return
|
|
4747
|
-
"document_id",
|
|
4748
|
-
|
|
4749
|
-
|
|
4860
|
+
return function(query) {
|
|
4861
|
+
query.select("id").from(tableName).whereIn("document_id", (documentIDSubQuery) => {
|
|
4862
|
+
documentIDSubQuery.from(tableName).select("document_id").where("id", id);
|
|
4863
|
+
});
|
|
4864
|
+
};
|
|
4750
4865
|
};
|
|
4751
4866
|
const deletePreviousOneToAnyRelations = async ({
|
|
4752
4867
|
id,
|
|
@@ -4763,7 +4878,7 @@ const deletePreviousOneToAnyRelations = async ({
|
|
|
4763
4878
|
const { joinTable } = attribute;
|
|
4764
4879
|
const { joinColumn, inverseJoinColumn } = joinTable;
|
|
4765
4880
|
const con = db.getConnection();
|
|
4766
|
-
await con.delete().from(joinTable.name).whereNotIn(joinColumn.name, getDocumentSiblingIdsQuery(
|
|
4881
|
+
await con.delete().from(joinTable.name).whereNotIn(joinColumn.name, getDocumentSiblingIdsQuery(joinColumn.referencedTable, id)).whereIn(inverseJoinColumn.name, relIdsToadd).where(joinTable.on || {}).transacting(trx);
|
|
4767
4882
|
await cleanOrderColumns({ attribute, db, inverseRelIds: relIdsToadd, transaction: trx });
|
|
4768
4883
|
};
|
|
4769
4884
|
const deletePreviousAnyToOneRelations = async ({
|
|
@@ -4782,7 +4897,7 @@ const deletePreviousAnyToOneRelations = async ({
|
|
|
4782
4897
|
if (isManyToAny(attribute)) {
|
|
4783
4898
|
const relsToDelete = await con.select(inverseJoinColumn.name).from(joinTable.name).where(joinColumn.name, id).whereNotIn(
|
|
4784
4899
|
inverseJoinColumn.name,
|
|
4785
|
-
getDocumentSiblingIdsQuery(
|
|
4900
|
+
getDocumentSiblingIdsQuery(inverseJoinColumn.referencedTable, relIdToadd)
|
|
4786
4901
|
).where(joinTable.on || {}).transacting(trx);
|
|
4787
4902
|
const relIdsToDelete = map(inverseJoinColumn.name, relsToDelete);
|
|
4788
4903
|
await createQueryBuilder(joinTable.name, db).delete().where({
|
|
@@ -4793,7 +4908,7 @@ const deletePreviousAnyToOneRelations = async ({
|
|
|
4793
4908
|
} else {
|
|
4794
4909
|
await con.delete().from(joinTable.name).where(joinColumn.name, id).whereNotIn(
|
|
4795
4910
|
inverseJoinColumn.name,
|
|
4796
|
-
getDocumentSiblingIdsQuery(
|
|
4911
|
+
getDocumentSiblingIdsQuery(inverseJoinColumn.referencedTable, relIdToadd)
|
|
4797
4912
|
).where(joinTable.on || {}).transacting(trx);
|
|
4798
4913
|
}
|
|
4799
4914
|
};
|
|
@@ -5877,6 +5992,21 @@ const createStorage = (opts) => {
|
|
|
5877
5992
|
const wrapTransaction = (db) => (fn) => () => {
|
|
5878
5993
|
return db.transaction(({ trx }) => Promise.resolve(fn(trx, db)));
|
|
5879
5994
|
};
|
|
5995
|
+
const transformLogMessage = (level, message) => {
|
|
5996
|
+
if (typeof message === "string") {
|
|
5997
|
+
return { level, message };
|
|
5998
|
+
}
|
|
5999
|
+
if (typeof message === "object" && message !== null) {
|
|
6000
|
+
if ("event" in message && "name" in message) {
|
|
6001
|
+
return {
|
|
6002
|
+
level,
|
|
6003
|
+
message: `[internal migration]: ${message.event} ${message?.name}`,
|
|
6004
|
+
timestamp: Date.now()
|
|
6005
|
+
};
|
|
6006
|
+
}
|
|
6007
|
+
}
|
|
6008
|
+
return "";
|
|
6009
|
+
};
|
|
5880
6010
|
const migrationResolver = ({ name, path: path2, context }) => {
|
|
5881
6011
|
const { db } = context;
|
|
5882
6012
|
if (!path2) {
|
|
@@ -5905,7 +6035,20 @@ const createUserMigrationProvider = (db) => {
|
|
|
5905
6035
|
const context = { db };
|
|
5906
6036
|
const umzugProvider = new Umzug({
|
|
5907
6037
|
storage: createStorage({ db, tableName: "strapi_migrations" }),
|
|
5908
|
-
logger:
|
|
6038
|
+
logger: {
|
|
6039
|
+
info(message) {
|
|
6040
|
+
db.logger.info(transformLogMessage("info", message));
|
|
6041
|
+
},
|
|
6042
|
+
warn(message) {
|
|
6043
|
+
db.logger.warn(transformLogMessage("warn", message));
|
|
6044
|
+
},
|
|
6045
|
+
error(message) {
|
|
6046
|
+
db.logger.error(transformLogMessage("error", message));
|
|
6047
|
+
},
|
|
6048
|
+
debug(message) {
|
|
6049
|
+
db.logger.debug(transformLogMessage("debug", message));
|
|
6050
|
+
}
|
|
6051
|
+
},
|
|
5909
6052
|
context,
|
|
5910
6053
|
migrations: {
|
|
5911
6054
|
glob: ["*.{js,sql}", { cwd: dir }],
|
|
@@ -6211,7 +6354,8 @@ const createdLocale = {
|
|
|
6211
6354
|
if (!model) {
|
|
6212
6355
|
continue;
|
|
6213
6356
|
}
|
|
6214
|
-
|
|
6357
|
+
const hasLocaleColumn = await knex2.schema.hasColumn(meta.tableName, "locale");
|
|
6358
|
+
if (meta.attributes.locale && !hasLocaleColumn) {
|
|
6215
6359
|
await createLocaleColumn(knex2, meta.tableName);
|
|
6216
6360
|
}
|
|
6217
6361
|
}
|
|
@@ -6220,17 +6364,87 @@ const createdLocale = {
|
|
|
6220
6364
|
throw new Error("not implemented");
|
|
6221
6365
|
}
|
|
6222
6366
|
};
|
|
6367
|
+
const createPublishedAtColumn = async (db, tableName) => {
|
|
6368
|
+
await db.schema.alterTable(tableName, (table) => {
|
|
6369
|
+
table.string("published_at");
|
|
6370
|
+
});
|
|
6371
|
+
};
|
|
6372
|
+
const createdPublishedAt = {
|
|
6373
|
+
name: "5.0.0-04-created-published-at",
|
|
6374
|
+
async up(knex2, db) {
|
|
6375
|
+
for (const meta of db.metadata.values()) {
|
|
6376
|
+
const hasTable = await knex2.schema.hasTable(meta.tableName);
|
|
6377
|
+
if (!hasTable) {
|
|
6378
|
+
continue;
|
|
6379
|
+
}
|
|
6380
|
+
const uid = meta.uid;
|
|
6381
|
+
const model = strapi.getModel(uid);
|
|
6382
|
+
if (!model) {
|
|
6383
|
+
continue;
|
|
6384
|
+
}
|
|
6385
|
+
const hasPublishedAtColumn = await knex2.schema.hasColumn(meta.tableName, "published_at");
|
|
6386
|
+
if (meta.attributes.publishedAt && !hasPublishedAtColumn) {
|
|
6387
|
+
await createPublishedAtColumn(knex2, meta.tableName);
|
|
6388
|
+
}
|
|
6389
|
+
}
|
|
6390
|
+
},
|
|
6391
|
+
async down() {
|
|
6392
|
+
throw new Error("not implemented");
|
|
6393
|
+
}
|
|
6394
|
+
};
|
|
6395
|
+
const dropIndex = async (knex2, tableName, columnName) => {
|
|
6396
|
+
try {
|
|
6397
|
+
await knex2.schema.alterTable(tableName, (table) => {
|
|
6398
|
+
table.dropUnique([columnName], `${tableName}_${columnName}_unique`);
|
|
6399
|
+
});
|
|
6400
|
+
} catch (error) {
|
|
6401
|
+
}
|
|
6402
|
+
};
|
|
6403
|
+
const dropSlugFieldsIndex = {
|
|
6404
|
+
name: "5.0.0-05-drop-slug-fields-index",
|
|
6405
|
+
async up(knex2, db) {
|
|
6406
|
+
for (const meta of db.metadata.values()) {
|
|
6407
|
+
const hasTable = await knex2.schema.hasTable(meta.tableName);
|
|
6408
|
+
if (!hasTable) {
|
|
6409
|
+
continue;
|
|
6410
|
+
}
|
|
6411
|
+
for (const attribute of Object.values(meta.attributes)) {
|
|
6412
|
+
if (attribute.type === "uid" && attribute.columnName) {
|
|
6413
|
+
await dropIndex(knex2, meta.tableName, attribute.columnName);
|
|
6414
|
+
}
|
|
6415
|
+
}
|
|
6416
|
+
}
|
|
6417
|
+
},
|
|
6418
|
+
async down() {
|
|
6419
|
+
throw new Error("not implemented");
|
|
6420
|
+
}
|
|
6421
|
+
};
|
|
6223
6422
|
const internalMigrations = [
|
|
6224
6423
|
renameIdentifiersLongerThanMaxLength,
|
|
6225
6424
|
createdDocumentId,
|
|
6226
|
-
createdLocale
|
|
6425
|
+
createdLocale,
|
|
6426
|
+
createdPublishedAt,
|
|
6427
|
+
dropSlugFieldsIndex
|
|
6227
6428
|
];
|
|
6228
6429
|
const createInternalMigrationProvider = (db) => {
|
|
6229
6430
|
const context = { db };
|
|
6230
6431
|
const migrations = [...internalMigrations];
|
|
6231
6432
|
const umzugProvider = new Umzug({
|
|
6232
6433
|
storage: createStorage({ db, tableName: "strapi_migrations_internal" }),
|
|
6233
|
-
logger:
|
|
6434
|
+
logger: {
|
|
6435
|
+
info(message) {
|
|
6436
|
+
db.logger.debug(transformLogMessage("info", message));
|
|
6437
|
+
},
|
|
6438
|
+
warn(message) {
|
|
6439
|
+
db.logger.warn(transformLogMessage("warn", message));
|
|
6440
|
+
},
|
|
6441
|
+
error(message) {
|
|
6442
|
+
db.logger.error(transformLogMessage("error", message));
|
|
6443
|
+
},
|
|
6444
|
+
debug(message) {
|
|
6445
|
+
db.logger.debug(transformLogMessage("debug", message));
|
|
6446
|
+
}
|
|
6447
|
+
},
|
|
6234
6448
|
context,
|
|
6235
6449
|
migrations: () => migrations.map((migration) => {
|
|
6236
6450
|
return {
|
|
@@ -6501,6 +6715,7 @@ class Database {
|
|
|
6501
6715
|
migrations;
|
|
6502
6716
|
lifecycles;
|
|
6503
6717
|
entityManager;
|
|
6718
|
+
logger;
|
|
6504
6719
|
constructor(config) {
|
|
6505
6720
|
this.config = {
|
|
6506
6721
|
...config,
|
|
@@ -6520,6 +6735,7 @@ class Database {
|
|
|
6520
6735
|
this.migrations = createMigrationsProvider(this);
|
|
6521
6736
|
this.lifecycles = createLifecyclesProvider(this);
|
|
6522
6737
|
this.entityManager = createEntityManager(this);
|
|
6738
|
+
this.logger = config.logger ?? console;
|
|
6523
6739
|
}
|
|
6524
6740
|
async init({ models }) {
|
|
6525
6741
|
this.metadata.loadModels(models);
|