@forestadmin/datasource-sql 1.2.4 → 1.2.6
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/introspection/introspector.js +6 -6
- package/dist/introspection/types.d.ts +1 -2
- package/dist/orm-builder/helpers/relation-extractor.d.ts +1 -0
- package/dist/orm-builder/helpers/relation-extractor.js +20 -23
- package/dist/orm-builder/helpers/relation-name-generator.js +6 -5
- package/dist/orm-builder/model.d.ts +6 -0
- package/dist/orm-builder/model.js +49 -14
- package/package.json +1 -1
|
@@ -56,24 +56,25 @@ class Introspector {
|
|
|
56
56
|
]);
|
|
57
57
|
// Create columns
|
|
58
58
|
const columns = Object.entries(columnDescriptions).map(([name, description]) => {
|
|
59
|
-
const indexes = tableIndexes.filter(i => i.fields.find(f => f.attribute === name));
|
|
60
59
|
const references = tableReferences.filter(r => r.columnName === name);
|
|
61
|
-
const options = { name, description,
|
|
60
|
+
const options = { name, description, references };
|
|
62
61
|
return this.getColumn(sequelize, logger, tableName, options);
|
|
63
62
|
});
|
|
64
63
|
return {
|
|
65
64
|
name: tableName,
|
|
66
65
|
columns: (await Promise.all(columns)).filter(Boolean),
|
|
66
|
+
unique: tableIndexes
|
|
67
|
+
.filter(i => i.unique || i.primary)
|
|
68
|
+
.map(i => i.fields.map(f => f.attribute)),
|
|
67
69
|
};
|
|
68
70
|
}
|
|
69
71
|
static async getColumn(sequelize, logger, tableName, options) {
|
|
70
|
-
const { name, description,
|
|
72
|
+
const { name, description, references } = options;
|
|
71
73
|
const dialect = sequelize.getDialect();
|
|
72
74
|
const typeConverter = new sql_type_converter_1.default(sequelize);
|
|
73
75
|
try {
|
|
74
76
|
const type = await typeConverter.convert(tableName, name, description);
|
|
75
77
|
const defaultValue = new default_value_parser_1.default(dialect).parse(description.defaultValue, type);
|
|
76
|
-
const unique = !!indexes.find(i => i.fields.length === 1 && i.fields[0].attribute === name && i.unique);
|
|
77
78
|
// Workaround autoincrement flag not being properly set when using postgres
|
|
78
79
|
const autoIncrement = Boolean(description.autoIncrement || description.defaultValue?.match?.(/^nextval\(.+\)$/));
|
|
79
80
|
return {
|
|
@@ -82,7 +83,6 @@ class Introspector {
|
|
|
82
83
|
defaultValue: autoIncrement ? null : defaultValue,
|
|
83
84
|
name,
|
|
84
85
|
allowNull: description.allowNull,
|
|
85
|
-
unique,
|
|
86
86
|
primaryKey: description.primaryKey,
|
|
87
87
|
constraints: references.map(r => ({
|
|
88
88
|
table: r.referencedTableName,
|
|
@@ -96,4 +96,4 @@ class Introspector {
|
|
|
96
96
|
}
|
|
97
97
|
}
|
|
98
98
|
exports.default = Introspector;
|
|
99
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
99
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW50cm9zcGVjdG9yLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2ludHJvc3BlY3Rpb24vaW50cm9zcGVjdG9yLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBR0EscUNBU2tCO0FBQ2xCLDBGQUFnRTtBQUNoRSxzRkFBNEQ7QUFHNUQsTUFBcUIsWUFBWTtJQUMvQixNQUFNLENBQUMsS0FBSyxDQUFDLFVBQVUsQ0FBQyxTQUFvQixFQUFFLE1BQWU7UUFDM0QsSUFBSTtZQUNGLE1BQU0sVUFBVSxHQUFHLE1BQU0sSUFBSSxDQUFDLGFBQWEsQ0FBQyxTQUFTLENBQUMsQ0FBQztZQUV2RCxPQUFPLE1BQU0sT0FBTyxDQUFDLEdBQUcsQ0FBQyxVQUFVLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxTQUFTLEVBQUUsTUFBTSxFQUFFLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQztTQUMxRjtRQUFDLE9BQU8sQ0FBQyxFQUFFO1lBQ1YsUUFBUyxDQUE4QixDQUFDLElBQUksRUFBRTtnQkFDNUMsS0FBSywwQkFBMEI7b0JBQzdCLE1BQU0sSUFBSSx3QkFBZSxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsQ0FBQztnQkFDdkMsS0FBSyw0QkFBNEI7b0JBQy9CLE1BQU0sSUFBSSwwQkFBaUIsQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLENBQUM7Z0JBQ3pDLEtBQUssaUNBQWlDO29CQUNwQyxNQUFNLElBQUksK0JBQXNCLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxDQUFDO2dCQUM5QyxLQUFLLGdDQUFnQztvQkFDbkMsTUFBTSxJQUFJLDhCQUFxQixDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsQ0FBQztnQkFDN0MsS0FBSyw0QkFBNEI7b0JBQy9CLE1BQU0sSUFBSSwwQkFBaUIsQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLENBQUM7Z0JBQ3pDLEtBQUssd0NBQXdDO29CQUMz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
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { AbstractDataType, AbstractDataTypeConstructor, QueryInterface } from 'sequelize/types';
|
|
2
|
-
export type SequelizeIndex = Awaited<ReturnType<QueryInterface['showIndex']>>[number];
|
|
3
2
|
export type SequelizeColumn = Awaited<ReturnType<QueryInterface['describeTable']>>[number];
|
|
4
3
|
export type SequelizeColumnType = AbstractDataType | AbstractDataTypeConstructor;
|
|
5
4
|
export type SequelizeReference = Awaited<ReturnType<QueryInterface['getForeignKeyReferencesForTable']>>[number];
|
|
@@ -27,12 +26,12 @@ export type ColumnType = {
|
|
|
27
26
|
};
|
|
28
27
|
export type Table = {
|
|
29
28
|
name: string;
|
|
29
|
+
unique: string[][];
|
|
30
30
|
columns: {
|
|
31
31
|
name: string;
|
|
32
32
|
type: ColumnType;
|
|
33
33
|
defaultValue: unknown;
|
|
34
34
|
allowNull: boolean;
|
|
35
|
-
unique: boolean;
|
|
36
35
|
autoIncrement: boolean;
|
|
37
36
|
primaryKey: boolean;
|
|
38
37
|
constraints: {
|
|
@@ -23,7 +23,7 @@ class RelationExtractor {
|
|
|
23
23
|
// Skip HasMany to junction tables
|
|
24
24
|
if (!this.isJunctionTable(table))
|
|
25
25
|
relations.push({
|
|
26
|
-
type: column.
|
|
26
|
+
type: this.isUnique(table, column.name) ? 'HasOne' : 'HasMany',
|
|
27
27
|
from: constraint.table,
|
|
28
28
|
to: table.name,
|
|
29
29
|
originKey: column.name,
|
|
@@ -37,33 +37,30 @@ class RelationExtractor {
|
|
|
37
37
|
const relations = [];
|
|
38
38
|
const columns = table.columns.filter(c => c.primaryKey && c.constraints.length === 1);
|
|
39
39
|
if (this.isJunctionTable(table)) {
|
|
40
|
-
const [column1, column2]
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
through: table.name,
|
|
56
|
-
originKey: column2.name,
|
|
57
|
-
foreignKey: column1.name,
|
|
58
|
-
originKeyTarget: column2.constraints[0].column,
|
|
59
|
-
foreignKeyTarget: column1.constraints[0].column,
|
|
60
|
-
});
|
|
40
|
+
for (const [column1, column2] of [
|
|
41
|
+
[columns[0], columns[1]],
|
|
42
|
+
[columns[1], columns[0]],
|
|
43
|
+
]) {
|
|
44
|
+
relations.push({
|
|
45
|
+
type: 'BelongsToMany',
|
|
46
|
+
from: column1.constraints[0].table,
|
|
47
|
+
to: column2.constraints[0].table,
|
|
48
|
+
through: table.name,
|
|
49
|
+
originKey: column1.name,
|
|
50
|
+
foreignKey: column2.name,
|
|
51
|
+
originKeyTarget: column1.constraints[0].column,
|
|
52
|
+
foreignKeyTarget: column2.constraints[0].column,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
61
55
|
}
|
|
62
56
|
return relations;
|
|
63
57
|
}
|
|
64
58
|
static isJunctionTable(table) {
|
|
65
59
|
return table.columns.filter(c => c.primaryKey && c.constraints.length === 1).length === 2;
|
|
66
60
|
}
|
|
61
|
+
static isUnique(table, columnName) {
|
|
62
|
+
return table.unique.some(u => u.length === 1 && u[0] === columnName);
|
|
63
|
+
}
|
|
67
64
|
}
|
|
68
65
|
exports.default = RelationExtractor;
|
|
69
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
66
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVsYXRpb24tZXh0cmFjdG9yLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL29ybS1idWlsZGVyL2hlbHBlcnMvcmVsYXRpb24tZXh0cmFjdG9yLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBR0EsTUFBcUIsaUJBQWlCO0lBQ3BDLE1BQU0sQ0FBQyxhQUFhLENBQUMsU0FBaUIsRUFBRSxNQUFlO1FBQ3JELE1BQU0sU0FBUyxHQUFlLEVBQUUsQ0FBQztRQUVqQyxLQUFLLE1BQU0sS0FBSyxJQUFJLE1BQU0sRUFBRTtZQUMxQixTQUFTLENBQUMsSUFBSSxDQUFDLEdBQUcsSUFBSSxDQUFDLG1CQUFtQixDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUM7WUFDbkQsU0FBUyxDQUFDLElBQUksQ0FBQyxHQUFHLElBQUksQ0FBQyxxQkFBcUIsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDO1NBQ3REO1FBRUQsT0FBTyxTQUFTLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksS0FBSyxTQUFTLENBQUMsQ0FBQztJQUNyRCxDQUFDO0lBRU8sTUFBTSxDQUFDLG1CQUFtQixDQUFDLEtBQVk7UUFDN0MsTUFBTSxTQUFTLEdBQWUsRUFBRSxDQUFDO1FBRWpDLEtBQUssTUFBTSxNQUFNLElBQUksS0FBSyxDQUFDLE9BQU8sRUFBRTtZQUNsQyxLQUFLLE1BQU0sVUFBVSxJQUFJLE1BQU0sQ0FBQyxXQUFXLEVBQUU7Z0JBQzNDLFNBQVMsQ0FBQyxJQUFJLENBQUM7b0JBQ2IsSUFBSSxFQUFFLFdBQVc7b0JBQ2pCLElBQUksRUFBRSxLQUFLLENBQUMsSUFBSTtvQkFDaEIsRUFBRSxFQUFFLFVBQVUsQ0FBQyxLQUFLO29CQUNwQixVQUFVLEVBQUUsTUFBTSxDQUFDLElBQUk7b0JBQ3ZCLGdCQUFnQixFQUFFLFVBQVUsQ0FBQyxNQUFNO2lCQUNwQyxDQUFDLENBQUM7Z0JBRUgsa0NBQWtDO2dCQUNsQyxJ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
|
|
@@ -34,10 +34,11 @@ class RelationNameGenerator {
|
|
|
34
34
|
static getSimpleName(relation) {
|
|
35
35
|
const { foreignKey } = relation;
|
|
36
36
|
let name = relation.to;
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
37
|
+
for (const suffix of ['_id', 'Id']) {
|
|
38
|
+
if (foreignKey?.length > suffix.length && foreignKey?.endsWith(suffix)) {
|
|
39
|
+
name = foreignKey.substring(0, foreignKey.length - suffix.length);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
41
42
|
return relation.type === 'HasMany' || relation.type === 'BelongsToMany'
|
|
42
43
|
? (0, pluralize_1.plural)(name)
|
|
43
44
|
: (0, pluralize_1.singular)(name);
|
|
@@ -58,4 +59,4 @@ class RelationNameGenerator {
|
|
|
58
59
|
}
|
|
59
60
|
}
|
|
60
61
|
exports.default = RelationNameGenerator;
|
|
61
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
62
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVsYXRpb24tbmFtZS1nZW5lcmF0b3IuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvb3JtLWJ1aWxkZXIvaGVscGVycy9yZWxhdGlvbi1uYW1lLWdlbmVyYXRvci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLHlDQUE2QztBQUs3QyxNQUFxQixxQkFBcUI7SUFDeEMsTUFBTSxDQUFDLHNCQUFzQixDQUFDLEtBQVksRUFBRSxTQUFxQjs7UUFDL0QsTUFBTSxLQUFLLEdBQUcsU0FBUyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDLENBQUM7UUFFaEQsd0JBQXdCO1FBQ3hCLE1BQU0sYUFBYSxHQUE2QixFQUFFLENBQUM7UUFFbkQsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLEtBQUssQ0FBQyxNQUFNLEVBQUUsQ0FBQyxJQUFJLENBQUMsRUFBRTtZQUN4QyxhQUFhLE1BQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxNQUF0QixhQUFhLE9BQWUsRUFBRSxFQUFDO1lBQy9CLGFBQWEsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUM7U0FDakM7UUFFRCw0REFBNEQ7UUFDNUQsS0FBSyxNQUFNLENBQUMsSUFBSSxFQUFFLE9BQU8sQ0FBQyxJQUFJLE1BQU0sQ0FBQyxPQUFPLENBQUMsYUFBYSxDQUFDLEVBQUU7WUFDM0Qsb0NBQW9DO1lBQ3BDLE1BQU0sbUJBQW1CLEdBQUcsQ0FBQyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksS0FBSyxJQUFJLENBQUMsQ0FBQztZQUN2RSxNQUFNLDBCQUEwQixHQUFHLE9BQU8sQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDO1lBRXRELDRCQUE0QjtZQUM1QiwwREFBMEQ7WUFDMUQsTUFBTSxrQkFBa0IsR0FBRyxJQUFJLEtBQUssS0FBSyxDQUFDLElBQUksQ0FBQztZQUMvQyxNQUFNLHlCQUF5QixHQUFHLFNBQVMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsT0FBTyxLQUFLLElBQUksQ0FBQyxDQUFDO1lBRTFFLElBQ0UsbUJBQW1CO2dCQUNuQixrQkFBa0I7Z0JBQ2xCLDBCQUEwQjtnQkFDMUIseUJBQXlCLEVBQ3pCO2dCQUNBLEtBQUssTUFBTSxLQUFLLElBQUksT0FBTyxFQUFFO29CQUMzQixLQUFLLENBQUMsS0FBSyxDQUFDLEdBQUcsSUFBSSxDQUFDLGFBQWEsQ0FBQyxTQUFTLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQztpQkFDckQ7YUFDRjtTQUNGO1FBRUQsT0FBTyxLQUFLLENBQUM7SUFDZixDQUFDO0lBRU8sTUFBTSxDQUFDLGFBQWEsQ0FBQyxRQUFrQjtRQUM3QyxNQUFNLEVBQUUsVUFBVSxFQUFFLEdBQUcsUUFBUSxDQUFDO1FBQ2hDLElBQUksSUFBSSxHQUFHLFFBQVEsQ0FBQyxFQUFFLENBQUM7UUFFdkIsS0FBSyxNQUFNLE1BQU0sSUFBSSxDQUFDLEtBQUssRUFBRSxJQUFJLENBQUMsRUFBRTtZQUNsQyxJQUFJLFVBQVUsRUFBRSxNQUFNLEdBQUcsTUFBTSxDQUFDLE1BQU0sSUFBSSxVQUFVLEVBQUUsUUFBUSxDQUFDLE1BQU0sQ0FBQyxFQUFFO2dCQUN0RSxJQUFJLEdBQUcsVUFBVSxDQUFDLFNBQVMsQ0FBQyxDQUFDLEVBQUUsVUFBVSxDQUFDLE1BQU0sR0FBRyxNQUFNLENBQUMsTUFBTSxDQUFDLENBQUM7YUFDbkU7U0FDRjtRQUVELE9BQU8sUUFBUSxDQUFDLElBQUksS0FBSyxTQUFTLElBQUksUUFBUSxDQUFDLElBQUksS0FBSyxlQUFlO1lBQ3JFLENBQUMsQ0FBQyxJQUFBLGtCQUFNLEVBQUMsSUFBSSxDQUFDO1lBQ2QsQ0FBQyxDQUFDLElBQUEsb0JBQVEsRUFBQyxJQUFJLENBQUMsQ0FBQztJQUNyQixDQUFDO0lBRU8sTUFBTSxDQUFDLGFBQWEsQ0FBQyxRQUFrQjtRQUM3QyxRQUFRLFFBQVEsQ0FBQyxJQUFJLEVBQUU7WUFDckIsS0FBSyxXQUFXO2dCQUNkLE9BQU8sR0FBRyxJQUFBLG9CQUFRLEVBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQyxZQUFZLFFBQVEsQ0FBQyxVQUFVLEVBQUUsQ0FBQztZQUNuRSxLQUFLLFFBQVE7Z0JBQ1gsT0FBTyxHQUFHLElBQUEsb0JBQVEsRUFBQyxRQUFRLENBQUMsRUFBRSxDQUFDLFlBQVksUUFBUSxDQUFDLElBQUksSUFBSSxRQUFRLENBQUMsU0FBUyxFQUFFLENBQUM7WUFDbkYsS0FBSyxlQUFlO2dCQUNsQixPQUFPLEdBQUcsSUFBQSxrQkFBTSxFQUFDLFFBQVEsQ0FBQyxFQUFFLENBQUMsWUFBWSxRQUFRLENBQUMsT0FBTyxFQUFFLENBQUM7WUFDOUQsS0FBSyxTQUFTO2dCQUNaLE9BQU8sR0FBRyxJQUFBLGtCQUFNLEVBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQyxZQUFZLFFBQVEsQ0FBQyxJQUFJLElBQUksUUFBUSxDQUFDLFNBQVMsRUFBRSxDQUFDO1lBQ2pGO2dCQUNFLE1BQU0sSUFBSSxLQUFLLENBQUMseUJBQXlCLFFBQVEsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDO1NBQzdEO0lBQ0gsQ0FBQztDQUNGO0FBbkVELHdDQW1FQyJ9
|
|
@@ -4,6 +4,12 @@ import { Table } from '../introspection/types';
|
|
|
4
4
|
export default class ModelBuilder {
|
|
5
5
|
static defineModels(sequelize: Sequelize, logger: Logger, tables: Table[]): void;
|
|
6
6
|
private static defineModel;
|
|
7
|
+
private static buildModelAttributes;
|
|
8
|
+
/**
|
|
9
|
+
* When the primary key is missing, we attempt to find a column that may act as such.
|
|
10
|
+
* This enables us to support tables that have no primary key.
|
|
11
|
+
*/
|
|
12
|
+
private static guessPrimaryKeyInPlace;
|
|
7
13
|
private static hasTimestamps;
|
|
8
14
|
private static isParanoid;
|
|
9
15
|
}
|
|
@@ -11,22 +11,12 @@ class ModelBuilder {
|
|
|
11
11
|
}
|
|
12
12
|
}
|
|
13
13
|
static defineModel(sequelize, logger, table) {
|
|
14
|
-
const modelAttrs = {};
|
|
15
14
|
const hasTimestamps = this.hasTimestamps(table);
|
|
16
15
|
const isParanoid = this.isParanoid(table);
|
|
17
16
|
const dialect = sequelize.getDialect();
|
|
18
|
-
|
|
19
|
-
const isExplicit = !(hasTimestamps && (column.name === 'updatedAt' || column.name === 'createdAt')) &&
|
|
20
|
-
!(isParanoid && column.name === 'deletedAt');
|
|
21
|
-
// Clone object, because sequelize modifies it.
|
|
22
|
-
if (isExplicit)
|
|
23
|
-
modelAttrs[column.name] = {
|
|
24
|
-
...column,
|
|
25
|
-
type: sequelize_type_1.default.makeType(dialect, column.type, table.name, column.name),
|
|
26
|
-
};
|
|
27
|
-
}
|
|
17
|
+
const attributes = this.buildModelAttributes(logger, table, hasTimestamps, isParanoid, dialect);
|
|
28
18
|
try {
|
|
29
|
-
const model = sequelize.define(table.name,
|
|
19
|
+
const model = sequelize.define(table.name, attributes, {
|
|
30
20
|
tableName: table.name,
|
|
31
21
|
timestamps: hasTimestamps,
|
|
32
22
|
paranoid: isParanoid,
|
|
@@ -34,14 +24,59 @@ class ModelBuilder {
|
|
|
34
24
|
// @see https://sequelize.org/docs/v6/other-topics/legacy/#primary-keys
|
|
35
25
|
// Tell sequelize NOT to invent primary keys when we don't provide them.
|
|
36
26
|
// (Note that this does not seem to work)
|
|
37
|
-
if (!
|
|
27
|
+
if (!attributes.id && model.getAttributes().id) {
|
|
38
28
|
model.removeAttribute('id');
|
|
39
29
|
}
|
|
40
30
|
}
|
|
41
31
|
catch (e) {
|
|
32
|
+
// In practice, now that we added the primary key guessing, this should not happen anymore.
|
|
33
|
+
// But we keep it here just in case.
|
|
42
34
|
logger?.('Warn', `Skipping table "${table.name}" because of error: ${e.message}`);
|
|
43
35
|
}
|
|
44
36
|
}
|
|
37
|
+
static buildModelAttributes(logger, table, hasTimestamps, isParanoid, dialect) {
|
|
38
|
+
const modelAttrs = {};
|
|
39
|
+
for (const column of table.columns) {
|
|
40
|
+
const isExplicit = !(hasTimestamps && (column.name === 'updatedAt' || column.name === 'createdAt')) &&
|
|
41
|
+
!(isParanoid && column.name === 'deletedAt');
|
|
42
|
+
// Clone object, because sequelize modifies it.
|
|
43
|
+
if (isExplicit)
|
|
44
|
+
modelAttrs[column.name] = {
|
|
45
|
+
...column,
|
|
46
|
+
type: sequelize_type_1.default.makeType(dialect, column.type, table.name, column.name),
|
|
47
|
+
unique: table.unique.some(u => u.length === 1 && u[0] === column.name),
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
// If there is no primary key, we try to guess one.
|
|
51
|
+
if (!table.columns.some(c => c.primaryKey)) {
|
|
52
|
+
this.guessPrimaryKeyInPlace(logger, table, modelAttrs);
|
|
53
|
+
}
|
|
54
|
+
return modelAttrs;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* When the primary key is missing, we attempt to find a column that may act as such.
|
|
58
|
+
* This enables us to support tables that have no primary key.
|
|
59
|
+
*/
|
|
60
|
+
static guessPrimaryKeyInPlace(logger, table, attributes) {
|
|
61
|
+
// Try to find a column named "id".
|
|
62
|
+
let primaryKeys = table.columns.some(c => c.name === 'id') ? ['id'] : [];
|
|
63
|
+
// If there is no id column, look at unique indexes, and use the shortest one.
|
|
64
|
+
// (hopefully only one column, but this can also be a composite key for many-to-many tables)
|
|
65
|
+
if (!primaryKeys.length && table.unique.length) {
|
|
66
|
+
[primaryKeys] = [...table.unique].sort((a, b) => a.length - b.length);
|
|
67
|
+
}
|
|
68
|
+
// If all the columns have contraints (e.g. foreign keys), use all of them as a composite key.
|
|
69
|
+
if (!primaryKeys.length &&
|
|
70
|
+
table.columns.length === 2 &&
|
|
71
|
+
table.columns.every(c => c.constraints.length)) {
|
|
72
|
+
primaryKeys = table.columns.map(c => c.name);
|
|
73
|
+
}
|
|
74
|
+
for (const column of primaryKeys)
|
|
75
|
+
attributes[column].primaryKey = true;
|
|
76
|
+
if (primaryKeys.length) {
|
|
77
|
+
logger?.('Warn', `Table "${table.name}" has no primary key. Using "${primaryKeys.join(', ')}".`);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
45
80
|
static hasTimestamps(table) {
|
|
46
81
|
return (!!table.columns.find(c => c.name === 'createdAt') &&
|
|
47
82
|
!!table.columns.find(c => c.name === 'updatedAt'));
|
|
@@ -51,4 +86,4 @@ class ModelBuilder {
|
|
|
51
86
|
}
|
|
52
87
|
}
|
|
53
88
|
exports.default = ModelBuilder;
|
|
54
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
89
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibW9kZWwuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvb3JtLWJ1aWxkZXIvbW9kZWwudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFJQSw4RUFBNEQ7QUFHNUQsTUFBcUIsWUFBWTtJQUMvQixNQUFNLENBQUMsWUFBWSxDQUFDLFNBQW9CLEVBQUUsTUFBYyxFQUFFLE1BQWU7UUFDdkUsS0FBSyxNQUFNLEtBQUssSUFBSSxNQUFNLEVBQUU7WUFDMUIsSUFBSSxDQUFDLFdBQVcsQ0FBQyxTQUFTLEVBQUUsTUFBTSxFQUFFLEtBQUssQ0FBQyxDQUFDO1NBQzVDO0lBQ0gsQ0FBQztJQUVPLE1BQU0sQ0FBQyxXQUFXLENBQUMsU0FBb0IsRUFBRSxNQUFjLEVBQUUsS0FBWTtRQUMzRSxNQUFNLGFBQWEsR0FBRyxJQUFJLENBQUMsYUFBYSxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQ2hELE1BQU0sVUFBVSxHQUFHLElBQUksQ0FBQyxVQUFVLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDMUMsTUFBTSxPQUFPLEdBQUcsU0FBUyxDQUFDLFVBQVUsRUFBRSxDQUFDO1FBQ3ZDLE1BQU0sVUFBVSxHQUFHLElBQUksQ0FBQyxvQkFBb0IsQ0FBQyxNQUFNLEVBQUUsS0FBSyxFQUFFLGFBQWEsRUFBRSxVQUFVLEVBQUUsT0FBTyxDQUFDLENBQUM7UUFFaEcsSUFBSTtZQUNGLE1BQU0sS0FBSyxHQUFHLFNBQVMsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLElBQUksRUFBRSxVQUFVLEVBQUU7Z0JBQ3JELFNBQVMsRUFBRSxLQUFLLENBQUMsSUFBSTtnQkFDckIsVUFBVSxFQUFFLGFBQWE7Z0JBQ3pCLFFBQVEsRUFBRSxVQUFVO2FBQ3JCLENBQUMsQ0FBQztZQUVILHVFQUF1RTtZQUN2RSx3RUFBd0U7WUFDeEUseUNBQXlDO1lBQ3pDLElBQUksQ0FBQyxVQUFVLENBQUMsRUFBRSxJQUFJLEtBQUssQ0FBQyxhQUFhLEVBQUUsQ0FBQyxFQUFFLEVB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
|