"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.AutoGenerator = void 0; const lodash_1 = __importDefault(require("lodash")); const types_1 = require("./types"); /** Generates text from each table in TableData */ class AutoGenerator { constructor(tableData, dialect, options) { this.tables = tableData.tables; this.foreignKeys = tableData.foreignKeys; this.hasTriggerTables = tableData.hasTriggerTables; this.indexes = tableData.indexes; this.relations = tableData.relations; this.dialect = dialect; this.options = options; this.options.lang = this.options.lang || 'es5'; this.space = (0, types_1.makeIndent)(this.options.spaces, this.options.indentation); this.attrbuitesstr = ''; } makeHeaderTemplate() { const header = "import { Column, DataType, Table, Model,Sequelize } from 'sequelize-typescript';\n\n"; return header; } // 生成文本 generateText() { const tableNames = lodash_1.default.keys(this.tables); // 创建通用文件头部内容 const header = this.makeHeaderTemplate(); const text = {}; tableNames.forEach(table => { let str = header; const [schemaName, tableNameOrig] = (0, types_1.qNameSplit)(table); const tableName = (0, types_1.makeTableName)(this.options.caseModel, tableNameOrig, this.options.singularize, this.options.lang); // 为表的模型创建一个字符串 str += this.addTable(table).trim(); const re = new RegExp('#TABLE#', 'g'); str = str.replace(re, tableName); text[table] = str; }); return text; } addTable(table) { const [schemaName, tableNameOrig] = (0, types_1.qNameSplit)(table); const space = this.space; let timestamps = (this.options.additional && this.options.additional.timestamps === true) || false; let paranoid = (this.options.additional && this.options.additional.paranoid === true) || false; // 为表全部的字段生成字符串 let str = '@Table({\n'; str += space[2] + "tableName: '" + tableNameOrig + "',\n"; if (schemaName && this.dialect.hasSchema) { str += space[2] + "schema: '" + schemaName + "',\n"; } if (this.hasTriggerTables[table]) { str += space[2] + "hasTrigger: true,\n"; } str += space[2] + "timestamps: " + timestamps + ",\n"; if (paranoid) { str += space[2] + "paranoid: true,\n"; } // 有条件地添加额外选项 const hasadditional = lodash_1.default.isObject(this.options.additional) && lodash_1.default.keys(this.options.additional).length > 0; if (hasadditional) { lodash_1.default.each(this.options.additional, (value, key) => { if (key === 'name') { // name: true - preserve table name always str += space[2] + "name: {\n"; str += space[3] + "singular: '" + table + "',\n"; str += space[3] + "plural: '" + table + "'\n"; str += space[2] + "},\n"; } else if (key === "timestamps" || key === "paranoid") { // handled above } else { value = lodash_1.default.isBoolean(value) ? value : ("'" + value + "'"); str += space[2] + key + ": " + value + ",\n"; } }); } if (!this.options.noIndexes) { // 添加索引 str += this.addIndexes(table); } str = space[2] + str.trim(); str = str.substring(0, str.length - 1); str += "\n})\n"; const characters = [...lodash_1.default.camelCase(tableNameOrig)]; characters[0] = characters[0].toUpperCase(); const entityName = characters.join(""); str += `export class ${entityName}Entity extends Model {\n`; const fields = lodash_1.default.keys(this.tables[table]); fields.forEach((field, index) => { // 判断是否为 created_at 和 updated_at 字段 timestamps || (timestamps = this.isTimestampField(field)); // 判断是否为 deleted_at 字段 paranoid || (paranoid = this.isParanoidField(field)); // 创建一个包含字段属性(类型、defaultValue等)的字符串 str += this.addField(table, field); }); // 移除最后的 ",\n" str = str.substring(0, str.length - 2) + "\n}"; str += this.addAttributesHeader(entityName,this.attrbuitesstr); this.attrbuitesstr = ''; return str; } addField(table, field) { // 忽略 Sequelize 标准字段 const additional = this.options.additional; if (additional && (additional.timestamps !== false) && (this.isTimestampField(field) || this.isParanoidField(field))) { return ''; } // 判断是否为配置的忽略字段 if (this.isIgnoredField(field)) { return ''; } // 发现外键 const foreignKey = this.foreignKeys[table] && this.foreignKeys[table][field] ? this.foreignKeys[table][field] : null; const fieldObj = this.tables[table][field]; if (lodash_1.default.isObject(foreignKey)) { fieldObj.foreignKey = foreignKey; } const fieldName = (0, types_1.recase)(this.options.caseProp, field); let str = "@Column({\n"; const quoteWrapper = '"'; const unique = fieldObj.unique || fieldObj.foreignKey && fieldObj.foreignKey.isUnique; const isSerialKey = (fieldObj.foreignKey && fieldObj.foreignKey.isSerialKey) || this.dialect.isSerialKey && this.dialect.isSerialKey(fieldObj); let wroteAutoIncrement = false; let wroteTimestamp = false; const space = this.space; // 列的属性 let typeStr; const fieldAttrs = lodash_1.default.keys(fieldObj); fieldAttrs.forEach(attr => { // 我们不需要来自postgresql的特殊属性; "unique"被单独处理 if (attr === "special" || attr === "elementType" || attr === "unique") { return true; } if (isSerialKey && !wroteAutoIncrement) { str += space[3] + "autoIncrement: true,\n"; // 默认使用Postgres的GENERATED作为IDENTITY,而不是SERIAL if (this.dialect.name === "postgres" && fieldObj.foreignKey && fieldObj.foreignKey.isPrimaryKey === true && (fieldObj.foreignKey.generation === "ALWAYS" || fieldObj.foreignKey.generation === "BY DEFAULT")) { str += space[3] + "autoIncrementIdentity: true,\n"; } wroteAutoIncrement = true; } if (attr === "foreignKey") { // 外键属性 if (foreignKey && foreignKey.isForeignKey) { str += space[3] + "references: {\n"; str += space[4] + "model: \'" + fieldObj[attr].foreignSources.target_table + "\',\n"; str += space[4] + "key: \'" + fieldObj[attr].foreignSources.target_column + "\'\n"; str += space[3] + "}"; } else { return true; } } else if (attr === "references") { // covered by foreignKey return true; } else if (attr === "primaryKey") { // 主键属性 if (fieldObj[attr] === true && (!lodash_1.default.has(fieldObj, 'foreignKey') || !!fieldObj.foreignKey.isPrimaryKey)) { str += space[3] + "primaryKey: true"; } else { return true; } } else if (attr === "autoIncrement") { // 自动增长属性 if (fieldObj[attr] === true && !wroteAutoIncrement) { str += space[3] + "autoIncrement: true,\n"; // Resort to Postgres' GENERATED BY DEFAULT AS IDENTITY instead of SERIAL if (this.dialect.name === "postgres" && fieldObj.foreignKey && fieldObj.foreignKey.isPrimaryKey === true && (fieldObj.foreignKey.generation === "ALWAYS" || fieldObj.foreignKey.generation === "BY DEFAULT")) { str += space[3] + "autoIncrementIdentity: true,\n"; } wroteAutoIncrement = true; } return true; } else if (attr === "allowNull") { // 允许为null str += space[3] + attr + ": " + fieldObj[attr]; } else if (attr === "defaultValue") { // 有默认值 let defaultVal = fieldObj.defaultValue; if (this.dialect.name === "mssql" && defaultVal && defaultVal.toLowerCase() === '(newid())') { defaultVal = null; // disable adding "default value" attribute for UUID fields if generating for MS SQL } if (this.dialect.name === "mssql" && (["(NULL)", "NULL"].includes(defaultVal) || typeof defaultVal === "undefined")) { defaultVal = null; // Override default NULL in MS SQL to javascript null } if (defaultVal === null || defaultVal === undefined) { return true; } if (isSerialKey) { return true; // value generated in the database } let val_text = defaultVal; if (lodash_1.default.isString(defaultVal)) { const field_type = fieldObj.type.toLowerCase(); defaultVal = this.escapeSpecial(defaultVal); while (defaultVal.startsWith('(') && defaultVal.endsWith(')')) { // remove extra parens around mssql defaults defaultVal = defaultVal.replace(/^[(]/, '').replace(/[)]$/, ''); } if (field_type === 'bit(1)' || field_type === 'bit' || field_type === 'boolean') { // convert string to boolean val_text = /1|true/i.test(defaultVal) ? "true" : "false"; } else if (this.isArray(field_type)) { // remove outer {} val_text = defaultVal.replace(/^{/, '').replace(/}$/, ''); if (val_text && this.isString(fieldObj.elementType)) { // quote the array elements val_text = val_text.split(',').map(s => `"${s}"`).join(','); } val_text = `[${val_text}]`; } else if (field_type.match(/^(json)/)) { // don't quote json val_text = defaultVal; } else if (field_type === 'uuid' && (defaultVal === 'gen_random_uuid()' || defaultVal === 'uuid_generate_v4()')) { val_text = "DataType.UUIDV4"; } else if (defaultVal.match(/\w+\(\)$/)) { // replace db function with sequelize function val_text = "Sequelize.fn('" + defaultVal.replace(/\(\)$/g, "") + "')"; } else if (this.isNumber(field_type)) { if (defaultVal.match(/\(\)/g)) { // assume it's a server function if it contains parens val_text = "Sequelize.literal('" + defaultVal + "')"; } else { // don't quote numbers val_text = defaultVal; } } else if (defaultVal.match(/\(\)/g)) { // embedded function, pass as literal val_text = "Sequelize.literal('" + defaultVal + "')"; } else if (field_type.indexOf('date') === 0 || field_type.indexOf('timestamp') === 0) { if (lodash_1.default.includes(['current_timestamp', 'current_date', 'current_time', 'localtime', 'localtimestamp'], defaultVal.toLowerCase())) { val_text = "Sequelize.literal('" + defaultVal + "')"; wroteTimestamp = true; } else { val_text = quoteWrapper + defaultVal + quoteWrapper; } } else { val_text = quoteWrapper + defaultVal + quoteWrapper; } } str += space[3] + attr + ": " + val_text; } else if (attr === "comment" && (!fieldObj[attr] || this.dialect.name === "mssql")) { // 有备注 return true; } else { let val = null; if (attr === "type") { val = this.getSqType(fieldObj, attr); typeStr = this.getFieldType(fieldObj, attr); } if (val == null) { val = fieldObj[attr]; val = lodash_1.default.isString(val) ? quoteWrapper + this.escapeSpecial(val) + quoteWrapper : val; } str += space[3] + attr + ": " + val; } str += ",\n"; }); if (unique) { const uniq = lodash_1.default.isString(unique) ? quoteWrapper + unique.replace(/\"/g, '\\"') + quoteWrapper : unique; str += space[3] + "unique: " + uniq + ",\n"; } if (field !== fieldName) { str += space[3] + "field: '" + field + "',\n"; } // 删除属性选项中的最后一个“,” str = str.trim().replace(/,+$/, '') + "\n"; str = space[2] + str + space[2] + "})\n"; str += space[2] + this.quoteName(fieldName) + `: ${typeStr};\n\n`; this.attrbuitesstr += this.addAttributesMain(this.quoteName(fieldName),typeStr,space[2],wroteAutoIncrement,wroteTimestamp); return str; } /** * 添加属性 * @param {*} table * @param {*} field */ addAttributesHeader(entityName,mainStr) { let str = `\nexport interface ${entityName}Attributes {\n`; str += (mainStr + "}\n"); return str; } /** * 生成字段属性 * @param {*} entityName * @param {*} fileName * @param {*} typeStr * @param {*} indexspace */ addAttributesMain(fileName,typeStr,indexspace,iswroteAutoIncrement = false,wroteTimestamp = false) { let str = indexspace + fileName +"?:" + typeStr +"\n"; return str; } // 添加索引 addIndexes(table) { const indexes = this.indexes[table]; const space = this.space; let str = ""; if (indexes && indexes.length) { str += space[2] + "indexes: [\n"; indexes.forEach(idx => { str += space[3] + "{\n"; if (idx.name) { str += space[4] + `name: "${idx.name}",\n`; } if (idx.unique) { str += space[4] + "unique: true,\n"; } if (idx.type) { if (['UNIQUE', 'FULLTEXT', 'SPATIAL'].includes(idx.type)) { str += space[4] + `type: "${idx.type}",\n`; } else { str += space[4] + `using: "${idx.type}",\n`; } } str += space[4] + `fields: [\n`; idx.fields.forEach(ff => { str += space[5] + `{ name: "${ff.attribute}"`; if (ff.collate) { str += `, collate: "${ff.collate}"`; } if (ff.length) { str += `, length: ${ff.length}`; } if (ff.order && ff.order !== "ASC") { str += `, order: "${ff.order}"`; } str += " },\n"; }); str += space[4] + "]\n"; str += space[3] + "},\n"; }); str += space[2] + "],\n"; } return str; } getFieldType(fieldObj, attr) { let typeStr = 'number'; const attrValue = fieldObj[attr]; if (!attrValue.toLowerCase) { console.log("attrValue", attr, attrValue); return attrValue; } const type = attrValue.toLowerCase(); let typematch = null; if (type === "boolean" || type === "bit(1)" || type === "bit" || type === "tinyint(1)") { typeStr = 'boolean'; } else if (typematch = type.match(/^(bigint|smallint|mediumint|tinyint|int)/)) { typeStr = 'number'; } else if (type === 'nvarchar(max)' || type === 'varchar(max)') { typeStr = 'string'; } else if (type.match(/n?varchar|string|varying/)) { typeStr = 'string'; } else if (type.match(/^n?char/)) { typeStr = 'string'; } else if (type.match(/text$/)) { typeStr = 'string'; } else if (type === "date") { typeStr = 'string'; } else if (type.match(/^(date|timestamp|year)/)) { typeStr = 'string'; } else if (type.match(/^(time)/)) { typeStr = 'string'; } else if (type.match(/^(float|float4)/)) { typeStr = 'number'; } else if (type.match(/^(decimal|numeric)/)) { typeStr = 'number'; } else if (type.match(/^money/)) { typeStr = 'number'; } else if (type.match(/^smallmoney/)) { typeStr = 'number'; } else if (type.match(/^(float8|double)/)) { typeStr = 'number'; } else if (type.match(/^uuid|uniqueidentifier/)) { typeStr = 'string'; } else if (type.match(/^jsonb/)) { typeStr = 'string'; } else if (type.match(/^json/)) { typeStr = 'string'; } return typeStr; } // 从字段中获取sequelize类型 getSqType(fieldObj, attr) { let typeStr = ''; const attrValue = fieldObj[attr]; if (!attrValue.toLowerCase) { console.log("attrValue", attr, attrValue); return attrValue; } const type = attrValue.toLowerCase(); const length = type.match(/\(\d+\)/); const precision = type.match(/\(\d+,\d+\)/); let val = null; let typematch = null; if (type === "boolean" || type === "bit(1)" || type === "bit" || type === "tinyint(1)") { val = 'DataType.BOOLEAN'; // postgres range types } else if (type === "numrange") { val = 'DataType.RANGE(DataType.DECIMAL)'; } else if (type === "int4range") { val = 'DataType.RANGE(DataType.INTEGER)'; } else if (type === "int8range") { val = 'DataType.RANGE(DataType.BIGINT)'; } else if (type === "daterange") { val = 'DataType.RANGE(DataType.DATEONLY)'; } else if (type === "tsrange" || type === "tstzrange") { val = 'DataType.RANGE(DataType.DATE)'; } else if (typematch = type.match(/^(bigint|smallint|mediumint|tinyint|int)/)) { // integer subtypes val = 'DataType.' + (typematch[0] === 'int' ? 'INTEGER' : typematch[0].toUpperCase()); if (/unsigned/i.test(type)) { val += '.UNSIGNED'; } if (/zerofill/i.test(type)) { val += '.ZEROFILL'; } } else if (type === 'nvarchar(max)' || type === 'varchar(max)') { val = 'DataType.TEXT'; } else if (type.match(/n?varchar|string|varying/)) { val = 'DataType.STRING' + (!lodash_1.default.isNull(length) ? length : ''); } else if (type.match(/^n?char/)) { val = 'DataType.CHAR' + (!lodash_1.default.isNull(length) ? length : ''); } else if (type.match(/^real/)) { val = 'DataType.REAL'; } else if (type.match(/text$/)) { val = 'DataType.TEXT' + (!lodash_1.default.isNull(length) ? length : ''); } else if (type === "date") { val = 'DataType.DATEONLY'; } else if (type.match(/^(date|timestamp|year)/)) { val = 'DataType.DATE' + (!lodash_1.default.isNull(length) ? length : ''); } else if (type.match(/^(time)/)) { val = 'DataType.TIME'; } else if (type.match(/^(float|float4)/)) { val = 'DataType.FLOAT' + (!lodash_1.default.isNull(precision) ? precision : ''); } else if (type.match(/^(decimal|numeric)/)) { val = 'DataType.DECIMAL' + (!lodash_1.default.isNull(precision) ? precision : ''); } else if (type.match(/^money/)) { val = 'DataType.DECIMAL(19,4)'; } else if (type.match(/^smallmoney/)) { val = 'DataType.DECIMAL(10,4)'; } else if (type.match(/^(float8|double)/)) { val = 'DataType.DOUBLE' + (!lodash_1.default.isNull(precision) ? precision : ''); } else if (type.match(/^uuid|uniqueidentifier/)) { val = 'DataType.UUID'; } else if (type.match(/^jsonb/)) { val = 'DataType.JSONB'; } else if (type.match(/^json/)) { val = 'DataType.JSON'; } else if (type.match(/^geometry/)) { const gtype = fieldObj.elementType ? `(${fieldObj.elementType})` : ''; val = `DataType.GEOMETRY${gtype}`; } else if (type.match(/^geography/)) { const gtype = fieldObj.elementType ? `(${fieldObj.elementType})` : ''; val = `DataType.GEOGRAPHY${gtype}`; } else if (type.match(/^array/)) { const eltype = this.getSqType(fieldObj, "elementType"); val = `DataType.ARRAY(${eltype})`; } else if (type.match(/(binary|image|blob|bytea)/)) { val = 'DataType.BLOB'; } else if (type.match(/^hstore/)) { val = 'DataType.HSTORE'; } else if (type.match(/^inet/)) { val = 'DataType.INET'; } else if (type.match(/^cidr/)) { val = 'DataType.CIDR'; } else if (type.match(/^oid/)) { val = 'DataType.INTEGER'; } else if (type.match(/^macaddr/)) { val = 'DataType.MACADDR'; } else if (type.match(/^enum(\(.*\))?$/)) { const enumValues = this.getEnumValues(fieldObj); val = `DataType.ENUM(${enumValues})`; } return val; } getTypeScriptPrimaryKeys(table) { const fields = lodash_1.default.keys(this.tables[table]); return fields.filter((field) => { const fieldObj = this.tables[table][field]; return fieldObj['primaryKey']; }); } getTypeScriptCreationOptionalFields(table) { const fields = lodash_1.default.keys(this.tables[table]); return fields.filter((field) => { const fieldObj = this.tables[table][field]; return fieldObj.allowNull || (!!fieldObj.defaultValue || fieldObj.defaultValue === "") || fieldObj.autoIncrement || this.isTimestampField(field); }); } /** Add schema to table so it will match the relation data. Fixes mysql problem. */ addSchemaForRelations(table) { if (!table.includes('.') && !this.relations.some(rel => rel.childTable === table)) { // if no tables match the given table, then assume we need to fix the schema const first = this.relations.find(rel => !!rel.childTable); if (first) { const [schemaName, tableName] = (0, types_1.qNameSplit)(first.childTable); if (schemaName) { table = (0, types_1.qNameJoin)(schemaName, table); } } } return table; } addTypeScriptAssociationMixins(table) { const sp = this.space[1]; const needed = {}; let str = ''; table = this.addSchemaForRelations(table); this.relations.forEach(rel => { var _a, _b, _c; var _d, _e; if (!rel.isM2M) { if (rel.childTable === table) { // current table is a child that belongsTo parent const pparent = lodash_1.default.upperFirst(rel.parentProp); str += `${sp}// ${rel.childModel} belongsTo ${rel.parentModel} via ${rel.parentId}\n`; str += `${sp}${rel.parentProp}!: ${rel.parentModel};\n`; str += `${sp}get${pparent}!: Sequelize.BelongsToGetAssociationMixin<${rel.parentModel}>;\n`; str += `${sp}set${pparent}!: Sequelize.BelongsToSetAssociationMixin<${rel.parentModel}, ${rel.parentModel}Id>;\n`; str += `${sp}create${pparent}!: Sequelize.BelongsToCreateAssociationMixin<${rel.parentModel}>;\n`; (_a = needed[_d = rel.parentTable]) !== null && _a !== void 0 ? _a : (needed[_d] = new Set()); needed[rel.parentTable].add(rel.parentModel); needed[rel.parentTable].add(rel.parentModel + 'Id'); } else if (rel.parentTable === table) { (_b = needed[_e = rel.childTable]) !== null && _b !== void 0 ? _b : (needed[_e] = new Set()); const pchild = lodash_1.default.upperFirst(rel.childProp); if (rel.isOne) { // const hasModelSingular = singularize(hasModel); str += `${sp}// ${rel.parentModel} hasOne ${rel.childModel} via ${rel.parentId}\n`; str += `${sp}${rel.childProp}!: ${rel.childModel};\n`; str += `${sp}get${pchild}!: Sequelize.HasOneGetAssociationMixin<${rel.childModel}>;\n`; str += `${sp}set${pchild}!: Sequelize.HasOneSetAssociationMixin<${rel.childModel}, ${rel.childModel}Id>;\n`; str += `${sp}create${pchild}!: Sequelize.HasOneCreateAssociationMixin<${rel.childModel}>;\n`; needed[rel.childTable].add(rel.childModel); needed[rel.childTable].add(`${rel.childModel}Id`); needed[rel.childTable].add(`${rel.childModel}CreationAttributes`); } else { const hasModel = rel.childModel; const sing = lodash_1.default.upperFirst((0, types_1.singularize)(rel.childProp)); const lur = (0, types_1.pluralize)(rel.childProp); const plur = lodash_1.default.upperFirst(lur); str += `${sp}// ${rel.parentModel} hasMany ${rel.childModel} via ${rel.parentId}\n`; str += `${sp}${lur}!: ${rel.childModel}[];\n`; str += `${sp}get${plur}!: Sequelize.HasManyGetAssociationsMixin<${hasModel}>;\n`; str += `${sp}set${plur}!: Sequelize.HasManySetAssociationsMixin<${hasModel}, ${hasModel}Id>;\n`; str += `${sp}add${sing}!: Sequelize.HasManyAddAssociationMixin<${hasModel}, ${hasModel}Id>;\n`; str += `${sp}add${plur}!: Sequelize.HasManyAddAssociationsMixin<${hasModel}, ${hasModel}Id>;\n`; str += `${sp}create${sing}!: Sequelize.HasManyCreateAssociationMixin<${hasModel}>;\n`; str += `${sp}remove${sing}!: Sequelize.HasManyRemoveAssociationMixin<${hasModel}, ${hasModel}Id>;\n`; str += `${sp}remove${plur}!: Sequelize.HasManyRemoveAssociationsMixin<${hasModel}, ${hasModel}Id>;\n`; str += `${sp}has${sing}!: Sequelize.HasManyHasAssociationMixin<${hasModel}, ${hasModel}Id>;\n`; str += `${sp}has${plur}!: Sequelize.HasManyHasAssociationsMixin<${hasModel}, ${hasModel}Id>;\n`; str += `${sp}count${plur}!: Sequelize.HasManyCountAssociationsMixin;\n`; needed[rel.childTable].add(hasModel); needed[rel.childTable].add(`${hasModel}Id`); } } } else { // rel.isM2M if (rel.parentTable === table) { // many-to-many const isParent = (rel.parentTable === table); const thisModel = isParent ? rel.parentModel : rel.childModel; const otherModel = isParent ? rel.childModel : rel.parentModel; const otherModelSingular = lodash_1.default.upperFirst((0, types_1.singularize)(isParent ? rel.childProp : rel.parentProp)); const lotherModelPlural = (0, types_1.pluralize)(isParent ? rel.childProp : rel.parentProp); const otherModelPlural = lodash_1.default.upperFirst(lotherModelPlural); const otherTable = isParent ? rel.childTable : rel.parentTable; str += `${sp}// ${thisModel} belongsToMany ${otherModel} via ${rel.parentId} and ${rel.childId}\n`; str += `${sp}${lotherModelPlural}!: ${otherModel}[];\n`; str += `${sp}get${otherModelPlural}!: Sequelize.BelongsToManyGetAssociationsMixin<${otherModel}>;\n`; str += `${sp}set${otherModelPlural}!: Sequelize.BelongsToManySetAssociationsMixin<${otherModel}, ${otherModel}Id>;\n`; str += `${sp}add${otherModelSingular}!: Sequelize.BelongsToManyAddAssociationMixin<${otherModel}, ${otherModel}Id>;\n`; str += `${sp}add${otherModelPlural}!: Sequelize.BelongsToManyAddAssociationsMixin<${otherModel}, ${otherModel}Id>;\n`; str += `${sp}create${otherModelSingular}!: Sequelize.BelongsToManyCreateAssociationMixin<${otherModel}>;\n`; str += `${sp}remove${otherModelSingular}!: Sequelize.BelongsToManyRemoveAssociationMixin<${otherModel}, ${otherModel}Id>;\n`; str += `${sp}remove${otherModelPlural}!: Sequelize.BelongsToManyRemoveAssociationsMixin<${otherModel}, ${otherModel}Id>;\n`; str += `${sp}has${otherModelSingular}!: Sequelize.BelongsToManyHasAssociationMixin<${otherModel}, ${otherModel}Id>;\n`; str += `${sp}has${otherModelPlural}!: Sequelize.BelongsToManyHasAssociationsMixin<${otherModel}, ${otherModel}Id>;\n`; str += `${sp}count${otherModelPlural}!: Sequelize.BelongsToManyCountAssociationsMixin;\n`; (_c = needed[otherTable]) !== null && _c !== void 0 ? _c : (needed[otherTable] = new Set()); needed[otherTable].add(otherModel); needed[otherTable].add(`${otherModel}Id`); } } }); if (needed[table]) { delete needed[table]; // don't add import for self } return { needed, str }; } addTypeScriptFields(table, isInterface) { const sp = this.space[1]; const fields = lodash_1.default.keys(this.tables[table]); const notNull = isInterface ? '' : '!'; let str = ''; fields.forEach(field => { if (!this.options.skipFields || !this.options.skipFields.includes(field)) { const name = this.quoteName((0, types_1.recase)(this.options.caseProp, field)); const isOptional = this.getTypeScriptFieldOptional(table, field); str += `${sp}${name}${isOptional ? '?' : notNull}: ${this.getTypeScriptType(table, field)};\n`; } }); return str; } getTypeScriptFieldOptional(table, field) { const fieldObj = this.tables[table][field]; return fieldObj.allowNull; } getTypeScriptType(table, field) { const fieldObj = this.tables[table][field]; return this.getTypeScriptFieldType(fieldObj, "type"); } getTypeScriptFieldType(fieldObj, attr) { const rawFieldType = fieldObj[attr] || ''; const fieldType = String(rawFieldType).toLowerCase(); let jsType; if (this.isArray(fieldType)) { const eltype = this.getTypeScriptFieldType(fieldObj, "elementType"); jsType = eltype + '[]'; } else if (this.isNumber(fieldType)) { jsType = 'number'; } else if (this.isBoolean(fieldType)) { jsType = 'boolean'; } else if (this.isDate(fieldType)) { jsType = 'Date'; } else if (this.isString(fieldType)) { jsType = 'string'; } else if (this.isEnum(fieldType)) { const values = this.getEnumValues(fieldObj); jsType = values.join(' | '); } else if (this.isJSON(fieldType)) { jsType = 'object'; } else { console.log(`Missing TypeScript type: ${fieldType || fieldObj['type']}`); jsType = 'any'; } return jsType; } getEnumValues(fieldObj) { if (fieldObj.special) { // postgres return fieldObj.special.map((v) => `"${v}"`); } else { // mysql return fieldObj.type.substring(5, fieldObj.type.length - 1).split(','); } } isTimestampField(field) { const additional = this.options.additional; if (additional.timestamps === false) { return false; } return ((!additional.createdAt && (0, types_1.recase)('c', field) === 'createdAt') || additional.createdAt === field) || ((!additional.updatedAt && (0, types_1.recase)('c', field) === 'updatedAt') || additional.updatedAt === field); } isParanoidField(field) { const additional = this.options.additional; if (additional.timestamps === false || additional.paranoid === false) { return false; } return ((!additional.deletedAt && (0, types_1.recase)('c', field) === 'deletedAt') || additional.deletedAt === field); } isIgnoredField(field) { return (this.options.skipFields && this.options.skipFields.includes(field)); } escapeSpecial(val) { if (typeof (val) !== "string") { return val; } return val .replace(/[\\]/g, '\\\\') .replace(/[\"]/g, '\\"') .replace(/[\/]/g, '\\/') .replace(/[\b]/g, '\\b') .replace(/[\f]/g, '\\f') .replace(/[\n]/g, '\\n') .replace(/[\r]/g, '\\r') .replace(/[\t]/g, '\\t'); } /** Quote the name if it is not a valid identifier */ quoteName(name) { return (/^[$A-Z_][0-9A-Z_$]*$/i.test(name) ? name : "'" + name + "'"); } isNumber(fieldType) { return /^(smallint|mediumint|tinyint|int|bigint|float|money|smallmoney|double|decimal|numeric|real|oid)/.test(fieldType); } isBoolean(fieldType) { return /^(boolean|bit)/.test(fieldType); } isDate(fieldType) { return /^(datetime|timestamp)/.test(fieldType); } isString(fieldType) { return /^(char|nchar|string|varying|varchar|nvarchar|text|longtext|mediumtext|tinytext|ntext|uuid|uniqueidentifier|date|time|inet|cidr|macaddr)/.test(fieldType); } isArray(fieldType) { return /(^array)|(range$)/.test(fieldType); } isEnum(fieldType) { return /^(enum)/.test(fieldType); } isJSON(fieldType) { return /^(json|jsonb)/.test(fieldType); } } exports.AutoGenerator = AutoGenerator; //# sourceMappingURL=auto-generator.js.map