diff --git a/.gitignore b/.gitignore index 4236107..66b634a 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ node_modules/ npm-debug.log ormconfig.json .vscode +.idea typings/ **/*.js **/*.js.map diff --git a/docker-compose.yml b/docker-compose.yml index cf9b21c..0b3a074 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -44,6 +44,6 @@ services: # container_name: "typeorm-mg-oracle" # ports: # - "1521:1521" - # environment: - # DB_SID: "ORCLCDB" - # SYS_PASSWORD: "Oradoc_db1" + # environment: + # DB_SID: "ORCLCDB" + # SYS_PASSWORD: "Oradoc_db1" diff --git a/package-lock.json b/package-lock.json index 1ccbcc0..ab1af3a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -424,6 +424,15 @@ "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=" }, + "camel-case": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz", + "integrity": "sha1-yjw2iKTpzzpM2nd9xNy8cTJJz3M=", + "requires": { + "no-case": "2.3.2", + "upper-case": "1.1.3" + } + }, "camelcase": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", @@ -491,6 +500,31 @@ "supports-color": "4.5.0" } }, + "change-case": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/change-case/-/change-case-3.0.1.tgz", + "integrity": "sha1-7l9a0EFa0a2egHLPSc1M+nZgpVQ=", + "requires": { + "camel-case": "3.0.0", + "constant-case": "2.0.0", + "dot-case": "2.1.1", + "header-case": "1.0.1", + "is-lower-case": "1.1.3", + "is-upper-case": "1.1.2", + "lower-case": "1.1.4", + "lower-case-first": "1.0.2", + "no-case": "2.3.2", + "param-case": "2.1.1", + "pascal-case": "2.0.1", + "path-case": "2.1.1", + "sentence-case": "2.1.1", + "snake-case": "2.1.0", + "swap-case": "1.1.2", + "title-case": "2.1.1", + "upper-case": "1.1.3", + "upper-case-first": "1.1.2" + } + }, "check-error": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", @@ -666,6 +700,15 @@ "xdg-basedir": "3.0.0" } }, + "constant-case": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/constant-case/-/constant-case-2.0.0.tgz", + "integrity": "sha1-QXV2TTidP6nI7NKRhu1gBSQ7akY=", + "requires": { + "snake-case": "2.1.0", + "upper-case": "1.1.3" + } + }, "core-js": { "version": "2.5.3", "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.3.tgz", @@ -788,6 +831,14 @@ "integrity": "sha512-MKPHZDMB0o6yHyDryUOScqZibp914ksXwAMYMTHj6KO8UeKsRYNJD3oNCKjTqZon+V488P7N/HzXF8t7ZR95ww==", "dev": true }, + "dot-case": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-2.1.1.tgz", + "integrity": "sha1-NNzzf1Co6TwrO8qLt/uRVcfaO+4=", + "requires": { + "no-case": "2.3.2" + } + }, "dot-prop": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz", @@ -1171,6 +1222,15 @@ "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", "dev": true }, + "header-case": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/header-case/-/header-case-1.0.1.tgz", + "integrity": "sha1-lTWXMZfBRLCWE81l0xfvGZY70C0=", + "requires": { + "no-case": "2.3.2", + "upper-case": "1.1.3" + } + }, "highlight.js": { "version": "9.12.0", "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.12.0.tgz", @@ -1314,6 +1374,14 @@ "is-path-inside": "1.0.1" } }, + "is-lower-case": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/is-lower-case/-/is-lower-case-1.1.3.tgz", + "integrity": "sha1-fhR75HaNxGbbO/shzGCzHmrWk5M=", + "requires": { + "lower-case": "1.1.4" + } + }, "is-npm": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-1.0.0.tgz", @@ -1382,6 +1450,14 @@ "unc-path-regex": "0.1.2" } }, + "is-upper-case": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-upper-case/-/is-upper-case-1.1.2.tgz", + "integrity": "sha1-jQsfp+eTOh5YSDYA7H2WYcuvdW8=", + "requires": { + "upper-case": "1.1.3" + } + }, "is-windows": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-0.2.0.tgz", @@ -1689,6 +1765,19 @@ "js-tokens": "3.0.2" } }, + "lower-case": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz", + "integrity": "sha1-miyr0bno4K6ZOkv31YdcOcQujqw=" + }, + "lower-case-first": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/lower-case-first/-/lower-case-first-1.0.2.tgz", + "integrity": "sha1-5dp8JvKacHO+AtUrrJmA5ZIq36E=", + "requires": { + "lower-case": "1.1.4" + } + }, "lowercase-keys": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.0.tgz", @@ -1893,6 +1982,14 @@ } } }, + "no-case": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz", + "integrity": "sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==", + "requires": { + "lower-case": "1.1.4" + } + }, "nopt": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", @@ -2057,6 +2154,14 @@ "resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-0.3.1.tgz", "integrity": "sha1-zWLmCvjX/qinBexP+ZCHHEaHHyc=" }, + "param-case": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-2.1.1.tgz", + "integrity": "sha1-35T9jPZTHs915r75oIWPvHK+Ikc=", + "requires": { + "no-case": "2.3.2" + } + }, "parent-require": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/parent-require/-/parent-require-1.0.0.tgz", @@ -2078,6 +2183,23 @@ "@types/node": "9.3.0" } }, + "pascal-case": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-2.0.1.tgz", + "integrity": "sha1-LVeNNFX2YNpl7KGO+VtODekSdh4=", + "requires": { + "camel-case": "3.0.0", + "upper-case-first": "1.1.2" + } + }, + "path-case": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/path-case/-/path-case-2.1.1.tgz", + "integrity": "sha1-lLgDfDctP+KQbkZbtF4l0ibo7qU=", + "requires": { + "no-case": "2.3.2" + } + }, "path-exists": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", @@ -2526,6 +2648,15 @@ } } }, + "sentence-case": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/sentence-case/-/sentence-case-2.1.1.tgz", + "integrity": "sha1-H24t2jnBaL+S0T+G1KkYkz9mftQ=", + "requires": { + "no-case": "2.3.2", + "upper-case-first": "1.1.2" + } + }, "set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", @@ -2590,6 +2721,14 @@ "is-fullwidth-code-point": "2.0.0" } }, + "snake-case": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-2.1.0.tgz", + "integrity": "sha1-Qb2xtz8w7GagTU4srRt2OH1NbZ8=", + "requires": { + "no-case": "2.3.2" + } + }, "sntp": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz", @@ -2742,6 +2881,15 @@ "has-flag": "2.0.0" } }, + "swap-case": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/swap-case/-/swap-case-1.1.2.tgz", + "integrity": "sha1-w5IDpFhzhfrTyFCgvRvK+ggZdOM=", + "requires": { + "lower-case": "1.1.4", + "upper-case": "1.1.3" + } + }, "tedious": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/tedious/-/tedious-2.1.5.tgz", @@ -2835,6 +2983,15 @@ "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=", "dev": true }, + "title-case": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/title-case/-/title-case-2.1.1.tgz", + "integrity": "sha1-PhJyFtpY0rxb7PE3q5Ha46fNj6o=", + "requires": { + "no-case": "2.3.2", + "upper-case": "1.1.3" + } + }, "touch": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/touch/-/touch-1.0.0.tgz", @@ -3209,6 +3366,19 @@ "xdg-basedir": "3.0.0" } }, + "upper-case": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz", + "integrity": "sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg=" + }, + "upper-case-first": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/upper-case-first/-/upper-case-first-1.1.2.tgz", + "integrity": "sha1-XXm+3P8UQZUY/S7bCgUHybaFkRU=", + "requires": { + "upper-case": "1.1.3" + } + }, "url-parse-lax": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz", diff --git a/package.json b/package.json index 1f6db16..f44c467 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "pg": "^7.4.0", "reflect-metadata": "^0.1.10", "typeorm": "^0.2.0-alpha.13", + "change-case": "^3.0.1", "typescript": "^2.6.1", "yargs": "^10.0.3", "yn": "^2.0.0" diff --git a/src/Engine.ts b/src/Engine.ts index 7f7fb72..3dbce67 100644 --- a/src/Engine.ts +++ b/src/Engine.ts @@ -4,6 +4,7 @@ import * as Handlebars from 'handlebars' import fs = require('fs'); import path = require('path') import * as TomgUtils from './Utils' +import changeCase = require("change-case"); /** * Engine */ @@ -25,6 +26,10 @@ export class Engine { } private createModelFromMetadata(databaseModel: DatabaseModel) { + Handlebars.registerHelper("curly", (open) => {return open ? "{" : "}";}); + Handlebars.registerHelper("toEntityName", str => {return this.Options.convertCase ? changeCase.pascalCase(str) : str;}); + Handlebars.registerHelper("toFileName", str => {return this.Options.convertCase ? changeCase.paramCase(str) : str;}); + Handlebars.registerHelper("toPropertyName", str => {return this.Options.convertCase ? changeCase.camelCase(str) : str;}); let templatePath = path.resolve(__dirname, '../../src/entity.mst') let template = fs.readFileSync(templatePath, 'UTF-8'); let resultPath = this.Options.resultsPath @@ -43,8 +48,20 @@ export class Engine { }); let compliedTemplate = Handlebars.compile(template, { noEscape: true }) databaseModel.entities.forEach(element => { - let resultFilePath = path.resolve(entitesPath, element.EntityName + '.ts'); - let rendered = compliedTemplate(element) + element.Imports = []; + element.Columns.forEach((column) => { + column.relations.forEach( + (relation) => { + if (element.EntityName !== relation.relatedTable) + {element.Imports.push(relation.relatedTable);} + } + ); + }); + element.Imports.filter(function (elem, index, self) { + return index === self.indexOf(elem); + }); + let resultFilePath = path.resolve(entitesPath, (this.Options.convertCase ? changeCase.paramCase(element.EntityName) : element.EntityName) + '.ts'); + let rendered =compliedTemplate(element) fs.writeFileSync(resultFilePath, rendered, { encoding: 'UTF-8', flag: 'w' }) }); } @@ -111,5 +128,6 @@ export interface EngineOptions { databaseType: string, schemaName: string, ssl: boolean, - noConfigs: boolean + noConfigs: boolean, + convertCase: boolean } diff --git a/src/drivers/PostgresDriver.ts b/src/drivers/PostgresDriver.ts index fbac97a..cfe4f33 100644 --- a/src/drivers/PostgresDriver.ts +++ b/src/drivers/PostgresDriver.ts @@ -123,6 +123,10 @@ export class PostgresDriver extends AbstractDriver { colInfo.ts_type = "Date" colInfo.sql_type = "timestamp" break; + case "timestamp with time zone": + colInfo.ts_type = "Date" + colInfo.sql_type = "timestamp" + break; case "json": colInfo.ts_type = "Object" colInfo.sql_type = "json" diff --git a/src/entity.mst b/src/entity.mst index bea2940..90ebe73 100644 --- a/src/entity.mst +++ b/src/entity.mst @@ -1,11 +1,13 @@ import {Index,Entity, PrimaryColumn, Column, OneToOne, OneToMany, ManyToOne, JoinColumn} from "typeorm"; -{{relationImports}} +{{relationImports}}{{#each UniqueImports}}import {{curly true}}{{toEntityName this}}{{curly false}} from "./{{toFileName this}}"; +{{/each}} -@Entity() + +@Entity("{{toEntityName EntityName}}") {{#Indexes}}{{^isPrimaryKey}}@Index("{{name}}",[{{#columns}}"{{name}}",{{/columns}}]{{#isUnique}},{unique:true}{{/isUnique}}) -{{/isPrimaryKey}}{{/Indexes}}export class {{EntityName}} { +{{/isPrimaryKey}}{{/Indexes}}export class {{toEntityName EntityName}} { +{{#Columns}} - {{#Columns}} {{^relations}} @Column("{{sql_type}}",{ {{#is_generated}} generated:true,{{/is_generated}}{{#is_nullable}} @@ -17,12 +19,13 @@ import {Index,Entity, PrimaryColumn, Column, OneToOne, OneToMany, ManyToOne, Joi scale:{{.}},{{/numericScale}}{{#isPrimary}} primary:{{isPrimary}},{{/isPrimary}} }) - {{name}}:{{ts_type}}; + {{toPropertyName name}}:{{ts_type}}; {{/relations}}{{#relations}} - @{{relationType}}(type=>{{relatedTable}}, {{../name}}=>{{../name}}.{{#if isOwner}}{{ownerColumn}}{{else}}{{relatedColumn}}{{/if}}){{#isOwner}} - @JoinColumn({name:'{{../name}}'}){{/isOwner}} - {{#if isOneToMany}}{{../name}}:{{relatedTable}}[]; - {{else}}{{../name}}:{{relatedTable}}; + @{{relationType}}(type=>{{toEntityName relatedTable}}, {{toPropertyName ../name}}=>{{toPropertyName ../name}}.{{#if isOwner}}{{toPropertyName ownerColumn}}{{else}}{{toPropertyName relatedColumn}}{{/if}}){{#isOwner}} + @JoinColumn({ name:'{{toPropertyName ../name}}'}){{/isOwner}} + {{#if isOneToMany}}{{toPropertyName ../name}}:{{toEntityName relatedTable}}[]; + {{else}}{{toPropertyName ../name}}:{{toEntityName relatedTable}}; {{/if}}{{/relations}} + {{"\n"}} {{/Columns}} } diff --git a/src/index.ts b/src/index.ts index ebe42e5..5a15798 100644 --- a/src/index.ts +++ b/src/index.ts @@ -61,6 +61,10 @@ var argv = Yargs describe: `Doesn't create tsconfig.json and ormconfig.json`, default: false }) + .option('c', { + alias: 'case', + describe: 'Convert snake_case tables names to PascalCase entities and snake_case columns to camelCase properties' + }) .argv; @@ -106,7 +110,8 @@ let engine = new Engine( resultsPath: argv.o, schemaName: argv.s || standardSchema, ssl: argv.ssl, - noConfigs: argv.noConfig + noConfigs: argv.noConfig, + convertCase: !!argv.c }); console.log(`[${new Date().toLocaleTimeString()}] Starting creation of model classes.`); diff --git a/src/models/DatabaseModel.ts b/src/models/DatabaseModel.ts index 411534e..d151d63 100644 --- a/src/models/DatabaseModel.ts +++ b/src/models/DatabaseModel.ts @@ -6,10 +6,12 @@ export class DatabaseModel { cascadeUpdate: boolean, cascadeRemove: boolean, } + +//TODO:check if unused relationImports(): any { let that = this; return function (text, render) { - if ('l' != render(text)) return `import {${render(text)}} from "./${render(text)}"` + if ('l' != render(text)) return `import {{curly true}}{{toEntityName ${render(text)}}}{{curly false}} from "./{{ ${render( "toFileName"+ text)}}}` else return ''; } } diff --git a/src/models/EntityInfo.ts b/src/models/EntityInfo.ts index f3fe230..12d638b 100644 --- a/src/models/EntityInfo.ts +++ b/src/models/EntityInfo.ts @@ -1,10 +1,14 @@ import { ColumnInfo } from './ColumnInfo' +import * as Handlebars from 'handlebars' + /** * EntityInfo */ export class EntityInfo { EntityName: string; Columns: ColumnInfo[]; + Imports: string[]; + UniqueImports: string[]; Indexes: IndexInfo[]; relationImports(): any { @@ -18,13 +22,9 @@ export class EntityInfo { } ) }); - imports.filter(function (elem, index, self) { + this.UniqueImports=imports.filter(function (elem, index, self) { return index == self.indexOf(elem); - }).forEach((imp) => { - returnString += `import {${imp}} from './${imp}'\n` }) - - return returnString; } } diff --git a/test/utils/GeneralTestUtils.ts b/test/utils/GeneralTestUtils.ts index fb00ae1..26e1fa6 100644 --- a/test/utils/GeneralTestUtils.ts +++ b/test/utils/GeneralTestUtils.ts @@ -50,7 +50,8 @@ export async function createMSSQLModels(filesOrgPath: string, resultsPath: strin resultsPath: resultsPath, schemaName: 'dbo', ssl: yn(process.env.MSSQL_SSL), - noConfigs: false + noConfigs: false, + convertCase:false }); @@ -94,7 +95,8 @@ export async function createPostgresModels(filesOrgPath: string, resultsPath: st resultsPath: resultsPath, schemaName: 'public', ssl: yn(process.env.POSTGRES_SSL), - noConfigs: false + noConfigs: false, + convertCase: false }); @@ -139,7 +141,8 @@ export async function createMysqlModels(filesOrgPath: string, resultsPath: strin resultsPath: resultsPath, schemaName: 'ignored', ssl: yn(process.env.MYSQL_SSL), - noConfigs: false + noConfigs: false, + convertCase: false }); @@ -184,7 +187,8 @@ export async function createMariaDBModels(filesOrgPath: string, resultsPath: str resultsPath: resultsPath, schemaName: 'ignored', ssl: yn(process.env.MARIADB_SSL), - noConfigs: false + noConfigs: false, + convertCase: false }); @@ -231,7 +235,8 @@ export async function createOracleDBModels(filesOrgPath: string, resultsPath: st resultsPath: resultsPath, schemaName: String(process.env.ORACLE_Username), ssl: yn(process.env.ORACLE_SSL), - noConfigs: false + noConfigs: false, + convertCase: false });