diff --git a/src/AbstractNamingStrategy.ts b/src/AbstractNamingStrategy.ts index b739cd2..ee3b9ee 100644 --- a/src/AbstractNamingStrategy.ts +++ b/src/AbstractNamingStrategy.ts @@ -1,11 +1,11 @@ -import { DatabaseModel } from "./models/DatabaseModel"; +import { EntityInfo } from "./models/EntityInfo"; import { RelationInfo } from "./models/RelationInfo"; export abstract class AbstractNamingStrategy { public abstract relationName( columnName: string, relation: RelationInfo, - dbModel: DatabaseModel + dbModel: EntityInfo[] ): string; public abstract entityName(entityName: string): string; diff --git a/src/Engine.ts b/src/Engine.ts index 42c78d5..379a5f2 100644 --- a/src/Engine.ts +++ b/src/Engine.ts @@ -10,213 +10,207 @@ import { MysqlDriver } from "./drivers/MysqlDriver"; import { OracleDriver } from "./drivers/OracleDriver"; import { PostgresDriver } from "./drivers/PostgresDriver"; import { SqliteDriver } from "./drivers/SqliteDriver"; -import { DatabaseModel } from "./models/DatabaseModel"; +import { EntityInfo } from "./models/EntityInfo"; import { NamingStrategy } from "./NamingStrategy"; import * as TomgUtils from "./Utils"; -export class Engine { - public static createDriver(driverName: string): AbstractDriver { - switch (driverName) { - case "mssql": - return new MssqlDriver(); - case "postgres": - return new PostgresDriver(); - case "mysql": - return new MysqlDriver(); - case "mariadb": - return new MariaDbDriver(); - case "oracle": - return new OracleDriver(); - case "sqlite": - return new SqliteDriver(); - default: - TomgUtils.LogError("Database engine not recognized.", false); - throw new Error("Database engine not recognized."); - } +export function createDriver(driverName: string): AbstractDriver { + switch (driverName) { + case "mssql": + return new MssqlDriver(); + case "postgres": + return new PostgresDriver(); + case "mysql": + return new MysqlDriver(); + case "mariadb": + return new MariaDbDriver(); + case "oracle": + return new OracleDriver(); + case "sqlite": + return new SqliteDriver(); + default: + TomgUtils.LogError("Database engine not recognized.", false); + throw new Error("Database engine not recognized."); } +} - public static async createModelFromDatabase( - driver: AbstractDriver, - connectionOptions: IConnectionOptions, - generationOptions: IGenerationOptions - ): Promise { - const dbModel = await driver.GetDataFromServer( - connectionOptions.databaseName, - connectionOptions.host, - connectionOptions.port, - connectionOptions.user, - connectionOptions.password, - connectionOptions.schemaName, - connectionOptions.ssl, - generationOptions.relationIds - ); - if (dbModel.entities.length > 0) { - this.ApplyNamingStrategy(dbModel, generationOptions.namingStrategy); - this.createModelFromMetadata( - dbModel, - connectionOptions, - generationOptions - ); - } else { - TomgUtils.LogError( - "Tables not found in selected database. Skipping creation of typeorm model.", - false - ); - } - return true; - } - - private static createModelFromMetadata( - databaseModel: DatabaseModel, - connectionOptions: IConnectionOptions, - generationOptions: IGenerationOptions - ) { - this.createHandlebarsHelpers(generationOptions); - const templatePath = path.resolve(__dirname, "../../src/entity.mst"); - const template = fs.readFileSync(templatePath, "UTF-8"); - const resultPath = generationOptions.resultsPath; - if (!fs.existsSync(resultPath)) { - fs.mkdirSync(resultPath); - } - let entitesPath = resultPath; - if (!generationOptions.noConfigs) { - this.createTsConfigFile(resultPath); - this.createTypeOrmConfig(resultPath, connectionOptions); - entitesPath = path.resolve(resultPath, "./entities"); - if (!fs.existsSync(entitesPath)) { - fs.mkdirSync(entitesPath); - } - } - const compliedTemplate = Handlebars.compile(template, { - noEscape: true - }); - databaseModel.entities.forEach(element => { - element.Imports = []; - element.Columns.forEach(column => { - column.relations.forEach(relation => { - if (element.tsEntityName !== relation.relatedTable) { - element.Imports.push(relation.relatedTable); - } +export async function createModelFromDatabase( + driver: AbstractDriver, + connectionOptions: IConnectionOptions, + generationOptions: IGenerationOptions +) { + function setRelationId(model: EntityInfo[]) { + if (generationOptions.relationIds) { + model.forEach(ent => { + ent.Columns.forEach(col => { + col.relations.map(rel => { + rel.relationIdField = rel.isOwner; + }); }); }); - element.GenerateConstructor = generationOptions.constructor; - element.IsActiveRecord = generationOptions.activeRecord; - element.Imports.filter((elem, index, self) => { - return index === self.indexOf(elem); - }); - let casedFileName = ""; - switch (generationOptions.convertCaseFile) { - case "camel": - casedFileName = changeCase.camelCase(element.tsEntityName); - break; - case "param": - casedFileName = changeCase.paramCase(element.tsEntityName); - break; - case "pascal": - casedFileName = changeCase.pascalCase(element.tsEntityName); - break; - case "none": - casedFileName = element.tsEntityName; - break; - } - const resultFilePath = path.resolve( - entitesPath, - casedFileName + ".ts" - ); - const rendered = compliedTemplate(element); - fs.writeFileSync(resultFilePath, rendered, { - encoding: "UTF-8", - flag: "w" - }); - }); - } - private static createHandlebarsHelpers( - generationOptions: IGenerationOptions - ) { - Handlebars.registerHelper("curly", open => (open ? "{" : "}")); - Handlebars.registerHelper("toEntityName", str => { - let retStr = ""; - switch (generationOptions.convertCaseEntity) { - case "camel": - retStr = changeCase.camelCase(str); - break; - case "pascal": - retStr = changeCase.pascalCase(str); - break; - case "none": - retStr = str; - break; - } - return retStr; - }); - Handlebars.registerHelper("concat", (stra, strb) => { - return stra + strb; - }); - Handlebars.registerHelper("toFileName", str => { - let retStr = ""; - switch (generationOptions.convertCaseFile) { - case "camel": - retStr = changeCase.camelCase(str); - break; - case "param": - retStr = changeCase.paramCase(str); - break; - case "pascal": - retStr = changeCase.pascalCase(str); - break; - case "none": - retStr = str; - break; - } - return retStr; - }); - Handlebars.registerHelper( - "printPropertyVisibility", - () => - generationOptions.propertyVisibility !== "none" - ? generationOptions.propertyVisibility + " " - : "" - ); - Handlebars.registerHelper("toPropertyName", str => { - let retStr = ""; - switch (generationOptions.convertCaseProperty) { - case "camel": - retStr = changeCase.camelCase(str); - break; - case "pascal": - retStr = changeCase.pascalCase(str); - break; - case "none": - retStr = str; - break; - } - return retStr; - }); - Handlebars.registerHelper("toLowerCase", str => str.toLowerCase()); - Handlebars.registerHelper("toLazy", str => { - if (generationOptions.lazy) { - return `Promise<${str}>`; - } else { - return str; - } - }); - Handlebars.registerHelper({ - and: (v1, v2) => v1 && v2, - eq: (v1, v2) => v1 === v2, - gt: (v1, v2) => v1 > v2, - gte: (v1, v2) => v1 >= v2, - lt: (v1, v2) => v1 < v2, - lte: (v1, v2) => v1 <= v2, - ne: (v1, v2) => v1 !== v2, - or: (v1, v2) => v1 || v2 - }); + } + return model; } - // TODO:Move to mustache template file - private static createTsConfigFile(resultPath) { - fs.writeFileSync( - path.resolve(resultPath, "tsconfig.json"), - `{"compilerOptions": { + let dbModel = await driver.GetDataFromServer(connectionOptions); + if (dbModel.length === 0) { + TomgUtils.LogError( + "Tables not found in selected database. Skipping creation of typeorm model.", + false + ); + return; + } + dbModel = setRelationId(dbModel); + dbModel = ApplyNamingStrategy(generationOptions.namingStrategy, dbModel); + createModelFromMetadata(connectionOptions, generationOptions, dbModel); +} +function createModelFromMetadata( + connectionOptions: IConnectionOptions, + generationOptions: IGenerationOptions, + databaseModel: EntityInfo[] +) { + createHandlebarsHelpers(generationOptions); + const templatePath = path.resolve(__dirname, "../../src/entity.mst"); + const template = fs.readFileSync(templatePath, "UTF-8"); + const resultPath = generationOptions.resultsPath; + if (!fs.existsSync(resultPath)) { + fs.mkdirSync(resultPath); + } + let entitesPath = resultPath; + if (!generationOptions.noConfigs) { + createTsConfigFile(resultPath); + createTypeOrmConfig(resultPath, connectionOptions); + entitesPath = path.resolve(resultPath, "./entities"); + if (!fs.existsSync(entitesPath)) { + fs.mkdirSync(entitesPath); + } + } + const compliedTemplate = Handlebars.compile(template, { + noEscape: true + }); + databaseModel.forEach(element => { + element.Imports = []; + element.Columns.forEach(column => { + column.relations.forEach(relation => { + if (element.tsEntityName !== relation.relatedTable) { + element.Imports.push(relation.relatedTable); + } + }); + }); + element.GenerateConstructor = generationOptions.constructor; + element.IsActiveRecord = generationOptions.activeRecord; + element.Imports.filter((elem, index, self) => { + return index === self.indexOf(elem); + }); + let casedFileName = ""; + switch (generationOptions.convertCaseFile) { + case "camel": + casedFileName = changeCase.camelCase(element.tsEntityName); + break; + case "param": + casedFileName = changeCase.paramCase(element.tsEntityName); + break; + case "pascal": + casedFileName = changeCase.pascalCase(element.tsEntityName); + break; + case "none": + casedFileName = element.tsEntityName; + break; + } + const resultFilePath = path.resolve(entitesPath, casedFileName + ".ts"); + const rendered = compliedTemplate(element); + fs.writeFileSync(resultFilePath, rendered, { + encoding: "UTF-8", + flag: "w" + }); + }); +} + +function createHandlebarsHelpers(generationOptions: IGenerationOptions) { + Handlebars.registerHelper("curly", open => (open ? "{" : "}")); + Handlebars.registerHelper("toEntityName", str => { + let retStr = ""; + switch (generationOptions.convertCaseEntity) { + case "camel": + retStr = changeCase.camelCase(str); + break; + case "pascal": + retStr = changeCase.pascalCase(str); + break; + case "none": + retStr = str; + break; + } + return retStr; + }); + Handlebars.registerHelper("concat", (stra, strb) => { + return stra + strb; + }); + Handlebars.registerHelper("toFileName", str => { + let retStr = ""; + switch (generationOptions.convertCaseFile) { + case "camel": + retStr = changeCase.camelCase(str); + break; + case "param": + retStr = changeCase.paramCase(str); + break; + case "pascal": + retStr = changeCase.pascalCase(str); + break; + case "none": + retStr = str; + break; + } + return retStr; + }); + Handlebars.registerHelper( + "printPropertyVisibility", + () => + generationOptions.propertyVisibility !== "none" + ? generationOptions.propertyVisibility + " " + : "" + ); + Handlebars.registerHelper("toPropertyName", str => { + let retStr = ""; + switch (generationOptions.convertCaseProperty) { + case "camel": + retStr = changeCase.camelCase(str); + break; + case "pascal": + retStr = changeCase.pascalCase(str); + break; + case "none": + retStr = str; + break; + } + return retStr; + }); + Handlebars.registerHelper("toLowerCase", str => str.toLowerCase()); + Handlebars.registerHelper("toLazy", str => { + if (generationOptions.lazy) { + return `Promise<${str}>`; + } else { + return str; + } + }); + Handlebars.registerHelper({ + and: (v1, v2) => v1 && v2, + eq: (v1, v2) => v1 === v2, + gt: (v1, v2) => v1 > v2, + gte: (v1, v2) => v1 >= v2, + lt: (v1, v2) => v1 < v2, + lte: (v1, v2) => v1 <= v2, + ne: (v1, v2) => v1 !== v2, + or: (v1, v2) => v1 || v2 + }); +} + +// TODO:Move to mustache template file +function createTsConfigFile(resultPath) { + fs.writeFileSync( + path.resolve(resultPath, "tsconfig.json"), + `{"compilerOptions": { "lib": ["es5", "es6"], "target": "es6", "module": "commonjs", @@ -225,17 +219,17 @@ export class Engine { "experimentalDecorators": true, "sourceMap": true }}`, - { encoding: "UTF-8", flag: "w" } - ); - } - private static createTypeOrmConfig( - resultPath: string, - connectionOptions: IConnectionOptions - ) { - if (connectionOptions.schemaName === "") { - fs.writeFileSync( - path.resolve(resultPath, "ormconfig.json"), - `[ + { encoding: "UTF-8", flag: "w" } + ); +} +function createTypeOrmConfig( + resultPath: string, + connectionOptions: IConnectionOptions +) { + if (connectionOptions.schemaName === "") { + fs.writeFileSync( + path.resolve(resultPath, "ormconfig.json"), + `[ { "name": "default", "type": "${connectionOptions.databaseType}", @@ -250,12 +244,12 @@ export class Engine { ] } ]`, - { encoding: "UTF-8", flag: "w" } - ); - } else { - fs.writeFileSync( - path.resolve(resultPath, "ormconfig.json"), - `[ + { encoding: "UTF-8", flag: "w" } + ); + } else { + fs.writeFileSync( + path.resolve(resultPath, "ormconfig.json"), + `[ { "name": "default", "type": "${connectionOptions.databaseType}", @@ -271,89 +265,29 @@ export class Engine { ] } ]`, - { encoding: "UTF-8", flag: "w" } - ); - } + { encoding: "UTF-8", flag: "w" } + ); } - private static ApplyNamingStrategy( - dbModel: DatabaseModel, - namingStrategy: NamingStrategy - ) { - this.changeRelationNames(dbModel, namingStrategy); - this.changeEntityNames(dbModel, namingStrategy); - this.changeColumnNames(dbModel, namingStrategy); - } - private static changeColumnNames( - dbModel: DatabaseModel, - namingStrategy: NamingStrategy - ) { - dbModel.entities.forEach(entity => { - entity.Columns.forEach(column => { - const newName = namingStrategy.columnName(column.tsName); - entity.Indexes.forEach(index => { - index.columns - .filter(column2 => column2.name === column.tsName) - .forEach(column2 => (column2.name = newName)); - }); - dbModel.entities.forEach(entity2 => { - entity2.Columns.forEach(column2 => { - column2.relations - .filter( - relation => - relation.relatedTable === - entity.tsEntityName && - relation.relatedColumn === column.tsName - ) - .map(v => (v.relatedColumn = newName)); - column2.relations - .filter( - relation => - relation.relatedTable === - entity.tsEntityName && - relation.ownerColumn === column.tsName - ) - .map(v => (v.ownerColumn = newName)); - }); - }); +} +function ApplyNamingStrategy( + namingStrategy: NamingStrategy, + dbModel: EntityInfo[] +) { + dbModel = changeRelationNames(dbModel); + dbModel = changeEntityNames(dbModel); + dbModel = changeColumnNames(dbModel); + return dbModel; - column.tsName = newName; - }); - }); - } - private static changeEntityNames( - dbModel: DatabaseModel, - namingStrategy: NamingStrategy - ) { - dbModel.entities.forEach(entity => { - const newName = namingStrategy.entityName(entity.tsEntityName); - dbModel.entities.forEach(entity2 => { - entity2.Columns.forEach(column => { - column.relations.forEach(relation => { - if (relation.ownerTable === entity.tsEntityName) { - relation.ownerTable = newName; - } - if (relation.relatedTable === entity.tsEntityName) { - relation.relatedTable = newName; - } - }); - }); - }); - entity.tsEntityName = newName; - }); - } - private static changeRelationNames( - dbModel: DatabaseModel, - namingStrategy: NamingStrategy - ) { - dbModel.entities.forEach(entity => { + function changeRelationNames(model: EntityInfo[]) { + model.forEach(entity => { entity.Columns.forEach(column => { column.relations.forEach(relation => { const newName = namingStrategy.relationName( column.tsName, relation, - dbModel + model ); - dbModel.entities.forEach(entity2 => { + model.forEach(entity2 => { entity2.Columns.forEach(column2 => { column2.relations.forEach(relation2 => { if ( @@ -389,6 +323,62 @@ export class Engine { }); }); }); + return dbModel; + } + + function changeColumnNames(model: EntityInfo[]) { + model.forEach(entity => { + entity.Columns.forEach(column => { + const newName = namingStrategy.columnName(column.tsName); + entity.Indexes.forEach(index => { + index.columns + .filter(column2 => column2.name === column.tsName) + .forEach(column2 => (column2.name = newName)); + }); + model.forEach(entity2 => { + entity2.Columns.forEach(column2 => { + column2.relations + .filter( + relation => + relation.relatedTable === + entity.tsEntityName && + relation.relatedColumn === column.tsName + ) + .map(v => (v.relatedColumn = newName)); + column2.relations + .filter( + relation => + relation.relatedTable === + entity.tsEntityName && + relation.ownerColumn === column.tsName + ) + .map(v => (v.ownerColumn = newName)); + }); + }); + + column.tsName = newName; + }); + }); + return model; + } + function changeEntityNames(entities: EntityInfo[]) { + entities.forEach(entity => { + const newName = namingStrategy.entityName(entity.tsEntityName); + entities.forEach(entity2 => { + entity2.Columns.forEach(column => { + column.relations.forEach(relation => { + if (relation.ownerTable === entity.tsEntityName) { + relation.ownerTable = newName; + } + if (relation.relatedTable === entity.tsEntityName) { + relation.relatedTable = newName; + } + }); + }); + }); + entity.tsEntityName = newName; + }); + return entities; } } diff --git a/src/NamingStrategy.ts b/src/NamingStrategy.ts index 10bf0c5..5dc38f8 100644 --- a/src/NamingStrategy.ts +++ b/src/NamingStrategy.ts @@ -1,15 +1,15 @@ import { AbstractNamingStrategy } from "./AbstractNamingStrategy"; -import { DatabaseModel } from "./models/DatabaseModel"; +import { EntityInfo } from "./models/EntityInfo"; import { RelationInfo } from "./models/RelationInfo"; export class NamingStrategy extends AbstractNamingStrategy { public relationName( columnOldName: string, relation: RelationInfo, - dbModel: DatabaseModel + dbModel: EntityInfo[] ): string { const isRelationToMany = relation.isOneToMany || relation.isManyToMany; - const ownerEntity = dbModel.entities.find( + const ownerEntity = dbModel.find( v => v.tsEntityName === relation.ownerTable )!; diff --git a/src/drivers/AbstractDriver.ts b/src/drivers/AbstractDriver.ts index 7570cfa..882447b 100644 --- a/src/drivers/AbstractDriver.ts +++ b/src/drivers/AbstractDriver.ts @@ -3,8 +3,8 @@ import { WithPrecisionColumnType, WithWidthColumnType } from "typeorm/driver/types/ColumnTypes"; +import { IConnectionOptions } from "../Engine"; import { ColumnInfo } from "../models/ColumnInfo"; -import { DatabaseModel } from "../models/DatabaseModel"; import { EntityInfo } from "../models/EntityInfo"; import { RelationInfo } from "../models/RelationInfo"; import * as TomgUtils from "../Utils"; @@ -56,7 +56,6 @@ export abstract class AbstractDriver { "binary", "varbinary" ]; - public generateRelationsIds: boolean; public abstract GetAllTablesQuery: ( schema: string @@ -67,8 +66,8 @@ export abstract class AbstractDriver { }> >; - public FindManyToManyRelations(dbModel: DatabaseModel) { - const manyToManyEntities = dbModel.entities.filter( + public FindManyToManyRelations(dbModel: EntityInfo[]) { + const manyToManyEntities = dbModel.filter( entity => entity.Columns.filter(column => { return ( @@ -88,7 +87,7 @@ export abstract class AbstractDriver { .map(v => v.relatedTable) .filter((v, i, s) => s.indexOf(v) === i); if (namesOfRelatedTables.length === 2) { - const relatedTable1 = dbModel.entities.find( + const relatedTable1 = dbModel.find( v => v.tsEntityName === namesOfRelatedTables[0] )!; relatedTable1.Columns = relatedTable1.Columns.filter( @@ -97,7 +96,7 @@ export abstract class AbstractDriver { .toLowerCase() .startsWith(entity.tsEntityName.toLowerCase()) ); - const relatedTable2 = dbModel.entities.find( + const relatedTable2 = dbModel.find( v => v.tsEntityName === namesOfRelatedTables[1] )!; relatedTable2.Columns = relatedTable2.Columns.filter( @@ -106,7 +105,7 @@ export abstract class AbstractDriver { .toLowerCase() .startsWith(entity.tsEntityName.toLowerCase()) ); - dbModel.entities = dbModel.entities.filter(ent => { + dbModel = dbModel.filter(ent => { return ent.tsEntityName !== entity.tsEntityName; }); @@ -137,42 +136,26 @@ export abstract class AbstractDriver { relatedTable2.Columns.push(column2); } }); + return dbModel; } public async GetDataFromServer( - database: string, - server: string, - port: number, - user: string, - password: string, - schema: string, - ssl: boolean, - relationIds: boolean - ): Promise { - this.generateRelationsIds = relationIds; - const dbModel = {} as DatabaseModel; - await this.ConnectToServer(database, server, port, user, password, ssl); - const sqlEscapedSchema = "'" + schema.split(",").join("','") + "'"; - dbModel.entities = await this.GetAllTables(sqlEscapedSchema); - await this.GetCoulmnsFromEntity(dbModel.entities, sqlEscapedSchema); - await this.GetIndexesFromEntity(dbModel.entities, sqlEscapedSchema); - dbModel.entities = await this.GetRelations( - dbModel.entities, - sqlEscapedSchema - ); + connectionOptons: IConnectionOptions + ): Promise { + let dbModel = [] as EntityInfo[]; + await this.ConnectToServer(connectionOptons); + const sqlEscapedSchema = + "'" + connectionOptons.schemaName.split(",").join("','") + "'"; + dbModel = await this.GetAllTables(sqlEscapedSchema); + await this.GetCoulmnsFromEntity(dbModel, sqlEscapedSchema); + await this.GetIndexesFromEntity(dbModel, sqlEscapedSchema); + dbModel = await this.GetRelations(dbModel, sqlEscapedSchema); await this.DisconnectFromServer(); - this.FindManyToManyRelations(dbModel); + dbModel = this.FindManyToManyRelations(dbModel); this.FindPrimaryColumnsFromIndexes(dbModel); return dbModel; } - public abstract async ConnectToServer( - database: string, - server: string, - port: number, - user: string, - password: string, - ssl: boolean - ); + public abstract async ConnectToServer(connectionOptons: IConnectionOptions); public async GetAllTables(schema: string): Promise { const response = await this.GetAllTablesQuery(schema); @@ -276,7 +259,6 @@ export abstract class AbstractDriver { ownerRelation.relationType = isOneToMany ? "ManyToOne" : "OneToOne"; - ownerRelation.relationIdField = this.generateRelationsIds; let columnName = ownerEntity.tsEntityName; if ( @@ -351,8 +333,8 @@ export abstract class AbstractDriver { schema: string ): Promise; - public FindPrimaryColumnsFromIndexes(dbModel: DatabaseModel) { - dbModel.entities.forEach(entity => { + public FindPrimaryColumnsFromIndexes(dbModel: EntityInfo[]) { + dbModel.forEach(entity => { const primaryIndex = entity.Indexes.find(v => v.isPrimaryKey); entity.Columns.filter( col => diff --git a/src/drivers/MssqlDriver.ts b/src/drivers/MssqlDriver.ts index c1638b7..7ab2a6a 100644 --- a/src/drivers/MssqlDriver.ts +++ b/src/drivers/MssqlDriver.ts @@ -1,4 +1,5 @@ import * as MSSQL from "mssql"; +import { IConnectionOptions } from "../Engine"; import { ColumnInfo } from "../models/ColumnInfo"; import { EntityInfo } from "../models/EntityInfo"; import * as TomgUtils from "../Utils"; @@ -354,24 +355,17 @@ order by await this.Connection.close(); } } - public async ConnectToServer( - database: string, - server: string, - port: number, - user: string, - password: string, - ssl: boolean - ) { + public async ConnectToServer(connectionOptons: IConnectionOptions) { const config: MSSQL.config = { - database, + database: connectionOptons.databaseName, options: { appName: "typeorm-model-generator", - encrypt: ssl + encrypt: connectionOptons.ssl }, - password, - port, - server, - user + password: connectionOptons.password, + port: connectionOptons.port, + server: connectionOptons.host, + user: connectionOptons.user }; const promise = new Promise((resolve, reject) => { diff --git a/src/drivers/MysqlDriver.ts b/src/drivers/MysqlDriver.ts index 1603644..bccbd65 100644 --- a/src/drivers/MysqlDriver.ts +++ b/src/drivers/MysqlDriver.ts @@ -1,4 +1,5 @@ import * as MYSQL from "mysql"; +import { IConnectionOptions } from "../Engine"; import { ColumnInfo } from "../models/ColumnInfo"; import { EntityInfo } from "../models/EntityInfo"; import * as TomgUtils from "../Utils"; @@ -339,33 +340,26 @@ export class MysqlDriver extends AbstractDriver { await promise; } } - public async ConnectToServer( - database: string, - server: string, - port: number, - user: string, - password: string, - ssl: boolean - ) { + public async ConnectToServer(connectionOptons: IConnectionOptions) { let config: MYSQL.ConnectionConfig; - if (ssl) { + if (connectionOptons.ssl) { config = { - database, - host: server, - password, - port, + database: connectionOptons.databaseName, + host: connectionOptons.host, + password: connectionOptons.password, + port: connectionOptons.port, ssl: { rejectUnauthorized: false }, - user + user: connectionOptons.user }; } else { config = { - database, - host: server, - password, - port, - user + database: connectionOptons.databaseName, + host: connectionOptons.host, + password: connectionOptons.password, + port: connectionOptons.port, + user: connectionOptons.user }; } diff --git a/src/drivers/OracleDriver.ts b/src/drivers/OracleDriver.ts index 0b5ca4e..4ccf0e9 100644 --- a/src/drivers/OracleDriver.ts +++ b/src/drivers/OracleDriver.ts @@ -1,3 +1,4 @@ +import { IConnectionOptions } from "../Engine"; import { ColumnInfo } from "../models/ColumnInfo"; import { EntityInfo } from "../models/EntityInfo"; import * as TomgUtils from "../Utils"; @@ -291,29 +292,26 @@ export class OracleDriver extends AbstractDriver { await this.Connection.close(); } } - public async ConnectToServer( - database: string, - server: string, - port: number, - user: string, - password: string, - ssl: boolean - ) { + public async ConnectToServer(connectionOptons: IConnectionOptions) { let config: any; - if (user === String(process.env.ORACLE_UsernameSys)) { + if (connectionOptons.user === String(process.env.ORACLE_UsernameSys)) { config /*Oracle.IConnectionAttributes*/ = { - connectString: `${server}:${port}/${database}`, - externalAuth: ssl, - password, + connectString: `${connectionOptons.host}:${ + connectionOptons.port + }/${connectionOptons.databaseName}`, + externalAuth: connectionOptons.ssl, + password: connectionOptons.password, privilege: this.Oracle.SYSDBA, - user + user: connectionOptons.user }; } else { config /*Oracle.IConnectionAttributes*/ = { - connectString: `${server}:${port}/${database}`, - externalAuth: ssl, - password, - user + connectString: `${connectionOptons.host}:${ + connectionOptons.port + }/${connectionOptons.databaseName}`, + externalAuth: connectionOptons.ssl, + password: connectionOptons.password, + user: connectionOptons.user }; } const that = this; diff --git a/src/drivers/PostgresDriver.ts b/src/drivers/PostgresDriver.ts index 58317ca..ebe741c 100644 --- a/src/drivers/PostgresDriver.ts +++ b/src/drivers/PostgresDriver.ts @@ -1,4 +1,5 @@ import * as PG from "pg"; +import { IConnectionOptions } from "../Engine"; import { ColumnInfo } from "../models/ColumnInfo"; import { EntityInfo } from "../models/EntityInfo"; import * as TomgUtils from "../Utils"; @@ -531,21 +532,14 @@ export class PostgresDriver extends AbstractDriver { } } - public async ConnectToServer( - database: string, - server: string, - port: number, - user: string, - password: string, - ssl: boolean - ) { + public async ConnectToServer(connectionOptons: IConnectionOptions) { this.Connection = new PG.Client({ - database, - host: server, - password, - port, - ssl, - user + database: connectionOptons.databaseName, + host: connectionOptons.host, + password: connectionOptons.password, + port: connectionOptons.port, + ssl: connectionOptons.ssl, + user: connectionOptons.user }); const promise = new Promise((resolve, reject) => { diff --git a/src/drivers/SqliteDriver.ts b/src/drivers/SqliteDriver.ts index cdab5b6..b65ba2b 100644 --- a/src/drivers/SqliteDriver.ts +++ b/src/drivers/SqliteDriver.ts @@ -1,3 +1,4 @@ +import { IConnectionOptions } from "../Engine"; import { ColumnInfo } from "../models/ColumnInfo"; import { EntityInfo } from "../models/EntityInfo"; import * as TomgUtils from "../Utils"; @@ -292,15 +293,8 @@ export class SqliteDriver extends AbstractDriver { this.db.close(); } - public async ConnectToServer( - database: string, - server: string, - port: number, - user: string, - password: string, - ssl: boolean - ) { - await this.UseDB(database); + public async ConnectToServer(connectionOptons: IConnectionOptions) { + await this.UseDB(connectionOptons.databaseName); } public async CreateDB(dbName: string) { diff --git a/src/index.ts b/src/index.ts index 5cc2ab7..9cc4bf0 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,7 +1,12 @@ import path = require("path"); import * as Yargs from "yargs"; import { AbstractNamingStrategy } from "./AbstractNamingStrategy"; -import { Engine, IConnectionOptions, IGenerationOptions } from "./Engine"; +import { + createDriver, + createModelFromDatabase, + IConnectionOptions, + IGenerationOptions +} from "./Engine"; import { NamingStrategy } from "./NamingStrategy"; import * as TomgUtils from "./Utils"; @@ -105,7 +110,7 @@ const argv = Yargs.usage( describe: "Generate constructor allowing partial initialization" }).argv; -const driver = Engine.createDriver(argv.e); +const driver = createDriver(argv.e); const standardPort = driver.standardPort; const standardSchema = driver.standardPort; const standardUser = driver.standardPort; @@ -146,12 +151,10 @@ console.log(TomgUtils.packageVersion()); console.log( `[${new Date().toLocaleTimeString()}] Starting creation of model classes.` ); -Engine.createModelFromDatabase( - driver, - connectionOptions, - generationOptions -).then(() => { - console.info( - `[${new Date().toLocaleTimeString()}] Typeorm model classes created.` - ); -}); +createModelFromDatabase(driver, connectionOptions, generationOptions).then( + () => { + console.info( + `[${new Date().toLocaleTimeString()}] Typeorm model classes created.` + ); + } +); diff --git a/src/models/DatabaseModel.ts b/src/models/DatabaseModel.ts deleted file mode 100644 index 8dd6410..0000000 --- a/src/models/DatabaseModel.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { EntityInfo } from "./EntityInfo"; -export class DatabaseModel { - public entities: EntityInfo[]; -} diff --git a/test/integration/defaultValues.test.ts b/test/integration/defaultValues.test.ts index a840a47..6e4f06c 100644 --- a/test/integration/defaultValues.test.ts +++ b/test/integration/defaultValues.test.ts @@ -7,7 +7,7 @@ import { EntityFileToJson } from "../utils/EntityFileToJson"; import chai = require('chai'); import chaiSubset = require('chai-subset'); import * as ts from "typescript"; -import { Engine } from "../../src/Engine"; +import { createDriver, createModelFromDatabase } from "../../src/Engine"; import * as GTU from "../utils/GeneralTestUtils" chai.use(chaiSubset); @@ -32,11 +32,11 @@ describe("Column default values", async function () { const resultsPath = path.resolve(process.cwd(), `output`) fs.removeSync(resultsPath) - const driver = Engine.createDriver(dbDriver); + const driver = createDriver(dbDriver); const connectionOptions = await GTU.createModelsInDb(dbDriver, filesOrgPathJS); const generationOptions = GTU.getGenerationOptions(resultsPath); - await Engine.createModelFromDatabase(driver,connectionOptions,generationOptions) + await createModelFromDatabase(driver,connectionOptions,generationOptions) const filesGenPath = path.resolve(resultsPath, 'entities') const filesOrg = fs.readdirSync(filesOrgPathTS).filter((val) => val.toString().endsWith('.ts')) diff --git a/test/integration/entityTypes.test.ts b/test/integration/entityTypes.test.ts index d39d831..4bf1134 100644 --- a/test/integration/entityTypes.test.ts +++ b/test/integration/entityTypes.test.ts @@ -7,7 +7,7 @@ import { EntityFileToJson } from "../utils/EntityFileToJson"; import chai = require('chai'); import chaiSubset = require('chai-subset'); import * as ts from "typescript"; -import { Engine } from "../../src/Engine"; +import { createDriver, createModelFromDatabase } from "../../src/Engine"; import * as GTU from "../utils/GeneralTestUtils" chai.use(chaiSubset); @@ -32,11 +32,11 @@ describe("Platform specyfic types", async function () { const resultsPath = path.resolve(process.cwd(), `output`) fs.removeSync(resultsPath) - const driver = Engine.createDriver(dbDriver); + const driver = createDriver(dbDriver); const connectionOptions = await GTU.createModelsInDb(dbDriver, filesOrgPathJS); const generationOptions = GTU.getGenerationOptions(resultsPath); - await Engine.createModelFromDatabase(driver,connectionOptions,generationOptions) + await createModelFromDatabase(driver,connectionOptions,generationOptions) const filesGenPath = path.resolve(resultsPath, 'entities') const filesOrg = fs.readdirSync(filesOrgPathTS).filter((val) => val.toString().endsWith('.ts')) diff --git a/test/integration/githubIssues.test.ts b/test/integration/githubIssues.test.ts index ddb9b4a..dee14ae 100644 --- a/test/integration/githubIssues.test.ts +++ b/test/integration/githubIssues.test.ts @@ -3,7 +3,7 @@ import { expect } from "chai"; import fs = require('fs-extra'); import path = require('path') import "reflect-metadata"; -import { Engine } from "../../src/Engine"; +import { createModelFromDatabase, createDriver } from "../../src/Engine"; import { EntityFileToJson } from "../utils/EntityFileToJson"; import chai = require('chai'); import chaiSubset = require('chai-subset'); @@ -45,7 +45,7 @@ describe("GitHub issues", async function () { const resultsPath = path.resolve(process.cwd(), `output`) fs.removeSync(resultsPath) - const driver = Engine.createDriver(dbDriver); + const driver = createDriver(dbDriver); const connectionOptions = await GTU.createModelsInDb(dbDriver, filesOrgPathJS); const generationOptions = GTU.getGenerationOptions(resultsPath); @@ -57,7 +57,7 @@ describe("GitHub issues", async function () { break; } - await Engine.createModelFromDatabase(driver,connectionOptions,generationOptions) + await createModelFromDatabase(driver,connectionOptions,generationOptions) const filesGenPath = path.resolve(resultsPath, 'entities') const filesOrg = fs.readdirSync(filesOrgPathTS).filter((val) => val.toString().endsWith('.ts')) diff --git a/test/integration/integration.test.ts b/test/integration/integration.test.ts index edf6401..4710217 100644 --- a/test/integration/integration.test.ts +++ b/test/integration/integration.test.ts @@ -3,7 +3,7 @@ import { expect } from "chai"; import fs = require('fs-extra'); import path = require('path') import "reflect-metadata"; -import { Engine } from "../../src/Engine"; +import { createModelFromDatabase, createDriver } from "../../src/Engine"; import { EntityFileToJson } from "../utils/EntityFileToJson"; import chai = require('chai'); import chaiSubset = require('chai-subset'); @@ -31,7 +31,7 @@ describe("TypeOrm examples", async function () { const resultsPath = path.resolve(process.cwd(), `output`) fs.removeSync(resultsPath) - const driver=Engine.createDriver(dbDriver); + const driver=createDriver(dbDriver); const connectionOptions = await GTU.createModelsInDb(dbDriver, filesOrgPathJS); const generationOptions = GTU.getGenerationOptions(resultsPath); @@ -39,7 +39,7 @@ describe("TypeOrm examples", async function () { generationOptions.lazy = true; } - await Engine.createModelFromDatabase(driver,connectionOptions,generationOptions) + await createModelFromDatabase(driver,connectionOptions,generationOptions) const filesGenPath = path.resolve(resultsPath, 'entities') const filesOrg = fs.readdirSync(filesOrgPathTS).filter((val) => val.toString().endsWith('.ts')) diff --git a/test/utils/GeneralTestUtils.ts b/test/utils/GeneralTestUtils.ts index a710ded..75ebb03 100644 --- a/test/utils/GeneralTestUtils.ts +++ b/test/utils/GeneralTestUtils.ts @@ -32,7 +32,18 @@ export async function createMSSQLModels(filesOrgPath: string): Promise { let driver: AbstractDriver; driver = new PostgresDriver(); - await driver.ConnectToServer(`postgres`, String(process.env.POSTGRES_Host), Number(process.env.POSTGRES_Port), String(process.env.POSTGRES_Username), String(process.env.POSTGRES_Password), yn(process.env.POSTGRES_SSL)); + const connectionOptions: IConnectionOptions = { + host: String(process.env.POSTGRES_Host), + port: Number(process.env.POSTGRES_Port), + databaseName: `postgres`, + user: String(process.env.POSTGRES_Username), + password: String(process.env.POSTGRES_Password), + databaseType: 'postgres', + schemaName: 'public,sch1,sch2', + ssl: yn(process.env.POSTGRES_SSL), + } + await driver.ConnectToServer(connectionOptions); + connectionOptions.databaseName = String(process.env.POSTGRES_Database); if (await driver.CheckIfDBExists(String(process.env.POSTGRES_Database))) { await driver.DropDB(String(process.env.POSTGRES_Database)); @@ -113,24 +124,23 @@ export async function createPostgresModels(filesOrgPath: string): Promise { let driver: AbstractDriver; driver = new SqliteDriver(); - await driver.ConnectToServer(String(process.env.SQLITE_Database), '', 0, '', '', false); + const connectionOptions: IConnectionOptions = { + host: '', + port: 0, + databaseName: String(process.env.SQLITE_Database), + user: '', + password: '', + databaseType: 'sqlite', + schemaName: '', + ssl: false, + } + await driver.ConnectToServer(connectionOptions); if (await driver.CheckIfDBExists(String(process.env.SQLITE_Database))) { await driver.DropDB(String(process.env.SQLITE_Database)); @@ -153,24 +163,23 @@ export async function createSQLiteModels(filesOrgPath: string): Promise { let driver: AbstractDriver; driver = new MysqlDriver(); - await driver.ConnectToServer(String(process.env.MYSQL_Database), String(process.env.MYSQL_Host), Number(process.env.MYSQL_Port), String(process.env.MYSQL_Username), String(process.env.MYSQL_Password), yn(process.env.MYSQL_SSL)); + const connectionOptions: IConnectionOptions = { + host: String(process.env.MYSQL_Host), + port: Number(process.env.MYSQL_Port), + databaseName: String(process.env.MYSQL_Database), + user: String(process.env.MYSQL_Username), + password: String(process.env.MYSQL_Password), + databaseType: 'mysql', + schemaName: 'ignored', + ssl: yn(process.env.MYSQL_SSL), + } + await driver.ConnectToServer(connectionOptions); if (await driver.CheckIfDBExists(String(process.env.MYSQL_Database))) { await driver.DropDB(String(process.env.MYSQL_Database)); @@ -195,23 +204,22 @@ export async function createMysqlModels(filesOrgPath: string): Promise { let driver: AbstractDriver; driver = new MariaDbDriver(); - await driver.ConnectToServer(String(process.env.MARIADB_Database), String(process.env.MARIADB_Host), Number(process.env.MARIADB_Port), String(process.env.MARIADB_Username), String(process.env.MARIADB_Password), yn(process.env.MARIADB_SSL)); + const connectionOptions: IConnectionOptions = { + host: String(process.env.MARIADB_Host), + port: Number(process.env.MARIADB_Port), + databaseName: String(process.env.MARIADB_Database), + user: String(process.env.MARIADB_Username), + password: String(process.env.MARIADB_Password), + databaseType: 'mariadb', + schemaName: 'ignored', + ssl: yn(process.env.MARIADB_SSL), + } + await driver.ConnectToServer(connectionOptions); if (await driver.CheckIfDBExists(String(process.env.MARIADB_Database))) { await driver.DropDB(String(process.env.MARIADB_Database)); @@ -236,24 +244,26 @@ export async function createMariaDBModels(filesOrgPath: string): Promise { let driver: AbstractDriver; driver = new OracleDriver(); - await driver.ConnectToServer(String(process.env.ORACLE_Database), String(process.env.ORACLE_Host), Number(process.env.ORACLE_Port), String(process.env.ORACLE_UsernameSys), String(process.env.ORACLE_PasswordSys), yn(process.env.ORACLE_SSL)); + + const connectionOptions: IConnectionOptions = { + host: String(process.env.ORACLE_Host), + port: Number(process.env.ORACLE_Port), + databaseName: String(process.env.ORACLE_Database), + user: String(process.env.ORACLE_UsernameSys), + password: String(process.env.ORACLE_PasswordSys), + databaseType: 'oracle', + schemaName: String(process.env.ORACLE_Username), + ssl: yn(process.env.ORACLE_SSL), + } + await driver.ConnectToServer(connectionOptions); + connectionOptions.user = String(process.env.ORACLE_Username) + connectionOptions.password = String(process.env.ORACLE_Password) if (await driver.CheckIfDBExists(String(process.env.ORACLE_Username))) { await driver.DropDB(String(process.env.ORACLE_Username)); @@ -278,17 +288,6 @@ export async function createOracleDBModels(filesOrgPath: string): Promise