@forestadmin/datasource-sql 1.0.0-beta.42 → 1.0.0-beta.43
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/CHANGELOG.md +7 -0
- package/dist/datasource-factory.d.ts +7 -0
- package/dist/datasource-factory.js +34 -0
- package/dist/index.js +4 -5
- package/dist/sequelize-builder.d.ts +33 -0
- package/dist/sequelize-builder.js +162 -0
- package/dist/utils/types.d.ts +25 -0
- package/dist/utils/types.js +3 -0
- package/package.json +1 -1
- package/dist/datasource.d.ts +0 -26
- package/dist/datasource.js +0 -154
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
# @forestadmin/datasource-sql [1.0.0-beta.43](https://github.com/ForestAdmin/agent-nodejs/compare/@forestadmin/datasource-sql@1.0.0-beta.42...@forestadmin/datasource-sql@1.0.0-beta.43) (2022-09-02)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* **datasource-sql:** skip models which do not have primary keys ([#393](https://github.com/ForestAdmin/agent-nodejs/issues/393)) ([820fbe9](https://github.com/ForestAdmin/agent-nodejs/commit/820fbe9087ec9977fc998363016ce1728438c8f2))
|
|
7
|
+
|
|
1
8
|
# @forestadmin/datasource-sql [1.0.0-beta.42](https://github.com/ForestAdmin/agent-nodejs/compare/@forestadmin/datasource-sql@1.0.0-beta.41...@forestadmin/datasource-sql@1.0.0-beta.42) (2022-08-23)
|
|
2
9
|
|
|
3
10
|
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { DataSource } from '@forestadmin/datasource-toolkit';
|
|
2
|
+
import { Builder } from './utils/types';
|
|
3
|
+
export default class SqlDataSourceFactory {
|
|
4
|
+
static build(builder: Builder): Promise<DataSource>;
|
|
5
|
+
private static canDefineRelation;
|
|
6
|
+
}
|
|
7
|
+
//# sourceMappingURL=datasource-factory.d.ts.map
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
class SqlDataSourceFactory {
|
|
4
|
+
static async build(builder) {
|
|
5
|
+
const excludedTables = new Set();
|
|
6
|
+
const tableNames = await builder.getTableNames();
|
|
7
|
+
const modelsToBuild = tableNames.map(async (tableName) => {
|
|
8
|
+
try {
|
|
9
|
+
await builder.defineModel(tableName);
|
|
10
|
+
}
|
|
11
|
+
catch (e) {
|
|
12
|
+
excludedTables.add(tableName);
|
|
13
|
+
builder.logger?.('Warn', `Skipping table "${tableName}" and its relations because of error: ${e.message}`);
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
await Promise.all(modelsToBuild);
|
|
17
|
+
const relationsToBuild = tableNames.map(async (tableName) => {
|
|
18
|
+
if (await SqlDataSourceFactory.canDefineRelation(tableName, builder, excludedTables)) {
|
|
19
|
+
await builder.defineRelation(tableName);
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
await Promise.all(relationsToBuild);
|
|
23
|
+
return builder.buildDataSource();
|
|
24
|
+
}
|
|
25
|
+
static async canDefineRelation(tableName, builder, excludedTables) {
|
|
26
|
+
if (excludedTables.has(tableName)) {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
const relatedTables = await builder.getRelatedTables(tableName);
|
|
30
|
+
return !relatedTables.some(table => excludedTables.has(table));
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
exports.default = SqlDataSourceFactory;
|
|
34
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGF0YXNvdXJjZS1mYWN0b3J5LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL2RhdGFzb3VyY2UtZmFjdG9yeS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUlBLE1BQXFCLG9CQUFvQjtJQUN2QyxNQUFNLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQyxPQUFnQjtRQUNqQyxNQUFNLGNBQWMsR0FBRyxJQUFJLEdBQUcsRUFBVSxDQUFDO1FBQ3pDLE1BQU0sVUFBVSxHQUFHLE1BQU0sT0FBTyxDQUFDLGFBQWEsRUFBRSxDQUFDO1FBRWpELE1BQU0sYUFBYSxHQUFHLFVBQVUsQ0FBQyxHQUFHLENBQUMsS0FBSyxFQUFDLFNBQVMsRUFBQyxFQUFFO1lBQ3JELElBQUk7Z0JBQ0YsTUFBTSxPQUFPLENBQUMsV0FBVyxDQUFDLFNBQVMsQ0FBQyxDQUFDO2FBQ3RDO1lBQUMsT0FBTyxDQUFDLEVBQUU7Z0JBQ1YsY0FBYyxDQUFDLEdBQUcsQ0FBQyxTQUFTLENBQUMsQ0FBQztnQkFDOUIsT0FBTyxDQUFDLE1BQU0sRUFBRSxDQUNkLE1BQU0sRUFDTixtQkFBbUIsU0FBUyx5Q0FBeUMsQ0FBQyxDQUFDLE9BQU8sRUFBRSxDQUNqRixDQUFDO2FBQ0g7UUFDSCxDQUFDLENBQUMsQ0FBQztRQUNILE1BQU0sT0FBTyxDQUFDLEdBQUcsQ0FBQyxhQUFhLENBQUMsQ0FBQztRQUVqQyxNQUFNLGdCQUFnQixHQUFHLFVBQVUsQ0FBQyxHQUFHLENBQUMsS0FBSyxFQUFDLFNBQVMsRUFBQyxFQUFFO1lBQ3hELElBQUksTUFBTSxvQkFBb0IsQ0FBQyxpQkFBaUIsQ0FBQyxTQUFTLEVBQUUsT0FBTyxFQUFFLGNBQWMsQ0FBQyxFQUFFO2dCQUNwRixNQUFNLE9BQU8sQ0FBQyxjQUFjLENBQUMsU0FBUyxDQUFDLENBQUM7YUFDekM7UUFDSCxDQUFDLENBQUMsQ0FBQztRQUNILE1BQU0sT0FBTyxDQUFDLEdBQUcsQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDO1FBRXBDLE9BQU8sT0FBTyxDQUFDLGVBQWUsRUFBRSxDQUFDO0lBQ25DLENBQUM7SUFFTyxNQUFNLENBQUMsS0FBSyxDQUFDLGlCQUFpQixDQUFDLFNBQWlCLEVBQUUsT0FBZ0IsRUFBRSxjQUFjO1FBQ3hGLElBQUksY0FBYyxDQUFDLEdBQUcsQ0FBQyxTQUFTLENBQUMsRUFBRTtZQUNqQyxPQUFPLEtBQUssQ0FBQztTQUNkO1FBRUQsTUFBTSxhQUFhLEdBQUcsTUFBTSxPQUFPLENBQUMsZ0JBQWdCLENBQUMsU0FBUyxDQUFDLENBQUM7UUFFaEUsT0FBTyxDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxjQUFjLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUM7SUFDakUsQ0FBQztDQUNGO0FBckNELHVDQXFDQyJ9
|
package/dist/index.js
CHANGED
|
@@ -4,17 +4,16 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.createSqlDataSource = void 0;
|
|
7
|
-
const
|
|
7
|
+
const sequelize_builder_1 = __importDefault(require("./sequelize-builder"));
|
|
8
|
+
const datasource_factory_1 = __importDefault(require("./datasource-factory"));
|
|
8
9
|
// eslint-disable-next-line import/prefer-default-export
|
|
9
10
|
function createSqlDataSource(connectionUri) {
|
|
10
11
|
if (!/.*:\/\//g.test(connectionUri))
|
|
11
12
|
throw new Error(`Connection Uri "${connectionUri}" provided to Sql data source is not valid.` +
|
|
12
13
|
' Should be <dialect>://<connection>.');
|
|
13
14
|
return async (logger) => {
|
|
14
|
-
|
|
15
|
-
await datasource.build();
|
|
16
|
-
return datasource;
|
|
15
|
+
return datasource_factory_1.default.build(new sequelize_builder_1.default(connectionUri, logger));
|
|
17
16
|
};
|
|
18
17
|
}
|
|
19
18
|
exports.createSqlDataSource = createSqlDataSource;
|
|
20
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
19
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBRUEsNEVBQTZEO0FBQzdELDhFQUF3RDtBQUV4RCx3REFBd0Q7QUFDeEQsU0FBZ0IsbUJBQW1CLENBQUMsYUFBcUI7SUFDdkQsSUFBSSxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDO1FBQ2pDLE1BQU0sSUFBSSxLQUFLLENBQ2IsbUJBQW1CLGFBQWEsNkNBQTZDO1lBQzNFLHNDQUFzQyxDQUN6QyxDQUFDO0lBRUosT0FBTyxLQUFLLEVBQUUsTUFBYyxFQUFFLEVBQUU7UUFDOUIsT0FBTyw0QkFBb0IsQ0FBQyxLQUFLLENBQUMsSUFBSSwyQkFBMEIsQ0FBQyxhQUFhLEVBQUUsTUFBTSxDQUFDLENBQUMsQ0FBQztJQUMzRixDQUFDLENBQUM7QUFDSixDQUFDO0FBVkQsa0RBVUMifQ==
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { DataSource, Logger } from '@forestadmin/datasource-toolkit';
|
|
2
|
+
import { SequelizeDataSource } from '@forestadmin/datasource-sequelize';
|
|
3
|
+
import { Builder, Model } from './utils/types';
|
|
4
|
+
export default class SequelizeDataSourceBuilder extends SequelizeDataSource implements Builder {
|
|
5
|
+
logger?: Logger;
|
|
6
|
+
constructor(connectionUri: string, logger?: Logger);
|
|
7
|
+
buildDataSource(): DataSource;
|
|
8
|
+
get models(): {
|
|
9
|
+
[modelName: string]: Model;
|
|
10
|
+
};
|
|
11
|
+
defineModel(tableName: any): Promise<void>;
|
|
12
|
+
defineRelation(tableName: string): Promise<void>;
|
|
13
|
+
getRelatedTables(tableName: string): Promise<string[]>;
|
|
14
|
+
/**
|
|
15
|
+
* Fixes Sequelize behavior incorrectly implemented.
|
|
16
|
+
* Types indicate that showAllTables() should return a list of string, but it
|
|
17
|
+
* returns a list of object for both mariadb & mssql
|
|
18
|
+
* @see https://github.com/sequelize/sequelize/blob/main/src/dialects/mariadb/query.js#L295
|
|
19
|
+
*/
|
|
20
|
+
getTableNames(): Promise<string[]>;
|
|
21
|
+
private getForeignReferences;
|
|
22
|
+
private getUniqueFields;
|
|
23
|
+
private buildFieldDescriptions;
|
|
24
|
+
private isJunctionTable;
|
|
25
|
+
private buildForJunctionTable;
|
|
26
|
+
private buildOtherRelations;
|
|
27
|
+
private buildModel;
|
|
28
|
+
private static removeTimestampColumns;
|
|
29
|
+
private static isParanoid;
|
|
30
|
+
private static removeParanoidColumn;
|
|
31
|
+
private static hasTimestamps;
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=sequelize-builder.d.ts.map
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const sequelize_1 = require("sequelize");
|
|
7
|
+
const datasource_sequelize_1 = require("@forestadmin/datasource-sequelize");
|
|
8
|
+
const default_value_parser_1 = __importDefault(require("./utils/default-value-parser"));
|
|
9
|
+
const sql_type_converter_1 = __importDefault(require("./utils/sql-type-converter"));
|
|
10
|
+
class SequelizeDataSourceBuilder extends datasource_sequelize_1.SequelizeDataSource {
|
|
11
|
+
constructor(connectionUri, logger) {
|
|
12
|
+
const logging = (sql) => logger?.('Debug', sql.substring(sql.indexOf(':') + 2));
|
|
13
|
+
super(new sequelize_1.Sequelize(connectionUri, { logging }));
|
|
14
|
+
this.logger = logger;
|
|
15
|
+
}
|
|
16
|
+
buildDataSource() {
|
|
17
|
+
super.createCollections(this.sequelize.models, this.logger);
|
|
18
|
+
return this;
|
|
19
|
+
}
|
|
20
|
+
get models() {
|
|
21
|
+
return Object.keys(this.sequelize.models).reduce((models, modelName) => {
|
|
22
|
+
const model = this.sequelize.model(modelName);
|
|
23
|
+
models[modelName] = {
|
|
24
|
+
getAttributes: () => model.getAttributes(),
|
|
25
|
+
name: modelName,
|
|
26
|
+
associations: model.associations,
|
|
27
|
+
};
|
|
28
|
+
return models;
|
|
29
|
+
}, {});
|
|
30
|
+
}
|
|
31
|
+
async defineModel(tableName) {
|
|
32
|
+
const columnDescriptions = await this.sequelize.getQueryInterface().describeTable(tableName);
|
|
33
|
+
const fieldDescriptions = await this.buildFieldDescriptions(columnDescriptions, tableName);
|
|
34
|
+
this.buildModel(tableName, fieldDescriptions);
|
|
35
|
+
}
|
|
36
|
+
async defineRelation(tableName) {
|
|
37
|
+
const foreignReferences = await this.getForeignReferences(tableName);
|
|
38
|
+
if (this.isJunctionTable(tableName)) {
|
|
39
|
+
this.buildForJunctionTable(tableName, foreignReferences);
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
const uniqueFields = await this.getUniqueFields(tableName);
|
|
43
|
+
this.buildOtherRelations(foreignReferences, tableName, uniqueFields);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
async getRelatedTables(tableName) {
|
|
47
|
+
const foreignReferences = await this.getForeignReferences(tableName);
|
|
48
|
+
if (this.isJunctionTable(tableName)) {
|
|
49
|
+
const [{ referencedTableName: tableA }, { referencedTableName: tableB }] = foreignReferences;
|
|
50
|
+
return [tableA, tableB];
|
|
51
|
+
}
|
|
52
|
+
return foreignReferences.map(({ referencedTableName }) => referencedTableName);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Fixes Sequelize behavior incorrectly implemented.
|
|
56
|
+
* Types indicate that showAllTables() should return a list of string, but it
|
|
57
|
+
* returns a list of object for both mariadb & mssql
|
|
58
|
+
* @see https://github.com/sequelize/sequelize/blob/main/src/dialects/mariadb/query.js#L295
|
|
59
|
+
*/
|
|
60
|
+
async getTableNames() {
|
|
61
|
+
const names = await this.sequelize
|
|
62
|
+
.getQueryInterface()
|
|
63
|
+
.showAllTables();
|
|
64
|
+
return names.map(name => (typeof name === 'string' ? name : name?.tableName));
|
|
65
|
+
}
|
|
66
|
+
async getForeignReferences(tableName) {
|
|
67
|
+
return this.sequelize.getQueryInterface().getForeignKeyReferencesForTable(tableName);
|
|
68
|
+
}
|
|
69
|
+
async getUniqueFields(tableName) {
|
|
70
|
+
const tableIndex = await this.sequelize.getQueryInterface().showIndex(tableName);
|
|
71
|
+
return tableIndex
|
|
72
|
+
.filter(({ primary, unique, fields }) => !primary && unique && fields.length === 1)
|
|
73
|
+
.map(({ fields }) => fields.map(({ attribute }) => attribute))
|
|
74
|
+
.flat();
|
|
75
|
+
}
|
|
76
|
+
async buildFieldDescriptions(columnDescriptions, tableName) {
|
|
77
|
+
const fields = Object.entries(columnDescriptions).map(async ([columnName, columnDescription]) => {
|
|
78
|
+
try {
|
|
79
|
+
const type = await new sql_type_converter_1.default(this.sequelize).convert(tableName, columnName, columnDescription);
|
|
80
|
+
let defaultValue = new default_value_parser_1.default(this.sequelize.getDialect()).parse(columnDescription.defaultValue, type);
|
|
81
|
+
if (columnDescription.primaryKey && defaultValue) {
|
|
82
|
+
defaultValue = null;
|
|
83
|
+
columnDescription.autoIncrement = true;
|
|
84
|
+
}
|
|
85
|
+
return [columnName, { ...columnDescription, type, defaultValue }];
|
|
86
|
+
}
|
|
87
|
+
catch (e) {
|
|
88
|
+
this.logger?.('Warn', `Skipping column ${tableName}.${columnName} (${e.message})`);
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
const fieldDescriptions = await Promise.all(fields);
|
|
92
|
+
return fieldDescriptions.filter(Boolean);
|
|
93
|
+
}
|
|
94
|
+
isJunctionTable(modelName) {
|
|
95
|
+
const model = this.sequelize.model(modelName);
|
|
96
|
+
const modelAttributes = model.getAttributes();
|
|
97
|
+
// remove autogenerated field to keep the belongsToMany behavior
|
|
98
|
+
const attributes = Object.values(modelAttributes);
|
|
99
|
+
const modelAttributesDefinition = attributes.filter(({ _autoGenerated }) => !_autoGenerated);
|
|
100
|
+
if (modelAttributesDefinition.length !== 2)
|
|
101
|
+
return false;
|
|
102
|
+
return !modelAttributesDefinition.some(({ primaryKey }) => !primaryKey);
|
|
103
|
+
}
|
|
104
|
+
buildForJunctionTable(modelName, foreignReferences) {
|
|
105
|
+
const [{ referencedTableName: tableA, columnName: columnA, referencedColumnName: referencedColumnA }, { referencedTableName: tableB, columnName: columnB, referencedColumnName: referencedColumnB },] = foreignReferences;
|
|
106
|
+
const model = this.sequelize.model(modelName);
|
|
107
|
+
const modelA = this.sequelize.model(tableA);
|
|
108
|
+
const modelB = this.sequelize.model(tableB);
|
|
109
|
+
const through = model.name;
|
|
110
|
+
modelA.belongsToMany(modelB, { through, foreignKey: columnA, otherKey: columnB });
|
|
111
|
+
modelB.belongsToMany(modelA, { through, foreignKey: columnB, otherKey: columnA });
|
|
112
|
+
model.belongsTo(modelA, { foreignKey: columnA, targetKey: referencedColumnA });
|
|
113
|
+
model.belongsTo(modelB, { foreignKey: columnB, targetKey: referencedColumnB });
|
|
114
|
+
}
|
|
115
|
+
buildOtherRelations(foreignReferences, modelName, uniqueFields) {
|
|
116
|
+
foreignReferences.forEach(({ columnName: foreignKey, referencedTableName, referencedColumnName: sourceKey }) => {
|
|
117
|
+
const referencedModel = this.sequelize.model(referencedTableName);
|
|
118
|
+
const model = this.sequelize.model(modelName);
|
|
119
|
+
model.belongsTo(referencedModel, { foreignKey, targetKey: sourceKey });
|
|
120
|
+
if (uniqueFields.includes(foreignKey)) {
|
|
121
|
+
referencedModel.hasOne(model, { foreignKey, sourceKey });
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
referencedModel.hasMany(model, { foreignKey, sourceKey });
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
buildModel(tableName, fieldDescriptions) {
|
|
129
|
+
let model = Object.fromEntries(fieldDescriptions);
|
|
130
|
+
const columnNames = Object.keys(model);
|
|
131
|
+
const timestamps = SequelizeDataSourceBuilder.hasTimestamps(columnNames);
|
|
132
|
+
const paranoid = SequelizeDataSourceBuilder.isParanoid(columnNames);
|
|
133
|
+
if (timestamps) {
|
|
134
|
+
model = SequelizeDataSourceBuilder.removeTimestampColumns(model);
|
|
135
|
+
}
|
|
136
|
+
if (paranoid) {
|
|
137
|
+
model = SequelizeDataSourceBuilder.removeParanoidColumn(model);
|
|
138
|
+
}
|
|
139
|
+
this.sequelize.define(tableName, model, { tableName, timestamps, paranoid });
|
|
140
|
+
}
|
|
141
|
+
static removeTimestampColumns(modelDefinition) {
|
|
142
|
+
const copy = { ...modelDefinition };
|
|
143
|
+
delete copy.createdAt;
|
|
144
|
+
delete copy.updatedAt;
|
|
145
|
+
return copy;
|
|
146
|
+
}
|
|
147
|
+
static isParanoid(columnNames) {
|
|
148
|
+
return columnNames.includes('deletedAt');
|
|
149
|
+
}
|
|
150
|
+
static removeParanoidColumn(modelDefinition) {
|
|
151
|
+
const copy = { ...modelDefinition };
|
|
152
|
+
delete copy.deletedAt;
|
|
153
|
+
return copy;
|
|
154
|
+
}
|
|
155
|
+
static hasTimestamps(columnNames) {
|
|
156
|
+
const hasCreatedAt = columnNames.includes('createdAt');
|
|
157
|
+
const hasUpdatedAt = columnNames.includes('updatedAt');
|
|
158
|
+
return hasCreatedAt && hasUpdatedAt;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
exports.default = SequelizeDataSourceBuilder;
|
|
162
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VxdWVsaXplLWJ1aWxkZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvc2VxdWVsaXplLWJ1aWxkZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFBQSx5Q0FBb0Y7QUFFcEYsNEVBQXdFO0FBR3hFLHdGQUE4RDtBQUM5RCxvRkFBMEQ7QUFFMUQsTUFBcUIsMEJBQTJCLFNBQVEsMENBQW1CO0lBR3pFLFlBQVksYUFBcUIsRUFBRSxNQUFlO1FBQ2hELE1BQU0sT0FBTyxHQUFHLENBQUMsR0FBVyxFQUFFLEVBQUUsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxPQUFPLEVBQUUsR0FBRyxDQUFDLFNBQVMsQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDeEYsS0FBSyxDQUFDLElBQUkscUJBQVMsQ0FBQyxhQUFhLEVBQUUsRUFBRSxPQUFPLEVBQUUsQ0FBQyxDQUFDLENBQUM7UUFDakQsSUFBSSxDQUFDLE1BQU0sR0FBRyxNQUFNLENBQUM7SUFDdkIsQ0FBQztJQUVELGVBQWU7UUFDYixLQUFLLENBQUMsaUJBQWlCLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxNQUFNLEVBQUUsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBRTVELE9BQU8sSUFBSSxDQUFDO0lBQ2QsQ0FBQztJQUVELElBQUksTUFBTTtRQUNSLE9BQU8sTUFBTSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLE1BQU0sQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLE1BQU0sRUFBRSxTQUFTLEVBQUUsRUFBRTtZQUNyRSxNQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQyxTQUFTLENBQUMsQ0FBQztZQUU5QyxNQUFNLENBQUMsU0FBUyxDQUFDLEdBQUc7Z0JBQ2xCLGFBQWEsRUFBRSxHQUFHLEVBQUUsQ0FBQyxLQUFLLENBQUMsYUFBYSxFQUFFO2dCQUMx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
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { AbstractDataType, AbstractDataTypeConstructor, ColumnDescription } from 'sequelize';
|
|
2
|
+
import { DataSource, Logger } from '@forestadmin/datasource-toolkit';
|
|
3
|
+
import { QueryInterface } from 'sequelize/types/dialects/abstract/query-interface';
|
|
4
|
+
export declare type FieldDescription = (string | (Omit<ColumnDescription, 'defaultValue' | 'type'> & {
|
|
5
|
+
defaultValue: unknown;
|
|
6
|
+
type: AbstractDataType | AbstractDataTypeConstructor;
|
|
7
|
+
}))[];
|
|
8
|
+
export declare type ForeignKeyReference = Awaited<ReturnType<QueryInterface['getForeignKeyReferencesForTable']>>[number];
|
|
9
|
+
export declare type Model = {
|
|
10
|
+
name: string;
|
|
11
|
+
associations: unknown;
|
|
12
|
+
getAttributes: () => unknown;
|
|
13
|
+
};
|
|
14
|
+
export interface Builder {
|
|
15
|
+
defineModel(tableName: string): Promise<void>;
|
|
16
|
+
defineRelation(tableName: string): Promise<void>;
|
|
17
|
+
getRelatedTables(tableName: string): Promise<string[]>;
|
|
18
|
+
buildDataSource(): DataSource;
|
|
19
|
+
getTableNames(): Promise<string[]>;
|
|
20
|
+
logger?: Logger;
|
|
21
|
+
models: {
|
|
22
|
+
[modelName: string]: Model;
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvdXRpbHMvdHlwZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IiJ9
|
package/package.json
CHANGED
package/dist/datasource.d.ts
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { Logger } from '@forestadmin/datasource-toolkit';
|
|
2
|
-
import { SequelizeDataSource } from '@forestadmin/datasource-sequelize';
|
|
3
|
-
export default class SqlDataSource extends SequelizeDataSource {
|
|
4
|
-
private readonly queryInterface;
|
|
5
|
-
private readonly defaultValueParser;
|
|
6
|
-
private readonly sqlTypeConverter;
|
|
7
|
-
protected logger: Logger;
|
|
8
|
-
constructor(connectionUri: string, logger?: Logger);
|
|
9
|
-
/**
|
|
10
|
-
* Fixes Sequelize behavior incorrectly implemented.
|
|
11
|
-
* Types indicate that showAllTables() should return a list of string, but it
|
|
12
|
-
* returns a list of object for both mariadb & mssql
|
|
13
|
-
* @see https://github.com/sequelize/sequelize/blob/main/src/dialects/mariadb/query.js#L295
|
|
14
|
-
*/
|
|
15
|
-
getRealTableNames(): Promise<string[]>;
|
|
16
|
-
build(): Promise<void>;
|
|
17
|
-
private defineModels;
|
|
18
|
-
private defineRelations;
|
|
19
|
-
private hasTimestamps;
|
|
20
|
-
private removeTimeStampColumns;
|
|
21
|
-
private isParanoid;
|
|
22
|
-
private removeParanoidColumn;
|
|
23
|
-
private isJunctionTable;
|
|
24
|
-
private getUniqueFields;
|
|
25
|
-
}
|
|
26
|
-
//# sourceMappingURL=datasource.d.ts.map
|
package/dist/datasource.js
DELETED
|
@@ -1,154 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
const sequelize_1 = require("sequelize");
|
|
7
|
-
const datasource_sequelize_1 = require("@forestadmin/datasource-sequelize");
|
|
8
|
-
const default_value_parser_1 = __importDefault(require("./utils/default-value-parser"));
|
|
9
|
-
const sql_type_converter_1 = __importDefault(require("./utils/sql-type-converter"));
|
|
10
|
-
class SqlDataSource extends datasource_sequelize_1.SequelizeDataSource {
|
|
11
|
-
constructor(connectionUri, logger) {
|
|
12
|
-
const logging = (sql) => logger?.('Debug', sql.substring(sql.indexOf(':') + 2));
|
|
13
|
-
super(new sequelize_1.Sequelize(connectionUri, { logging }));
|
|
14
|
-
this.logger = logger;
|
|
15
|
-
this.queryInterface = this.sequelize.getQueryInterface();
|
|
16
|
-
this.defaultValueParser = new default_value_parser_1.default(this.sequelize.getDialect());
|
|
17
|
-
this.sqlTypeConverter = new sql_type_converter_1.default(this.sequelize);
|
|
18
|
-
}
|
|
19
|
-
/**
|
|
20
|
-
* Fixes Sequelize behavior incorrectly implemented.
|
|
21
|
-
* Types indicate that showAllTables() should return a list of string, but it
|
|
22
|
-
* returns a list of object for both mariadb & mssql
|
|
23
|
-
* @see https://github.com/sequelize/sequelize/blob/main/src/dialects/mariadb/query.js#L295
|
|
24
|
-
*/
|
|
25
|
-
async getRealTableNames() {
|
|
26
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
27
|
-
const tableNames = (await this.queryInterface.showAllTables());
|
|
28
|
-
return tableNames.map(tableName => tableName?.tableName || tableName);
|
|
29
|
-
}
|
|
30
|
-
async build() {
|
|
31
|
-
const tableNames = await this.getRealTableNames();
|
|
32
|
-
await this.defineModels(tableNames);
|
|
33
|
-
await this.defineRelations(tableNames);
|
|
34
|
-
this.createCollections(this.sequelize.models, this.logger);
|
|
35
|
-
}
|
|
36
|
-
async defineModels(tableNames) {
|
|
37
|
-
return Promise.all(tableNames.map(async (tableName) => {
|
|
38
|
-
const colmumnDescriptions = await this.queryInterface.describeTable(tableName);
|
|
39
|
-
const fieldDescriptions = await Promise.all(Object.entries(colmumnDescriptions).map(async ([columnName, colmumnDescription]) => {
|
|
40
|
-
try {
|
|
41
|
-
const type = await this.sqlTypeConverter.convert(tableName, columnName, colmumnDescription);
|
|
42
|
-
let defaultValue = this.defaultValueParser.parse(colmumnDescription.defaultValue, type);
|
|
43
|
-
if (colmumnDescription.primaryKey && defaultValue) {
|
|
44
|
-
defaultValue = null;
|
|
45
|
-
colmumnDescription.autoIncrement = true;
|
|
46
|
-
}
|
|
47
|
-
return [columnName, { ...colmumnDescription, type, defaultValue }];
|
|
48
|
-
}
|
|
49
|
-
catch (e) {
|
|
50
|
-
this.logger?.('Warn', `Skipping column ${tableName}.${columnName} (${e.message})`);
|
|
51
|
-
}
|
|
52
|
-
}));
|
|
53
|
-
let modelDefinition = Object.fromEntries(fieldDescriptions.filter(Boolean));
|
|
54
|
-
const columnNames = Object.keys(modelDefinition);
|
|
55
|
-
const hasTimestamps = this.hasTimestamps(columnNames);
|
|
56
|
-
const isParanoid = this.isParanoid(columnNames);
|
|
57
|
-
if (hasTimestamps) {
|
|
58
|
-
modelDefinition = this.removeTimeStampColumns(modelDefinition);
|
|
59
|
-
}
|
|
60
|
-
if (isParanoid) {
|
|
61
|
-
modelDefinition = this.removeParanoidColumn(modelDefinition);
|
|
62
|
-
}
|
|
63
|
-
this.sequelize.define(tableName, modelDefinition, {
|
|
64
|
-
tableName,
|
|
65
|
-
timestamps: hasTimestamps,
|
|
66
|
-
paranoid: isParanoid,
|
|
67
|
-
});
|
|
68
|
-
}));
|
|
69
|
-
}
|
|
70
|
-
async defineRelations(tableNames) {
|
|
71
|
-
return Promise.all(tableNames.map(async (tableName) => {
|
|
72
|
-
const foreignReferences = await this.queryInterface.getForeignKeyReferencesForTable(tableName);
|
|
73
|
-
const currentModel = this.sequelize.model(tableName);
|
|
74
|
-
if (this.isJunctionTable(currentModel.getAttributes())) {
|
|
75
|
-
const { referencedTableName: tableA, columnName: columnA, referencedColumnName: referencedColumnA, } = foreignReferences[0];
|
|
76
|
-
const { referencedTableName: tableB, columnName: columnB, referencedColumnName: referencedColumnB, } = foreignReferences[1];
|
|
77
|
-
const modelA = this.sequelize.model(tableA);
|
|
78
|
-
const modelB = this.sequelize.model(tableB);
|
|
79
|
-
modelA.belongsToMany(modelB, {
|
|
80
|
-
through: currentModel.name,
|
|
81
|
-
foreignKey: columnA,
|
|
82
|
-
otherKey: columnB,
|
|
83
|
-
});
|
|
84
|
-
modelB.belongsToMany(modelA, {
|
|
85
|
-
through: currentModel.name,
|
|
86
|
-
foreignKey: columnB,
|
|
87
|
-
otherKey: columnA,
|
|
88
|
-
});
|
|
89
|
-
currentModel.belongsTo(modelA, { foreignKey: columnA, targetKey: referencedColumnA });
|
|
90
|
-
currentModel.belongsTo(modelB, { foreignKey: columnB, targetKey: referencedColumnB });
|
|
91
|
-
}
|
|
92
|
-
else {
|
|
93
|
-
const uniqueFields = await this.getUniqueFields(tableName);
|
|
94
|
-
foreignReferences.forEach(foreignReference => {
|
|
95
|
-
const { columnName, referencedTableName, referencedColumnName } = foreignReference;
|
|
96
|
-
const referencedModel = this.sequelize.model(referencedTableName);
|
|
97
|
-
currentModel.belongsTo(referencedModel, {
|
|
98
|
-
foreignKey: columnName,
|
|
99
|
-
targetKey: referencedColumnName,
|
|
100
|
-
});
|
|
101
|
-
if (uniqueFields.includes(columnName)) {
|
|
102
|
-
referencedModel.hasOne(currentModel, {
|
|
103
|
-
foreignKey: columnName,
|
|
104
|
-
sourceKey: referencedColumnName,
|
|
105
|
-
});
|
|
106
|
-
}
|
|
107
|
-
else {
|
|
108
|
-
referencedModel.hasMany(currentModel, {
|
|
109
|
-
foreignKey: columnName,
|
|
110
|
-
sourceKey: referencedColumnName,
|
|
111
|
-
});
|
|
112
|
-
}
|
|
113
|
-
});
|
|
114
|
-
}
|
|
115
|
-
}));
|
|
116
|
-
}
|
|
117
|
-
hasTimestamps(columnNames) {
|
|
118
|
-
const hasCreatedAt = columnNames.includes('createdAt');
|
|
119
|
-
const hasUpdatedAt = columnNames.includes('updatedAt');
|
|
120
|
-
return hasCreatedAt && hasUpdatedAt;
|
|
121
|
-
}
|
|
122
|
-
removeTimeStampColumns(modelDefinition) {
|
|
123
|
-
const copy = { ...modelDefinition };
|
|
124
|
-
delete copy.createdAt;
|
|
125
|
-
delete copy.updatedAt;
|
|
126
|
-
return copy;
|
|
127
|
-
}
|
|
128
|
-
isParanoid(columnNames) {
|
|
129
|
-
return columnNames.includes('deletedAt');
|
|
130
|
-
}
|
|
131
|
-
removeParanoidColumn(modelDefinition) {
|
|
132
|
-
const copy = { ...modelDefinition };
|
|
133
|
-
delete copy.deletedAt;
|
|
134
|
-
return copy;
|
|
135
|
-
}
|
|
136
|
-
isJunctionTable(modelAttributes) {
|
|
137
|
-
// remove autogenerated field to keep the belongsToMany behavior
|
|
138
|
-
const modelAttributesDefinition = Object.values(modelAttributes).filter(({ _autoGenerated }) => !_autoGenerated);
|
|
139
|
-
if (modelAttributesDefinition.length !== 2)
|
|
140
|
-
return false;
|
|
141
|
-
if (modelAttributesDefinition.some(({ primaryKey }) => !primaryKey))
|
|
142
|
-
return false;
|
|
143
|
-
return true;
|
|
144
|
-
}
|
|
145
|
-
async getUniqueFields(tableName) {
|
|
146
|
-
const tableIndex = await this.queryInterface.showIndex(tableName);
|
|
147
|
-
return tableIndex
|
|
148
|
-
.filter(({ primary, unique, fields }) => !primary && unique && fields.length === 1)
|
|
149
|
-
.map(({ fields }) => fields.map(({ attribute }) => attribute))
|
|
150
|
-
.flat();
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
exports.default = SqlDataSource;
|
|
154
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGF0YXNvdXJjZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9kYXRhc291cmNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBQUEseUNBTW1CO0FBR25CLDRFQUF3RTtBQUV4RSx3RkFBOEQ7QUFDOUQsb0ZBQTBEO0FBRTFELE1BQXFCLGFBQWMsU0FBUSwwQ0FBbUI7SUFNNUQsWUFBWSxhQUFxQixFQUFFLE1BQWU7UUFDaEQsTUFBTSxPQUFPLEdBQUcsQ0FBQyxHQUFXLEVBQUUsRUFBRSxDQUFDLE1BQU0sRUFBRSxDQUFDLE9BQU8sRUFBRSxHQUFHLENBQUMsU0FBUyxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUN4RixLQUFLLENBQUMsSUFBSSxxQkFBUyxDQUFDLGFBQWEsRUFBRSxFQUFFLE9BQU8sRUFBRSxDQUFDLENBQUMsQ0FBQztRQUVqRCxJQUFJLENBQUMsTUFBTSxHQUFHLE1BQU0sQ0FBQztRQUNyQixJQUFJLENBQUMsY0FBYyxHQUFHLElBQUksQ0FBQyxTQUFTLENBQUMsaUJBQWlCLEVBQUUsQ0FBQztRQUN6RCxJQUFJLENBQUMsa0JBQWtCLEdBQUcsSUFBSSw4QkFBa0IsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLFVBQVUsRUFBYSxDQUFDLENBQUM7UUFDekYsSUFBSSxDQUFDLGdCQUFnQixHQUFHLElBQUksNEJBQWdCLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDO0lBQy9ELENBQUM7SUFFRDs7Ozs7T0FLRztJQUNILEtBQUssQ0FBQyxpQkFBaUI7UUFDckIsOERBQThEO1FBQzlELE1BQU0sVUFBVSxHQUFHLENBQUMsTUFBTSxJQUFJLENBQUMsY0FBYyxDQUFDLGFBQWEsRUFBRSxDQUFlLENBQUM7UUFFN0UsT0FBTyxVQUFVLENBQUMsR0FBRyxDQUFDLFNBQVMsQ0FBQyxFQUFFLENBQUMsU0FBUyxFQUFFLFNBQVMsSUFBSSxTQUFT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
|