@strapi/database 4.20.5 → 5.0.0-alpha.0
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/connection.d.ts +2 -1
- package/dist/connection.d.ts.map +1 -1
- package/dist/dialects/dialect.d.ts +1 -2
- package/dist/dialects/dialect.d.ts.map +1 -1
- package/dist/dialects/index.d.ts.map +1 -1
- package/dist/dialects/mysql/database-inspector.d.ts +1 -1
- package/dist/dialects/mysql/database-inspector.d.ts.map +1 -1
- package/dist/dialects/mysql/index.d.ts +1 -2
- package/dist/dialects/mysql/index.d.ts.map +1 -1
- package/dist/dialects/postgresql/index.d.ts +1 -1
- package/dist/dialects/postgresql/index.d.ts.map +1 -1
- package/dist/dialects/sqlite/index.d.ts +1 -1
- package/dist/dialects/sqlite/index.d.ts.map +1 -1
- package/dist/entity-manager/entity-repository.d.ts.map +1 -1
- package/dist/entity-manager/index.d.ts.map +1 -1
- package/dist/entity-manager/regular-relations.d.ts +6 -31
- package/dist/entity-manager/regular-relations.d.ts.map +1 -1
- package/dist/entity-manager/types.d.ts +8 -26
- package/dist/entity-manager/types.d.ts.map +1 -1
- package/dist/index.d.ts +13 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +518 -645
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +514 -639
- package/dist/index.mjs.map +1 -1
- package/dist/metadata/index.d.ts +2 -2
- package/dist/metadata/index.d.ts.map +1 -1
- package/dist/metadata/metadata.d.ts +1 -4
- package/dist/metadata/metadata.d.ts.map +1 -1
- package/dist/metadata/relations.d.ts +0 -1
- package/dist/metadata/relations.d.ts.map +1 -1
- package/dist/migrations/common.d.ts +20 -0
- package/dist/migrations/common.d.ts.map +1 -0
- package/dist/migrations/index.d.ts +2 -9
- package/dist/migrations/index.d.ts.map +1 -1
- package/dist/migrations/internal-migrations/index.d.ts +12 -0
- package/dist/migrations/internal-migrations/index.d.ts.map +1 -0
- package/dist/migrations/internal.d.ts +4 -0
- package/dist/migrations/internal.d.ts.map +1 -0
- package/dist/migrations/storage.d.ts +1 -1
- package/dist/migrations/storage.d.ts.map +1 -1
- package/dist/migrations/users.d.ts +4 -0
- package/dist/migrations/users.d.ts.map +1 -0
- package/dist/schema/diff.d.ts.map +1 -1
- package/dist/schema/index.d.ts +2 -0
- package/dist/schema/index.d.ts.map +1 -1
- package/dist/schema/schema.d.ts.map +1 -1
- package/dist/types/index.d.ts +9 -5
- package/dist/types/index.d.ts.map +1 -1
- package/dist/utils/identifiers/index.d.ts +48 -0
- package/dist/utils/identifiers/index.d.ts.map +1 -0
- package/dist/utils/identifiers/shortener.d.ts +73 -0
- package/dist/utils/identifiers/shortener.d.ts.map +1 -0
- package/dist/utils/types.d.ts +0 -2
- package/dist/utils/types.d.ts.map +1 -1
- package/dist/validations/relations/bidirectional.d.ts.map +1 -1
- package/package.json +9 -9
- package/dist/entity-manager/relations/cloning/regular-relations.d.ts +0 -17
- package/dist/entity-manager/relations/cloning/regular-relations.d.ts.map +0 -1
- package/dist/utils/content-types.d.ts +0 -13
- package/dist/utils/content-types.d.ts.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,23 +1,21 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
-
const semver = require("semver");
|
|
4
3
|
const path = require("path");
|
|
5
4
|
const fse = require("fs-extra");
|
|
6
5
|
const createDebug = require("debug");
|
|
7
6
|
const _ = require("lodash/fp");
|
|
8
7
|
const crypto = require("crypto");
|
|
9
|
-
const
|
|
8
|
+
const crypto$1 = require("node:crypto");
|
|
10
9
|
const dateFns = require("date-fns");
|
|
10
|
+
const utils$1 = 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
|
-
const path$1 = require("node:path");
|
|
17
16
|
const umzug = require("umzug");
|
|
18
17
|
const assert = require("assert");
|
|
19
18
|
const knex = require("knex");
|
|
20
|
-
const SqliteClient = require("knex/lib/dialects/sqlite3/index");
|
|
21
19
|
const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
|
|
22
20
|
function _interopNamespace(e) {
|
|
23
21
|
if (e && e.__esModule)
|
|
@@ -37,19 +35,17 @@ function _interopNamespace(e) {
|
|
|
37
35
|
n.default = e;
|
|
38
36
|
return Object.freeze(n);
|
|
39
37
|
}
|
|
40
|
-
const semver__default = /* @__PURE__ */ _interopDefault(semver);
|
|
41
38
|
const path__default = /* @__PURE__ */ _interopDefault(path);
|
|
42
39
|
const fse__default = /* @__PURE__ */ _interopDefault(fse);
|
|
43
40
|
const createDebug__default = /* @__PURE__ */ _interopDefault(createDebug);
|
|
44
41
|
const ___default = /* @__PURE__ */ _interopDefault(_);
|
|
45
42
|
const crypto__default = /* @__PURE__ */ _interopDefault(crypto);
|
|
43
|
+
const crypto__default$1 = /* @__PURE__ */ _interopDefault(crypto$1);
|
|
46
44
|
const dateFns__namespace = /* @__PURE__ */ _interopNamespace(dateFns);
|
|
47
45
|
const KnexBuilder__default = /* @__PURE__ */ _interopDefault(KnexBuilder);
|
|
48
46
|
const KnexRaw__default = /* @__PURE__ */ _interopDefault(KnexRaw);
|
|
49
47
|
const ___default$1 = /* @__PURE__ */ _interopDefault(_$1);
|
|
50
|
-
const path__default$1 = /* @__PURE__ */ _interopDefault(path$1);
|
|
51
48
|
const knex__default = /* @__PURE__ */ _interopDefault(knex);
|
|
52
|
-
const SqliteClient__default = /* @__PURE__ */ _interopDefault(SqliteClient);
|
|
53
49
|
class Dialect {
|
|
54
50
|
db;
|
|
55
51
|
schemaInspector = {};
|
|
@@ -60,7 +56,8 @@ class Dialect {
|
|
|
60
56
|
}
|
|
61
57
|
configure() {
|
|
62
58
|
}
|
|
63
|
-
|
|
59
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
60
|
+
async initialize(_nativeConnection) {
|
|
64
61
|
}
|
|
65
62
|
getSqlType(type) {
|
|
66
63
|
return type;
|
|
@@ -77,9 +74,6 @@ class Dialect {
|
|
|
77
74
|
supportsUnsigned() {
|
|
78
75
|
return false;
|
|
79
76
|
}
|
|
80
|
-
supportsWindowFunctions() {
|
|
81
|
-
return true;
|
|
82
|
-
}
|
|
83
77
|
supportsOperator() {
|
|
84
78
|
return true;
|
|
85
79
|
}
|
|
@@ -423,7 +417,7 @@ class PostgresDialect extends Dialect {
|
|
|
423
417
|
useReturning() {
|
|
424
418
|
return true;
|
|
425
419
|
}
|
|
426
|
-
async initialize() {
|
|
420
|
+
async initialize(nativeConnection) {
|
|
427
421
|
this.db.connection.client.driver.types.setTypeParser(
|
|
428
422
|
this.db.connection.client.driver.types.builtins.DATE,
|
|
429
423
|
"text",
|
|
@@ -439,6 +433,10 @@ class PostgresDialect extends Dialect {
|
|
|
439
433
|
"text",
|
|
440
434
|
parseFloat
|
|
441
435
|
);
|
|
436
|
+
const schemaName = this.db.getSchemaName();
|
|
437
|
+
if (schemaName) {
|
|
438
|
+
await this.db.connection.raw(`SET search_path TO "${schemaName}"`).connection(nativeConnection);
|
|
439
|
+
}
|
|
442
440
|
}
|
|
443
441
|
usesForeignKeys() {
|
|
444
442
|
return true;
|
|
@@ -702,11 +700,11 @@ class MysqlDatabaseInspector {
|
|
|
702
700
|
constructor(db) {
|
|
703
701
|
this.db = db;
|
|
704
702
|
}
|
|
705
|
-
async getInformation() {
|
|
703
|
+
async getInformation(nativeConnection) {
|
|
706
704
|
let database;
|
|
707
705
|
let versionNumber;
|
|
708
706
|
try {
|
|
709
|
-
const [results] = await this.db.connection.raw(SQL_QUERIES$1.VERSION);
|
|
707
|
+
const [results] = await this.db.connection.raw(SQL_QUERIES$1.VERSION).connection(nativeConnection);
|
|
710
708
|
const versionSplit = results[0].version.split("-");
|
|
711
709
|
const databaseName = versionSplit[1];
|
|
712
710
|
versionNumber = versionSplit[0];
|
|
@@ -753,12 +751,14 @@ class MysqlDialect extends Dialect {
|
|
|
753
751
|
return next();
|
|
754
752
|
};
|
|
755
753
|
}
|
|
756
|
-
async initialize() {
|
|
754
|
+
async initialize(nativeConnection) {
|
|
757
755
|
try {
|
|
758
|
-
await this.db.connection.raw(`set session sql_require_primary_key = 0;`);
|
|
756
|
+
await this.db.connection.raw(`set session sql_require_primary_key = 0;`).connection(nativeConnection);
|
|
759
757
|
} catch (err) {
|
|
760
758
|
}
|
|
761
|
-
this.info
|
|
759
|
+
if (!this.info) {
|
|
760
|
+
this.info = await this.databaseInspector.getInformation(nativeConnection);
|
|
761
|
+
}
|
|
762
762
|
}
|
|
763
763
|
async startSchemaUpdate() {
|
|
764
764
|
try {
|
|
@@ -773,14 +773,6 @@ class MysqlDialect extends Dialect {
|
|
|
773
773
|
supportsUnsigned() {
|
|
774
774
|
return true;
|
|
775
775
|
}
|
|
776
|
-
supportsWindowFunctions() {
|
|
777
|
-
const isMysqlDB = !this.info?.database || this.info.database === MYSQL;
|
|
778
|
-
const isBeforeV8 = !semver__default.default.valid(this.info?.version) || semver__default.default.lt(this.info?.version ?? "", "8.0.0");
|
|
779
|
-
if (isMysqlDB && isBeforeV8) {
|
|
780
|
-
return false;
|
|
781
|
-
}
|
|
782
|
-
return true;
|
|
783
|
-
}
|
|
784
776
|
usesForeignKeys() {
|
|
785
777
|
return true;
|
|
786
778
|
}
|
|
@@ -938,8 +930,8 @@ class SqliteDialect extends Dialect {
|
|
|
938
930
|
useReturning() {
|
|
939
931
|
return true;
|
|
940
932
|
}
|
|
941
|
-
async initialize() {
|
|
942
|
-
await this.db.connection.raw("pragma foreign_keys = on");
|
|
933
|
+
async initialize(nativeConnection) {
|
|
934
|
+
await this.db.connection.raw("pragma foreign_keys = on").connection(nativeConnection);
|
|
943
935
|
}
|
|
944
936
|
canAlterConstraints() {
|
|
945
937
|
return false;
|
|
@@ -1001,10 +993,8 @@ const getDialectName = (client) => {
|
|
|
1001
993
|
case "postgres":
|
|
1002
994
|
return "postgres";
|
|
1003
995
|
case "mysql":
|
|
1004
|
-
case "mysql2":
|
|
1005
996
|
return "mysql";
|
|
1006
997
|
case "sqlite":
|
|
1007
|
-
case "sqlite-legacy":
|
|
1008
998
|
return "sqlite";
|
|
1009
999
|
default:
|
|
1010
1000
|
throw new Error(`Unknown dialect ${client}`);
|
|
@@ -1268,7 +1258,11 @@ const createHelpers = (db) => {
|
|
|
1268
1258
|
dropTableForeignKeys
|
|
1269
1259
|
};
|
|
1270
1260
|
};
|
|
1271
|
-
const RESERVED_TABLE_NAMES = [
|
|
1261
|
+
const RESERVED_TABLE_NAMES = [
|
|
1262
|
+
"strapi_migrations",
|
|
1263
|
+
"strapi_migrations_internal",
|
|
1264
|
+
"strapi_database_schema"
|
|
1265
|
+
];
|
|
1272
1266
|
const statuses = {
|
|
1273
1267
|
CHANGED: "CHANGED",
|
|
1274
1268
|
UNCHANGED: "UNCHANGED"
|
|
@@ -1648,11 +1642,212 @@ const NUMBER_TYPES = ["biginteger", "integer", "decimal", "float"];
|
|
|
1648
1642
|
const isString = (type) => STRING_TYPES.includes(type);
|
|
1649
1643
|
const isNumber = (type) => NUMBER_TYPES.includes(type);
|
|
1650
1644
|
const isScalar = (type) => SCALAR_TYPES.includes(type);
|
|
1651
|
-
const isComponent = (type) => type === "component";
|
|
1652
|
-
const isDynamicZone = (type) => type === "dynamiczone";
|
|
1653
1645
|
const isRelation = (type) => type === "relation";
|
|
1654
1646
|
const isScalarAttribute = (attribute) => isScalar(attribute.type);
|
|
1655
1647
|
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
|
+
function createHash(data, len) {
|
|
1654
|
+
if (!_.isInteger(len) || len <= 0) {
|
|
1655
|
+
throw new Error(`createHash length must be a positive integer, received ${len}`);
|
|
1656
|
+
}
|
|
1657
|
+
const hash = crypto__default$1.default.createHash("shake256", { outputLength: Math.ceil(len / 2) }).update(data);
|
|
1658
|
+
return hash.digest("hex").substring(0, len);
|
|
1659
|
+
}
|
|
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
|
+
);
|
|
1677
|
+
}
|
|
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)");
|
|
1683
|
+
}
|
|
1684
|
+
const fullLengthName = nameTokens.map((token) => _.snakeCase(token.name)).join(IDENTIFIER_SEPARATOR);
|
|
1685
|
+
if (fullLengthName.length <= maxLength || maxLength === 0) {
|
|
1686
|
+
return fullLengthName;
|
|
1687
|
+
}
|
|
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);
|
|
1722
|
+
}
|
|
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;
|
|
1729
|
+
}
|
|
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;
|
|
1737
|
+
}
|
|
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);
|
|
1743
|
+
}
|
|
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}`
|
|
1749
|
+
);
|
|
1750
|
+
}
|
|
1751
|
+
return shortenedName;
|
|
1752
|
+
}
|
|
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" }));
|
|
1656
1851
|
const createColumn = (name, attribute) => {
|
|
1657
1852
|
const { type, args = [], ...opts } = getColumnType(attribute);
|
|
1658
1853
|
return {
|
|
@@ -1678,51 +1873,62 @@ const createTable = (meta) => {
|
|
|
1678
1873
|
if (attribute.type === "relation") {
|
|
1679
1874
|
if ("morphColumn" in attribute && attribute.morphColumn && attribute.owner) {
|
|
1680
1875
|
const { idColumn, typeColumn } = attribute.morphColumn;
|
|
1876
|
+
const idColumnName = getName(idColumn.name);
|
|
1877
|
+
const typeColumnName = getName(typeColumn.name);
|
|
1681
1878
|
table.columns.push(
|
|
1682
|
-
createColumn(
|
|
1879
|
+
createColumn(idColumnName, {
|
|
1683
1880
|
type: "integer",
|
|
1684
1881
|
column: {
|
|
1685
1882
|
unsigned: true
|
|
1686
1883
|
}
|
|
1687
1884
|
})
|
|
1688
1885
|
);
|
|
1689
|
-
table.columns.push(createColumn(
|
|
1886
|
+
table.columns.push(createColumn(typeColumnName, { type: "string" }));
|
|
1690
1887
|
} else if ("joinColumn" in attribute && attribute.joinColumn && attribute.owner && attribute.joinColumn.referencedTable) {
|
|
1691
|
-
const {
|
|
1888
|
+
const {
|
|
1889
|
+
name: columnNameFull,
|
|
1890
|
+
referencedColumn,
|
|
1891
|
+
referencedTable,
|
|
1892
|
+
columnType = "integer"
|
|
1893
|
+
} = attribute.joinColumn;
|
|
1894
|
+
const columnName = getName(columnNameFull);
|
|
1692
1895
|
const column = createColumn(columnName, {
|
|
1693
|
-
|
|
1896
|
+
// TODO: find the column type automatically, or allow passing all the column params
|
|
1897
|
+
type: columnType,
|
|
1694
1898
|
column: {
|
|
1695
1899
|
unsigned: true
|
|
1696
1900
|
}
|
|
1697
1901
|
});
|
|
1698
1902
|
table.columns.push(column);
|
|
1903
|
+
const fkName = getFkIndexName([table.name, columnName]);
|
|
1699
1904
|
table.foreignKeys.push({
|
|
1700
|
-
name:
|
|
1701
|
-
columns: [
|
|
1905
|
+
name: fkName,
|
|
1906
|
+
columns: [column.name],
|
|
1702
1907
|
referencedTable,
|
|
1703
1908
|
referencedColumns: [referencedColumn],
|
|
1704
1909
|
// NOTE: could allow configuration
|
|
1705
1910
|
onDelete: "SET NULL"
|
|
1706
1911
|
});
|
|
1707
1912
|
table.indexes.push({
|
|
1708
|
-
name:
|
|
1709
|
-
columns: [
|
|
1913
|
+
name: fkName,
|
|
1914
|
+
columns: [column.name]
|
|
1710
1915
|
});
|
|
1711
1916
|
}
|
|
1712
1917
|
} else if (isScalarAttribute(attribute)) {
|
|
1713
|
-
const
|
|
1918
|
+
const columnName = getName(attribute.columnName || key);
|
|
1919
|
+
const column = createColumn(columnName, attribute);
|
|
1714
1920
|
if (column.unique) {
|
|
1715
1921
|
table.indexes.push({
|
|
1716
1922
|
type: "unique",
|
|
1717
|
-
name:
|
|
1718
|
-
columns: [
|
|
1923
|
+
name: getUniqueIndexName([table.name, column.name]),
|
|
1924
|
+
columns: [columnName]
|
|
1719
1925
|
});
|
|
1720
1926
|
}
|
|
1721
1927
|
if (column.primary) {
|
|
1722
1928
|
table.indexes.push({
|
|
1723
1929
|
type: "primary",
|
|
1724
|
-
name:
|
|
1725
|
-
columns: [
|
|
1930
|
+
name: getPrimaryIndexName([table.name, column.name]),
|
|
1931
|
+
columns: [columnName]
|
|
1726
1932
|
});
|
|
1727
1933
|
}
|
|
1728
1934
|
table.columns.push(column);
|
|
@@ -1750,8 +1956,7 @@ const getColumnType = (attribute) => {
|
|
|
1750
1956
|
}
|
|
1751
1957
|
case "uid": {
|
|
1752
1958
|
return {
|
|
1753
|
-
type: "string"
|
|
1754
|
-
unique: true
|
|
1959
|
+
type: "string"
|
|
1755
1960
|
};
|
|
1756
1961
|
}
|
|
1757
1962
|
case "richtext":
|
|
@@ -1824,8 +2029,14 @@ const metadataToSchema = (metadata) => {
|
|
|
1824
2029
|
};
|
|
1825
2030
|
const debug = createDebug__default.default("strapi::database");
|
|
1826
2031
|
const createSchemaProvider = (db) => {
|
|
1827
|
-
const
|
|
2032
|
+
const state = {};
|
|
1828
2033
|
return {
|
|
2034
|
+
get schema() {
|
|
2035
|
+
if (!state.schema) {
|
|
2036
|
+
state.schema = metadataToSchema(db.metadata);
|
|
2037
|
+
}
|
|
2038
|
+
return state.schema;
|
|
2039
|
+
},
|
|
1829
2040
|
builder: createSchemaBuilder(db),
|
|
1830
2041
|
schemaDiff: createSchemaDiff(db),
|
|
1831
2042
|
schemaStorage: createSchemaStorage(db),
|
|
@@ -1842,7 +2053,7 @@ const createSchemaProvider = (db) => {
|
|
|
1842
2053
|
*/
|
|
1843
2054
|
async create() {
|
|
1844
2055
|
debug("Created database schema");
|
|
1845
|
-
await this.builder.createSchema(schema);
|
|
2056
|
+
await this.builder.createSchema(this.schema);
|
|
1846
2057
|
},
|
|
1847
2058
|
/**
|
|
1848
2059
|
* Resets the database schema
|
|
@@ -1855,11 +2066,11 @@ const createSchemaProvider = (db) => {
|
|
|
1855
2066
|
async syncSchema() {
|
|
1856
2067
|
debug("Synchronizing database schema");
|
|
1857
2068
|
const DBSchema = await db.dialect.schemaInspector.getSchema();
|
|
1858
|
-
const { status, diff } = await this.schemaDiff.diff(DBSchema, schema);
|
|
2069
|
+
const { status, diff } = await this.schemaDiff.diff(DBSchema, this.schema);
|
|
1859
2070
|
if (status === "CHANGED") {
|
|
1860
2071
|
await this.builder.updateSchema(diff);
|
|
1861
2072
|
}
|
|
1862
|
-
await this.schemaStorage.add(schema);
|
|
2073
|
+
await this.schemaStorage.add(this.schema);
|
|
1863
2074
|
},
|
|
1864
2075
|
// TODO: support options to migrate softly or forcefully
|
|
1865
2076
|
// TODO: support option to disable auto migration & run a CLI command instead to avoid doing it at startup
|
|
@@ -1876,7 +2087,7 @@ const createSchemaProvider = (db) => {
|
|
|
1876
2087
|
return this.syncSchema();
|
|
1877
2088
|
}
|
|
1878
2089
|
const { hash: oldHash } = oldSchema;
|
|
1879
|
-
const hash = await this.schemaStorage.hashSchema(schema);
|
|
2090
|
+
const hash = await this.schemaStorage.hashSchema(this.schema);
|
|
1880
2091
|
if (oldHash !== hash) {
|
|
1881
2092
|
debug("Schema changed");
|
|
1882
2093
|
return this.syncSchema();
|
|
@@ -1885,9 +2096,11 @@ const createSchemaProvider = (db) => {
|
|
|
1885
2096
|
}
|
|
1886
2097
|
};
|
|
1887
2098
|
};
|
|
2099
|
+
const ID = ID_COLUMN;
|
|
2100
|
+
const ORDER = ORDER_COLUMN;
|
|
2101
|
+
const FIELD = FIELD_COLUMN;
|
|
1888
2102
|
const hasInversedBy = (attr) => "inversedBy" in attr;
|
|
1889
2103
|
const hasMappedBy = (attr) => "mappedBy" in attr;
|
|
1890
|
-
const isPolymorphic = (attribute) => ["morphOne", "morphMany", "morphToOne", "morphToMany"].includes(attribute.relation);
|
|
1891
2104
|
const isOneToAny = (attribute) => ["oneToOne", "oneToMany"].includes(attribute.relation);
|
|
1892
2105
|
const isManyToAny = (attribute) => ["manyToMany", "manyToOne"].includes(attribute.relation);
|
|
1893
2106
|
const isAnyToOne = (attribute) => ["oneToOne", "manyToOne"].includes(attribute.relation);
|
|
@@ -1895,7 +2108,6 @@ const isAnyToMany = (attribute) => ["oneToMany", "manyToMany"].includes(attribut
|
|
|
1895
2108
|
const isBidirectional = (attribute) => hasInversedBy(attribute) || hasMappedBy(attribute);
|
|
1896
2109
|
const isOwner = (attribute) => !isBidirectional(attribute) || hasInversedBy(attribute);
|
|
1897
2110
|
const shouldUseJoinTable = (attribute) => !("useJoinTable" in attribute) || attribute.useJoinTable !== false;
|
|
1898
|
-
const getJoinTableName = (tableName, attributeName) => ___default.default.snakeCase(`${tableName}_${attributeName}_links`);
|
|
1899
2111
|
const hasOrderColumn = (attribute) => isAnyToMany(attribute);
|
|
1900
2112
|
const hasInverseOrderColumn = (attribute) => isBidirectional(attribute) && isManyToAny(attribute);
|
|
1901
2113
|
const createOneToOne = (attributeName, attribute, meta, metadata) => {
|
|
@@ -1954,8 +2166,11 @@ const createManyToMany = (attributeName, attribute, meta, metadata) => {
|
|
|
1954
2166
|
}
|
|
1955
2167
|
};
|
|
1956
2168
|
const createMorphToOne = (attributeName, attribute) => {
|
|
1957
|
-
const idColumnName = "
|
|
1958
|
-
const typeColumnName = "
|
|
2169
|
+
const idColumnName = getJoinColumnAttributeIdName("target");
|
|
2170
|
+
const typeColumnName = getMorphColumnTypeName("target");
|
|
2171
|
+
if ("morphColumn" in attribute && attribute.morphColumn) {
|
|
2172
|
+
return;
|
|
2173
|
+
}
|
|
1959
2174
|
Object.assign(attribute, {
|
|
1960
2175
|
owner: true,
|
|
1961
2176
|
morphColumn: {
|
|
@@ -1965,23 +2180,26 @@ const createMorphToOne = (attributeName, attribute) => {
|
|
|
1965
2180
|
},
|
|
1966
2181
|
idColumn: {
|
|
1967
2182
|
name: idColumnName,
|
|
1968
|
-
referencedColumn:
|
|
2183
|
+
referencedColumn: ID
|
|
1969
2184
|
}
|
|
1970
2185
|
}
|
|
1971
2186
|
});
|
|
1972
2187
|
};
|
|
1973
2188
|
const createMorphToMany = (attributeName, attribute, meta, metadata) => {
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
const
|
|
1978
|
-
const
|
|
2189
|
+
if ("joinTable" in attribute && attribute.joinTable) {
|
|
2190
|
+
return;
|
|
2191
|
+
}
|
|
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);
|
|
1979
2197
|
metadata.add({
|
|
1980
2198
|
singularName: joinTableName,
|
|
1981
2199
|
uid: joinTableName,
|
|
1982
2200
|
tableName: joinTableName,
|
|
1983
2201
|
attributes: {
|
|
1984
|
-
|
|
2202
|
+
[ID]: {
|
|
1985
2203
|
type: "increments"
|
|
1986
2204
|
},
|
|
1987
2205
|
[joinColumnName]: {
|
|
@@ -1999,10 +2217,10 @@ const createMorphToMany = (attributeName, attribute, meta, metadata) => {
|
|
|
1999
2217
|
[typeColumnName]: {
|
|
2000
2218
|
type: "string"
|
|
2001
2219
|
},
|
|
2002
|
-
|
|
2220
|
+
[FIELD]: {
|
|
2003
2221
|
type: "string"
|
|
2004
2222
|
},
|
|
2005
|
-
|
|
2223
|
+
[ORDER]: {
|
|
2006
2224
|
type: "float",
|
|
2007
2225
|
column: {
|
|
2008
2226
|
unsigned: true
|
|
@@ -2011,12 +2229,12 @@ const createMorphToMany = (attributeName, attribute, meta, metadata) => {
|
|
|
2011
2229
|
},
|
|
2012
2230
|
indexes: [
|
|
2013
2231
|
{
|
|
2014
|
-
name:
|
|
2232
|
+
name: fkIndexName,
|
|
2015
2233
|
columns: [joinColumnName]
|
|
2016
2234
|
},
|
|
2017
2235
|
{
|
|
2018
2236
|
name: `${joinTableName}_order_index`,
|
|
2019
|
-
columns: [
|
|
2237
|
+
columns: [ORDER]
|
|
2020
2238
|
},
|
|
2021
2239
|
{
|
|
2022
2240
|
name: `${joinTableName}_id_column_index`,
|
|
@@ -2025,10 +2243,10 @@ const createMorphToMany = (attributeName, attribute, meta, metadata) => {
|
|
|
2025
2243
|
],
|
|
2026
2244
|
foreignKeys: [
|
|
2027
2245
|
{
|
|
2028
|
-
name:
|
|
2246
|
+
name: fkIndexName,
|
|
2029
2247
|
columns: [joinColumnName],
|
|
2030
|
-
referencedColumns: [
|
|
2031
|
-
referencedTable: meta.tableName,
|
|
2248
|
+
referencedColumns: [ID],
|
|
2249
|
+
referencedTable: getTableName(meta.tableName),
|
|
2032
2250
|
onDelete: "CASCADE"
|
|
2033
2251
|
}
|
|
2034
2252
|
],
|
|
@@ -2039,7 +2257,7 @@ const createMorphToMany = (attributeName, attribute, meta, metadata) => {
|
|
|
2039
2257
|
name: joinTableName,
|
|
2040
2258
|
joinColumn: {
|
|
2041
2259
|
name: joinColumnName,
|
|
2042
|
-
referencedColumn:
|
|
2260
|
+
referencedColumn: ID
|
|
2043
2261
|
},
|
|
2044
2262
|
morphColumn: {
|
|
2045
2263
|
typeColumn: {
|
|
@@ -2047,7 +2265,7 @@ const createMorphToMany = (attributeName, attribute, meta, metadata) => {
|
|
|
2047
2265
|
},
|
|
2048
2266
|
idColumn: {
|
|
2049
2267
|
name: idColumnName,
|
|
2050
|
-
referencedColumn:
|
|
2268
|
+
referencedColumn: ID
|
|
2051
2269
|
}
|
|
2052
2270
|
},
|
|
2053
2271
|
orderBy: {
|
|
@@ -2083,9 +2301,12 @@ const createJoinColum = (metadata, { attribute, attributeName }) => {
|
|
|
2083
2301
|
const joinColumnName = ___default.default.snakeCase(`${attributeName}_id`);
|
|
2084
2302
|
const joinColumn = {
|
|
2085
2303
|
name: joinColumnName,
|
|
2086
|
-
referencedColumn:
|
|
2304
|
+
referencedColumn: ID,
|
|
2087
2305
|
referencedTable: targetMeta.tableName
|
|
2088
2306
|
};
|
|
2307
|
+
if ("joinColumn" in attribute) {
|
|
2308
|
+
Object.assign(joinColumn, attribute.joinColumn);
|
|
2309
|
+
}
|
|
2089
2310
|
Object.assign(attribute, { owner: true, joinColumn });
|
|
2090
2311
|
if (isBidirectional(attribute)) {
|
|
2091
2312
|
const inverseAttribute = targetMeta.attributes[attribute.inversedBy];
|
|
@@ -2102,23 +2323,30 @@ const createJoinTable = (metadata, { attributeName, attribute, meta }) => {
|
|
|
2102
2323
|
if (!targetMeta) {
|
|
2103
2324
|
throw new Error(`Unknown target ${attribute.target}`);
|
|
2104
2325
|
}
|
|
2326
|
+
if ("joinTable" in attribute && attribute.joinTable) {
|
|
2327
|
+
return;
|
|
2328
|
+
}
|
|
2105
2329
|
const joinTableName = getJoinTableName(meta.tableName, attributeName);
|
|
2106
|
-
const joinColumnName =
|
|
2107
|
-
let inverseJoinColumnName =
|
|
2330
|
+
const joinColumnName = getJoinColumnAttributeIdName(meta.singularName);
|
|
2331
|
+
let inverseJoinColumnName = getJoinColumnAttributeIdName(targetMeta.singularName);
|
|
2108
2332
|
if (joinColumnName === inverseJoinColumnName) {
|
|
2109
|
-
inverseJoinColumnName =
|
|
2333
|
+
inverseJoinColumnName = getInverseJoinColumnAttributeIdName(
|
|
2334
|
+
targetMeta.singularName
|
|
2335
|
+
);
|
|
2110
2336
|
}
|
|
2111
|
-
const orderColumnName =
|
|
2112
|
-
let inverseOrderColumnName =
|
|
2337
|
+
const orderColumnName = getOrderColumnName(targetMeta.singularName);
|
|
2338
|
+
let inverseOrderColumnName = getOrderColumnName(meta.singularName);
|
|
2113
2339
|
if (attribute.relation === "manyToMany" && orderColumnName === inverseOrderColumnName) {
|
|
2114
|
-
inverseOrderColumnName =
|
|
2340
|
+
inverseOrderColumnName = getInverseOrderColumnName(meta.singularName);
|
|
2115
2341
|
}
|
|
2342
|
+
const fkIndexName = getFkIndexName(joinTableName);
|
|
2343
|
+
const invFkIndexName = getInverseFkIndexName(joinTableName);
|
|
2116
2344
|
const metadataSchema = {
|
|
2117
2345
|
singularName: joinTableName,
|
|
2118
2346
|
uid: joinTableName,
|
|
2119
2347
|
tableName: joinTableName,
|
|
2120
2348
|
attributes: {
|
|
2121
|
-
|
|
2349
|
+
[ID]: {
|
|
2122
2350
|
type: "increments"
|
|
2123
2351
|
},
|
|
2124
2352
|
[joinColumnName]: {
|
|
@@ -2137,32 +2365,34 @@ const createJoinTable = (metadata, { attributeName, attribute, meta }) => {
|
|
|
2137
2365
|
},
|
|
2138
2366
|
indexes: [
|
|
2139
2367
|
{
|
|
2140
|
-
name:
|
|
2368
|
+
name: fkIndexName,
|
|
2141
2369
|
columns: [joinColumnName]
|
|
2142
2370
|
},
|
|
2143
2371
|
{
|
|
2144
|
-
name:
|
|
2372
|
+
name: invFkIndexName,
|
|
2145
2373
|
columns: [inverseJoinColumnName]
|
|
2146
2374
|
},
|
|
2147
2375
|
{
|
|
2148
|
-
name:
|
|
2376
|
+
name: getUniqueIndexName(joinTableName),
|
|
2149
2377
|
columns: [joinColumnName, inverseJoinColumnName],
|
|
2150
2378
|
type: "unique"
|
|
2151
2379
|
}
|
|
2152
2380
|
],
|
|
2153
2381
|
foreignKeys: [
|
|
2154
2382
|
{
|
|
2155
|
-
name:
|
|
2383
|
+
name: fkIndexName,
|
|
2156
2384
|
columns: [joinColumnName],
|
|
2157
|
-
referencedColumns: [
|
|
2385
|
+
referencedColumns: [ID],
|
|
2158
2386
|
referencedTable: meta.tableName,
|
|
2387
|
+
// TODO: does this need to be wrapped or do we trust meta.tableName to be the right shortened version?
|
|
2159
2388
|
onDelete: "CASCADE"
|
|
2160
2389
|
},
|
|
2161
2390
|
{
|
|
2162
|
-
name:
|
|
2391
|
+
name: invFkIndexName,
|
|
2163
2392
|
columns: [inverseJoinColumnName],
|
|
2164
|
-
referencedColumns: [
|
|
2393
|
+
referencedColumns: [ID],
|
|
2165
2394
|
referencedTable: targetMeta.tableName,
|
|
2395
|
+
// TODO: does this need to be wrapped or do we trust meta.tableName to be the right shortened version?
|
|
2166
2396
|
onDelete: "CASCADE"
|
|
2167
2397
|
}
|
|
2168
2398
|
],
|
|
@@ -2173,11 +2403,13 @@ const createJoinTable = (metadata, { attributeName, attribute, meta }) => {
|
|
|
2173
2403
|
name: joinTableName,
|
|
2174
2404
|
joinColumn: {
|
|
2175
2405
|
name: joinColumnName,
|
|
2176
|
-
referencedColumn:
|
|
2406
|
+
referencedColumn: ID,
|
|
2407
|
+
referencedTable: meta.tableName
|
|
2177
2408
|
},
|
|
2178
2409
|
inverseJoinColumn: {
|
|
2179
2410
|
name: inverseJoinColumnName,
|
|
2180
|
-
referencedColumn:
|
|
2411
|
+
referencedColumn: ID,
|
|
2412
|
+
referencedTable: targetMeta.tableName
|
|
2181
2413
|
},
|
|
2182
2414
|
pivotColumns: [joinColumnName, inverseJoinColumnName]
|
|
2183
2415
|
};
|
|
@@ -2190,7 +2422,8 @@ const createJoinTable = (metadata, { attributeName, attribute, meta }) => {
|
|
|
2190
2422
|
}
|
|
2191
2423
|
};
|
|
2192
2424
|
metadataSchema.indexes.push({
|
|
2193
|
-
name:
|
|
2425
|
+
name: getOrderFkIndexName(joinTableName),
|
|
2426
|
+
// TODO: should we send joinTableName as parts?
|
|
2194
2427
|
columns: [orderColumnName]
|
|
2195
2428
|
});
|
|
2196
2429
|
joinTable.orderColumnName = orderColumnName;
|
|
@@ -2205,7 +2438,7 @@ const createJoinTable = (metadata, { attributeName, attribute, meta }) => {
|
|
|
2205
2438
|
}
|
|
2206
2439
|
};
|
|
2207
2440
|
metadataSchema.indexes.push({
|
|
2208
|
-
name:
|
|
2441
|
+
name: getOrderInverseFkIndexName(joinTableName),
|
|
2209
2442
|
columns: [inverseOrderColumnName]
|
|
2210
2443
|
});
|
|
2211
2444
|
joinTable.inverseOrderColumnName = inverseOrderColumnName;
|
|
@@ -2286,207 +2519,60 @@ class Metadata extends Map {
|
|
|
2286
2519
|
seenTables.set(meta.tableName, true);
|
|
2287
2520
|
}
|
|
2288
2521
|
}
|
|
2289
|
-
|
|
2290
|
-
const
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
}
|
|
2296
|
-
metadata.add({
|
|
2297
|
-
...model,
|
|
2298
|
-
attributes: {
|
|
2299
|
-
id: {
|
|
2300
|
-
type: "increments"
|
|
2522
|
+
loadModels(models = []) {
|
|
2523
|
+
for (const model of ___default.default.cloneDeep(models)) {
|
|
2524
|
+
this.add({
|
|
2525
|
+
...model,
|
|
2526
|
+
attributes: {
|
|
2527
|
+
...model.attributes
|
|
2301
2528
|
},
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
columnToAttribute: {}
|
|
2308
|
-
});
|
|
2309
|
-
}
|
|
2310
|
-
for (const meta of metadata.values()) {
|
|
2311
|
-
if (hasComponentsOrDz(meta)) {
|
|
2312
|
-
const compoLinkModelMeta = createCompoLinkModelMeta(meta);
|
|
2313
|
-
meta.componentLink = compoLinkModelMeta;
|
|
2314
|
-
metadata.add(compoLinkModelMeta);
|
|
2529
|
+
lifecycles: model.lifecycles ?? {},
|
|
2530
|
+
indexes: model.indexes ?? [],
|
|
2531
|
+
foreignKeys: model.foreignKeys ?? [],
|
|
2532
|
+
columnToAttribute: {}
|
|
2533
|
+
});
|
|
2315
2534
|
}
|
|
2316
|
-
for (const
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
createAttribute(attributeName, attribute);
|
|
2331
|
-
} catch (error) {
|
|
2332
|
-
console.log(error);
|
|
2333
|
-
if (error instanceof Error) {
|
|
2334
|
-
throw new Error(
|
|
2335
|
-
`Error on attribute ${attributeName} in model ${meta.singularName}(${meta.uid}): ${error.message}`
|
|
2336
|
-
);
|
|
2535
|
+
for (const meta of this.values()) {
|
|
2536
|
+
for (const [attributeName, attribute] of Object.entries(meta.attributes)) {
|
|
2537
|
+
try {
|
|
2538
|
+
if (isRelationalAttribute(attribute)) {
|
|
2539
|
+
createRelation(attributeName, attribute, meta, this);
|
|
2540
|
+
continue;
|
|
2541
|
+
}
|
|
2542
|
+
createAttribute(attributeName, attribute);
|
|
2543
|
+
} catch (error) {
|
|
2544
|
+
if (error instanceof Error) {
|
|
2545
|
+
throw new Error(
|
|
2546
|
+
`Error on attribute ${attributeName} in model ${meta.singularName}(${meta.uid}): ${error.message}`
|
|
2547
|
+
);
|
|
2548
|
+
}
|
|
2337
2549
|
}
|
|
2338
2550
|
}
|
|
2339
2551
|
}
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
return Object.assign(acc, { [attribute.columnName || key]: key });
|
|
2346
|
-
}
|
|
2347
|
-
return Object.assign(acc, { [key]: key });
|
|
2348
|
-
}, {});
|
|
2349
|
-
meta.columnToAttribute = columnToAttribute;
|
|
2350
|
-
}
|
|
2351
|
-
metadata.validate();
|
|
2352
|
-
return metadata;
|
|
2353
|
-
};
|
|
2354
|
-
const hasComponentsOrDz = (model) => {
|
|
2355
|
-
return Object.values(model.attributes).some(
|
|
2356
|
-
({ type }) => isComponent(type) || isDynamicZone(type)
|
|
2357
|
-
);
|
|
2358
|
-
};
|
|
2359
|
-
const createCompoLinkModelMeta = (baseModelMeta) => {
|
|
2360
|
-
const name = `${baseModelMeta.tableName}_components`;
|
|
2361
|
-
return {
|
|
2362
|
-
// TODO: make sure there can't be any conflicts with a prefix
|
|
2363
|
-
singularName: name,
|
|
2364
|
-
uid: name,
|
|
2365
|
-
tableName: name,
|
|
2366
|
-
attributes: {
|
|
2367
|
-
id: {
|
|
2368
|
-
type: "increments"
|
|
2369
|
-
},
|
|
2370
|
-
entity_id: {
|
|
2371
|
-
type: "integer",
|
|
2372
|
-
column: {
|
|
2373
|
-
unsigned: true
|
|
2374
|
-
}
|
|
2375
|
-
},
|
|
2376
|
-
component_id: {
|
|
2377
|
-
type: "integer",
|
|
2378
|
-
column: {
|
|
2379
|
-
unsigned: true
|
|
2380
|
-
}
|
|
2381
|
-
},
|
|
2382
|
-
component_type: {
|
|
2383
|
-
type: "string"
|
|
2384
|
-
},
|
|
2385
|
-
field: {
|
|
2386
|
-
type: "string"
|
|
2387
|
-
},
|
|
2388
|
-
order: {
|
|
2389
|
-
type: "float",
|
|
2390
|
-
column: {
|
|
2391
|
-
unsigned: true,
|
|
2392
|
-
defaultTo: null
|
|
2552
|
+
for (const meta of this.values()) {
|
|
2553
|
+
const columnToAttribute = Object.keys(meta.attributes).reduce((acc, key) => {
|
|
2554
|
+
const attribute = meta.attributes[key];
|
|
2555
|
+
if ("columnName" in attribute) {
|
|
2556
|
+
return Object.assign(acc, { [attribute.columnName || key]: key });
|
|
2393
2557
|
}
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
{
|
|
2398
|
-
name: `${baseModelMeta.tableName}_field_index`,
|
|
2399
|
-
columns: ["field"]
|
|
2400
|
-
},
|
|
2401
|
-
{
|
|
2402
|
-
name: `${baseModelMeta.tableName}_component_type_index`,
|
|
2403
|
-
columns: ["component_type"]
|
|
2404
|
-
},
|
|
2405
|
-
{
|
|
2406
|
-
name: `${baseModelMeta.tableName}_entity_fk`,
|
|
2407
|
-
columns: ["entity_id"]
|
|
2408
|
-
},
|
|
2409
|
-
{
|
|
2410
|
-
name: `${baseModelMeta.tableName}_unique`,
|
|
2411
|
-
columns: ["entity_id", "component_id", "field", "component_type"],
|
|
2412
|
-
type: "unique"
|
|
2413
|
-
}
|
|
2414
|
-
],
|
|
2415
|
-
foreignKeys: [
|
|
2416
|
-
{
|
|
2417
|
-
name: `${baseModelMeta.tableName}_entity_fk`,
|
|
2418
|
-
columns: ["entity_id"],
|
|
2419
|
-
referencedColumns: ["id"],
|
|
2420
|
-
referencedTable: baseModelMeta.tableName,
|
|
2421
|
-
onDelete: "CASCADE"
|
|
2422
|
-
}
|
|
2423
|
-
],
|
|
2424
|
-
lifecycles: {},
|
|
2425
|
-
columnToAttribute: {}
|
|
2426
|
-
};
|
|
2427
|
-
};
|
|
2428
|
-
const createDynamicZone = (attributeName, attribute, meta) => {
|
|
2429
|
-
Object.assign(attribute, {
|
|
2430
|
-
type: "relation",
|
|
2431
|
-
relation: "morphToMany",
|
|
2432
|
-
// TODO: handle restrictions at some point
|
|
2433
|
-
// target: attribute.components,
|
|
2434
|
-
joinTable: {
|
|
2435
|
-
name: meta.componentLink.tableName,
|
|
2436
|
-
joinColumn: {
|
|
2437
|
-
name: "entity_id",
|
|
2438
|
-
referencedColumn: "id"
|
|
2439
|
-
},
|
|
2440
|
-
morphColumn: {
|
|
2441
|
-
idColumn: {
|
|
2442
|
-
name: "component_id",
|
|
2443
|
-
referencedColumn: "id"
|
|
2444
|
-
},
|
|
2445
|
-
typeColumn: {
|
|
2446
|
-
name: "component_type"
|
|
2447
|
-
},
|
|
2448
|
-
typeField: "__component"
|
|
2449
|
-
},
|
|
2450
|
-
on: {
|
|
2451
|
-
field: attributeName
|
|
2452
|
-
},
|
|
2453
|
-
orderBy: {
|
|
2454
|
-
order: "asc"
|
|
2455
|
-
},
|
|
2456
|
-
pivotColumns: ["entity_id", "component_id", "field", "component_type"]
|
|
2457
|
-
}
|
|
2458
|
-
});
|
|
2459
|
-
};
|
|
2460
|
-
const createComponent = (attributeName, attribute, meta) => {
|
|
2461
|
-
Object.assign(attribute, {
|
|
2462
|
-
type: "relation",
|
|
2463
|
-
relation: "repeatable" in attribute && attribute.repeatable === true ? "oneToMany" : "oneToOne",
|
|
2464
|
-
target: "component" in attribute && attribute.component,
|
|
2465
|
-
joinTable: {
|
|
2466
|
-
name: meta.componentLink.tableName,
|
|
2467
|
-
joinColumn: {
|
|
2468
|
-
name: "entity_id",
|
|
2469
|
-
referencedColumn: "id"
|
|
2470
|
-
},
|
|
2471
|
-
inverseJoinColumn: {
|
|
2472
|
-
name: "component_id",
|
|
2473
|
-
referencedColumn: "id"
|
|
2474
|
-
},
|
|
2475
|
-
on: {
|
|
2476
|
-
field: attributeName
|
|
2477
|
-
},
|
|
2478
|
-
orderColumnName: "order",
|
|
2479
|
-
orderBy: {
|
|
2480
|
-
order: "asc"
|
|
2481
|
-
},
|
|
2482
|
-
pivotColumns: ["entity_id", "component_id", "field", "component_type"]
|
|
2558
|
+
return Object.assign(acc, { [key]: key });
|
|
2559
|
+
}, {});
|
|
2560
|
+
meta.columnToAttribute = columnToAttribute;
|
|
2483
2561
|
}
|
|
2484
|
-
|
|
2485
|
-
}
|
|
2562
|
+
this.validate();
|
|
2563
|
+
}
|
|
2564
|
+
}
|
|
2486
2565
|
const createAttribute = (attributeName, attribute) => {
|
|
2487
|
-
const columnName =
|
|
2566
|
+
const columnName = getColumnName(attributeName);
|
|
2488
2567
|
Object.assign(attribute, { columnName });
|
|
2489
2568
|
};
|
|
2569
|
+
const createMetadata = (models = []) => {
|
|
2570
|
+
const metadata = new Metadata();
|
|
2571
|
+
if (models.length) {
|
|
2572
|
+
metadata.loadModels(models);
|
|
2573
|
+
}
|
|
2574
|
+
return metadata;
|
|
2575
|
+
};
|
|
2490
2576
|
class Field {
|
|
2491
2577
|
config;
|
|
2492
2578
|
constructor(config) {
|
|
@@ -3458,7 +3544,7 @@ const castValue = (value, attribute) => {
|
|
|
3458
3544
|
};
|
|
3459
3545
|
const processSingleAttributeWhere = (attribute, where, operator = "$eq") => {
|
|
3460
3546
|
if (!isRecord$1(where)) {
|
|
3461
|
-
if (utils.isOperatorOfType("cast", operator)) {
|
|
3547
|
+
if (utils$1.isOperatorOfType("cast", operator)) {
|
|
3462
3548
|
return castValue(where, attribute);
|
|
3463
3549
|
}
|
|
3464
3550
|
return where;
|
|
@@ -3466,7 +3552,7 @@ const processSingleAttributeWhere = (attribute, where, operator = "$eq") => {
|
|
|
3466
3552
|
const filters = {};
|
|
3467
3553
|
for (const key of Object.keys(where)) {
|
|
3468
3554
|
const value = where[key];
|
|
3469
|
-
if (!utils.isOperatorOfType("where", key)) {
|
|
3555
|
+
if (!utils$1.isOperatorOfType("where", key)) {
|
|
3470
3556
|
throw new Error(`Undefined attribute level operator ${key}`);
|
|
3471
3557
|
}
|
|
3472
3558
|
filters[key] = processAttributeWhere(attribute, value, key);
|
|
@@ -3497,7 +3583,7 @@ function processWhere(where, ctx) {
|
|
|
3497
3583
|
const filters = {};
|
|
3498
3584
|
for (const key of Object.keys(where)) {
|
|
3499
3585
|
const value = where[key];
|
|
3500
|
-
if (utils.isOperatorOfType("group", key) && Array.isArray(value)) {
|
|
3586
|
+
if (utils$1.isOperatorOfType("group", key) && Array.isArray(value)) {
|
|
3501
3587
|
filters[key] = value.map((sub) => processNested(sub, ctx));
|
|
3502
3588
|
continue;
|
|
3503
3589
|
}
|
|
@@ -3505,7 +3591,7 @@ function processWhere(where, ctx) {
|
|
|
3505
3591
|
filters[key] = processNested(value, ctx);
|
|
3506
3592
|
continue;
|
|
3507
3593
|
}
|
|
3508
|
-
if (utils.isOperatorOfType("where", key)) {
|
|
3594
|
+
if (utils$1.isOperatorOfType("where", key)) {
|
|
3509
3595
|
throw new Error(
|
|
3510
3596
|
`Only $and, $or and $not can only be used as root level operators. Found ${key}.`
|
|
3511
3597
|
);
|
|
@@ -3527,7 +3613,7 @@ function processWhere(where, ctx) {
|
|
|
3527
3613
|
alias: subAlias,
|
|
3528
3614
|
uid: attribute.target
|
|
3529
3615
|
});
|
|
3530
|
-
if (!isRecord$1(nestedWhere) || utils.isOperatorOfType("where", _.keys(nestedWhere)[0])) {
|
|
3616
|
+
if (!isRecord$1(nestedWhere) || utils$1.isOperatorOfType("where", _.keys(nestedWhere)[0])) {
|
|
3531
3617
|
nestedWhere = { [qb.aliasColumn("id", subAlias)]: nestedWhere };
|
|
3532
3618
|
}
|
|
3533
3619
|
Object.assign(filters, nestedWhere);
|
|
@@ -3544,7 +3630,7 @@ function processWhere(where, ctx) {
|
|
|
3544
3630
|
return filters;
|
|
3545
3631
|
}
|
|
3546
3632
|
const applyOperator = (qb, column, operator, value) => {
|
|
3547
|
-
if (Array.isArray(value) && !utils.isOperatorOfType("array", operator)) {
|
|
3633
|
+
if (Array.isArray(value) && !utils$1.isOperatorOfType("array", operator)) {
|
|
3548
3634
|
return qb.where((subQB) => {
|
|
3549
3635
|
value.forEach(
|
|
3550
3636
|
(subValue) => subQB.orWhere((innerQB) => {
|
|
@@ -4343,9 +4429,6 @@ const createRepository = (uid, db) => {
|
|
|
4343
4429
|
updateMany(params) {
|
|
4344
4430
|
return db.entityManager.updateMany(uid, params);
|
|
4345
4431
|
},
|
|
4346
|
-
clone(id, params) {
|
|
4347
|
-
return db.entityManager.clone(uid, id, params);
|
|
4348
|
-
},
|
|
4349
4432
|
delete(params) {
|
|
4350
4433
|
return db.entityManager.delete(uid, params);
|
|
4351
4434
|
},
|
|
@@ -4371,9 +4454,6 @@ const createRepository = (uid, db) => {
|
|
|
4371
4454
|
deleteRelations(id) {
|
|
4372
4455
|
return db.entityManager.deleteRelations(uid, id);
|
|
4373
4456
|
},
|
|
4374
|
-
cloneRelations(targetId, sourceId, params) {
|
|
4375
|
-
return db.entityManager.cloneRelations(uid, targetId, sourceId, params);
|
|
4376
|
-
},
|
|
4377
4457
|
populate(entity, populate) {
|
|
4378
4458
|
return db.entityManager.populate(uid, entity, populate);
|
|
4379
4459
|
},
|
|
@@ -4449,6 +4529,19 @@ const deleteRelatedMorphOneRelationsAfterMorphToManyUpdate = async (rows, {
|
|
|
4449
4529
|
await createQueryBuilder(joinTable.name, db).delete().where({ $or: orWhere }).transacting(trx).execute();
|
|
4450
4530
|
}
|
|
4451
4531
|
};
|
|
4532
|
+
const getDocumentSiblingIdsQuery = (con, tableName, id) => {
|
|
4533
|
+
const models = Array.from(strapi.db.metadata.values());
|
|
4534
|
+
const isContentType = models.find((model) => {
|
|
4535
|
+
return model.tableName === tableName && model.attributes.documentId;
|
|
4536
|
+
});
|
|
4537
|
+
if (!isContentType) {
|
|
4538
|
+
return [id];
|
|
4539
|
+
}
|
|
4540
|
+
return con.from(tableName).select("id").where(
|
|
4541
|
+
"document_id",
|
|
4542
|
+
con.from(tableName).select("document_id").where("id", id)
|
|
4543
|
+
);
|
|
4544
|
+
};
|
|
4452
4545
|
const deletePreviousOneToAnyRelations = async ({
|
|
4453
4546
|
id,
|
|
4454
4547
|
attribute,
|
|
@@ -4463,10 +4556,8 @@ const deletePreviousOneToAnyRelations = async ({
|
|
|
4463
4556
|
}
|
|
4464
4557
|
const { joinTable } = attribute;
|
|
4465
4558
|
const { joinColumn, inverseJoinColumn } = joinTable;
|
|
4466
|
-
|
|
4467
|
-
|
|
4468
|
-
[joinColumn.name]: { $ne: id }
|
|
4469
|
-
}).where(joinTable.on || {}).transacting(trx).execute();
|
|
4559
|
+
const con = db.getConnection();
|
|
4560
|
+
await con.delete().from(joinTable.name).whereNotIn(joinColumn.name, getDocumentSiblingIdsQuery(con, joinColumn.referencedTable, id)).whereIn(inverseJoinColumn.name, relIdsToadd).where(joinTable.on || {}).transacting(trx);
|
|
4470
4561
|
await cleanOrderColumns({ attribute, db, inverseRelIds: relIdsToadd, transaction: trx });
|
|
4471
4562
|
};
|
|
4472
4563
|
const deletePreviousAnyToOneRelations = async ({
|
|
@@ -4478,14 +4569,15 @@ const deletePreviousAnyToOneRelations = async ({
|
|
|
4478
4569
|
}) => {
|
|
4479
4570
|
const { joinTable } = attribute;
|
|
4480
4571
|
const { joinColumn, inverseJoinColumn } = joinTable;
|
|
4572
|
+
const con = db.getConnection();
|
|
4481
4573
|
if (!isAnyToOne(attribute)) {
|
|
4482
4574
|
throw new Error("deletePreviousAnyToOneRelations can only be called for anyToOne relations");
|
|
4483
4575
|
}
|
|
4484
4576
|
if (isManyToAny(attribute)) {
|
|
4485
|
-
const relsToDelete = await
|
|
4486
|
-
|
|
4487
|
-
|
|
4488
|
-
|
|
4577
|
+
const relsToDelete = await con.select(inverseJoinColumn.name).from(joinTable.name).where(joinColumn.name, id).whereNotIn(
|
|
4578
|
+
inverseJoinColumn.name,
|
|
4579
|
+
getDocumentSiblingIdsQuery(con, inverseJoinColumn.referencedTable, relIdToadd)
|
|
4580
|
+
).where(joinTable.on || {}).transacting(trx);
|
|
4489
4581
|
const relIdsToDelete = _.map(inverseJoinColumn.name, relsToDelete);
|
|
4490
4582
|
await createQueryBuilder(joinTable.name, db).delete().where({
|
|
4491
4583
|
[joinColumn.name]: id,
|
|
@@ -4493,10 +4585,10 @@ const deletePreviousAnyToOneRelations = async ({
|
|
|
4493
4585
|
}).where(joinTable.on || {}).transacting(trx).execute();
|
|
4494
4586
|
await cleanOrderColumns({ attribute, db, inverseRelIds: relIdsToDelete, transaction: trx });
|
|
4495
4587
|
} else {
|
|
4496
|
-
await
|
|
4497
|
-
|
|
4498
|
-
|
|
4499
|
-
|
|
4588
|
+
await con.delete().from(joinTable.name).where(joinColumn.name, id).whereNotIn(
|
|
4589
|
+
inverseJoinColumn.name,
|
|
4590
|
+
getDocumentSiblingIdsQuery(con, inverseJoinColumn.referencedTable, relIdToadd)
|
|
4591
|
+
).where(joinTable.on || {}).transacting(trx);
|
|
4500
4592
|
}
|
|
4501
4593
|
};
|
|
4502
4594
|
const deleteRelations = async ({
|
|
@@ -4548,10 +4640,6 @@ const cleanOrderColumns = async ({
|
|
|
4548
4640
|
if (!(hasOrderColumn(attribute) && id) && !(hasInverseOrderColumn(attribute) && !_.isEmpty(inverseRelIds))) {
|
|
4549
4641
|
return;
|
|
4550
4642
|
}
|
|
4551
|
-
if (!strapi.db.dialect.supportsWindowFunctions()) {
|
|
4552
|
-
await cleanOrderColumnsForOldDatabases({ id, attribute, db, inverseRelIds, transaction: trx });
|
|
4553
|
-
return;
|
|
4554
|
-
}
|
|
4555
4643
|
const { joinTable } = attribute;
|
|
4556
4644
|
const { joinColumn, inverseJoinColumn, orderColumnName, inverseOrderColumnName } = joinTable;
|
|
4557
4645
|
const updateOrderColumn = async () => {
|
|
@@ -4613,94 +4701,6 @@ const cleanOrderColumns = async ({
|
|
|
4613
4701
|
};
|
|
4614
4702
|
return Promise.all([updateOrderColumn(), updateInverseOrderColumn()]);
|
|
4615
4703
|
};
|
|
4616
|
-
const cleanOrderColumnsForOldDatabases = async ({
|
|
4617
|
-
id,
|
|
4618
|
-
attribute,
|
|
4619
|
-
db,
|
|
4620
|
-
inverseRelIds,
|
|
4621
|
-
transaction: trx
|
|
4622
|
-
}) => {
|
|
4623
|
-
const { joinTable } = attribute;
|
|
4624
|
-
const { joinColumn, inverseJoinColumn, orderColumnName, inverseOrderColumnName } = joinTable;
|
|
4625
|
-
const randomSuffix = `${(/* @__PURE__ */ new Date()).valueOf()}_${crypto.randomBytes(16).toString("hex")}`;
|
|
4626
|
-
if (hasOrderColumn(attribute) && id) {
|
|
4627
|
-
const orderVar = `order_${randomSuffix}`;
|
|
4628
|
-
await db.connection.raw(`SET @${orderVar} = 0;`).transacting(trx);
|
|
4629
|
-
await db.connection.raw(
|
|
4630
|
-
`UPDATE :joinTableName: as a, (
|
|
4631
|
-
SELECT id, (@${orderVar}:=@${orderVar} + 1) AS src_order
|
|
4632
|
-
FROM :joinTableName:
|
|
4633
|
-
WHERE :joinColumnName: = :id
|
|
4634
|
-
ORDER BY :orderColumnName:
|
|
4635
|
-
) AS b
|
|
4636
|
-
SET :orderColumnName: = b.src_order
|
|
4637
|
-
WHERE a.id = b.id
|
|
4638
|
-
AND a.:joinColumnName: = :id`,
|
|
4639
|
-
{
|
|
4640
|
-
joinTableName: joinTable.name,
|
|
4641
|
-
orderColumnName,
|
|
4642
|
-
joinColumnName: joinColumn.name,
|
|
4643
|
-
id
|
|
4644
|
-
}
|
|
4645
|
-
).transacting(trx);
|
|
4646
|
-
}
|
|
4647
|
-
if (hasInverseOrderColumn(attribute) && !_.isEmpty(inverseRelIds)) {
|
|
4648
|
-
const orderVar = `order_${randomSuffix}`;
|
|
4649
|
-
const columnVar = `col_${randomSuffix}`;
|
|
4650
|
-
await db.connection.raw(`SET @${orderVar} = 0;`).transacting(trx);
|
|
4651
|
-
await db.connection.raw(
|
|
4652
|
-
`UPDATE ?? as a, (
|
|
4653
|
-
SELECT
|
|
4654
|
-
id,
|
|
4655
|
-
@${orderVar}:=CASE WHEN @${columnVar} = ?? THEN @${orderVar} + 1 ELSE 1 END AS inv_order,
|
|
4656
|
-
@${columnVar}:=?? ??
|
|
4657
|
-
FROM ?? a
|
|
4658
|
-
WHERE ?? IN(${inverseRelIds.map(() => "?").join(", ")})
|
|
4659
|
-
ORDER BY ??, ??
|
|
4660
|
-
) AS b
|
|
4661
|
-
SET ?? = b.inv_order
|
|
4662
|
-
WHERE a.id = b.id
|
|
4663
|
-
AND a.?? IN(${inverseRelIds.map(() => "?").join(", ")})`,
|
|
4664
|
-
[
|
|
4665
|
-
joinTable.name,
|
|
4666
|
-
inverseJoinColumn.name,
|
|
4667
|
-
inverseJoinColumn.name,
|
|
4668
|
-
inverseJoinColumn.name,
|
|
4669
|
-
joinTable.name,
|
|
4670
|
-
inverseJoinColumn.name,
|
|
4671
|
-
...inverseRelIds,
|
|
4672
|
-
inverseJoinColumn.name,
|
|
4673
|
-
joinColumn.name,
|
|
4674
|
-
inverseOrderColumnName,
|
|
4675
|
-
inverseJoinColumn.name,
|
|
4676
|
-
...inverseRelIds
|
|
4677
|
-
]
|
|
4678
|
-
).transacting(trx);
|
|
4679
|
-
}
|
|
4680
|
-
};
|
|
4681
|
-
const cleanInverseOrderColumn = async ({
|
|
4682
|
-
id,
|
|
4683
|
-
attribute,
|
|
4684
|
-
trx
|
|
4685
|
-
}) => {
|
|
4686
|
-
const con = strapi.db.connection;
|
|
4687
|
-
const { joinTable } = attribute;
|
|
4688
|
-
const { joinColumn, inverseJoinColumn, inverseOrderColumnName } = joinTable;
|
|
4689
|
-
switch (strapi.db.dialect.client) {
|
|
4690
|
-
case "mysql": {
|
|
4691
|
-
const subQuery = con(joinTable.name).select(inverseJoinColumn.name).max(inverseOrderColumnName, { as: "max_inv_order" }).groupBy(inverseJoinColumn.name).as("t2");
|
|
4692
|
-
await con(`${joinTable.name} as t1`).join(subQuery, `t1.${inverseJoinColumn.name}`, "=", `t2.${inverseJoinColumn.name}`).where(joinColumn.name, id).update({
|
|
4693
|
-
[inverseOrderColumnName]: con.raw("t2.max_inv_order + 1")
|
|
4694
|
-
}).transacting(trx);
|
|
4695
|
-
break;
|
|
4696
|
-
}
|
|
4697
|
-
default: {
|
|
4698
|
-
const selectMaxInverseOrder = con.raw(`max(${inverseOrderColumnName}) + 1`);
|
|
4699
|
-
const subQuery = con(`${joinTable.name} as t2`).select(selectMaxInverseOrder).whereRaw(`t2.${inverseJoinColumn.name} = t1.${inverseJoinColumn.name}`);
|
|
4700
|
-
await con(`${joinTable.name} as t1`).where(`t1.${joinColumn.name}`, id).update({ [inverseOrderColumnName]: subQuery }).transacting(trx);
|
|
4701
|
-
}
|
|
4702
|
-
}
|
|
4703
|
-
};
|
|
4704
4704
|
const sortConnectArray = (connectArr, initialArr = [], strictSort = true) => {
|
|
4705
4705
|
const sortedConnect = [];
|
|
4706
4706
|
let needsSorting = false;
|
|
@@ -4841,55 +4841,6 @@ const relationsOrderer = (initArr, idColumn, orderColumn, strict) => {
|
|
|
4841
4841
|
}
|
|
4842
4842
|
};
|
|
4843
4843
|
};
|
|
4844
|
-
const replaceRegularRelations = async ({
|
|
4845
|
-
targetId,
|
|
4846
|
-
sourceId,
|
|
4847
|
-
attribute,
|
|
4848
|
-
omitIds,
|
|
4849
|
-
transaction: trx
|
|
4850
|
-
}) => {
|
|
4851
|
-
const { joinTable } = attribute;
|
|
4852
|
-
const { joinColumn, inverseJoinColumn } = joinTable;
|
|
4853
|
-
await strapi.db.entityManager.createQueryBuilder(joinTable.name).update({ [joinColumn.name]: targetId }).where({ [joinColumn.name]: sourceId }).where({ $not: { [inverseJoinColumn.name]: omitIds } }).onConflict([joinColumn.name, inverseJoinColumn.name]).ignore().transacting(trx).execute();
|
|
4854
|
-
};
|
|
4855
|
-
const cloneRegularRelations = async ({
|
|
4856
|
-
targetId,
|
|
4857
|
-
sourceId,
|
|
4858
|
-
attribute,
|
|
4859
|
-
transaction: trx
|
|
4860
|
-
}) => {
|
|
4861
|
-
const { joinTable } = attribute;
|
|
4862
|
-
const { joinColumn, inverseJoinColumn, orderColumnName, inverseOrderColumnName } = joinTable;
|
|
4863
|
-
const connection = strapi.db.getConnection();
|
|
4864
|
-
const columns = [joinColumn.name, inverseJoinColumn.name];
|
|
4865
|
-
if (orderColumnName) {
|
|
4866
|
-
columns.push(orderColumnName);
|
|
4867
|
-
}
|
|
4868
|
-
if (inverseOrderColumnName) {
|
|
4869
|
-
columns.push(inverseOrderColumnName);
|
|
4870
|
-
}
|
|
4871
|
-
if (joinTable.on) {
|
|
4872
|
-
columns.push(...Object.keys(joinTable.on));
|
|
4873
|
-
}
|
|
4874
|
-
const selectStatement = connection.select(
|
|
4875
|
-
// Override joinColumn with the new id
|
|
4876
|
-
{ [joinColumn.name]: targetId },
|
|
4877
|
-
...columns.slice(1)
|
|
4878
|
-
).where(joinColumn.name, sourceId).from(joinTable.name).toSQL();
|
|
4879
|
-
await strapi.db.entityManager.createQueryBuilder(joinTable.name).insert(
|
|
4880
|
-
strapi.db.connection.raw(
|
|
4881
|
-
`(${columns.join(",")}) ${selectStatement.sql}`,
|
|
4882
|
-
selectStatement.bindings
|
|
4883
|
-
)
|
|
4884
|
-
).onConflict([joinColumn.name, inverseJoinColumn.name]).ignore().transacting(trx).execute();
|
|
4885
|
-
if (inverseOrderColumnName) {
|
|
4886
|
-
await cleanInverseOrderColumn({
|
|
4887
|
-
id: targetId,
|
|
4888
|
-
attribute,
|
|
4889
|
-
trx
|
|
4890
|
-
});
|
|
4891
|
-
}
|
|
4892
|
-
};
|
|
4893
4844
|
const isRecord = (value) => _.isObject(value) && !_.isNil(value);
|
|
4894
4845
|
const toId = (value) => {
|
|
4895
4846
|
if (isRecord(value) && "id" in value && isValidId(value.id)) {
|
|
@@ -5039,7 +4990,8 @@ const createEntityManager = (db) => {
|
|
|
5039
4990
|
const result = await this.findOne(uid, {
|
|
5040
4991
|
where: { id },
|
|
5041
4992
|
select: params.select,
|
|
5042
|
-
populate: params.populate
|
|
4993
|
+
populate: params.populate,
|
|
4994
|
+
filters: params.filters
|
|
5043
4995
|
});
|
|
5044
4996
|
await db.lifecycles.run("afterCreate", uid, { params, result }, states);
|
|
5045
4997
|
return result;
|
|
@@ -5097,7 +5049,8 @@ const createEntityManager = (db) => {
|
|
|
5097
5049
|
const result = await this.findOne(uid, {
|
|
5098
5050
|
where: { id },
|
|
5099
5051
|
select: params.select,
|
|
5100
|
-
populate: params.populate
|
|
5052
|
+
populate: params.populate,
|
|
5053
|
+
filters: params.filters
|
|
5101
5054
|
});
|
|
5102
5055
|
await db.lifecycles.run("afterUpdate", uid, { params, result }, states);
|
|
5103
5056
|
return result;
|
|
@@ -5116,50 +5069,6 @@ const createEntityManager = (db) => {
|
|
|
5116
5069
|
await db.lifecycles.run("afterUpdateMany", uid, { params, result }, states);
|
|
5117
5070
|
return result;
|
|
5118
5071
|
},
|
|
5119
|
-
async clone(uid, cloneId, params = {}) {
|
|
5120
|
-
const states = await db.lifecycles.run("beforeCreate", uid, { params });
|
|
5121
|
-
const metadata = db.metadata.get(uid);
|
|
5122
|
-
const { data } = params;
|
|
5123
|
-
if (!_.isNil(data) && !_.isPlainObject(data)) {
|
|
5124
|
-
throw new Error("Create expects a data object");
|
|
5125
|
-
}
|
|
5126
|
-
const entity = await this.findOne(uid, { where: { id: cloneId } });
|
|
5127
|
-
const dataToInsert = _.flow(
|
|
5128
|
-
// Omit unwanted properties
|
|
5129
|
-
_.omit(["id", "created_at", "updated_at"]),
|
|
5130
|
-
// Merge with provided data, set attribute to null if data attribute is null
|
|
5131
|
-
_.mergeWith(
|
|
5132
|
-
data || {},
|
|
5133
|
-
(original, override) => override === null ? override : original
|
|
5134
|
-
),
|
|
5135
|
-
// Process data with metadata
|
|
5136
|
-
(entity2) => processData(metadata, entity2, { withDefaults: true })
|
|
5137
|
-
)(entity);
|
|
5138
|
-
const res = await this.createQueryBuilder(uid).insert(dataToInsert).execute();
|
|
5139
|
-
const id = isRecord(res[0]) ? res[0].id : res[0];
|
|
5140
|
-
const trx = await strapi.db.transaction();
|
|
5141
|
-
try {
|
|
5142
|
-
const cloneAttrs = Object.entries(metadata.attributes).reduce((acc, [attrName, attr]) => {
|
|
5143
|
-
if (isRelationalAttribute(attr) && "joinTable" in attr && attr.joinTable && !("component" in attr)) {
|
|
5144
|
-
acc.push(attrName);
|
|
5145
|
-
}
|
|
5146
|
-
return acc;
|
|
5147
|
-
}, []);
|
|
5148
|
-
await this.cloneRelations(uid, id, cloneId, data, { cloneAttrs, transaction: trx.get() });
|
|
5149
|
-
await trx.commit();
|
|
5150
|
-
} catch (e) {
|
|
5151
|
-
await trx.rollback();
|
|
5152
|
-
await this.createQueryBuilder(uid).where({ id }).delete().execute();
|
|
5153
|
-
throw e;
|
|
5154
|
-
}
|
|
5155
|
-
const result = await this.findOne(uid, {
|
|
5156
|
-
where: { id },
|
|
5157
|
-
select: params.select,
|
|
5158
|
-
populate: params.populate
|
|
5159
|
-
});
|
|
5160
|
-
await db.lifecycles.run("afterCreate", uid, { params, result }, states);
|
|
5161
|
-
return result;
|
|
5162
|
-
},
|
|
5163
5072
|
async delete(uid, params = {}) {
|
|
5164
5073
|
const states = await db.lifecycles.run("beforeDelete", uid, { params });
|
|
5165
5074
|
const { where, select, populate } = params;
|
|
@@ -5445,9 +5354,8 @@ const createEntityManager = (db) => {
|
|
|
5445
5354
|
const isPartialUpdate = !_.has("set", cleanRelationData);
|
|
5446
5355
|
let relIdsToaddOrMove;
|
|
5447
5356
|
if (isPartialUpdate) {
|
|
5448
|
-
if (isAnyToOne(attribute))
|
|
5449
|
-
|
|
5450
|
-
}
|
|
5357
|
+
if (isAnyToOne(attribute))
|
|
5358
|
+
;
|
|
5451
5359
|
relIdsToaddOrMove = toIds(cleanRelationData.connect);
|
|
5452
5360
|
const relIdsToDelete = toIds(
|
|
5453
5361
|
_.differenceWith(
|
|
@@ -5661,58 +5569,6 @@ const createEntityManager = (db) => {
|
|
|
5661
5569
|
}
|
|
5662
5570
|
}
|
|
5663
5571
|
},
|
|
5664
|
-
// TODO: Clone polymorphic relations
|
|
5665
|
-
/**
|
|
5666
|
-
*
|
|
5667
|
-
* @param {string} uid - uid of the entity to clone
|
|
5668
|
-
* @param {number} targetId - id of the entity to clone into
|
|
5669
|
-
* @param {number} sourceId - id of the entity to clone from
|
|
5670
|
-
* @param {object} opt
|
|
5671
|
-
* @param {object} opt.cloneAttrs - key value pair of attributes to clone
|
|
5672
|
-
* @param {object} opt.transaction - transaction to use
|
|
5673
|
-
* @example cloneRelations('user', 3, 1, { cloneAttrs: ["comments"]})
|
|
5674
|
-
* @example cloneRelations('post', 5, 2, { cloneAttrs: ["comments", "likes"] })
|
|
5675
|
-
*/
|
|
5676
|
-
async cloneRelations(uid, targetId, sourceId, data, options) {
|
|
5677
|
-
const { attributes } = db.metadata.get(uid);
|
|
5678
|
-
const { cloneAttrs = [], transaction } = options ?? {};
|
|
5679
|
-
if (!attributes) {
|
|
5680
|
-
return;
|
|
5681
|
-
}
|
|
5682
|
-
await utils.mapAsync(cloneAttrs, async (attrName) => {
|
|
5683
|
-
const attribute = attributes[attrName];
|
|
5684
|
-
if (attribute.type !== "relation") {
|
|
5685
|
-
throw new DatabaseError(
|
|
5686
|
-
`Attribute ${attrName} is not a relation attribute. Cloning relations is only supported for relation attributes.`
|
|
5687
|
-
);
|
|
5688
|
-
}
|
|
5689
|
-
if (isPolymorphic(attribute)) {
|
|
5690
|
-
return;
|
|
5691
|
-
}
|
|
5692
|
-
if ("joinColumn" in attribute) {
|
|
5693
|
-
return;
|
|
5694
|
-
}
|
|
5695
|
-
if (!attribute.joinTable) {
|
|
5696
|
-
return;
|
|
5697
|
-
}
|
|
5698
|
-
let omitIds = [];
|
|
5699
|
-
if (_.has(attrName, data)) {
|
|
5700
|
-
const cleanRelationData = toAssocs(data[attrName]);
|
|
5701
|
-
if (cleanRelationData.set) {
|
|
5702
|
-
return;
|
|
5703
|
-
}
|
|
5704
|
-
if (cleanRelationData.disconnect) {
|
|
5705
|
-
omitIds = toIds(cleanRelationData.disconnect);
|
|
5706
|
-
}
|
|
5707
|
-
}
|
|
5708
|
-
if (isOneToAny(attribute) && isBidirectional(attribute)) {
|
|
5709
|
-
await replaceRegularRelations({ targetId, sourceId, attribute, omitIds, transaction });
|
|
5710
|
-
} else {
|
|
5711
|
-
await cloneRegularRelations({ targetId, sourceId, attribute, transaction });
|
|
5712
|
-
}
|
|
5713
|
-
});
|
|
5714
|
-
await this.updateRelations(uid, targetId, data, { transaction });
|
|
5715
|
-
},
|
|
5716
5572
|
// TODO: add lifecycle events
|
|
5717
5573
|
async populate(uid, entity, populate) {
|
|
5718
5574
|
const entry = await this.findOne(uid, {
|
|
@@ -5774,7 +5630,7 @@ const createEntityManager = (db) => {
|
|
|
5774
5630
|
};
|
|
5775
5631
|
};
|
|
5776
5632
|
const createStorage = (opts) => {
|
|
5777
|
-
const { db, tableName
|
|
5633
|
+
const { db, tableName } = opts;
|
|
5778
5634
|
const hasMigrationTable = () => db.getSchemaConnection().hasTable(tableName);
|
|
5779
5635
|
const createMigrationTable = () => {
|
|
5780
5636
|
return db.getSchemaConnection().createTable(tableName, (table) => {
|
|
@@ -5804,7 +5660,7 @@ const createStorage = (opts) => {
|
|
|
5804
5660
|
};
|
|
5805
5661
|
};
|
|
5806
5662
|
const wrapTransaction = (db) => (fn) => () => {
|
|
5807
|
-
return db.connection.transaction((trx) => Promise.resolve(fn(trx)));
|
|
5663
|
+
return db.connection.transaction((trx) => Promise.resolve(fn(trx, db)));
|
|
5808
5664
|
};
|
|
5809
5665
|
const migrationResolver = ({ name, path: path2, context }) => {
|
|
5810
5666
|
const { db } = context;
|
|
@@ -5828,31 +5684,82 @@ const migrationResolver = ({ name, path: path2, context }) => {
|
|
|
5828
5684
|
down: wrapTransaction(db)(migration.down)
|
|
5829
5685
|
};
|
|
5830
5686
|
};
|
|
5831
|
-
const
|
|
5832
|
-
const
|
|
5833
|
-
fse__default.default.ensureDirSync(
|
|
5834
|
-
|
|
5687
|
+
const createUserMigrationProvider = (db) => {
|
|
5688
|
+
const dir = db.config.settings.migrations.dir;
|
|
5689
|
+
fse__default.default.ensureDirSync(dir);
|
|
5690
|
+
const context = { db };
|
|
5691
|
+
const umzugProvider = new umzug.Umzug({
|
|
5835
5692
|
storage: createStorage({ db, tableName: "strapi_migrations" }),
|
|
5836
5693
|
logger: console,
|
|
5837
|
-
context
|
|
5694
|
+
context,
|
|
5838
5695
|
migrations: {
|
|
5839
|
-
glob: ["*.{js,sql}", { cwd:
|
|
5696
|
+
glob: ["*.{js,sql}", { cwd: dir }],
|
|
5840
5697
|
resolve: migrationResolver
|
|
5841
5698
|
}
|
|
5842
5699
|
});
|
|
5700
|
+
return {
|
|
5701
|
+
async shouldRun() {
|
|
5702
|
+
const pendingMigrations = await umzugProvider.pending();
|
|
5703
|
+
return pendingMigrations.length > 0 && db.config?.settings?.runMigrations === true;
|
|
5704
|
+
},
|
|
5705
|
+
async up() {
|
|
5706
|
+
await umzugProvider.up();
|
|
5707
|
+
},
|
|
5708
|
+
async down() {
|
|
5709
|
+
await umzugProvider.down();
|
|
5710
|
+
}
|
|
5711
|
+
};
|
|
5712
|
+
};
|
|
5713
|
+
const internalMigrations = [];
|
|
5714
|
+
const createInternalMigrationProvider = (db) => {
|
|
5715
|
+
const context = { db };
|
|
5716
|
+
const umzugProvider = new umzug.Umzug({
|
|
5717
|
+
storage: createStorage({ db, tableName: "strapi_migrations_internal" }),
|
|
5718
|
+
logger: console,
|
|
5719
|
+
context,
|
|
5720
|
+
migrations: internalMigrations.map((migration) => {
|
|
5721
|
+
return {
|
|
5722
|
+
name: migration.name,
|
|
5723
|
+
up: wrapTransaction(context.db)(migration.up),
|
|
5724
|
+
down: wrapTransaction(context.db)(migration.down)
|
|
5725
|
+
};
|
|
5726
|
+
})
|
|
5727
|
+
});
|
|
5728
|
+
return {
|
|
5729
|
+
async shouldRun() {
|
|
5730
|
+
const pendingMigrations = await umzugProvider.pending();
|
|
5731
|
+
return pendingMigrations.length > 0;
|
|
5732
|
+
},
|
|
5733
|
+
async up() {
|
|
5734
|
+
await umzugProvider.up();
|
|
5735
|
+
},
|
|
5736
|
+
async down() {
|
|
5737
|
+
await umzugProvider.down();
|
|
5738
|
+
}
|
|
5739
|
+
};
|
|
5843
5740
|
};
|
|
5844
5741
|
const createMigrationsProvider = (db) => {
|
|
5845
|
-
const
|
|
5742
|
+
const providers = [createUserMigrationProvider(db), createInternalMigrationProvider(db)];
|
|
5846
5743
|
return {
|
|
5847
5744
|
async shouldRun() {
|
|
5848
|
-
const
|
|
5849
|
-
|
|
5745
|
+
const shouldRunResponses = await Promise.all(
|
|
5746
|
+
providers.map((provider) => provider.shouldRun())
|
|
5747
|
+
);
|
|
5748
|
+
return shouldRunResponses.some((shouldRun) => shouldRun);
|
|
5850
5749
|
},
|
|
5851
5750
|
async up() {
|
|
5852
|
-
|
|
5751
|
+
for (const provider of providers) {
|
|
5752
|
+
if (await provider.shouldRun()) {
|
|
5753
|
+
await provider.up();
|
|
5754
|
+
}
|
|
5755
|
+
}
|
|
5853
5756
|
},
|
|
5854
5757
|
async down() {
|
|
5855
|
-
|
|
5758
|
+
for (const provider of providers) {
|
|
5759
|
+
if (await provider.shouldRun()) {
|
|
5760
|
+
await provider.down();
|
|
5761
|
+
}
|
|
5762
|
+
}
|
|
5856
5763
|
}
|
|
5857
5764
|
};
|
|
5858
5765
|
};
|
|
@@ -5965,82 +5872,41 @@ const createLifecyclesProvider = (db) => {
|
|
|
5965
5872
|
}
|
|
5966
5873
|
};
|
|
5967
5874
|
};
|
|
5968
|
-
class LegacySqliteClient extends SqliteClient__default.default {
|
|
5969
|
-
_driver() {
|
|
5970
|
-
return require("sqlite3");
|
|
5971
|
-
}
|
|
5972
|
-
}
|
|
5973
5875
|
const clientMap = {
|
|
5974
|
-
|
|
5975
|
-
|
|
5976
|
-
|
|
5876
|
+
sqlite: "better-sqlite3",
|
|
5877
|
+
mysql: "mysql2",
|
|
5878
|
+
postgres: "pg"
|
|
5977
5879
|
};
|
|
5978
|
-
|
|
5979
|
-
|
|
5980
|
-
|
|
5981
|
-
|
|
5982
|
-
|
|
5983
|
-
|
|
5984
|
-
|
|
5985
|
-
|
|
5986
|
-
|
|
5987
|
-
|
|
5988
|
-
|
|
5989
|
-
const
|
|
5990
|
-
|
|
5991
|
-
|
|
5992
|
-
|
|
5993
|
-
|
|
5994
|
-
|
|
5995
|
-
|
|
5996
|
-
|
|
5997
|
-
|
|
5998
|
-
|
|
5999
|
-
|
|
6000
|
-
|
|
6001
|
-
if (knexConfig.client === "sqlite") {
|
|
6002
|
-
const sqlitePackageName = getSqlitePackageName();
|
|
6003
|
-
knexConfig.client = clientMap[sqlitePackageName];
|
|
5880
|
+
function isClientValid(config) {
|
|
5881
|
+
return Object.keys(clientMap).includes(config.client);
|
|
5882
|
+
}
|
|
5883
|
+
const createConnection = (userConfig, strapiConfig) => {
|
|
5884
|
+
if (!isClientValid(userConfig)) {
|
|
5885
|
+
throw new Error(`Unsupported database client ${userConfig.client}`);
|
|
5886
|
+
}
|
|
5887
|
+
const knexConfig = { ...userConfig, client: clientMap[userConfig.client] };
|
|
5888
|
+
if (strapiConfig?.pool?.afterCreate) {
|
|
5889
|
+
knexConfig.pool = knexConfig.pool || {};
|
|
5890
|
+
const userAfterCreate = knexConfig.pool?.afterCreate;
|
|
5891
|
+
const strapiAfterCreate = strapiConfig.pool.afterCreate;
|
|
5892
|
+
knexConfig.pool.afterCreate = (conn, done) => {
|
|
5893
|
+
strapiAfterCreate(conn, (err, nativeConn) => {
|
|
5894
|
+
if (err) {
|
|
5895
|
+
return done(err, nativeConn);
|
|
5896
|
+
}
|
|
5897
|
+
if (userAfterCreate) {
|
|
5898
|
+
return userAfterCreate(nativeConn, done);
|
|
5899
|
+
}
|
|
5900
|
+
return done(null, nativeConn);
|
|
5901
|
+
});
|
|
5902
|
+
};
|
|
6004
5903
|
}
|
|
6005
5904
|
return knex__default.default(knexConfig);
|
|
6006
5905
|
};
|
|
6007
|
-
const transformAttribute = (attribute) => {
|
|
6008
|
-
switch (attribute.type) {
|
|
6009
|
-
case "media": {
|
|
6010
|
-
return {
|
|
6011
|
-
type: "relation",
|
|
6012
|
-
relation: attribute.multiple === true ? "morphMany" : "morphOne",
|
|
6013
|
-
target: "plugin::upload.file",
|
|
6014
|
-
morphBy: "related"
|
|
6015
|
-
};
|
|
6016
|
-
}
|
|
6017
|
-
default: {
|
|
6018
|
-
return attribute;
|
|
6019
|
-
}
|
|
6020
|
-
}
|
|
6021
|
-
};
|
|
6022
|
-
const transformContentTypes = (contentTypes) => {
|
|
6023
|
-
return contentTypes.map((contentType) => {
|
|
6024
|
-
const model = {
|
|
6025
|
-
...contentType,
|
|
6026
|
-
// reuse new model def
|
|
6027
|
-
singularName: contentType.modelName,
|
|
6028
|
-
tableName: contentType.collectionName,
|
|
6029
|
-
attributes: {
|
|
6030
|
-
...Object.keys(contentType.attributes || {}).reduce((attrs, attrName) => {
|
|
6031
|
-
return Object.assign(attrs, {
|
|
6032
|
-
[attrName]: transformAttribute(contentType.attributes[attrName])
|
|
6033
|
-
});
|
|
6034
|
-
}, {})
|
|
6035
|
-
}
|
|
6036
|
-
};
|
|
6037
|
-
return model;
|
|
6038
|
-
});
|
|
6039
|
-
};
|
|
6040
5906
|
const getLinksWithoutMappedBy = (db) => {
|
|
6041
5907
|
const relationsToUpdate = {};
|
|
6042
|
-
db.metadata.forEach((
|
|
6043
|
-
const attributes =
|
|
5908
|
+
db.metadata.forEach((modelMetadata) => {
|
|
5909
|
+
const attributes = modelMetadata.attributes;
|
|
6044
5910
|
Object.values(attributes).forEach((attribute) => {
|
|
6045
5911
|
if (attribute.type !== "relation") {
|
|
6046
5912
|
return;
|
|
@@ -6068,19 +5934,19 @@ const isLinkTableEmpty = async (db, linkTableName) => {
|
|
|
6068
5934
|
const validateBidirectionalRelations = async (db) => {
|
|
6069
5935
|
const invalidLinks = getLinksWithoutMappedBy(db);
|
|
6070
5936
|
for (const { relation, invRelation } of invalidLinks) {
|
|
6071
|
-
const
|
|
6072
|
-
const
|
|
6073
|
-
const joinTableName = getJoinTableName(
|
|
6074
|
-
const inverseJoinTableName = getJoinTableName(
|
|
5937
|
+
const modelMetadata = db.metadata.get(invRelation.target);
|
|
5938
|
+
const invModelMetadata = db.metadata.get(relation.target);
|
|
5939
|
+
const joinTableName = getJoinTableName(modelMetadata.tableName, invRelation.inversedBy);
|
|
5940
|
+
const inverseJoinTableName = getJoinTableName(invModelMetadata.tableName, relation.inversedBy);
|
|
6075
5941
|
const joinTableEmpty = await isLinkTableEmpty(db, joinTableName);
|
|
6076
5942
|
const inverseJoinTableEmpty = await isLinkTableEmpty(db, inverseJoinTableName);
|
|
6077
5943
|
if (joinTableEmpty) {
|
|
6078
5944
|
process.emitWarning(
|
|
6079
|
-
`Error on attribute "${invRelation.inversedBy}" in model "${
|
|
5945
|
+
`Error on attribute "${invRelation.inversedBy}" in model "${modelMetadata.singularName}" (${modelMetadata.uid}). Please modify your ${modelMetadata.singularName} schema by renaming the key "inversedBy" to "mappedBy". Ex: { "inversedBy": "${relation.inversedBy}" } -> { "mappedBy": "${relation.inversedBy}" }`
|
|
6080
5946
|
);
|
|
6081
5947
|
} else if (inverseJoinTableEmpty) {
|
|
6082
5948
|
process.emitWarning(
|
|
6083
|
-
`Error on attribute "${relation.inversedBy}" in model "${
|
|
5949
|
+
`Error on attribute "${relation.inversedBy}" in model "${invModelMetadata.singularName}" (${invModelMetadata.uid}). Please modify your ${invModelMetadata.singularName} schema by renaming the key "inversedBy" to "mappedBy". Ex: { "inversedBy": "${invRelation.inversedBy}" } -> { "mappedBy": "${invRelation.inversedBy}" }`
|
|
6084
5950
|
);
|
|
6085
5951
|
} else
|
|
6086
5952
|
;
|
|
@@ -6092,6 +5958,11 @@ const validateRelations = async (db) => {
|
|
|
6092
5958
|
async function validateDatabase(db) {
|
|
6093
5959
|
await validateRelations(db);
|
|
6094
5960
|
}
|
|
5961
|
+
const afterCreate = (db) => (nativeConnection, done) => {
|
|
5962
|
+
db.dialect.initialize(nativeConnection).then(() => {
|
|
5963
|
+
return done(null, nativeConnection);
|
|
5964
|
+
});
|
|
5965
|
+
};
|
|
6095
5966
|
class Database {
|
|
6096
5967
|
connection;
|
|
6097
5968
|
dialect;
|
|
@@ -6101,14 +5972,7 @@ class Database {
|
|
|
6101
5972
|
migrations;
|
|
6102
5973
|
lifecycles;
|
|
6103
5974
|
entityManager;
|
|
6104
|
-
static transformContentTypes = transformContentTypes;
|
|
6105
|
-
static async init(config) {
|
|
6106
|
-
const db = new Database(config);
|
|
6107
|
-
await validateDatabase(db);
|
|
6108
|
-
return db;
|
|
6109
|
-
}
|
|
6110
5975
|
constructor(config) {
|
|
6111
|
-
this.metadata = createMetadata(config.models);
|
|
6112
5976
|
this.config = {
|
|
6113
5977
|
...config,
|
|
6114
5978
|
settings: {
|
|
@@ -6119,13 +5983,20 @@ class Database {
|
|
|
6119
5983
|
};
|
|
6120
5984
|
this.dialect = getDialect(this);
|
|
6121
5985
|
this.dialect.configure();
|
|
6122
|
-
this.
|
|
6123
|
-
this.
|
|
5986
|
+
this.metadata = createMetadata();
|
|
5987
|
+
this.connection = createConnection(this.config.connection, {
|
|
5988
|
+
pool: { afterCreate: afterCreate(this) }
|
|
5989
|
+
});
|
|
6124
5990
|
this.schema = createSchemaProvider(this);
|
|
6125
5991
|
this.migrations = createMigrationsProvider(this);
|
|
6126
5992
|
this.lifecycles = createLifecyclesProvider(this);
|
|
6127
5993
|
this.entityManager = createEntityManager(this);
|
|
6128
5994
|
}
|
|
5995
|
+
async init({ models }) {
|
|
5996
|
+
this.metadata.loadModels(models);
|
|
5997
|
+
await validateDatabase(this);
|
|
5998
|
+
return this;
|
|
5999
|
+
}
|
|
6129
6000
|
query(uid) {
|
|
6130
6001
|
if (!this.metadata.has(uid)) {
|
|
6131
6002
|
throw new Error(`Model ${uid} not found`);
|
|
@@ -6189,7 +6060,9 @@ class Database {
|
|
|
6189
6060
|
await this.connection.destroy();
|
|
6190
6061
|
}
|
|
6191
6062
|
}
|
|
6063
|
+
const utils = { identifiers };
|
|
6192
6064
|
exports.Database = Database;
|
|
6193
6065
|
exports.errors = index;
|
|
6194
6066
|
exports.isKnexQuery = isKnexQuery;
|
|
6067
|
+
exports.utils = utils;
|
|
6195
6068
|
//# sourceMappingURL=index.js.map
|