diff --git a/src/drivers/AbstractDriver.ts b/src/drivers/AbstractDriver.ts index b07eb01..7bdfddf 100644 --- a/src/drivers/AbstractDriver.ts +++ b/src/drivers/AbstractDriver.ts @@ -15,10 +15,11 @@ export abstract class AbstractDriver { ): Promise { let dbModel = {}; await this.ConnectToServer(database, server, port, user, password, ssl); - dbModel.entities = await this.GetAllTables(schema); - await this.GetCoulmnsFromEntity(dbModel.entities, schema); - await this.GetIndexesFromEntity(dbModel.entities, schema); - dbModel.entities = await this.GetRelations(dbModel.entities, schema); + let 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); await this.DisconnectFromServer(); this.FindPrimaryColumnsFromIndexes(dbModel); return dbModel; diff --git a/src/drivers/MssqlDriver.ts b/src/drivers/MssqlDriver.ts index fb337e2..c1515d5 100644 --- a/src/drivers/MssqlDriver.ts +++ b/src/drivers/MssqlDriver.ts @@ -37,12 +37,13 @@ export class MssqlDriver extends AbstractDriver { TABLE_SCHEMA: string; TABLE_NAME: string; }[] = (await request.query( - `SELECT TABLE_SCHEMA,TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE='BASE TABLE' and TABLE_SCHEMA='${schema}'` + `SELECT TABLE_SCHEMA,TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE='BASE TABLE' and TABLE_SCHEMA in (${schema})` )).recordset; let ret: EntityInfo[] = []; response.forEach(val => { let ent: EntityInfo = new EntityInfo(); ent.EntityName = val.TABLE_NAME; + ent.Schema=val.TABLE_SCHEMA; ent.Columns = []; ent.Indexes = []; ret.push(ent); @@ -66,7 +67,7 @@ export class MssqlDriver extends AbstractDriver { IsIdentity: number; }[] = (await request.query(`SELECT TABLE_NAME,COLUMN_NAME,COLUMN_DEFAULT,IS_NULLABLE, DATA_TYPE,CHARACTER_MAXIMUM_LENGTH,NUMERIC_PRECISION,NUMERIC_SCALE, - COLUMNPROPERTY(object_id(TABLE_NAME), COLUMN_NAME, 'IsIdentity') IsIdentity FROM INFORMATION_SCHEMA.COLUMNS where TABLE_SCHEMA='${schema}'`)) + COLUMNPROPERTY(object_id(TABLE_NAME), COLUMN_NAME, 'IsIdentity') IsIdentity FROM INFORMATION_SCHEMA.COLUMNS where TABLE_SCHEMA in (${schema})`)) .recordset; entities.forEach(ent => { response @@ -278,7 +279,7 @@ INNER JOIN INNER JOIN sys.schemas s on s.schema_id=t.schema_id WHERE - t.is_ms_shipped = 0 and s.name='${schema}' + t.is_ms_shipped = 0 and s.name in (${schema}) ORDER BY t.name, ind.name, ind.index_id, ic.key_ordinal;`)).recordset; entities.forEach(ent => { @@ -352,7 +353,7 @@ inner join 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='${schema}' + fk.is_disabled=0 and fk.is_ms_shipped=0 and parentSchema.name in (${schema}) order by TableWithForeignKey, FK_PartNo`)).recordset; let relationsTemp: RelationTempInfo[] = []; diff --git a/src/drivers/PostgresDriver.ts b/src/drivers/PostgresDriver.ts index 513957b..204bb3e 100644 --- a/src/drivers/PostgresDriver.ts +++ b/src/drivers/PostgresDriver.ts @@ -37,13 +37,14 @@ export class PostgresDriver extends AbstractDriver { table_schema: string; table_name: string; }[] = (await this.Connection.query( - `SELECT table_schema,table_name FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE='BASE TABLE' AND table_schema = '${schema}' ` + `SELECT table_schema,table_name FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE='BASE TABLE' AND table_schema in (${schema}) ` )).rows; let ret: EntityInfo[] = []; response.forEach(val => { let ent: EntityInfo = new EntityInfo(); ent.EntityName = val.table_name; + ent.Schema=val.table_schema; ent.Columns = []; ent.Indexes = []; ret.push(ent); @@ -69,7 +70,7 @@ export class PostgresDriver extends AbstractDriver { data_type,character_maximum_length,numeric_precision,numeric_scale --,COLUMNPROPERTY(object_id(table_name), column_name, 'isidentity') isidentity , case when column_default LIKE 'nextval%' then 'YES' else 'NO' end isidentity - FROM INFORMATION_SCHEMA.COLUMNS where table_schema ='${schema}'`)) + FROM INFORMATION_SCHEMA.COLUMNS where table_schema in (${schema})`)) .rows; entities.forEach(ent => { response @@ -84,7 +85,7 @@ export class PostgresDriver extends AbstractDriver { colInfo.is_generated = resp.isidentity == "YES" ? true : false; colInfo.default = colInfo.is_generated - ? "" + ? null : resp.column_default; colInfo.sql_type = resp.data_type; switch (resp.data_type) { @@ -252,7 +253,7 @@ export class PostgresDriver extends AbstractDriver { LEFT JOIN pg_class AS i ON ix.indexrelid = i.oid WHERE c.relkind = 'r'::char - AND n.nspname = '${schema}' + AND n.nspname in (${schema}) --AND c.relname = 'nodes' -- Replace with table name, or Comment this for get all tables AND f.attnum > 0 AND i.oid<>0 @@ -331,7 +332,7 @@ export class PostgresDriver extends AbstractDriver { con1.contype = 'f'::"char" AND cl_1.relnamespace = ns.oid AND con1.conrelid = cl_1.oid - and nspname='${schema}' + and nspname in (${schema}) ) con, pg_attribute att, pg_class cl, diff --git a/src/entity.mst b/src/entity.mst index 393fb53..f0698dc 100644 --- a/src/entity.mst +++ b/src/entity.mst @@ -3,7 +3,7 @@ import {Index,Entity, PrimaryColumn, Column, OneToOne, OneToMany, ManyToOne, Joi {{/each}} -@Entity("{{EntityName}}") +@Entity("{{EntityName}}"{{#Schema}},{schema:"{{.}}"}{{/Schema}}) {{#Indexes}}{{^isPrimaryKey}}@Index("{{name}}",[{{#columns}}"{{name}}",{{/columns}}]{{#isUnique}},{unique:true}{{/isUnique}}) {{/isPrimaryKey}}{{/Indexes}}export class {{toEntityName EntityName}} { {{#Columns}} diff --git a/src/models/EntityInfo.ts b/src/models/EntityInfo.ts index 265ec62..357f4a8 100644 --- a/src/models/EntityInfo.ts +++ b/src/models/EntityInfo.ts @@ -10,6 +10,7 @@ export class EntityInfo { Imports: string[]; UniqueImports: string[]; Indexes: IndexInfo[]; + Schema:string; relationImports(): any { var returnString = ""; diff --git a/test/drivers/MssqlDriver.test.ts b/test/drivers/MssqlDriver.test.ts index e872335..4b0934c 100644 --- a/test/drivers/MssqlDriver.test.ts +++ b/test/drivers/MssqlDriver.test.ts @@ -61,6 +61,7 @@ describe('MssqlDriver', function () { let expectedResult = []; let y = new EntityInfo(); y.EntityName = 'name' + y.Schema='schema' y.Columns = []; y.Indexes = []; expectedResult.push(y) diff --git a/test/integration/github-issues/39/entity/Post.ts b/test/integration/github-issues/39/entity/Post.ts new file mode 100644 index 0000000..378587a --- /dev/null +++ b/test/integration/github-issues/39/entity/Post.ts @@ -0,0 +1,28 @@ +import {Index,Entity, PrimaryColumn, Column, OneToOne, OneToMany, ManyToOne, JoinColumn} from "typeorm"; +import {User} from "./User"; + + +@Entity("Post",{schema:"sch1"}) +export class Post { + + @Column("integer",{ + nullable:false, + primary:true, + name:"id" + }) + id:number; + + + + @ManyToOne(type=>User, userId=>userId.posts) + @JoinColumn({ name:"userId"}) + userId:User; + + + @Column("text",{ + nullable:true, + name:"body" + }) + body:string; + +} diff --git a/test/integration/github-issues/39/entity/User.ts b/test/integration/github-issues/39/entity/User.ts new file mode 100644 index 0000000..a709565 --- /dev/null +++ b/test/integration/github-issues/39/entity/User.ts @@ -0,0 +1,27 @@ +import {Index,Entity, PrimaryColumn, Column, OneToOne, OneToMany, ManyToOne, JoinColumn} from "typeorm"; +import {Post} from "./Post"; + + +@Entity("User",{schema:"sch2"}) +export class User { + + @Column("integer",{ + nullable:false, + primary:true, + name:"id" + }) + id:number; + + + @Column("text",{ + nullable:true, + name:"name" + }) + name:string; + + + + @OneToMany(type=>Post, posts=>posts.userId) + posts:Post[]; + +} diff --git a/test/integration/githubIssues.test.ts b/test/integration/githubIssues.test.ts index 8266e65..155a588 100644 --- a/test/integration/githubIssues.test.ts +++ b/test/integration/githubIssues.test.ts @@ -34,6 +34,16 @@ describe("GitHub issues", async function () { describe(`#${folder}`, async function () { for (let dbDriver of dbDrivers) { + + switch (folder) { + case '39': + if (dbDriver =='mysql' || dbDriver=='mariadb') + continue; + break; + default: + break; + } + it(dbDriver, async function () { let filesOrgPathJS = path.resolve(examplesPathJS, folder, 'entity') diff --git a/test/utils/EntityFileToJson.ts b/test/utils/EntityFileToJson.ts index 22f9a42..1ec2c3a 100644 --- a/test/utils/EntityFileToJson.ts +++ b/test/utils/EntityFileToJson.ts @@ -1,4 +1,21 @@ +import { debug } from "util"; + export class EntityFileToJson { + getEntityOptions(trimmedLine: string, ent: EntityJson) { + let decoratorParameters = trimmedLine.slice(trimmedLine.indexOf('(') + 1, trimmedLine.lastIndexOf(')')) + + if (decoratorParameters.length > 0) { + if (decoratorParameters[0] == '"' && decoratorParameters.endsWith('"')) { + + } else { + let badJSON = decoratorParameters.substring(decoratorParameters.indexOf(',') + 1).trim() + if (badJSON.lastIndexOf(',') == badJSON.length - 3) { + badJSON = badJSON.slice(0, badJSON.length - 3) + badJSON[badJSON.length - 2] + badJSON[badJSON.length - 1] + } + ent.entityOptions = JSON.parse(badJSON.replace(/(['"])?([a-z0-9A-Z_]+)(['"])?:/g, '"$2": ')) + } + } + } getColumnOptionsAndType(trimmedLine: string, col: EntityColumn) { let decoratorParameters = trimmedLine.slice(trimmedLine.indexOf('(') + 1, trimmedLine.lastIndexOf(')')) @@ -104,7 +121,15 @@ export class EntityFileToJson { if (trimmedLine.startsWith('import')) { continue; //import statement is not part of entity definition } else if (trimmedLine.startsWith('@Entity')) { - continue; //TODO:entity options + if (this.isPartOfMultilineStatement(trimmedLine)) { + isMultilineStatement = true; + priorPartOfMultilineStatement = trimmedLine; + continue; + } else { + let options = trimmedLine.substring(trimmedLine.lastIndexOf('{'), trimmedLine.lastIndexOf('}')+1).trim().toLowerCase() + this.getEntityOptions(trimmedLine,retVal); + continue; + } } else if (trimmedLine.startsWith('export class')) { retVal.entityName = trimmedLine.substring(trimmedLine.indexOf('class') + 5, trimmedLine.lastIndexOf('{')).trim().toLowerCase() isInClassBody = true; diff --git a/test/utils/GeneralTestUtils.ts b/test/utils/GeneralTestUtils.ts index 0c1f224..f23c0df 100644 --- a/test/utils/GeneralTestUtils.ts +++ b/test/utils/GeneralTestUtils.ts @@ -17,8 +17,9 @@ export async function createMSSQLModels(filesOrgPath: string, resultsPath: strin driver = new MssqlDriver(); await driver.ConnectToServer(`master`, String(process.env.MSSQL_Host), Number(process.env.MSSQL_Port), String(process.env.MSSQL_Username), String(process.env.MSSQL_Password), yn(process.env.MSSQL_SSL)); - if (! await driver.CheckIfDBExists(String(process.env.MSSQL_Database))) - await driver.CreateDB(String(process.env.MSSQL_Database)); + if (await driver.CheckIfDBExists(String(process.env.MSSQL_Database))) + await driver.DropDB(String(process.env.MSSQL_Database)); + await driver.CreateDB(String(process.env.MSSQL_Database)); await driver.DisconnectFromServer(); let connOpt: ConnectionOptions = { @@ -49,7 +50,7 @@ export async function createMSSQLModels(filesOrgPath: string, resultsPath: strin password: String(process.env.MSSQL_Password), databaseType: 'mssql', resultsPath: resultsPath, - schemaName: 'dbo', + schemaName: 'dbo,sch1,sch2', ssl: yn(process.env.MSSQL_SSL), noConfigs: false, convertCaseEntity: 'none', @@ -66,8 +67,9 @@ export async function createPostgresModels(filesOrgPath: string, resultsPath: st 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)); - if (! await driver.CheckIfDBExists(String(process.env.POSTGRES_Database))) - await driver.CreateDB(String(process.env.POSTGRES_Database)); + if (await driver.CheckIfDBExists(String(process.env.POSTGRES_Database))) + await driver.DropDB(String(process.env.POSTGRES_Database)); + await driver.CreateDB(String(process.env.POSTGRES_Database)); await driver.DisconnectFromServer(); let connOpt: ConnectionOptions = { @@ -96,7 +98,7 @@ export async function createPostgresModels(filesOrgPath: string, resultsPath: st password: String(process.env.POSTGRES_Password), databaseType: 'postgres', resultsPath: resultsPath, - schemaName: 'public', + schemaName: 'public,sch1,sch2', ssl: yn(process.env.POSTGRES_SSL), noConfigs: false, convertCaseEntity: 'none', @@ -114,8 +116,9 @@ export async function createMysqlModels(filesOrgPath: string, resultsPath: strin driver = new MysqlDriver(); await driver.ConnectToServer(`mysql`, 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)); - if (! await driver.CheckIfDBExists(String(process.env.MYSQL_Database))) - await driver.CreateDB(String(process.env.MYSQL_Database)); + if (await driver.CheckIfDBExists(String(process.env.MYSQL_Database))) + await driver.DropDB(String(process.env.MYSQL_Database)); + await driver.CreateDB(String(process.env.MYSQL_Database)); await driver.DisconnectFromServer(); let connOpt: ConnectionOptions = { @@ -161,8 +164,9 @@ export async function createMariaDBModels(filesOrgPath: string, resultsPath: str driver = new MariaDbDriver(); await driver.ConnectToServer(`mysql`, 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)); - if (! await driver.CheckIfDBExists(String(process.env.MARIADB_Database))) - await driver.CreateDB(String(process.env.MARIADB_Database)); + if (await driver.CheckIfDBExists(String(process.env.MARIADB_Database))) + await driver.DropDB(String(process.env.MARIADB_Database)); + await driver.CreateDB(String(process.env.MARIADB_Database)); await driver.DisconnectFromServer(); let connOpt: ConnectionOptions = {