From 8d18027adfb6a46a611709c521677d73b02678e3 Mon Sep 17 00:00:00 2001 From: Kononnable Date: Sun, 22 Apr 2018 20:26:59 +0200 Subject: [PATCH] added lazy relations --- README.md | 25 ++++++++------- src/Engine.ts | 8 +++++ src/drivers/MssqlDriver.ts | 32 +++++++++++++++---- src/entity.mst | 4 +-- src/index.ts | 8 ++++- .../sample18-lazy-relations/entity/Author.ts | 25 +++++++++++++++ .../entity/Category.ts | 16 ++++++++++ .../sample18-lazy-relations/entity/Post.ts | 29 +++++++++++++++++ test/integration/integration.test.ts | 4 ++- test/utils/EntityFileToJson.ts | 7 +++- test/utils/GeneralTestUtils.ts | 5 +++ 11 files changed, 140 insertions(+), 23 deletions(-) create mode 100644 test/integration/examples/sample18-lazy-relations/entity/Author.ts create mode 100644 test/integration/examples/sample18-lazy-relations/entity/Category.ts create mode 100644 test/integration/examples/sample18-lazy-relations/entity/Post.ts diff --git a/README.md b/README.md index 9a9188c..76f2202 100644 --- a/README.md +++ b/README.md @@ -27,25 +27,26 @@ Usage: typeorm-model-generator -h -d -p [port] -u -x [password] -e [engine] Options: - -h, --host IP adress/Hostname for database server. [required] - -d, --database Database name. [required] - -u, --user Username for database server. [required] - -x, --pass Password for database server. [required] - -p, --port Port number for database server. - -e, --engine Database engine. + -h, --host IP adress/Hostname for database server. [required] + -d, --database Database name. [required] + -u, --user Username for database server. [required] + -x, --pass Password for database server. [required] + -p, --port Port number for database server. + -e, --engine Database engine. [choices: "mssql", "postgres", "mysql", "mariadb", "oracle"] [default: "mssql"] - -o, --output Where to place generated models. - -s, --schema Schema name to create model from. Only for mssql and postgres. - --ssl [boolean] [default: false] - --noConfig Doesn't create tsconfig.json and ormconfig.json + -o, --output Where to place generated models. + -s, --schema Schema name to create model from. Only for mssql and postgres. + --ssl [boolean] [defau lt: false] + --noConfig Doesn't create tsconfig.json and ormconfig.json [boolean] [default: false] - --cf, --case-file Convert file names to specified case + --cf, --case-file Convert file names to specified case [choices: "pascal", "param", "camel", "none"] [default: "none"] - --ce, --case-entity Convert class names to specified case + --ce, --case-entity Convert class names to specified case [choices: "pascal", "camel", "none"] [default: "none"] --cp, --case-property Convert property names to specified case [choices: "pascal", "camel", "none"] [default: "none"] + --lazy Generate lazy relations [boolean] [default: false] ``` ### Examples diff --git a/src/Engine.ts b/src/Engine.ts index c159840..d06a046 100644 --- a/src/Engine.ts +++ b/src/Engine.ts @@ -124,6 +124,9 @@ export class Engine { } return retStr; }); + Handlebars.registerHelper("concat", (stra, strb) => { + return stra + strb; + }); Handlebars.registerHelper("toFileName", str => { let retStr = ""; switch (this.Options.convertCaseFile) { @@ -160,6 +163,10 @@ export class Engine { Handlebars.registerHelper("toLowerCase", str => { return str.toLowerCase(); }); + Handlebars.registerHelper("toLazy", str => { + if (this.Options.lazy) return `Promise<${str}>`; + else return str; + }); Handlebars.registerHelper({ eq: function(v1, v2) { return v1 === v2; @@ -263,4 +270,5 @@ export interface EngineOptions { convertCaseFile: "pascal" | "param" | "camel" | "none"; convertCaseEntity: "pascal" | "camel" | "none"; convertCaseProperty: "pascal" | "camel" | "none"; + lazy: boolean; } diff --git a/src/drivers/MssqlDriver.ts b/src/drivers/MssqlDriver.ts index 11d6c85..705b59f 100644 --- a/src/drivers/MssqlDriver.ts +++ b/src/drivers/MssqlDriver.ts @@ -284,8 +284,8 @@ ORDER BY ForeignKeyColumn: string; TableReferenced: string; ForeignKeyColumnReferenced: string; - onDelete: "RESTRICT" | "CASCADE" | "SET NULL" | "NO_ACTION"; - onUpdate: "RESTRICT" | "CASCADE" | "SET NULL" | "NO_ACTION"; + onDelete: "RESTRICT" | "CASCADE" | "SET_NULL" | "NO_ACTION"; + onUpdate: "RESTRICT" | "CASCADE" | "SET_NULL" | "NO_ACTION"; object_id: number; }[] = (await request.query(`select parentTable.name as TableWithForeignKey, @@ -323,10 +323,30 @@ order by rels = {}; rels.ownerColumnsNames = []; rels.referencedColumnsNames = []; - rels.actionOnDelete = - resp.onDelete == "NO_ACTION" ? null : resp.onDelete; - rels.actionOnUpdate = - resp.onUpdate == "NO_ACTION" ? null : resp.onUpdate; + switch (resp.onDelete) { + case "NO_ACTION": + rels.actionOnDelete = null; + break; + case "SET_NULL": + rels.actionOnDelete = "SET NULL"; + break; + default: + rels.actionOnDelete = resp.onDelete; + + break; + } + switch (resp.onUpdate) { + case "NO_ACTION": + rels.actionOnUpdate = null; + break; + case "SET_NULL": + rels.actionOnUpdate = "SET NULL"; + break; + default: + rels.actionOnUpdate = resp.onUpdate; + + break; + } rels.object_id = resp.object_id; rels.ownerTable = resp.TableWithForeignKey; rels.referencedTable = resp.TableReferenced; diff --git a/src/entity.mst b/src/entity.mst index 2c72658..cb702db 100644 --- a/src/entity.mst +++ b/src/entity.mst @@ -26,8 +26,8 @@ import {Index,Entity, PrimaryColumn, Column, OneToOne, OneToMany, ManyToOne, Man {{/relations}}{{#relations}} @{{relationType}}(type=>{{toEntityName relatedTable}}, {{toPropertyName ../name}}=>{{toPropertyName ../name}}.{{#if isOwner}}{{toPropertyName ownerColumn}},{ {{#../isPrimary}}primary:true,{{/../isPrimary}}{{^../is_nullable}} nullable:false,{{/../is_nullable}}{{#actionOnDelete}}onDelete: '{{.}}'{{/actionOnDelete}} }{{else}}{{toPropertyName relatedColumn}}{{#actionOnDelete}},{ onDelete: '{{.}}' }{{/actionOnDelete}}{{/if}}){{#isOwner}} {{#if isManyToMany}}@JoinTable(){{else}}@JoinColumn({ name:'{{ ../name}}'}){{/if}}{{/isOwner}} - {{#if (or isOneToMany isManyToMany)}}{{toPropertyName ../name}}:{{toEntityName relatedTable}}[]; - {{else}}{{toPropertyName ../name}}:{{toEntityName relatedTable}}; + {{#if (or isOneToMany isManyToMany)}}{{toPropertyName ../name}}:{{toLazy (concat (toEntityName relatedTable) "[]")}}; + {{else}}{{toPropertyName ../name}}:{{toLazy (toEntityName relatedTable)}}; {{/if}}{{/relations}} {{/Columns}} } diff --git a/src/index.ts b/src/index.ts index a2a0804..4c6573f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -78,6 +78,11 @@ var argv = Yargs.usage( describe: "Convert property names to specified case", choices: ["pascal", "camel", "none"], default: "none" + }) + .option("lazy", { + describe: "Generate lazy relations", + boolean: true, + default: false }).argv; var driver: AbstractDriver; @@ -124,7 +129,8 @@ let engine = new Engine(driver, { noConfigs: argv.noConfig, convertCaseFile: argv.cf, convertCaseEntity: argv.ce, - convertCaseProperty: argv.cp + convertCaseProperty: argv.cp, + lazy: argv.ssl }); console.log( diff --git a/test/integration/examples/sample18-lazy-relations/entity/Author.ts b/test/integration/examples/sample18-lazy-relations/entity/Author.ts new file mode 100644 index 0000000..0d3d178 --- /dev/null +++ b/test/integration/examples/sample18-lazy-relations/entity/Author.ts @@ -0,0 +1,25 @@ +import { Column, Entity, Index, PrimaryGeneratedColumn, OneToMany } from "typeorm" +import {Post} from "./Post"; + +@Entity("Author") +export class Author { + + @PrimaryGeneratedColumn() + id: number; + + @Column() + name: string; + + @OneToMany(type => Post, post => post.author, { + // cascade: true + }) + posts: Promise; + + // /** + // * You can add this helper method. + // */ + // asPromise() { + // return Promise.resolve(this); + // } + +} diff --git a/test/integration/examples/sample18-lazy-relations/entity/Category.ts b/test/integration/examples/sample18-lazy-relations/entity/Category.ts new file mode 100644 index 0000000..42ce1f2 --- /dev/null +++ b/test/integration/examples/sample18-lazy-relations/entity/Category.ts @@ -0,0 +1,16 @@ +import { Column, Entity, Index, PrimaryGeneratedColumn, VersionColumn, ManyToMany } from "typeorm" +import {Post} from "./Post"; + +@Entity("Category") +export class Category { + + @PrimaryGeneratedColumn() + id: number; + + @Column() + name: string; + + @ManyToMany(type => Post, post => post.Category) + Post: Promise; + +} diff --git a/test/integration/examples/sample18-lazy-relations/entity/Post.ts b/test/integration/examples/sample18-lazy-relations/entity/Post.ts new file mode 100644 index 0000000..303ff25 --- /dev/null +++ b/test/integration/examples/sample18-lazy-relations/entity/Post.ts @@ -0,0 +1,29 @@ +import { Column, Entity, Index, PrimaryGeneratedColumn, ManyToOne, ManyToMany, JoinTable } from "typeorm" +import {Author} from "./Author"; +import {Category} from "./Category"; + +@Entity("Post") +export class Post { + + @PrimaryGeneratedColumn() + id: number; + + @Column() + title: string; + + @Column() + text: string; + + @ManyToOne(type => Author, author => author.posts, { + // cascade: ["insert"], + onDelete: "SET NULL" + }) + author: Promise; + + @ManyToMany(type => Category, category => category.Post, { + // cascade: true + }) + @JoinTable() + Category: Promise; + +} diff --git a/test/integration/integration.test.ts b/test/integration/integration.test.ts index fe7c24f..e763af2 100644 --- a/test/integration/integration.test.ts +++ b/test/integration/integration.test.ts @@ -65,7 +65,9 @@ describe("TypeOrm examples", async function () { engine = {} break; } - + if (folder=='sample18-lazy-relations') { + engine.Options.lazy=true; + } let result = await engine.createModelFromDatabase() diff --git a/test/utils/EntityFileToJson.ts b/test/utils/EntityFileToJson.ts index 4fae927..1f17050 100644 --- a/test/utils/EntityFileToJson.ts +++ b/test/utils/EntityFileToJson.ts @@ -301,7 +301,12 @@ export class EntityFileToJson { } else if (trimmedLine.split(':').length - 1 > 0) { retVal.columns[retVal.columns.length - 1].columnName = trimmedLine.split(':')[0].trim(); //TODO:Should check if null only column is nullable? - retVal.columns[retVal.columns.length - 1].columnTypes = trimmedLine.split(':')[1].split(';')[0].trim().split('|').map(function (x) { + let colTypes=trimmedLine.split(':')[1].split(';')[0].trim(); + if (colTypes.startsWith('Promise<')) { + colTypes=colTypes.substring(8,colTypes.length-1) + retVal.columns[retVal.columns.length - 1].columnOptions.isLazy=true; + } + retVal.columns[retVal.columns.length - 1].columnTypes = colTypes.split('|').map(function (x) { if (x == 'any') { x = 'string' //for json columns } diff --git a/test/utils/GeneralTestUtils.ts b/test/utils/GeneralTestUtils.ts index 191a07f..01b9924 100644 --- a/test/utils/GeneralTestUtils.ts +++ b/test/utils/GeneralTestUtils.ts @@ -63,6 +63,7 @@ export async function createMSSQLModels(filesOrgPath: string, resultsPath: strin convertCaseEntity: 'none', convertCaseFile: 'none', convertCaseProperty: 'none', + lazy:false }); conn = await createConnection(connOpt) @@ -126,6 +127,7 @@ export async function createPostgresModels(filesOrgPath: string, resultsPath: st convertCaseEntity: 'none', convertCaseFile: 'none', convertCaseProperty: 'none', + lazy:false }); conn = await createConnection(connOpt) @@ -182,6 +184,7 @@ export async function createMysqlModels(filesOrgPath: string, resultsPath: strin convertCaseEntity: 'none', convertCaseFile: 'none', convertCaseProperty: 'none', + lazy:false }); @@ -231,6 +234,7 @@ export async function createMariaDBModels(filesOrgPath: string, resultsPath: str convertCaseEntity: 'none', convertCaseFile: 'none', convertCaseProperty: 'none', + lazy:false }); @@ -282,6 +286,7 @@ export async function createOracleDBModels(filesOrgPath: string, resultsPath: st convertCaseEntity: 'none', convertCaseFile: 'none', convertCaseProperty: 'none', + lazy:false }); return engine;