@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/dist/index.js CHANGED
@@ -7,11 +7,11 @@ const _ = require("lodash/fp");
7
7
  const crypto = require("crypto");
8
8
  const crypto$1 = require("node:crypto");
9
9
  const dateFns = require("date-fns");
10
- const utils = require("@strapi/utils");
10
+ const node_async_hooks = require("node:async_hooks");
11
11
  const KnexBuilder = require("knex/lib/query/querybuilder");
12
12
  const KnexRaw = require("knex/lib/raw");
13
+ const utils = require("@strapi/utils");
13
14
  const stream = require("stream");
14
- const node_async_hooks = require("node:async_hooks");
15
15
  const _$1 = require("lodash");
16
16
  const umzug = require("umzug");
17
17
  const cuid2 = require("@paralleldrive/cuid2");
@@ -1119,7 +1119,7 @@ const createHelpers = (db) => {
1119
1119
  }
1120
1120
  }
1121
1121
  };
1122
- const dropIndex = (tableBuilder, index2) => {
1122
+ const dropIndex2 = (tableBuilder, index2) => {
1123
1123
  if (!db.config.settings?.forceMigration) {
1124
1124
  return;
1125
1125
  }
@@ -1196,13 +1196,13 @@ const createHelpers = (db) => {
1196
1196
  for (const removedIndex of table.indexes.removed) {
1197
1197
  if (!ignoreForeignKeyNames.includes(removedIndex.name)) {
1198
1198
  debug$2(`Dropping index ${removedIndex.name} on ${table.name}`);
1199
- dropIndex(tableBuilder, removedIndex);
1199
+ dropIndex2(tableBuilder, removedIndex);
1200
1200
  }
1201
1201
  }
1202
1202
  for (const updatedIndex of table.indexes.updated) {
1203
1203
  if (!ignoreForeignKeyNames.includes(updatedIndex.name)) {
1204
1204
  debug$2(`Dropping updated index ${updatedIndex.name} on ${table.name}`);
1205
- dropIndex(tableBuilder, updatedIndex.object);
1205
+ dropIndex2(tableBuilder, updatedIndex.object);
1206
1206
  }
1207
1207
  }
1208
1208
  for (const updatedColumn of table.columns.updated) {
@@ -1388,27 +1388,28 @@ const createSchemaDiff = (db) => {
1388
1388
  }
1389
1389
  };
1390
1390
  };
1391
- const diffTableColumns = (srcTable, destTable) => {
1391
+ const diffTableColumns = (diffCtx) => {
1392
+ const { databaseTable, userSchemaTable, previousTable } = diffCtx;
1392
1393
  const addedColumns = [];
1393
1394
  const updatedColumns = [];
1394
1395
  const unchangedColumns = [];
1395
1396
  const removedColumns = [];
1396
- for (const destColumn of destTable.columns) {
1397
- const srcColumn = helpers.findColumn(srcTable, destColumn.name);
1398
- if (srcColumn) {
1399
- const { status, diff } = diffColumns(srcColumn, destColumn);
1397
+ for (const userSchemaColumn of userSchemaTable.columns) {
1398
+ const databaseColumn = helpers.findColumn(databaseTable, userSchemaColumn.name);
1399
+ if (databaseColumn) {
1400
+ const { status, diff } = diffColumns(databaseColumn, userSchemaColumn);
1400
1401
  if (status === statuses.CHANGED) {
1401
1402
  updatedColumns.push(diff);
1402
1403
  } else {
1403
- unchangedColumns.push(srcColumn);
1404
+ unchangedColumns.push(databaseColumn);
1404
1405
  }
1405
1406
  } else {
1406
- addedColumns.push(destColumn);
1407
+ addedColumns.push(userSchemaColumn);
1407
1408
  }
1408
1409
  }
1409
- for (const srcColumn of srcTable.columns) {
1410
- if (!helpers.hasColumn(destTable, srcColumn.name)) {
1411
- removedColumns.push(srcColumn);
1410
+ for (const databaseColumn of databaseTable.columns) {
1411
+ if (!helpers.hasColumn(userSchemaTable, databaseColumn.name) && previousTable && helpers.hasColumn(previousTable, databaseColumn.name)) {
1412
+ removedColumns.push(databaseColumn);
1412
1413
  }
1413
1414
  }
1414
1415
  const hasChanged = [addedColumns, updatedColumns, removedColumns].some((arr) => arr.length > 0);
@@ -1422,27 +1423,28 @@ const createSchemaDiff = (db) => {
1422
1423
  }
1423
1424
  };
1424
1425
  };
1425
- const diffTableIndexes = (srcTable, destTable) => {
1426
+ const diffTableIndexes = (diffCtx) => {
1427
+ const { databaseTable, userSchemaTable, previousTable } = diffCtx;
1426
1428
  const addedIndexes = [];
1427
1429
  const updatedIndexes = [];
1428
1430
  const unchangedIndexes = [];
1429
1431
  const removedIndexes = [];
1430
- for (const destIndex of destTable.indexes) {
1431
- const srcIndex = helpers.findIndex(srcTable, destIndex.name);
1432
- if (srcIndex) {
1433
- const { status, diff } = diffIndexes(srcIndex, destIndex);
1432
+ for (const userSchemaIndex of userSchemaTable.indexes) {
1433
+ const databaseIndex = helpers.findIndex(databaseTable, userSchemaIndex.name);
1434
+ if (databaseIndex) {
1435
+ const { status, diff } = diffIndexes(databaseIndex, userSchemaIndex);
1434
1436
  if (status === statuses.CHANGED) {
1435
1437
  updatedIndexes.push(diff);
1436
1438
  } else {
1437
- unchangedIndexes.push(srcIndex);
1439
+ unchangedIndexes.push(databaseIndex);
1438
1440
  }
1439
1441
  } else {
1440
- addedIndexes.push(destIndex);
1442
+ addedIndexes.push(userSchemaIndex);
1441
1443
  }
1442
1444
  }
1443
- for (const srcIndex of srcTable.indexes) {
1444
- if (!helpers.hasIndex(destTable, srcIndex.name)) {
1445
- removedIndexes.push(srcIndex);
1445
+ for (const databaseIndex of databaseTable.indexes) {
1446
+ if (!helpers.hasIndex(userSchemaTable, databaseIndex.name) && previousTable && helpers.hasIndex(previousTable, databaseIndex.name)) {
1447
+ removedIndexes.push(databaseIndex);
1446
1448
  }
1447
1449
  }
1448
1450
  const hasChanged = [addedIndexes, updatedIndexes, removedIndexes].some((arr) => arr.length > 0);
@@ -1456,7 +1458,8 @@ const createSchemaDiff = (db) => {
1456
1458
  }
1457
1459
  };
1458
1460
  };
1459
- const diffTableForeignKeys = (srcTable, destTable) => {
1461
+ const diffTableForeignKeys = (diffCtx) => {
1462
+ const { databaseTable, userSchemaTable, previousTable } = diffCtx;
1460
1463
  const addedForeignKeys = [];
1461
1464
  const updatedForeignKeys = [];
1462
1465
  const unchangedForeignKeys = [];
@@ -1472,22 +1475,22 @@ const createSchemaDiff = (db) => {
1472
1475
  }
1473
1476
  };
1474
1477
  }
1475
- for (const destForeignKey of destTable.foreignKeys) {
1476
- const srcForeignKey = helpers.findForeignKey(srcTable, destForeignKey.name);
1477
- if (srcForeignKey) {
1478
- const { status, diff } = diffForeignKeys(srcForeignKey, destForeignKey);
1478
+ for (const userSchemaForeignKeys of userSchemaTable.foreignKeys) {
1479
+ const databaseForeignKeys = helpers.findForeignKey(databaseTable, userSchemaForeignKeys.name);
1480
+ if (databaseForeignKeys) {
1481
+ const { status, diff } = diffForeignKeys(databaseForeignKeys, userSchemaForeignKeys);
1479
1482
  if (status === statuses.CHANGED) {
1480
1483
  updatedForeignKeys.push(diff);
1481
1484
  } else {
1482
- unchangedForeignKeys.push(srcForeignKey);
1485
+ unchangedForeignKeys.push(databaseForeignKeys);
1483
1486
  }
1484
1487
  } else {
1485
- addedForeignKeys.push(destForeignKey);
1488
+ addedForeignKeys.push(userSchemaForeignKeys);
1486
1489
  }
1487
1490
  }
1488
- for (const srcForeignKey of srcTable.foreignKeys) {
1489
- if (!helpers.hasForeignKey(destTable, srcForeignKey.name)) {
1490
- removedForeignKeys.push(srcForeignKey);
1491
+ for (const databaseForeignKeys of databaseTable.foreignKeys) {
1492
+ if (!helpers.hasForeignKey(userSchemaTable, databaseForeignKeys.name) && previousTable && helpers.hasForeignKey(previousTable, databaseForeignKeys.name)) {
1493
+ removedForeignKeys.push(databaseForeignKeys);
1491
1494
  }
1492
1495
  }
1493
1496
  const hasChanged = [addedForeignKeys, updatedForeignKeys, removedForeignKeys].some(
@@ -1503,37 +1506,44 @@ const createSchemaDiff = (db) => {
1503
1506
  }
1504
1507
  };
1505
1508
  };
1506
- const diffTables = (srcTable, destTable) => {
1507
- const columnsDiff = diffTableColumns(srcTable, destTable);
1508
- const indexesDiff = diffTableIndexes(srcTable, destTable);
1509
- const foreignKeysDiff = diffTableForeignKeys(srcTable, destTable);
1509
+ const diffTables = (diffCtx) => {
1510
+ const { databaseTable } = diffCtx;
1511
+ const columnsDiff = diffTableColumns(diffCtx);
1512
+ const indexesDiff = diffTableIndexes(diffCtx);
1513
+ const foreignKeysDiff = diffTableForeignKeys(diffCtx);
1510
1514
  const hasChanged = [columnsDiff, indexesDiff, foreignKeysDiff].some(hasChangedStatus);
1511
1515
  return {
1512
1516
  status: hasChanged ? statuses.CHANGED : statuses.UNCHANGED,
1513
1517
  diff: {
1514
- name: srcTable.name,
1518
+ name: databaseTable.name,
1515
1519
  indexes: indexesDiff.diff,
1516
1520
  foreignKeys: foreignKeysDiff.diff,
1517
1521
  columns: columnsDiff.diff
1518
1522
  }
1519
1523
  };
1520
1524
  };
1521
- const diffSchemas = async (srcSchema, destSchema) => {
1525
+ const diffSchemas = async (schemaDiffCtx) => {
1526
+ const { previousSchema, databaseSchema, userSchema } = schemaDiffCtx;
1522
1527
  const addedTables = [];
1523
1528
  const updatedTables = [];
1524
1529
  const unchangedTables = [];
1525
1530
  const removedTables = [];
1526
- for (const destTable of destSchema.tables) {
1527
- const srcTable = helpers.findTable(srcSchema, destTable.name);
1528
- if (srcTable) {
1529
- const { status, diff } = diffTables(srcTable, destTable);
1531
+ for (const userSchemaTable of userSchema.tables) {
1532
+ const databaseTable = helpers.findTable(databaseSchema, userSchemaTable.name);
1533
+ const previousTable = previousSchema && helpers.findTable(previousSchema, userSchemaTable.name);
1534
+ if (databaseTable) {
1535
+ const { status, diff } = diffTables({
1536
+ previousTable,
1537
+ databaseTable,
1538
+ userSchemaTable
1539
+ });
1530
1540
  if (status === statuses.CHANGED) {
1531
1541
  updatedTables.push(diff);
1532
1542
  } else {
1533
- unchangedTables.push(srcTable);
1543
+ unchangedTables.push(databaseTable);
1534
1544
  }
1535
1545
  } else {
1536
- addedTables.push(destTable);
1546
+ addedTables.push(userSchemaTable);
1537
1547
  }
1538
1548
  }
1539
1549
  const parsePersistedTable = (persistedTable) => {
@@ -1542,23 +1552,34 @@ const createSchemaDiff = (db) => {
1542
1552
  }
1543
1553
  return persistedTable.name;
1544
1554
  };
1545
- const persistedTables = helpers.hasTable(srcSchema, "strapi_core_store_settings") ? await strapi.store.get({
1546
- type: "core",
1547
- key: "persisted_tables"
1548
- }) ?? [] : [];
1555
+ const persistedTables = helpers.hasTable(databaseSchema, "strapi_core_store_settings") ? (
1556
+ // TODO: replace with low level db query instead
1557
+ await strapi.store.get({
1558
+ type: "core",
1559
+ key: "persisted_tables"
1560
+ }) ?? []
1561
+ ) : [];
1549
1562
  const reservedTables = [...RESERVED_TABLE_NAMES, ...persistedTables.map(parsePersistedTable)];
1550
- for (const srcTable of srcSchema.tables) {
1551
- if (!helpers.hasTable(destSchema, srcTable.name) && !reservedTables.includes(srcTable.name)) {
1563
+ for (const databaseTable of databaseSchema.tables) {
1564
+ const isInUserSchema = helpers.hasTable(userSchema, databaseTable.name);
1565
+ const wasTracked = previousSchema && helpers.hasTable(previousSchema, databaseTable.name);
1566
+ const isReserved = reservedTables.includes(databaseTable.name);
1567
+ if (!isInUserSchema && !wasTracked) {
1568
+ continue;
1569
+ }
1570
+ if (!isInUserSchema && wasTracked && !isReserved) {
1552
1571
  const dependencies = persistedTables.filter((table) => {
1553
1572
  const dependsOn = table?.dependsOn;
1554
1573
  if (!___default.default.isArray(dependsOn)) {
1555
1574
  return;
1556
1575
  }
1557
- return dependsOn.some((table2) => table2.name === srcTable.name);
1576
+ return dependsOn.some((table2) => table2.name === databaseTable.name);
1558
1577
  }).map((dependsOnTable) => {
1559
- return srcSchema.tables.find((srcTable2) => srcTable2.name === dependsOnTable.name);
1578
+ return databaseSchema.tables.find(
1579
+ (databaseTable2) => databaseTable2.name === dependsOnTable.name
1580
+ );
1560
1581
  }).filter((table) => !___default.default.isNil(table));
1561
- removedTables.push(srcTable, ...dependencies);
1582
+ removedTables.push(databaseTable, ...dependencies);
1562
1583
  }
1563
1584
  }
1564
1585
  const hasChanged = [addedTables, updatedTables, removedTables].some((arr) => arr.length > 0);
@@ -2204,8 +2225,13 @@ const createSchemaProvider = (db) => {
2204
2225
  },
2205
2226
  async syncSchema() {
2206
2227
  debug$1("Synchronizing database schema");
2207
- const DBSchema = await db.dialect.schemaInspector.getSchema();
2208
- const { status, diff } = await this.schemaDiff.diff(DBSchema, this.schema);
2228
+ const databaseSchema = await db.dialect.schemaInspector.getSchema();
2229
+ const storedSchema = await this.schemaStorage.read();
2230
+ const { status, diff } = await this.schemaDiff.diff({
2231
+ previousSchema: storedSchema?.schema,
2232
+ databaseSchema,
2233
+ userSchema: this.schema
2234
+ });
2209
2235
  if (status === "CHANGED") {
2210
2236
  await this.builder.updateSchema(diff);
2211
2237
  }
@@ -2927,6 +2953,68 @@ const createField = (attribute) => {
2927
2953
  }
2928
2954
  throw new Error(`Undefined field for type ${type}`);
2929
2955
  };
2956
+ const storage = new node_async_hooks.AsyncLocalStorage();
2957
+ const transactionCtx = {
2958
+ async run(trx, cb) {
2959
+ const store = storage.getStore();
2960
+ return storage.run(
2961
+ {
2962
+ trx,
2963
+ // Fill with existing callbacks if nesting transactions
2964
+ commitCallbacks: store?.commitCallbacks || [],
2965
+ rollbackCallbacks: store?.rollbackCallbacks || []
2966
+ },
2967
+ cb
2968
+ );
2969
+ },
2970
+ get() {
2971
+ const store = storage.getStore();
2972
+ return store?.trx;
2973
+ },
2974
+ async commit(trx) {
2975
+ const store = storage.getStore();
2976
+ if (store?.trx) {
2977
+ store.trx = null;
2978
+ }
2979
+ await trx.commit();
2980
+ if (!store?.commitCallbacks.length) {
2981
+ return;
2982
+ }
2983
+ store.commitCallbacks.forEach((cb) => cb());
2984
+ store.commitCallbacks = [];
2985
+ },
2986
+ async rollback(trx) {
2987
+ const store = storage.getStore();
2988
+ if (store?.trx) {
2989
+ store.trx = null;
2990
+ }
2991
+ await trx.rollback();
2992
+ if (!store?.rollbackCallbacks.length) {
2993
+ return;
2994
+ }
2995
+ store.rollbackCallbacks.forEach((cb) => cb());
2996
+ store.rollbackCallbacks = [];
2997
+ },
2998
+ onCommit(cb) {
2999
+ const store = storage.getStore();
3000
+ if (store?.commitCallbacks) {
3001
+ store.commitCallbacks.push(cb);
3002
+ }
3003
+ },
3004
+ onRollback(cb) {
3005
+ const store = storage.getStore();
3006
+ if (store?.rollbackCallbacks) {
3007
+ store.rollbackCallbacks.push(cb);
3008
+ }
3009
+ }
3010
+ };
3011
+ function isKnexQuery(value) {
3012
+ return value instanceof KnexBuilder__default.default || value instanceof KnexRaw__default.default;
3013
+ }
3014
+ const addSchema = (db, tableName) => {
3015
+ const schemaName = db.getSchemaName();
3016
+ return schemaName ? `${schemaName}.${tableName}` : tableName;
3017
+ };
2930
3018
  const fromSingleRow = (meta, row) => {
2931
3019
  const { attributes } = meta;
2932
3020
  if (___default.default.isNil(row)) {
@@ -3049,7 +3137,7 @@ const escapeQuery = (query, charsToEscape, escapeChar = "\\") => {
3049
3137
  ""
3050
3138
  );
3051
3139
  };
3052
- const createPivotJoin = (ctx, { alias, refAlias, joinTable, targetMeta }) => {
3140
+ const createPivotJoin = (ctx, { alias: alias2, refAlias, joinTable, targetMeta }) => {
3053
3141
  const { qb } = ctx;
3054
3142
  const joinAlias = qb.getAlias();
3055
3143
  qb.join({
@@ -3057,7 +3145,7 @@ const createPivotJoin = (ctx, { alias, refAlias, joinTable, targetMeta }) => {
3057
3145
  referencedTable: joinTable.name,
3058
3146
  referencedColumn: joinTable.joinColumn.name,
3059
3147
  rootColumn: joinTable.joinColumn.referencedColumn,
3060
- rootTable: alias,
3148
+ rootTable: alias2,
3061
3149
  on: joinTable.on
3062
3150
  });
3063
3151
  const subAlias = refAlias || qb.getAlias();
@@ -3070,7 +3158,7 @@ const createPivotJoin = (ctx, { alias, refAlias, joinTable, targetMeta }) => {
3070
3158
  });
3071
3159
  return subAlias;
3072
3160
  };
3073
- const createJoin = (ctx, { alias, refAlias, attributeName, attribute }) => {
3161
+ const createJoin = (ctx, { alias: alias2, refAlias, attributeName, attribute }) => {
3074
3162
  const { db, qb, uid } = ctx;
3075
3163
  if (attribute.type !== "relation") {
3076
3164
  throw new Error(`Cannot join on non relational field ${attributeName}`);
@@ -3086,7 +3174,7 @@ const createJoin = (ctx, { alias, refAlias, attributeName, attribute }) => {
3086
3174
  referencedTable: targetMeta.tableName,
3087
3175
  referencedColumn: morphColumn.idColumn.name,
3088
3176
  rootColumn: morphColumn.idColumn.referencedColumn,
3089
- rootTable: alias,
3177
+ rootTable: alias2,
3090
3178
  on: {
3091
3179
  [morphColumn.typeColumn.name]: uid,
3092
3180
  ...morphColumn.on
@@ -3101,7 +3189,7 @@ const createJoin = (ctx, { alias, refAlias, attributeName, attribute }) => {
3101
3189
  referencedTable: joinTable2.name,
3102
3190
  referencedColumn: joinTable2.morphColumn.idColumn.name,
3103
3191
  rootColumn: joinTable2.morphColumn.idColumn.referencedColumn,
3104
- rootTable: alias,
3192
+ rootTable: alias2,
3105
3193
  on: {
3106
3194
  [joinTable2.morphColumn.typeColumn.name]: uid,
3107
3195
  field: attributeName
@@ -3117,7 +3205,7 @@ const createJoin = (ctx, { alias, refAlias, attributeName, attribute }) => {
3117
3205
  });
3118
3206
  return subAlias;
3119
3207
  }
3120
- return alias;
3208
+ return alias2;
3121
3209
  }
3122
3210
  const { joinColumn } = attribute;
3123
3211
  if (joinColumn) {
@@ -3127,20 +3215,20 @@ const createJoin = (ctx, { alias, refAlias, attributeName, attribute }) => {
3127
3215
  referencedTable: targetMeta.tableName,
3128
3216
  referencedColumn: joinColumn.referencedColumn,
3129
3217
  rootColumn: joinColumn.name,
3130
- rootTable: alias
3218
+ rootTable: alias2
3131
3219
  });
3132
3220
  return subAlias;
3133
3221
  }
3134
3222
  const { joinTable } = attribute;
3135
3223
  if (joinTable) {
3136
- return createPivotJoin(ctx, { alias, refAlias, joinTable, targetMeta });
3224
+ return createPivotJoin(ctx, { alias: alias2, refAlias, joinTable, targetMeta });
3137
3225
  }
3138
- return alias;
3226
+ return alias2;
3139
3227
  };
3140
3228
  const applyJoin = (qb, join) => {
3141
3229
  const {
3142
3230
  method = "leftJoin",
3143
- alias,
3231
+ alias: alias2,
3144
3232
  referencedTable,
3145
3233
  referencedColumn,
3146
3234
  rootColumn,
@@ -3150,26 +3238,28 @@ const applyJoin = (qb, join) => {
3150
3238
  on,
3151
3239
  orderBy
3152
3240
  } = join;
3153
- qb[method](`${referencedTable} as ${alias}`, (inner) => {
3154
- inner.on(`${rootTable}.${rootColumn}`, `${alias}.${referencedColumn}`);
3241
+ qb[method](`${referencedTable} as ${alias2}`, (inner) => {
3242
+ inner.on(`${rootTable}.${rootColumn}`, `${alias2}.${referencedColumn}`);
3155
3243
  if (on) {
3156
3244
  for (const key of Object.keys(on)) {
3157
- inner.onVal(`${alias}.${key}`, on[key]);
3245
+ inner.onVal(`${alias2}.${key}`, on[key]);
3158
3246
  }
3159
3247
  }
3160
3248
  });
3161
3249
  if (orderBy) {
3162
3250
  Object.keys(orderBy).forEach((column) => {
3163
3251
  const direction = orderBy[column];
3164
- qb.orderBy(`${alias}.${column}`, direction);
3252
+ qb.orderBy(`${alias2}.${column}`, direction);
3165
3253
  });
3166
3254
  }
3167
3255
  };
3168
3256
  const applyJoins = (qb, joins) => {
3169
3257
  return joins.forEach((join) => applyJoin(qb, join));
3170
3258
  };
3259
+ const COL_STRAPI_ROW_NUMBER = "__strapi_row_number";
3260
+ const COL_STRAPI_ORDER_BY_PREFIX = "__strapi_order_by";
3171
3261
  const processOrderBy = (orderBy, ctx) => {
3172
- const { db, uid, qb, alias } = ctx;
3262
+ const { db, uid, qb, alias: alias2 } = ctx;
3173
3263
  const meta = db.metadata.get(uid);
3174
3264
  const { attributes } = meta;
3175
3265
  if (typeof orderBy === "string") {
@@ -3178,7 +3268,7 @@ const processOrderBy = (orderBy, ctx) => {
3178
3268
  throw new Error(`Attribute ${orderBy} not found on model ${uid}`);
3179
3269
  }
3180
3270
  const columnName = toColumnName(meta, orderBy);
3181
- return [{ column: qb.aliasColumn(columnName, alias) }];
3271
+ return [{ column: qb.aliasColumn(columnName, alias2) }];
3182
3272
  }
3183
3273
  if (Array.isArray(orderBy)) {
3184
3274
  return orderBy.flatMap((value) => processOrderBy(value, ctx));
@@ -3192,11 +3282,11 @@ const processOrderBy = (orderBy, ctx) => {
3192
3282
  }
3193
3283
  if (isScalar(attribute.type)) {
3194
3284
  const columnName = toColumnName(meta, key);
3195
- return { column: qb.aliasColumn(columnName, alias), order: direction };
3285
+ return { column: qb.aliasColumn(columnName, alias2), order: direction };
3196
3286
  }
3197
3287
  if (attribute.type === "relation" && "target" in attribute) {
3198
3288
  const subAlias = createJoin(ctx, {
3199
- alias: alias || qb.alias,
3289
+ alias: alias2 || qb.alias,
3200
3290
  attributeName: key,
3201
3291
  attribute
3202
3292
  });
@@ -3212,6 +3302,75 @@ const processOrderBy = (orderBy, ctx) => {
3212
3302
  }
3213
3303
  throw new Error("Invalid orderBy syntax");
3214
3304
  };
3305
+ const getStrapiOrderColumnAlias = (column) => {
3306
+ const trimmedColumnName = column.replaceAll(".", "_");
3307
+ return `${COL_STRAPI_ORDER_BY_PREFIX}__${trimmedColumnName}`;
3308
+ };
3309
+ const wrapWithDeepSort = (originalQuery, ctx) => {
3310
+ const { db, qb, uid } = ctx;
3311
+ const { tableName } = db.metadata.get(uid);
3312
+ const orderBy = ___default.default.cloneDeep(qb.state.orderBy);
3313
+ const resultQueryAlias = qb.getAlias();
3314
+ const aliasedTableName = qb.mustUseAlias() ? alias(resultQueryAlias, tableName) : tableName;
3315
+ const resultQuery = db.getConnection(aliasedTableName);
3316
+ const baseQuery = originalQuery.clone();
3317
+ const baseQueryAlias = qb.getAlias();
3318
+ baseQuery.clear("select").clear("order").clear("limit").clear("offset");
3319
+ baseQuery.select(
3320
+ // Always select the row id for future manipulation
3321
+ prefix(qb.alias, "id"),
3322
+ ...orderBy.map(
3323
+ (orderByClause) => alias(getStrapiOrderColumnAlias(orderByClause.column), orderByClause.column)
3324
+ )
3325
+ );
3326
+ const partitionedQueryAlias = qb.getAlias();
3327
+ const selectRowsAsNumberedPartitions = (partitionedQuery) => {
3328
+ const prefixedOrderBy = orderBy.map((orderByClause) => ({
3329
+ column: prefix(baseQueryAlias, getStrapiOrderColumnAlias(orderByClause.column)),
3330
+ order: orderByClause.order
3331
+ }));
3332
+ const orderByColumns = prefixedOrderBy.map(___default.default.prop("column"));
3333
+ partitionedQuery.select(
3334
+ // Always select baseQuery.id
3335
+ prefix(baseQueryAlias, "id"),
3336
+ ...orderByColumns
3337
+ ).rowNumber(COL_STRAPI_ROW_NUMBER, (subQuery) => {
3338
+ for (const orderByClause of prefixedOrderBy) {
3339
+ subQuery.orderBy(orderByClause.column, orderByClause.order, "last");
3340
+ }
3341
+ subQuery.partitionBy(`${baseQueryAlias}.id`);
3342
+ }).from(baseQuery.as(baseQueryAlias)).as(partitionedQueryAlias);
3343
+ };
3344
+ const originalSelect = ___default.default.difference(
3345
+ qb.state.select,
3346
+ // Remove order by columns from the initial select
3347
+ qb.state.orderBy.map(___default.default.prop("column"))
3348
+ ).map(prefix(resultQueryAlias));
3349
+ resultQuery.select(originalSelect).innerJoin(selectRowsAsNumberedPartitions, function() {
3350
+ this.on(`${partitionedQueryAlias}.id`, `${resultQueryAlias}.id`).andOnVal(`${partitionedQueryAlias}.${COL_STRAPI_ROW_NUMBER}`, "=", 1);
3351
+ });
3352
+ if (qb.state.limit) {
3353
+ resultQuery.limit(qb.state.limit);
3354
+ }
3355
+ if (qb.state.offset) {
3356
+ resultQuery.offset(qb.state.offset);
3357
+ }
3358
+ if (qb.state.first) {
3359
+ resultQuery.first();
3360
+ }
3361
+ resultQuery.orderBy([
3362
+ // Transform "order by" clause to their T alias and prefix them with T alias
3363
+ ...orderBy.map((orderByClause) => ({
3364
+ column: prefix(partitionedQueryAlias, getStrapiOrderColumnAlias(orderByClause.column)),
3365
+ order: orderByClause.order
3366
+ })),
3367
+ // Add T.id to the order by clause to get consistent results in case several rows have the exact same order
3368
+ { column: `${partitionedQueryAlias}.id`, order: "asc" }
3369
+ ]);
3370
+ return resultQuery;
3371
+ };
3372
+ const alias = ___default.default.curry((alias2, value) => `${value} as ${alias2}`);
3373
+ const prefix = ___default.default.curry((prefix2, value) => `${prefix2}.${value}`);
3215
3374
  const joinColPrefix = "__strapi";
3216
3375
  const XtoOne = async (input, ctx) => {
3217
3376
  const { attribute, attributeName, results, populateValue, targetMeta, isCount } = input;
@@ -3239,8 +3398,8 @@ const XtoOne = async (input, ctx) => {
3239
3398
  const { joinTable } = attribute;
3240
3399
  const qb2 = db.entityManager.createQueryBuilder(targetMeta.uid);
3241
3400
  const { name: joinColumnName, referencedColumn: referencedColumnName } = joinTable.joinColumn;
3242
- const alias = qb2.getAlias();
3243
- const joinColAlias = `${alias}.${joinColumnName}`;
3401
+ const alias2 = qb2.getAlias();
3402
+ const joinColAlias = `${alias2}.${joinColumnName}`;
3244
3403
  const joinColRenameAs = `${joinColPrefix}${joinColumnName}`;
3245
3404
  const joinColSelect = `${joinColAlias} as ${joinColRenameAs}`;
3246
3405
  const referencedValues = ___default.default.uniq(
@@ -3254,7 +3413,7 @@ const XtoOne = async (input, ctx) => {
3254
3413
  return;
3255
3414
  }
3256
3415
  const rows2 = await qb2.init(populateValue).join({
3257
- alias,
3416
+ alias: alias2,
3258
3417
  referencedTable: joinTable.name,
3259
3418
  referencedColumn: joinTable.inverseJoinColumn.name,
3260
3419
  rootColumn: joinTable.inverseJoinColumn.referencedColumn,
@@ -3280,7 +3439,7 @@ const XtoOne = async (input, ctx) => {
3280
3439
  return;
3281
3440
  }
3282
3441
  const rows = await qb2.init(populateValue).join({
3283
- alias,
3442
+ alias: alias2,
3284
3443
  referencedTable: joinTable.name,
3285
3444
  referencedColumn: joinTable.inverseJoinColumn.name,
3286
3445
  rootColumn: joinTable.inverseJoinColumn.referencedColumn,
@@ -3320,8 +3479,8 @@ const oneToMany = async (input, ctx) => {
3320
3479
  const { joinTable } = attribute;
3321
3480
  const qb2 = db.entityManager.createQueryBuilder(targetMeta.uid);
3322
3481
  const { name: joinColumnName, referencedColumn: referencedColumnName } = joinTable.joinColumn;
3323
- const alias = qb2.getAlias();
3324
- const joinColAlias = `${alias}.${joinColumnName}`;
3482
+ const alias2 = qb2.getAlias();
3483
+ const joinColAlias = `${alias2}.${joinColumnName}`;
3325
3484
  const joinColRenameAs = `${joinColPrefix}${joinColumnName}`;
3326
3485
  const joinColSelect = `${joinColAlias} as ${joinColRenameAs}`;
3327
3486
  const referencedValues = ___default.default.uniq(
@@ -3335,7 +3494,7 @@ const oneToMany = async (input, ctx) => {
3335
3494
  return;
3336
3495
  }
3337
3496
  const rows2 = await qb2.init(populateValue).join({
3338
- alias,
3497
+ alias: alias2,
3339
3498
  referencedTable: joinTable.name,
3340
3499
  referencedColumn: joinTable.inverseJoinColumn.name,
3341
3500
  rootColumn: joinTable.inverseJoinColumn.referencedColumn,
@@ -3361,7 +3520,7 @@ const oneToMany = async (input, ctx) => {
3361
3520
  return;
3362
3521
  }
3363
3522
  const rows = await qb2.init(populateValue).join({
3364
- alias,
3523
+ alias: alias2,
3365
3524
  referencedTable: joinTable.name,
3366
3525
  referencedColumn: joinTable.inverseJoinColumn.name,
3367
3526
  rootColumn: joinTable.inverseJoinColumn.referencedColumn,
@@ -3382,8 +3541,8 @@ const manyToMany = async (input, ctx) => {
3382
3541
  const { joinTable } = attribute;
3383
3542
  const populateQb = db.entityManager.createQueryBuilder(targetMeta.uid);
3384
3543
  const { name: joinColumnName, referencedColumn: referencedColumnName } = joinTable.joinColumn;
3385
- const alias = populateQb.getAlias();
3386
- const joinColAlias = `${alias}.${joinColumnName}`;
3544
+ const alias2 = populateQb.getAlias();
3545
+ const joinColAlias = `${alias2}.${joinColumnName}`;
3387
3546
  const joinColRenameAs = `${joinColPrefix}${joinColumnName}`;
3388
3547
  const joinColSelect = `${joinColAlias} as ${joinColRenameAs}`;
3389
3548
  const referencedValues = ___default.default.uniq(
@@ -3397,7 +3556,7 @@ const manyToMany = async (input, ctx) => {
3397
3556
  return;
3398
3557
  }
3399
3558
  const rows2 = await populateQb.init(populateValue).join({
3400
- alias,
3559
+ alias: alias2,
3401
3560
  referencedTable: joinTable.name,
3402
3561
  referencedColumn: joinTable.inverseJoinColumn.name,
3403
3562
  rootColumn: joinTable.inverseJoinColumn.referencedColumn,
@@ -3423,7 +3582,7 @@ const manyToMany = async (input, ctx) => {
3423
3582
  return;
3424
3583
  }
3425
3584
  const rows = await populateQb.init(populateValue).join({
3426
- alias,
3585
+ alias: alias2,
3427
3586
  referencedTable: joinTable.name,
3428
3587
  referencedColumn: joinTable.inverseJoinColumn.name,
3429
3588
  rootColumn: joinTable.inverseJoinColumn.referencedColumn,
@@ -3474,9 +3633,9 @@ const morphX = async (input, ctx) => {
3474
3633
  return;
3475
3634
  }
3476
3635
  const qb = db.entityManager.createQueryBuilder(target);
3477
- const alias = qb.getAlias();
3636
+ const alias2 = qb.getAlias();
3478
3637
  const rows = await qb.init(populateValue).join({
3479
- alias,
3638
+ alias: alias2,
3480
3639
  referencedTable: joinTable.name,
3481
3640
  referencedColumn: joinColumn.name,
3482
3641
  rootColumn: joinColumn.referencedColumn,
@@ -3486,9 +3645,9 @@ const morphX = async (input, ctx) => {
3486
3645
  field: attributeName
3487
3646
  },
3488
3647
  orderBy: ___default.default.mapValues((v) => populateValue.ordering || v, joinTable.orderBy)
3489
- }).addSelect([`${alias}.${idColumn.name}`, `${alias}.${typeColumn.name}`]).where({
3490
- [`${alias}.${idColumn.name}`]: referencedValues,
3491
- [`${alias}.${typeColumn.name}`]: uid
3648
+ }).addSelect([`${alias2}.${idColumn.name}`, `${alias2}.${typeColumn.name}`]).where({
3649
+ [`${alias2}.${idColumn.name}`]: referencedValues,
3650
+ [`${alias2}.${typeColumn.name}`]: uid
3492
3651
  }).execute({ mapResults: false });
3493
3652
  const map = ___default.default.groupBy(idColumn.name)(rows);
3494
3653
  results.forEach((result) => {
@@ -3737,13 +3896,6 @@ const processPopulate = (populate, ctx) => {
3737
3896
  }
3738
3897
  return finalPopulate;
3739
3898
  };
3740
- function isKnexQuery(value) {
3741
- return value instanceof KnexBuilder__default.default || value instanceof KnexRaw__default.default;
3742
- }
3743
- const addSchema = (db, tableName) => {
3744
- const schemaName = db.getSchemaName();
3745
- return schemaName ? `${schemaName}.${tableName}` : tableName;
3746
- };
3747
3899
  const isRecord$1 = (value) => _.isPlainObject(value);
3748
3900
  const castValue = (value, attribute) => {
3749
3901
  if (!attribute) {
@@ -3785,8 +3937,8 @@ const processNested = (where, ctx) => {
3785
3937
  return processWhere(where, ctx);
3786
3938
  };
3787
3939
  const processRelationWhere = (where, ctx) => {
3788
- const { qb, alias } = ctx;
3789
- const idAlias = qb.aliasColumn("id", alias);
3940
+ const { qb, alias: alias2 } = ctx;
3941
+ const idAlias = qb.aliasColumn("id", alias2);
3790
3942
  if (!isRecord$1(where)) {
3791
3943
  return { [idAlias]: where };
3792
3944
  }
@@ -3816,7 +3968,7 @@ function processWhere(where, ctx) {
3816
3968
  if (_.isArray(where)) {
3817
3969
  return where.map((sub) => processWhere(sub, ctx));
3818
3970
  }
3819
- const { db, uid, qb, alias } = ctx;
3971
+ const { db, uid, qb, alias: alias2 } = ctx;
3820
3972
  const meta = db.metadata.get(uid);
3821
3973
  const filters = {};
3822
3974
  for (const key of Object.keys(where)) {
@@ -3839,12 +3991,12 @@ function processWhere(where, ctx) {
3839
3991
  }
3840
3992
  const attribute = meta.attributes[key];
3841
3993
  if (!attribute) {
3842
- filters[qb.aliasColumn(key, alias)] = processAttributeWhere(null, value);
3994
+ filters[qb.aliasColumn(key, alias2)] = processAttributeWhere(null, value);
3843
3995
  continue;
3844
3996
  }
3845
3997
  if (isRelation(attribute.type) && "target" in attribute) {
3846
3998
  const subAlias = createJoin(ctx, {
3847
- alias: alias || qb.alias,
3999
+ alias: alias2 || qb.alias,
3848
4000
  attributeName: key,
3849
4001
  attribute
3850
4002
  });
@@ -3859,7 +4011,7 @@ function processWhere(where, ctx) {
3859
4011
  }
3860
4012
  if (isScalar(attribute.type)) {
3861
4013
  const columnName = toColumnName(meta, key);
3862
- const aliasedColumnName = qb.aliasColumn(columnName, alias);
4014
+ const aliasedColumnName = qb.aliasColumn(columnName, alias2);
3863
4015
  filters[aliasedColumnName] = processAttributeWhere(attribute, value);
3864
4016
  continue;
3865
4017
  }
@@ -4087,7 +4239,7 @@ class ReadableStrapiQuery extends stream.Readable {
4087
4239
  * Custom ._read() implementation
4088
4240
  *
4089
4241
  * NOTE: Here "size" means the number of entities to be read from the database.
4090
- * Not the actual byte size, as it would means that we need to return partial entities.
4242
+ * Not the actual byte size, as it would mean that we need to return partial entities.
4091
4243
  *
4092
4244
  */
4093
4245
  async _read(size) {
@@ -4150,61 +4302,6 @@ class ReadableStrapiQuery extends stream.Readable {
4150
4302
  }
4151
4303
  }
4152
4304
  }
4153
- const storage = new node_async_hooks.AsyncLocalStorage();
4154
- const transactionCtx = {
4155
- async run(trx, cb) {
4156
- const store = storage.getStore();
4157
- return storage.run(
4158
- {
4159
- trx,
4160
- // Fill with existing callbacks if nesting transactions
4161
- commitCallbacks: store?.commitCallbacks || [],
4162
- rollbackCallbacks: store?.rollbackCallbacks || []
4163
- },
4164
- cb
4165
- );
4166
- },
4167
- get() {
4168
- const store = storage.getStore();
4169
- return store?.trx;
4170
- },
4171
- async commit(trx) {
4172
- const store = storage.getStore();
4173
- if (store?.trx) {
4174
- store.trx = null;
4175
- }
4176
- await trx.commit();
4177
- if (!store?.commitCallbacks.length) {
4178
- return;
4179
- }
4180
- store.commitCallbacks.forEach((cb) => cb());
4181
- store.commitCallbacks = [];
4182
- },
4183
- async rollback(trx) {
4184
- const store = storage.getStore();
4185
- if (store?.trx) {
4186
- store.trx = null;
4187
- }
4188
- await trx.rollback();
4189
- if (!store?.rollbackCallbacks.length) {
4190
- return;
4191
- }
4192
- store.rollbackCallbacks.forEach((cb) => cb());
4193
- store.rollbackCallbacks = [];
4194
- },
4195
- onCommit(cb) {
4196
- const store = storage.getStore();
4197
- if (store?.commitCallbacks) {
4198
- store.commitCallbacks.push(cb);
4199
- }
4200
- },
4201
- onRollback(cb) {
4202
- const store = storage.getStore();
4203
- if (store?.rollbackCallbacks) {
4204
- store.rollbackCallbacks.push(cb);
4205
- }
4206
- }
4207
- };
4208
4305
  const createQueryBuilder = (uid, db, initialState = {}) => {
4209
4306
  const meta = db.metadata.get(uid);
4210
4307
  const { tableName } = meta;
@@ -4237,9 +4334,9 @@ const createQueryBuilder = (uid, db, initialState = {}) => {
4237
4334
  initialState
4238
4335
  );
4239
4336
  const getAlias = () => {
4240
- const alias = `t${state.aliasCounter}`;
4337
+ const alias2 = `t${state.aliasCounter}`;
4241
4338
  state.aliasCounter += 1;
4242
- return alias;
4339
+ return alias2;
4243
4340
  };
4244
4341
  return {
4245
4342
  alias: getAlias(),
@@ -4406,15 +4503,15 @@ const createQueryBuilder = (uid, db, initialState = {}) => {
4406
4503
  mustUseAlias() {
4407
4504
  return ["select", "count"].includes(state.type);
4408
4505
  },
4409
- aliasColumn(key, alias) {
4506
+ aliasColumn(key, alias2) {
4410
4507
  if (typeof key !== "string") {
4411
4508
  return key;
4412
4509
  }
4413
4510
  if (key.indexOf(".") >= 0) {
4414
4511
  return key;
4415
4512
  }
4416
- if (!___default.default.isNil(alias)) {
4417
- return `${alias}.${key}`;
4513
+ if (!___default.default.isNil(alias2)) {
4514
+ return `${alias2}.${key}`;
4418
4515
  }
4419
4516
  return this.mustUseAlias() ? `${this.alias}.${key}` : key;
4420
4517
  },
@@ -4449,6 +4546,20 @@ const createQueryBuilder = (uid, db, initialState = {}) => {
4449
4546
  shouldUseDistinct() {
4450
4547
  return state.joins.length > 0 && ___default.default.isEmpty(state.groupBy);
4451
4548
  },
4549
+ shouldUseDeepSort() {
4550
+ return state.orderBy.filter(({ column }) => column.indexOf(".") >= 0).filter(({ column }) => {
4551
+ const col = column.split(".");
4552
+ for (let i = 0; i < col.length - 1; i += 1) {
4553
+ const el = col[i];
4554
+ const isRelationAttribute = meta.attributes[el]?.type === "relation";
4555
+ const isAliasedRelation = Object.values(state.joins).map((join) => join.alias).includes(el);
4556
+ if (isRelationAttribute || isAliasedRelation) {
4557
+ return true;
4558
+ }
4559
+ }
4560
+ return false;
4561
+ }).length > 0;
4562
+ },
4452
4563
  processSelect() {
4453
4564
  state.select = state.select.map((field) => {
4454
4565
  if (isKnexQuery(field)) {
@@ -4566,6 +4677,9 @@ const createQueryBuilder = (uid, db, initialState = {}) => {
4566
4677
  if (state.joins.length > 0) {
4567
4678
  applyJoins(qb, state.joins);
4568
4679
  }
4680
+ if (this.shouldUseDeepSort()) {
4681
+ return wrapWithDeepSort(qb, { qb: this, db, uid });
4682
+ }
4569
4683
  return qb;
4570
4684
  },
4571
4685
  async execute({ mapResults = true } = {}) {
@@ -4767,7 +4881,7 @@ const deleteRelatedMorphOneRelationsAfterMorphToManyUpdate = async (rows, {
4767
4881
  await createQueryBuilder(joinTable.name, db).delete().where({ $or: orWhere }).transacting(trx).execute();
4768
4882
  }
4769
4883
  };
4770
- const getDocumentSiblingIdsQuery = (con, tableName, id) => {
4884
+ const getDocumentSiblingIdsQuery = (tableName, id) => {
4771
4885
  const models = Array.from(strapi.db.metadata.values());
4772
4886
  const isContentType = models.find((model) => {
4773
4887
  return model.tableName === tableName && model.attributes.documentId;
@@ -4775,10 +4889,11 @@ const getDocumentSiblingIdsQuery = (con, tableName, id) => {
4775
4889
  if (!isContentType) {
4776
4890
  return [id];
4777
4891
  }
4778
- return con.from(tableName).select("id").where(
4779
- "document_id",
4780
- con.from(tableName).select("document_id").where("id", id)
4781
- );
4892
+ return function(query) {
4893
+ query.select("id").from(tableName).whereIn("document_id", (documentIDSubQuery) => {
4894
+ documentIDSubQuery.from(tableName).select("document_id").where("id", id);
4895
+ });
4896
+ };
4782
4897
  };
4783
4898
  const deletePreviousOneToAnyRelations = async ({
4784
4899
  id,
@@ -4795,7 +4910,7 @@ const deletePreviousOneToAnyRelations = async ({
4795
4910
  const { joinTable } = attribute;
4796
4911
  const { joinColumn, inverseJoinColumn } = joinTable;
4797
4912
  const con = db.getConnection();
4798
- await con.delete().from(joinTable.name).whereNotIn(joinColumn.name, getDocumentSiblingIdsQuery(con, joinColumn.referencedTable, id)).whereIn(inverseJoinColumn.name, relIdsToadd).where(joinTable.on || {}).transacting(trx);
4913
+ await con.delete().from(joinTable.name).whereNotIn(joinColumn.name, getDocumentSiblingIdsQuery(joinColumn.referencedTable, id)).whereIn(inverseJoinColumn.name, relIdsToadd).where(joinTable.on || {}).transacting(trx);
4799
4914
  await cleanOrderColumns({ attribute, db, inverseRelIds: relIdsToadd, transaction: trx });
4800
4915
  };
4801
4916
  const deletePreviousAnyToOneRelations = async ({
@@ -4814,7 +4929,7 @@ const deletePreviousAnyToOneRelations = async ({
4814
4929
  if (isManyToAny(attribute)) {
4815
4930
  const relsToDelete = await con.select(inverseJoinColumn.name).from(joinTable.name).where(joinColumn.name, id).whereNotIn(
4816
4931
  inverseJoinColumn.name,
4817
- getDocumentSiblingIdsQuery(con, inverseJoinColumn.referencedTable, relIdToadd)
4932
+ getDocumentSiblingIdsQuery(inverseJoinColumn.referencedTable, relIdToadd)
4818
4933
  ).where(joinTable.on || {}).transacting(trx);
4819
4934
  const relIdsToDelete = _.map(inverseJoinColumn.name, relsToDelete);
4820
4935
  await createQueryBuilder(joinTable.name, db).delete().where({
@@ -4825,7 +4940,7 @@ const deletePreviousAnyToOneRelations = async ({
4825
4940
  } else {
4826
4941
  await con.delete().from(joinTable.name).where(joinColumn.name, id).whereNotIn(
4827
4942
  inverseJoinColumn.name,
4828
- getDocumentSiblingIdsQuery(con, inverseJoinColumn.referencedTable, relIdToadd)
4943
+ getDocumentSiblingIdsQuery(inverseJoinColumn.referencedTable, relIdToadd)
4829
4944
  ).where(joinTable.on || {}).transacting(trx);
4830
4945
  }
4831
4946
  };
@@ -5909,6 +6024,21 @@ const createStorage = (opts) => {
5909
6024
  const wrapTransaction = (db) => (fn) => () => {
5910
6025
  return db.transaction(({ trx }) => Promise.resolve(fn(trx, db)));
5911
6026
  };
6027
+ const transformLogMessage = (level, message) => {
6028
+ if (typeof message === "string") {
6029
+ return { level, message };
6030
+ }
6031
+ if (typeof message === "object" && message !== null) {
6032
+ if ("event" in message && "name" in message) {
6033
+ return {
6034
+ level,
6035
+ message: `[internal migration]: ${message.event} ${message?.name}`,
6036
+ timestamp: Date.now()
6037
+ };
6038
+ }
6039
+ }
6040
+ return "";
6041
+ };
5912
6042
  const migrationResolver = ({ name, path: path2, context }) => {
5913
6043
  const { db } = context;
5914
6044
  if (!path2) {
@@ -5937,7 +6067,20 @@ const createUserMigrationProvider = (db) => {
5937
6067
  const context = { db };
5938
6068
  const umzugProvider = new umzug.Umzug({
5939
6069
  storage: createStorage({ db, tableName: "strapi_migrations" }),
5940
- logger: console,
6070
+ logger: {
6071
+ info(message) {
6072
+ db.logger.info(transformLogMessage("info", message));
6073
+ },
6074
+ warn(message) {
6075
+ db.logger.warn(transformLogMessage("warn", message));
6076
+ },
6077
+ error(message) {
6078
+ db.logger.error(transformLogMessage("error", message));
6079
+ },
6080
+ debug(message) {
6081
+ db.logger.debug(transformLogMessage("debug", message));
6082
+ }
6083
+ },
5941
6084
  context,
5942
6085
  migrations: {
5943
6086
  glob: ["*.{js,sql}", { cwd: dir }],
@@ -6243,7 +6386,8 @@ const createdLocale = {
6243
6386
  if (!model) {
6244
6387
  continue;
6245
6388
  }
6246
- if (_.isNil(meta.attributes.locale)) {
6389
+ const hasLocaleColumn = await knex2.schema.hasColumn(meta.tableName, "locale");
6390
+ if (meta.attributes.locale && !hasLocaleColumn) {
6247
6391
  await createLocaleColumn(knex2, meta.tableName);
6248
6392
  }
6249
6393
  }
@@ -6252,17 +6396,87 @@ const createdLocale = {
6252
6396
  throw new Error("not implemented");
6253
6397
  }
6254
6398
  };
6399
+ const createPublishedAtColumn = async (db, tableName) => {
6400
+ await db.schema.alterTable(tableName, (table) => {
6401
+ table.string("published_at");
6402
+ });
6403
+ };
6404
+ const createdPublishedAt = {
6405
+ name: "5.0.0-04-created-published-at",
6406
+ async up(knex2, db) {
6407
+ for (const meta of db.metadata.values()) {
6408
+ const hasTable = await knex2.schema.hasTable(meta.tableName);
6409
+ if (!hasTable) {
6410
+ continue;
6411
+ }
6412
+ const uid = meta.uid;
6413
+ const model = strapi.getModel(uid);
6414
+ if (!model) {
6415
+ continue;
6416
+ }
6417
+ const hasPublishedAtColumn = await knex2.schema.hasColumn(meta.tableName, "published_at");
6418
+ if (meta.attributes.publishedAt && !hasPublishedAtColumn) {
6419
+ await createPublishedAtColumn(knex2, meta.tableName);
6420
+ }
6421
+ }
6422
+ },
6423
+ async down() {
6424
+ throw new Error("not implemented");
6425
+ }
6426
+ };
6427
+ const dropIndex = async (knex2, tableName, columnName) => {
6428
+ try {
6429
+ await knex2.schema.alterTable(tableName, (table) => {
6430
+ table.dropUnique([columnName], `${tableName}_${columnName}_unique`);
6431
+ });
6432
+ } catch (error) {
6433
+ }
6434
+ };
6435
+ const dropSlugFieldsIndex = {
6436
+ name: "5.0.0-05-drop-slug-fields-index",
6437
+ async up(knex2, db) {
6438
+ for (const meta of db.metadata.values()) {
6439
+ const hasTable = await knex2.schema.hasTable(meta.tableName);
6440
+ if (!hasTable) {
6441
+ continue;
6442
+ }
6443
+ for (const attribute of Object.values(meta.attributes)) {
6444
+ if (attribute.type === "uid" && attribute.columnName) {
6445
+ await dropIndex(knex2, meta.tableName, attribute.columnName);
6446
+ }
6447
+ }
6448
+ }
6449
+ },
6450
+ async down() {
6451
+ throw new Error("not implemented");
6452
+ }
6453
+ };
6255
6454
  const internalMigrations = [
6256
6455
  renameIdentifiersLongerThanMaxLength,
6257
6456
  createdDocumentId,
6258
- createdLocale
6457
+ createdLocale,
6458
+ createdPublishedAt,
6459
+ dropSlugFieldsIndex
6259
6460
  ];
6260
6461
  const createInternalMigrationProvider = (db) => {
6261
6462
  const context = { db };
6262
6463
  const migrations = [...internalMigrations];
6263
6464
  const umzugProvider = new umzug.Umzug({
6264
6465
  storage: createStorage({ db, tableName: "strapi_migrations_internal" }),
6265
- logger: console,
6466
+ logger: {
6467
+ info(message) {
6468
+ db.logger.debug(transformLogMessage("info", message));
6469
+ },
6470
+ warn(message) {
6471
+ db.logger.warn(transformLogMessage("warn", message));
6472
+ },
6473
+ error(message) {
6474
+ db.logger.error(transformLogMessage("error", message));
6475
+ },
6476
+ debug(message) {
6477
+ db.logger.debug(transformLogMessage("debug", message));
6478
+ }
6479
+ },
6266
6480
  context,
6267
6481
  migrations: () => migrations.map((migration) => {
6268
6482
  return {
@@ -6533,6 +6747,7 @@ class Database {
6533
6747
  migrations;
6534
6748
  lifecycles;
6535
6749
  entityManager;
6750
+ logger;
6536
6751
  constructor(config) {
6537
6752
  this.config = {
6538
6753
  ...config,
@@ -6552,6 +6767,7 @@ class Database {
6552
6767
  this.migrations = createMigrationsProvider(this);
6553
6768
  this.lifecycles = createLifecyclesProvider(this);
6554
6769
  this.entityManager = createEntityManager(this);
6770
+ this.logger = config.logger ?? console;
6555
6771
  }
6556
6772
  async init({ models }) {
6557
6773
  this.metadata.loadModels(models);