@strapi/database 5.0.0-beta.1 → 5.0.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/dist/entity-manager/index.d.ts.map +1 -1
  2. package/dist/entity-manager/relations-orderer.d.ts.map +1 -1
  3. package/dist/index.d.ts +3 -6
  4. package/dist/index.d.ts.map +1 -1
  5. package/dist/index.js +757 -313
  6. package/dist/index.js.map +1 -1
  7. package/dist/index.mjs +752 -308
  8. package/dist/index.mjs.map +1 -1
  9. package/dist/lifecycles/types.d.ts +1 -0
  10. package/dist/lifecycles/types.d.ts.map +1 -1
  11. package/dist/metadata/index.d.ts +1 -1
  12. package/dist/metadata/index.d.ts.map +1 -1
  13. package/dist/metadata/metadata.d.ts +2 -1
  14. package/dist/metadata/metadata.d.ts.map +1 -1
  15. package/dist/metadata/relations.d.ts.map +1 -1
  16. package/dist/migrations/internal-migrations/5.0.0-01-convert-identifiers-long-than-max-length.d.ts +3 -0
  17. package/dist/migrations/internal-migrations/5.0.0-01-convert-identifiers-long-than-max-length.d.ts.map +1 -0
  18. package/dist/migrations/internal-migrations/5.0.0-02-document-id.d.ts +3 -0
  19. package/dist/migrations/internal-migrations/5.0.0-02-document-id.d.ts.map +1 -0
  20. package/dist/migrations/internal-migrations/index.d.ts.map +1 -1
  21. package/dist/query/helpers/populate/apply.d.ts.map +1 -1
  22. package/dist/schema/index.d.ts +0 -3
  23. package/dist/schema/index.d.ts.map +1 -1
  24. package/dist/types/index.d.ts +3 -0
  25. package/dist/types/index.d.ts.map +1 -1
  26. package/dist/utils/identifiers/hash.d.ts +31 -0
  27. package/dist/utils/identifiers/hash.d.ts.map +1 -0
  28. package/dist/utils/identifiers/index.d.ts +107 -47
  29. package/dist/utils/identifiers/index.d.ts.map +1 -1
  30. package/dist/utils/identifiers/types.d.ts +27 -0
  31. package/dist/utils/identifiers/types.d.ts.map +1 -0
  32. package/dist/validations/relations/bidirectional.d.ts.map +1 -1
  33. package/package.json +7 -6
  34. package/dist/utils/identifiers/shortener.d.ts +0 -73
  35. package/dist/utils/identifiers/shortener.d.ts.map +0 -1
package/dist/index.js CHANGED
@@ -7,13 +7,14 @@ 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$1 = require("@strapi/utils");
10
+ const utils = require("@strapi/utils");
11
11
  const KnexBuilder = require("knex/lib/query/querybuilder");
12
12
  const KnexRaw = require("knex/lib/raw");
13
13
  const stream = require("stream");
14
14
  const node_async_hooks = require("node:async_hooks");
15
15
  const _$1 = require("lodash");
16
16
  const umzug = require("umzug");
17
+ const cuid2 = require("@paralleldrive/cuid2");
17
18
  const assert = require("assert");
18
19
  const knex = require("knex");
19
20
  const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
@@ -1007,7 +1008,7 @@ const getDialect = (db) => {
1007
1008
  const dialect = new constructor(db, dialectName);
1008
1009
  return dialect;
1009
1010
  };
