@strapi/database 4.25.19 → 4.25.20

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.mjs CHANGED
@@ -28,6 +28,9 @@ class Dialect {
28
28
  }
29
29
  initialize() {
30
30
  }
31
+ getTables() {
32
+ throw new Error("getTables not implemented for this dialect");
33
+ }
31
34
  getSqlType(type) {
32
35
  return type;
33
36
  }
@@ -983,7 +986,7 @@ const getDialect = (db) => {
983
986
  const dialect = new constructor(db, dialectName);
984
987
  return dialect;
985
988
  };
986
- const debug$1 = createDebug("strapi::database");
989
+ const debug$2 = createDebug("strapi::database");
987
990
  const createSchemaBuilder = (db) => {
988
991
  const helpers2 = createHelpers(db);
989
992
  return {
@@ -1009,12 +1012,12 @@ const createSchemaBuilder = (db) => {
1009
1012
  */
1010
1013
  async createTables(tables, trx) {
1011
1014
  for (const table of tables) {
1012
- debug$1(`Creating table: ${table.name}`);
1015
+ debug$2(`Creating table: ${table.name}`);
1013
1016
  const schemaBuilder = this.getSchemaBuilder(trx);
1014
1017
  await helpers2.createTable(schemaBuilder, table);
1015
1018
  }
1016
1019
  for (const table of tables) {
1017
- debug$1(`Creating table foreign keys: ${table.name}`);
1020
+ debug$2(`Creating table foreign keys: ${table.name}`);
1018
1021
  const schemaBuilder = this.getSchemaBuilder(trx);
1019
1022
  await helpers2.createTableForeignKeys(schemaBuilder, table);
1020
1023
  }
@@ -1045,18 +1048,18 @@ const createSchemaBuilder = (db) => {
1045
1048
  await this.createTables(schemaDiff.tables.added, trx);
1046
1049
  if (forceMigration) {
1047
1050
  for (const table of schemaDiff.tables.removed) {
1048
- debug$1(`Removing table foreign keys: ${table.name}`);
1051
+ debug$2(`Removing table foreign keys: ${table.name}`);
1049
1052
  const schemaBuilder = this.getSchemaBuilder(trx);
1050
1053
  await helpers2.dropTableForeignKeys(schemaBuilder, table);
1051
1054
  }
1052
1055
  for (const table of schemaDiff.tables.removed) {
1053
- debug$1(`Removing table: ${table.name}`);
1056
+ debug$2(`Removing table: ${table.name}`);
1054
1057
  const schemaBuilder = this.getSchemaBuilder(trx);
1055
1058
  await helpers2.dropTable(schemaBuilder, table);
1056
1059
  }
1057
1060
  }
1058
1061
  for (const table of schemaDiff.tables.updated) {
1059
- debug$1(`Updating table: ${table.name}`);
1062
+ debug$2(`Updating table: ${table.name}`);
1060
1063
  const schemaBuilder = this.getSchemaBuilder(trx);
1061
1064
  await helpers2.alterTable(schemaBuilder, table);
1062
1065
  }
@@ -1152,27 +1155,27 @@ const createHelpers = (db) => {
1152
1155
  const alterTable = async (schemaBuilder, table) => {
1153
1156
  await schemaBuilder.alterTable(table.name, (tableBuilder) => {
1154
1157
  for (const removedIndex of table.indexes.removed) {
1155
- debug$1(`Dropping index ${removedIndex.name}`);
1158
+ debug$2(`Dropping index ${removedIndex.name}`);
1156
1159
  dropIndex(tableBuilder, removedIndex);
1157
1160
  }
1158
1161
  for (const updateddIndex of table.indexes.updated) {
1159
- debug$1(`Dropping updated index ${updateddIndex.name}`);
1162
+ debug$2(`Dropping updated index ${updateddIndex.name}`);
1160
1163
  dropIndex(tableBuilder, updateddIndex.object);
1161
1164
  }
1162
1165
  for (const removedForeignKey of table.foreignKeys.removed) {
1163
- debug$1(`Dropping foreign key ${removedForeignKey.name}`);
1166
+ debug$2(`Dropping foreign key ${removedForeignKey.name}`);
1164
1167
  dropForeignKey(tableBuilder, removedForeignKey);
1165
1168
  }
1166
1169
  for (const updatedForeignKey of table.foreignKeys.updated) {
1167
- debug$1(`Dropping updated foreign key ${updatedForeignKey.name}`);
1170
+ debug$2(`Dropping updated foreign key ${updatedForeignKey.name}`);
1168
1171
  dropForeignKey(tableBuilder, updatedForeignKey.object);
1169
1172
  }
1170
1173
  for (const removedColumn of table.columns.removed) {
1171
- debug$1(`Dropping column ${removedColumn.name}`);
1174
+ debug$2(`Dropping column ${removedColumn.name}`);
1172
1175
  dropColumn(tableBuilder, removedColumn);
1173
1176
  }
1174
1177
  for (const updatedColumn of table.columns.updated) {
1175
- debug$1(`Updating column ${updatedColumn.name}`);
1178
+ debug$2(`Updating column ${updatedColumn.name}`);
1176
1179
  const { object } = updatedColumn;
1177
1180
  if (object.type === "increments") {
1178
1181
  createColumn2(tableBuilder, { ...object, type: "integer" }).alter();
@@ -1181,15 +1184,15 @@ const createHelpers = (db) => {
1181
1184
  }
1182
1185
  }
1183
1186
  for (const updatedForeignKey of table.foreignKeys.updated) {
1184
- debug$1(`Recreating updated foreign key ${updatedForeignKey.name}`);
1187
+ debug$2(`Recreating updated foreign key ${updatedForeignKey.name}`);
1185
1188
  createForeignKey(tableBuilder, updatedForeignKey.object);
1186
1189
  }
1187
1190
  for (const updatedIndex of table.indexes.updated) {
1188
- debug$1(`Recreating updated index ${updatedIndex.name}`);
1191
+ debug$2(`Recreating updated index ${updatedIndex.name}`);
1189
1192
  createIndex(tableBuilder, updatedIndex.object);
1190
1193
  }
1191
1194
  for (const addedColumn of table.columns.added) {
1192
- debug$1(`Creating column ${addedColumn.name}`);
1195
+ debug$2(`Creating column ${addedColumn.name}`);
1193
1196
  if (addedColumn.type === "increments" && !db.dialect.canAddIncrements()) {
1194
1197
  tableBuilder.integer(addedColumn.name).unsigned();
1195
1198
  tableBuilder.primary([addedColumn.name]);
@@ -1198,11 +1201,11 @@ const createHelpers = (db) => {
1198
1201
  }
1199
1202
  }
1200
1203
  for (const addedForeignKey of table.foreignKeys.added) {
1201
- debug$1(`Creating foreign keys ${addedForeignKey.name}`);
1204
+ debug$2(`Creating foreign keys ${addedForeignKey.name}`);
1202
1205
  createForeignKey(tableBuilder, addedForeignKey);
1203
1206
  }
1204
1207
  for (const addedIndex of table.indexes.added) {
1205
- debug$1(`Creating index ${addedIndex.name}`);
1208
+ debug$2(`Creating index ${addedIndex.name}`);
1206
1209
  createIndex(tableBuilder, addedIndex);
1207
1210
  }
1208
1211
  });
@@ -1788,7 +1791,7 @@ const metadataToSchema = (metadata) => {
1788
1791
  });
1789
1792
  return schema;
1790
1793
  };
1791
- const debug = createDebug("strapi::database");
1794
+ const debug$1 = createDebug("strapi::database");
1792
1795
  const createSchemaProvider = (db) => {
1793
1796
  const schema = metadataToSchema(db.metadata);
1794
1797
  return {
@@ -1799,7 +1802,7 @@ const createSchemaProvider = (db) => {
1799
1802
  * Drops the database schema
1800
1803
  */
1801
1804
  async drop() {
1802
- debug("Dropping database schema");
1805
+ debug$1("Dropping database schema");
1803
1806
  const DBSchema = await db.dialect.schemaInspector.getSchema();
1804
1807
  await this.builder.dropSchema(DBSchema);
1805
1808
  },
@@ -1807,47 +1810,49 @@ const createSchemaProvider = (db) => {
1807
1810
  * Creates the database schema
1808
1811
  */
1809
1812
  async create() {
1810
- debug("Created database schema");
1813
+ debug$1("Created database schema");
1811
1814
  await this.builder.createSchema(schema);
1812
1815
  },
1813
1816
  /**
1814
1817
  * Resets the database schema
1815
1818
  */
1816
1819
  async reset() {
1817
- debug("Resetting database schema");
1820
+ debug$1("Resetting database schema");
1818
1821
  await this.drop();
1819
1822
  await this.create();
1820
1823
  },
1821
1824
  async syncSchema() {
1822
- debug("Synchronizing database schema");
1825
+ debug$1("Synchronizing database schema");
1823
1826
  const DBSchema = await db.dialect.schemaInspector.getSchema();
1824
1827
  const { status, diff } = await this.schemaDiff.diff(DBSchema, schema);
1825
1828
  if (status === "CHANGED") {
1826
1829
  await this.builder.updateSchema(diff);
1827
1830
  }
1828
1831
  await this.schemaStorage.add(schema);
1832
+ return status;
1829
1833
  },
1830
1834
  // TODO: support options to migrate softly or forcefully
1831
1835
  // TODO: support option to disable auto migration & run a CLI command instead to avoid doing it at startup
1832
1836
  // TODO: Allow keeping extra indexes / extra tables / extra columns (globally or on a per table basis)
1833
1837
  async sync() {
1834
1838
  if (await db.migrations.shouldRun()) {
1835
- debug("Found migrations to run");
1839
+ debug$1("Found migrations to run");
1836
1840
  await db.migrations.up();
1837
1841
  return this.syncSchema();
1838
1842
  }
1839
1843
  const oldSchema = await this.schemaStorage.read();
1840
1844
  if (!oldSchema) {
1841
- debug("Schema not persisted yet");
1845
+ debug$1("Schema not persisted yet");
1842
1846
  return this.syncSchema();
1843
1847
  }
1844
1848
  const { hash: oldHash } = oldSchema;
1845
1849
  const hash = await this.schemaStorage.hashSchema(schema);
1846
1850
  if (oldHash !== hash) {
1847
- debug("Schema changed");
1851
+ debug$1("Schema changed");
1848
1852
  return this.syncSchema();
1849
1853
  }
1850
- debug("Schema unchanged");
1854
+ debug$1("Schema unchanged");
1855
+ return "UNCHANGED";
1851
1856
  }
1852
1857
  };
1853
1858
  };
@@ -5955,6 +5960,7 @@ const createLifecyclesProvider = (db) => {
5955
5960
  timestampsLifecyclesSubscriber,
5956
5961
  modelsLifecyclesSubscriber
5957
5962
  ];
5963
+ let isLifecycleHooksDisabled = false;
5958
5964
  return {
5959
5965
  subscribe(subscriber) {
5960
5966
  strict(
@@ -5964,6 +5970,12 @@ const createLifecyclesProvider = (db) => {
5964
5970
  subscribers.push(subscriber);
5965
5971
  return () => subscribers.splice(subscribers.indexOf(subscriber), 1);
5966
5972
  },
5973
+ disable() {
5974
+ isLifecycleHooksDisabled = true;
5975
+ },
5976
+ enable() {
5977
+ isLifecycleHooksDisabled = false;
5978
+ },
5967
5979
  clear() {
5968
5980
  subscribers = [];
5969
5981
  },
@@ -5983,6 +5995,8 @@ const createLifecyclesProvider = (db) => {
5983
5995
  * @param {Map<any, any>} states
5984
5996
  */
5985
5997
  async run(action, uid, properties, states = /* @__PURE__ */ new Map()) {
5998
+ if (isLifecycleHooksDisabled)
5999
+ return states;
5986
6000
  for (let i = 0; i < subscribers.length; i += 1) {
5987
6001
  const subscriber = subscribers[i];
5988
6002
  if (typeof subscriber === "function") {
@@ -6048,6 +6062,61 @@ const createConnection = (config) => {
6048
6062
  }
6049
6063
  return knex(knexConfig);
6050
6064
  };
6065
+ const debug = createDebug("strapi::database");
6066
+ const isMorphRelationWithPivot = (attribute, pivot) => {
6067
+ return attribute.type === "relation" && "relation" in attribute && "joinTable" in attribute && "target" in attribute && "name" in attribute.joinTable && "pivotColumns" in attribute.joinTable && attribute.joinTable.pivotColumns.includes(pivot);
6068
+ };
6069
+ const filterMorphRelationalAttributes = (attributes, pivot) => {
6070
+ return Object.values(attributes).filter(
6071
+ (attribute) => isMorphRelationWithPivot(attribute, pivot)
6072
+ );
6073
+ };
6074
+ const removeOrphanMorphType = async (db, { pivot }) => {
6075
+ debug(`Removing orphaned morph type: ${JSON.stringify(pivot)}`);
6076
+ const mdValues = db.metadata.values();
6077
+ for (const model of mdValues) {
6078
+ const attributes = filterMorphRelationalAttributes(model.attributes || {}, pivot);
6079
+ for (const attribute of attributes) {
6080
+ const joinTableName = attribute.joinTable.name;
6081
+ const morphTypes = await db.connection(joinTableName).distinct(pivot).pluck(pivot);
6082
+ for (const morphType of morphTypes) {
6083
+ const deleteComponentType = await (async () => {
6084
+ try {
6085
+ return !db.metadata.get(morphType);
6086
+ } catch {
6087
+ debug(`Metadata for morph type "${morphType}" in table "${joinTableName}" not found`);
6088
+ return true;
6089
+ }
6090
+ })();
6091
+ if (deleteComponentType) {
6092
+ debug(`Removing invalid morph type "${morphType}" from table "${joinTableName}".`);
6093
+ try {
6094
+ await db.connection(joinTableName).where(pivot, morphType).del();
6095
+ } catch (error) {
6096
+ const errorMessage = error instanceof Error ? error.message : String(error);
6097
+ debug(
6098
+ `Failed to remove invalid morph type "${morphType}" from table "${joinTableName}": ${errorMessage}`
6099
+ );
6100
+ }
6101
+ }
6102
+ }
6103
+ }
6104
+ }
6105
+ };
6106
+ const asyncCurry = (fn) => {
6107
+ const curried = (...args) => {
6108
+ if (args.length >= fn.length) {
6109
+ return fn(...args);
6110
+ }
6111
+ return (...moreArgs) => curried(...args, ...moreArgs);
6112
+ };
6113
+ return curried;
6114
+ };
6115
+ const createRepairManager = (db) => {
6116
+ return {
6117
+ removeOrphanMorphType: asyncCurry(removeOrphanMorphType)(db)
6118
+ };
6119
+ };
6051
6120
  const transformAttribute = (attribute) => {
6052
6121
  switch (attribute.type) {
6053
6122
  case "media": {
@@ -6145,6 +6214,7 @@ class Database {
6145
6214
  migrations;
6146
6215
  lifecycles;
6147
6216
  entityManager;
6217
+ repair;
6148
6218
  static transformContentTypes = transformContentTypes;
6149
6219
  static async init(config) {
6150
6220
  const db = new Database(config);
@@ -6169,6 +6239,7 @@ class Database {
6169
6239
  this.migrations = createMigrationsProvider(this);
6170
6240
  this.lifecycles = createLifecyclesProvider(this);
6171
6241
  this.entityManager = createEntityManager(this);
6242
+ this.repair = createRepairManager(this);
6172
6243
  }
6173
6244
  query(uid) {
6174
6245
  if (!this.metadata.has(uid)) {