From d46738e9323bc831b0362ed72f4c27b3a4e99fa2 Mon Sep 17 00:00:00 2001 From: Kononnable Date: Sun, 25 Mar 2018 01:13:16 +0100 Subject: [PATCH 1/5] code cleaning --- src/drivers/AbstractDriver.ts | 23 ++++++++++++++++++++++- src/drivers/MssqlDriver.ts | 21 --------------------- src/drivers/MysqlDriver.ts | 21 --------------------- src/drivers/OracleDriver.ts | 21 --------------------- src/drivers/PostgresDriver.ts | 21 --------------------- src/models/DatabaseModel.ts | 19 ------------------- 6 files changed, 22 insertions(+), 104 deletions(-) diff --git a/src/drivers/AbstractDriver.ts b/src/drivers/AbstractDriver.ts index c5494f4..b69f656 100644 --- a/src/drivers/AbstractDriver.ts +++ b/src/drivers/AbstractDriver.ts @@ -1,5 +1,6 @@ import { EntityInfo } from "./../models/EntityInfo"; import { DatabaseModel } from "./../models/DatabaseModel"; +import * as TomgUtils from "./../Utils"; /** * AbstractDriver */ @@ -48,7 +49,27 @@ export abstract class AbstractDriver { entities: EntityInfo[], schema: string ): Promise; - abstract async FindPrimaryColumnsFromIndexes(dbModel: DatabaseModel); + + FindPrimaryColumnsFromIndexes(dbModel: DatabaseModel) { + dbModel.entities.forEach(entity => { + let primaryIndex = entity.Indexes.find(v => v.isPrimaryKey); + if (!primaryIndex) { + TomgUtils.LogFatalError( + `Table ${entity.EntityName} has no PK.`, + false + ); + return; + } + entity.Columns.forEach(col => { + if ( + primaryIndex!.columns.some( + cIndex => cIndex.name == col.name + ) + ) + col.isPrimary = true; + }); + }); + } abstract async DisconnectFromServer(); abstract async CreateDB(dbName: string); diff --git a/src/drivers/MssqlDriver.ts b/src/drivers/MssqlDriver.ts index 9c56fde..6997d17 100644 --- a/src/drivers/MssqlDriver.ts +++ b/src/drivers/MssqlDriver.ts @@ -10,27 +10,6 @@ import * as TomgUtils from "./../Utils"; * MssqlDriver */ export class MssqlDriver extends AbstractDriver { - FindPrimaryColumnsFromIndexes(dbModel: DatabaseModel) { - dbModel.entities.forEach(entity => { - let primaryIndex = entity.Indexes.find(v => v.isPrimaryKey); - if (!primaryIndex) { - TomgUtils.LogFatalError( - `Table ${entity.EntityName} has no PK.`, - false - ); - return; - } - entity.Columns.forEach(col => { - if ( - primaryIndex!.columns.some( - cIndex => cIndex.name == col.name - ) - ) - col.isPrimary = true; - }); - }); - } - async GetAllTables(schema: string): Promise { let request = new MSSQL.Request(this.Connection); let response: { diff --git a/src/drivers/MysqlDriver.ts b/src/drivers/MysqlDriver.ts index e631edf..7bf6875 100644 --- a/src/drivers/MysqlDriver.ts +++ b/src/drivers/MysqlDriver.ts @@ -11,27 +11,6 @@ import * as TomgUtils from "./../Utils"; export class MysqlDriver extends AbstractDriver { readonly EngineName: string = "MySQL"; - FindPrimaryColumnsFromIndexes(dbModel: DatabaseModel) { - dbModel.entities.forEach(entity => { - let primaryIndex = entity.Indexes.find(v => v.isPrimaryKey); - if (!primaryIndex) { - TomgUtils.LogFatalError( - `Table ${entity.EntityName} has no PK.`, - false - ); - return; - } - entity.Columns.forEach(col => { - if ( - primaryIndex!.columns.some( - cIndex => cIndex.name == col.name - ) - ) - col.isPrimary = true; - }); - }); - } - async GetAllTables(schema: string): Promise { let response = await this.ExecQuery<{ TABLE_SCHEMA: string; diff --git a/src/drivers/OracleDriver.ts b/src/drivers/OracleDriver.ts index 8a1d3f5..4246a29 100644 --- a/src/drivers/OracleDriver.ts +++ b/src/drivers/OracleDriver.ts @@ -22,27 +22,6 @@ export class OracleDriver extends AbstractDriver { } } - FindPrimaryColumnsFromIndexes(dbModel: DatabaseModel) { - dbModel.entities.forEach(entity => { - let primaryIndex = entity.Indexes.find(v => v.isPrimaryKey); - if (!primaryIndex) { - TomgUtils.LogFatalError( - `Table ${entity.EntityName} has no PK.`, - false - ); - return; - } - entity.Columns.forEach(col => { - if ( - primaryIndex!.columns.some( - cIndex => cIndex.name == col.name - ) - ) - col.isPrimary = true; - }); - }); - } - async GetAllTables(schema: string): Promise { let response: any[][] = (await this.Connection.execute( ` SELECT TABLE_NAME FROM all_tables WHERE owner = (select user from dual)` diff --git a/src/drivers/PostgresDriver.ts b/src/drivers/PostgresDriver.ts index ccef3ad..a785979 100644 --- a/src/drivers/PostgresDriver.ts +++ b/src/drivers/PostgresDriver.ts @@ -11,27 +11,6 @@ import * as TomgUtils from "./../Utils"; export class PostgresDriver extends AbstractDriver { private Connection: PG.Client; - FindPrimaryColumnsFromIndexes(dbModel: DatabaseModel) { - dbModel.entities.forEach(entity => { - let primaryIndex = entity.Indexes.find(v => v.isPrimaryKey); - if (!primaryIndex) { - TomgUtils.LogFatalError( - `Table ${entity.EntityName} has no PK.`, - false - ); - return; - } - entity.Columns.forEach(col => { - if ( - primaryIndex!.columns.some( - cIndex => cIndex.name == col.name - ) - ) - col.isPrimary = true; - }); - }); - } - async GetAllTables(schema: string): Promise { let response: { table_schema: string; diff --git a/src/models/DatabaseModel.ts b/src/models/DatabaseModel.ts index e3d409e..27c6b7b 100644 --- a/src/models/DatabaseModel.ts +++ b/src/models/DatabaseModel.ts @@ -1,23 +1,4 @@ import { EntityInfo } from "./EntityInfo"; export class DatabaseModel { entities: EntityInfo[]; - config: { - cascadeInsert: boolean; - cascadeUpdate: boolean; - cascadeRemove: boolean; - }; - - //TODO:check if unused - relationImports(): any { - let that = this; - return function(text, render) { - if ("l" != render(text)) - return `import {{curly true}}{{toEntityName ${render( - text - )}}}{{curly false}} from "./{{ ${render( - "toFileName" + text - )}}}`; - else return ""; - }; - } } From f7e7cdd64988346415cc89adfb64461a9f106f70 Mon Sep 17 00:00:00 2001 From: Kononnable Date: Mon, 26 Mar 2018 22:41:50 +0200 Subject: [PATCH 2/5] many to many relations --- src/Engine.ts | 26 ++++++++ src/drivers/AbstractDriver.ts | 62 +++++++++++++++++++ src/entity.mst | 6 +- src/models/RelationInfo.ts | 5 +- .../sample4-many-to-many/entity/Post.ts | 62 +++++++++++++++++++ .../sample4-many-to-many/entity/PostAuthor.ts | 16 +++++ .../entity/PostCategory.ts | 12 ++++ .../entity/PostDetails.ts | 22 +++++++ .../sample4-many-to-many/entity/PostImage.ts | 16 +++++ .../entity/PostInformation.ts | 16 +++++ .../entity/PostMetadata.ts | 16 +++++ test/utils/EntityFileToJson.ts | 42 ++++++++++--- 12 files changed, 287 insertions(+), 14 deletions(-) create mode 100644 test/integration/examples/sample4-many-to-many/entity/Post.ts create mode 100644 test/integration/examples/sample4-many-to-many/entity/PostAuthor.ts create mode 100644 test/integration/examples/sample4-many-to-many/entity/PostCategory.ts create mode 100644 test/integration/examples/sample4-many-to-many/entity/PostDetails.ts create mode 100644 test/integration/examples/sample4-many-to-many/entity/PostImage.ts create mode 100644 test/integration/examples/sample4-many-to-many/entity/PostInformation.ts create mode 100644 test/integration/examples/sample4-many-to-many/entity/PostMetadata.ts diff --git a/src/Engine.ts b/src/Engine.ts index ee6d21d..ff9a358 100644 --- a/src/Engine.ts +++ b/src/Engine.ts @@ -160,6 +160,32 @@ export class Engine { Handlebars.registerHelper("toLowerCase", str => { return str.toLowerCase(); }); + Handlebars.registerHelper({ + eq: function(v1, v2) { + return v1 === v2; + }, + ne: function(v1, v2) { + return v1 !== v2; + }, + lt: function(v1, v2) { + return v1 < v2; + }, + gt: function(v1, v2) { + return v1 > v2; + }, + lte: function(v1, v2) { + return v1 <= v2; + }, + gte: function(v1, v2) { + return v1 >= v2; + }, + and: function(v1, v2) { + return v1 && v2; + }, + or: function(v1, v2) { + return v1 || v2; + } + }); } //TODO:Move to mustache template file diff --git a/src/drivers/AbstractDriver.ts b/src/drivers/AbstractDriver.ts index b69f656..29d6873 100644 --- a/src/drivers/AbstractDriver.ts +++ b/src/drivers/AbstractDriver.ts @@ -1,10 +1,71 @@ import { EntityInfo } from "./../models/EntityInfo"; import { DatabaseModel } from "./../models/DatabaseModel"; import * as TomgUtils from "./../Utils"; +import { RelationInfo } from "../models/RelationInfo"; +import { ColumnInfo } from "../models/ColumnInfo"; +import { ManyToMany } from "typeorm"; /** * AbstractDriver */ export abstract class AbstractDriver { + FindManyToManyRelations(dbModel: DatabaseModel) { + let manyToManyEntities = dbModel.entities.filter(entity => { + return ( + entity.Columns.filter(column => { + return ( + column.relations.length == 1 && + !column.relations[0].isOneToMany && + column.relations[0].isOwner + ); + }).length == entity.Columns.length + ); + }); + manyToManyEntities.map(entity => { + let relations: RelationInfo[] = []; + relations = entity.Columns.reduce((prev: RelationInfo[], curr) => { + return prev.concat(curr.relations); + }, relations); + //TODO: Composed keys + if (relations.length == 2) { + let relatedTable1 = dbModel.entities.filter( + v => v.EntityName == relations[0].relatedTable + )[0]; + relatedTable1.Columns = relatedTable1.Columns.filter( + v => v.name != entity.EntityName + ); + let relatedTable2 = dbModel.entities.filter( + v => v.EntityName == relations[1].relatedTable + )[0]; + relatedTable2.Columns = relatedTable2.Columns.filter( + v => v.name != entity.EntityName + ); + dbModel.entities = dbModel.entities.filter(ent => { + return ent.EntityName != entity.EntityName; + }); + + let column1 = new ColumnInfo(); + column1.name = relations[1].relatedTable; + let col1Rel = new RelationInfo(); + col1Rel.relatedTable = relations[1].relatedTable; + col1Rel.relatedColumn = relations[1].relatedTable; + col1Rel.relationType = "ManyToMany"; + col1Rel.isOwner = true; + col1Rel.ownerColumn = relations[0].relatedTable; + column1.relations.push(col1Rel); + relatedTable1.Columns.push(column1); + + let column2 = new ColumnInfo(); + column2.name = relations[0].relatedTable; + let col2Rel = new RelationInfo(); + col2Rel.relatedTable = relations[0].relatedTable; + col2Rel.relatedColumn = relations[1].relatedTable; + col2Rel.relationType = "ManyToMany"; + col2Rel.isOwner = false; + column2.relations.push(col2Rel); + relatedTable2.Columns.push(column2); + } + }); + } async GetDataFromServer( database: string, server: string, @@ -25,6 +86,7 @@ export abstract class AbstractDriver { sqlEscapedSchema ); await this.DisconnectFromServer(); + this.FindManyToManyRelations(dbModel); this.FindPrimaryColumnsFromIndexes(dbModel); return dbModel; } diff --git a/src/entity.mst b/src/entity.mst index f0698dc..e542077 100644 --- a/src/entity.mst +++ b/src/entity.mst @@ -1,4 +1,4 @@ -import {Index,Entity, PrimaryColumn, Column, OneToOne, OneToMany, ManyToOne, JoinColumn} from "typeorm"; +import {Index,Entity, PrimaryColumn, Column, OneToOne, OneToMany, ManyToOne, ManyToMany, JoinColumn, JoinTable} from "typeorm"; {{relationImports}}{{#each UniqueImports}}import {{curly true}}{{toEntityName this}}{{curly false}} from "./{{toFileName this}}"; {{/each}} @@ -23,8 +23,8 @@ import {Index,Entity, PrimaryColumn, Column, OneToOne, OneToMany, ManyToOne, Joi {{toPropertyName name}}:{{ts_type}}; {{/relations}}{{#relations}} @{{relationType}}(type=>{{toEntityName relatedTable}}, {{toPropertyName ../name}}=>{{toPropertyName ../name}}.{{#if isOwner}}{{toPropertyName ownerColumn}}{{else}}{{toPropertyName relatedColumn}}{{/if}}){{#isOwner}} - @JoinColumn({ name:'{{ ../name}}'}){{/isOwner}} - {{#if isOneToMany}}{{toPropertyName ../name}}:{{toEntityName relatedTable}}[]; + {{#if isManyToMany}}@JoinTable(){{else}}@JoinColumn({ name:'{{ ../name}}'}){{/if}}{{/isOwner}} + {{#if (or isOneToMany isManyToMany)}}{{toPropertyName ../name}}:{{toEntityName relatedTable}}[]; {{else}}{{toPropertyName ../name}}:{{toEntityName relatedTable}}; {{/if}}{{/relations}} {{/Columns}} diff --git a/src/models/RelationInfo.ts b/src/models/RelationInfo.ts index 88dd40a..8d895a2 100644 --- a/src/models/RelationInfo.ts +++ b/src/models/RelationInfo.ts @@ -2,7 +2,7 @@ export class RelationInfo { [x: string]: any; isOwner: boolean; - relationType: "OneToOne" | "OneToMany" | "ManyToOne"; + relationType: "OneToOne" | "OneToMany" | "ManyToOne" | "ManyToMany"; relatedTable: string; relatedColumn: string; ownerTable: string; @@ -13,4 +13,7 @@ export class RelationInfo { get isOneToMany(): boolean { return this.relationType == "OneToMany"; } + get isManyToMany(): boolean { + return this.relationType == "ManyToMany"; + } } diff --git a/test/integration/examples/sample4-many-to-many/entity/Post.ts b/test/integration/examples/sample4-many-to-many/entity/Post.ts new file mode 100644 index 0000000..0495570 --- /dev/null +++ b/test/integration/examples/sample4-many-to-many/entity/Post.ts @@ -0,0 +1,62 @@ +import { PrimaryGeneratedColumn, Column, Entity, OneToOne, OneToMany, ManyToOne, ManyToMany, JoinColumn, JoinTable } from "typeorm"; +import {PostDetails} from "./PostDetails"; +import {PostCategory} from "./PostCategory"; +import {PostAuthor} from "./PostAuthor"; +import {PostInformation} from "./PostInformation"; +import {PostImage} from "./PostImage"; +import {PostMetadata} from "./PostMetadata"; + +@Entity("Post") +export class Post { + + @PrimaryGeneratedColumn() + id: number; + + @Column() + title: string; + + @Column() + text: string; + + // post has relation with category, however inverse relation is not set (category does not have relation with post set) + @ManyToMany(type => PostCategory, { + cascade: true + }) + @JoinTable() + PostCategory: PostCategory[]; + + // post has relation with details. cascade inserts here means if new PostDetails instance will be set to this + // relation it will be inserted automatically to the db when you save this Post entity + @ManyToMany(type => PostDetails, details => details.Post, { + cascade: true + }) + @JoinTable() + PostDetails: PostDetails[]; + + // post has relation with details. cascade update here means if new PostDetail instance will be set to this relation + // it will be inserted automatically to the db when you save this Post entity + @ManyToMany(type => PostImage, image => image.Post, { + cascade: true + }) + @JoinTable() + PostImage: PostImage[]; + + // post has relation with details. cascade update here means if new PostDetail instance will be set to this relation + // it will be inserted automatically to the db when you save this Post entity + @ManyToMany(type => PostMetadata, metadata => metadata.Post) + @JoinTable() + PostMetadata: PostMetadata[]; + + // post has relation with details. full cascades here + @ManyToMany(type => PostInformation, information => information.Post, { + cascade: true + }) + @JoinTable() + PostInformation: PostInformation[]; + + // post has relation with details. not cascades here. means cannot be persisted, updated or removed + @ManyToMany(type => PostAuthor, author => author.Post) + @JoinTable() + PostAuthor: PostAuthor[]; + +} diff --git a/test/integration/examples/sample4-many-to-many/entity/PostAuthor.ts b/test/integration/examples/sample4-many-to-many/entity/PostAuthor.ts new file mode 100644 index 0000000..abb6d03 --- /dev/null +++ b/test/integration/examples/sample4-many-to-many/entity/PostAuthor.ts @@ -0,0 +1,16 @@ +import { PrimaryGeneratedColumn, Column, Entity, OneToOne, OneToMany, ManyToOne, ManyToMany, JoinColumn, JoinTable } from "typeorm"; +import {Post} from "./Post"; + +@Entity("PostAuthor") +export class PostAuthor { + + @PrimaryGeneratedColumn() + id: number; + + @Column() + name: string; + + @ManyToMany(type => Post, post => post.PostAuthor) + Post: Post[]; + +} diff --git a/test/integration/examples/sample4-many-to-many/entity/PostCategory.ts b/test/integration/examples/sample4-many-to-many/entity/PostCategory.ts new file mode 100644 index 0000000..a0d3306 --- /dev/null +++ b/test/integration/examples/sample4-many-to-many/entity/PostCategory.ts @@ -0,0 +1,12 @@ +import { PrimaryGeneratedColumn, Column, Entity, OneToOne, OneToMany, ManyToOne, ManyToMany, JoinColumn, JoinTable } from "typeorm"; + +@Entity("PostCategory") +export class PostCategory { + + @PrimaryGeneratedColumn() + id: number; + + @Column() + name: string; + +} diff --git a/test/integration/examples/sample4-many-to-many/entity/PostDetails.ts b/test/integration/examples/sample4-many-to-many/entity/PostDetails.ts new file mode 100644 index 0000000..2b570d8 --- /dev/null +++ b/test/integration/examples/sample4-many-to-many/entity/PostDetails.ts @@ -0,0 +1,22 @@ +import { PrimaryGeneratedColumn, Column, Entity, OneToOne, OneToMany, ManyToOne, ManyToMany, JoinColumn, JoinTable } from "typeorm"; +import {Post} from "./Post"; + +@Entity("PostDetails") +export class PostDetails { + + @PrimaryGeneratedColumn() + id: number; + + @Column() + authorName: string; + + @Column() + comment: string; + + @Column() + metadata: string; + + @ManyToMany(type => Post, post => post.PostDetails) + Post: Post[]; + +} diff --git a/test/integration/examples/sample4-many-to-many/entity/PostImage.ts b/test/integration/examples/sample4-many-to-many/entity/PostImage.ts new file mode 100644 index 0000000..d758949 --- /dev/null +++ b/test/integration/examples/sample4-many-to-many/entity/PostImage.ts @@ -0,0 +1,16 @@ +import { PrimaryGeneratedColumn, Column, Entity, OneToOne, OneToMany, ManyToOne, ManyToMany, JoinColumn, JoinTable } from "typeorm"; +import {Post} from "./Post"; + +@Entity("PostImage") +export class PostImage { + + @PrimaryGeneratedColumn() + id: number; + + @Column() + url: string; + + @ManyToMany(type => Post, post => post.PostImage) + Post: Post[]; + +} diff --git a/test/integration/examples/sample4-many-to-many/entity/PostInformation.ts b/test/integration/examples/sample4-many-to-many/entity/PostInformation.ts new file mode 100644 index 0000000..600fea7 --- /dev/null +++ b/test/integration/examples/sample4-many-to-many/entity/PostInformation.ts @@ -0,0 +1,16 @@ +import { PrimaryGeneratedColumn, Column, Entity, OneToOne, OneToMany, ManyToOne, ManyToMany, JoinColumn, JoinTable } from "typeorm"; +import {Post} from "./Post"; + +@Entity("PostInformation") +export class PostInformation { + + @PrimaryGeneratedColumn() + id: number; + + @Column() + text: string; + + @ManyToMany(type => Post, post => post.PostInformation) + Post: Post[]; + +} diff --git a/test/integration/examples/sample4-many-to-many/entity/PostMetadata.ts b/test/integration/examples/sample4-many-to-many/entity/PostMetadata.ts new file mode 100644 index 0000000..283f2d4 --- /dev/null +++ b/test/integration/examples/sample4-many-to-many/entity/PostMetadata.ts @@ -0,0 +1,16 @@ +import { PrimaryGeneratedColumn, Column, Entity, OneToOne, OneToMany, ManyToOne, ManyToMany, JoinColumn, JoinTable } from "typeorm"; +import {Post} from "./Post"; + +@Entity("PostMetadata") +export class PostMetadata { + + @PrimaryGeneratedColumn() + id: number; + + @Column() + description: string; + + @ManyToMany(type => Post, post => post.PostMetadata) + Post: Post[]; + +} diff --git a/test/utils/EntityFileToJson.ts b/test/utils/EntityFileToJson.ts index 1ec2c3a..90bf4bd 100644 --- a/test/utils/EntityFileToJson.ts +++ b/test/utils/EntityFileToJson.ts @@ -5,15 +5,15 @@ export class EntityFileToJson { let decoratorParameters = trimmedLine.slice(trimmedLine.indexOf('(') + 1, trimmedLine.lastIndexOf(')')) if (decoratorParameters.length > 0) { - if (decoratorParameters[0] == '"' && decoratorParameters.endsWith('"')) { + 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": ')) + } 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) { @@ -126,8 +126,8 @@ export class EntityFileToJson { priorPartOfMultilineStatement = trimmedLine; continue; } else { - let options = trimmedLine.substring(trimmedLine.lastIndexOf('{'), trimmedLine.lastIndexOf('}')+1).trim().toLowerCase() - this.getEntityOptions(trimmedLine,retVal); + let options = trimmedLine.substring(trimmedLine.lastIndexOf('{'), trimmedLine.lastIndexOf('}') + 1).trim().toLowerCase() + this.getEntityOptions(trimmedLine, retVal); continue; } } else if (trimmedLine.startsWith('export class')) { @@ -225,6 +225,18 @@ export class EntityFileToJson { column.relationType = "OneToMany" continue; } + } else if (trimmedLine.startsWith('@ManyToMany')) { + if (this.isPartOfMultilineStatement(trimmedLine)) { + isMultilineStatement = true; + priorPartOfMultilineStatement = trimmedLine; + continue; + } else { + isMultilineStatement = false; + let column = new EntityColumn() + retVal.columns.push(column) + column.relationType = "ManyToMany" + continue; + } } else if (trimmedLine.startsWith('@OneToOne')) { if (this.isPartOfMultilineStatement(trimmedLine)) { isMultilineStatement = true; @@ -247,6 +259,16 @@ export class EntityFileToJson { retVal.columns[retVal.columns.length - 1].isOwnerOfRelation = true; continue; } + } else if (trimmedLine.startsWith('@JoinTable')) { + if (this.isPartOfMultilineStatement(trimmedLine)) { + isMultilineStatement = true; + priorPartOfMultilineStatement = trimmedLine; + continue; + } else { + isMultilineStatement = false; + retVal.columns[retVal.columns.length - 1].isOwnerOfRelation = true; + continue; + } } else if (trimmedLine.startsWith('@Index')) { if (this.isPartOfMultilineStatement(trimmedLine)) { isMultilineStatement = true; @@ -332,7 +354,7 @@ class EntityColumn { columnName: string columnTypes: string[] = [] columnOptions: any = {} - relationType: "OneToOne" | "OneToMany" | "ManyToOne" | "None" = "None" + relationType: "OneToOne" | "OneToMany" | "ManyToOne" | "ManyToMany" | "None" = "None" isOwnerOfRelation: boolean = false; } class EntityIndex { From 7ebc0450b6ee00afddf54203eabf369d2fe92c07 Mon Sep 17 00:00:00 2001 From: Kononnable Date: Tue, 27 Mar 2018 22:04:21 +0200 Subject: [PATCH 3/5] postgres fix on finding indexes when multiple constraints --- src/drivers/AbstractDriver.ts | 4 +-- src/drivers/PostgresDriver.ts | 50 +++++++++++++++++------------------ 2 files changed, 26 insertions(+), 28 deletions(-) diff --git a/src/drivers/AbstractDriver.ts b/src/drivers/AbstractDriver.ts index 29d6873..c7781c1 100644 --- a/src/drivers/AbstractDriver.ts +++ b/src/drivers/AbstractDriver.ts @@ -31,13 +31,13 @@ export abstract class AbstractDriver { v => v.EntityName == relations[0].relatedTable )[0]; relatedTable1.Columns = relatedTable1.Columns.filter( - v => v.name != entity.EntityName + v => v.name.toLowerCase() != entity.EntityName.toLowerCase() ); let relatedTable2 = dbModel.entities.filter( v => v.EntityName == relations[1].relatedTable )[0]; relatedTable2.Columns = relatedTable2.Columns.filter( - v => v.name != entity.EntityName + v => v.name.toLowerCase() != entity.EntityName.toLowerCase() ); dbModel.entities = dbModel.entities.filter(ent => { return ent.EntityName != entity.EntityName; diff --git a/src/drivers/PostgresDriver.ts b/src/drivers/PostgresDriver.ts index a785979..a1a1b43 100644 --- a/src/drivers/PostgresDriver.ts +++ b/src/drivers/PostgresDriver.ts @@ -214,33 +214,31 @@ export class PostgresDriver extends AbstractDriver { is_unique: number; is_primary_key: number; //, is_descending_key: number//, is_included_column: number }[] = (await this.Connection.query(`SELECT - c.relname AS tablename, - i.relname as indexname, - f.attname AS columnname, - CASE - WHEN ix.indisunique = true THEN '1' - ELSE '0' - END AS is_unique, - CASE - WHEN p.contype = 'p' THEN '1' - ELSE '0' - END AS is_primary_key - FROM pg_attribute f - JOIN pg_class c ON c.oid = f.attrelid - JOIN pg_type t ON t.oid = f.atttypid - LEFT JOIN pg_attrdef d ON d.adrelid = c.oid AND d.adnum = f.attnum - LEFT JOIN pg_namespace n ON n.oid = c.relnamespace - LEFT JOIN pg_constraint p ON p.conrelid = c.oid AND f.attnum = ANY (p.conkey) - LEFT JOIN pg_class AS g ON p.confrelid = g.oid - 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 + c.relname AS tablename, + i.relname as indexname, + f.attname AS columnname, + CASE + WHEN ix.indisunique = true THEN '1' + ELSE '0' + END AS is_unique, + CASE + WHEN ix.indisprimary='true' THEN '1' + ELSE '0' + END AS is_primary_key + FROM pg_attribute f + JOIN pg_class c ON c.oid = f.attrelid + JOIN pg_type t ON t.oid = f.atttypid + LEFT JOIN pg_attrdef d ON d.adrelid = c.oid AND d.adnum = f.attnum + LEFT JOIN pg_namespace n ON n.oid = c.relnamespace + 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 c.relname = 'nodes' -- Replace with table name, or Comment this for get all tables - AND f.attnum > 0 - AND i.oid<>0 - ORDER BY c.relname,f.attname;`)).rows; + WHERE c.relkind = 'r'::char + 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 + ORDER BY c.relname,f.attname;`)).rows; entities.forEach(ent => { response .filter(filterVal => { From 7c65907f21bdb2838bce0e7e021fd3cb37209053 Mon Sep 17 00:00:00 2001 From: Kononnable Date: Tue, 27 Mar 2018 23:29:14 +0200 Subject: [PATCH 4/5] Logging error will no longer exit node program --- src/Engine.ts | 2 +- src/Utils.ts | 9 ++++----- src/drivers/AbstractDriver.ts | 2 +- src/drivers/MssqlDriver.ts | 12 ++++++------ src/drivers/MysqlDriver.ts | 14 +++++++------- src/drivers/OracleDriver.ts | 14 +++++++------- src/drivers/PostgresDriver.ts | 14 +++++++------- src/index.ts | 2 +- 8 files changed, 34 insertions(+), 35 deletions(-) diff --git a/src/Engine.ts b/src/Engine.ts index ff9a358..c159840 100644 --- a/src/Engine.ts +++ b/src/Engine.ts @@ -27,7 +27,7 @@ export class Engine { if (dbModel.entities.length > 0) { this.createModelFromMetadata(dbModel); } else { - TomgUtils.LogFatalError( + TomgUtils.LogError( "Tables not found in selected database. Skipping creation of typeorm model.", false ); diff --git a/src/Utils.ts b/src/Utils.ts index 2835553..72c601a 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -1,20 +1,19 @@ import * as data from "./../../package.json"; -export function LogFatalError( +export function LogError( errText: string, isABug: boolean = true, errObject?: any ) { let x = data; console.error(errText); - console.error(`Fatal error occured.`); + console.error(`Error occured in typeorm-model-generator.`); console.error(`${x.name}@${x.version} node@${process.version}`); - console.error(`Fatal error occured in typeorm-model-generator.`); console.error( - `If this is a bug please open an issue including this log on ${ + `If you think this is a bug please open an issue including this log on ${ x.bugs.url }` ); if (isABug && !errObject) errObject = new Error().stack; if (!!errObject) console.error(errObject); - process.abort(); + // process.abort(); } diff --git a/src/drivers/AbstractDriver.ts b/src/drivers/AbstractDriver.ts index c7781c1..f7c77a1 100644 --- a/src/drivers/AbstractDriver.ts +++ b/src/drivers/AbstractDriver.ts @@ -116,7 +116,7 @@ export abstract class AbstractDriver { dbModel.entities.forEach(entity => { let primaryIndex = entity.Indexes.find(v => v.isPrimaryKey); if (!primaryIndex) { - TomgUtils.LogFatalError( + TomgUtils.LogError( `Table ${entity.EntityName} has no PK.`, false ); diff --git a/src/drivers/MssqlDriver.ts b/src/drivers/MssqlDriver.ts index 6997d17..ea11b22 100644 --- a/src/drivers/MssqlDriver.ts +++ b/src/drivers/MssqlDriver.ts @@ -217,7 +217,7 @@ export class MssqlDriver extends AbstractDriver { colInfo.ts_type = "string"; break; default: - TomgUtils.LogFatalError( + TomgUtils.LogError( `Unknown column type: ${ resp.DATA_TYPE } table name: ${ @@ -363,7 +363,7 @@ order by return entitity.EntityName == relationTmp.ownerTable; }); if (!ownerEntity) { - TomgUtils.LogFatalError( + TomgUtils.LogError( `Relation between tables ${relationTmp.ownerTable} and ${ relationTmp.referencedTable } didn't found entity model ${relationTmp.ownerTable}.` @@ -374,7 +374,7 @@ order by return entitity.EntityName == relationTmp.referencedTable; }); if (!referencedEntity) { - TomgUtils.LogFatalError( + TomgUtils.LogError( `Relation between tables ${relationTmp.ownerTable} and ${ relationTmp.referencedTable } didn't found entity model ${relationTmp.referencedTable}.` @@ -385,7 +385,7 @@ order by return column.name == relationTmp.ownerColumnsNames[0]; }); if (!ownerColumn) { - TomgUtils.LogFatalError( + TomgUtils.LogError( `Relation between tables ${relationTmp.ownerTable} and ${ relationTmp.referencedTable } didn't found entity column ${ @@ -398,7 +398,7 @@ order by return column.name == relationTmp.referencedColumnsNames[0]; }); if (!relatedColumn) { - TomgUtils.LogFatalError( + TomgUtils.LogError( `Relation between tables ${relationTmp.ownerTable} and ${ relationTmp.referencedTable } didn't found entity column ${ @@ -517,7 +517,7 @@ order by //Connection successfull resolve(true); } else { - TomgUtils.LogFatalError( + TomgUtils.LogError( "Error connecting to MSSQL Server.", false, err.message diff --git a/src/drivers/MysqlDriver.ts b/src/drivers/MysqlDriver.ts index 7bf6875..aa1e1c7 100644 --- a/src/drivers/MysqlDriver.ts +++ b/src/drivers/MysqlDriver.ts @@ -210,7 +210,7 @@ export class MysqlDriver extends AbstractDriver { .replace(/\'/gi, '"'); break; default: - TomgUtils.LogFatalError( + TomgUtils.LogError( `Unknown column type: ${ resp.DATA_TYPE } table name: ${ @@ -326,7 +326,7 @@ export class MysqlDriver extends AbstractDriver { return entitity.EntityName == relationTmp.ownerTable; }); if (!ownerEntity) { - TomgUtils.LogFatalError( + TomgUtils.LogError( `Relation between tables ${relationTmp.ownerTable} and ${ relationTmp.referencedTable } didn't found entity model ${relationTmp.ownerTable}.` @@ -337,7 +337,7 @@ export class MysqlDriver extends AbstractDriver { return entitity.EntityName == relationTmp.referencedTable; }); if (!referencedEntity) { - TomgUtils.LogFatalError( + TomgUtils.LogError( `Relation between tables ${relationTmp.ownerTable} and ${ relationTmp.referencedTable } didn't found entity model ${relationTmp.referencedTable}.` @@ -348,7 +348,7 @@ export class MysqlDriver extends AbstractDriver { return column.name == relationTmp.ownerColumnsNames[0]; }); if (!ownerColumn) { - TomgUtils.LogFatalError( + TomgUtils.LogError( `Relation between tables ${relationTmp.ownerTable} and ${ relationTmp.referencedTable } didn't found entity column ${ @@ -361,7 +361,7 @@ export class MysqlDriver extends AbstractDriver { return column.name == relationTmp.referencedColumnsNames[0]; }); if (!relatedColumn) { - TomgUtils.LogFatalError( + TomgUtils.LogError( `Relation between tables ${relationTmp.ownerTable} and ${ relationTmp.referencedTable } didn't found entity column ${ @@ -456,7 +456,7 @@ export class MysqlDriver extends AbstractDriver { //Connection successfull resolve(true); } else { - TomgUtils.LogFatalError( + TomgUtils.LogError( `Error disconnecting to ${this.EngineName} Server.`, false, err.message @@ -508,7 +508,7 @@ export class MysqlDriver extends AbstractDriver { //Connection successfull resolve(true); } else { - TomgUtils.LogFatalError( + TomgUtils.LogError( `Error connecting to ${this.EngineName} Server.`, false, err.message diff --git a/src/drivers/OracleDriver.ts b/src/drivers/OracleDriver.ts index 4246a29..41a769d 100644 --- a/src/drivers/OracleDriver.ts +++ b/src/drivers/OracleDriver.ts @@ -17,7 +17,7 @@ export class OracleDriver extends AbstractDriver { try { this.Oracle = require("oracledb"); } catch (error) { - TomgUtils.LogFatalError("", false, error); + TomgUtils.LogError("", false, error); throw error; } } @@ -70,7 +70,7 @@ export class OracleDriver extends AbstractDriver { resp[5] > 0 ? resp[5] : null; break; default: - TomgUtils.LogFatalError( + TomgUtils.LogError( "Unknown column type:" + resp[4] ); break; @@ -164,7 +164,7 @@ export class OracleDriver extends AbstractDriver { return entitity.EntityName == relationTmp.ownerTable; }); if (!ownerEntity) { - TomgUtils.LogFatalError( + TomgUtils.LogError( `Relation between tables ${relationTmp.ownerTable} and ${ relationTmp.referencedTable } didn't found entity model ${relationTmp.ownerTable}.` @@ -175,7 +175,7 @@ export class OracleDriver extends AbstractDriver { return entitity.EntityName == relationTmp.referencedTable; }); if (!referencedEntity) { - TomgUtils.LogFatalError( + TomgUtils.LogError( `Relation between tables ${relationTmp.ownerTable} and ${ relationTmp.referencedTable } didn't found entity model ${relationTmp.referencedTable}.` @@ -186,7 +186,7 @@ export class OracleDriver extends AbstractDriver { return column.name == relationTmp.ownerColumnsNames[0]; }); if (!ownerColumn) { - TomgUtils.LogFatalError( + TomgUtils.LogError( `Relation between tables ${relationTmp.ownerTable} and ${ relationTmp.referencedTable } didn't found entity column ${ @@ -199,7 +199,7 @@ export class OracleDriver extends AbstractDriver { return column.name == relationTmp.referencedColumnsNames[0]; }); if (!relatedColumn) { - TomgUtils.LogFatalError( + TomgUtils.LogError( `Relation between tables ${relationTmp.ownerTable} and ${ relationTmp.referencedTable } didn't found entity column ${ @@ -316,7 +316,7 @@ export class OracleDriver extends AbstractDriver { that.Connection = connection; resolve(true); } else { - TomgUtils.LogFatalError( + TomgUtils.LogError( "Error connecting to Oracle Server.", false, err.message diff --git a/src/drivers/PostgresDriver.ts b/src/drivers/PostgresDriver.ts index a1a1b43..172ee64 100644 --- a/src/drivers/PostgresDriver.ts +++ b/src/drivers/PostgresDriver.ts @@ -188,7 +188,7 @@ export class PostgresDriver extends AbstractDriver { colInfo.ts_type = "string"; break; default: - TomgUtils.LogFatalError( + TomgUtils.LogError( `Unknown column type: ${ resp.data_type } table name: ${ @@ -350,7 +350,7 @@ export class PostgresDriver extends AbstractDriver { return entitity.EntityName == relationTmp.ownerTable; }); if (!ownerEntity) { - TomgUtils.LogFatalError( + TomgUtils.LogError( `Relation between tables ${relationTmp.ownerTable} and ${ relationTmp.referencedTable } didn't found entity model ${relationTmp.ownerTable}.` @@ -361,7 +361,7 @@ export class PostgresDriver extends AbstractDriver { return entitity.EntityName == relationTmp.referencedTable; }); if (!referencedEntity) { - TomgUtils.LogFatalError( + TomgUtils.LogError( `Relation between tables ${relationTmp.ownerTable} and ${ relationTmp.referencedTable } didn't found entity model ${relationTmp.referencedTable}.` @@ -372,7 +372,7 @@ export class PostgresDriver extends AbstractDriver { return column.name == relationTmp.ownerColumnsNames[0]; }); if (!ownerColumn) { - TomgUtils.LogFatalError( + TomgUtils.LogError( `Relation between tables ${relationTmp.ownerTable} and ${ relationTmp.referencedTable } didn't found entity column ${ @@ -385,7 +385,7 @@ export class PostgresDriver extends AbstractDriver { return column.name == relationTmp.referencedColumnsNames[0]; }); if (!relatedColumn) { - TomgUtils.LogFatalError( + TomgUtils.LogError( `Relation between tables ${relationTmp.ownerTable} and ${ relationTmp.referencedTable } didn't found entity column ${ @@ -481,7 +481,7 @@ export class PostgresDriver extends AbstractDriver { //Connection successfull resolve(true); } else { - TomgUtils.LogFatalError( + TomgUtils.LogError( "Error connecting to Postgres Server.", false, err.message @@ -517,7 +517,7 @@ export class PostgresDriver extends AbstractDriver { //Connection successfull resolve(true); } else { - TomgUtils.LogFatalError( + TomgUtils.LogError( "Error connecting to Postgres Server.", false, err.message diff --git a/src/index.ts b/src/index.ts index 1c0d49b..cac693e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -107,7 +107,7 @@ switch (argv.e) { standardPort = 1521; break; default: - TomgUtils.LogFatalError("Database engine not recognized.", false); + TomgUtils.LogError("Database engine not recognized.", false); throw new Error("Database engine not recognized."); } From 3069a06e9d1720c84b93a2863a57f9681bcaf8b3 Mon Sep 17 00:00:00 2001 From: Kononnable Date: Tue, 27 Mar 2018 23:37:58 +0200 Subject: [PATCH 5/5] 0.2.12 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6a56d4c..56dc25e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "typeorm-model-generator", - "version": "0.2.11", + "version": "0.2.12", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 7f5aa80..b7957db 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "typeorm-model-generator", - "version": "0.2.11", + "version": "0.2.12", "description": "Generates models for TypeORM from existing databases.", "bin": "bin/typeorm-model-generator", "scripts": {