1010
- const debug$1 = createDebug__default.default("strapi::database");
1011
+ const debug$2 = createDebug__default.default("strapi::database");
1011
1012
  const createSchemaBuilder = (db) => {
1012
1013
  const helpers2 = createHelpers(db);
1013
1014
  return {
@@ -1033,12 +1034,12 @@ const createSchemaBuilder = (db) => {
1033
1034
  */
1034
1035
  async createTables(tables, trx) {
1035
1036
  for (const table of tables) {
1036
- debug$1(`Creating table: ${table.name}`);
1037
+ debug$2(`Creating table: ${table.name}`);
1037
1038
  const schemaBuilder = this.getSchemaBuilder(trx);
1038
1039
  await helpers2.createTable(schemaBuilder, table);
1039
1040
  }
1040
1041
  for (const table of tables) {
1041
- debug$1(`Creating table foreign keys: ${table.name}`);
1042
+ debug$2(`Creating table foreign keys: ${table.name}`);
1042
1043
  const schemaBuilder = this.getSchemaBuilder(trx);
1043
1044
  await helpers2.createTableForeignKeys(schemaBuilder, table);
1044
1045
  }
@@ -1069,18 +1070,18 @@ const createSchemaBuilder = (db) => {
1069
1070
  await this.createTables(schemaDiff.tables.added, trx);
1070
1071
  if (forceMigration) {
1071
1072
  for (const table of schemaDiff.tables.removed) {
1072
- debug$1(`Removing table foreign keys: ${table.name}`);
1073
+ debug$2(`Removing table foreign keys: ${table.name}`);
1073
1074
  const schemaBuilder = this.getSchemaBuilder(trx);
1074
1075
  await helpers2.dropTableForeignKeys(schemaBuilder, table);
1075
1076
  }
1076
1077
  for (const table of schemaDiff.tables.removed) {
1077
- debug$1(`Removing table: ${table.name}`);
1078
+ debug$2(`Removing table: ${table.name}`);
1078
1079
  const schemaBuilder = this.getSchemaBuilder(trx);
1079
1080
  await helpers2.dropTable(schemaBuilder, table);
1080
1081
  }
1081
1082
  }
1082
1083
  for (const table of schemaDiff.tables.updated) {
1083
- debug$1(`Updating table: ${table.name}`);
1084
+ debug$2(`Updating table: ${table.name}`);
1084
1085
  const schemaBuilder = this.getSchemaBuilder(trx);
1085
1086
  await helpers2.alterTable(schemaBuilder, table);
1086
1087
  }
@@ -1176,27 +1177,27 @@ const createHelpers = (db) => {
1176
1177
  const alterTable = async (schemaBuilder, table) => {
1177
1178
  await schemaBuilder.alterTable(table.name, (tableBuilder) => {
1178
1179
  for (const removedIndex of table.indexes.removed) {
1179
- debug$1(`Dropping index ${removedIndex.name}`);
1180
+ debug$2(`Dropping index ${removedIndex.name} on ${table.name}`);
1180
1181
  dropIndex(tableBuilder, removedIndex);
1181
1182
  }
1182
1183
  for (const updateddIndex of table.indexes.updated) {
1183
- debug$1(`Dropping updated index ${updateddIndex.name}`);
1184
+ debug$2(`Dropping updated index ${updateddIndex.name} on ${table.name}`);
1184
1185
  dropIndex(tableBuilder, updateddIndex.object);
1185
1186
  }
1186
1187
  for (const removedForeignKey of table.foreignKeys.removed) {
1187
- debug$1(`Dropping foreign key ${removedForeignKey.name}`);
1188
+ debug$2(`Dropping foreign key ${removedForeignKey.name} on ${table.name}`);
1188
1189
  dropForeignKey(tableBuilder, removedForeignKey);
1189
1190
  }
1190
1191
  for (const updatedForeignKey of table.foreignKeys.updated) {
1191
- debug$1(`Dropping updated foreign key ${updatedForeignKey.name}`);
1192
+ debug$2(`Dropping updated foreign key ${updatedForeignKey.name} on ${table.name}`);
1192
1193
  dropForeignKey(tableBuilder, updatedForeignKey.object);
1193
1194
  }
1194
1195
  for (const removedColumn of table.columns.removed) {
1195
- debug$1(`Dropping column ${removedColumn.name}`);
1196
+ debug$2(`Dropping column ${removedColumn.name} on ${table.name}`);
1196
1197
  dropColumn(tableBuilder, removedColumn);
1197
1198
  }
1198
1199
  for (const updatedColumn of table.columns.updated) {
1199
- debug$1(`Updating column ${updatedColumn.name}`);
1200
+ debug$2(`Updating column ${updatedColumn.name} on ${table.name}`);
1200
1201
  const { object } = updatedColumn;
1201
1202
  if (object.type === "increments") {
1202
1203
  createColumn2(tableBuilder, { ...object, type: "integer" }).alter();
@@ -1205,15 +1206,15 @@ const createHelpers = (db) => {
1205
1206
  }
1206
1207
  }
1207
1208
  for (const updatedForeignKey of table.foreignKeys.updated) {
1208
- debug$1(`Recreating updated foreign key ${updatedForeignKey.name}`);
1209
+ debug$2(`Recreating updated foreign key ${updatedForeignKey.name} on ${table.name}`);
1209
1210
  createForeignKey(tableBuilder, updatedForeignKey.object);
1210
1211
  }
1211
1212
  for (const updatedIndex of table.indexes.updated) {
1212
- debug$1(`Recreating updated index ${updatedIndex.name}`);
1213
+ debug$2(`Recreating updated index ${updatedIndex.name} on ${table.name}`);
1213
1214
  createIndex(tableBuilder, updatedIndex.object);
1214
1215
  }
1215
1216
  for (const addedColumn of table.columns.added) {
1216
- debug$1(`Creating column ${addedColumn.name}`);
1217
+ debug$2(`Creating column ${addedColumn.name} on ${table.name}`);
1217
1218
  if (addedColumn.type === "increments" && !db.dialect.canAddIncrements()) {
1218
1219
  tableBuilder.integer(addedColumn.name).unsigned();
1219
1220
  tableBuilder.primary([addedColumn.name]);
@@ -1222,11 +1223,11 @@ const createHelpers = (db) => {
1222
1223
  }
1223
1224
  }
1224
1225
  for (const addedForeignKey of table.foreignKeys.added) {
1225
- debug$1(`Creating foreign keys ${addedForeignKey.name}`);
1226
+ debug$2(`Creating foreign keys ${addedForeignKey.name} on ${table.name}`);
1226
1227
  createForeignKey(tableBuilder, addedForeignKey);
1227
1228
  }
1228
1229
  for (const addedIndex of table.indexes.added) {
1229
- debug$1(`Creating index ${addedIndex.name}`);
1230
+ debug$2(`Creating index ${addedIndex.name} on ${table.name}`);
1230
1231
  createIndex(tableBuilder, addedIndex);
1231
1232
  }
1232
1233
  });
@@ -1645,11 +1646,6 @@ const isScalar = (type) => SCALAR_TYPES.includes(type);
1645
1646
  const isRelation = (type) => type === "relation";
1646
1647
  const isScalarAttribute = (attribute) => isScalar(attribute.type);
1647
1648
  const isRelationalAttribute = (attribute) => isRelation(attribute.type);
1648
- const MAX_DB_IDENTIFIER_LENGTH = 0;
1649
- const HASH_LENGTH = 5;
1650
- const HASH_SEPARATOR = "";
1651
- const IDENTIFIER_SEPARATOR = "_";
1652
- const MIN_TOKEN_LENGTH = 3;
1653
1649
  function createHash(data, len) {
1654
1650
  if (!_.isInteger(len) || len <= 0) {
1655
1651
  throw new Error(`createHash length must be a positive integer, received ${len}`);
@@ -1657,201 +1653,334 @@ function createHash(data, len) {
1657
1653
  const hash = crypto__default$1.default.createHash("shake256", { outputLength: Math.ceil(len / 2) }).update(data);
1658
1654
  return hash.digest("hex").substring(0, len);
1659
1655
  }
1660
- function getShortenedName(name, len) {
1661
- if (!_.isInteger(len) || len <= 0) {
1662
- throw new Error(`tokenWithHash length must be a positive integer, received ${len}`);
1663
- }
1664
- if (name.length <= len) {
1665
- return name;
1666
- }
1667
- if (len < MIN_TOKEN_LENGTH + HASH_LENGTH) {
1668
- throw new Error(
1669
- `length for part of identifier too short, minimum is hash length (${HASH_LENGTH}) plus min token length (${MIN_TOKEN_LENGTH}), received ${len} for token ${name}`
1670
- );
1671
- }
1672
- const availableLength = len - HASH_LENGTH - HASH_SEPARATOR.length;
1673
- if (availableLength < MIN_TOKEN_LENGTH) {
1674
- throw new Error(
1675
- `length for part of identifier minimum is less than min token length (${MIN_TOKEN_LENGTH}), received ${len} for token ${name}`
1676
- );
1656
+ const IDENTIFIER_MAX_LENGTH = 55;
1657
+ class Identifiers {
1658
+ ID_COLUMN = "id";
1659
+ ORDER_COLUMN = "order";
1660
+ FIELD_COLUMN = "field";
1661
+ HASH_LENGTH = 5;
1662
+ HASH_SEPARATOR = "";
1663
+ // no separator is needed, we will just attach hash directly to shortened name
1664
+ IDENTIFIER_SEPARATOR = "_";
1665
+ MIN_TOKEN_LENGTH = 3;
1666
+ // the min characters required at the beginning of a name part
1667
+ // Fixed compression map for suffixes and prefixes
1668
+ #replacementMap = {
1669
+ links: "lnk",
1670
+ order_inv_fk: "oifk",
1671
+ order: "ord",
1672
+ morphs: "mph",
1673
+ index: "idx",
1674
+ inv_fk: "ifk",
1675
+ order_fk: "ofk",
1676
+ id_column_index: "idix",
1677
+ order_index: "oidx",
1678
+ unique: "uq",
1679
+ primary: "pk"
1680
+ };
1681
+ #options;
1682
+ constructor(options) {
1683
+ this.#options = options;
1677
1684
  }
1678
- return `${name.substring(0, availableLength)}${HASH_SEPARATOR}${createHash(name, HASH_LENGTH)}`;
1679
- }
1680
- function getNameFromTokens(nameTokens, maxLength = MAX_DB_IDENTIFIER_LENGTH) {
1681
- if (!_.isInteger(maxLength) || maxLength < 0) {
1682
- throw new Error("maxLength must be a positive integer or 0 (for unlimited length)");
1685
+ get replacementMap() {
1686
+ return this.#replacementMap;
1683
1687
  }
1684
- const fullLengthName = nameTokens.map((token) => _.snakeCase(token.name)).join(IDENTIFIER_SEPARATOR);
1685
- if (fullLengthName.length <= maxLength || maxLength === 0) {
1686
- return fullLengthName;
1688
+ get options() {
1689
+ return this.#options;
1687
1690
  }
1688
- const [compressible, incompressible] = _.partition(
1689
- (token) => token.compressible,
1690
- nameTokens
1691
- );
1692
- const totalIncompressibleLength = _.sumBy((token) => token.name.length)(incompressible);
1693
- const totalSeparatorsLength = nameTokens.length * IDENTIFIER_SEPARATOR.length - 1;
1694
- const available = maxLength - totalIncompressibleLength - totalSeparatorsLength;
1695
- const availablePerToken = Math.floor(available / compressible.length);
1696
- if (totalIncompressibleLength + totalSeparatorsLength > maxLength || availablePerToken < MIN_TOKEN_LENGTH) {
1697
- throw new Error("Maximum length is too small to accommodate all tokens");
1698
- }
1699
- let surplus = available % compressible.length;
1700
- const minHashedLength = HASH_LENGTH + HASH_SEPARATOR.length + MIN_TOKEN_LENGTH;
1701
- const totalLength = nameTokens.reduce((total, token) => {
1702
- if (token.compressible) {
1703
- if (token.name.length < availablePerToken) {
1704
- return total + token.name.length;
1705
- }
1706
- return total + minHashedLength;
1707
- }
1708
- return total + token.name.length;
1709
- }, nameTokens.length * IDENTIFIER_SEPARATOR.length - 1);
1710
- if (maxLength < totalLength) {
1711
- throw new Error("Maximum length is too small to accommodate all tokens");
1712
- }
1713
- let deficits = [];
1714
- compressible.forEach((token) => {
1715
- const actualLength = token.name.length;
1716
- if (actualLength < availablePerToken) {
1717
- surplus += availablePerToken - actualLength;
1718
- token.allocatedLength = actualLength;
1719
- } else {
1720
- token.allocatedLength = availablePerToken;
1721
- deficits.push(token);
1691
+ mapshortNames = (name) => {
1692
+ if (name in this.replacementMap) {
1693
+ return this.replacementMap[name];
1722
1694
  }
1723
- });
1724
- function filterAndIncreaseLength(token) {
1725
- if (token.allocatedLength < token.name.length && surplus > 0) {
1726
- token.allocatedLength += 1;
1727
- surplus -= 1;
1728
- return token.allocatedLength < token.name.length;
1695
+ return void 0;
1696
+ };
1697
+ // Generic name handler that must be used by all helper functions
1698
+ /**
1699
+ * TODO: we should be requiring snake_case inputs for all names here, but we
1700
+ * aren't and it will require some refactoring to make it work. Currently if
1701
+ * we get names 'myModel' and 'my_model' they would be converted to the same
1702
+ * final string my_model which generally works but is not entirely safe
1703
+ * */
1704
+ getName = (names, options) => {
1705
+ const tokens = ___default.default.castArray(names).map((name) => {
1706
+ return {
1707
+ name,
1708
+ compressible: true
1709
+ };
1710
+ });
1711
+ if (options?.suffix) {
1712
+ tokens.push({
1713
+ name: options.suffix,
1714
+ compressible: false,
1715
+ shortName: this.mapshortNames(options.suffix)
1716
+ });
1729
1717
  }
1730
- return false;
1731
- }
1732
- let previousSurplus = surplus + 1;
1733
- while (surplus > 0 && deficits.length > 0) {
1734
- deficits = deficits.filter((token) => filterAndIncreaseLength(token));
1735
- if (surplus === previousSurplus) {
1736
- break;
1718
+ if (options?.prefix) {
1719
+ tokens.unshift({
1720
+ name: options.prefix,
1721
+ compressible: false,
1722
+ shortName: this.mapshortNames(options.prefix)
1723
+ });
1737
1724
  }
1738
- previousSurplus = surplus;
1739
- }
1740
- const shortenedName = nameTokens.map((token) => {
1741
- if (token.compressible && "allocatedLength" in token && token.allocatedLength !== void 0) {
1742
- return getShortenedName(token.name, token.allocatedLength);
1725
+ return this.getNameFromTokens(tokens);
1726
+ };
1727
+ /**
1728
+ * TABLES
1729
+ */
1730
+ getTableName = (name, options) => {
1731
+ return this.getName(name, options);
1732
+ };
1733
+ getJoinTableName = (collectionName, attributeName, options) => {
1734
+ return this.getName([collectionName, attributeName], {
1735
+ suffix: "links",
1736
+ ...options
1737
+ });
1738
+ };
1739
+ getMorphTableName = (collectionName, attributeName, options) => {
1740
+ return this.getName([_.snakeCase(collectionName), _.snakeCase(attributeName)], {
1741
+ suffix: "morphs",
1742
+ ...options
1743
+ });
1744
+ };
1745
+ /**
1746
+ * COLUMNS
1747
+ */
1748
+ getColumnName = (attributeName, options) => {
1749
+ return this.getName(attributeName, options);
1750
+ };
1751
+ getJoinColumnAttributeIdName = (attributeName, options) => {
1752
+ return this.getName(attributeName, { suffix: "id", ...options });
1753
+ };
1754
+ getInverseJoinColumnAttributeIdName = (attributeName, options) => {
1755
+ return this.getName(_.snakeCase(attributeName), { suffix: "id", prefix: "inv", ...options });
1756
+ };
1757
+ getOrderColumnName = (singularName, options) => {
1758
+ return this.getName(singularName, { suffix: "order", ...options });
1759
+ };
1760
+ getInverseOrderColumnName = (singularName, options) => {
1761
+ return this.getName(singularName, {
1762
+ suffix: "order",
1763
+ prefix: "inv",
1764
+ ...options
1765
+ });
1766
+ };
1767
+ /**
1768
+ * Morph Join Tables
1769
+ */
1770
+ getMorphColumnJoinTableIdName = (singularName, options) => {
1771
+ return this.getName(_.snakeCase(singularName), { suffix: "id", ...options });
1772
+ };
1773
+ getMorphColumnAttributeIdName = (attributeName, options) => {
1774
+ return this.getName(_.snakeCase(attributeName), { suffix: "id", ...options });
1775
+ };
1776
+ getMorphColumnTypeName = (attributeName, options) => {
1777
+ return this.getName(_.snakeCase(attributeName), { suffix: "type", ...options });
1778
+ };
1779
+ /**
1780
+ * INDEXES
1781
+ * Note that these methods are generally used to reference full table names + attribute(s), which
1782
+ * may already be shortened strings rather than individual parts.
1783
+ * That is fine and expected to compress the previously incompressible parts of those strings,
1784
+ * because in these cases the relevant information is the table name and we can't really do
1785
+ * any better; shortening the individual parts again might make it even more confusing.
1786
+ *
1787
+ * So for example, the fk for the table `mytable_myattr4567d_localizations` will become
1788
+ * mytable_myattr4567d_loc63bf2_fk
1789
+ */
1790
+ // base index types
1791
+ getIndexName = (names, options) => {
1792
+ return this.getName(names, { suffix: "index", ...options });
1793
+ };
1794
+ getFkIndexName = (names, options) => {
1795
+ return this.getName(names, { suffix: "fk", ...options });
1796
+ };
1797
+ getUniqueIndexName = (names, options) => {
1798
+ return this.getName(names, { suffix: "unique", ...options });
1799
+ };
1800
+ getPrimaryIndexName = (names, options) => {
1801
+ return this.getName(names, { suffix: "primary", ...options });
1802
+ };
1803
+ // custom index types
1804
+ getInverseFkIndexName = (names, options) => {
1805
+ return this.getName(names, { suffix: "inv_fk", ...options });
1806
+ };
1807
+ getOrderFkIndexName = (names, options) => {
1808
+ return this.getName(names, { suffix: "order_fk", ...options });
1809
+ };
1810
+ getOrderInverseFkIndexName = (names, options) => {
1811
+ return this.getName(names, { suffix: "order_inv_fk", ...options });
1812
+ };
1813
+ getIdColumnIndexName = (names, options) => {
1814
+ return this.getName(names, { suffix: "id_column_index", ...options });
1815
+ };
1816
+ getOrderIndexName = (names, options) => {
1817
+ return this.getName(names, { suffix: "order_index", ...options });
1818
+ };
1819
+ /**
1820
+ * Generates a string with a max length, appending a hash at the end if necessary to keep it unique
1821
+ *
1822
+ * @example
1823
+ * // if we have strings such as "longstring1" and "longstring2" with a max length of 9,
1824
+ * // we don't want to end up with "longstrin" and "longstrin"
1825
+ * // we want something such as "longs0b23" and "longs953f"
1826
+ * const token1 = generateToken("longstring1", 9); // "longs0b23"
1827
+ * const token2 = generateToken("longstring2", 9); // "longs953f"
1828
+ *
1829
+ * @param name - The base name
1830
+ * @param len - The desired length of the token.
1831
+ * @returns The generated token with hash.
1832
+ * @throws Error if the length is not a positive integer, or if the length is too short for the token.
1833
+ * @internal
1834
+ */
1835
+ getShortenedName = (name, len) => {
1836
+ if (!_.isInteger(len) || len <= 0) {
1837
+ throw new Error(`tokenWithHash length must be a positive integer, received ${len}`);
1743
1838
  }
1744
- return token.name;
1745
- }).join(IDENTIFIER_SEPARATOR);
1746
- if (shortenedName.length > maxLength) {
1747
- throw new Error(
1748
- `name shortening failed to generate a name of the correct maxLength; name ${shortenedName}`
1839
+ if (name.length <= len) {
1840
+ return name;
1841
+ }
1842
+ if (len < this.MIN_TOKEN_LENGTH + this.HASH_LENGTH) {
1843
+ throw new Error(
1844
+ `length for part of identifier too short, minimum is hash length (${this.HASH_LENGTH}) plus min token length (${this.MIN_TOKEN_LENGTH}), received ${len} for token ${name}`
1845
+ );
1846
+ }
1847
+ const availableLength = len - this.HASH_LENGTH - this.HASH_SEPARATOR.length;
1848
+ if (availableLength < this.MIN_TOKEN_LENGTH) {
1849
+ throw new Error(
1850
+ `length for part of identifier minimum is less than min token length (${this.MIN_TOKEN_LENGTH}), received ${len} for token ${name}`
1851
+ );
1852
+ }
1853
+ return `${name.substring(0, availableLength)}${this.HASH_SEPARATOR}${createHash(
1854
+ name,
1855
+ this.HASH_LENGTH
1856
+ )}`;
1857
+ };
1858
+ /**
1859
+ * Constructs a name from an array of name tokens within a specified maximum length. It ensures the final name does not exceed
1860
+ * this limit by selectively compressing tokens marked as compressible. If the name exceeds the maximum length and cannot be
1861
+ * compressed sufficiently, an error is thrown. This function supports dynamic adjustment of token lengths to fit within the
1862
+ * maxLength constraint (that is, it will always make use of all available space), while also ensuring the preservation of
1863
+ * incompressible tokens.
1864
+ * @internal
1865
+ */
1866
+ getNameFromTokens = (nameTokens) => {
1867
+ const { maxLength } = this.options;
1868
+ if (!_.isInteger(maxLength) || maxLength < 0) {
1869
+ throw new Error("maxLength must be a positive integer or 0 (for unlimited length)");
1870
+ }
1871
+ const unshortenedName = nameTokens.map((token) => {
1872
+ return token.name;
1873
+ }).join(this.IDENTIFIER_SEPARATOR);
1874
+ if (maxLength === 0) {
1875
+ this.setUnshortenedName(unshortenedName, unshortenedName);
1876
+ return unshortenedName;
1877
+ }
1878
+ const fullLengthName = nameTokens.map((token) => {
1879
+ if (token.compressible) {
1880
+ return token.name;
1881
+ }
1882
+ return token.shortName ?? token.name;
1883
+ }).join(this.IDENTIFIER_SEPARATOR);
1884
+ if (fullLengthName.length <= maxLength) {
1885
+ this.setUnshortenedName(fullLengthName, unshortenedName);
1886
+ return fullLengthName;
1887
+ }
1888
+ const [compressible, incompressible] = _.partition(
1889
+ (token) => token.compressible,
1890
+ nameTokens
1749
1891
  );
1750
- }
1751
- return shortenedName;
1892
+ const totalIncompressibleLength = _.sumBy(
1893
+ (token) => token.compressible === false && token.shortName !== void 0 ? token.shortName.length : token.name.length
1894
+ )(incompressible);
1895
+ const totalSeparatorsLength = nameTokens.length * this.IDENTIFIER_SEPARATOR.length - 1;
1896
+ const available = maxLength - totalIncompressibleLength - totalSeparatorsLength;
1897
+ const availablePerToken = Math.floor(available / compressible.length);
1898
+ if (totalIncompressibleLength + totalSeparatorsLength > maxLength || availablePerToken < this.MIN_TOKEN_LENGTH) {
1899
+ throw new Error("Maximum length is too small to accommodate all tokens");
1900
+ }
1901
+ let surplus = available % compressible.length;
1902
+ const minHashedLength = this.HASH_LENGTH + this.HASH_SEPARATOR.length + this.MIN_TOKEN_LENGTH;
1903
+ const totalLength = nameTokens.reduce(
1904
+ (total, token) => {
1905
+ if (token.compressible) {
1906
+ if (token.name.length < availablePerToken) {
1907
+ return total + token.name.length;
1908
+ }
1909
+ return total + minHashedLength;
1910
+ }
1911
+ const tokenName = token.shortName ?? token.name;
1912
+ return total + tokenName.length;
1913
+ },
1914
+ nameTokens.length * this.IDENTIFIER_SEPARATOR.length - 1
1915
+ );
1916
+ if (maxLength < totalLength) {
1917
+ throw new Error("Maximum length is too small to accommodate all tokens");
1918
+ }
1919
+ let deficits = [];
1920
+ compressible.forEach((token) => {
1921
+ const actualLength = token.name.length;
1922
+ if (actualLength < availablePerToken) {
1923
+ surplus += availablePerToken - actualLength;
1924
+ token.allocatedLength = actualLength;
1925
+ } else {
1926
+ token.allocatedLength = availablePerToken;
1927
+ deficits.push(token);
1928
+ }
1929
+ });
1930
+ function filterAndIncreaseLength(token) {
1931
+ if (token.allocatedLength < token.name.length && surplus > 0) {
1932
+ token.allocatedLength += 1;
1933
+ surplus -= 1;
1934
+ return token.allocatedLength < token.name.length;
1935
+ }
1936
+ return false;
1937
+ }
1938
+ let previousSurplus = surplus + 1;
1939
+ while (surplus > 0 && deficits.length > 0) {
1940
+ deficits = deficits.filter((token) => filterAndIncreaseLength(token));
1941
+ if (surplus === previousSurplus) {
1942
+ break;
1943
+ }
1944
+ previousSurplus = surplus;
1945
+ }
1946
+ const shortenedName = nameTokens.map((token) => {
1947
+ if (token.compressible && "allocatedLength" in token && token.allocatedLength !== void 0) {
1948
+ return this.getShortenedName(token.name, token.allocatedLength);
1949
+ }
1950
+ if (token.compressible === false && token.shortName) {
1951
+ return token.shortName;
1952
+ }
1953
+ return token.name;
1954
+ }).join(this.IDENTIFIER_SEPARATOR);
1955
+ if (shortenedName.length > maxLength) {
1956
+ throw new Error(
1957
+ `name shortening failed to generate a name of the correct maxLength; name ${shortenedName}`
1958
+ );
1959
+ }
1960
+ this.setUnshortenedName(shortenedName, unshortenedName);
1961
+ return shortenedName;
1962
+ };
1963
+ // We need to be able to find the full-length name for any shortened name, primarily for migration purposes
1964
+ // Therefore we store every name that passes through so we can retrieve the original later
1965
+ nameMap = /* @__PURE__ */ new Map();
1966
+ getUnshortenedName = (shortName) => {
1967
+ return this.nameMap.get(this.serializeKey(shortName)) ?? shortName;
1968
+ };
1969
+ setUnshortenedName = (shortName, fullName) => {
1970
+ if (this.nameMap.get(this.serializeKey(shortName)) && shortName === fullName) {
1971
+ return;
1972
+ }
1973
+ this.nameMap.set(this.serializeKey(shortName), fullName);
1974
+ };
1975
+ serializeKey = (shortName) => {
1976
+ return `${shortName}.${this.options.maxLength}`;
1977
+ };
1752
1978
  }
1753
- const ID_COLUMN = "id";
1754
- const ORDER_COLUMN = "order";
1755
- const FIELD_COLUMN = "field";
1756
- const getName = (names, options) => {
1757
- const tokens = ___default.default.castArray(names).map((name) => {
1758
- return {
1759
- name,
1760
- compressible: true
1761
- };
1762
- });
1763
- if (options?.suffix) {
1764
- tokens.push({ name: options.suffix, compressible: false });
1765
- }
1766
- if (options?.prefix) {
1767
- tokens.unshift({ name: options.prefix, compressible: false });
1768
- }
1769
- const maxLength = options?.maxLength ?? MAX_DB_IDENTIFIER_LENGTH;
1770
- return getNameFromTokens(tokens, maxLength);
1771
- };
1772
- const getTableName = (name, options) => {
1773
- return getName(name, options);
1774
- };
1775
- const getJoinTableName = (collectionName, attributeName, options) => {
1776
- return getName([collectionName, attributeName], { suffix: "links", ...options });
1777
- };
1778
- const getMorphTableName = (collectionName, attributeName, options) => {
1779
- return getName([collectionName, attributeName], { suffix: "morphs", ...options });
1780
- };
1781
- const getColumnName = (attributeName, options) => {
1782
- return getName(attributeName, options);
1783
- };
1784
- const getJoinColumnAttributeIdName = (attributeName, options) => {
1785
- return getName(attributeName, { suffix: "id", ...options });
1786
- };
1787
- const getInverseJoinColumnAttributeIdName = (attributeName, options) => {
1788
- return getName(attributeName, { suffix: "id", prefix: "inv", ...options });
1789
- };
1790
- const getOrderColumnName = (singularName, options) => {
1791
- return getName(singularName, { suffix: "order", ...options });
1792
- };
1793
- const getInverseOrderColumnName = (singularName, options) => {
1794
- return getName(singularName, { suffix: "order", prefix: "inv", ...options });
1795
- };
1796
- const getMorphColumnJoinTableIdName = (singularName, options) => {
1797
- return getName(singularName, { suffix: "id", ...options });
1798
- };
1799
- const getMorphColumnAttributeIdName = (attributeName, options) => {
1800
- return getName(attributeName, { suffix: "id", ...options });
1801
- };
1802
- const getMorphColumnTypeName = (attributeName, options) => {
1803
- return getName(attributeName, { suffix: "type", ...options });
1804
- };
1805
- const getIndexName = (names, options) => {
1806
- return getName(names, { suffix: "index", ...options });
1807
- };
1808
- const getFkIndexName = (names, options) => {
1809
- return getName(names, { suffix: "fk", ...options });
1810
- };
1811
- const getInverseFkIndexName = (names, options) => {
1812
- return getName(names, { suffix: "inv_fk", ...options });
1813
- };
1814
- const getOrderFkIndexName = (names, options) => {
1815
- return getName(names, { suffix: "order_fk", ...options });
1816
- };
1817
- const getOrderInverseFkIndexName = (names, options) => {
1818
- return getName(names, { suffix: "order_inv_fk", ...options });
1819
- };
1820
- const getUniqueIndexName = (names, options) => {
1821
- return getName(names, { suffix: "unique", ...options });
1822
- };
1823
- const getPrimaryIndexName = (names) => {
1824
- return getName(names, { suffix: "primary" });
1825
- };
1826
- const identifiers = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
1827
- __proto__: null,
1828
- FIELD_COLUMN,
1829
- ID_COLUMN,
1830
- ORDER_COLUMN,
1831
- getColumnName,
1832
- getFkIndexName,
1833
- getIndexName,
1834
- getInverseFkIndexName,
1835
- getInverseJoinColumnAttributeIdName,
1836
- getInverseOrderColumnName,
1837
- getJoinColumnAttributeIdName,
1838
- getJoinTableName,
1839
- getMorphColumnAttributeIdName,
1840
- getMorphColumnJoinTableIdName,
1841
- getMorphColumnTypeName,
1842
- getMorphTableName,
1843
- getName,
1844
- getOrderColumnName,
1845
- getOrderFkIndexName,
1846
- getOrderInverseFkIndexName,
1847
- getPrimaryIndexName,
1848
- getTableName,
1849
- getUniqueIndexName
1850
- }, Symbol.toStringTag, { value: "Module" }));
1979
+ const identifiers = new Identifiers({ maxLength: IDENTIFIER_MAX_LENGTH });
1851
1980
  const createColumn = (name, attribute) => {
1852
1981
  const { type, args = [], ...opts } = getColumnType(attribute);
1853
1982
  return {
1854
- name,
1983
+ name: identifiers.getName(name),
1855
1984
  type,
1856
1985
  args,
1857
1986
  defaultTo: null,
@@ -1873,8 +2002,8 @@ const createTable = (meta) => {
1873
2002
  if (attribute.type === "relation") {
1874
2003
  if ("morphColumn" in attribute && attribute.morphColumn && attribute.owner) {
1875
2004
  const { idColumn, typeColumn } = attribute.morphColumn;
1876
- const idColumnName = getName(idColumn.name);
1877
- const typeColumnName = getName(typeColumn.name);
2005
+ const idColumnName = identifiers.getName(idColumn.name);
2006
+ const typeColumnName = identifiers.getName(typeColumn.name);
1878
2007
  table.columns.push(
1879
2008
  createColumn(idColumnName, {
1880
2009
  type: "integer",
@@ -1891,7 +2020,7 @@ const createTable = (meta) => {
1891
2020
  referencedTable,
1892
2021
  columnType = "integer"
1893
2022
  } = attribute.joinColumn;
1894
- const columnName = getName(columnNameFull);
2023
+ const columnName = identifiers.getName(columnNameFull);
1895
2024
  const column = createColumn(columnName, {
1896
2025
  // TODO: find the column type automatically, or allow passing all the column params
1897
2026
  type: columnType,
@@ -1900,7 +2029,7 @@ const createTable = (meta) => {
1900
2029
  }
1901
2030
  });
1902
2031
  table.columns.push(column);
1903
- const fkName = getFkIndexName([table.name, columnName]);
2032
+ const fkName = identifiers.getFkIndexName([table.name, columnName]);
1904
2033
  table.foreignKeys.push({
1905
2034
  name: fkName,
1906
2035
  columns: [column.name],
@@ -1915,19 +2044,19 @@ const createTable = (meta) => {
1915
2044
  });
1916
2045
  }
1917
2046
  } else if (isScalarAttribute(attribute)) {
1918
- const columnName = getName(attribute.columnName || key);
2047
+ const columnName = identifiers.getName(attribute.columnName || key);
1919
2048
  const column = createColumn(columnName, attribute);
1920
2049
  if (column.unique) {
1921
2050
  table.indexes.push({
1922
2051
  type: "unique",
1923
- name: getUniqueIndexName([table.name, column.name]),
2052
+ name: identifiers.getUniqueIndexName([table.name, column.name]),
1924
2053
  columns: [columnName]
1925
2054
  });
1926
2055
  }
1927
2056
  if (column.primary) {
1928
2057
  table.indexes.push({
1929
2058
  type: "primary",
1930
- name: getPrimaryIndexName([table.name, column.name]),
2059
+ name: identifiers.getPrimaryIndexName([table.name, column.name]),
1931
2060
  columns: [columnName]
1932
2061
  });
1933
2062
  }
@@ -2027,12 +2156,13 @@ const metadataToSchema = (metadata) => {
2027
2156
  });
2028
2157
  return schema;
2029
2158
  };
2030
- const debug = createDebug__default.default("strapi::database");
2159
+ const debug$1 = createDebug__default.default("strapi::database");
2031
2160
  const createSchemaProvider = (db) => {
2032
2161
  const state = {};
2033
2162
  return {
2034
2163
  get schema() {
2035
2164
  if (!state.schema) {
2165
+ debug$1("Converting metadata to database schema");
2036
2166
  state.schema = metadataToSchema(db.metadata);
2037
2167
  }
2038
2168
  return state.schema;
@@ -2044,7 +2174,7 @@ const createSchemaProvider = (db) => {
2044
2174
  * Drops the database schema
2045
2175
  */
2046
2176
  async drop() {
2047
- debug("Dropping database schema");
2177
+ debug$1("Dropping database schema");
2048
2178
  const DBSchema = await db.dialect.schemaInspector.getSchema();
2049
2179
  await this.builder.dropSchema(DBSchema);
2050
2180
  },
@@ -2052,19 +2182,19 @@ const createSchemaProvider = (db) => {
2052
2182
  * Creates the database schema
2053
2183
  */
2054
2184
  async create() {
2055
- debug("Created database schema");
2185
+ debug$1("Created database schema");
2056
2186
  await this.builder.createSchema(this.schema);
2057
2187
  },
2058
2188
  /**
2059
2189
  * Resets the database schema
2060
2190
  */
2061
2191
  async reset() {
2062
- debug("Resetting database schema");
2192
+ debug$1("Resetting database schema");
2063
2193
  await this.drop();
2064
2194
  await this.create();
2065
2195
  },
2066
2196
  async syncSchema() {
2067
- debug("Synchronizing database schema");
2197
+ debug$1("Synchronizing database schema");
2068
2198
  const DBSchema = await db.dialect.schemaInspector.getSchema();
2069
2199
  const { status, diff } = await this.schemaDiff.diff(DBSchema, this.schema);
2070
2200
  if (status === "CHANGED") {
@@ -2077,28 +2207,28 @@ const createSchemaProvider = (db) => {
2077
2207
  // TODO: Allow keeping extra indexes / extra tables / extra columns (globally or on a per table basis)
2078
2208
  async sync() {
2079
2209
  if (await db.migrations.shouldRun()) {
2080
- debug("Found migrations to run");
2210
+ debug$1("Found migrations to run");
2081
2211
  await db.migrations.up();
2082
2212
  return this.syncSchema();
2083
2213
  }
2084
2214
  const oldSchema = await this.schemaStorage.read();
2085
2215
  if (!oldSchema) {
2086
- debug("Schema not persisted yet");
2216
+ debug$1("Schema not persisted yet");
2087
2217
  return this.syncSchema();
2088
2218
  }
2089
2219
  const { hash: oldHash } = oldSchema;
2090
2220
  const hash = await this.schemaStorage.hashSchema(this.schema);
2091
2221
  if (oldHash !== hash) {
2092
- debug("Schema changed");
2222
+ debug$1("Schema changed");
2093
2223
  return this.syncSchema();
2094
2224
  }
2095
- debug("Schema unchanged");
2225
+ debug$1("Schema unchanged");
2096
2226
  }
2097
2227
  };
2098
2228
  };
2099
- const ID = ID_COLUMN;
2100
- const ORDER = ORDER_COLUMN;
2101
- const FIELD = FIELD_COLUMN;
2229
+ const ID = identifiers.ID_COLUMN;
2230
+ const ORDER = identifiers.ORDER_COLUMN;
2231
+ const FIELD = identifiers.FIELD_COLUMN;
2102
2232
  const hasInversedBy = (attr) => "inversedBy" in attr;
2103
2233
  const hasMappedBy = (attr) => "mappedBy" in attr;
2104
2234
  const isOneToAny = (attribute) => ["oneToOne", "oneToMany"].includes(attribute.relation);
@@ -2119,7 +2249,7 @@ const createOneToOne = (attributeName, attribute, meta, metadata) => {
2119
2249
  meta
2120
2250
  });
2121
2251
  } else {
2122
- createJoinColum(metadata, {
2252
+ createJoinColumn(metadata, {
2123
2253
  attribute,
2124
2254
  attributeName,
2125
2255
  meta
@@ -2149,7 +2279,7 @@ const createManyToOne = (attributeName, attribute, meta, metadata) => {
2149
2279
  meta
2150
2280
  });
2151
2281
  } else {
2152
- createJoinColum(metadata, {
2282
+ createJoinColumn(metadata, {
2153
2283
  attribute,
2154
2284
  attributeName,
2155
2285
  meta
@@ -2166,8 +2296,8 @@ const createManyToMany = (attributeName, attribute, meta, metadata) => {
2166
2296
  }
2167
2297
  };
2168
2298
  const createMorphToOne = (attributeName, attribute) => {
2169
- const idColumnName = getJoinColumnAttributeIdName("target");
2170
- const typeColumnName = getMorphColumnTypeName("target");
2299
+ const idColumnName = identifiers.getJoinColumnAttributeIdName("target");
2300
+ const typeColumnName = identifiers.getMorphColumnTypeName("target");
2171
2301
  if ("morphColumn" in attribute && attribute.morphColumn) {
2172
2302
  return;
2173
2303
  }
@@ -2189,11 +2319,11 @@ const createMorphToMany = (attributeName, attribute, meta, metadata) => {
2189
2319
  if ("joinTable" in attribute && attribute.joinTable) {
2190
2320
  return;
2191
2321
  }
2192
- const joinTableName = getMorphTableName(meta.tableName, attributeName);
2193
- const joinColumnName = getMorphColumnJoinTableIdName(meta.singularName);
2194
- const idColumnName = getMorphColumnAttributeIdName(attributeName);
2195
- const typeColumnName = getMorphColumnTypeName(attributeName);
2196
- const fkIndexName = getFkIndexName(joinTableName);
2322
+ const joinTableName = identifiers.getMorphTableName(meta.tableName, attributeName);
2323
+ const joinColumnName = identifiers.getMorphColumnJoinTableIdName(_.snakeCase(meta.singularName));
2324
+ const idColumnName = identifiers.getMorphColumnAttributeIdName(attributeName);
2325
+ const typeColumnName = identifiers.getMorphColumnTypeName(attributeName);
2326
+ const fkIndexName = identifiers.getFkIndexName(joinTableName);
2197
2327
  metadata.add({
2198
2328
  singularName: joinTableName,
2199
2329
  uid: joinTableName,
@@ -2206,7 +2336,9 @@ const createMorphToMany = (attributeName, attribute, meta, metadata) => {
2206
2336
  type: "integer",
2207
2337
  column: {
2208
2338
  unsigned: true
2209
- }
2339
+ },
2340
+ // This must be set explicitly so that it is used instead of shortening the attribute name, which is already shortened
2341
+ columnName: joinColumnName
2210
2342
  },
2211
2343
  [idColumnName]: {
2212
2344
  type: "integer",
@@ -2233,11 +2365,11 @@ const createMorphToMany = (attributeName, attribute, meta, metadata) => {
2233
2365
  columns: [joinColumnName]
2234
2366
  },
2235
2367
  {
2236
- name: `${joinTableName}_order_index`,
2368
+ name: identifiers.getOrderIndexName(joinTableName),
2237
2369
  columns: [ORDER]
2238
2370
  },
2239
2371
  {
2240
- name: `${joinTableName}_id_column_index`,
2372
+ name: identifiers.getIdColumnIndexName(joinTableName),
2241
2373
  columns: [idColumnName]
2242
2374
  }
2243
2375
  ],
@@ -2246,7 +2378,7 @@ const createMorphToMany = (attributeName, attribute, meta, metadata) => {
2246
2378
  name: fkIndexName,
2247
2379
  columns: [joinColumnName],
2248
2380
  referencedColumns: [ID],
2249
- referencedTable: getTableName(meta.tableName),
2381
+ referencedTable: meta.tableName,
2250
2382
  onDelete: "CASCADE"
2251
2383
  }
2252
2384
  ],
@@ -2293,12 +2425,12 @@ const createMorphMany = (attributeName, attribute, meta, metadata) => {
2293
2425
  throw new Error(`Morph target attribute not found. Looking for ${attribute.morphBy}`);
2294
2426
  }
2295
2427
  };
2296
- const createJoinColum = (metadata, { attribute, attributeName }) => {
2428
+ const createJoinColumn = (metadata, { attribute, attributeName }) => {
2297
2429
  const targetMeta = metadata.get(attribute.target);
2298
2430
  if (!targetMeta) {
2299
2431
  throw new Error(`Unknown target ${attribute.target}`);
2300
2432
  }
2301
- const joinColumnName = ___default.default.snakeCase(`${attributeName}_id`);
2433
+ const joinColumnName = identifiers.getJoinColumnAttributeIdName(_.snakeCase(attributeName));
2302
2434
  const joinColumn = {
2303
2435
  name: joinColumnName,
2304
2436
  referencedColumn: ID,
@@ -2313,7 +2445,7 @@ const createJoinColum = (metadata, { attribute, attributeName }) => {
2313
2445
  Object.assign(inverseAttribute, {
2314
2446
  joinColumn: {
2315
2447
  name: joinColumn.referencedColumn,
2316
- referencedColumn: joinColumn.name
2448
+ referencedColumn: joinColumnName
2317
2449
  }
2318
2450
  });
2319
2451
  }
@@ -2326,21 +2458,26 @@ const createJoinTable = (metadata, { attributeName, attribute, meta }) => {
2326
2458
  if ("joinTable" in attribute && attribute.joinTable) {
2327
2459
  return;
2328
2460
  }
2329
- const joinTableName = getJoinTableName(meta.tableName, attributeName);
2330
- const joinColumnName = getJoinColumnAttributeIdName(meta.singularName);
2331
- let inverseJoinColumnName = getJoinColumnAttributeIdName(targetMeta.singularName);
2461
+ const joinTableName = identifiers.getJoinTableName(
2462
+ _.snakeCase(meta.tableName),
2463
+ _.snakeCase(attributeName)
2464
+ );
2465
+ const joinColumnName = identifiers.getJoinColumnAttributeIdName(_.snakeCase(meta.singularName));
2466
+ let inverseJoinColumnName = identifiers.getJoinColumnAttributeIdName(
2467
+ _.snakeCase(targetMeta.singularName)
2468
+ );
2332
2469
  if (joinColumnName === inverseJoinColumnName) {
2333
- inverseJoinColumnName = getInverseJoinColumnAttributeIdName(
2334
- targetMeta.singularName
2470
+ inverseJoinColumnName = identifiers.getInverseJoinColumnAttributeIdName(
2471
+ _.snakeCase(targetMeta.singularName)
2335
2472
  );
2336
2473
  }
2337
- const orderColumnName = getOrderColumnName(targetMeta.singularName);
2338
- let inverseOrderColumnName = getOrderColumnName(meta.singularName);
2474
+ const orderColumnName = identifiers.getOrderColumnName(_.snakeCase(targetMeta.singularName));
2475
+ let inverseOrderColumnName = identifiers.getOrderColumnName(_.snakeCase(meta.singularName));
2339
2476
  if (attribute.relation === "manyToMany" && orderColumnName === inverseOrderColumnName) {
2340
- inverseOrderColumnName = getInverseOrderColumnName(meta.singularName);
2477
+ inverseOrderColumnName = identifiers.getInverseOrderColumnName(_.snakeCase(meta.singularName));
2341
2478
  }
2342
- const fkIndexName = getFkIndexName(joinTableName);
2343
- const invFkIndexName = getInverseFkIndexName(joinTableName);
2479
+ const fkIndexName = identifiers.getFkIndexName(joinTableName);
2480
+ const invFkIndexName = identifiers.getInverseFkIndexName(joinTableName);
2344
2481
  const metadataSchema = {
2345
2482
  singularName: joinTableName,
2346
2483
  uid: joinTableName,
@@ -2353,13 +2490,17 @@ const createJoinTable = (metadata, { attributeName, attribute, meta }) => {
2353
2490
  type: "integer",
2354
2491
  column: {
2355
2492
  unsigned: true
2356
- }
2493
+ },
2494
+ // This must be set explicitly so that it is used instead of shortening the attribute name, which is already shortened
2495
+ columnName: joinColumnName
2357
2496
  },
2358
2497
  [inverseJoinColumnName]: {
2359
2498
  type: "integer",
2360
2499
  column: {
2361
2500
  unsigned: true
2362
- }
2501
+ },
2502
+ // This must be set explicitly so that it is used instead of shortening the attribute name, which is already shortened
2503
+ columnName: inverseJoinColumnName
2363
2504
  }
2364
2505
  // TODO: add extra pivot attributes -> user should use an intermediate entity
2365
2506
  },
@@ -2373,7 +2514,7 @@ const createJoinTable = (metadata, { attributeName, attribute, meta }) => {
2373
2514
  columns: [inverseJoinColumnName]
2374
2515
  },
2375
2516
  {
2376
- name: getUniqueIndexName(joinTableName),
2517
+ name: identifiers.getUniqueIndexName(joinTableName),
2377
2518
  columns: [joinColumnName, inverseJoinColumnName],
2378
2519
  type: "unique"
2379
2520
  }
@@ -2384,7 +2525,6 @@ const createJoinTable = (metadata, { attributeName, attribute, meta }) => {
2384
2525
  columns: [joinColumnName],
2385
2526
  referencedColumns: [ID],
2386
2527
  referencedTable: meta.tableName,
2387
- // TODO: does this need to be wrapped or do we trust meta.tableName to be the right shortened version?
2388
2528
  onDelete: "CASCADE"
2389
2529
  },
2390
2530
  {
@@ -2392,7 +2532,6 @@ const createJoinTable = (metadata, { attributeName, attribute, meta }) => {
2392
2532
  columns: [inverseJoinColumnName],
2393
2533
  referencedColumns: [ID],
2394
2534
  referencedTable: targetMeta.tableName,
2395
- // TODO: does this need to be wrapped or do we trust meta.tableName to be the right shortened version?
2396
2535
  onDelete: "CASCADE"
2397
2536
  }
2398
2537
  ],
@@ -2422,8 +2561,7 @@ const createJoinTable = (metadata, { attributeName, attribute, meta }) => {
2422
2561
  }
2423
2562
  };
2424
2563
  metadataSchema.indexes.push({
2425
- name: getOrderFkIndexName(joinTableName),
2426
- // TODO: should we send joinTableName as parts?
2564
+ name: identifiers.getOrderFkIndexName(joinTableName),
2427
2565
  columns: [orderColumnName]
2428
2566
  });
2429
2567
  joinTable.orderColumnName = orderColumnName;
@@ -2438,7 +2576,7 @@ const createJoinTable = (metadata, { attributeName, attribute, meta }) => {
2438
2576
  }
2439
2577
  };
2440
2578
  metadataSchema.indexes.push({
2441
- name: getOrderInverseFkIndexName(joinTableName),
2579
+ name: identifiers.getOrderInverseFkIndexName(joinTableName),
2442
2580
  columns: [inverseOrderColumnName]
2443
2581
  });
2444
2582
  joinTable.inverseOrderColumnName = inverseOrderColumnName;
@@ -2496,6 +2634,12 @@ const createRelation = (attributeName, attribute, meta, metadata) => {
2496
2634
  }
2497
2635
  };
2498
2636
  class Metadata extends Map {
2637
+ // TODO: we expose the global identifiers in this way so that in the future we can instantiate our own
2638
+ // However, it should NOT be done until all the methods used by metadata can be part of this metadata object
2639
+ // and access this one; currently they all access the global identifiers directly.
2640
+ get identifiers() {
2641
+ return identifiers;
2642
+ }
2499
2643
  get(key) {
2500
2644
  if (!super.has(key)) {
2501
2645
  throw new Error(`Metadata for "${key}" not found`);
@@ -2519,10 +2663,12 @@ class Metadata extends Map {
2519
2663
  seenTables.set(meta.tableName, true);
2520
2664
  }
2521
2665
  }
2522
- loadModels(models = []) {
2523
- for (const model of ___default.default.cloneDeep(models)) {
2666
+ loadModels(models) {
2667
+ for (const model of _.cloneDeep(models ?? [])) {
2668
+ const tableName = identifiers.getTableName(model.tableName);
2524
2669
  this.add({
2525
2670
  ...model,
2671
+ tableName,
2526
2672
  attributes: {
2527
2673
  ...model.attributes
2528
2674
  },
@@ -2563,10 +2709,13 @@ class Metadata extends Map {
2563
2709
  }
2564
2710
  }
2565
2711
  const createAttribute = (attributeName, attribute) => {
2566
- const columnName = getColumnName(attributeName);
2712
+ if ("columnName" in attribute && attribute.columnName) {
2713
+ return;
2714
+ }
2715
+ const columnName = identifiers.getColumnName(_.snakeCase(attributeName));
2567
2716
  Object.assign(attribute, { columnName });
2568
2717
  };
2569
- const createMetadata = (models = []) => {
2718
+ const createMetadata = (models) => {
2570
2719
  const metadata = new Metadata();
2571
2720
  if (models.length) {
2572
2721
  metadata.loadModels(models);
@@ -3061,10 +3210,13 @@ const XtoOne = async (input, ctx) => {
3061
3210
  rootTable: qb2.alias,
3062
3211
  on: joinTable.on
3063
3212
  }).select([joinColAlias, qb2.raw("count(*) AS count")]).where({ [joinColAlias]: referencedValues }).groupBy(joinColAlias).execute({ mapResults: false });
3064
- const map2 = rows2.reduce((map3, row) => {
3065
- map3[row[joinColumnName]] = { count: Number(row.count) };
3066
- return map3;
3067
- }, {});
3213
+ const map2 = rows2.reduce(
3214
+ (map3, row) => {
3215
+ map3[row[joinColumnName]] = { count: Number(row.count) };
3216
+ return map3;
3217
+ },
3218
+ {}
3219
+ );
3068
3220
  results.forEach((result) => {
3069
3221
  result[attributeName] = map2[result[referencedColumnName]] || { count: 0 };
3070
3222
  });
@@ -3137,10 +3289,13 @@ const oneToMany = async (input, ctx) => {
3137
3289
  rootTable: qb2.alias,
3138
3290
  on: joinTable.on
3139
3291
  }).select([joinColAlias, qb2.raw("count(*) AS count")]).where({ [joinColAlias]: referencedValues }).groupBy(joinColAlias).execute({ mapResults: false });
3140
- const map2 = rows2.reduce((map3, row) => {
3141
- map3[row[joinColumnName]] = { count: Number(row.count) };
3142
- return map3;
3143
- }, {});
3292
+ const map2 = rows2.reduce(
3293
+ (map3, row) => {
3294
+ map3[row[joinColumnName]] = { count: Number(row.count) };
3295
+ return map3;
3296
+ },
3297
+ {}
3298
+ );
3144
3299
  results.forEach((result) => {
3145
3300
  result[attributeName] = map2[result[referencedColumnName]] || { count: 0 };
3146
3301
  });
@@ -3194,10 +3349,13 @@ const manyToMany = async (input, ctx) => {
3194
3349
  rootTable: populateQb.alias,
3195
3350
  on: joinTable.on
3196
3351
  }).select([joinColAlias, populateQb.raw("count(*) AS count")]).where({ [joinColAlias]: referencedValues }).groupBy(joinColAlias).execute({ mapResults: false });
3197
- const map2 = rows2.reduce((map3, row) => {
3198
- map3[row[joinColumnName]] = { count: Number(row.count) };
3199
- return map3;
3200
- }, {});
3352
+ const map2 = rows2.reduce(
3353
+ (map3, row) => {
3354
+ map3[row[joinColumnName]] = { count: Number(row.count) };
3355
+ return map3;
3356
+ },
3357
+ {}
3358
+ );
3201
3359
  results.forEach((result) => {
3202
3360
  result[attributeName] = map2[result[referencedColumnName]] || { count: 0 };
3203
3361
  });
@@ -3544,7 +3702,7 @@ const castValue = (value, attribute) => {
3544
3702
  };
3545
3703
  const processSingleAttributeWhere = (attribute, where, operator = "$eq") => {
3546
3704
  if (!isRecord$1(where)) {
3547
- if (utils$1.isOperatorOfType("cast", operator)) {
3705
+ if (utils.isOperatorOfType("cast", operator)) {
3548
3706
  return castValue(where, attribute);
3549
3707
  }
3550
3708
  return where;
@@ -3552,7 +3710,7 @@ const processSingleAttributeWhere = (attribute, where, operator = "$eq") => {
3552
3710
  const filters = {};
3553
3711
  for (const key of Object.keys(where)) {
3554
3712
  const value = where[key];
3555
- if (!utils$1.isOperatorOfType("where", key)) {
3713
+ if (!utils.isOperatorOfType("where", key)) {
3556
3714
  throw new Error(`Undefined attribute level operator ${key}`);
3557
3715
  }
3558
3716
  filters[key] = processAttributeWhere(attribute, value, key);
@@ -3583,7 +3741,7 @@ function processWhere(where, ctx) {
3583
3741
  const filters = {};
3584
3742
  for (const key of Object.keys(where)) {
3585
3743
  const value = where[key];
3586
- if (utils$1.isOperatorOfType("group", key) && Array.isArray(value)) {
3744
+ if (utils.isOperatorOfType("group", key) && Array.isArray(value)) {
3587
3745
  filters[key] = value.map((sub) => processNested(sub, ctx));
3588
3746
  continue;
3589
3747
  }
@@ -3591,7 +3749,7 @@ function processWhere(where, ctx) {
3591
3749
  filters[key] = processNested(value, ctx);
3592
3750
  continue;
3593
3751
  }
3594
- if (utils$1.isOperatorOfType("where", key)) {
3752
+ if (utils.isOperatorOfType("where", key)) {
3595
3753
  throw new Error(
3596
3754
  `Only $and, $or and $not can only be used as root level operators. Found ${key}.`
3597
3755
  );
@@ -3613,7 +3771,7 @@ function processWhere(where, ctx) {
3613
3771
  alias: subAlias,
3614
3772
  uid: attribute.target
3615
3773
  });
3616
- if (!isRecord$1(nestedWhere) || utils$1.isOperatorOfType("where", _.keys(nestedWhere)[0])) {
3774
+ if (!isRecord$1(nestedWhere) || utils.isOperatorOfType("where", _.keys(nestedWhere)[0])) {
3617
3775
  nestedWhere = { [qb.aliasColumn("id", subAlias)]: nestedWhere };
3618
3776
  }
3619
3777
  Object.assign(filters, nestedWhere);
@@ -3630,7 +3788,7 @@ function processWhere(where, ctx) {
3630
3788
  return filters;
3631
3789
  }
3632
3790
  const applyOperator = (qb, column, operator, value) => {
3633
- if (Array.isArray(value) && !utils$1.isOperatorOfType("array", operator)) {
3791
+ if (Array.isArray(value) && !utils.isOperatorOfType("array", operator)) {
3634
3792
  return qb.where((subQB) => {
3635
3793
  value.forEach(
3636
3794
  (subValue) => subQB.orWhere((innerQB) => {
@@ -4708,21 +4866,24 @@ const sortConnectArray = (connectArr, initialArr = [], strictSort = true) => {
4708
4866
  (acc, rel) => ({ ...acc, [rel.id]: true }),
4709
4867
  {}
4710
4868
  );
4711
- const mappedRelations = connectArr.reduce((mapper, relation) => {
4712
- const adjacentRelId = relation.position?.before || relation.position?.after;
4713
- if (!adjacentRelId || !relationInInitialArray[adjacentRelId] && !mapper[adjacentRelId]) {
4714
- needsSorting = true;
4715
- }
4716
- if (mapper[relation.id]) {
4717
- throw new InvalidRelationError(
4718
- `The relation with id ${relation.id} is already connected. You cannot connect the same relation twice.`
4719
- );
4720
- }
4721
- return {
4722
- [relation.id]: { ...relation, computed: false },
4723
- ...mapper
4724
- };
4725
- }, {});
4869
+ const mappedRelations = connectArr.reduce(
4870
+ (mapper, relation) => {
4871
+ const adjacentRelId = relation.position?.before || relation.position?.after;
4872
+ if (!adjacentRelId || !relationInInitialArray[adjacentRelId] && !mapper[adjacentRelId]) {
4873
+ needsSorting = true;
4874
+ }
4875
+ if (mapper[relation.id]) {
4876
+ throw new InvalidRelationError(
4877
+ `The relation with id ${relation.id} is already connected. You cannot connect the same relation twice.`
4878
+ );
4879
+ }
4880
+ return {
4881
+ [relation.id]: { ...relation, computed: false },
4882
+ ...mapper
4883
+ };
4884
+ },
4885
+ {}
4886
+ );
4726
4887
  if (!needsSorting)
4727
4888
  return connectArr;
4728
4889
  const computeRelation = (relation, relationsSeenInBranch) => {
@@ -4830,14 +4991,17 @@ const relationsOrderer = (initArr, idColumn, orderColumn, strict) => {
4830
4991
  * Get a map between the relation id and its order
4831
4992
  */
4832
4993
  getOrderMap() {
4833
- return ___default$1.default(computedRelations).groupBy("order").reduce((acc, relations) => {
4834
- if (relations[0]?.init)
4994
+ return ___default$1.default(computedRelations).groupBy("order").reduce(
4995
+ (acc, relations) => {
4996
+ if (relations[0]?.init)
4997
+ return acc;
4998
+ relations.forEach((relation, idx) => {
4999
+ acc[relation.id] = Math.floor(relation.order) + (idx + 1) / (relations.length + 1);
5000
+ });
4835
5001
  return acc;
4836
- relations.forEach((relation, idx) => {
4837
- acc[relation.id] = Math.floor(relation.order) + (idx + 1) / (relations.length + 1);
4838
- });
4839
- return acc;
4840
- }, {});
5002
+ },
5003
+ {}
5004
+ );
4841
5005
  }
4842
5006
  };
4843
5007
  };
@@ -5591,10 +5755,13 @@ const createEntityManager = (db) => {
5591
5755
  const entry = await this.findOne(uid, {
5592
5756
  select: ["id"],
5593
5757
  where: { id: entity.id },
5594
- populate: fieldsArr.reduce((acc, field) => {
5595
- acc[field] = populate || true;
5596
- return acc;
5597
- }, {})
5758
+ populate: fieldsArr.reduce(
5759
+ (acc, field) => {
5760
+ acc[field] = populate || true;
5761
+ return acc;
5762
+ },
5763
+ {}
5764
+ )
5598
5765
  });
5599
5766
  if (!entry) {
5600
5767
  return null;
@@ -5710,7 +5877,280 @@ const createUserMigrationProvider = (db) => {
5710
5877
  }
5711
5878
  };
5712
5879
  };
5713
- const internalMigrations = [];
5880
+ const QUERIES = {
5881
+ async postgres(knex2, params) {
5882
+ const res = await knex2.raw(
5883
+ `
5884
+ SELECT :tableName:.id as id, string_agg(DISTINCT :inverseJoinColumn:::character varying, ',') as other_ids
5885
+ FROM :tableName:
5886
+ LEFT JOIN :joinTableName: ON :tableName:.id = :joinTableName:.:joinColumn:
5887
+ WHERE document_id IS NULL
5888
+ GROUP BY :tableName:.id, :joinColumn:
5889
+ LIMIT 1;
5890
+ `,
5891
+ params
5892
+ );
5893
+ return res.rows;
5894
+ },
5895
+ async mysql(knex2, params) {
5896
+ const [res] = await knex2.raw(
5897
+ `
5898
+ SELECT :tableName:.id as id, group_concat(DISTINCT :inverseJoinColumn:) as other_ids
5899
+ FROM :tableName:
5900
+ LEFT JOIN :joinTableName: ON :tableName:.id = :joinTableName:.:joinColumn:
5901
+ WHERE document_id IS NULL
5902
+ GROUP BY :tableName:.id, :joinColumn:
5903
+ LIMIT 1;
5904
+ `,
5905
+ params
5906
+ );
5907
+ return res;
5908
+ },
5909
+ async sqlite(knex2, params) {
5910
+ return knex2.raw(
5911
+ `
5912
+ SELECT :tableName:.id as id, group_concat(DISTINCT :inverseJoinColumn:) as other_ids
5913
+ FROM :tableName:
5914
+ LEFT JOIN :joinTableName: ON :tableName:.id = :joinTableName:.:joinColumn:
5915
+ WHERE document_id IS NULL
5916
+ GROUP BY :joinColumn:
5917
+ LIMIT 1;
5918
+ `,
5919
+ params
5920
+ );
5921
+ }
5922
+ };
5923
+ const getNextIdsToCreateDocumentId = async (db, knex2, {
5924
+ joinColumn,
5925
+ inverseJoinColumn,
5926
+ tableName,
5927
+ joinTableName
5928
+ }) => {
5929
+ const res = await QUERIES[db.dialect.client](knex2, {
5930
+ joinColumn,
5931
+ inverseJoinColumn,
5932
+ tableName,
5933
+ joinTableName
5934
+ });
5935
+ if (res.length > 0) {
5936
+ const row = res[0];
5937
+ const otherIds = row.other_ids ? row.other_ids.split(",").map((v) => parseInt(v, 10)) : [];
5938
+ return [row.id, ...otherIds];
5939
+ }
5940
+ return [];
5941
+ };
5942
+ const migrateDocumentIdsWithLocalizations = async (db, knex2, meta) => {
5943
+ const singularName = meta.singularName.toLowerCase();
5944
+ const joinColumn = identifiers.getJoinColumnAttributeIdName(singularName);
5945
+ const inverseJoinColumn = identifiers.getInverseJoinColumnAttributeIdName(singularName);
5946
+ let ids;
5947
+ do {
5948
+ ids = await getNextIdsToCreateDocumentId(db, knex2, {
5949
+ joinColumn,
5950
+ inverseJoinColumn,
5951
+ tableName: meta.tableName,
5952
+ joinTableName: identifiers.getJoinTableName(meta.tableName, `localizations`)
5953
+ });
5954
+ if (ids.length > 0) {
5955
+ await knex2(meta.tableName).update({ document_id: cuid2.createId() }).whereIn("id", ids);
5956
+ }
5957
+ } while (ids.length > 0);
5958
+ };
5959
+ const migrationDocumentIds = async (db, knex2, meta) => {
5960
+ let run = true;
5961
+ do {
5962
+ const updatedRows = await knex2(meta.tableName).update({ document_id: cuid2.createId() }).whereIn("id", (builder) => {
5963
+ return builder.whereNull("document_id").select("id").limit(1);
5964
+ });
5965
+ if (updatedRows <= 0) {
5966
+ run = false;
5967
+ }
5968
+ } while (run);
5969
+ };
5970
+ const createDocumentIdColumn = async (knex2, tableName) => {
5971
+ await knex2.schema.alterTable(tableName, (table) => {
5972
+ table.string("document_id");
5973
+ });
5974
+ };
5975
+ const hasLocalizationsJoinTable = async (knex2, tableName) => {
5976
+ const joinTableName = identifiers.getJoinTableName(tableName, "localizations");
5977
+ return knex2.schema.hasTable(joinTableName);
5978
+ };
5979
+ const createdDocumentId = {
5980
+ name: "5.0.0-02-created-document-id",
5981
+ async up(knex2, db) {
5982
+ for (const meta of db.metadata.values()) {
5983
+ const hasTable = await knex2.schema.hasTable(meta.tableName);
5984
+ if (!hasTable) {
5985
+ continue;
5986
+ }
5987
+ if ("documentId" in meta.attributes) {
5988
+ const hasDocumentIdColumn = await knex2.schema.hasColumn(meta.tableName, "document_id");
5989
+ if (hasDocumentIdColumn) {
5990
+ continue;
5991
+ }
5992
+ await createDocumentIdColumn(knex2, meta.tableName);
5993
+ if (await hasLocalizationsJoinTable(knex2, meta.tableName)) {
5994
+ await migrateDocumentIdsWithLocalizations(db, knex2, meta);
5995
+ } else {
5996
+ await migrationDocumentIds(db, knex2, meta);
5997
+ }
5998
+ }
5999
+ }
6000
+ },
6001
+ async down() {
6002
+ throw new Error("not implemented");
6003
+ }
6004
+ };
6005
+ const debug = createDebug__default.default("strapi::database::migration");
6006
+ const renameIdentifiersLongerThanMaxLength = {
6007
+ name: "5.0.0-rename-identifiers-longer-than-max-length",
6008
+ async up(knex2, db) {
6009
+ const md = db.metadata;
6010
+ const diffs = findDiffs(md);
6011
+ for (const indexDiff of diffs.indexes) {
6012
+ await renameIndex(knex2, db, indexDiff);
6013
+ }
6014
+ for (const columnDiff of diffs.columns) {
6015
+ const { full, short } = columnDiff;
6016
+ const tableName = full.tableName;
6017
+ const hasTable = await knex2.schema.hasTable(tableName);
6018
+ if (hasTable) {
6019
+ const hasColumn = await knex2.schema.hasColumn(tableName, full.columnName);
6020
+ if (hasColumn) {
6021
+ await knex2.schema.alterTable(tableName, async (table) => {
6022
+ debug(`renaming column ${full.columnName} to ${short.columnName}`);
6023
+ table.renameColumn(full.columnName, short.columnName);
6024
+ });
6025
+ }
6026
+ }
6027
+ }
6028
+ for (const tableDiff of diffs.tables) {
6029
+ const hasTable = await knex2.schema.hasTable(tableDiff.full.tableName);
6030
+ if (hasTable) {
6031
+ debug(`renaming table ${tableDiff.full.tableName} to ${tableDiff.short.tableName}`);
6032
+ await knex2.schema.renameTable(tableDiff.full.tableName, tableDiff.short.tableName);
6033
+ }
6034
+ }
6035
+ },
6036
+ async down() {
6037
+ throw new Error("not implemented");
6038
+ }
6039
+ };
6040
+ const renameIndex = async (knex2, db, diff) => {
6041
+ const client = db.config.connection.client;
6042
+ const short = diff.short;
6043
+ const full = diff.full;
6044
+ if (full.indexName === short.indexName) {
6045
+ debug(`not renaming index ${full.indexName} because name hasn't changed`);
6046
+ return;
6047
+ }
6048
+ if (short.indexName.includes("_lnk_") || full.indexName.includes("_lnk_") || short.indexName.endsWith("fk") || full.indexName.endsWith("fk")) {
6049
+ return;
6050
+ }
6051
+ debug(`renaming index from ${full.indexName} to ${short.indexName}`);
6052
+ try {
6053
+ await knex2.transaction(async (trx) => {
6054
+ if (client === "mysql" || client === "mariadb") {
6055
+ await knex2.raw(
6056
+ `ALTER TABLE \`${full.tableName}\` RENAME INDEX \`${full.indexName}\` TO \`${short.indexName}\``
6057
+ ).transacting(trx);
6058
+ } else if (client === "pg" || client === "postgres") {
6059
+ await knex2.raw(`ALTER INDEX "${full.indexName}" RENAME TO "${short.indexName}"`).transacting(trx);
6060
+ } else if (client === "sqlite" || client === "better") {
6061
+ } else {
6062
+ debug("No db client name matches, not creating index");
6063
+ }
6064
+ });
6065
+ } catch (err) {
6066
+ debug(`error creating index: ${JSON.stringify(err)}`);
6067
+ }
6068
+ };
6069
+ const findDiffs = (shortMap) => {
6070
+ const diffs = {
6071
+ tables: [],
6072
+ columns: [],
6073
+ indexes: []
6074
+ };
6075
+ const shortArr = Array.from(shortMap.entries());
6076
+ shortArr.forEach(([, shortObj], index2) => {
6077
+ const fullTableName = identifiers.getUnshortenedName(shortObj.tableName);
6078
+ if (!fullTableName) {
6079
+ throw new Error(`Missing full table name for ${shortObj.tableName}`);
6080
+ }
6081
+ if (shortObj.tableName !== fullTableName) {
6082
+ diffs.tables.push({
6083
+ full: {
6084
+ index: index2,
6085
+ key: "tableName",
6086
+ tableName: fullTableName
6087
+ },
6088
+ short: {
6089
+ index: index2,
6090
+ key: "tableName",
6091
+ tableName: shortObj.tableName
6092
+ }
6093
+ });
6094
+ }
6095
+ for (const attrKey in shortObj.attributes) {
6096
+ if (shortObj.attributes[attrKey].type === "relation") {
6097
+ continue;
6098
+ }
6099
+ const attr = shortObj.attributes[attrKey];
6100
+ const shortColumnName = attr.columnName;
6101
+ const longColumnName = identifiers.getUnshortenedName(shortColumnName);
6102
+ if (!shortColumnName || !longColumnName) {
6103
+ throw new Error(`missing column name(s) for attribute ${JSON.stringify(attr, null, 2)}`);
6104
+ }
6105
+ if (shortColumnName && longColumnName && shortColumnName !== longColumnName) {
6106
+ diffs.columns.push({
6107
+ short: {
6108
+ index: index2,
6109
+ tableName: fullTableName,
6110
+ // NOTE: this means that we must rename columns before tables
6111
+ key: `attributes.${attrKey}`,
6112
+ columnName: shortColumnName
6113
+ },
6114
+ full: {
6115
+ index: index2,
6116
+ tableName: fullTableName,
6117
+ key: `attributes.${attrKey}`,
6118
+ columnName: longColumnName
6119
+ }
6120
+ });
6121
+ }
6122
+ }
6123
+ for (const attrKey in shortObj.indexes) {
6124
+ const shortIndexName = shortObj.indexes[attrKey].name;
6125
+ const longIndexName = identifiers.getUnshortenedName(shortIndexName);
6126
+ if (!longIndexName) {
6127
+ throw new Error(`Missing full index name for ${shortIndexName}`);
6128
+ }
6129
+ if (shortIndexName && longIndexName && shortIndexName !== longIndexName) {
6130
+ diffs.indexes.push({
6131
+ short: {
6132
+ index: index2,
6133
+ tableName: fullTableName,
6134
+ // NOTE: this means that we must rename columns before tables
6135
+ key: `indexes.${attrKey}`,
6136
+ indexName: shortIndexName
6137
+ },
6138
+ full: {
6139
+ index: index2,
6140
+ tableName: fullTableName,
6141
+ key: `indexes.${attrKey}`,
6142
+ indexName: longIndexName
6143
+ }
6144
+ });
6145
+ }
6146
+ }
6147
+ });
6148
+ return diffs;
6149
+ };
6150
+ const internalMigrations = [
6151
+ renameIdentifiersLongerThanMaxLength,
6152
+ createdDocumentId
6153
+ ];
5714
6154
  const createInternalMigrationProvider = (db) => {
5715
6155
  const context = { db };
5716
6156
  const umzugProvider = new umzug.Umzug({
@@ -5936,8 +6376,14 @@ const validateBidirectionalRelations = async (db) => {
5936
6376
  for (const { relation, invRelation } of invalidLinks) {
5937
6377
  const modelMetadata = db.metadata.get(invRelation.target);
5938
6378
  const invModelMetadata = db.metadata.get(relation.target);
5939
- const joinTableName = getJoinTableName(modelMetadata.tableName, invRelation.inversedBy);
5940
- const inverseJoinTableName = getJoinTableName(invModelMetadata.tableName, relation.inversedBy);
6379
+ const joinTableName = identifiers.getJoinTableName(
6380
+ _.snakeCase(modelMetadata.tableName),
6381
+ _.snakeCase(invRelation.inversedBy)
6382
+ );
6383
+ const inverseJoinTableName = identifiers.getJoinTableName(
6384
+ _.snakeCase(invModelMetadata.tableName),
6385
+ _.snakeCase(relation.inversedBy)
6386
+ );
5941
6387
  const joinTableEmpty = await isLinkTableEmpty(db, joinTableName);
5942
6388
  const inverseJoinTableEmpty = await isLinkTableEmpty(db, inverseJoinTableName);
5943
6389
  if (joinTableEmpty) {
@@ -5983,7 +6429,7 @@ class Database {
5983
6429
  };
5984
6430
  this.dialect = getDialect(this);
5985
6431
  this.dialect.configure();
5986
- this.metadata = createMetadata();
6432
+ this.metadata = createMetadata([]);
5987
6433
  this.connection = createConnection(this.config.connection, {
5988
6434
  pool: { afterCreate: afterCreate(this) }
5989
6435
  });
@@ -6060,9 +6506,7 @@ class Database {
6060
6506
  await this.connection.destroy();
6061
6507
  }
6062
6508
  }
6063
- const utils = { identifiers };
6064
6509
  exports.Database = Database;
6065
6510
  exports.errors = index;
6066
6511
  exports.isKnexQuery = isKnexQuery;
6067
- exports.utils = utils;
6068
6512
  //# sourceMappingURL=index.js.map