diff --git a/src/Engine.ts b/src/Engine.ts index dee0712..c256f2c 100644 --- a/src/Engine.ts +++ b/src/Engine.ts @@ -53,11 +53,11 @@ export async function createModelFromDatabase( ); return; } - // dbModel = modelCustomizationPhase( - // dbModel, - // generationOptions, - // driver.defaultValues - // ); + dbModel = modelCustomizationPhase( + dbModel, + generationOptions, + driver.defaultValues + ); // const dbModel: Entity = { // sqlName: "sqlName", // tscName: "typescriptName", @@ -128,7 +128,7 @@ export async function dataCollectionPhase( } export function modelCustomizationPhase( - dbModel: EntityInfo[], + dbModel: Entity[], generationOptions: IGenerationOptions, defaultValues: DataTypeDefaults ) { @@ -144,9 +144,10 @@ export function modelCustomizationPhase( namingStrategy = new NamingStrategy(); } let retVal = setRelationId(generationOptions, dbModel); - retVal = applyNamingStrategy(namingStrategy, retVal); - retVal = addImportsAndGenerationOptions(retVal, generationOptions); - retVal = removeColumnDefaultProperties(retVal, defaultValues); + // TODO: + // retVal = applyNamingStrategy(namingStrategy, retVal); + // retVal = addImportsAndGenerationOptions(retVal, generationOptions); + // retVal = removeColumnDefaultProperties(retVal, defaultValues); return retVal; } function removeColumnDefaultProperties( @@ -216,19 +217,17 @@ function addImportsAndGenerationOptions( return dbModel; } -function setRelationId( - generationOptions: IGenerationOptions, - model: EntityInfo[] -) { - if (generationOptions.relationIds) { - model.forEach(ent => { - ent.Columns.forEach(col => { - col.relations.forEach(rel => { - rel.relationIdField = rel.isOwner; - }); - }); - }); - } +function setRelationId(generationOptions: IGenerationOptions, model: Entity[]) { + // TODO: + // if (generationOptions.relationIds) { + // model.forEach(ent => { + // ent.columns.forEach(col => { + // col.relations.forEach(rel => { + // rel.relationIdField = rel.isOwner; + // }); + // }); + // }); + // } return model; } export function modelGenerationPhase( @@ -310,6 +309,13 @@ function createHandlebarsHelpers(generationOptions: IGenerationOptions) { Handlebars.registerHelper("concat", (stra, strb) => { return stra + strb; }); + Handlebars.registerHelper("toFileImports", (set: Set) => { + return [...set].reduce( + (pv, cv) => + `${pv}import { {{toEntityName ${cv}}} } from './{{toFileName ${cv}}};`, + "" + ); + }); Handlebars.registerHelper("toFileName", str => { let retStr = ""; switch (generationOptions.convertCaseFile) { diff --git a/src/drivers/AbstractDriver.ts b/src/drivers/AbstractDriver.ts index 3907077..273cc35 100644 --- a/src/drivers/AbstractDriver.ts +++ b/src/drivers/AbstractDriver.ts @@ -160,35 +160,49 @@ export default abstract class AbstractDriver { } public async GetDataFromServer( - connectionOptons: IConnectionOptions + connectionOptions: IConnectionOptions ): Promise { let dbModel = [] as Entity[]; - await this.ConnectToServer(connectionOptons); + await this.ConnectToServer(connectionOptions); const sqlEscapedSchema = AbstractDriver.escapeCommaSeparatedList( - connectionOptons.schemaName + connectionOptions.schemaName ); dbModel = await this.GetAllTables( sqlEscapedSchema, - connectionOptons.databaseName + connectionOptions.databaseName ); await this.GetCoulmnsFromEntity( dbModel, sqlEscapedSchema, - connectionOptons.databaseName + connectionOptions.databaseName ); await this.GetIndexesFromEntity( dbModel, sqlEscapedSchema, - connectionOptons.databaseName + connectionOptions.databaseName ); + AbstractDriver.FindPrimaryColumnsFromIndexes(dbModel); dbModel = await this.GetRelations( dbModel, sqlEscapedSchema, - connectionOptons.databaseName + connectionOptions.databaseName ); await this.DisconnectFromServer(); // dbModel = AbstractDriver.FindManyToManyRelations(dbModel); - AbstractDriver.FindPrimaryColumnsFromIndexes(dbModel); + dbModel = AbstractDriver.FindFileImports(dbModel); + return dbModel; + } + + private static FindFileImports(dbModel: Entity[]) { + dbModel.forEach(entity => { + entity.relations.forEach(relation => { + if ( + !entity.fileImports.some(v => v === relation.relatedTable) + ) { + entity.fileImports.push(relation.relatedTable); + } + }); + }); return dbModel; } @@ -208,7 +222,8 @@ export default abstract class AbstractDriver { sqlName: val.TABLE_NAME, tscName: val.TABLE_NAME, database: dbNames.includes(",") ? val.DB_NAME : "", - schema: val.TABLE_SCHEMA + schema: val.TABLE_SCHEMA, + fileImports: [] }); }); return ret; @@ -304,11 +319,35 @@ export default abstract class AbstractDriver { ); isOneToMany = !index; - const ownerRelation: Relation = { - fieldName: AbstractDriver.findNameForNewField( + if (true) { + // TODO: RelationId + ownerEntity.columns = ownerEntity.columns.filter( + v => + !relationTmp.ownerColumns.some( + u => u === v.tscName + ) || v.primary + ); + relationTmp.relatedTable.columns = relationTmp.relatedTable.columns.filter( + v => + !relationTmp.relatedColumns.some( + u => u === v.tscName + ) || v.primary + ); + } + let fieldName = ""; + if (relationTmp.ownerColumns.length === 1) { + fieldName = AbstractDriver.findNameForNewField( + ownerColumn.tscName, + ownerEntity + ); + } else { + fieldName = AbstractDriver.findNameForNewField( relationTmp.relatedTable.tscName, ownerEntity - ), + ); + } + const ownerRelation: Relation = { + fieldName, joinColumnOptions: relationTmp.ownerColumns.map( (v, idx) => { const retVal: JoinColumnOptions = { @@ -334,7 +373,7 @@ export default abstract class AbstractDriver { fieldName: ownerRelation.relatedField, relatedField: ownerRelation.fieldName, relatedTable: relationTmp.ownerTable.tscName, - relationOptions: ownerRelation.relationOptions, + // relationOptions: ownerRelation.relationOptions, relationType: isOneToMany ? "ManyToOne" : "OneToOne" }; @@ -350,7 +389,7 @@ export default abstract class AbstractDriver { const validNameCondition = entity.columns.every(v => v.tscName !== fieldName) && entity.relations.every(v => v.fieldName !== fieldName); - if (validNameCondition) { + if (!validNameCondition) { fieldName += "_"; for ( let i = 2; diff --git a/src/drivers/MysqlDriver.ts b/src/drivers/MysqlDriver.ts index b5d812b..8531daf 100644 --- a/src/drivers/MysqlDriver.ts +++ b/src/drivers/MysqlDriver.ts @@ -380,6 +380,7 @@ export default class MysqlDriver extends AbstractDriver { internal.ownerColumns.push(row.ForeignKeyColumn); internal.relatedColumns.push(row.ForeignKeyColumnReferenced); }); + relationsTemp.push(internal); }); const retVal = MysqlDriver.GetRelationsFromRelationTempInfo( diff --git a/src/drivers/SqliteDriver.ts b/src/drivers/SqliteDriver.ts index fac4571..7a84e5d 100644 --- a/src/drivers/SqliteDriver.ts +++ b/src/drivers/SqliteDriver.ts @@ -45,7 +45,8 @@ export default class SqliteDriver extends AbstractDriver { indices: [], relations: [], sqlName: val.tbl_name, - tscName: val.tbl_name + tscName: val.tbl_name, + fileImports: [] }); }); return ret; diff --git a/src/entity.mst b/src/entity.mst index 403f851..2ad37df 100644 --- a/src/entity.mst +++ b/src/entity.mst @@ -1,20 +1,25 @@ {{#*inline "Index"}} @Index("{{name}}",[{{#columns}}"{{.}}",{{/columns~}}],{ {{json options}} }) {{/inline}} +{{#*inline "Import"}} +import { {{toEntityName .}} } from './{{toFileName .}}' +{{/inline}} {{#*inline "Column"}} {{#generated}}@PrimaryGeneratedColumn({ type:"{{type}}", {{/generated}}{{^generated}}@Column("{{type}}",{ {{#primary}}primary:{{primary}},{{/primary}}{{/generated}}{{json options}}{{#default}},default: {{.}},{{/default}} }) -{{tscName}}:{{tscType}}; +{{toPropertyName tscName}}:{{tscType}}; {{/inline}} {{#*inline "Relation"}} -@{{relationType}}(()=>{{relatedTable}},{{relatedTable}}=>{{relatedTable}}.{{relatedField}},{ {{json relationOptions}} }) -{{fieldName}}:{{relatedTable}}; +@{{relationType}}(()=>{{toEntityName relatedTable}},{{toEntityName relatedTable}}=>{{toEntityName relatedTable}}.{{toPropertyName relatedField}}{{#if (or joinColumnOptions joinTableOptions)}},{ {{json relationOptions}} }{{/if}}) +{{#if joinColumnOptions}}@JoinColumn({{json joinColumnOptions}}){{/if}} +{{#if joinTableOptions}}@JoinTable{{json joinTableOptions}}){{/if}} +{{toPropertyName fieldName}}:{{toEntityName relatedTable}}; {{/inline}} {{#*inline "Entity"}} {{#indices}}{{> Index}}{{/indices~}} @Entity("{{sqlName}}",{schema:"{{schema}}",database:"{{database}}"}) -export class {{tscName}} { +export class {{toEntityName tscName}} { {{#columns}}{{> Column}}{{/columns~}} {{#relations}}{{> Relation}}{{/relations~}} @@ -22,6 +27,7 @@ export class {{tscName}} { {{/inline}} import {BaseEntity,Column,Entity,Index,JoinColumn,JoinTable,ManyToMany,ManyToOne,OneToMany,OneToOne,PrimaryColumn,PrimaryGeneratedColumn,RelationId} from "typeorm"; +{{#fileImports}}{{> Import}}{{/fileImports~}} {{~> Entity}} diff --git a/src/models/Entity.ts b/src/models/Entity.ts index 7a99347..9a2c566 100644 --- a/src/models/Entity.ts +++ b/src/models/Entity.ts @@ -12,4 +12,5 @@ export type Entity = { columns: Column[]; relations: Relation[]; indices: Index[]; + fileImports: string[]; }; diff --git a/src/models/Relation.ts b/src/models/Relation.ts index d3ef883..c8cb02f 100644 --- a/src/models/Relation.ts +++ b/src/models/Relation.ts @@ -6,7 +6,7 @@ export type Relation = { relatedTable: string; relatedField: string; fieldName: string; - relationOptions: RelationOptions; + relationOptions?: RelationOptions; joinColumnOptions?: JoinColumnOptions[]; joinTableOptions?: JoinTableMultipleColumnsOptions; }; diff --git a/test/integration/examples/sample1-simple-entity/entity/Post.ts b/test/integration/examples/sample1-simple-entity/entity/Post.ts index acc4bc1..3511066 100644 --- a/test/integration/examples/sample1-simple-entity/entity/Post.ts +++ b/test/integration/examples/sample1-simple-entity/entity/Post.ts @@ -1,8 +1,13 @@ -import { Column, Entity, PrimaryGeneratedColumn, Index, Generated } from "typeorm"; +import { + Column, + Entity, + PrimaryGeneratedColumn, + Index, + Generated +} from "typeorm"; @Entity("Post") export class Post { - @PrimaryGeneratedColumn() id: number; @@ -13,8 +18,8 @@ export class Post { text: string; @Column("int", { - nullable: false + // Columns are non-nullable by default + // nullable: false }) likesCount: number; - } diff --git a/test/integration/runTestsFromPath.test.ts b/test/integration/runTestsFromPath.test.ts index ab1a915..2b37def 100644 --- a/test/integration/runTestsFromPath.test.ts +++ b/test/integration/runTestsFromPath.test.ts @@ -106,12 +106,11 @@ function runTestForMultipleDrivers( ); break; } - // TODO: Remove - // dbModel = modelCustomizationPhase( - // dbModel, - // generationOptions, - // driver.defaultValues - // ); + dbModel = modelCustomizationPhase( + dbModel, + generationOptions, + driver.defaultValues + ); modelGenerationPhase(connectionOptions, generationOptions, dbModel); const filesGenPath = path.resolve(resultsPath, "entities"); compareGeneratedFiles(filesOrgPathTS, filesGenPath); @@ -163,12 +162,11 @@ async function runTest( filesOrgPathTS } = await prepareTestRuns(testPartialPath, dbDriver, dbDriver); let dbModel = await dataCollectionPhase(driver, connectionOptions); - // TODO: Remove - // dbModel = modelCustomizationPhase( - // dbModel, - // generationOptions, - // driver.defaultValues - // ); + dbModel = modelCustomizationPhase( + dbModel, + generationOptions, + driver.defaultValues + ); modelGenerationPhase(connectionOptions, generationOptions, dbModel); const filesGenPath = path.resolve(resultsPath, "entities"); compareGeneratedFiles(filesOrgPathTS, filesGenPath); diff --git a/test/utils/EntityFileToJson.ts b/test/utils/EntityFileToJson.ts index 73d9f2b..902e595 100644 --- a/test/utils/EntityFileToJson.ts +++ b/test/utils/EntityFileToJson.ts @@ -173,7 +173,7 @@ export default class EntityFileToJson { decoratorParameters.indexOf('"') + 1, decoratorParameters .substr(decoratorParameters.indexOf('"') + 1) - .indexOf('"') + .indexOf('"') + 1 ); } if (containsTables) { diff --git a/test/utils/GeneralTestUtils.ts b/test/utils/GeneralTestUtils.ts index 8c4af84..00b7e23 100644 --- a/test/utils/GeneralTestUtils.ts +++ b/test/utils/GeneralTestUtils.ts @@ -15,9 +15,9 @@ export function getGenerationOptions(resultsPath: string): IGenerationOptions { return { resultsPath, noConfigs: false, - convertCaseEntity: "none", + convertCaseEntity: "none", // TODO: Change to lib defaults convertCaseFile: "none", - convertCaseProperty: "none", + convertCaseProperty: "camel", propertyVisibility: "none", lazy: false, generateConstructor: false,