UNPKG

@jsindos/sequelize-typescript-generator

Version:

Automatically generates typescript models compatible with sequelize-typescript library (https://www.npmjs.com/package/sequelize-typescript) directly from your source database.

255 lines (254 loc) 10.1 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.DialectMSSQL = void 0; const sequelize_1 = require("sequelize"); const sequelize_typescript_1 = require("sequelize-typescript"); const Dialect_1 = require("./Dialect"); const utils_1 = require("./utils"); const jsDataTypesMap = { int: 'number', bigint: 'string', tinyint: 'number', smallint: 'number', numeric: 'number', decimal: 'number', float: 'number', real: 'number', money: 'number', smallmoney: 'number', char: 'string', nchar: 'string', varchar: 'string', nvarchar: 'string', text: 'string', ntext: 'string', date: 'string', datetime: 'Date', datetime2: 'Date', timestamp: 'Date', datetimeoffset: 'Date', time: 'Date', smalldatetime: 'string', bit: 'boolean', binary: 'Uint8Array', varbinary: 'Uint8Array', uniqueidentifier: 'string', xml: 'string', geography: 'object', }; const sequelizeDataTypesMap = { int: sequelize_typescript_1.DataType.INTEGER, bigint: sequelize_typescript_1.DataType.BIGINT, tinyint: sequelize_typescript_1.DataType.INTEGER, smallint: sequelize_typescript_1.DataType.INTEGER, numeric: sequelize_typescript_1.DataType.DECIMAL, decimal: sequelize_typescript_1.DataType.DECIMAL, float: sequelize_typescript_1.DataType.FLOAT, real: sequelize_typescript_1.DataType.REAL, money: sequelize_typescript_1.DataType.STRING, smallmoney: sequelize_typescript_1.DataType.STRING, char: sequelize_typescript_1.DataType.STRING, nchar: sequelize_typescript_1.DataType.STRING, varchar: sequelize_typescript_1.DataType.STRING, nvarchar: sequelize_typescript_1.DataType.STRING, text: sequelize_typescript_1.DataType.STRING, ntext: sequelize_typescript_1.DataType.STRING, date: sequelize_typescript_1.DataType.DATEONLY, datetime: sequelize_typescript_1.DataType.DATE, datetime2: sequelize_typescript_1.DataType.DATE, timestamp: sequelize_typescript_1.DataType.DATE, datetimeoffset: sequelize_typescript_1.DataType.STRING, time: sequelize_typescript_1.DataType.TIME, smalldatetime: sequelize_typescript_1.DataType.DATE, bit: sequelize_typescript_1.DataType.STRING, binary: sequelize_typescript_1.DataType.STRING, varbinary: sequelize_typescript_1.DataType.STRING, uniqueidentifier: sequelize_typescript_1.DataType.STRING, xml: sequelize_typescript_1.DataType.STRING, geography: sequelize_typescript_1.DataType.GEOGRAPHY, }; /** * Dialect for Postgres * @class DialectPostgres */ class DialectMSSQL extends Dialect_1.Dialect { constructor() { super('mssql'); } /** * Map database data type to sequelize data type * @param {string} dbType * @returns {string} */ mapDbTypeToSequelize(dbType) { return sequelizeDataTypesMap[dbType]; } /** * Map database data type to javascript data type * @param {string} dbType * @returns {string */ mapDbTypeToJs(dbType) { return jsDataTypesMap[dbType]; } /** * Map database default values to Sequelize type (e.g. uuid() => DataType.UUIDV4). * @param {string} v * @returns {string} */ mapDefaultValueToSequelize(v) { return v; } /** * Fetch table names for the provided database/schema * @param {Sequelize} connection * @param {IConfig} config * @returns {Promise<ITable[]>} */ async fetchTables(connection, config) { const query = ` SELECT t.name AS [table_name], td.value AS [table_comment] FROM sysobjects t INNER JOIN sysusers u ON u.uid = t.uid LEFT OUTER JOIN sys.extended_properties td ON td.major_id = t.id AND td.minor_id = 0 AND td.name = 'MS_Description' WHERE t.type = 'u'; `; const tables = (await connection.query(query, { type: sequelize_1.QueryTypes.SELECT, raw: true, })).map(({ table_name, table_comment }) => { const t = { name: table_name, comment: table_comment !== null && table_comment !== void 0 ? table_comment : undefined, }; return t; }); return tables; } /** * Fetch columns metadata for the provided schema and table * @param {Sequelize} connection * @param {IConfig} config * @param {string} table * @returns {Promise<IColumnMetadata[]>} */ async fetchColumnsMetadata(connection, config, table) { var _a, _b, _c; const columnsMetadata = []; const query = ` SELECT c.*, CASE WHEN COLUMNPROPERTY(object_id(c.TABLE_SCHEMA +'.' + c.TABLE_NAME), c.COLUMN_NAME, 'IsIdentity') = 1 THEN 'YES' ELSE 'NO' END AS IS_IDENTITY, tc.CONSTRAINT_NAME, tc.CONSTRAINT_TYPE, ep.value AS [COLUMN_COMMENT] FROM information_schema.columns c LEFT OUTER JOIN information_schema.key_column_usage ku ON c.TABLE_CATALOG = ku.TABLE_CATALOG AND c.TABLE_NAME = ku.TABLE_NAME AND c.COLUMN_NAME = ku.COLUMN_NAME LEFT OUTER JOIN information_schema.table_constraints tc ON c.TABLE_CATALOG = tc.TABLE_CATALOG AND c.TABLE_NAME = tc.TABLE_NAME AND ku.CONSTRAINT_CATALOG = tc.CONSTRAINT_CATALOG AND ku.CONSTRAINT_NAME = tc.CONSTRAINT_NAME INNER JOIN sysobjects t ON c.TABLE_NAME = t.name AND t.type = 'u' INNER JOIN syscolumns sc ON sc.id = t.id AND sc.name = c.COLUMN_NAME LEFT OUTER JOIN sys.extended_properties ep ON ep.major_id = sc.id AND ep.minor_id = sc.colid AND ep.name = 'MS_Description' WHERE c.TABLE_CATALOG = N'${config.connection.database}' AND c.TABLE_NAME = N'${table}' ORDER BY c.ORDINAL_POSITION; `; const columns = await connection.query(query, { type: sequelize_1.QueryTypes.SELECT, raw: true, }); for (const column of columns) { // Unknown data type if (!this.mapDbTypeToSequelize(column.DATA_TYPE)) { (0, utils_1.warnUnknownMappingForDataType)(column.DATA_TYPE); } const columnMetadata = { name: column.COLUMN_NAME, originName: column.COLUMN_NAME, type: column.DATA_TYPE, typeExt: column.DATA_TYPE, ...this.mapDbTypeToSequelize(column.DATA_TYPE) && { dataType: 'DataType.' + this.mapDbTypeToSequelize(column.DATA_TYPE).key .split(' ')[0], // avoids 'DOUBLE PRECISION' key to include PRECISION in the mapping }, allowNull: column.IS_NULLABLE.toUpperCase() === 'YES' && ((_a = column.CONSTRAINT_TYPE) === null || _a === void 0 ? void 0 : _a.toUpperCase()) !== 'PRIMARY KEY', primaryKey: ((_b = column.CONSTRAINT_TYPE) === null || _b === void 0 ? void 0 : _b.toUpperCase()) === 'PRIMARY KEY', autoIncrement: column.IS_IDENTITY === 'YES', indices: [], comment: (_c = column.COLUMN_COMMENT) !== null && _c !== void 0 ? _c : undefined, }; // Additional data type information switch (column.DATA_TYPE) { case 'decimal': case 'numeric': case 'float': case 'double': columnMetadata.dataType += (0, utils_1.generatePrecisionSignature)(column.NUMERIC_PRECISION, column.NUMERIC_SCALE); break; case 'datetime2': columnMetadata.dataType += (0, utils_1.generatePrecisionSignature)(column.DATETIME_PRECISION); break; case 'char': case 'nchar': case 'varchar': case 'nvarchar': columnMetadata.dataType += (0, utils_1.generatePrecisionSignature)(column.CHARACTER_MAXIMUM_LENGTH); break; } columnsMetadata.push(columnMetadata); } return columnsMetadata; } async fetchColumnIndexMetadata(connection, config, table, column) { const indicesMetadata = []; const query = ` SELECT c.column_id, OBJECT_NAME(i.[object_id]) TableName, i.name IndexName, c.name ColumnName, ic.is_included_column, i.index_id, i.is_unique, i.data_space_id, i.ignore_dup_key, i.is_primary_key, i.is_unique_constraint, i.type, i.type_desc FROM sys.indexes i JOIN sys.index_columns ic ON ic.object_id = i.object_id AND i.index_id = ic.index_id JOIN sys.columns c ON ic.object_id = c.object_id AND ic.column_id = c.column_id JOIN sys.tables t ON t.object_id = c.object_id WHERE t.object_id = object_id(N'${table}') AND c.name=N'${column}' ORDER BY ic.column_id; `; const indices = await connection.query(query, { type: sequelize_1.QueryTypes.SELECT, raw: true, }); for (const index of indices) { indicesMetadata.push({ name: index.IndexName, unique: index.is_unique, }); } return indicesMetadata; } } exports.DialectMSSQL = DialectMSSQL;