@forestadmin/datasource-sql 1.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.
@@ -0,0 +1,9 @@
1
+ import { DataSourceFactory, Logger } from '@forestadmin/datasource-toolkit';
2
+ import { Sequelize } from 'sequelize';
3
+ import { Table } from './introspection/types';
4
+ export declare function introspect(connectionUri: string, logger?: Logger): Promise<Table[]>;
5
+ export declare function buildSequelizeInstance(connectionUri: string, logger: Logger, introspection?: Table[]): Promise<Sequelize>;
6
+ export declare function createSqlDataSource(connectionUri: string, options?: {
7
+ introspection: Table[];
8
+ }): DataSourceFactory;
9
+ //# sourceMappingURL=index.d.ts.map
package/dist/index.js ADDED
@@ -0,0 +1,41 @@
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
+ exports.createSqlDataSource = exports.buildSequelizeInstance = exports.introspect = void 0;
7
+ const sequelize_1 = require("sequelize");
8
+ const datasource_sequelize_1 = require("@forestadmin/datasource-sequelize");
9
+ const introspector_1 = __importDefault(require("./introspection/introspector"));
10
+ const model_1 = __importDefault(require("./orm-builder/model"));
11
+ const relations_1 = __importDefault(require("./orm-builder/relations"));
12
+ function createEmptySequelize(connectionUri, logger) {
13
+ if (!/.*:\/\//g.test(connectionUri))
14
+ throw new Error(`Connection Uri "${connectionUri}" provided to SQL data source is not valid.` +
15
+ ' Should be <dialect>://<connection>.');
16
+ const logging = (sql) => logger?.('Debug', sql.substring(sql.indexOf(':') + 2));
17
+ return new sequelize_1.Sequelize(connectionUri, { logging });
18
+ }
19
+ async function introspect(connectionUri, logger) {
20
+ const sequelize = createEmptySequelize(connectionUri, logger);
21
+ const tables = await introspector_1.default.introspect(sequelize, logger);
22
+ sequelize.close();
23
+ return tables;
24
+ }
25
+ exports.introspect = introspect;
26
+ async function buildSequelizeInstance(connectionUri, logger, introspection) {
27
+ const sequelize = createEmptySequelize(connectionUri, logger);
28
+ const tables = introspection ?? (await introspector_1.default.introspect(sequelize, logger));
29
+ model_1.default.defineModels(sequelize, logger, tables);
30
+ relations_1.default.defineRelations(sequelize, logger, tables);
31
+ return sequelize;
32
+ }
33
+ exports.buildSequelizeInstance = buildSequelizeInstance;
34
+ function createSqlDataSource(connectionUri, options) {
35
+ return async (logger) => {
36
+ const sequelize = await buildSequelizeInstance(connectionUri, logger, options?.introspection);
37
+ return new datasource_sequelize_1.SequelizeDataSource(sequelize, logger);
38
+ };
39
+ }
40
+ exports.createSqlDataSource = createSqlDataSource;
41
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBQ0EseUNBQXNDO0FBQ3RDLDRFQUF3RTtBQUd4RSxnRkFBd0Q7QUFDeEQsZ0VBQStDO0FBQy9DLHdFQUFzRDtBQUV0RCxTQUFTLG9CQUFvQixDQUFDLGFBQXFCLEVBQUUsTUFBYztJQUNqRSxJQUFJLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxhQUFhLENBQUM7UUFDakMsTUFBTSxJQUFJLEtBQUssQ0FDYixtQkFBbUIsYUFBYSw2Q0FBNkM7WUFDM0Usc0NBQXNDLENBQ3pDLENBQUM7SUFFSixNQUFNLE9BQU8sR0FBRyxDQUFDLEdBQVcsRUFBRSxFQUFFLENBQUMsTUFBTSxFQUFFLENBQUMsT0FBTyxFQUFFLEdBQUcsQ0FBQyxTQUFTLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBRXhGLE9BQU8sSUFBSSxxQkFBUyxDQUFDLGFBQWEsRUFBRSxFQUFFLE9BQU8sRUFBRSxDQUFDLENBQUM7QUFDbkQsQ0FBQztBQUVNLEtBQUssVUFBVSxVQUFVLENBQUMsYUFBcUIsRUFBRSxNQUFlO0lBQ3JFLE1BQU0sU0FBUyxHQUFHLG9CQUFvQixDQUFDLGFBQWEsRUFBRSxNQUFNLENBQUMsQ0FBQztJQUM5RCxNQUFNLE1BQU0sR0FBRyxNQUFNLHNCQUFZLENBQUMsVUFBVSxDQUFDLFNBQVMsRUFBRSxNQUFNLENBQUMsQ0FBQztJQUNoRSxTQUFTLENBQUMsS0FBSyxFQUFFLENBQUM7SUFFbEIsT0FBTyxNQUFNLENBQUM7QUFDaEIsQ0FBQztBQU5ELGdDQU1DO0FBRU0sS0FBSyxVQUFVLHNCQUFzQixDQUMxQyxhQUFxQixFQUNyQixNQUFjLEVBQ2QsYUFBdUI7SUFFdkIsTUFBTSxTQUFTLEdBQUcsb0JBQW9CLENBQUMsYUFBYSxFQUFFLE1BQU0sQ0FBQyxDQUFDO0lBQzlELE1BQU0sTUFBTSxHQUFHLGFBQWEsSUFBSSxDQUFDLE1BQU0sc0JBQVksQ0FBQyxVQUFVLENBQUMsU0FBUyxFQUFFLE1BQU0sQ0FBQyxDQUFDLENBQUM7SUFFbkYsZUFBWSxDQUFDLFlBQVksQ0FBQyxTQUFTLEVBQUUsTUFBTSxFQUFFLE1BQU0sQ0FBQyxDQUFDO0lBQ3JELG1CQUFlLENBQUMsZUFBZSxDQUFDLFNBQVMsRUFBRSxNQUFNLEVBQUUsTUFBTSxDQUFDLENBQUM7SUFFM0QsT0FBTyxTQUFTLENBQUM7QUFDbkIsQ0FBQztBQVpELHdEQVlDO0FBRUQsU0FBZ0IsbUJBQW1CLENBQ2pDLGFBQXFCLEVBQ3JCLE9BQW9DO0lBRXBDLE9BQU8sS0FBSyxFQUFFLE1BQWMsRUFBRSxFQUFFO1FBQzlCLE1BQU0sU0FBUyxHQUFHLE1BQU0sc0JBQXNCLENBQUMsYUFBYSxFQUFFLE1BQU0sRUFBRSxPQUFPLEVBQUUsYUFBYSxDQUFDLENBQUM7UUFFOUYsT0FBTyxJQUFJLDBDQUFtQixDQUFDLFNBQVMsRUFBRSxNQUFNLENBQUMsQ0FBQztJQUNwRCxDQUFDLENBQUM7QUFDSixDQUFDO0FBVEQsa0RBU0MifQ==
@@ -0,0 +1,12 @@
1
+ import { Sequelize } from 'sequelize';
2
+ export default class ArrayTypeGetter {
3
+ private readonly sequelize;
4
+ private readonly fromArray;
5
+ private readonly query;
6
+ constructor(sequelize: Sequelize);
7
+ getType(tableName: string, columnName: string): Promise<{
8
+ type: string;
9
+ special: string[];
10
+ }>;
11
+ }
12
+ //# sourceMappingURL=array-type-getter.d.ts.map
@@ -0,0 +1,67 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const sequelize_1 = require("sequelize");
4
+ class ArrayTypeGetter {
5
+ constructor(sequelize) {
6
+ this.query = `
7
+ SELECT
8
+ (
9
+ CASE
10
+ WHEN e.udt_name = 'hstore' THEN e.udt_name
11
+ ELSE e.data_type
12
+ END
13
+ ) || (
14
+ CASE
15
+ WHEN e.character_maximum_length IS NOT NULL THEN '(' || e.character_maximum_length || ')'
16
+ ELSE ''
17
+ END
18
+ ) as "type",
19
+ (
20
+ SELECT
21
+ array_agg(en.enumlabel)
22
+ FROM
23
+ pg_catalog.pg_type t
24
+ JOIN pg_catalog.pg_enum en ON t.oid = en.enumtypid
25
+ WHERE
26
+ t.typname = e.udt_name
27
+ ) AS "special"
28
+ FROM
29
+ INFORMATION_SCHEMA.columns c
30
+ LEFT JOIN INFORMATION_SCHEMA.element_types e ON (
31
+ (
32
+ c.table_catalog,
33
+ c.table_schema,
34
+ c.table_name,
35
+ 'TABLE',
36
+ c.dtd_identifier
37
+ ) = (
38
+ e.object_catalog,
39
+ e.object_schema,
40
+ e.object_name,
41
+ e.object_type,
42
+ e.collection_type_identifier
43
+ )
44
+ )
45
+ WHERE
46
+ table_name = :tableName
47
+ AND c.column_name = :columnName
48
+ ;
49
+ `;
50
+ this.sequelize = sequelize;
51
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
52
+ this.fromArray = this.sequelize.getQueryInterface().queryGenerator.fromArray;
53
+ }
54
+ async getType(tableName, columnName) {
55
+ const replacements = { tableName, columnName };
56
+ const [{ type, special }] = await this.sequelize.query(this.query, {
57
+ replacements,
58
+ type: sequelize_1.QueryTypes.SELECT,
59
+ });
60
+ return {
61
+ type: type.toUpperCase(),
62
+ special: special ? this.fromArray(special) : [],
63
+ };
64
+ }
65
+ }
66
+ exports.default = ArrayTypeGetter;
67
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXJyYXktdHlwZS1nZXR0ZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvaW50cm9zcGVjdGlvbi9oZWxwZXJzL2FycmF5LXR5cGUtZ2V0dGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBQUEseUNBQWtEO0FBRWxELE1BQXFCLGVBQWU7SUFnRGxDLFlBQVksU0FBb0I7UUE3Q2YsVUFBSyxHQUFHOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBMkN4QixDQUFDO1FBR0EsSUFBSSxDQUFDLFNBQVMsR0FBRyxTQUFTLENBQUM7UUFDM0IsOERBQThEO1FBQzlELElBQUksQ0FBQyxTQUFTLEdBQUksSUFBSSxDQUFDLFNBQVMsQ0FBQyxpQkFBaUIsRUFBRSxDQUFDLGNBQXNCLENBQUMsU0FBUyxDQUFDO0lBQ3hGLENBQUM7SUFFRCxLQUFLLENBQUMsT0FBTyxDQUNYLFNBQWlCLEVBQ2pCLFVBQWtCO1FBRWxCLE1BQU0sWUFBWSxHQUFHLEVBQUUsU0FBUyxFQUFFLFVBQVUsRUFBRSxDQUFDO1FBRS9DLE1BQU0sQ0FBQyxFQUFFLElBQUksRUFBRSxPQUFPLEVBQUUsQ0FBQyxHQUFHLE1BQU0sSUFBSSxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLEtBQUssRUFBRTtZQUNqRSxZQUFZO1lBQ1osSUFBSSxFQUFFLHNCQUFVLENBQUMsTUFBTTtTQUN4QixDQUFDLENBQUM7UUFFSCxPQUFPO1lBQ0wsSUFBSSxFQUFFLElBQUksQ0FBQyxXQUFXLEVBQUU7WUFDeEIsT0FBTyxFQUFFLE9BQU8sQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRTtTQUNoRCxDQUFDO0lBQ0osQ0FBQztDQUNGO0FBdEVELGtDQXNFQyJ9
@@ -0,0 +1,12 @@
1
+ import { Dialect } from 'sequelize';
2
+ import { ColumnType } from '../types';
3
+ export default class DefaultValueParser {
4
+ private readonly dialect;
5
+ constructor(dialect: Dialect);
6
+ parse(expression: any, columnType: ColumnType): unknown;
7
+ private parseGeneric;
8
+ private sanitizeExpression;
9
+ private literalUnlessMatch;
10
+ private parseNumber;
11
+ }
12
+ //# sourceMappingURL=default-value-parser.d.ts.map
@@ -0,0 +1,78 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const sequelize_1 = require("sequelize");
4
+ class DefaultValueParser {
5
+ constructor(dialect) {
6
+ this.dialect = dialect;
7
+ }
8
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
9
+ parse(expression, columnType) {
10
+ if (expression === null || expression === undefined)
11
+ return undefined;
12
+ if (typeof expression === 'string' && expression.startsWith('NULL'))
13
+ return null;
14
+ // FA backend not handle correctly
15
+ if (columnType.type === 'array')
16
+ return undefined;
17
+ try {
18
+ const result = this.parseGeneric(expression, columnType);
19
+ return result !== undefined ? result : (0, sequelize_1.literal)(expression);
20
+ }
21
+ catch (e) {
22
+ return (0, sequelize_1.literal)(expression);
23
+ }
24
+ }
25
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
26
+ parseGeneric(expression, columnType) {
27
+ let sanitizedExpression = expression;
28
+ // sanitize string
29
+ if (typeof expression === 'string') {
30
+ sanitizedExpression = this.sanitizeExpression(expression);
31
+ }
32
+ if (columnType.type === 'enum') {
33
+ return sanitizedExpression;
34
+ }
35
+ switch (columnType.subType) {
36
+ case 'BOOLEAN':
37
+ return [true, 'true', 'TRUE', "b'1'", '1'].includes(sanitizedExpression);
38
+ case 'NUMBER':
39
+ case 'BIGINT':
40
+ case 'FLOAT':
41
+ case 'DOUBLE':
42
+ return this.parseNumber(sanitizedExpression);
43
+ case 'DATE':
44
+ case 'DATEONLY':
45
+ return this.literalUnlessMatch(/^(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})|(\d{4}-\d{2}-\d{2})|(\d{2}:\d{2}:\d{2})$/, sanitizedExpression);
46
+ case 'STRING':
47
+ return sanitizedExpression;
48
+ case 'JSON':
49
+ case 'JSONB':
50
+ return JSON.parse(sanitizedExpression);
51
+ default:
52
+ return undefined;
53
+ }
54
+ }
55
+ sanitizeExpression(expression) {
56
+ let sanitizedExpression = expression;
57
+ if (/^'.*'$/.test(sanitizedExpression)) {
58
+ sanitizedExpression = expression.substring(1, expression.length - 1);
59
+ }
60
+ if (this.dialect === 'mssql') {
61
+ // Sequelize send default values with weird char at the beginning (`(Ndefault value`)
62
+ sanitizedExpression = sanitizedExpression.replace(/\(N/, '');
63
+ while (/^\(.*\)$/.test(sanitizedExpression)) {
64
+ sanitizedExpression = sanitizedExpression.substring(1, sanitizedExpression.length - 1);
65
+ }
66
+ }
67
+ return sanitizedExpression;
68
+ }
69
+ literalUnlessMatch(regexp, expression) {
70
+ return regexp.test(expression) ? expression : (0, sequelize_1.literal)(expression);
71
+ }
72
+ parseNumber(expression) {
73
+ const result = Number.parseFloat(expression);
74
+ return Number.isNaN(result) ? (0, sequelize_1.literal)(expression) : result;
75
+ }
76
+ }
77
+ exports.default = DefaultValueParser;
78
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGVmYXVsdC12YWx1ZS1wYXJzZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvaW50cm9zcGVjdGlvbi9oZWxwZXJzL2RlZmF1bHQtdmFsdWUtcGFyc2VyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBQUEseUNBQTZDO0FBSTdDLE1BQXFCLGtCQUFrQjtJQUdyQyxZQUFZLE9BQWdCO1FBQzFCLElBQUksQ0FBQyxPQUFPLEdBQUcsT0FBTyxDQUFDO0lBQ3pCLENBQUM7SUFFRCw4REFBOEQ7SUFDOUQsS0FBSyxDQUFDLFVBQWUsRUFBRSxVQUFzQjtRQUMzQyxJQUFJLFVBQVUsS0FBSyxJQUFJLElBQUksVUFBVSxLQUFLLFNBQVM7WUFBRSxPQUFPLFNBQVMsQ0FBQztRQUV0RSxJQUFJLE9BQU8sVUFBVSxLQUFLLFFBQVEsSUFBSSxVQUFVLENBQUMsVUFBVSxDQUFDLE1BQU0sQ0FBQztZQUFFLE9BQU8sSUFBSSxDQUFDO1FBRWpGLGtDQUFrQztRQUNsQyxJQUFJLFVBQVUsQ0FBQyxJQUFJLEtBQUssT0FBTztZQUFFLE9BQU8sU0FBUyxDQUFDO1FBRWxELElBQUk7WUFDRixNQUFNLE1BQU0sR0FBRyxJQUFJLENBQUMsWUFBWSxDQUFDLFVBQVUsRUFBRSxVQUFVLENBQUMsQ0FBQztZQUV6RCxPQUFPLE1BQU0sS0FBSyxTQUFTLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsSUFBQSxtQkFBTyxFQUFDLFVBQVUsQ0FBQyxDQUFDO1NBQzVEO1FBQUMsT0FBTyxDQUFDLEVBQUU7WUFDVixPQUFPLElBQUEsbUJBQU8sRUFBQyxVQUFVLENBQUMsQ0FBQztTQUM1QjtJQUNILENBQUM7SUFFRCw4REFBOEQ7SUFDdEQsWUFBWSxDQUFDLFVBQWUsRUFBRSxVQUFzQjtRQUMxRCxJQUFJLG1CQUFtQixHQUFHLFVBQVUsQ0FBQztRQUVyQyxrQkFBa0I7UUFDbEIsSUFBSSxPQUFPLFVBQVUsS0FBSyxRQUFRLEVBQUU7WUFD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
@@ -0,0 +1,15 @@
1
+ import { ColumnDescription, Sequelize } from 'sequelize';
2
+ import { ColumnType } from '../types';
3
+ export default class SqlTypeConverter {
4
+ private readonly enumRegex;
5
+ private readonly arrayTypeGetter;
6
+ constructor(sequelize: Sequelize);
7
+ private typeMatch;
8
+ private typeStartsWith;
9
+ private typeContains;
10
+ private convertToEnum;
11
+ private getTypeForUserDefined;
12
+ private getTypeForArray;
13
+ convert(tableName: string, columnName: string, columnInfo: ColumnDescription): Promise<ColumnType>;
14
+ }
15
+ //# sourceMappingURL=sql-type-converter.d.ts.map
@@ -0,0 +1,101 @@
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 array_type_getter_1 = __importDefault(require("./array-type-getter"));
7
+ class SqlTypeConverter {
8
+ constructor(sequelize) {
9
+ this.enumRegex = /ENUM\((.*)\)/i;
10
+ this.arrayTypeGetter = new array_type_getter_1.default(sequelize);
11
+ }
12
+ typeMatch(type, value) {
13
+ return (type.match(value) || {}).input;
14
+ }
15
+ typeStartsWith(type, value) {
16
+ return this.typeMatch(type, new RegExp(`^${value}.*`, 'i'));
17
+ }
18
+ typeContains(type, value) {
19
+ return this.typeMatch(type, new RegExp(`${value}.*`, 'i'));
20
+ }
21
+ convertToEnum(type) {
22
+ const enumOptions = this.enumRegex.exec(type)?.[1];
23
+ return { type: 'enum', values: enumOptions.replace(/'/g, '').split(',') };
24
+ }
25
+ getTypeForUserDefined(columnInfo) {
26
+ const { special } = columnInfo;
27
+ if (special && special.length > 0) {
28
+ return { type: 'enum', values: special };
29
+ }
30
+ // User-defined enum with no values will default to string
31
+ return { type: 'scalar', subType: 'STRING' };
32
+ }
33
+ async getTypeForArray(tableName, columnName) {
34
+ const { type, special } = await this.arrayTypeGetter.getType(tableName, columnName);
35
+ const columnInfo = { type, special };
36
+ const arrayType = await this.convert(tableName, columnName, columnInfo);
37
+ return { type: 'array', subType: arrayType };
38
+ }
39
+ async convert(tableName, columnName, columnInfo) {
40
+ const { type } = columnInfo;
41
+ switch (type) {
42
+ case 'JSON':
43
+ return { type: 'scalar', subType: 'JSON' };
44
+ case 'TINYINT(1)': // MYSQL bool
45
+ case 'BIT': // NOTICE: MSSQL type.
46
+ case 'BOOLEAN':
47
+ return { type: 'scalar', subType: 'BOOLEAN' };
48
+ case 'CHARACTER VARYING':
49
+ case 'TEXT':
50
+ case 'NTEXT': // MSSQL type
51
+ case this.typeContains(type, 'TEXT'):
52
+ case this.typeContains(type, 'VARCHAR'):
53
+ case this.typeContains(type, 'CHAR'):
54
+ case 'NVARCHAR': // NOTICE: MSSQL type.
55
+ return { type: 'scalar', subType: 'STRING' };
56
+ case 'USER-DEFINED':
57
+ return this.getTypeForUserDefined(columnInfo);
58
+ case this.typeMatch(type, this.enumRegex):
59
+ return this.convertToEnum(type);
60
+ case 'UNIQUEIDENTIFIER':
61
+ case 'UUID':
62
+ return { type: 'scalar', subType: 'UUID' };
63
+ case 'JSONB':
64
+ return { type: 'scalar', subType: 'JSONB' };
65
+ case 'INTEGER':
66
+ case 'SERIAL':
67
+ case 'BIGSERIAL':
68
+ case this.typeStartsWith(type, 'INT'):
69
+ case this.typeStartsWith(type, 'SMALLINT'):
70
+ case this.typeStartsWith(type, 'TINYINT'):
71
+ case this.typeStartsWith(type, 'MEDIUMINT'):
72
+ return { type: 'scalar', subType: 'NUMBER' };
73
+ case this.typeStartsWith(type, 'BIGINT'):
74
+ return { type: 'scalar', subType: 'BIGINT' };
75
+ case this.typeContains(type, 'FLOAT'):
76
+ return { type: 'scalar', subType: 'FLOAT' };
77
+ case 'NUMERIC':
78
+ case 'REAL':
79
+ case 'DOUBLE':
80
+ case 'DOUBLE PRECISION':
81
+ case this.typeContains(type, 'DECIMAL'):
82
+ return { type: 'scalar', subType: 'DOUBLE' };
83
+ case 'DATE':
84
+ return { type: 'scalar', subType: 'DATEONLY' };
85
+ case this.typeStartsWith(type, 'DATETIME'):
86
+ case this.typeStartsWith(type, 'TIMESTAMP'):
87
+ return { type: 'scalar', subType: 'DATE' };
88
+ case 'TIME':
89
+ case 'TIME WITHOUT TIME ZONE':
90
+ return { type: 'scalar', subType: 'TIME' };
91
+ case 'ARRAY':
92
+ return this.getTypeForArray(tableName, columnName);
93
+ case 'INET':
94
+ return { type: 'scalar', subType: 'INET' };
95
+ default:
96
+ throw new Error(`Unsupported type: ${type}`);
97
+ }
98
+ }
99
+ }
100
+ exports.default = SqlTypeConverter;
101
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3FsLXR5cGUtY29udmVydGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2ludHJvc3BlY3Rpb24vaGVscGVycy9zcWwtdHlwZS1jb252ZXJ0ZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFFQSw0RUFBa0Q7QUFFbEQsTUFBcUIsZ0JBQWdCO0lBSW5DLFlBQVksU0FBb0I7UUFIZixjQUFTLEdBQUcsZUFBZSxDQUFDO1FBSTNDLElBQUksQ0FBQyxlQUFlLEdBQUcsSUFBSSwyQkFBZSxDQUFDLFNBQVMsQ0FBQyxDQUFDO0lBQ3hELENBQUM7SUFFTyxTQUFTLENBQUMsSUFBWSxFQUFFLEtBQXNCO1FBQ3BELE9BQU8sQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDLEtBQUssQ0FBQztJQUN6QyxDQUFDO0lBRU8sY0FBYyxDQUFDLElBQVksRUFBRSxLQUFhO1FBQ2hELE9BQU8sSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLEVBQUUsSUFBSSxNQUFNLENBQUMsSUFBSSxLQUFLLElBQUksRUFBRSxHQUFHLENBQUMsQ0FBQyxDQUFDO0lBQzlELENBQUM7SUFFTyxZQUFZLENBQUMsSUFBWSxFQUFFLEtBQWE7UUFDOUMsT0FBTyxJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksRUFBRSxJQUFJLE1BQU0sQ0FBQyxHQUFHLEtBQUssSUFBSSxFQUFFLEdBQUcsQ0FBQyxDQUFDLENBQUM7SUFDN0QsQ0FBQztJQUVPLGFBQWEsQ0FBQyxJQUFZO1FBQ2hDLE1BQU0sV0FBVyxHQUFHLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFFbkQsT0FBTyxFQUFFLElBQUksRUFBRSxNQUFNLEVBQUUsTUFBTSxFQUFFLFdBQVcsQ0FBQyxPQUFPLENBQUMsSUFBSSxFQUFFLEVBQUUsQ0FBQyxDQUFDLEtBQUssQ0FBQyxH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
@@ -0,0 +1,12 @@
1
+ import { Sequelize } from 'sequelize';
2
+ import { Logger } from '@forestadmin/datasource-toolkit';
3
+ import { Table } from './types';
4
+ export default class Introspector {
5
+ static introspect(sequelize: Sequelize, logger?: Logger): Promise<Table[]>;
6
+ /** Get names of all tables in the public schema of the db */
7
+ private static getTableNames;
8
+ /** Instrospect a single table */
9
+ private static getTable;
10
+ private static getColumn;
11
+ }
12
+ //# sourceMappingURL=introspector.d.ts.map
@@ -0,0 +1,74 @@
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 default_value_parser_1 = __importDefault(require("./helpers/default-value-parser"));
7
+ const sql_type_converter_1 = __importDefault(require("./helpers/sql-type-converter"));
8
+ class Introspector {
9
+ static async introspect(sequelize, logger) {
10
+ const tableNames = await this.getTableNames(sequelize);
11
+ return Promise.all(tableNames.map(name => this.getTable(sequelize, logger, name)));
12
+ }
13
+ /** Get names of all tables in the public schema of the db */
14
+ static async getTableNames(sequelize) {
15
+ const names = await sequelize
16
+ .getQueryInterface()
17
+ .showAllTables();
18
+ // Fixes Sequelize behavior incorrectly implemented.
19
+ // Types indicate that showAllTables() should return a list of string, but it
20
+ // returns a list of object for both mariadb & mssql
21
+ // @see https://github.com/sequelize/sequelize/blob/main/src/dialects/mariadb/query.js#L295
22
+ return names.map(name => (typeof name === 'string' ? name : name?.tableName));
23
+ }
24
+ /** Instrospect a single table */
25
+ static async getTable(sequelize, logger, tableName) {
26
+ // Load columns descriptions, indexes and references of the current table.
27
+ const [columnDescriptions, tableIndexes, tableReferences] = await Promise.all([
28
+ sequelize.getQueryInterface().describeTable(tableName),
29
+ sequelize.getQueryInterface().showIndex(tableName),
30
+ sequelize.getQueryInterface().getForeignKeyReferencesForTable(tableName),
31
+ ]);
32
+ // Create columns
33
+ const columns = Object.entries(columnDescriptions).map(([name, description]) => {
34
+ const indexes = tableIndexes.filter(i => i.fields.find(f => f.attribute === name));
35
+ const references = tableReferences.filter(r => r.columnName === name);
36
+ const options = { name, description, indexes, references };
37
+ return this.getColumn(sequelize, logger, tableName, options);
38
+ });
39
+ return {
40
+ name: tableName,
41
+ columns: (await Promise.all(columns)).filter(Boolean),
42
+ };
43
+ }
44
+ static async getColumn(sequelize, logger, tableName, options) {
45
+ const { name, description, indexes, references } = options;
46
+ const dialect = sequelize.getDialect();
47
+ const typeConverter = new sql_type_converter_1.default(sequelize);
48
+ try {
49
+ const type = await typeConverter.convert(tableName, name, description);
50
+ const defaultValue = new default_value_parser_1.default(dialect).parse(description.defaultValue, type);
51
+ const unique = !!indexes.find(i => i.fields.length === 1 && i.fields[0].attribute === name && i.unique);
52
+ // Workaround autoincrement flag not being properly set when using postgres
53
+ const autoIncrement = Boolean(description.autoIncrement || description.defaultValue?.match?.(/^nextval\(.+\)$/));
54
+ return {
55
+ type,
56
+ autoIncrement,
57
+ defaultValue: autoIncrement ? null : defaultValue,
58
+ name,
59
+ allowNull: description.allowNull,
60
+ unique,
61
+ primaryKey: description.primaryKey,
62
+ constraints: references.map(r => ({
63
+ table: r.referencedTableName,
64
+ column: r.referencedColumnName,
65
+ })),
66
+ };
67
+ }
68
+ catch (e) {
69
+ logger?.('Warn', `Skipping column ${tableName}.${name} (${e.message})`);
70
+ }
71
+ }
72
+ }
73
+ exports.default = Introspector;
74
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW50cm9zcGVjdG9yLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2ludHJvc3BlY3Rpb24vaW50cm9zcGVjdG9yLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBSUEsMEZBQWdFO0FBQ2hFLHNGQUE0RDtBQUU1RCxNQUFxQixZQUFZO0lBQy9CLE1BQU0sQ0FBQyxLQUFLLENBQUMsVUFBVSxDQUFDLFNBQW9CLEVBQUUsTUFBZTtRQUMzRCxNQUFNLFVBQVUsR0FBRyxNQUFNLElBQUksQ0FBQyxhQUFhLENBQUMsU0FBUyxDQUFDLENBQUM7UUFFdkQsT0FBTyxPQUFPLENBQUMsR0FBRyxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLFNBQVMsRUFBRSxNQUFNLEVBQUUsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3JGLENBQUM7SUFFRCw2REFBNkQ7SUFDckQsTUFBTSxDQUFDLEtBQUssQ0FBQyxhQUFhLENBQUMsU0FBb0I7UUFDckQsTUFBTSxLQUFLLEdBQXVDLE1BQU0sU0FBUzthQUM5RCxpQkFBaUIsRUFBRTthQUNuQixhQUFhLEVBQUUsQ0FBQztRQUVuQixvREFBb0Q7UUFDcEQsNkVBQTZFO1FBQzdFLG9EQUFvRDtRQUNwRCwyRkFBMkY7UUFDM0YsT0FBTyxLQUFLLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQyxPQUFPLElBQUksS0FBSyxRQUFRLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsSUFBSSxFQUFFLFNBQVMsQ0FBQyxDQUFDLENBQUM7SUFDaEYsQ0FBQztJQUVELGlDQUFpQztJQUN6QixNQUFNLENBQUMsS0FBSyxDQUFDLFFBQVEsQ0FDM0IsU0FBb0IsRUFDcEIsTUFBYyxFQUNkLFNBQWlCO1FBRWpCLDBFQUEwRTtRQUMxRSxNQUFNLENBQUMsa0JBQWtCLEVBQUUsWUFBWSxFQUFFLGVBQWUs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
@@ -0,0 +1,32 @@
1
+ import { AbstractDataType, AbstractDataTypeConstructor, QueryInterface } from 'sequelize/types';
2
+ export declare type SequelizeIndex = Awaited<ReturnType<QueryInterface['showIndex']>>[number];
3
+ export declare type SequelizeColumn = Awaited<ReturnType<QueryInterface['describeTable']>>[number];
4
+ export declare type SequelizeColumnType = AbstractDataType | AbstractDataTypeConstructor;
5
+ export declare type SequelizeReference = Awaited<ReturnType<QueryInterface['getForeignKeyReferencesForTable']>>[number];
6
+ export declare type ColumnType = {
7
+ type: 'scalar';
8
+ subType: 'BIGINT' | 'BOOLEAN' | 'DATE' | 'DATEONLY' | 'DOUBLE' | 'FLOAT' | 'INET' | 'JSON' | 'JSONB' | 'NUMBER' | 'STRING' | 'TIME' | 'UUID';
9
+ } | {
10
+ type: 'array';
11
+ subType: ColumnType;
12
+ } | {
13
+ type: 'enum';
14
+ values: string[];
15
+ };
16
+ export declare type Table = {
17
+ name: string;
18
+ columns: {
19
+ name: string;
20
+ type: ColumnType;
21
+ defaultValue: unknown;
22
+ allowNull: boolean;
23
+ unique: boolean;
24
+ autoIncrement: boolean;
25
+ primaryKey: boolean;
26
+ constraints: {
27
+ table: string;
28
+ column: string;
29
+ }[];
30
+ }[];
31
+ };
32
+ //# 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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvaW50cm9zcGVjdGlvbi90eXBlcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiIn0=
@@ -0,0 +1,9 @@
1
+ import { Relation } from '../types';
2
+ import { Table } from '../../introspection/types';
3
+ export default class RelationExtractor {
4
+ static listRelations(tableName: string, tables: Table[]): Relation[];
5
+ private static listDirectRelations;
6
+ private static listIndirectRelations;
7
+ private static isJunctionTable;
8
+ }
9
+ //# sourceMappingURL=relation-extractor.d.ts.map
@@ -0,0 +1,69 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ class RelationExtractor {
4
+ static listRelations(tableName, tables) {
5
+ const relations = [];
6
+ for (const table of tables) {
7
+ relations.push(...this.listDirectRelations(table));
8
+ relations.push(...this.listIndirectRelations(table));
9
+ }
10
+ return relations.filter(r => r.from === tableName);
11
+ }
12
+ static listDirectRelations(table) {
13
+ const relations = [];
14
+ for (const column of table.columns) {
15
+ for (const constraint of column.constraints) {
16
+ relations.push({
17
+ type: 'BelongsTo',
18
+ from: table.name,
19
+ to: constraint.table,
20
+ foreignKey: column.name,
21
+ foreignKeyTarget: constraint.column,
22
+ });
23
+ // Skip HasMany to junction tables
24
+ if (!this.isJunctionTable(table))
25
+ relations.push({
26
+ type: column.unique ? 'HasOne' : 'HasMany',
27
+ from: constraint.table,
28
+ to: table.name,
29
+ originKey: column.name,
30
+ originKeyTarget: constraint.column,
31
+ });
32
+ }
33
+ }
34
+ return relations;
35
+ }
36
+ static listIndirectRelations(table) {
37
+ const relations = [];
38
+ const columns = table.columns.filter(c => c.primaryKey && c.constraints.length === 1);
39
+ if (this.isJunctionTable(table)) {
40
+ const [column1, column2] = columns;
41
+ relations.push({
42
+ type: 'BelongsToMany',
43
+ from: column1.constraints[0].table,
44
+ to: column2.constraints[0].table,
45
+ through: table.name,
46
+ originKey: column1.name,
47
+ foreignKey: column2.name,
48
+ originKeyTarget: column1.constraints[0].column,
49
+ foreignKeyTarget: column2.constraints[0].column,
50
+ });
51
+ relations.push({
52
+ type: 'BelongsToMany',
53
+ from: column2.constraints[0].table,
54
+ to: column1.constraints[0].table,
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
+ });
61
+ }
62
+ return relations;
63
+ }
64
+ static isJunctionTable(table) {
65
+ return table.columns.filter(c => c.primaryKey && c.constraints.length === 1).length === 2;
66
+ }
67
+ }
68
+ exports.default = RelationExtractor;
69
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVsYXRpb24tZXh0cmFjdG9yLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL29ybS1idWlsZGVyL2hlbHBlcnMvcmVsYXRpb24tZXh0cmFjdG9yLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBR0EsTUFBcUIsaUJBQWlCO0lBQ3BDLE1BQU0sQ0FBQyxhQUFhLENBQUMsU0FBaUIsRUFBRSxNQUFlO1FBQ3JELE1BQU0sU0FBUyxHQUFlLEVBQUUsQ0FBQztRQUVqQyxLQUFLLE1BQU0sS0FBSyxJQUFJLE1BQU0sRUFBRTtZQUMxQixTQUFTLENBQUMsSUFBSSxDQUFDLEdBQUcsSUFBSSxDQUFDLG1CQUFtQixDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUM7WUFDbkQsU0FBUyxDQUFDLElBQUksQ0FBQyxHQUFHLElBQUksQ0FBQyxxQkFBcUIsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDO1NBQ3REO1FBRUQsT0FBTyxTQUFTLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksS0FBSyxTQUFTLENBQUMsQ0FBQztJQUNyRCxDQUFDO0lBRU8sTUFBTSxDQUFDLG1CQUFtQixDQUFDLEtBQVk7UUFDN0MsTUFBTSxTQUFTLEdBQWUsRUFBRSxDQUFDO1FBRWpDLEtBQUssTUFBTSxNQUFNLElBQUksS0FBSyxDQUFDLE9BQU8sRUFBRTtZQUNsQyxLQUFLLE1BQU0sVUFBVSxJQUFJLE1BQU0sQ0FBQyxXQUFXLEVBQUU7Z0JBQzNDLFNBQVMsQ0FBQyxJQUFJLENBQUM7b0JBQ2IsSUFBSSxFQUFFLFdBQVc7b0JBQ2pCLElBQUksRUFBRSxLQUFLLENBQUMsSUFBSTtvQkFDaEIsRUFBRSxFQUFFLFVBQVUsQ0FBQyxLQUFLO29CQUNwQixVQUFVLEVBQUUsTUFBTSxDQUFDLElBQUk7b0JBQ3ZCLGdCQUFnQixFQUFFLFVBQVUsQ0FBQyxNQUFNO2lCQUNwQyxDQUFDLENBQUM7Z0JBRUgsa0NBQWtDO2dCQUNsQyxJQUFJLENBQUMsSUFBSSxDQUFDLGVBQWUsQ0FBQyxLQUFLLENBQUM7b0JBQzlCLFNBQVMsQ0FBQyxJQUFJLENBQUM7d0JBQ2IsSUFBSSxFQUFFLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsU0FBUzt3QkFDMUMsSUFBSSxFQUFFLFVBQVUsQ0FBQyxLQUFLO3dCQUN0QixFQUFFLEVBQUUsS0FBSyxDQUFDLElBQUk7d0JBQ2QsU0FBUyxFQUFFLE1BQU0sQ0FBQyxJQUFJO3dCQUN0QixlQUFlLEVBQUUsVUFBVSxDQUFDLE1BQU07cUJBQ25DLENBQUMsQ0FBQzthQUNOO1NBQ0Y7UUFFRCxPQUFPLFNBQVMsQ0FBQztJQUNuQixDQUFDO0lBRU8sTUFBTSxDQUFDLHFCQUFxQixDQUFDLEtBQVk7UUFDL0MsTUFBTSxTQUFTLEdBQWUsRUFBRSxDQUFDO1FBQ2pDLE1BQU0sT0FBTyxHQUFHLEtBQUssQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLFVBQVUsSUFBSSxDQUFDLENBQUMsV0FBVyxDQUFDLE1BQU0sS0FBSyxDQUFDLENBQUMsQ0FBQztRQUV0RixJQUFJLElBQUksQ0FBQyxlQUFlLENBQUMsS0FBSyxDQUFDLEVBQUU7WUFDL0IsTUFBTSxDQUFDLE9BQU8sRUFBRSxPQUFPLENBQUMsR0FBRyxPQUFPLENBQUM7WUFFbkMsU0FBUyxDQUFDLElBQUksQ0FBQztnQkFDYixJQUFJLEVBQUUsZUFBZTtnQkFDckIsSUFBSSxFQUFFLE9BQU8sQ0FBQyxXQUFXLENBQUMsQ0FBQyxDQUFDLENBQUMsS0FBSztnQkFDbEMsRUFBRSxFQUFFLE9BQU8sQ0FBQyxXQUFXLENBQUMsQ0FBQyxDQUFDLENBQUMsS0FBSztnQkFDaEMsT0FBTyxFQUFFLEtBQUssQ0FBQyxJQUFJO2dCQUNuQixTQUFTLEVBQUUsT0FBTyxDQUFDLElBQUk7Z0JBQ3ZCLFVBQVUsRUFBRSxPQUFPLENBQUMsSUFBSTtnQkFDeEIsZUFBZSxFQUFFLE9BQU8sQ0FBQyxXQUFXLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBTTtnQkFDOUMsZ0JBQWdCLEVBQUUsT0FBTyxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxNQUFNO2FBQ2hELENBQUMsQ0FBQztZQUVILFNBQVMsQ0FBQyxJQUFJLENBQUM7Z0JBQ2IsSUFBSSxFQUFFLGVBQWU7Z0JBQ3JCLElBQUksRUFBRSxPQUFPLENBQUMsV0FBVyxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUs7Z0JBQ2xDLEVBQUUsRUFBRSxPQUFPLENBQUMsV0FBVyxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUs7Z0JBQ2hDLE9BQU8sRUFBRSxLQUFLLENBQUMsSUFBSTtnQkFDbkIsU0FBUyxFQUFFLE9BQU8sQ0FBQyxJQUFJO2dCQUN2QixVQUFVLEVBQUUsT0FBTyxDQUFDLElBQUk7Z0JBQ3hCLGVBQWUsRUFBRSxPQUFPLENBQUMsV0FBVyxDQUFDLENBQUMsQ0FBQyxDQUFDLE1BQU07Z0JBQzlDLGdCQUFnQixFQUFFLE9BQU8sQ0FBQyxXQUFXLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBTTthQUNoRCxDQUFDLENBQUM7U0FDSjtRQUVELE9BQU8sU0FBUyxDQUFDO0lBQ25CLENBQUM7SUFFTyxNQUFNLENBQUMsZUFBZSxDQUFDLEtBQVk7UUFDekMsT0FBTyxLQUFLLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxVQUFVLElBQUksQ0FBQyxDQUFDLFdBQVcsQ0FBQyxNQUFNLEtBQUssQ0FBQyxDQUFDLENBQUMsTUFBTSxLQUFLLENBQUMsQ0FBQztJQUM1RixDQUFDO0NBQ0Y7QUE1RUQsb0NBNEVDIn0=
@@ -0,0 +1,8 @@
1
+ import { Relation } from '../types';
2
+ import { Table } from '../../introspection/types';
3
+ export default class RelationNameGenerator {
4
+ static getUniqueRelationNames(table: Table, relations: Relation[]): string[];
5
+ private static getSimpleName;
6
+ private static getUniqueName;
7
+ }
8
+ //# sourceMappingURL=relation-name-generator.d.ts.map