diff --git a/.eslintrc.js b/.eslintrc.js index d90359b..7cac98f 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -32,7 +32,22 @@ module.exports = { "no-param-reassign": ["off"], "@typescript-eslint/no-explicit-any": ["off"], "no-loop-func": ["off"], - "@typescript-eslint/explicit-module-boundary-types": ["off"] + "@typescript-eslint/explicit-module-boundary-types": ["off"], + 'no-restricted-syntax': [ + 'error', + { + selector: 'ForInStatement', + message: 'for..in loops iterate over the entire prototype chain, which is virtually never what you want. Use Object.{keys,values,entries}, and iterate over the resulting array.', + }, + { + selector: 'LabeledStatement', + message: 'Labels are a form of GOTO; using them makes code confusing and hard to maintain and understand.', + }, + { + selector: 'WithStatement', + message: '`with` is disallowed in strict mode because it makes code impossible to predict and optimize.', + }, + ], }, settings: { "import/resolver": { diff --git a/src/IConnectionOptions.ts b/src/IConnectionOptions.ts index 1cbea89..b5a4379 100644 --- a/src/IConnectionOptions.ts +++ b/src/IConnectionOptions.ts @@ -4,7 +4,7 @@ export default interface IConnectionOptions { host: string; port: number; - databaseName: string; + databaseNames: string[]; user: string; password: string; databaseType: @@ -14,7 +14,7 @@ export default interface IConnectionOptions { | "mariadb" | "oracle" | "sqlite"; - schemaName: string; + schemaNames: string[]; instanceName?: string; ssl: boolean; skipTables: string[]; @@ -25,11 +25,11 @@ export function getDefaultConnectionOptions(): IConnectionOptions { const connectionOptions: IConnectionOptions = { host: "127.0.0.1", port: 0, - databaseName: "", + databaseNames: [""], user: "", password: "", databaseType: undefined as any, - schemaName: "", + schemaNames: [""], instanceName: undefined, ssl: false, skipTables: [], diff --git a/src/Utils.ts b/src/Utils.ts index de32d35..e666a3c 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -80,3 +80,6 @@ export function requireLocalFile(fileName: string): any { throw err; } } +export function assertUnreachable(x: never): never { + throw new Error("Didn't expect to get here"); +} diff --git a/src/drivers/AbstractDriver.ts b/src/drivers/AbstractDriver.ts index c6deff0..637bde1 100644 --- a/src/drivers/AbstractDriver.ts +++ b/src/drivers/AbstractDriver.ts @@ -67,17 +67,6 @@ export default abstract class AbstractDriver { "varbinary", ]; - public abstract GetAllTablesQuery: ( - schema: string, - dbNames: string - ) => Promise< - { - TABLE_SCHEMA: string; - TABLE_NAME: string; - DB_NAME: string; - }[] - >; - public static FindManyToManyRelations(dbModel: Entity[]) { let retVal = dbModel; const manyToManyEntities = retVal.filter( @@ -182,28 +171,25 @@ export default abstract class AbstractDriver { ): Promise { let dbModel = [] as Entity[]; await this.ConnectToServer(connectionOptions); - const sqlEscapedSchema = AbstractDriver.escapeCommaSeparatedList( - connectionOptions.schemaName - ); dbModel = await this.GetAllTables( - sqlEscapedSchema, - connectionOptions.databaseName + connectionOptions.schemaNames, + connectionOptions.databaseNames ); await this.GetCoulmnsFromEntity( dbModel, - sqlEscapedSchema, - connectionOptions.databaseName + connectionOptions.schemaNames, + connectionOptions.databaseNames ); await this.GetIndexesFromEntity( dbModel, - sqlEscapedSchema, - connectionOptions.databaseName + connectionOptions.schemaNames, + connectionOptions.databaseNames ); AbstractDriver.FindPrimaryColumnsFromIndexes(dbModel); dbModel = await this.GetRelations( dbModel, - sqlEscapedSchema, - connectionOptions.databaseName, + connectionOptions.schemaNames, + connectionOptions.databaseNames, generationOptions ); await this.DisconnectFromServer(); @@ -230,30 +216,14 @@ export default abstract class AbstractDriver { ); } - public abstract async ConnectToServer(connectionOptons: IConnectionOptions); + public abstract ConnectToServer( + connectionOptons: IConnectionOptions + ): Promise; - public async GetAllTables( - schema: string, - dbNames: string - ): Promise { - const response = await this.GetAllTablesQuery(schema, dbNames); - const ret: Entity[] = [] as Entity[]; - response.forEach((val) => { - ret.push({ - columns: [], - indices: [], - relations: [], - relationIds: [], - sqlName: val.TABLE_NAME, - tscName: val.TABLE_NAME, - fileName: val.TABLE_NAME, - database: dbNames.includes(",") ? val.DB_NAME : "", - schema: val.TABLE_SCHEMA, - fileImports: [], - }); - }); - return ret; - } + public abstract GetAllTables( + schemas: string[], + dbNames: string[] + ): Promise; public static GetRelationsFromRelationTempInfo( relationsTemp: RelationInternal[], @@ -405,22 +375,22 @@ export default abstract class AbstractDriver { return entities; } - public abstract async GetCoulmnsFromEntity( + public abstract GetCoulmnsFromEntity( entities: Entity[], - schema: string, - dbNames: string + schemas: string[], + dbNames: string[] ): Promise; - public abstract async GetIndexesFromEntity( + public abstract GetIndexesFromEntity( entities: Entity[], - schema: string, - dbNames: string + schemas: string[], + dbNames: string[] ): Promise; - public abstract async GetRelations( + public abstract GetRelations( entities: Entity[], - schema: string, - dbNames: string, + schemas: string[], + dbNames: string[], generationOptions: IGenerationOptions ): Promise; @@ -455,18 +425,15 @@ export default abstract class AbstractDriver { }); } - public abstract async DisconnectFromServer(); + public abstract DisconnectFromServer(): Promise; - public abstract async CreateDB(dbName: string); + public abstract CreateDB(dbName: string): Promise; - public abstract async DropDB(dbName: string); + public abstract DropDB(dbName: string): Promise; - public abstract async UseDB(dbName: string); + public abstract CheckIfDBExists(dbName: string): Promise; - public abstract async CheckIfDBExists(dbName: string): Promise; - - // TODO: change name - protected static escapeCommaSeparatedList(commaSeparatedList: string) { - return `'${commaSeparatedList.split(",").join("','")}'`; + protected static buildEscapedObjectList(dbNames: string[]) { + return `'${dbNames.join("','")}'`; } } diff --git a/src/drivers/MssqlDriver.ts b/src/drivers/MssqlDriver.ts index 8a87984..068053a 100644 --- a/src/drivers/MssqlDriver.ts +++ b/src/drivers/MssqlDriver.ts @@ -37,7 +37,10 @@ export default class MssqlDriver extends AbstractDriver { } } - public GetAllTablesQuery = async (schema: string, dbNames: string) => { + public async GetAllTables( + schemas: string[], + dbNames: string[] + ): Promise { const request = new this.MSSQL.Request(this.Connection); const response: { TABLE_SCHEMA: string; @@ -46,18 +49,36 @@ export default class MssqlDriver extends AbstractDriver { }[] = ( await request.query( `SELECT TABLE_SCHEMA,TABLE_NAME, table_catalog as "DB_NAME" FROM INFORMATION_SCHEMA.TABLES -WHERE TABLE_TYPE='BASE TABLE' and TABLE_SCHEMA in (${schema}) AND TABLE_CATALOG in (${MssqlDriver.escapeCommaSeparatedList( + WHERE TABLE_TYPE='BASE TABLE' and TABLE_SCHEMA in (${MssqlDriver.buildEscapedObjectList( + schemas + )}) AND TABLE_CATALOG in (${MssqlDriver.buildEscapedObjectList( dbNames )})` ) ).recordset; - return response; - }; + // const response = await this.GetAllTablesQuery(schemas, dbNames); + const ret: Entity[] = [] as Entity[]; + response.forEach((val) => { + ret.push({ + columns: [], + indices: [], + relations: [], + relationIds: [], + sqlName: val.TABLE_NAME, + tscName: val.TABLE_NAME, + fileName: val.TABLE_NAME, + database: dbNames.length > 1 ? val.DB_NAME : "", + schema: val.TABLE_SCHEMA, + fileImports: [], + }); + }); + return ret; + } public async GetCoulmnsFromEntity( entities: Entity[], - schema: string, - dbNames: string + schemas: string[], + dbNames: string[] ): Promise { const request = new this.MSSQL.Request(this.Connection); const response: { @@ -86,7 +107,9 @@ WHERE TABLE_TYPE='BASE TABLE' and TABLE_SCHEMA in (${schema}) AND TABLE_CATALOG and cu.COLUMN_NAME = c.COLUMN_NAME and tc.TABLE_SCHEMA=c.TABLE_SCHEMA) IsUnique FROM INFORMATION_SCHEMA.COLUMNS c - where TABLE_SCHEMA in (${schema}) AND TABLE_CATALOG in (${MssqlDriver.escapeCommaSeparatedList( + where TABLE_SCHEMA in (${MssqlDriver.buildEscapedObjectList( + schemas + )}) AND TABLE_CATALOG in (${MssqlDriver.buildEscapedObjectList( dbNames )}) order by ordinal_position`) @@ -255,8 +278,8 @@ WHERE TABLE_TYPE='BASE TABLE' and TABLE_SCHEMA in (${schema}) AND TABLE_CATALOG public async GetIndexesFromEntity( entities: Entity[], - schema: string, - dbNames: string + schemas: string[], + dbNames: string[] ): Promise { const request = new this.MSSQL.Request(this.Connection); /* eslint-disable camelcase */ @@ -269,38 +292,40 @@ WHERE TABLE_TYPE='BASE TABLE' and TABLE_SCHEMA in (${schema}) AND TABLE_CATALOG is_primary_key: boolean; }[] = []; /* eslint-enable camelcase */ - await Promise.all( - dbNames.split(",").map(async (dbName) => { - if (dbNames.length > 1) { - await this.UseDB(dbName); - } - const resp = ( - await request.query(`SELECT - TableName = t.name, - TableSchema = s.name, - IndexName = ind.name, - ColumnName = col.name, - ind.is_unique, - ind.is_primary_key - FROM - sys.indexes ind - INNER JOIN - sys.index_columns ic ON ind.object_id = ic.object_id and ind.index_id = ic.index_id - INNER JOIN - sys.columns col ON ic.object_id = col.object_id and ic.column_id = col.column_id - INNER JOIN - sys.tables t ON ind.object_id = t.object_id - INNER JOIN - sys.schemas s on s.schema_id=t.schema_id - WHERE - t.is_ms_shipped = 0 and s.name in (${schema}) - ORDER BY - t.name, ind.name, ind.index_id, ic.key_ordinal;`) - ).recordset; - response.push(...resp); - }) - ); + /* eslint-disable no-await-in-loop */ + for (const dbName of dbNames) { + if (dbNames.length > 1) { + await this.UseDB(dbName); + } + const resp = ( + await request.query(`SELECT + TableName = t.name, + TableSchema = s.name, + IndexName = ind.name, + ColumnName = col.name, + ind.is_unique, + ind.is_primary_key + FROM + sys.indexes ind + INNER JOIN + sys.index_columns ic ON ind.object_id = ic.object_id and ind.index_id = ic.index_id + INNER JOIN + sys.columns col ON ic.object_id = col.object_id and ic.column_id = col.column_id + INNER JOIN + sys.tables t ON ind.object_id = t.object_id + INNER JOIN + sys.schemas s on s.schema_id=t.schema_id + WHERE + t.is_ms_shipped = 0 and s.name in (${MssqlDriver.buildEscapedObjectList( + schemas + )}) + ORDER BY + t.name, ind.name, ind.index_id, ic.key_ordinal;`) + ).recordset; + response.push(...resp); + } + /* eslint-enable no-await-in-loop */ entities.forEach((ent) => { const entityIndices = response.filter( (filterVal) => @@ -331,8 +356,8 @@ WHERE TABLE_TYPE='BASE TABLE' and TABLE_SCHEMA in (${schema}) AND TABLE_CATALOG public async GetRelations( entities: Entity[], - schema: string, - dbNames: string, + schemas: string[], + dbNames: string[], generationOptions: IGenerationOptions ): Promise { const request = new this.MSSQL.Request(this.Connection); @@ -347,53 +372,56 @@ WHERE TABLE_TYPE='BASE TABLE' and TABLE_SCHEMA in (${schema}) AND TABLE_CATALOG onUpdate: "RESTRICT" | "CASCADE" | "SET_NULL" | "NO_ACTION"; objectId: number; }[] = []; - await Promise.all( - dbNames.split(",").map(async (dbName) => { - if (dbNames.length > 1) { - await this.UseDB(dbName); - } - const resp: { - TableWithForeignKey: string; - // eslint-disable-next-line camelcase - FK_PartNo: number; - ForeignKeyColumn: string; - TableReferenced: string; - ForeignKeyColumnReferenced: string; - onDelete: "RESTRICT" | "CASCADE" | "SET_NULL" | "NO_ACTION"; - onUpdate: "RESTRICT" | "CASCADE" | "SET_NULL" | "NO_ACTION"; - objectId: number; - }[] = ( - await request.query(`select - parentTable.name as TableWithForeignKey, - fkc.constraint_column_id as FK_PartNo, - parentColumn.name as ForeignKeyColumn, - referencedTable.name as TableReferenced, - referencedColumn.name as ForeignKeyColumnReferenced, - fk.delete_referential_action_desc as onDelete, - fk.update_referential_action_desc as onUpdate, - fk.object_id as objectId - from - sys.foreign_keys fk - inner join - sys.foreign_key_columns as fkc on fkc.constraint_object_id=fk.object_id - inner join - sys.tables as parentTable on fkc.parent_object_id = parentTable.object_id - inner join - sys.columns as parentColumn on fkc.parent_object_id = parentColumn.object_id and fkc.parent_column_id = parentColumn.column_id - inner join - sys.tables as referencedTable on fkc.referenced_object_id = referencedTable.object_id - inner join - sys.columns as referencedColumn on fkc.referenced_object_id = referencedColumn.object_id and fkc.referenced_column_id = referencedColumn.column_id - inner join - sys.schemas as parentSchema on parentSchema.schema_id=parentTable.schema_id - where - fk.is_disabled=0 and fk.is_ms_shipped=0 and parentSchema.name in (${schema}) - order by - TableWithForeignKey, FK_PartNo`) - ).recordset; - response.push(...resp); - }) - ); + /* eslint-disable no-await-in-loop */ + for (const dbName of dbNames) { + if (dbNames.length > 1) { + await this.UseDB(dbName); + } + const resp: { + TableWithForeignKey: string; + // eslint-disable-next-line camelcase + FK_PartNo: number; + ForeignKeyColumn: string; + TableReferenced: string; + ForeignKeyColumnReferenced: string; + onDelete: "RESTRICT" | "CASCADE" | "SET_NULL" | "NO_ACTION"; + onUpdate: "RESTRICT" | "CASCADE" | "SET_NULL" | "NO_ACTION"; + objectId: number; + }[] = ( + await request.query(`select + parentTable.name as TableWithForeignKey, + fkc.constraint_column_id as FK_PartNo, + parentColumn.name as ForeignKeyColumn, + referencedTable.name as TableReferenced, + referencedColumn.name as ForeignKeyColumnReferenced, + fk.delete_referential_action_desc as onDelete, + fk.update_referential_action_desc as onUpdate, + fk.object_id as objectId + from + sys.foreign_keys fk + inner join + sys.foreign_key_columns as fkc on fkc.constraint_object_id=fk.object_id + inner join + sys.tables as parentTable on fkc.parent_object_id = parentTable.object_id + inner join + sys.columns as parentColumn on fkc.parent_object_id = parentColumn.object_id and fkc.parent_column_id = parentColumn.column_id + inner join + sys.tables as referencedTable on fkc.referenced_object_id = referencedTable.object_id + inner join + sys.columns as referencedColumn on fkc.referenced_object_id = referencedColumn.object_id and fkc.referenced_column_id = referencedColumn.column_id + inner join + sys.schemas as parentSchema on parentSchema.schema_id=parentTable.schema_id + where + fk.is_disabled=0 and fk.is_ms_shipped=0 and parentSchema.name in (${MssqlDriver.buildEscapedObjectList( + schemas + )}) + order by + TableWithForeignKey, FK_PartNo`) + ).recordset; + response.push(...resp); + } + /* eslint-enable no-await-in-loop */ + const relationsTemp: RelationInternal[] = [] as RelationInternal[]; const relationKeys = new Set(response.map((v) => v.objectId)); @@ -460,7 +488,7 @@ WHERE TABLE_TYPE='BASE TABLE' and TABLE_SCHEMA in (${schema}) AND TABLE_CATALOG } public async ConnectToServer(connectionOptons: IConnectionOptions) { - const databaseName = connectionOptons.databaseName.split(",")[0]; + const databaseName = connectionOptons.databaseNames[0]; const config: MSSQL.config = { database: databaseName, options: { @@ -495,17 +523,17 @@ WHERE TABLE_TYPE='BASE TABLE' and TABLE_SCHEMA in (${schema}) AND TABLE_CATALOG public async CreateDB(dbName: string) { const request = new this.MSSQL.Request(this.Connection); - await request.query(`CREATE DATABASE ${dbName}; `); + await request.query(`CREATE DATABASE "${dbName}"; `); } public async UseDB(dbName: string) { const request = new this.MSSQL.Request(this.Connection); - await request.query(`USE ${dbName}; `); + await request.query(`USE "${dbName}"; `); } public async DropDB(dbName: string) { const request = new this.MSSQL.Request(this.Connection); - await request.query(`DROP DATABASE ${dbName}; `); + await request.query(`DROP DATABASE "${dbName}"; `); } public async CheckIfDBExists(dbName: string): Promise { diff --git a/src/drivers/MysqlDriver.ts b/src/drivers/MysqlDriver.ts index 921c310..e06c874 100644 --- a/src/drivers/MysqlDriver.ts +++ b/src/drivers/MysqlDriver.ts @@ -39,24 +39,45 @@ export default class MysqlDriver extends AbstractDriver { } } - public GetAllTablesQuery = async (schema: string, dbNames: string) => { - const response = this.ExecQuery<{ + public async GetAllTables( + schemas: string[], + dbNames: string[] + ): Promise { + const response: { TABLE_SCHEMA: string; TABLE_NAME: string; DB_NAME: string; - }>(`SELECT TABLE_SCHEMA, TABLE_NAME, TABLE_SCHEMA as DB_NAME - FROM information_schema.tables - WHERE table_type='BASE TABLE' - AND table_schema IN (${MysqlDriver.escapeCommaSeparatedList( - dbNames - )})`); - return response; - }; + }[] = await this.ExecQuery( + `SELECT TABLE_SCHEMA, TABLE_NAME, TABLE_SCHEMA as DB_NAME + FROM information_schema.tables + WHERE table_type='BASE TABLE' + AND table_schema IN (${MysqlDriver.buildEscapedObjectList( + dbNames + )})` + ); + // const response = await this.GetAllTablesQuery(schemas, dbNames); + const ret: Entity[] = [] as Entity[]; + response.forEach((val) => { + ret.push({ + columns: [], + indices: [], + relations: [], + relationIds: [], + sqlName: val.TABLE_NAME, + tscName: val.TABLE_NAME, + fileName: val.TABLE_NAME, + database: dbNames.length > 1 ? val.DB_NAME : "", + schema: val.TABLE_SCHEMA, + fileImports: [], + }); + }); + return ret; + } public async GetCoulmnsFromEntity( entities: Entity[], - schema: string, - dbNames: string + schemas: string[], + dbNames: string[] ): Promise { const response = await this.ExecQuery<{ TABLE_NAME: string; @@ -74,7 +95,7 @@ export default class MysqlDriver extends AbstractDriver { }>(`SELECT TABLE_NAME,COLUMN_NAME,COLUMN_DEFAULT,IS_NULLABLE, DATA_TYPE,CHARACTER_MAXIMUM_LENGTH,NUMERIC_PRECISION,NUMERIC_SCALE, CASE WHEN EXTRA like '%auto_increment%' THEN 1 ELSE 0 END IsIdentity, COLUMN_TYPE, COLUMN_KEY, COLUMN_COMMENT - FROM INFORMATION_SCHEMA.COLUMNS where TABLE_SCHEMA IN (${MysqlDriver.escapeCommaSeparatedList( + FROM INFORMATION_SCHEMA.COLUMNS where TABLE_SCHEMA IN (${MysqlDriver.buildEscapedObjectList( dbNames )}) order by ordinal_position`); @@ -297,8 +318,8 @@ export default class MysqlDriver extends AbstractDriver { public async GetIndexesFromEntity( entities: Entity[], - schema: string, - dbNames: string + schemas: string[], + dbNames: string[] ): Promise { /* eslint-disable camelcase */ const response = await this.ExecQuery<{ @@ -310,7 +331,7 @@ export default class MysqlDriver extends AbstractDriver { }>(`SELECT TABLE_NAME TableName,INDEX_NAME IndexName,COLUMN_NAME ColumnName,CASE WHEN NON_UNIQUE=0 THEN 1 ELSE 0 END is_unique, CASE WHEN INDEX_NAME='PRIMARY' THEN 1 ELSE 0 END is_primary_key FROM information_schema.statistics sta - WHERE table_schema IN (${MysqlDriver.escapeCommaSeparatedList( + WHERE table_schema IN (${MysqlDriver.buildEscapedObjectList( dbNames )})`); /* eslint-enable camelcase */ @@ -344,8 +365,8 @@ export default class MysqlDriver extends AbstractDriver { public async GetRelations( entities: Entity[], - schema: string, - dbNames: string, + schemas: string[], + dbNames: string[], generationOptions: IGenerationOptions ): Promise { const response = await this.ExecQuery<{ @@ -374,7 +395,7 @@ export default class MysqlDriver extends AbstractDriver { INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS RC ON CU.CONSTRAINT_NAME=RC.CONSTRAINT_NAME AND CU.CONSTRAINT_SCHEMA = RC.CONSTRAINT_SCHEMA WHERE - TABLE_SCHEMA IN (${MysqlDriver.escapeCommaSeparatedList(dbNames)}) + TABLE_SCHEMA IN (${MysqlDriver.buildEscapedObjectList(dbNames)}) AND CU.REFERENCED_TABLE_NAME IS NOT NULL; `); const relationsTemp: RelationInternal[] = [] as RelationInternal[]; @@ -444,7 +465,7 @@ export default class MysqlDriver extends AbstractDriver { } public async ConnectToServer(connectionOptons: IConnectionOptions) { - const databaseName = connectionOptons.databaseName.split(",")[0]; + const databaseName = connectionOptons.databaseNames[0]; let config: MYSQL.ConnectionConfig; if (connectionOptons.ssl) { config = { @@ -490,19 +511,19 @@ export default class MysqlDriver extends AbstractDriver { } public async CreateDB(dbName: string) { - await this.ExecQuery(`CREATE DATABASE ${dbName}; `); + await this.ExecQuery(`CREATE DATABASE \`${dbName}\`; `); } public async UseDB(dbName: string) { - await this.ExecQuery(`USE ${dbName}; `); + await this.ExecQuery(`USE \`${dbName}\`; `); } public async DropDB(dbName: string) { - await this.ExecQuery(`DROP DATABASE ${dbName}; `); + await this.ExecQuery(`DROP DATABASE \`${dbName}\`; `); } public async CheckIfDBExists(dbName: string): Promise { - const resp = await this.ExecQuery(`SHOW DATABASES LIKE '${dbName}' `); + const resp = await this.ExecQuery(`SHOW DATABASES LIKE "${dbName}" `); return resp.length > 0; } diff --git a/src/drivers/OracleDriver.ts b/src/drivers/OracleDriver.ts index 9636349..02727bb 100644 --- a/src/drivers/OracleDriver.ts +++ b/src/drivers/OracleDriver.ts @@ -38,7 +38,10 @@ export default class OracleDriver extends AbstractDriver { } } - public GetAllTablesQuery = async (schema: string, dbNames: string) => { + public async GetAllTables( + schemas: string[], + dbNames: string[] + ): Promise { const response = ( await this.Connection.execute<{ TABLE_SCHEMA: string; @@ -48,8 +51,23 @@ export default class OracleDriver extends AbstractDriver { `SELECT NULL AS TABLE_SCHEMA, TABLE_NAME, NULL AS DB_NAME FROM all_tables WHERE owner = (select user from dual)` ) ).rows!; - return response; - }; + const ret: Entity[] = []; + response.forEach((val) => { + ret.push({ + columns: [], + indices: [], + relations: [], + relationIds: [], + sqlName: val.TABLE_NAME, + tscName: val.TABLE_NAME, + fileName: val.TABLE_NAME, + database: dbNames.length > 1 ? val.DB_NAME : "", + schema: val.TABLE_SCHEMA, + fileImports: [], + }); + }); + return ret; + } public async GetCoulmnsFromEntity(entities: Entity[]): Promise { const response = ( @@ -262,8 +280,8 @@ export default class OracleDriver extends AbstractDriver { public async GetRelations( entities: Entity[], - schema: string, - dbNames: string, + schemas: string[], + dbNames: string[], generationOptions: IGenerationOptions ): Promise { const response = ( @@ -341,7 +359,7 @@ export default class OracleDriver extends AbstractDriver { let config: Oracle.ConnectionAttributes; if (connectionOptions.user === String(process.env.ORACLE_UsernameSys)) { config = { - connectString: `${connectionOptions.host}:${connectionOptions.port}/${connectionOptions.databaseName}`, + connectString: `${connectionOptions.host}:${connectionOptions.port}/${connectionOptions.databaseNames[0]}`, externalAuth: connectionOptions.ssl, password: connectionOptions.password, privilege: this.Oracle.SYSDBA, @@ -349,7 +367,7 @@ export default class OracleDriver extends AbstractDriver { }; } else { config = { - connectString: `${connectionOptions.host}:${connectionOptions.port}/${connectionOptions.databaseName}`, + connectString: `${connectionOptions.host}:${connectionOptions.port}/${connectionOptions.databaseNames[0]}`, externalAuth: connectionOptions.ssl, password: connectionOptions.password, user: connectionOptions.user, diff --git a/src/drivers/PostgresDriver.ts b/src/drivers/PostgresDriver.ts index 4f4b285..3a84f95 100644 --- a/src/drivers/PostgresDriver.ts +++ b/src/drivers/PostgresDriver.ts @@ -37,22 +37,42 @@ export default class PostgresDriver extends AbstractDriver { } } - public GetAllTablesQuery = async (schema: string, dbNames: string) => { + public async GetAllTables( + schemas: string[], + dbNames: string[] + ): Promise { const response: { TABLE_SCHEMA: string; TABLE_NAME: string; DB_NAME: string; }[] = ( await this.Connection.query( - `SELECT table_schema as "TABLE_SCHEMA",table_name as "TABLE_NAME", table_catalog as "DB_NAME" FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE='BASE TABLE' AND table_schema in (${schema})` + `SELECT table_schema as "TABLE_SCHEMA",table_name as "TABLE_NAME", table_catalog as "DB_NAME" FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE='BASE TABLE' AND table_schema in (${PostgresDriver.buildEscapedObjectList( + schemas + )})` ) ).rows; - return response; - }; + const ret: Entity[] = []; + response.forEach((val) => { + ret.push({ + columns: [], + indices: [], + relations: [], + relationIds: [], + sqlName: val.TABLE_NAME, + tscName: val.TABLE_NAME, + fileName: val.TABLE_NAME, + database: dbNames.length > 1 ? val.DB_NAME : "", + schema: val.TABLE_SCHEMA, + fileImports: [], + }); + }); + return ret; + } public async GetCoulmnsFromEntity( entities: Entity[], - schema: string + schemas: string[] ): Promise { const response: { /* eslint-disable camelcase */ @@ -93,7 +113,9 @@ export default class PostgresDriver extends AbstractDriver { WHERE "n"."nspname" = table_schema AND "t"."typname"=udt_name ) enumValues FROM INFORMATION_SCHEMA.COLUMNS c - where table_schema in (${schema}) + where table_schema in (${PostgresDriver.buildEscapedObjectList( + schemas + )}) order by ordinal_position`) ).rows; entities.forEach((ent) => { @@ -428,7 +450,7 @@ export default class PostgresDriver extends AbstractDriver { public async GetIndexesFromEntity( entities: Entity[], - schema: string + schemas: string[] ): Promise { const response: { tablename: string; @@ -459,7 +481,7 @@ export default class PostgresDriver extends AbstractDriver { LEFT JOIN pg_index AS ix ON f.attnum = ANY(ix.indkey) and c.oid = f.attrelid and c.oid = ix.indrelid LEFT JOIN pg_class AS i ON ix.indexrelid = i.oid WHERE c.relkind = 'r'::char - AND n.nspname in (${schema}) + AND n.nspname in (${PostgresDriver.buildEscapedObjectList(schemas)}) AND f.attnum > 0 AND i.oid<>0 ORDER BY c.relname,f.attname;`) @@ -492,8 +514,8 @@ export default class PostgresDriver extends AbstractDriver { public async GetRelations( entities: Entity[], - schema: string, - dbNames: string, + schemas: string[], + dbNames: string[], generationOptions: IGenerationOptions ): Promise { const response: { @@ -535,7 +557,9 @@ export default class PostgresDriver extends AbstractDriver { con1.contype = 'f'::"char" AND cl_1.relnamespace = ns.oid AND con1.conrelid = cl_1.oid - and nspname in (${schema}) + and nspname in (${PostgresDriver.buildEscapedObjectList( + schemas + )}) ) con, pg_attribute att, pg_class cl, @@ -618,7 +642,7 @@ export default class PostgresDriver extends AbstractDriver { public async ConnectToServer(connectionOptons: IConnectionOptions) { this.Connection = new this.PG.Client({ - database: connectionOptons.databaseName, + database: connectionOptons.databaseNames[0], host: connectionOptons.host, password: connectionOptons.password, port: connectionOptons.port, @@ -649,10 +673,6 @@ export default class PostgresDriver extends AbstractDriver { await this.Connection.query(`CREATE DATABASE ${dbName}; `); } - public async UseDB(dbName: string) { - await this.Connection.query(`USE ${dbName}; `); - } - public async DropDB(dbName: string) { await this.Connection.query(`DROP DATABASE ${dbName}; `); } diff --git a/src/drivers/SqliteDriver.ts b/src/drivers/SqliteDriver.ts index 6983598..77654b4 100644 --- a/src/drivers/SqliteDriver.ts +++ b/src/drivers/SqliteDriver.ts @@ -45,8 +45,10 @@ export default class SqliteDriver extends AbstractDriver { } public async GetAllTables( - schema: string, - dbNames: string + /* eslint-disable-next-line @typescript-eslint/no-unused-vars */ + schemas: string[], + /* eslint-disable-next-line @typescript-eslint/no-unused-vars */ + dbNames: string[] ): Promise { const ret: Entity[] = [] as Entity[]; // eslint-disable-next-line camelcase @@ -307,8 +309,8 @@ export default class SqliteDriver extends AbstractDriver { public async GetRelations( entities: Entity[], - schema: string, - dbNames: string, + schemas: string[], + dbNames: string[], generationOptions: IGenerationOptions ): Promise { let retVal = entities; @@ -387,7 +389,24 @@ export default class SqliteDriver extends AbstractDriver { } public async ConnectToServer(connectionOptons: IConnectionOptions) { - await this.UseDB(connectionOptons.databaseName); + const promise = new Promise((resolve, reject) => { + this.db = new this.sqlite.Database( + connectionOptons.databaseNames[0], + (err) => { + if (err) { + TomgUtils.LogError( + "Error connecting to SQLite database.", + false, + err.message + ); + reject(err); + return; + } + resolve(); + } + ); + }); + return promise; } // eslint-disable-next-line class-methods-use-this @@ -395,24 +414,6 @@ export default class SqliteDriver extends AbstractDriver { // not supported } - public async UseDB(dbName: string) { - const promise = new Promise((resolve, reject) => { - this.db = new this.sqlite.Database(dbName, (err) => { - if (err) { - TomgUtils.LogError( - "Error connecting to SQLite database.", - false, - err.message - ); - reject(err); - return; - } - resolve(); - }); - }); - return promise; - } - // eslint-disable-next-line class-methods-use-this public async DropDB() { // not supported diff --git a/src/index.ts b/src/index.ts index 7f1bd1c..5480e33 100644 --- a/src/index.ts +++ b/src/index.ts @@ -140,7 +140,7 @@ function checkYargsParameters(options: options): options { alias: "database", string: true, demand: true, - default: options.connectionOptions.databaseName, + default: options.connectionOptions.databaseNames.join(","), describe: "Database name(or path for sqlite). You can pass multiple values separated by comma.", }, @@ -184,7 +184,7 @@ function checkYargsParameters(options: options): options { s: { alias: "schema", string: true, - default: options.connectionOptions.schemaName, + default: options.connectionOptions.schemaNames.join(","), describe: "Schema name to create model from. Only for mssql and postgres. You can pass multiple values separated by comma eg. -s scheme1,scheme2,scheme3", }, @@ -299,7 +299,7 @@ function checkYargsParameters(options: options): options { }, }); - options.connectionOptions.databaseName = argv.d; + options.connectionOptions.databaseNames = argv.d.split(","); options.connectionOptions.databaseType = argv.e; const driver = createDriver(options.connectionOptions.databaseType); @@ -308,9 +308,9 @@ function checkYargsParameters(options: options): options { options.connectionOptions.host = argv.h; options.connectionOptions.password = argv.x; options.connectionOptions.port = argv.p || standardPort; - options.connectionOptions.schemaName = argv.s - ? argv.s.toString() - : standardSchema; + options.connectionOptions.schemaNames = argv.s + ? argv.s.split(",") + : [standardSchema]; options.connectionOptions.instanceName = argv.i || undefined; options.connectionOptions.ssl = argv.ssl; options.connectionOptions.user = argv.u || standardUser; @@ -371,7 +371,7 @@ async function useInquirer(options: options): Promise { if (options.connectionOptions.databaseType !== oldDatabaseType) { options.connectionOptions.port = driver.standardPort; options.connectionOptions.user = driver.standardUser; - options.connectionOptions.schemaName = driver.standardSchema; + options.connectionOptions.schemaNames = [driver.standardSchema]; } if (options.connectionOptions.databaseType !== "sqlite") { if (options.connectionOptions.databaseType === "mssql") { @@ -423,7 +423,7 @@ async function useInquirer(options: options): Promise { type: "password", }, { - default: options.connectionOptions.databaseName, + default: options.connectionOptions.databaseNames.join(","), message: "Database name: (You can pass multiple values separated by comma)", name: "dbName", @@ -434,29 +434,31 @@ async function useInquirer(options: options): Promise { options.connectionOptions.databaseType === "mssql" || options.connectionOptions.databaseType === "postgres" ) { - options.connectionOptions.schemaName = ( + options.connectionOptions.schemaNames = ( await inquirer.prompt([ { - default: options.connectionOptions.schemaName, + default: options.connectionOptions.schemaNames.join( + "," + ), message: "Database schema: (You can pass multiple values separated by comma)", name: "schema", type: "input", }, ]) - ).schema; + ).schema.split(","); } options.connectionOptions.port = parseInt(answ.port, 10); options.connectionOptions.host = answ.host; options.connectionOptions.user = answ.login; options.connectionOptions.password = answ.password; - options.connectionOptions.databaseName = answ.dbName; + options.connectionOptions.databaseNames = answ.dbName.split(","); options.connectionOptions.ssl = answ.ssl; } else { - options.connectionOptions.databaseName = ( + options.connectionOptions.databaseNames = ( await inquirer.prompt([ { - default: options.connectionOptions.databaseName, + default: options.connectionOptions.databaseNames, message: "Path to database file:", name: "dbName", type: "input", diff --git a/test/integration/github-issues/273/entity/Post.ts b/test/integration/github-issues/273/entity/Post.ts new file mode 100644 index 0000000..c6fc34d --- /dev/null +++ b/test/integration/github-issues/273/entity/Post.ts @@ -0,0 +1,20 @@ +import { PrimaryGeneratedColumn, Column, Entity, OneToOne, JoinColumn, Index } from "typeorm"; +import { PostAuthor } from "./PostAuthor"; + +@Entity("Post", {database: "db-1"}) +export class Post { + + @PrimaryGeneratedColumn() + id: number; + + @Column() + title: string; + + @Column() + text: string; + + @OneToOne(type => PostAuthor, author => author.post) + @JoinColumn() + author: PostAuthor; + +} diff --git a/test/integration/github-issues/273/entity/PostAuthor.ts b/test/integration/github-issues/273/entity/PostAuthor.ts new file mode 100644 index 0000000..b161fa2 --- /dev/null +++ b/test/integration/github-issues/273/entity/PostAuthor.ts @@ -0,0 +1,16 @@ +import { PrimaryGeneratedColumn, Column, Entity, OneToOne, JoinColumn } from "typeorm"; +import { Post } from "./Post"; + +@Entity("PostAuthor", {database: "db-1"}) +export class PostAuthor { + + @PrimaryGeneratedColumn() + id: number; + + @Column() + name: string; + + @OneToOne(type => Post, post => post.author) + post: Post; + +} diff --git a/test/integration/runTestsFromPath.test.ts b/test/integration/runTestsFromPath.test.ts index 0eb7af6..c6b9f69 100644 --- a/test/integration/runTestsFromPath.test.ts +++ b/test/integration/runTestsFromPath.test.ts @@ -5,7 +5,6 @@ import * as fs from "fs-extra"; import * as path from "path"; import * as chaiSubset from "chai-subset"; import * as flatMap from "array.prototype.flatmap"; -import * as yn from "yn"; import { CLIEngine } from "eslint"; import * as dotEnv from "dotenv" import EntityFileToJson from "../utils/EntityFileToJson"; @@ -15,6 +14,7 @@ import { Entity } from "../../src/models/Entity"; import IConnectionOptions from "../../src/IConnectionOptions"; import modelCustomizationPhase from "../../src/ModelCustomization"; import modelGenerationPhase from "../../src/ModelGeneration"; +import AbstractDriver from "../../src/drivers/AbstractDriver"; dotEnv.config(); @@ -41,7 +41,7 @@ describe("TypeOrm examples", async () => { describe("Filtering tables", async () => { const testPartialPath = "test/integration/examples"; it("skipTables",async ()=>{ - const dbDrivers: string[] = GTU.getEnabledDbDrivers(); + const dbDrivers = GTU.getEnabledDbDrivers(); const modelGenerationPromises = dbDrivers.map(async dbDriver => { const { generationOptions, @@ -61,7 +61,7 @@ describe("Filtering tables", async () => { await Promise.all(modelGenerationPromises); }); it("onlyTables",async ()=>{ - const dbDrivers: string[] = GTU.getEnabledDbDrivers(); + const dbDrivers = GTU.getEnabledDbDrivers(); const modelGenerationPromises = dbDrivers.map(async dbDriver => { const { generationOptions, @@ -87,7 +87,7 @@ async function runTestsFromPath( testPartialPath: string, isDbSpecific: boolean ) { - const dbDrivers: string[] = GTU.getEnabledDbDrivers(); + const dbDrivers: IConnectionOptions["databaseType"][] = GTU.getEnabledDbDrivers(); createOutputDirs(dbDrivers); const files = fs.readdirSync(path.resolve(process.cwd(), testPartialPath)); if (isDbSpecific) { @@ -114,7 +114,7 @@ function createOutputDirs(dbDrivers: string[]) { function runTestForMultipleDrivers( testName: string, - dbDrivers: string[], + dbDrivers: IConnectionOptions["databaseType"][], testPartialPath: string ) { it(testName, async () => { @@ -127,13 +127,23 @@ function runTestForMultipleDrivers( resultsPath, filesOrgPathTS } = await prepareTestRuns(testPartialPath, testName, dbDriver); - let dbModel: Entity[] = []; + let dbModel: Entity[] = []; switch (testName) { case "144": dbModel = await dataCollectionPhase( driver, Object.assign(connectionOptions, { - databaseName: "db1,db2" + databaseNames: ["db1","db2"] + }), + generationOptions + ); + break; + + case "273": + dbModel = await dataCollectionPhase( + driver, + Object.assign(connectionOptions, { + databaseNames: ["db-1","db-2"] }), generationOptions ); @@ -147,13 +157,13 @@ function runTestForMultipleDrivers( ); break; } - dbModel = modelCustomizationPhase( + dbModel = modelCustomizationPhase( dbModel, generationOptions, driver.defaultValues ); modelGenerationPhase(connectionOptions, generationOptions, dbModel); - const filesGenPath = path.resolve(resultsPath, "entities"); + const filesGenPath = path.resolve(resultsPath, "entities"); compareGeneratedFiles(filesOrgPathTS, filesGenPath); return { dbModel, @@ -189,6 +199,9 @@ function runTestForMultipleDrivers( case "248": return dbDrivers.filter(dbDriver => dbDriver === "postgres" + );case "273": + return dbDrivers.filter(dbDriver => + ["mysql", "mariadb","mssql"].includes(dbDriver) ); default: return dbDrivers; @@ -197,7 +210,7 @@ function runTestForMultipleDrivers( } async function runTest( - dbDrivers: string[], + dbDrivers: IConnectionOptions["databaseType"][], testPartialPath: string, files: string[] ) { @@ -359,7 +372,7 @@ export function compileGeneratedModel( async function prepareTestRuns( testPartialPath: string, testName: string, - dbDriver: string + dbDriver: IConnectionOptions["databaseType"] ) { const filesOrgPathJS = path.resolve( process.cwd(), @@ -373,6 +386,7 @@ async function prepareTestRuns( testName, "entity" ); + const resultsPath = path.resolve(process.cwd(), `output`, dbDriver); fs.removeSync(resultsPath); const driver = createDriver(dbDriver); @@ -385,51 +399,28 @@ async function prepareTestRuns( generationOptions.lazy = true; break; case "144": - // eslint-disable-next-line no-case-declarations + { let connectionOptions: IConnectionOptions; switch (dbDriver) { - case "mysql": - connectionOptions = { - 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, { default: false }), - skipTables: [], - onlyTables: [], - }; - break; case "mariadb": - connectionOptions = { - 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, { default: false }), - skipTables: [], - onlyTables: [] - }; + case "mysql": + connectionOptions = GTU.getTomgConnectionOptions(dbDriver); break; - default: break; } - await driver.ConnectToServer(connectionOptions!); - if (!(await driver.CheckIfDBExists("db1"))) { - await driver.CreateDB("db1"); - } - if (!(await driver.CheckIfDBExists("db2"))) { - await driver.CreateDB("db2"); - } + await createDatabases(["db1","db2"], driver); await driver.DisconnectFromServer(); break; + } + case "273":{ + const connectionOptions= GTU.getTomgConnectionOptions(dbDriver); + await driver.ConnectToServer(connectionOptions!); + await createDatabases(["db-1","db-2"], driver); + await driver.DisconnectFromServer(); + break; + } default: break; } @@ -445,3 +436,11 @@ async function prepareTestRuns( filesOrgPathTS }; } +async function createDatabases(databases: string[], driver: AbstractDriver) { + for await (const db of databases) { + if (!(await driver.CheckIfDBExists(db))) { + await driver.CreateDB(db); + } + } +} + diff --git a/test/utils/GeneralTestUtils.ts b/test/utils/GeneralTestUtils.ts index 763225d..65af0f3 100644 --- a/test/utils/GeneralTestUtils.ts +++ b/test/utils/GeneralTestUtils.ts @@ -11,6 +11,7 @@ import MariaDbDriver from "../../src/drivers/MariaDbDriver"; import PostgresDriver from "../../src/drivers/PostgresDriver"; import OracleDriver from "../../src/drivers/OracleDriver"; import MysqlDriver from "../../src/drivers/MysqlDriver"; +import { assertUnreachable } from "../../src/Utils"; export function getGenerationOptions(resultsPath: string): IGenerationOptions { const retVal = getDefaultGenerationOptions(); @@ -22,20 +23,9 @@ export async function createMSSQLModels( filesOrgPath: string ): Promise { const driver = new MssqlDriver(); - const connectionOptions: IConnectionOptions = { - host: String(process.env.MSSQL_Host), - port: Number(process.env.MSSQL_Port), - databaseName: `master`, - user: String(process.env.MSSQL_Username), - password: String(process.env.MSSQL_Password), - databaseType: "mssql", - schemaName: "dbo,sch1,sch2", - ssl: yn(process.env.MSSQL_SSL, { default: false }), - skipTables: [], - onlyTables: [] - }; + const connectionOptions = getTomgConnectionOptions("mssql"); await driver.ConnectToServer(connectionOptions); - connectionOptions.databaseName = String(process.env.MSSQL_Database); + connectionOptions.databaseNames = [String(process.env.MSSQL_Database)]; if (await driver.CheckIfDBExists(String(process.env.MSSQL_Database))) { await driver.DropDB(String(process.env.MSSQL_Database)); @@ -75,20 +65,9 @@ export async function createPostgresModels( filesOrgPath: string ): Promise { const driver = new PostgresDriver(); - 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, { default: false }), - skipTables: ["spatial_ref_sys"], - onlyTables: [] - }; + const connectionOptions = getTomgConnectionOptions("postgres"); await driver.ConnectToServer(connectionOptions); - connectionOptions.databaseName = String(process.env.POSTGRES_Database); + connectionOptions.databaseNames = [String(process.env.POSTGRES_Database)]; if (await driver.CheckIfDBExists(String(process.env.POSTGRES_Database))) { await driver.DropDB(String(process.env.POSTGRES_Database)); @@ -127,18 +106,7 @@ export async function createPostgresModels( export async function createSQLiteModels( filesOrgPath: string ): Promise { - const connectionOptions: IConnectionOptions = { - host: "", - port: 0, - databaseName: String(process.env.SQLITE_Database), - user: "", - password: "", - databaseType: "sqlite", - schemaName: "", - ssl: false, - skipTables: [], - onlyTables: [] - }; + const connectionOptions = getTomgConnectionOptions("sqlite"); const connOpt: ConnectionOptions = { database: String(process.env.SQLITE_Database), @@ -163,18 +131,7 @@ export async function createMysqlModels( filesOrgPath: string ): Promise { const driver = new MysqlDriver(); - 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, { default: false }), - skipTables: [], - onlyTables: [] - }; + const connectionOptions = getTomgConnectionOptions("mysql"); await driver.ConnectToServer(connectionOptions); if (await driver.CheckIfDBExists(String(process.env.MYSQL_Database))) { @@ -207,18 +164,7 @@ export async function createMariaDBModels( filesOrgPath: string ): Promise { const driver = new MariaDbDriver(); - 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, { default: false }), - skipTables: [], - onlyTables: [] - }; + const connectionOptions = getTomgConnectionOptions("mariadb"); await driver.ConnectToServer(connectionOptions); if (await driver.CheckIfDBExists(String(process.env.MARIADB_Database))) { @@ -253,18 +199,8 @@ export async function createOracleDBModels( ): Promise { const driver = new OracleDriver(); - 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, { default: false }), - skipTables: [], - onlyTables: [] - }; + const connectionOptions = getTomgConnectionOptions("oracle"); + await driver.ConnectToServer(connectionOptions); connectionOptions.user = String(process.env.ORACLE_Username); connectionOptions.password = String(process.env.ORACLE_Password); @@ -317,7 +253,7 @@ export function compileTsFiles( ); console.log( `${diagnostic.file!.fileName} (${lineAndCharacter.line + - 1},${lineAndCharacter.character + 1}): ${message}` + 1},${lineAndCharacter.character + 1}): ${message}` ); compiledWithoutErrors = false; }); @@ -325,8 +261,8 @@ export function compileTsFiles( return compiledWithoutErrors; } -export function getEnabledDbDrivers(): string[] { - const dbDrivers: string[] = []; +export function getEnabledDbDrivers(): IConnectionOptions["databaseType"][] { + const dbDrivers: IConnectionOptions["databaseType"][] = []; if (process.env.SQLITE_Skip === "0") { dbDrivers.push("sqlite"); } @@ -370,3 +306,89 @@ export function createModelsInDb( throw new Error("Unknown engine type"); } } + + +export function getTomgConnectionOptions(dbType: IConnectionOptions["databaseType"]): IConnectionOptions { + switch (dbType) { + case "mssql": + return { + host: String(process.env.MSSQL_Host), + port: Number(process.env.MSSQL_Port), + databaseNames: ["master"], + user: String(process.env.MSSQL_Username), + password: String(process.env.MSSQL_Password), + databaseType: "mssql", + schemaNames: ["dbo","sch1","sch2"], + ssl: yn(process.env.MSSQL_SSL, { default: false }), + skipTables: [], + onlyTables: [] + }; + case "mariadb": + return { + host: String(process.env.MARIADB_Host), + port: Number(process.env.MARIADB_Port), + databaseNames: [String(process.env.MARIADB_Database)], + user: String(process.env.MARIADB_Username), + password: String(process.env.MARIADB_Password), + databaseType: "mariadb", + schemaNames: ["ignored"], + ssl: yn(process.env.MARIADB_SSL, { default: false }), + skipTables: [], + onlyTables: [] + }; + case "mysql": + return { + host: String(process.env.MYSQL_Host), + port: Number(process.env.MYSQL_Port), + databaseNames: [String(process.env.MYSQL_Database)], + user: String(process.env.MYSQL_Username), + password: String(process.env.MYSQL_Password), + databaseType: "mysql", + schemaNames: ["ignored"], + ssl: yn(process.env.MYSQL_SSL, { default: false }), + skipTables: [], + onlyTables: [] + }; + case "oracle": + return { + host: String(process.env.ORACLE_Host), + port: Number(process.env.ORACLE_Port), + databaseNames: [String(process.env.ORACLE_Database)], + user: String(process.env.ORACLE_UsernameSys), + password: String(process.env.ORACLE_PasswordSys), + databaseType: "oracle", + schemaNames: [String(process.env.ORACLE_Username)], + ssl: yn(process.env.ORACLE_SSL, { default: false }), + skipTables: [], + onlyTables: [] + }; + case "postgres": + return { + host: String(process.env.POSTGRES_Host), + port: Number(process.env.POSTGRES_Port), + databaseNames: ["postgres"], + user: String(process.env.POSTGRES_Username), + password: String(process.env.POSTGRES_Password), + databaseType: "postgres", + schemaNames: ["public","sch1","sch2"], + ssl: yn(process.env.POSTGRES_SSL, { default: false }), + skipTables: ["spatial_ref_sys"], + onlyTables: [] + }; + case "sqlite": return { + host: "", + port: 0, + databaseNames: [String(process.env.SQLITE_Database)], + user: "", + password: "", + databaseType: "sqlite", + schemaNames: [""], + ssl: false, + skipTables: [], + onlyTables: [] + }; + default: + return assertUnreachable(dbType); + } + +}