UNPKG

sequelize-auto

Version:

Automatically generate bare sequelize models from your database.

202 lines 9.95 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.AutoWriter = void 0; const fs_1 = __importDefault(require("fs")); const lodash_1 = __importDefault(require("lodash")); const path_1 = __importDefault(require("path")); const util_1 = __importDefault(require("util")); const types_1 = require("./types"); const mkdirp = require('mkdirp'); /** Writes text into files from TableData.text, and writes init-models */ class AutoWriter { constructor(tableData, options) { this.tableText = tableData.text; this.foreignKeys = tableData.foreignKeys; this.relations = tableData.relations; this.options = options; this.space = (0, types_1.makeIndent)(this.options.spaces, this.options.indentation); } write() { if (this.options.noWrite) { return Promise.resolve(); } mkdirp.sync(path_1.default.resolve(this.options.directory || "./models")); const tables = lodash_1.default.keys(this.tableText); // write the individual model files const promises = tables.map(t => { return this.createFile(t); }); const isTypeScript = this.options.lang === 'ts'; const assoc = this.createAssociations(isTypeScript); // get table names without schema // TODO: add schema to model and file names when schema is non-default for the dialect const tableNames = tables.map(t => { const [schemaName, tableName] = (0, types_1.qNameSplit)(t); return tableName; }).sort(); // write the init-models file if (!this.options.noInitModels) { const initString = this.createInitString(tableNames, assoc, this.options.lang); const initFilePath = path_1.default.join(this.options.directory, "init-models" + (isTypeScript ? '.ts' : '.js')); const writeFile = util_1.default.promisify(fs_1.default.writeFile); const initPromise = writeFile(path_1.default.resolve(initFilePath), initString); promises.push(initPromise); } return Promise.all(promises); } createInitString(tableNames, assoc, lang) { switch (lang) { case 'ts': return this.createTsInitString(tableNames, assoc); case 'esm': return this.createESMInitString(tableNames, assoc); case 'es6': return this.createES5InitString(tableNames, assoc, "const"); default: return this.createES5InitString(tableNames, assoc, "var"); } } createFile(table) { // FIXME: schema is not used to write the file name and there could be collisions. For now it // is up to the developer to pick the right schema, and potentially chose different output // folders for each different schema. const [schemaName, tableName] = (0, types_1.qNameSplit)(table); const fileName = (0, types_1.recase)(this.options.caseFile, tableName, this.options.singularize); const filePath = path_1.default.join(this.options.directory, fileName + (this.options.lang === 'ts' ? '.ts' : '.js')); const writeFile = util_1.default.promisify(fs_1.default.writeFile); return writeFile(path_1.default.resolve(filePath), this.tableText[table]); } /** Create the belongsToMany/belongsTo/hasMany/hasOne association strings */ createAssociations(typeScript) { let strBelongs = ""; let strBelongsToMany = ""; const sp = this.space[1]; const rels = this.relations; rels.forEach(rel => { if (rel.isM2M) { const asprop = (0, types_1.recase)(this.options.caseProp, (0, types_1.pluralize)(rel.childProp)); strBelongsToMany += `${sp}${rel.parentModel}.belongsToMany(${rel.childModel}, { as: '${asprop}', through: ${rel.joinModel}, foreignKey: "${rel.parentId}", otherKey: "${rel.childId}" });\n`; } else { // const bAlias = (this.options.noAlias && rel.parentModel.toLowerCase() === rel.parentProp.toLowerCase()) ? '' : `as: "${rel.parentProp}", `; const asParentProp = (0, types_1.recase)(this.options.caseProp, rel.parentProp); const bAlias = this.options.noAlias ? '' : `as: "${asParentProp}", `; strBelongs += `${sp}${rel.childModel}.belongsTo(${rel.parentModel}, { ${bAlias}foreignKey: "${rel.parentId}"});\n`; const hasRel = rel.isOne ? "hasOne" : "hasMany"; // const hAlias = (this.options.noAlias && Utils.pluralize(rel.childModel.toLowerCase()) === rel.childProp.toLowerCase()) ? '' : `as: "${rel.childProp}", `; const asChildProp = (0, types_1.recase)(this.options.caseProp, rel.childProp); const hAlias = this.options.noAlias ? '' : `as: "${asChildProp}", `; strBelongs += `${sp}${rel.parentModel}.${hasRel}(${rel.childModel}, { ${hAlias}foreignKey: "${rel.parentId}"});\n`; } }); // belongsToMany must come first return strBelongsToMany + strBelongs; } // create the TypeScript init-models file to load all the models into Sequelize createTsInitString(tables, assoc) { let str = 'import type { Sequelize } from "sequelize";\n'; const sp = this.space[1]; const modelNames = []; // import statements tables.forEach(t => { const fileName = (0, types_1.recase)(this.options.caseFile, t, this.options.singularize); const modelName = (0, types_1.makeTableName)(this.options.caseModel, t, this.options.singularize, this.options.lang); modelNames.push(modelName); str += `import { ${modelName} as _${modelName} } from "./${fileName}";\n`; str += `import type { ${modelName}Attributes, ${modelName}CreationAttributes } from "./${fileName}";\n`; }); // re-export the model classes str += '\nexport {\n'; modelNames.forEach(m => { str += `${sp}_${m} as ${m},\n`; }); str += '};\n'; // re-export the model attirbutes str += '\nexport type {\n'; modelNames.forEach(m => { str += `${sp}${m}Attributes,\n`; str += `${sp}${m}CreationAttributes,\n`; }); str += '};\n\n'; // create the initialization function str += 'export function initModels(sequelize: Sequelize) {\n'; modelNames.forEach(m => { str += `${sp}const ${m} = _${m}.initModel(sequelize);\n`; }); // add the asociations str += "\n" + assoc; // return the models str += `\n${sp}return {\n`; modelNames.forEach(m => { str += `${this.space[2]}${m}: ${m},\n`; }); str += `${sp}};\n`; str += '}\n'; return str; } // create the ES5 init-models file to load all the models into Sequelize createES5InitString(tables, assoc, vardef) { let str = `${vardef} DataTypes = require("sequelize").DataTypes;\n`; const sp = this.space[1]; const modelNames = []; // import statements tables.forEach(t => { const fileName = (0, types_1.recase)(this.options.caseFile, t, this.options.singularize); const modelName = (0, types_1.makeTableName)(this.options.caseModel, t, this.options.singularize, this.options.lang); modelNames.push(modelName); str += `${vardef} _${modelName} = require("./${fileName}");\n`; }); // create the initialization function str += '\nfunction initModels(sequelize) {\n'; modelNames.forEach(m => { str += `${sp}${vardef} ${m} = _${m}(sequelize, DataTypes);\n`; }); // add the asociations str += "\n" + assoc; // return the models str += `\n${sp}return {\n`; modelNames.forEach(m => { str += `${this.space[2]}${m},\n`; }); str += `${sp}};\n`; str += '}\n'; str += 'module.exports = initModels;\n'; str += 'module.exports.initModels = initModels;\n'; str += 'module.exports.default = initModels;\n'; return str; } // create the ESM init-models file to load all the models into Sequelize createESMInitString(tables, assoc) { let str = 'import _sequelize from "sequelize";\n'; str += 'const DataTypes = _sequelize.DataTypes;\n'; const sp = this.space[1]; const modelNames = []; // import statements tables.forEach(t => { const fileName = (0, types_1.recase)(this.options.caseFile, t, this.options.singularize); const modelName = (0, types_1.makeTableName)(this.options.caseModel, t, this.options.singularize, this.options.lang); modelNames.push(modelName); str += `import _${modelName} from "./${fileName}.js";\n`; }); // create the initialization function str += '\nexport default function initModels(sequelize) {\n'; modelNames.forEach(m => { str += `${sp}const ${m} = _${m}.init(sequelize, DataTypes);\n`; }); // add the associations str += "\n" + assoc; // return the models str += `\n${sp}return {\n`; modelNames.forEach(m => { str += `${this.space[2]}${m},\n`; }); str += `${sp}};\n`; str += '}\n'; return str; } } exports.AutoWriter = AutoWriter; //# sourceMappingURL=auto-writer.js.map