@strapi/database 4.20.5 → 5.0.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/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.mjs
CHANGED
|
@@ -1,21 +1,19 @@
|
|
|
1
|
-
import semver from "semver";
|
|
2
1
|
import path from "path";
|
|
3
2
|
import fse from "fs-extra";
|
|
4
3
|
import createDebug from "debug";
|
|
5
|
-
import _, { isNil, castArray, prop, omit, toString, toNumber, isString as isString$1, padCharsEnd, isArray, keys, isPlainObject, isFinite, groupBy, pipe, mapValues, map, isEmpty, maxBy, pick,
|
|
6
|
-
import crypto
|
|
7
|
-
import
|
|
4
|
+
import _, { isNil, castArray, prop, omit, isInteger, snakeCase, partition, sumBy, toString, toNumber, isString as isString$1, padCharsEnd, isArray, keys, isPlainObject, isFinite, groupBy, pipe, mapValues, map, isEmpty, maxBy, pick, has, uniqBy, isNull, differenceWith, isEqual, compact, difference, isObject, isNumber as isNumber$1, isUndefined, uniqWith } from "lodash/fp";
|
|
5
|
+
import crypto from "crypto";
|
|
6
|
+
import crypto$1 from "node:crypto";
|
|
8
7
|
import * as dateFns from "date-fns";
|
|
8
|
+
import { isOperatorOfType } from "@strapi/utils";
|
|
9
9
|
import KnexBuilder from "knex/lib/query/querybuilder";
|
|
10
10
|
import KnexRaw from "knex/lib/raw";
|
|
11
11
|
import { Readable } from "stream";
|
|
12
12
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
13
13
|
import _$1 from "lodash";
|
|
14
|
-
import path$1 from "node:path";
|
|
15
14
|
import { Umzug } from "umzug";
|
|
16
15
|
import { strict } from "assert";
|
|
17
16
|
import knex from "knex";
|
|
18
|
-
import SqliteClient from "knex/lib/dialects/sqlite3/index";
|
|
19
17
|
class Dialect {
|
|
20
18
|
db;
|
|
21
19
|
schemaInspector = {};
|
|
@@ -26,7 +24,8 @@ class Dialect {
|
|
|
26
24
|
}
|
|
27
25
|
configure() {
|
|
28
26
|
}
|
|
29
|
-
|
|
27
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
28
|
+
async initialize(_nativeConnection) {
|
|
30
29
|
}
|
|
31
30
|
getSqlType(type) {
|
|
32
31
|
return type;
|
|
@@ -43,9 +42,6 @@ class Dialect {
|
|
|
43
42
|
supportsUnsigned() {
|
|
44
43
|
return false;
|
|
45
44
|
}
|
|
46
|
-
supportsWindowFunctions() {
|
|
47
|
-
return true;
|
|
48
|
-
}
|
|
49
45
|
supportsOperator() {
|
|
50
46
|
return true;
|
|
51
47
|
}
|
|
@@ -389,7 +385,7 @@ class PostgresDialect extends Dialect {
|
|
|
389
385
|
useReturning() {
|
|
390
386
|
return true;
|
|
391
387
|
}
|
|
392
|
-
async initialize() {
|
|
388
|
+
async initialize(nativeConnection) {
|
|
393
389
|
this.db.connection.client.driver.types.setTypeParser(
|
|
394
390
|
this.db.connection.client.driver.types.builtins.DATE,
|
|
395
391
|
"text",
|
|
@@ -405,6 +401,10 @@ class PostgresDialect extends Dialect {
|
|
|
405
401
|
"text",
|
|
406
402
|
parseFloat
|
|
407
403
|
);
|
|
404
|
+
const schemaName = this.db.getSchemaName();
|
|
405
|
+
if (schemaName) {
|
|
406
|
+
await this.db.connection.raw(`SET search_path TO "${schemaName}"`).connection(nativeConnection);
|
|
407
|
+
}
|
|
408
408
|
}
|
|
409
409
|
usesForeignKeys() {
|
|
410
410
|
return true;
|
|
@@ -668,11 +668,11 @@ class MysqlDatabaseInspector {
|
|
|
668
668
|
constructor(db) {
|
|
669
669
|
this.db = db;
|
|
670
670
|
}
|
|
671
|
-
async getInformation() {
|
|
671
|
+
async getInformation(nativeConnection) {
|
|
672
672
|
let database;
|
|
673
673
|
let versionNumber;
|
|
674
674
|
try {
|
|
675
|
-
const [results] = await this.db.connection.raw(SQL_QUERIES$1.VERSION);
|
|
675
|
+
const [results] = await this.db.connection.raw(SQL_QUERIES$1.VERSION).connection(nativeConnection);
|
|
676
676
|
const versionSplit = results[0].version.split("-");
|
|
677
677
|
const databaseName = versionSplit[1];
|
|
678
678
|
versionNumber = versionSplit[0];
|
|
@@ -719,12 +719,14 @@ class MysqlDialect extends Dialect {
|
|
|
719
719
|
return next();
|
|
720
720
|
};
|
|
721
721
|
}
|
|
722
|
-
async initialize() {
|
|
722
|
+
async initialize(nativeConnection) {
|
|
723
723
|
try {
|
|
724
|
-
await this.db.connection.raw(`set session sql_require_primary_key = 0;`);
|
|
724
|
+
await this.db.connection.raw(`set session sql_require_primary_key = 0;`).connection(nativeConnection);
|
|
725
725
|
} catch (err) {
|
|
726
726
|
}
|
|
727
|
-
this.info
|
|
727
|
+
if (!this.info) {
|
|
728
|
+
this.info = await this.databaseInspector.getInformation(nativeConnection);
|
|
729
|
+
}
|
|
728
730
|
}
|
|
729
731
|
async startSchemaUpdate() {
|
|
730
732
|
try {
|
|
@@ -739,14 +741,6 @@ class MysqlDialect extends Dialect {
|
|
|
739
741
|
supportsUnsigned() {
|
|
740
742
|
return true;
|
|
741
743
|
}
|
|
742
|
-
supportsWindowFunctions() {
|
|
743
|
-
const isMysqlDB = !this.info?.database || this.info.database === MYSQL;
|
|
744
|
-
const isBeforeV8 = !semver.valid(this.info?.version) || semver.lt(this.info?.version ?? "", "8.0.0");
|
|
745
|
-
if (isMysqlDB && isBeforeV8) {
|
|
746
|
-
return false;
|
|
747
|
-
}
|
|
748
|
-
return true;
|
|
749
|
-
}
|
|
750
744
|
usesForeignKeys() {
|
|
751
745
|
return true;
|
|
752
746
|
}
|
|
@@ -904,8 +898,8 @@ class SqliteDialect extends Dialect {
|
|
|
904
898
|
useReturning() {
|
|
905
899
|
return true;
|
|
906
900
|
}
|
|
907
|
-
async initialize() {
|
|
908
|
-
await this.db.connection.raw("pragma foreign_keys = on");
|
|
901
|
+
async initialize(nativeConnection) {
|
|
902
|
+
await this.db.connection.raw("pragma foreign_keys = on").connection(nativeConnection);
|
|
909
903
|
}
|
|
910
904
|
canAlterConstraints() {
|
|
911
905
|
return false;
|
|
@@ -967,10 +961,8 @@ const getDialectName = (client) => {
|
|
|
967
961
|
case "postgres":
|
|
968
962
|
return "postgres";
|
|
969
963
|
case "mysql":
|
|
970
|
-
case "mysql2":
|
|
971
964
|
return "mysql";
|
|
972
965
|
case "sqlite":
|
|
973
|
-
case "sqlite-legacy":
|
|
974
966
|
return "sqlite";
|
|
975
967
|
default:
|
|
976
968
|
throw new Error(`Unknown dialect ${client}`);
|
|
@@ -1234,7 +1226,11 @@ const createHelpers = (db) => {
|
|
|
1234
1226
|
dropTableForeignKeys
|
|
1235
1227
|
};
|
|
1236
1228
|
};
|
|
1237
|
-
const RESERVED_TABLE_NAMES = [
|
|
1229
|
+
const RESERVED_TABLE_NAMES = [
|
|
1230
|
+
"strapi_migrations",
|
|
1231
|
+
"strapi_migrations_internal",
|
|
1232
|
+
"strapi_database_schema"
|
|
1233
|
+
];
|
|
1238
1234
|
const statuses = {
|
|
1239
1235
|
CHANGED: "CHANGED",
|
|
1240
1236
|
UNCHANGED: "UNCHANGED"
|
|
@@ -1614,11 +1610,212 @@ const NUMBER_TYPES = ["biginteger", "integer", "decimal", "float"];
|
|
|
1614
1610
|
const isString = (type) => STRING_TYPES.includes(type);
|
|
1615
1611
|
const isNumber = (type) => NUMBER_TYPES.includes(type);
|
|
1616
1612
|
const isScalar = (type) => SCALAR_TYPES.includes(type);
|
|
1617
|
-
const isComponent = (type) => type === "component";
|
|
1618
|
-
const isDynamicZone = (type) => type === "dynamiczone";
|
|
1619
1613
|
const isRelation = (type) => type === "relation";
|
|
1620
1614
|
const isScalarAttribute = (attribute) => isScalar(attribute.type);
|
|
1621
1615
|
const isRelationalAttribute = (attribute) => isRelation(attribute.type);
|
|
1616
|
+
const MAX_DB_IDENTIFIER_LENGTH = 0;
|
|
1617
|
+
const HASH_LENGTH = 5;
|
|
1618
|
+
const HASH_SEPARATOR = "";
|
|
1619
|
+
const IDENTIFIER_SEPARATOR = "_";
|
|
1620
|
+
const MIN_TOKEN_LENGTH = 3;
|
|
1621
|
+
function createHash(data, len) {
|
|
1622
|
+
if (!isInteger(len) || len <= 0) {
|
|
1623
|
+
throw new Error(`createHash length must be a positive integer, received ${len}`);
|
|
1624
|
+
}
|
|
1625
|
+
const hash = crypto$1.createHash("shake256", { outputLength: Math.ceil(len / 2) }).update(data);
|
|
1626
|
+
return hash.digest("hex").substring(0, len);
|
|
1627
|
+
}
|
|
1628
|
+
function getShortenedName(name, len) {
|
|
1629
|
+
if (!isInteger(len) || len <= 0) {
|
|
1630
|
+
throw new Error(`tokenWithHash length must be a positive integer, received ${len}`);
|
|
1631
|
+
}
|
|
1632
|
+
if (name.length <= len) {
|
|
1633
|
+
return name;
|
|
1634
|
+
}
|
|
1635
|
+
if (len < MIN_TOKEN_LENGTH + HASH_LENGTH) {
|
|
1636
|
+
throw new Error(
|
|
1637
|
+
`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}`
|
|
1638
|
+
);
|
|
1639
|
+
}
|
|
1640
|
+
const availableLength = len - HASH_LENGTH - HASH_SEPARATOR.length;
|
|
1641
|
+
if (availableLength < MIN_TOKEN_LENGTH) {
|
|
1642
|
+
throw new Error(
|
|
1643
|
+
`length for part of identifier minimum is less than min token length (${MIN_TOKEN_LENGTH}), received ${len} for token ${name}`
|
|
1644
|
+
);
|
|
1645
|
+
}
|
|
1646
|
+
return `${name.substring(0, availableLength)}${HASH_SEPARATOR}${createHash(name, HASH_LENGTH)}`;
|
|
1647
|
+
}
|
|
1648
|
+
function getNameFromTokens(nameTokens, maxLength = MAX_DB_IDENTIFIER_LENGTH) {
|
|
1649
|
+
if (!isInteger(maxLength) || maxLength < 0) {
|
|
1650
|
+
throw new Error("maxLength must be a positive integer or 0 (for unlimited length)");
|
|
1651
|
+
}
|
|
1652
|
+
const fullLengthName = nameTokens.map((token) => snakeCase(token.name)).join(IDENTIFIER_SEPARATOR);
|
|
1653
|
+
if (fullLengthName.length <= maxLength || maxLength === 0) {
|
|
1654
|
+
return fullLengthName;
|
|
1655
|
+
}
|
|
1656
|
+
const [compressible, incompressible] = partition(
|
|
1657
|
+
(token) => token.compressible,
|
|
1658
|
+
nameTokens
|
|
1659
|
+
);
|
|
1660
|
+
const totalIncompressibleLength = sumBy((token) => token.name.length)(incompressible);
|
|
1661
|
+
const totalSeparatorsLength = nameTokens.length * IDENTIFIER_SEPARATOR.length - 1;
|
|
1662
|
+
const available = maxLength - totalIncompressibleLength - totalSeparatorsLength;
|
|
1663
|
+
const availablePerToken = Math.floor(available / compressible.length);
|
|
1664
|
+
if (totalIncompressibleLength + totalSeparatorsLength > maxLength || availablePerToken < MIN_TOKEN_LENGTH) {
|
|
1665
|
+
throw new Error("Maximum length is too small to accommodate all tokens");
|
|
1666
|
+
}
|
|
1667
|
+
let surplus = available % compressible.length;
|
|
1668
|
+
const minHashedLength = HASH_LENGTH + HASH_SEPARATOR.length + MIN_TOKEN_LENGTH;
|
|
1669
|
+
const totalLength = nameTokens.reduce((total, token) => {
|
|
1670
|
+
if (token.compressible) {
|
|
1671
|
+
if (token.name.length < availablePerToken) {
|
|
1672
|
+
return total + token.name.length;
|
|
1673
|
+
}
|
|
1674
|
+
return total + minHashedLength;
|
|
1675
|
+
}
|
|
1676
|
+
return total + token.name.length;
|
|
1677
|
+
}, nameTokens.length * IDENTIFIER_SEPARATOR.length - 1);
|
|
1678
|
+
if (maxLength < totalLength) {
|
|
1679
|
+
throw new Error("Maximum length is too small to accommodate all tokens");
|
|
1680
|
+
}
|
|
1681
|
+
let deficits = [];
|
|
1682
|
+
compressible.forEach((token) => {
|
|
1683
|
+
const actualLength = token.name.length;
|
|
1684
|
+
if (actualLength < availablePerToken) {
|
|
1685
|
+
surplus += availablePerToken - actualLength;
|
|
1686
|
+
token.allocatedLength = actualLength;
|
|
1687
|
+
} else {
|
|
1688
|
+
token.allocatedLength = availablePerToken;
|
|
1689
|
+
deficits.push(token);
|
|
1690
|
+
}
|
|
1691
|
+
});
|
|
1692
|
+
function filterAndIncreaseLength(token) {
|
|
1693
|
+
if (token.allocatedLength < token.name.length && surplus > 0) {
|
|
1694
|
+
token.allocatedLength += 1;
|
|
1695
|
+
surplus -= 1;
|
|
1696
|
+
return token.allocatedLength < token.name.length;
|
|
1697
|
+
}
|
|
1698
|
+
return false;
|
|
1699
|
+
}
|
|
1700
|
+
let previousSurplus = surplus + 1;
|
|
1701
|
+
while (surplus > 0 && deficits.length > 0) {
|
|
1702
|
+
deficits = deficits.filter((token) => filterAndIncreaseLength(token));
|
|
1703
|
+
if (surplus === previousSurplus) {
|
|
1704
|
+
break;
|
|
1705
|
+
}
|
|
1706
|
+
previousSurplus = surplus;
|
|
1707
|
+
}
|
|
1708
|
+
const shortenedName = nameTokens.map((token) => {
|
|
1709
|
+
if (token.compressible && "allocatedLength" in token && token.allocatedLength !== void 0) {
|
|
1710
|
+
return getShortenedName(token.name, token.allocatedLength);
|
|
1711
|
+
}
|
|
1712
|
+
return token.name;
|
|
1713
|
+
}).join(IDENTIFIER_SEPARATOR);
|
|
1714
|
+
if (shortenedName.length > maxLength) {
|
|
1715
|
+
throw new Error(
|
|
1716
|
+
`name shortening failed to generate a name of the correct maxLength; name ${shortenedName}`
|
|
1717
|
+
);
|
|
1718
|
+
}
|
|
1719
|
+
return shortenedName;
|
|
1720
|
+
}
|
|
1721
|
+
const ID_COLUMN = "id";
|
|
1722
|
+
const ORDER_COLUMN = "order";
|
|
1723
|
+
const FIELD_COLUMN = "field";
|
|
1724
|
+
const getName = (names, options) => {
|
|
1725
|
+
const tokens = _.castArray(names).map((name) => {
|
|
1726
|
+
return {
|
|
1727
|
+
name,
|
|
1728
|
+
compressible: true
|
|
1729
|
+
};
|
|
1730
|
+
});
|
|
1731
|
+
if (options?.suffix) {
|
|
1732
|
+
tokens.push({ name: options.suffix, compressible: false });
|
|
1733
|
+
}
|
|
1734
|
+
if (options?.prefix) {
|
|
1735
|
+
tokens.unshift({ name: options.prefix, compressible: false });
|
|
1736
|
+
}
|
|
1737
|
+
const maxLength = options?.maxLength ?? MAX_DB_IDENTIFIER_LENGTH;
|
|
1738
|
+
return getNameFromTokens(tokens, maxLength);
|
|
1739
|
+
};
|
|
1740
|
+
const getTableName = (name, options) => {
|
|
1741
|
+
return getName(name, options);
|
|
1742
|
+
};
|
|
1743
|
+
const getJoinTableName = (collectionName, attributeName, options) => {
|
|
1744
|
+
return getName([collectionName, attributeName], { suffix: "links", ...options });
|
|
1745
|
+
};
|
|
1746
|
+
const getMorphTableName = (collectionName, attributeName, options) => {
|
|
1747
|
+
return getName([collectionName, attributeName], { suffix: "morphs", ...options });
|
|
1748
|
+
};
|
|
1749
|
+
const getColumnName = (attributeName, options) => {
|
|
1750
|
+
return getName(attributeName, options);
|
|
1751
|
+
};
|
|
1752
|
+
const getJoinColumnAttributeIdName = (attributeName, options) => {
|
|
1753
|
+
return getName(attributeName, { suffix: "id", ...options });
|
|
1754
|
+
};
|
|
1755
|
+
const getInverseJoinColumnAttributeIdName = (attributeName, options) => {
|
|
1756
|
+
return getName(attributeName, { suffix: "id", prefix: "inv", ...options });
|
|
1757
|
+
};
|
|
1758
|
+
const getOrderColumnName = (singularName, options) => {
|
|
1759
|
+
return getName(singularName, { suffix: "order", ...options });
|
|
1760
|
+
};
|
|
1761
|
+
const getInverseOrderColumnName = (singularName, options) => {
|
|
1762
|
+
return getName(singularName, { suffix: "order", prefix: "inv", ...options });
|
|
1763
|
+
};
|
|
1764
|
+
const getMorphColumnJoinTableIdName = (singularName, options) => {
|
|
1765
|
+
return getName(singularName, { suffix: "id", ...options });
|
|
1766
|
+
};
|
|
1767
|
+
const getMorphColumnAttributeIdName = (attributeName, options) => {
|
|
1768
|
+
return getName(attributeName, { suffix: "id", ...options });
|
|
1769
|
+
};
|
|
1770
|
+
const getMorphColumnTypeName = (attributeName, options) => {
|
|
1771
|
+
return getName(attributeName, { suffix: "type", ...options });
|
|
1772
|
+
};
|
|
1773
|
+
const getIndexName = (names, options) => {
|
|
1774
|
+
return getName(names, { suffix: "index", ...options });
|
|
1775
|
+
};
|
|
1776
|
+
const getFkIndexName = (names, options) => {
|
|
1777
|
+
return getName(names, { suffix: "fk", ...options });
|
|
1778
|
+
};
|
|
1779
|
+
const getInverseFkIndexName = (names, options) => {
|
|
1780
|
+
return getName(names, { suffix: "inv_fk", ...options });
|
|
1781
|
+
};
|
|
1782
|
+
const getOrderFkIndexName = (names, options) => {
|
|
1783
|
+
return getName(names, { suffix: "order_fk", ...options });
|
|
1784
|
+
};
|
|
1785
|
+
const getOrderInverseFkIndexName = (names, options) => {
|
|
1786
|
+
return getName(names, { suffix: "order_inv_fk", ...options });
|
|
1787
|
+
};
|
|
1788
|
+
const getUniqueIndexName = (names, options) => {
|
|
1789
|
+
return getName(names, { suffix: "unique", ...options });
|
|
1790
|
+
};
|
|
1791
|
+
const getPrimaryIndexName = (names) => {
|
|
1792
|
+
return getName(names, { suffix: "primary" });
|
|
1793
|
+
};
|
|
1794
|
+
const identifiers = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
1795
|
+
__proto__: null,
|
|
1796
|
+
FIELD_COLUMN,
|
|
1797
|
+
ID_COLUMN,
|
|
1798
|
+
ORDER_COLUMN,
|
|
1799
|
+
getColumnName,
|
|
1800
|
+
getFkIndexName,
|
|
1801
|
+
getIndexName,
|
|
1802
|
+
getInverseFkIndexName,
|
|
1803
|
+
getInverseJoinColumnAttributeIdName,
|
|
1804
|
+
getInverseOrderColumnName,
|
|
1805
|
+
getJoinColumnAttributeIdName,
|
|
1806
|
+
getJoinTableName,
|
|
1807
|
+
getMorphColumnAttributeIdName,
|
|
1808
|
+
getMorphColumnJoinTableIdName,
|
|
1809
|
+
getMorphColumnTypeName,
|
|
1810
|
+
getMorphTableName,
|
|
1811
|
+
getName,
|
|
1812
|
+
getOrderColumnName,
|
|
1813
|
+
getOrderFkIndexName,
|
|
1814
|
+
getOrderInverseFkIndexName,
|
|
1815
|
+
getPrimaryIndexName,
|
|
1816
|
+
getTableName,
|
|
1817
|
+
getUniqueIndexName
|
|
1818
|
+
}, Symbol.toStringTag, { value: "Module" }));
|
|
1622
1819
|
const createColumn = (name, attribute) => {
|
|
1623
1820
|
const { type, args = [], ...opts } = getColumnType(attribute);
|
|
1624
1821
|
return {
|
|
@@ -1644,51 +1841,62 @@ const createTable = (meta) => {
|
|
|
1644
1841
|
if (attribute.type === "relation") {
|
|
1645
1842
|
if ("morphColumn" in attribute && attribute.morphColumn && attribute.owner) {
|
|
1646
1843
|
const { idColumn, typeColumn } = attribute.morphColumn;
|
|
1844
|
+
const idColumnName = getName(idColumn.name);
|
|
1845
|
+
const typeColumnName = getName(typeColumn.name);
|
|
1647
1846
|
table.columns.push(
|
|
1648
|
-
createColumn(
|
|
1847
|
+
createColumn(idColumnName, {
|
|
1649
1848
|
type: "integer",
|
|
1650
1849
|
column: {
|
|
1651
1850
|
unsigned: true
|
|
1652
1851
|
}
|
|
1653
1852
|
})
|
|
1654
1853
|
);
|
|
1655
|
-
table.columns.push(createColumn(
|
|
1854
|
+
table.columns.push(createColumn(typeColumnName, { type: "string" }));
|
|
1656
1855
|
} else if ("joinColumn" in attribute && attribute.joinColumn && attribute.owner && attribute.joinColumn.referencedTable) {
|
|
1657
|
-
const {
|
|
1856
|
+
const {
|
|
1857
|
+
name: columnNameFull,
|
|
1858
|
+
referencedColumn,
|
|
1859
|
+
referencedTable,
|
|
1860
|
+
columnType = "integer"
|
|
1861
|
+
} = attribute.joinColumn;
|
|
1862
|
+
const columnName = getName(columnNameFull);
|
|
1658
1863
|
const column = createColumn(columnName, {
|
|
1659
|
-
|
|
1864
|
+
// TODO: find the column type automatically, or allow passing all the column params
|
|
1865
|
+
type: columnType,
|
|
1660
1866
|
column: {
|
|
1661
1867
|
unsigned: true
|
|
1662
1868
|
}
|
|
1663
1869
|
});
|
|
1664
1870
|
table.columns.push(column);
|
|
1871
|
+
const fkName = getFkIndexName([table.name, columnName]);
|
|
1665
1872
|
table.foreignKeys.push({
|
|
1666
|
-
name:
|
|
1667
|
-
columns: [
|
|
1873
|
+
name: fkName,
|
|
1874
|
+
columns: [column.name],
|
|
1668
1875
|
referencedTable,
|
|
1669
1876
|
referencedColumns: [referencedColumn],
|
|
1670
1877
|
// NOTE: could allow configuration
|
|
1671
1878
|
onDelete: "SET NULL"
|
|
1672
1879
|
});
|
|
1673
1880
|
table.indexes.push({
|
|
1674
|
-
name:
|
|
1675
|
-
columns: [
|
|
1881
|
+
name: fkName,
|
|
1882
|
+
columns: [column.name]
|
|
1676
1883
|
});
|
|
1677
1884
|
}
|
|
1678
1885
|
} else if (isScalarAttribute(attribute)) {
|
|
1679
|
-
const
|
|
1886
|
+
const columnName = getName(attribute.columnName || key);
|
|
1887
|
+
const column = createColumn(columnName, attribute);
|
|
1680
1888
|
if (column.unique) {
|
|
1681
1889
|
table.indexes.push({
|
|
1682
1890
|
type: "unique",
|
|
1683
|
-
name:
|
|
1684
|
-
columns: [
|
|
1891
|
+
name: getUniqueIndexName([table.name, column.name]),
|
|
1892
|
+
columns: [columnName]
|
|
1685
1893
|
});
|
|
1686
1894
|
}
|
|
1687
1895
|
if (column.primary) {
|
|
1688
1896
|
table.indexes.push({
|
|
1689
1897
|
type: "primary",
|
|
1690
|
-
name:
|
|
1691
|
-
columns: [
|
|
1898
|
+
name: getPrimaryIndexName([table.name, column.name]),
|
|
1899
|
+
columns: [columnName]
|
|
1692
1900
|
});
|
|
1693
1901
|
}
|
|
1694
1902
|
table.columns.push(column);
|
|
@@ -1716,8 +1924,7 @@ const getColumnType = (attribute) => {
|
|
|
1716
1924
|
}
|
|
1717
1925
|
case "uid": {
|
|
1718
1926
|
return {
|
|
1719
|
-
type: "string"
|
|
1720
|
-
unique: true
|
|
1927
|
+
type: "string"
|
|
1721
1928
|
};
|
|
1722
1929
|
}
|
|
1723
1930
|
case "richtext":
|
|
@@ -1790,8 +1997,14 @@ const metadataToSchema = (metadata) => {
|
|
|
1790
1997
|
};
|
|
1791
1998
|
const debug = createDebug("strapi::database");
|
|
1792
1999
|
const createSchemaProvider = (db) => {
|
|
1793
|
-
const
|
|
2000
|
+
const state = {};
|
|
1794
2001
|
return {
|
|
2002
|
+
get schema() {
|
|
2003
|
+
if (!state.schema) {
|
|
2004
|
+
state.schema = metadataToSchema(db.metadata);
|
|
2005
|
+
}
|
|
2006
|
+
return state.schema;
|
|
2007
|
+
},
|
|
1795
2008
|
builder: createSchemaBuilder(db),
|
|
1796
2009
|
schemaDiff: createSchemaDiff(db),
|
|
1797
2010
|
schemaStorage: createSchemaStorage(db),
|
|
@@ -1808,7 +2021,7 @@ const createSchemaProvider = (db) => {
|
|
|
1808
2021
|
*/
|
|
1809
2022
|
async create() {
|
|
1810
2023
|
debug("Created database schema");
|
|
1811
|
-
await this.builder.createSchema(schema);
|
|
2024
|
+
await this.builder.createSchema(this.schema);
|
|
1812
2025
|
},
|
|
1813
2026
|
/**
|
|
1814
2027
|
* Resets the database schema
|
|
@@ -1821,11 +2034,11 @@ const createSchemaProvider = (db) => {
|
|
|
1821
2034
|
async syncSchema() {
|
|
1822
2035
|
debug("Synchronizing database schema");
|
|
1823
2036
|
const DBSchema = await db.dialect.schemaInspector.getSchema();
|
|
1824
|
-
const { status, diff } = await this.schemaDiff.diff(DBSchema, schema);
|
|
2037
|
+
const { status, diff } = await this.schemaDiff.diff(DBSchema, this.schema);
|
|
1825
2038
|
if (status === "CHANGED") {
|
|
1826
2039
|
await this.builder.updateSchema(diff);
|
|
1827
2040
|
}
|
|
1828
|
-
await this.schemaStorage.add(schema);
|
|
2041
|
+
await this.schemaStorage.add(this.schema);
|
|
1829
2042
|
},
|
|
1830
2043
|
// TODO: support options to migrate softly or forcefully
|
|
1831
2044
|
// TODO: support option to disable auto migration & run a CLI command instead to avoid doing it at startup
|
|
@@ -1842,7 +2055,7 @@ const createSchemaProvider = (db) => {
|
|
|
1842
2055
|
return this.syncSchema();
|
|
1843
2056
|
}
|
|
1844
2057
|
const { hash: oldHash } = oldSchema;
|
|
1845
|
-
const hash = await this.schemaStorage.hashSchema(schema);
|
|
2058
|
+
const hash = await this.schemaStorage.hashSchema(this.schema);
|
|
1846
2059
|
if (oldHash !== hash) {
|
|
1847
2060
|
debug("Schema changed");
|
|
1848
2061
|
return this.syncSchema();
|
|
@@ -1851,9 +2064,11 @@ const createSchemaProvider = (db) => {
|
|
|
1851
2064
|
}
|
|
1852
2065
|
};
|
|
1853
2066
|
};
|
|
2067
|
+
const ID = ID_COLUMN;
|
|
2068
|
+
const ORDER = ORDER_COLUMN;
|
|
2069
|
+
const FIELD = FIELD_COLUMN;
|
|
1854
2070
|
const hasInversedBy = (attr) => "inversedBy" in attr;
|
|
1855
2071
|
const hasMappedBy = (attr) => "mappedBy" in attr;
|
|
1856
|
-
const isPolymorphic = (attribute) => ["morphOne", "morphMany", "morphToOne", "morphToMany"].includes(attribute.relation);
|
|
1857
2072
|
const isOneToAny = (attribute) => ["oneToOne", "oneToMany"].includes(attribute.relation);
|
|
1858
2073
|
const isManyToAny = (attribute) => ["manyToMany", "manyToOne"].includes(attribute.relation);
|
|
1859
2074
|
const isAnyToOne = (attribute) => ["oneToOne", "manyToOne"].includes(attribute.relation);
|
|
@@ -1861,7 +2076,6 @@ const isAnyToMany = (attribute) => ["oneToMany", "manyToMany"].includes(attribut
|
|
|
1861
2076
|
const isBidirectional = (attribute) => hasInversedBy(attribute) || hasMappedBy(attribute);
|
|
1862
2077
|
const isOwner = (attribute) => !isBidirectional(attribute) || hasInversedBy(attribute);
|
|
1863
2078
|
const shouldUseJoinTable = (attribute) => !("useJoinTable" in attribute) || attribute.useJoinTable !== false;
|
|
1864
|
-
const getJoinTableName = (tableName, attributeName) => _.snakeCase(`${tableName}_${attributeName}_links`);
|
|
1865
2079
|
const hasOrderColumn = (attribute) => isAnyToMany(attribute);
|
|
1866
2080
|
const hasInverseOrderColumn = (attribute) => isBidirectional(attribute) && isManyToAny(attribute);
|
|
1867
2081
|
const createOneToOne = (attributeName, attribute, meta, metadata) => {
|
|
@@ -1920,8 +2134,11 @@ const createManyToMany = (attributeName, attribute, meta, metadata) => {
|
|
|
1920
2134
|
}
|
|
1921
2135
|
};
|
|
1922
2136
|
const createMorphToOne = (attributeName, attribute) => {
|
|
1923
|
-
const idColumnName = "
|
|
1924
|
-
const typeColumnName = "
|
|
2137
|
+
const idColumnName = getJoinColumnAttributeIdName("target");
|
|
2138
|
+
const typeColumnName = getMorphColumnTypeName("target");
|
|
2139
|
+
if ("morphColumn" in attribute && attribute.morphColumn) {
|
|
2140
|
+
return;
|
|
2141
|
+
}
|
|
1925
2142
|
Object.assign(attribute, {
|
|
1926
2143
|
owner: true,
|
|
1927
2144
|
morphColumn: {
|
|
@@ -1931,23 +2148,26 @@ const createMorphToOne = (attributeName, attribute) => {
|
|
|
1931
2148
|
},
|
|
1932
2149
|
idColumn: {
|
|
1933
2150
|
name: idColumnName,
|
|
1934
|
-
referencedColumn:
|
|
2151
|
+
referencedColumn: ID
|
|
1935
2152
|
}
|
|
1936
2153
|
}
|
|
1937
2154
|
});
|
|
1938
2155
|
};
|
|
1939
2156
|
const createMorphToMany = (attributeName, attribute, meta, metadata) => {
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
const
|
|
1944
|
-
const
|
|
2157
|
+
if ("joinTable" in attribute && attribute.joinTable) {
|
|
2158
|
+
return;
|
|
2159
|
+
}
|
|
2160
|
+
const joinTableName = getMorphTableName(meta.tableName, attributeName);
|
|
2161
|
+
const joinColumnName = getMorphColumnJoinTableIdName(meta.singularName);
|
|
2162
|
+
const idColumnName = getMorphColumnAttributeIdName(attributeName);
|
|
2163
|
+
const typeColumnName = getMorphColumnTypeName(attributeName);
|
|
2164
|
+
const fkIndexName = getFkIndexName(joinTableName);
|
|
1945
2165
|
metadata.add({
|
|
1946
2166
|
singularName: joinTableName,
|
|
1947
2167
|
uid: joinTableName,
|
|
1948
2168
|
tableName: joinTableName,
|
|
1949
2169
|
attributes: {
|
|
1950
|
-
|
|
2170
|
+
[ID]: {
|
|
1951
2171
|
type: "increments"
|
|
1952
2172
|
},
|
|
1953
2173
|
[joinColumnName]: {
|
|
@@ -1965,10 +2185,10 @@ const createMorphToMany = (attributeName, attribute, meta, metadata) => {
|
|
|
1965
2185
|
[typeColumnName]: {
|
|
1966
2186
|
type: "string"
|
|
1967
2187
|
},
|
|
1968
|
-
|
|
2188
|
+
[FIELD]: {
|
|
1969
2189
|
type: "string"
|
|
1970
2190
|
},
|
|
1971
|
-
|
|
2191
|
+
[ORDER]: {
|
|
1972
2192
|
type: "float",
|
|
1973
2193
|
column: {
|
|
1974
2194
|
unsigned: true
|
|
@@ -1977,12 +2197,12 @@ const createMorphToMany = (attributeName, attribute, meta, metadata) => {
|
|
|
1977
2197
|
},
|
|
1978
2198
|
indexes: [
|
|
1979
2199
|
{
|
|
1980
|
-
name:
|
|
2200
|
+
name: fkIndexName,
|
|
1981
2201
|
columns: [joinColumnName]
|
|
1982
2202
|
},
|
|
1983
2203
|
{
|
|
1984
2204
|
name: `${joinTableName}_order_index`,
|
|
1985
|
-
columns: [
|
|
2205
|
+
columns: [ORDER]
|
|
1986
2206
|
},
|
|
1987
2207
|
{
|
|
1988
2208
|
name: `${joinTableName}_id_column_index`,
|
|
@@ -1991,10 +2211,10 @@ const createMorphToMany = (attributeName, attribute, meta, metadata) => {
|
|
|
1991
2211
|
],
|
|
1992
2212
|
foreignKeys: [
|
|
1993
2213
|
{
|
|
1994
|
-
name:
|
|
2214
|
+
name: fkIndexName,
|
|
1995
2215
|
columns: [joinColumnName],
|
|
1996
|
-
referencedColumns: [
|
|
1997
|
-
referencedTable: meta.tableName,
|
|
2216
|
+
referencedColumns: [ID],
|
|
2217
|
+
referencedTable: getTableName(meta.tableName),
|
|
1998
2218
|
onDelete: "CASCADE"
|
|
1999
2219
|
}
|
|
2000
2220
|
],
|
|
@@ -2005,7 +2225,7 @@ const createMorphToMany = (attributeName, attribute, meta, metadata) => {
|
|
|
2005
2225
|
name: joinTableName,
|
|
2006
2226
|
joinColumn: {
|
|
2007
2227
|
name: joinColumnName,
|
|
2008
|
-
referencedColumn:
|
|
2228
|
+
referencedColumn: ID
|
|
2009
2229
|
},
|
|
2010
2230
|
morphColumn: {
|
|
2011
2231
|
typeColumn: {
|
|
@@ -2013,7 +2233,7 @@ const createMorphToMany = (attributeName, attribute, meta, metadata) => {
|
|
|
2013
2233
|
},
|
|
2014
2234
|
idColumn: {
|
|
2015
2235
|
name: idColumnName,
|
|
2016
|
-
referencedColumn:
|
|
2236
|
+
referencedColumn: ID
|
|
2017
2237
|
}
|
|
2018
2238
|
},
|
|
2019
2239
|
orderBy: {
|
|
@@ -2049,9 +2269,12 @@ const createJoinColum = (metadata, { attribute, attributeName }) => {
|
|
|
2049
2269
|
const joinColumnName = _.snakeCase(`${attributeName}_id`);
|
|
2050
2270
|
const joinColumn = {
|
|
2051
2271
|
name: joinColumnName,
|
|
2052
|
-
referencedColumn:
|
|
2272
|
+
referencedColumn: ID,
|
|
2053
2273
|
referencedTable: targetMeta.tableName
|
|
2054
2274
|
};
|
|
2275
|
+
if ("joinColumn" in attribute) {
|
|
2276
|
+
Object.assign(joinColumn, attribute.joinColumn);
|
|
2277
|
+
}
|
|
2055
2278
|
Object.assign(attribute, { owner: true, joinColumn });
|
|
2056
2279
|
if (isBidirectional(attribute)) {
|
|
2057
2280
|
const inverseAttribute = targetMeta.attributes[attribute.inversedBy];
|
|
@@ -2068,23 +2291,30 @@ const createJoinTable = (metadata, { attributeName, attribute, meta }) => {
|
|
|
2068
2291
|
if (!targetMeta) {
|
|
2069
2292
|
throw new Error(`Unknown target ${attribute.target}`);
|
|
2070
2293
|
}
|
|
2294
|
+
if ("joinTable" in attribute && attribute.joinTable) {
|
|
2295
|
+
return;
|
|
2296
|
+
}
|
|
2071
2297
|
const joinTableName = getJoinTableName(meta.tableName, attributeName);
|
|
2072
|
-
const joinColumnName =
|
|
2073
|
-
let inverseJoinColumnName =
|
|
2298
|
+
const joinColumnName = getJoinColumnAttributeIdName(meta.singularName);
|
|
2299
|
+
let inverseJoinColumnName = getJoinColumnAttributeIdName(targetMeta.singularName);
|
|
2074
2300
|
if (joinColumnName === inverseJoinColumnName) {
|
|
2075
|
-
inverseJoinColumnName =
|
|
2301
|
+
inverseJoinColumnName = getInverseJoinColumnAttributeIdName(
|
|
2302
|
+
targetMeta.singularName
|
|
2303
|
+
);
|
|
2076
2304
|
}
|
|
2077
|
-
const orderColumnName =
|
|
2078
|
-
let inverseOrderColumnName =
|
|
2305
|
+
const orderColumnName = getOrderColumnName(targetMeta.singularName);
|
|
2306
|
+
let inverseOrderColumnName = getOrderColumnName(meta.singularName);
|
|
2079
2307
|
if (attribute.relation === "manyToMany" && orderColumnName === inverseOrderColumnName) {
|
|
2080
|
-
inverseOrderColumnName =
|
|
2308
|
+
inverseOrderColumnName = getInverseOrderColumnName(meta.singularName);
|
|
2081
2309
|
}
|
|
2310
|
+
const fkIndexName = getFkIndexName(joinTableName);
|
|
2311
|
+
const invFkIndexName = getInverseFkIndexName(joinTableName);
|
|
2082
2312
|
const metadataSchema = {
|
|
2083
2313
|
singularName: joinTableName,
|
|
2084
2314
|
uid: joinTableName,
|
|
2085
2315
|
tableName: joinTableName,
|
|
2086
2316
|
attributes: {
|
|
2087
|
-
|
|
2317
|
+
[ID]: {
|
|
2088
2318
|
type: "increments"
|
|
2089
2319
|
},
|
|
2090
2320
|
[joinColumnName]: {
|
|
@@ -2103,32 +2333,34 @@ const createJoinTable = (metadata, { attributeName, attribute, meta }) => {
|
|
|
2103
2333
|
},
|
|
2104
2334
|
indexes: [
|
|
2105
2335
|
{
|
|
2106
|
-
name:
|
|
2336
|
+
name: fkIndexName,
|
|
2107
2337
|
columns: [joinColumnName]
|
|
2108
2338
|
},
|
|
2109
2339
|
{
|
|
2110
|
-
name:
|
|
2340
|
+
name: invFkIndexName,
|
|
2111
2341
|
columns: [inverseJoinColumnName]
|
|
2112
2342
|
},
|
|
2113
2343
|
{
|
|
2114
|
-
name:
|
|
2344
|
+
name: getUniqueIndexName(joinTableName),
|
|
2115
2345
|
columns: [joinColumnName, inverseJoinColumnName],
|
|
2116
2346
|
type: "unique"
|
|
2117
2347
|
}
|
|
2118
2348
|
],
|
|
2119
2349
|
foreignKeys: [
|
|
2120
2350
|
{
|
|
2121
|
-
name:
|
|
2351
|
+
name: fkIndexName,
|
|
2122
2352
|
columns: [joinColumnName],
|
|
2123
|
-
referencedColumns: [
|
|
2353
|
+
referencedColumns: [ID],
|
|
2124
2354
|
referencedTable: meta.tableName,
|
|
2355
|
+
// TODO: does this need to be wrapped or do we trust meta.tableName to be the right shortened version?
|
|
2125
2356
|
onDelete: "CASCADE"
|
|
2126
2357
|
},
|
|
2127
2358
|
{
|
|
2128
|
-
name:
|
|
2359
|
+
name: invFkIndexName,
|
|
2129
2360
|
columns: [inverseJoinColumnName],
|
|
2130
|
-
referencedColumns: [
|
|
2361
|
+
referencedColumns: [ID],
|
|
2131
2362
|
referencedTable: targetMeta.tableName,
|
|
2363
|
+
// TODO: does this need to be wrapped or do we trust meta.tableName to be the right shortened version?
|
|
2132
2364
|
onDelete: "CASCADE"
|
|
2133
2365
|
}
|
|
2134
2366
|
],
|
|
@@ -2139,11 +2371,13 @@ const createJoinTable = (metadata, { attributeName, attribute, meta }) => {
|
|
|
2139
2371
|
name: joinTableName,
|
|
2140
2372
|
joinColumn: {
|
|
2141
2373
|
name: joinColumnName,
|
|
2142
|
-
referencedColumn:
|
|
2374
|
+
referencedColumn: ID,
|
|
2375
|
+
referencedTable: meta.tableName
|
|
2143
2376
|
},
|
|
2144
2377
|
inverseJoinColumn: {
|
|
2145
2378
|
name: inverseJoinColumnName,
|
|
2146
|
-
referencedColumn:
|
|
2379
|
+
referencedColumn: ID,
|
|
2380
|
+
referencedTable: targetMeta.tableName
|
|
2147
2381
|
},
|
|
2148
2382
|
pivotColumns: [joinColumnName, inverseJoinColumnName]
|
|
2149
2383
|
};
|
|
@@ -2156,7 +2390,8 @@ const createJoinTable = (metadata, { attributeName, attribute, meta }) => {
|
|
|
2156
2390
|
}
|
|
2157
2391
|
};
|
|
2158
2392
|
metadataSchema.indexes.push({
|
|
2159
|
-
name:
|
|
2393
|
+
name: getOrderFkIndexName(joinTableName),
|
|
2394
|
+
// TODO: should we send joinTableName as parts?
|
|
2160
2395
|
columns: [orderColumnName]
|
|
2161
2396
|
});
|
|
2162
2397
|
joinTable.orderColumnName = orderColumnName;
|
|
@@ -2171,7 +2406,7 @@ const createJoinTable = (metadata, { attributeName, attribute, meta }) => {
|
|
|
2171
2406
|
}
|
|
2172
2407
|
};
|
|
2173
2408
|
metadataSchema.indexes.push({
|
|
2174
|
-
name:
|
|
2409
|
+
name: getOrderInverseFkIndexName(joinTableName),
|
|
2175
2410
|
columns: [inverseOrderColumnName]
|
|
2176
2411
|
});
|
|
2177
2412
|
joinTable.inverseOrderColumnName = inverseOrderColumnName;
|
|
@@ -2252,207 +2487,60 @@ class Metadata extends Map {
|
|
|
2252
2487
|
seenTables.set(meta.tableName, true);
|
|
2253
2488
|
}
|
|
2254
2489
|
}
|
|
2255
|
-
|
|
2256
|
-
const
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
}
|
|
2262
|
-
metadata.add({
|
|
2263
|
-
...model,
|
|
2264
|
-
attributes: {
|
|
2265
|
-
id: {
|
|
2266
|
-
type: "increments"
|
|
2490
|
+
loadModels(models = []) {
|
|
2491
|
+
for (const model of _.cloneDeep(models)) {
|
|
2492
|
+
this.add({
|
|
2493
|
+
...model,
|
|
2494
|
+
attributes: {
|
|
2495
|
+
...model.attributes
|
|
2267
2496
|
},
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
columnToAttribute: {}
|
|
2274
|
-
});
|
|
2275
|
-
}
|
|
2276
|
-
for (const meta of metadata.values()) {
|
|
2277
|
-
if (hasComponentsOrDz(meta)) {
|
|
2278
|
-
const compoLinkModelMeta = createCompoLinkModelMeta(meta);
|
|
2279
|
-
meta.componentLink = compoLinkModelMeta;
|
|
2280
|
-
metadata.add(compoLinkModelMeta);
|
|
2497
|
+
lifecycles: model.lifecycles ?? {},
|
|
2498
|
+
indexes: model.indexes ?? [],
|
|
2499
|
+
foreignKeys: model.foreignKeys ?? [],
|
|
2500
|
+
columnToAttribute: {}
|
|
2501
|
+
});
|
|
2281
2502
|
}
|
|
2282
|
-
for (const
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
createAttribute(attributeName, attribute);
|
|
2297
|
-
} catch (error) {
|
|
2298
|
-
console.log(error);
|
|
2299
|
-
if (error instanceof Error) {
|
|
2300
|
-
throw new Error(
|
|
2301
|
-
`Error on attribute ${attributeName} in model ${meta.singularName}(${meta.uid}): ${error.message}`
|
|
2302
|
-
);
|
|
2503
|
+
for (const meta of this.values()) {
|
|
2504
|
+
for (const [attributeName, attribute] of Object.entries(meta.attributes)) {
|
|
2505
|
+
try {
|
|
2506
|
+
if (isRelationalAttribute(attribute)) {
|
|
2507
|
+
createRelation(attributeName, attribute, meta, this);
|
|
2508
|
+
continue;
|
|
2509
|
+
}
|
|
2510
|
+
createAttribute(attributeName, attribute);
|
|
2511
|
+
} catch (error) {
|
|
2512
|
+
if (error instanceof Error) {
|
|
2513
|
+
throw new Error(
|
|
2514
|
+
`Error on attribute ${attributeName} in model ${meta.singularName}(${meta.uid}): ${error.message}`
|
|
2515
|
+
);
|
|
2516
|
+
}
|
|
2303
2517
|
}
|
|
2304
2518
|
}
|
|
2305
2519
|
}
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
return Object.assign(acc, { [attribute.columnName || key]: key });
|
|
2312
|
-
}
|
|
2313
|
-
return Object.assign(acc, { [key]: key });
|
|
2314
|
-
}, {});
|
|
2315
|
-
meta.columnToAttribute = columnToAttribute;
|
|
2316
|
-
}
|
|
2317
|
-
metadata.validate();
|
|
2318
|
-
return metadata;
|
|
2319
|
-
};
|
|
2320
|
-
const hasComponentsOrDz = (model) => {
|
|
2321
|
-
return Object.values(model.attributes).some(
|
|
2322
|
-
({ type }) => isComponent(type) || isDynamicZone(type)
|
|
2323
|
-
);
|
|
2324
|
-
};
|
|
2325
|
-
const createCompoLinkModelMeta = (baseModelMeta) => {
|
|
2326
|
-
const name = `${baseModelMeta.tableName}_components`;
|
|
2327
|
-
return {
|
|
2328
|
-
// TODO: make sure there can't be any conflicts with a prefix
|
|
2329
|
-
singularName: name,
|
|
2330
|
-
uid: name,
|
|
2331
|
-
tableName: name,
|
|
2332
|
-
attributes: {
|
|
2333
|
-
id: {
|
|
2334
|
-
type: "increments"
|
|
2335
|
-
},
|
|
2336
|
-
entity_id: {
|
|
2337
|
-
type: "integer",
|
|
2338
|
-
column: {
|
|
2339
|
-
unsigned: true
|
|
2340
|
-
}
|
|
2341
|
-
},
|
|
2342
|
-
component_id: {
|
|
2343
|
-
type: "integer",
|
|
2344
|
-
column: {
|
|
2345
|
-
unsigned: true
|
|
2346
|
-
}
|
|
2347
|
-
},
|
|
2348
|
-
component_type: {
|
|
2349
|
-
type: "string"
|
|
2350
|
-
},
|
|
2351
|
-
field: {
|
|
2352
|
-
type: "string"
|
|
2353
|
-
},
|
|
2354
|
-
order: {
|
|
2355
|
-
type: "float",
|
|
2356
|
-
column: {
|
|
2357
|
-
unsigned: true,
|
|
2358
|
-
defaultTo: null
|
|
2520
|
+
for (const meta of this.values()) {
|
|
2521
|
+
const columnToAttribute = Object.keys(meta.attributes).reduce((acc, key) => {
|
|
2522
|
+
const attribute = meta.attributes[key];
|
|
2523
|
+
if ("columnName" in attribute) {
|
|
2524
|
+
return Object.assign(acc, { [attribute.columnName || key]: key });
|
|
2359
2525
|
}
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
{
|
|
2364
|
-
name: `${baseModelMeta.tableName}_field_index`,
|
|
2365
|
-
columns: ["field"]
|
|
2366
|
-
},
|
|
2367
|
-
{
|
|
2368
|
-
name: `${baseModelMeta.tableName}_component_type_index`,
|
|
2369
|
-
columns: ["component_type"]
|
|
2370
|
-
},
|
|
2371
|
-
{
|
|
2372
|
-
name: `${baseModelMeta.tableName}_entity_fk`,
|
|
2373
|
-
columns: ["entity_id"]
|
|
2374
|
-
},
|
|
2375
|
-
{
|
|
2376
|
-
name: `${baseModelMeta.tableName}_unique`,
|
|
2377
|
-
columns: ["entity_id", "component_id", "field", "component_type"],
|
|
2378
|
-
type: "unique"
|
|
2379
|
-
}
|
|
2380
|
-
],
|
|
2381
|
-
foreignKeys: [
|
|
2382
|
-
{
|
|
2383
|
-
name: `${baseModelMeta.tableName}_entity_fk`,
|
|
2384
|
-
columns: ["entity_id"],
|
|
2385
|
-
referencedColumns: ["id"],
|
|
2386
|
-
referencedTable: baseModelMeta.tableName,
|
|
2387
|
-
onDelete: "CASCADE"
|
|
2388
|
-
}
|
|
2389
|
-
],
|
|
2390
|
-
lifecycles: {},
|
|
2391
|
-
columnToAttribute: {}
|
|
2392
|
-
};
|
|
2393
|
-
};
|
|
2394
|
-
const createDynamicZone = (attributeName, attribute, meta) => {
|
|
2395
|
-
Object.assign(attribute, {
|
|
2396
|
-
type: "relation",
|
|
2397
|
-
relation: "morphToMany",
|
|
2398
|
-
// TODO: handle restrictions at some point
|
|
2399
|
-
// target: attribute.components,
|
|
2400
|
-
joinTable: {
|
|
2401
|
-
name: meta.componentLink.tableName,
|
|
2402
|
-
joinColumn: {
|
|
2403
|
-
name: "entity_id",
|
|
2404
|
-
referencedColumn: "id"
|
|
2405
|
-
},
|
|
2406
|
-
morphColumn: {
|
|
2407
|
-
idColumn: {
|
|
2408
|
-
name: "component_id",
|
|
2409
|
-
referencedColumn: "id"
|
|
2410
|
-
},
|
|
2411
|
-
typeColumn: {
|
|
2412
|
-
name: "component_type"
|
|
2413
|
-
},
|
|
2414
|
-
typeField: "__component"
|
|
2415
|
-
},
|
|
2416
|
-
on: {
|
|
2417
|
-
field: attributeName
|
|
2418
|
-
},
|
|
2419
|
-
orderBy: {
|
|
2420
|
-
order: "asc"
|
|
2421
|
-
},
|
|
2422
|
-
pivotColumns: ["entity_id", "component_id", "field", "component_type"]
|
|
2423
|
-
}
|
|
2424
|
-
});
|
|
2425
|
-
};
|
|
2426
|
-
const createComponent = (attributeName, attribute, meta) => {
|
|
2427
|
-
Object.assign(attribute, {
|
|
2428
|
-
type: "relation",
|
|
2429
|
-
relation: "repeatable" in attribute && attribute.repeatable === true ? "oneToMany" : "oneToOne",
|
|
2430
|
-
target: "component" in attribute && attribute.component,
|
|
2431
|
-
joinTable: {
|
|
2432
|
-
name: meta.componentLink.tableName,
|
|
2433
|
-
joinColumn: {
|
|
2434
|
-
name: "entity_id",
|
|
2435
|
-
referencedColumn: "id"
|
|
2436
|
-
},
|
|
2437
|
-
inverseJoinColumn: {
|
|
2438
|
-
name: "component_id",
|
|
2439
|
-
referencedColumn: "id"
|
|
2440
|
-
},
|
|
2441
|
-
on: {
|
|
2442
|
-
field: attributeName
|
|
2443
|
-
},
|
|
2444
|
-
orderColumnName: "order",
|
|
2445
|
-
orderBy: {
|
|
2446
|
-
order: "asc"
|
|
2447
|
-
},
|
|
2448
|
-
pivotColumns: ["entity_id", "component_id", "field", "component_type"]
|
|
2526
|
+
return Object.assign(acc, { [key]: key });
|
|
2527
|
+
}, {});
|
|
2528
|
+
meta.columnToAttribute = columnToAttribute;
|
|
2449
2529
|
}
|
|
2450
|
-
|
|
2451
|
-
}
|
|
2530
|
+
this.validate();
|
|
2531
|
+
}
|
|
2532
|
+
}
|
|
2452
2533
|
const createAttribute = (attributeName, attribute) => {
|
|
2453
|
-
const columnName =
|
|
2534
|
+
const columnName = getColumnName(attributeName);
|
|
2454
2535
|
Object.assign(attribute, { columnName });
|
|
2455
2536
|
};
|
|
2537
|
+
const createMetadata = (models = []) => {
|
|
2538
|
+
const metadata = new Metadata();
|
|
2539
|
+
if (models.length) {
|
|
2540
|
+
metadata.loadModels(models);
|
|
2541
|
+
}
|
|
2542
|
+
return metadata;
|
|
2543
|
+
};
|
|
2456
2544
|
class Field {
|
|
2457
2545
|
config;
|
|
2458
2546
|
constructor(config) {
|
|
@@ -4309,9 +4397,6 @@ const createRepository = (uid, db) => {
|
|
|
4309
4397
|
updateMany(params) {
|
|
4310
4398
|
return db.entityManager.updateMany(uid, params);
|
|
4311
4399
|
},
|
|
4312
|
-
clone(id, params) {
|
|
4313
|
-
return db.entityManager.clone(uid, id, params);
|
|
4314
|
-
},
|
|
4315
4400
|
delete(params) {
|
|
4316
4401
|
return db.entityManager.delete(uid, params);
|
|
4317
4402
|
},
|
|
@@ -4337,9 +4422,6 @@ const createRepository = (uid, db) => {
|
|
|
4337
4422
|
deleteRelations(id) {
|
|
4338
4423
|
return db.entityManager.deleteRelations(uid, id);
|
|
4339
4424
|
},
|
|
4340
|
-
cloneRelations(targetId, sourceId, params) {
|
|
4341
|
-
return db.entityManager.cloneRelations(uid, targetId, sourceId, params);
|
|
4342
|
-
},
|
|
4343
4425
|
populate(entity, populate) {
|
|
4344
4426
|
return db.entityManager.populate(uid, entity, populate);
|
|
4345
4427
|
},
|
|
@@ -4415,6 +4497,19 @@ const deleteRelatedMorphOneRelationsAfterMorphToManyUpdate = async (rows, {
|
|
|
4415
4497
|
await createQueryBuilder(joinTable.name, db).delete().where({ $or: orWhere }).transacting(trx).execute();
|
|
4416
4498
|
}
|
|
4417
4499
|
};
|
|
4500
|
+
const getDocumentSiblingIdsQuery = (con, tableName, id) => {
|
|
4501
|
+
const models = Array.from(strapi.db.metadata.values());
|
|
4502
|
+
const isContentType = models.find((model) => {
|
|
4503
|
+
return model.tableName === tableName && model.attributes.documentId;
|
|
4504
|
+
});
|
|
4505
|
+
if (!isContentType) {
|
|
4506
|
+
return [id];
|
|
4507
|
+
}
|
|
4508
|
+
return con.from(tableName).select("id").where(
|
|
4509
|
+
"document_id",
|
|
4510
|
+
con.from(tableName).select("document_id").where("id", id)
|
|
4511
|
+
);
|
|
4512
|
+
};
|
|
4418
4513
|
const deletePreviousOneToAnyRelations = async ({
|
|
4419
4514
|
id,
|
|
4420
4515
|
attribute,
|
|
@@ -4429,10 +4524,8 @@ const deletePreviousOneToAnyRelations = async ({
|
|
|
4429
4524
|
}
|
|
4430
4525
|
const { joinTable } = attribute;
|
|
4431
4526
|
const { joinColumn, inverseJoinColumn } = joinTable;
|
|
4432
|
-
|
|
4433
|
-
|
|
4434
|
-
[joinColumn.name]: { $ne: id }
|
|
4435
|
-
}).where(joinTable.on || {}).transacting(trx).execute();
|
|
4527
|
+
const con = db.getConnection();
|
|
4528
|
+
await con.delete().from(joinTable.name).whereNotIn(joinColumn.name, getDocumentSiblingIdsQuery(con, joinColumn.referencedTable, id)).whereIn(inverseJoinColumn.name, relIdsToadd).where(joinTable.on || {}).transacting(trx);
|
|
4436
4529
|
await cleanOrderColumns({ attribute, db, inverseRelIds: relIdsToadd, transaction: trx });
|
|
4437
4530
|
};
|
|
4438
4531
|
const deletePreviousAnyToOneRelations = async ({
|
|
@@ -4444,14 +4537,15 @@ const deletePreviousAnyToOneRelations = async ({
|
|
|
4444
4537
|
}) => {
|
|
4445
4538
|
const { joinTable } = attribute;
|
|
4446
4539
|
const { joinColumn, inverseJoinColumn } = joinTable;
|
|
4540
|
+
const con = db.getConnection();
|
|
4447
4541
|
if (!isAnyToOne(attribute)) {
|
|
4448
4542
|
throw new Error("deletePreviousAnyToOneRelations can only be called for anyToOne relations");
|
|
4449
4543
|
}
|
|
4450
4544
|
if (isManyToAny(attribute)) {
|
|
4451
|
-
const relsToDelete = await
|
|
4452
|
-
|
|
4453
|
-
|
|
4454
|
-
|
|
4545
|
+
const relsToDelete = await con.select(inverseJoinColumn.name).from(joinTable.name).where(joinColumn.name, id).whereNotIn(
|
|
4546
|
+
inverseJoinColumn.name,
|
|
4547
|
+
getDocumentSiblingIdsQuery(con, inverseJoinColumn.referencedTable, relIdToadd)
|
|
4548
|
+
).where(joinTable.on || {}).transacting(trx);
|
|
4455
4549
|
const relIdsToDelete = map(inverseJoinColumn.name, relsToDelete);
|
|
4456
4550
|
await createQueryBuilder(joinTable.name, db).delete().where({
|
|
4457
4551
|
[joinColumn.name]: id,
|
|
@@ -4459,10 +4553,10 @@ const deletePreviousAnyToOneRelations = async ({
|
|
|
4459
4553
|
}).where(joinTable.on || {}).transacting(trx).execute();
|
|
4460
4554
|
await cleanOrderColumns({ attribute, db, inverseRelIds: relIdsToDelete, transaction: trx });
|
|
4461
4555
|
} else {
|
|
4462
|
-
await
|
|
4463
|
-
|
|
4464
|
-
|
|
4465
|
-
|
|
4556
|
+
await con.delete().from(joinTable.name).where(joinColumn.name, id).whereNotIn(
|
|
4557
|
+
inverseJoinColumn.name,
|
|
4558
|
+
getDocumentSiblingIdsQuery(con, inverseJoinColumn.referencedTable, relIdToadd)
|
|
4559
|
+
).where(joinTable.on || {}).transacting(trx);
|
|
4466
4560
|
}
|
|
4467
4561
|
};
|
|
4468
4562
|
const deleteRelations = async ({
|
|
@@ -4514,10 +4608,6 @@ const cleanOrderColumns = async ({
|
|
|
4514
4608
|
if (!(hasOrderColumn(attribute) && id) && !(hasInverseOrderColumn(attribute) && !isEmpty(inverseRelIds))) {
|
|
4515
4609
|
return;
|
|
4516
4610
|
}
|
|
4517
|
-
if (!strapi.db.dialect.supportsWindowFunctions()) {
|
|
4518
|
-
await cleanOrderColumnsForOldDatabases({ id, attribute, db, inverseRelIds, transaction: trx });
|
|
4519
|
-
return;
|
|
4520
|
-
}
|
|
4521
4611
|
const { joinTable } = attribute;
|
|
4522
4612
|
const { joinColumn, inverseJoinColumn, orderColumnName, inverseOrderColumnName } = joinTable;
|
|
4523
4613
|
const updateOrderColumn = async () => {
|
|
@@ -4579,94 +4669,6 @@ const cleanOrderColumns = async ({
|
|
|
4579
4669
|
};
|
|
4580
4670
|
return Promise.all([updateOrderColumn(), updateInverseOrderColumn()]);
|
|
4581
4671
|
};
|
|
4582
|
-
const cleanOrderColumnsForOldDatabases = async ({
|
|
4583
|
-
id,
|
|
4584
|
-
attribute,
|
|
4585
|
-
db,
|
|
4586
|
-
inverseRelIds,
|
|
4587
|
-
transaction: trx
|
|
4588
|
-
}) => {
|
|
4589
|
-
const { joinTable } = attribute;
|
|
4590
|
-
const { joinColumn, inverseJoinColumn, orderColumnName, inverseOrderColumnName } = joinTable;
|
|
4591
|
-
const randomSuffix = `${(/* @__PURE__ */ new Date()).valueOf()}_${randomBytes(16).toString("hex")}`;
|
|
4592
|
-
if (hasOrderColumn(attribute) && id) {
|
|
4593
|
-
const orderVar = `order_${randomSuffix}`;
|
|
4594
|
-
await db.connection.raw(`SET @${orderVar} = 0;`).transacting(trx);
|
|
4595
|
-
await db.connection.raw(
|
|
4596
|
-
`UPDATE :joinTableName: as a, (
|
|
4597
|
-
SELECT id, (@${orderVar}:=@${orderVar} + 1) AS src_order
|
|
4598
|
-
FROM :joinTableName:
|
|
4599
|
-
WHERE :joinColumnName: = :id
|
|
4600
|
-
ORDER BY :orderColumnName:
|
|
4601
|
-
) AS b
|
|
4602
|
-
SET :orderColumnName: = b.src_order
|
|
4603
|
-
WHERE a.id = b.id
|
|
4604
|
-
AND a.:joinColumnName: = :id`,
|
|
4605
|
-
{
|
|
4606
|
-
joinTableName: joinTable.name,
|
|
4607
|
-
orderColumnName,
|
|
4608
|
-
joinColumnName: joinColumn.name,
|
|
4609
|
-
id
|
|
4610
|
-
}
|
|
4611
|
-
).transacting(trx);
|
|
4612
|
-
}
|
|
4613
|
-
if (hasInverseOrderColumn(attribute) && !isEmpty(inverseRelIds)) {
|
|
4614
|
-
const orderVar = `order_${randomSuffix}`;
|
|
4615
|
-
const columnVar = `col_${randomSuffix}`;
|
|
4616
|
-
await db.connection.raw(`SET @${orderVar} = 0;`).transacting(trx);
|
|
4617
|
-
await db.connection.raw(
|
|
4618
|
-
`UPDATE ?? as a, (
|
|
4619
|
-
SELECT
|
|
4620
|
-
id,
|
|
4621
|
-
@${orderVar}:=CASE WHEN @${columnVar} = ?? THEN @${orderVar} + 1 ELSE 1 END AS inv_order,
|
|
4622
|
-
@${columnVar}:=?? ??
|
|
4623
|
-
FROM ?? a
|
|
4624
|
-
WHERE ?? IN(${inverseRelIds.map(() => "?").join(", ")})
|
|
4625
|
-
ORDER BY ??, ??
|
|
4626
|
-
) AS b
|
|
4627
|
-
SET ?? = b.inv_order
|
|
4628
|
-
WHERE a.id = b.id
|
|
4629
|
-
AND a.?? IN(${inverseRelIds.map(() => "?").join(", ")})`,
|
|
4630
|
-
[
|
|
4631
|
-
joinTable.name,
|
|
4632
|
-
inverseJoinColumn.name,
|
|
4633
|
-
inverseJoinColumn.name,
|
|
4634
|
-
inverseJoinColumn.name,
|
|
4635
|
-
joinTable.name,
|
|
4636
|
-
inverseJoinColumn.name,
|
|
4637
|
-
...inverseRelIds,
|
|
4638
|
-
inverseJoinColumn.name,
|
|
4639
|
-
joinColumn.name,
|
|
4640
|
-
inverseOrderColumnName,
|
|
4641
|
-
inverseJoinColumn.name,
|
|
4642
|
-
...inverseRelIds
|
|
4643
|
-
]
|
|
4644
|
-
).transacting(trx);
|
|
4645
|
-
}
|
|
4646
|
-
};
|
|
4647
|
-
const cleanInverseOrderColumn = async ({
|
|
4648
|
-
id,
|
|
4649
|
-
attribute,
|
|
4650
|
-
trx
|
|
4651
|
-
}) => {
|
|
4652
|
-
const con = strapi.db.connection;
|
|
4653
|
-
const { joinTable } = attribute;
|
|
4654
|
-
const { joinColumn, inverseJoinColumn, inverseOrderColumnName } = joinTable;
|
|
4655
|
-
switch (strapi.db.dialect.client) {
|
|
4656
|
-
case "mysql": {
|
|
4657
|
-
const subQuery = con(joinTable.name).select(inverseJoinColumn.name).max(inverseOrderColumnName, { as: "max_inv_order" }).groupBy(inverseJoinColumn.name).as("t2");
|
|
4658
|
-
await con(`${joinTable.name} as t1`).join(subQuery, `t1.${inverseJoinColumn.name}`, "=", `t2.${inverseJoinColumn.name}`).where(joinColumn.name, id).update({
|
|
4659
|
-
[inverseOrderColumnName]: con.raw("t2.max_inv_order + 1")
|
|
4660
|
-
}).transacting(trx);
|
|
4661
|
-
break;
|
|
4662
|
-
}
|
|
4663
|
-
default: {
|
|
4664
|
-
const selectMaxInverseOrder = con.raw(`max(${inverseOrderColumnName}) + 1`);
|
|
4665
|
-
const subQuery = con(`${joinTable.name} as t2`).select(selectMaxInverseOrder).whereRaw(`t2.${inverseJoinColumn.name} = t1.${inverseJoinColumn.name}`);
|
|
4666
|
-
await con(`${joinTable.name} as t1`).where(`t1.${joinColumn.name}`, id).update({ [inverseOrderColumnName]: subQuery }).transacting(trx);
|
|
4667
|
-
}
|
|
4668
|
-
}
|
|
4669
|
-
};
|
|
4670
4672
|
const sortConnectArray = (connectArr, initialArr = [], strictSort = true) => {
|
|
4671
4673
|
const sortedConnect = [];
|
|
4672
4674
|
let needsSorting = false;
|
|
@@ -4807,55 +4809,6 @@ const relationsOrderer = (initArr, idColumn, orderColumn, strict2) => {
|
|
|
4807
4809
|
}
|
|
4808
4810
|
};
|
|
4809
4811
|
};
|
|
4810
|
-
const replaceRegularRelations = async ({
|
|
4811
|
-
targetId,
|
|
4812
|
-
sourceId,
|
|
4813
|
-
attribute,
|
|
4814
|
-
omitIds,
|
|
4815
|
-
transaction: trx
|
|
4816
|
-
}) => {
|
|
4817
|
-
const { joinTable } = attribute;
|
|
4818
|
-
const { joinColumn, inverseJoinColumn } = joinTable;
|
|
4819
|
-
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();
|
|
4820
|
-
};
|
|
4821
|
-
const cloneRegularRelations = async ({
|
|
4822
|
-
targetId,
|
|
4823
|
-
sourceId,
|
|
4824
|
-
attribute,
|
|
4825
|
-
transaction: trx
|
|
4826
|
-
}) => {
|
|
4827
|
-
const { joinTable } = attribute;
|
|
4828
|
-
const { joinColumn, inverseJoinColumn, orderColumnName, inverseOrderColumnName } = joinTable;
|
|
4829
|
-
const connection = strapi.db.getConnection();
|
|
4830
|
-
const columns = [joinColumn.name, inverseJoinColumn.name];
|
|
4831
|
-
if (orderColumnName) {
|
|
4832
|
-
columns.push(orderColumnName);
|
|
4833
|
-
}
|
|
4834
|
-
if (inverseOrderColumnName) {
|
|
4835
|
-
columns.push(inverseOrderColumnName);
|
|
4836
|
-
}
|
|
4837
|
-
if (joinTable.on) {
|
|
4838
|
-
columns.push(...Object.keys(joinTable.on));
|
|
4839
|
-
}
|
|
4840
|
-
const selectStatement = connection.select(
|
|
4841
|
-
// Override joinColumn with the new id
|
|
4842
|
-
{ [joinColumn.name]: targetId },
|
|
4843
|
-
...columns.slice(1)
|
|
4844
|
-
).where(joinColumn.name, sourceId).from(joinTable.name).toSQL();
|
|
4845
|
-
await strapi.db.entityManager.createQueryBuilder(joinTable.name).insert(
|
|
4846
|
-
strapi.db.connection.raw(
|
|
4847
|
-
`(${columns.join(",")}) ${selectStatement.sql}`,
|
|
4848
|
-
selectStatement.bindings
|
|
4849
|
-
)
|
|
4850
|
-
).onConflict([joinColumn.name, inverseJoinColumn.name]).ignore().transacting(trx).execute();
|
|
4851
|
-
if (inverseOrderColumnName) {
|
|
4852
|
-
await cleanInverseOrderColumn({
|
|
4853
|
-
id: targetId,
|
|
4854
|
-
attribute,
|
|
4855
|
-
trx
|
|
4856
|
-
});
|
|
4857
|
-
}
|
|
4858
|
-
};
|
|
4859
4812
|
const isRecord = (value) => isObject(value) && !isNil(value);
|
|
4860
4813
|
const toId = (value) => {
|
|
4861
4814
|
if (isRecord(value) && "id" in value && isValidId(value.id)) {
|
|
@@ -5005,7 +4958,8 @@ const createEntityManager = (db) => {
|
|
|
5005
4958
|
const result = await this.findOne(uid, {
|
|
5006
4959
|
where: { id },
|
|
5007
4960
|
select: params.select,
|
|
5008
|
-
populate: params.populate
|
|
4961
|
+
populate: params.populate,
|
|
4962
|
+
filters: params.filters
|
|
5009
4963
|
});
|
|
5010
4964
|
await db.lifecycles.run("afterCreate", uid, { params, result }, states);
|
|
5011
4965
|
return result;
|
|
@@ -5063,7 +5017,8 @@ const createEntityManager = (db) => {
|
|
|
5063
5017
|
const result = await this.findOne(uid, {
|
|
5064
5018
|
where: { id },
|
|
5065
5019
|
select: params.select,
|
|
5066
|
-
populate: params.populate
|
|
5020
|
+
populate: params.populate,
|
|
5021
|
+
filters: params.filters
|
|
5067
5022
|
});
|
|
5068
5023
|
await db.lifecycles.run("afterUpdate", uid, { params, result }, states);
|
|
5069
5024
|
return result;
|
|
@@ -5082,50 +5037,6 @@ const createEntityManager = (db) => {
|
|
|
5082
5037
|
await db.lifecycles.run("afterUpdateMany", uid, { params, result }, states);
|
|
5083
5038
|
return result;
|
|
5084
5039
|
},
|
|
5085
|
-
async clone(uid, cloneId, params = {}) {
|
|
5086
|
-
const states = await db.lifecycles.run("beforeCreate", uid, { params });
|
|
5087
|
-
const metadata = db.metadata.get(uid);
|
|
5088
|
-
const { data } = params;
|
|
5089
|
-
if (!isNil(data) && !isPlainObject(data)) {
|
|
5090
|
-
throw new Error("Create expects a data object");
|
|
5091
|
-
}
|
|
5092
|
-
const entity = await this.findOne(uid, { where: { id: cloneId } });
|
|
5093
|
-
const dataToInsert = flow(
|
|
5094
|
-
// Omit unwanted properties
|
|
5095
|
-
omit(["id", "created_at", "updated_at"]),
|
|
5096
|
-
// Merge with provided data, set attribute to null if data attribute is null
|
|
5097
|
-
mergeWith(
|
|
5098
|
-
data || {},
|
|
5099
|
-
(original, override) => override === null ? override : original
|
|
5100
|
-
),
|
|
5101
|
-
// Process data with metadata
|
|
5102
|
-
(entity2) => processData(metadata, entity2, { withDefaults: true })
|
|
5103
|
-
)(entity);
|
|
5104
|
-
const res = await this.createQueryBuilder(uid).insert(dataToInsert).execute();
|
|
5105
|
-
const id = isRecord(res[0]) ? res[0].id : res[0];
|
|
5106
|
-
const trx = await strapi.db.transaction();
|
|
5107
|
-
try {
|
|
5108
|
-
const cloneAttrs = Object.entries(metadata.attributes).reduce((acc, [attrName, attr]) => {
|
|
5109
|
-
if (isRelationalAttribute(attr) && "joinTable" in attr && attr.joinTable && !("component" in attr)) {
|
|
5110
|
-
acc.push(attrName);
|
|
5111
|
-
}
|
|
5112
|
-
return acc;
|
|
5113
|
-
}, []);
|
|
5114
|
-
await this.cloneRelations(uid, id, cloneId, data, { cloneAttrs, transaction: trx.get() });
|
|
5115
|
-
await trx.commit();
|
|
5116
|
-
} catch (e) {
|
|
5117
|
-
await trx.rollback();
|
|
5118
|
-
await this.createQueryBuilder(uid).where({ id }).delete().execute();
|
|
5119
|
-
throw e;
|
|
5120
|
-
}
|
|
5121
|
-
const result = await this.findOne(uid, {
|
|
5122
|
-
where: { id },
|
|
5123
|
-
select: params.select,
|
|
5124
|
-
populate: params.populate
|
|
5125
|
-
});
|
|
5126
|
-
await db.lifecycles.run("afterCreate", uid, { params, result }, states);
|
|
5127
|
-
return result;
|
|
5128
|
-
},
|
|
5129
5040
|
async delete(uid, params = {}) {
|
|
5130
5041
|
const states = await db.lifecycles.run("beforeDelete", uid, { params });
|
|
5131
5042
|
const { where, select, populate } = params;
|
|
@@ -5411,9 +5322,8 @@ const createEntityManager = (db) => {
|
|
|
5411
5322
|
const isPartialUpdate = !has("set", cleanRelationData);
|
|
5412
5323
|
let relIdsToaddOrMove;
|
|
5413
5324
|
if (isPartialUpdate) {
|
|
5414
|
-
if (isAnyToOne(attribute))
|
|
5415
|
-
|
|
5416
|
-
}
|
|
5325
|
+
if (isAnyToOne(attribute))
|
|
5326
|
+
;
|
|
5417
5327
|
relIdsToaddOrMove = toIds(cleanRelationData.connect);
|
|
5418
5328
|
const relIdsToDelete = toIds(
|
|
5419
5329
|
differenceWith(
|
|
@@ -5627,58 +5537,6 @@ const createEntityManager = (db) => {
|
|
|
5627
5537
|
}
|
|
5628
5538
|
}
|
|
5629
5539
|
},
|
|
5630
|
-
// TODO: Clone polymorphic relations
|
|
5631
|
-
/**
|
|
5632
|
-
*
|
|
5633
|
-
* @param {string} uid - uid of the entity to clone
|
|
5634
|
-
* @param {number} targetId - id of the entity to clone into
|
|
5635
|
-
* @param {number} sourceId - id of the entity to clone from
|
|
5636
|
-
* @param {object} opt
|
|
5637
|
-
* @param {object} opt.cloneAttrs - key value pair of attributes to clone
|
|
5638
|
-
* @param {object} opt.transaction - transaction to use
|
|
5639
|
-
* @example cloneRelations('user', 3, 1, { cloneAttrs: ["comments"]})
|
|
5640
|
-
* @example cloneRelations('post', 5, 2, { cloneAttrs: ["comments", "likes"] })
|
|
5641
|
-
*/
|
|
5642
|
-
async cloneRelations(uid, targetId, sourceId, data, options) {
|
|
5643
|
-
const { attributes } = db.metadata.get(uid);
|
|
5644
|
-
const { cloneAttrs = [], transaction } = options ?? {};
|
|
5645
|
-
if (!attributes) {
|
|
5646
|
-
return;
|
|
5647
|
-
}
|
|
5648
|
-
await mapAsync(cloneAttrs, async (attrName) => {
|
|
5649
|
-
const attribute = attributes[attrName];
|
|
5650
|
-
if (attribute.type !== "relation") {
|
|
5651
|
-
throw new DatabaseError(
|
|
5652
|
-
`Attribute ${attrName} is not a relation attribute. Cloning relations is only supported for relation attributes.`
|
|
5653
|
-
);
|
|
5654
|
-
}
|
|
5655
|
-
if (isPolymorphic(attribute)) {
|
|
5656
|
-
return;
|
|
5657
|
-
}
|
|
5658
|
-
if ("joinColumn" in attribute) {
|
|
5659
|
-
return;
|
|
5660
|
-
}
|
|
5661
|
-
if (!attribute.joinTable) {
|
|
5662
|
-
return;
|
|
5663
|
-
}
|
|
5664
|
-
let omitIds = [];
|
|
5665
|
-
if (has(attrName, data)) {
|
|
5666
|
-
const cleanRelationData = toAssocs(data[attrName]);
|
|
5667
|
-
if (cleanRelationData.set) {
|
|
5668
|
-
return;
|
|
5669
|
-
}
|
|
5670
|
-
if (cleanRelationData.disconnect) {
|
|
5671
|
-
omitIds = toIds(cleanRelationData.disconnect);
|
|
5672
|
-
}
|
|
5673
|
-
}
|
|
5674
|
-
if (isOneToAny(attribute) && isBidirectional(attribute)) {
|
|
5675
|
-
await replaceRegularRelations({ targetId, sourceId, attribute, omitIds, transaction });
|
|
5676
|
-
} else {
|
|
5677
|
-
await cloneRegularRelations({ targetId, sourceId, attribute, transaction });
|
|
5678
|
-
}
|
|
5679
|
-
});
|
|
5680
|
-
await this.updateRelations(uid, targetId, data, { transaction });
|
|
5681
|
-
},
|
|
5682
5540
|
// TODO: add lifecycle events
|
|
5683
5541
|
async populate(uid, entity, populate) {
|
|
5684
5542
|
const entry = await this.findOne(uid, {
|
|
@@ -5740,7 +5598,7 @@ const createEntityManager = (db) => {
|
|
|
5740
5598
|
};
|
|
5741
5599
|
};
|
|
5742
5600
|
const createStorage = (opts) => {
|
|
5743
|
-
const { db, tableName
|
|
5601
|
+
const { db, tableName } = opts;
|
|
5744
5602
|
const hasMigrationTable = () => db.getSchemaConnection().hasTable(tableName);
|
|
5745
5603
|
const createMigrationTable = () => {
|
|
5746
5604
|
return db.getSchemaConnection().createTable(tableName, (table) => {
|
|
@@ -5770,7 +5628,7 @@ const createStorage = (opts) => {
|
|
|
5770
5628
|
};
|
|
5771
5629
|
};
|
|
5772
5630
|
const wrapTransaction = (db) => (fn) => () => {
|
|
5773
|
-
return db.connection.transaction((trx) => Promise.resolve(fn(trx)));
|
|
5631
|
+
return db.connection.transaction((trx) => Promise.resolve(fn(trx, db)));
|
|
5774
5632
|
};
|
|
5775
5633
|
const migrationResolver = ({ name, path: path2, context }) => {
|
|
5776
5634
|
const { db } = context;
|
|
@@ -5794,31 +5652,82 @@ const migrationResolver = ({ name, path: path2, context }) => {
|
|
|
5794
5652
|
down: wrapTransaction(db)(migration.down)
|
|
5795
5653
|
};
|
|
5796
5654
|
};
|
|
5797
|
-
const
|
|
5798
|
-
const
|
|
5799
|
-
fse.ensureDirSync(
|
|
5800
|
-
|
|
5655
|
+
const createUserMigrationProvider = (db) => {
|
|
5656
|
+
const dir = db.config.settings.migrations.dir;
|
|
5657
|
+
fse.ensureDirSync(dir);
|
|
5658
|
+
const context = { db };
|
|
5659
|
+
const umzugProvider = new Umzug({
|
|
5801
5660
|
storage: createStorage({ db, tableName: "strapi_migrations" }),
|
|
5802
5661
|
logger: console,
|
|
5803
|
-
context
|
|
5662
|
+
context,
|
|
5804
5663
|
migrations: {
|
|
5805
|
-
glob: ["*.{js,sql}", { cwd:
|
|
5664
|
+
glob: ["*.{js,sql}", { cwd: dir }],
|
|
5806
5665
|
resolve: migrationResolver
|
|
5807
5666
|
}
|
|
5808
5667
|
});
|
|
5668
|
+
return {
|
|
5669
|
+
async shouldRun() {
|
|
5670
|
+
const pendingMigrations = await umzugProvider.pending();
|
|
5671
|
+
return pendingMigrations.length > 0 && db.config?.settings?.runMigrations === true;
|
|
5672
|
+
},
|
|
5673
|
+
async up() {
|
|
5674
|
+
await umzugProvider.up();
|
|
5675
|
+
},
|
|
5676
|
+
async down() {
|
|
5677
|
+
await umzugProvider.down();
|
|
5678
|
+
}
|
|
5679
|
+
};
|
|
5680
|
+
};
|
|
5681
|
+
const internalMigrations = [];
|
|
5682
|
+
const createInternalMigrationProvider = (db) => {
|
|
5683
|
+
const context = { db };
|
|
5684
|
+
const umzugProvider = new Umzug({
|
|
5685
|
+
storage: createStorage({ db, tableName: "strapi_migrations_internal" }),
|
|
5686
|
+
logger: console,
|
|
5687
|
+
context,
|
|
5688
|
+
migrations: internalMigrations.map((migration) => {
|
|
5689
|
+
return {
|
|
5690
|
+
name: migration.name,
|
|
5691
|
+
up: wrapTransaction(context.db)(migration.up),
|
|
5692
|
+
down: wrapTransaction(context.db)(migration.down)
|
|
5693
|
+
};
|
|
5694
|
+
})
|
|
5695
|
+
});
|
|
5696
|
+
return {
|
|
5697
|
+
async shouldRun() {
|
|
5698
|
+
const pendingMigrations = await umzugProvider.pending();
|
|
5699
|
+
return pendingMigrations.length > 0;
|
|
5700
|
+
},
|
|
5701
|
+
async up() {
|
|
5702
|
+
await umzugProvider.up();
|
|
5703
|
+
},
|
|
5704
|
+
async down() {
|
|
5705
|
+
await umzugProvider.down();
|
|
5706
|
+
}
|
|
5707
|
+
};
|
|
5809
5708
|
};
|
|
5810
5709
|
const createMigrationsProvider = (db) => {
|
|
5811
|
-
const
|
|
5710
|
+
const providers = [createUserMigrationProvider(db), createInternalMigrationProvider(db)];
|
|
5812
5711
|
return {
|
|
5813
5712
|
async shouldRun() {
|
|
5814
|
-
const
|
|
5815
|
-
|
|
5713
|
+
const shouldRunResponses = await Promise.all(
|
|
5714
|
+
providers.map((provider) => provider.shouldRun())
|
|
5715
|
+
);
|
|
5716
|
+
return shouldRunResponses.some((shouldRun) => shouldRun);
|
|
5816
5717
|
},
|
|
5817
5718
|
async up() {
|
|
5818
|
-
|
|
5719
|
+
for (const provider of providers) {
|
|
5720
|
+
if (await provider.shouldRun()) {
|
|
5721
|
+
await provider.up();
|
|
5722
|
+
}
|
|
5723
|
+
}
|
|
5819
5724
|
},
|
|
5820
5725
|
async down() {
|
|
5821
|
-
|
|
5726
|
+
for (const provider of providers) {
|
|
5727
|
+
if (await provider.shouldRun()) {
|
|
5728
|
+
await provider.down();
|
|
5729
|
+
}
|
|
5730
|
+
}
|
|
5822
5731
|
}
|
|
5823
5732
|
};
|
|
5824
5733
|
};
|
|
@@ -5931,82 +5840,41 @@ const createLifecyclesProvider = (db) => {
|
|
|
5931
5840
|
}
|
|
5932
5841
|
};
|
|
5933
5842
|
};
|
|
5934
|
-
class LegacySqliteClient extends SqliteClient {
|
|
5935
|
-
_driver() {
|
|
5936
|
-
return require("sqlite3");
|
|
5937
|
-
}
|
|
5938
|
-
}
|
|
5939
5843
|
const clientMap = {
|
|
5940
|
-
|
|
5941
|
-
|
|
5942
|
-
|
|
5844
|
+
sqlite: "better-sqlite3",
|
|
5845
|
+
mysql: "mysql2",
|
|
5846
|
+
postgres: "pg"
|
|
5943
5847
|
};
|
|
5944
|
-
|
|
5945
|
-
|
|
5946
|
-
|
|
5947
|
-
|
|
5948
|
-
|
|
5949
|
-
|
|
5950
|
-
|
|
5951
|
-
|
|
5952
|
-
|
|
5953
|
-
|
|
5954
|
-
|
|
5955
|
-
const
|
|
5956
|
-
|
|
5957
|
-
|
|
5958
|
-
|
|
5959
|
-
|
|
5960
|
-
|
|
5961
|
-
|
|
5962
|
-
|
|
5963
|
-
|
|
5964
|
-
|
|
5965
|
-
|
|
5966
|
-
|
|
5967
|
-
if (knexConfig.client === "sqlite") {
|
|
5968
|
-
const sqlitePackageName = getSqlitePackageName();
|
|
5969
|
-
knexConfig.client = clientMap[sqlitePackageName];
|
|
5848
|
+
function isClientValid(config) {
|
|
5849
|
+
return Object.keys(clientMap).includes(config.client);
|
|
5850
|
+
}
|
|
5851
|
+
const createConnection = (userConfig, strapiConfig) => {
|
|
5852
|
+
if (!isClientValid(userConfig)) {
|
|
5853
|
+
throw new Error(`Unsupported database client ${userConfig.client}`);
|
|
5854
|
+
}
|
|
5855
|
+
const knexConfig = { ...userConfig, client: clientMap[userConfig.client] };
|
|
5856
|
+
if (strapiConfig?.pool?.afterCreate) {
|
|
5857
|
+
knexConfig.pool = knexConfig.pool || {};
|
|
5858
|
+
const userAfterCreate = knexConfig.pool?.afterCreate;
|
|
5859
|
+
const strapiAfterCreate = strapiConfig.pool.afterCreate;
|
|
5860
|
+
knexConfig.pool.afterCreate = (conn, done) => {
|
|
5861
|
+
strapiAfterCreate(conn, (err, nativeConn) => {
|
|
5862
|
+
if (err) {
|
|
5863
|
+
return done(err, nativeConn);
|
|
5864
|
+
}
|
|
5865
|
+
if (userAfterCreate) {
|
|
5866
|
+
return userAfterCreate(nativeConn, done);
|
|
5867
|
+
}
|
|
5868
|
+
return done(null, nativeConn);
|
|
5869
|
+
});
|
|
5870
|
+
};
|
|
5970
5871
|
}
|
|
5971
5872
|
return knex(knexConfig);
|
|
5972
5873
|
};
|
|
5973
|
-
const transformAttribute = (attribute) => {
|
|
5974
|
-
switch (attribute.type) {
|
|
5975
|
-
case "media": {
|
|
5976
|
-
return {
|
|
5977
|
-
type: "relation",
|
|
5978
|
-
relation: attribute.multiple === true ? "morphMany" : "morphOne",
|
|
5979
|
-
target: "plugin::upload.file",
|
|
5980
|
-
morphBy: "related"
|
|
5981
|
-
};
|
|
5982
|
-
}
|
|
5983
|
-
default: {
|
|
5984
|
-
return attribute;
|
|
5985
|
-
}
|
|
5986
|
-
}
|
|
5987
|
-
};
|
|
5988
|
-
const transformContentTypes = (contentTypes) => {
|
|
5989
|
-
return contentTypes.map((contentType) => {
|
|
5990
|
-
const model = {
|
|
5991
|
-
...contentType,
|
|
5992
|
-
// reuse new model def
|
|
5993
|
-
singularName: contentType.modelName,
|
|
5994
|
-
tableName: contentType.collectionName,
|
|
5995
|
-
attributes: {
|
|
5996
|
-
...Object.keys(contentType.attributes || {}).reduce((attrs, attrName) => {
|
|
5997
|
-
return Object.assign(attrs, {
|
|
5998
|
-
[attrName]: transformAttribute(contentType.attributes[attrName])
|
|
5999
|
-
});
|
|
6000
|
-
}, {})
|
|
6001
|
-
}
|
|
6002
|
-
};
|
|
6003
|
-
return model;
|
|
6004
|
-
});
|
|
6005
|
-
};
|
|
6006
5874
|
const getLinksWithoutMappedBy = (db) => {
|
|
6007
5875
|
const relationsToUpdate = {};
|
|
6008
|
-
db.metadata.forEach((
|
|
6009
|
-
const attributes =
|
|
5876
|
+
db.metadata.forEach((modelMetadata) => {
|
|
5877
|
+
const attributes = modelMetadata.attributes;
|
|
6010
5878
|
Object.values(attributes).forEach((attribute) => {
|
|
6011
5879
|
if (attribute.type !== "relation") {
|
|
6012
5880
|
return;
|
|
@@ -6034,19 +5902,19 @@ const isLinkTableEmpty = async (db, linkTableName) => {
|
|
|
6034
5902
|
const validateBidirectionalRelations = async (db) => {
|
|
6035
5903
|
const invalidLinks = getLinksWithoutMappedBy(db);
|
|
6036
5904
|
for (const { relation, invRelation } of invalidLinks) {
|
|
6037
|
-
const
|
|
6038
|
-
const
|
|
6039
|
-
const joinTableName = getJoinTableName(
|
|
6040
|
-
const inverseJoinTableName = getJoinTableName(
|
|
5905
|
+
const modelMetadata = db.metadata.get(invRelation.target);
|
|
5906
|
+
const invModelMetadata = db.metadata.get(relation.target);
|
|
5907
|
+
const joinTableName = getJoinTableName(modelMetadata.tableName, invRelation.inversedBy);
|
|
5908
|
+
const inverseJoinTableName = getJoinTableName(invModelMetadata.tableName, relation.inversedBy);
|
|
6041
5909
|
const joinTableEmpty = await isLinkTableEmpty(db, joinTableName);
|
|
6042
5910
|
const inverseJoinTableEmpty = await isLinkTableEmpty(db, inverseJoinTableName);
|
|
6043
5911
|
if (joinTableEmpty) {
|
|
6044
5912
|
process.emitWarning(
|
|
6045
|
-
`Error on attribute "${invRelation.inversedBy}" in model "${
|
|
5913
|
+
`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}" }`
|
|
6046
5914
|
);
|
|
6047
5915
|
} else if (inverseJoinTableEmpty) {
|
|
6048
5916
|
process.emitWarning(
|
|
6049
|
-
`Error on attribute "${relation.inversedBy}" in model "${
|
|
5917
|
+
`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}" }`
|
|
6050
5918
|
);
|
|
6051
5919
|
} else
|
|
6052
5920
|
;
|
|
@@ -6058,6 +5926,11 @@ const validateRelations = async (db) => {
|
|
|
6058
5926
|
async function validateDatabase(db) {
|
|
6059
5927
|
await validateRelations(db);
|
|
6060
5928
|
}
|
|
5929
|
+
const afterCreate = (db) => (nativeConnection, done) => {
|
|
5930
|
+
db.dialect.initialize(nativeConnection).then(() => {
|
|
5931
|
+
return done(null, nativeConnection);
|
|
5932
|
+
});
|
|
5933
|
+
};
|
|
6061
5934
|
class Database {
|
|
6062
5935
|
connection;
|
|
6063
5936
|
dialect;
|
|
@@ -6067,14 +5940,7 @@ class Database {
|
|
|
6067
5940
|
migrations;
|
|
6068
5941
|
lifecycles;
|
|
6069
5942
|
entityManager;
|
|
6070
|
-
static transformContentTypes = transformContentTypes;
|
|
6071
|
-
static async init(config) {
|
|
6072
|
-
const db = new Database(config);
|
|
6073
|
-
await validateDatabase(db);
|
|
6074
|
-
return db;
|
|
6075
|
-
}
|
|
6076
5943
|
constructor(config) {
|
|
6077
|
-
this.metadata = createMetadata(config.models);
|
|
6078
5944
|
this.config = {
|
|
6079
5945
|
...config,
|
|
6080
5946
|
settings: {
|
|
@@ -6085,13 +5951,20 @@ class Database {
|
|
|
6085
5951
|
};
|
|
6086
5952
|
this.dialect = getDialect(this);
|
|
6087
5953
|
this.dialect.configure();
|
|
6088
|
-
this.
|
|
6089
|
-
this.
|
|
5954
|
+
this.metadata = createMetadata();
|
|
5955
|
+
this.connection = createConnection(this.config.connection, {
|
|
5956
|
+
pool: { afterCreate: afterCreate(this) }
|
|
5957
|
+
});
|
|
6090
5958
|
this.schema = createSchemaProvider(this);
|
|
6091
5959
|
this.migrations = createMigrationsProvider(this);
|
|
6092
5960
|
this.lifecycles = createLifecyclesProvider(this);
|
|
6093
5961
|
this.entityManager = createEntityManager(this);
|
|
6094
5962
|
}
|
|
5963
|
+
async init({ models }) {
|
|
5964
|
+
this.metadata.loadModels(models);
|
|
5965
|
+
await validateDatabase(this);
|
|
5966
|
+
return this;
|
|
5967
|
+
}
|
|
6095
5968
|
query(uid) {
|
|
6096
5969
|
if (!this.metadata.has(uid)) {
|
|
6097
5970
|
throw new Error(`Model ${uid} not found`);
|
|
@@ -6155,9 +6028,11 @@ class Database {
|
|
|
6155
6028
|
await this.connection.destroy();
|
|
6156
6029
|
}
|
|
6157
6030
|
}
|
|
6031
|
+
const utils = { identifiers };
|
|
6158
6032
|
export {
|
|
6159
6033
|
Database,
|
|
6160
6034
|
index as errors,
|
|
6161
|
-
isKnexQuery
|
|
6035
|
+
isKnexQuery,
|
|
6036
|
+
utils
|
|
6162
6037
|
};
|
|
6163
6038
|
//# sourceMappingURL=index.mjs.map
|