diff --git a/.npmignore b/.npmignore index 26bb543..01817ea 100644 --- a/.npmignore +++ b/.npmignore @@ -23,3 +23,4 @@ codecov.yml tsconfig.json typings.json dist/test/ +src/tslint.json diff --git a/.travis.yml b/.travis.yml index 732b4bd..367ae48 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,6 +3,7 @@ node_js: - 10 - 8 - 6 +cache: npm sudo: required services: - docker @@ -32,6 +33,7 @@ before_install: - if [ -z "$DOCKER_USERNAME" ]; then echo "DOCKER_USERNAME is unset"; else echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin; fi - if [ -z "$DOCKER_USERNAME" ]; then mv docker-compose-without-login.yml docker-compose.yml; fi - if [ -z "$DOCKER_USERNAME" ]; then export ORACLE_Skip=1; fi +- docker-compose pull --parallel --ignore-pull-failures - docker-compose up -d - npm install -g npm@5 - npm install -g greenkeeper-lockfile@1 @@ -45,7 +47,6 @@ before_script: - npm link typescript - tsc - sleep 180 -- docker logs typeorm-mg-postgres after_script: - greenkeeper-lockfile-upload diff --git a/package-lock.json b/package-lock.json index b03a94e..c293e85 100644 --- a/package-lock.json +++ b/package-lock.json @@ -338,6 +338,59 @@ "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.7.0.tgz", "integrity": "sha512-32NDda82rhwD9/JBCCkB+MRYDp0oSvlo2IL6rQWA10PQi7tDUM3eqMSltXmY+Oyl/7N3P3qNtAlv7X0d9bI28w==" }, + "babel-code-frame": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", + "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", + "dev": true, + "requires": { + "chalk": "^1.1.3", + "esutils": "^2.0.2", + "js-tokens": "^3.0.2" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, "babel-runtime": { "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", @@ -2147,6 +2200,12 @@ "resolved": "https://registry.npmjs.org/js-string-escape/-/js-string-escape-1.0.1.tgz", "integrity": "sha1-4mJbrbwNZ8dTPp7cEGjFh65BN+8=" }, + "js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", + "dev": true + }, "js-yaml": { "version": "3.10.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.10.0.tgz", @@ -3510,6 +3569,12 @@ "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=" }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "dev": true + }, "path-to-regexp": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.7.0.tgz", @@ -4889,6 +4954,58 @@ "integrity": "sha512-AVP5Xol3WivEr7hnssHDsaM+lVrVXWUvd1cfXTRkTj80b//6g2wIFEH6hZG0muGZRnHGrfttpdzRk3YlBkWjKw==", "dev": true }, + "tslint": { + "version": "5.11.0", + "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.11.0.tgz", + "integrity": "sha1-mPMMAurjzecAYgHkwzywi0hYHu0=", + "dev": true, + "requires": { + "babel-code-frame": "^6.22.0", + "builtin-modules": "^1.1.1", + "chalk": "^2.3.0", + "commander": "^2.12.1", + "diff": "^3.2.0", + "glob": "^7.1.1", + "js-yaml": "^3.7.0", + "minimatch": "^3.0.4", + "resolve": "^1.3.2", + "semver": "^5.3.0", + "tslib": "^1.8.0", + "tsutils": "^2.27.2" + }, + "dependencies": { + "resolve": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz", + "integrity": "sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA==", + "dev": true, + "requires": { + "path-parse": "^1.0.5" + } + }, + "semver": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", + "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==", + "dev": true + } + } + }, + "tslint-config-prettier": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/tslint-config-prettier/-/tslint-config-prettier-1.17.0.tgz", + "integrity": "sha512-NKWNkThwqE4Snn4Cm6SZB7lV5RMDDFsBwz6fWUkTxOKGjMx8ycOHnjIbhn7dZd5XmssW3CwqUjlANR6EhP9YQw==", + "dev": true + }, + "tsutils": { + "version": "2.29.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", + "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + } + }, "tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", diff --git a/package.json b/package.json index 6ebc14d..aef97b4 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "compile": "npm run clean && tsc", "precommit": "npm run prettier && git update-index --again", "test": "istanbul cover ./node_modules/mocha/bin/_mocha dist/test/**/*.test.js -- -R spec", - "posttest": "remap-istanbul -i ./coverage/coverage.json -o ./coverage/coverage-remapped.json && codecov --file=./coverage/coverage-remapped.json ", + "posttest": "remap-istanbul -i ./coverage/coverage.json -o ./coverage/lcov.info -t lcovonly && remap-istanbul -i ./coverage/coverage.json -o ./coverage/coverage.json && codecov --file=./coverage/coverage.json ", "clean": "rimraf dist coverage output", "prettier": "prettier --write ./src/*.ts ./src/**/*.ts", "prepack": "npm run compile" @@ -65,6 +65,8 @@ "remap-istanbul": "^0.12.0", "rimraf": "^2.6.2", "sinon": "^6.0.0", - "sinon-chai": "^3.0.0" + "sinon-chai": "^3.0.0", + "tslint": "^5.11.0", + "tslint-config-prettier": "^1.17.0" } } diff --git a/src/AbstractNamingStrategy.ts b/src/AbstractNamingStrategy.ts index c0ea4bf..b739cd2 100644 --- a/src/AbstractNamingStrategy.ts +++ b/src/AbstractNamingStrategy.ts @@ -1,14 +1,14 @@ -import { RelationInfo } from "./models/RelationInfo"; import { DatabaseModel } from "./models/DatabaseModel"; +import { RelationInfo } from "./models/RelationInfo"; export abstract class AbstractNamingStrategy { - abstract relationName( + public abstract relationName( columnName: string, relation: RelationInfo, dbModel: DatabaseModel ): string; - abstract entityName(entityName: string): string; + public abstract entityName(entityName: string): string; - abstract columnName(columnName: string): string; + public abstract columnName(columnName: string): string; } diff --git a/src/Engine.ts b/src/Engine.ts index fd80fda..58a8d52 100644 --- a/src/Engine.ts +++ b/src/Engine.ts @@ -1,20 +1,20 @@ +import changeCase = require("change-case"); +import fs = require("fs"); +import * as Handlebars from "handlebars"; +import path = require("path"); +import { AbstractNamingStrategy } from "./AbstractNamingStrategy"; import { AbstractDriver } from "./drivers/AbstractDriver"; import { DatabaseModel } from "./models/DatabaseModel"; -import * as Handlebars from "handlebars"; -import fs = require("fs"); -import path = require("path"); import * as TomgUtils from "./Utils"; -import changeCase = require("change-case"); -import { AbstractNamingStrategy } from "./AbstractNamingStrategy"; export class Engine { constructor( private driver: AbstractDriver, - public Options: EngineOptions + public Options: IEngineOptions ) {} public async createModelFromDatabase(): Promise { - let dbModel = await this.getEntitiesInfo( + const dbModel = await this.getEntitiesInfo( this.Options.databaseName, this.Options.host, this.Options.port, @@ -60,18 +60,24 @@ export class Engine { } private createModelFromMetadata(databaseModel: DatabaseModel) { this.createHandlebarsHelpers(); - let templatePath = path.resolve(__dirname, "../../src/entity.mst"); - let template = fs.readFileSync(templatePath, "UTF-8"); - let resultPath = this.Options.resultsPath; - if (!fs.existsSync(resultPath)) fs.mkdirSync(resultPath); + const templatePath = path.resolve(__dirname, "../../src/entity.mst"); + const template = fs.readFileSync(templatePath, "UTF-8"); + const resultPath = this.Options.resultsPath; + if (!fs.existsSync(resultPath)) { + fs.mkdirSync(resultPath); + } let entitesPath = resultPath; if (!this.Options.noConfigs) { this.createTsConfigFile(resultPath); this.createTypeOrmConfig(resultPath); entitesPath = path.resolve(resultPath, "./entities"); - if (!fs.existsSync(entitesPath)) fs.mkdirSync(entitesPath); + if (!fs.existsSync(entitesPath)) { + fs.mkdirSync(entitesPath); + } } - let compliedTemplate = Handlebars.compile(template, { noEscape: true }); + const compliedTemplate = Handlebars.compile(template, { + noEscape: true + }); databaseModel.entities.forEach(element => { element.Imports = []; element.Columns.forEach(column => { @@ -82,7 +88,7 @@ export class Engine { }); }); element.GenerateConstructor = this.Options.constructor; - element.Imports.filter(function(elem, index, self) { + element.Imports.filter((elem, index, self) => { return index === self.indexOf(elem); }); let casedFileName = ""; @@ -100,11 +106,11 @@ export class Engine { casedFileName = element.EntityName; break; } - let resultFilePath = path.resolve( + const resultFilePath = path.resolve( entitesPath, casedFileName + ".ts" ); - let rendered = compliedTemplate(element); + const rendered = compliedTemplate(element); fs.writeFileSync(resultFilePath, rendered, { encoding: "UTF-8", flag: "w" @@ -112,9 +118,7 @@ export class Engine { }); } private createHandlebarsHelpers() { - Handlebars.registerHelper("curly", open => { - return open ? "{" : "}"; - }); + Handlebars.registerHelper("curly", open => (open ? "{" : "}")); Handlebars.registerHelper("toEntityName", str => { let retStr = ""; switch (this.Options.convertCaseEntity) { @@ -173,42 +177,27 @@ export class Engine { } return retStr; }); - Handlebars.registerHelper("toLowerCase", str => { - return str.toLowerCase(); - }); + Handlebars.registerHelper("toLowerCase", str => str.toLowerCase()); Handlebars.registerHelper("toLazy", str => { - if (this.Options.lazy) return `Promise<${str}>`; - else return str; + if (this.Options.lazy) { + return `Promise<${str}>`; + } else { + return str; + } }); 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; - } + and: (v1, v2) => v1 && v2, + eq: (v1, v2) => v1 === v2, + gt: (v1, v2) => v1 > v2, + gte: (v1, v2) => v1 >= v2, + lt: (v1, v2) => v1 < v2, + lte: (v1, v2) => v1 <= v2, + ne: (v1, v2) => v1 !== v2, + or: (v1, v2) => v1 || v2 }); } - //TODO:Move to mustache template file + // TODO:Move to mustache template file private createTsConfigFile(resultPath) { fs.writeFileSync( path.resolve(resultPath, "tsconfig.json"), @@ -225,7 +214,7 @@ export class Engine { ); } private createTypeOrmConfig(resultPath) { - if (this.Options.schemaName == "") { + if (this.Options.schemaName === "") { fs.writeFileSync( path.resolve(resultPath, "ormconfig.json"), `[ @@ -269,7 +258,7 @@ export class Engine { } } } -export interface EngineOptions { +export interface IEngineOptions { host: string; port: number; databaseName: string; diff --git a/src/NamingStrategy.ts b/src/NamingStrategy.ts index 1cad9cb..698f5a6 100644 --- a/src/NamingStrategy.ts +++ b/src/NamingStrategy.ts @@ -1,20 +1,17 @@ import { AbstractNamingStrategy } from "./AbstractNamingStrategy"; -import { RelationInfo } from "./models/RelationInfo"; import { DatabaseModel } from "./models/DatabaseModel"; +import { RelationInfo } from "./models/RelationInfo"; export class NamingStrategy extends AbstractNamingStrategy { - relationName( + public relationName( columnOldName: string, relation: RelationInfo, dbModel: DatabaseModel ): string { - let isRelationToMany = relation.isOneToMany || relation.isManyToMany; - let ownerEntity = dbModel.entities.filter(v => { - return v.EntityName == relation.ownerTable; - })[0]; - let referencedEntity = dbModel.entities.filter(v => { - return v.EntityName == relation.relatedTable; - })[0]; + const isRelationToMany = relation.isOneToMany || relation.isManyToMany; + const ownerEntity = dbModel.entities.find( + v => v.EntityName === relation.ownerTable + )!; let columnName = columnOldName[0].toLowerCase() + @@ -28,19 +25,19 @@ export class NamingStrategy extends AbstractNamingStrategy { columnName.toLowerCase().lastIndexOf("id") ); } - if (!isNaN(parseInt(columnName[columnName.length - 1]))) { + if (!isNaN(parseInt(columnName[columnName.length - 1], 10))) { columnName = columnName.substring(0, columnName.length - 1); } - if (!isNaN(parseInt(columnName[columnName.length - 1]))) { + if (!isNaN(parseInt(columnName[columnName.length - 1], 10))) { columnName = columnName.substring(0, columnName.length - 1); } columnName += isRelationToMany ? "s" : ""; if ( - relation.relationType != "ManyToMany" && - columnOldName != columnName + relation.relationType !== "ManyToMany" && + columnOldName !== columnName ) { - if (ownerEntity.Columns.some(v => v.tsName == columnName)) { + if (ownerEntity.Columns.some(v => v.tsName === columnName)) { columnName = columnName + "_"; for (let i = 2; i <= ownerEntity.Columns.length; i++) { columnName = @@ -51,11 +48,12 @@ export class NamingStrategy extends AbstractNamingStrategy { if ( ownerEntity.Columns.every( v => - v.tsName != columnName || - columnName == columnOldName + v.tsName !== columnName || + columnName === columnOldName ) - ) + ) { break; + } } } } @@ -63,11 +61,11 @@ export class NamingStrategy extends AbstractNamingStrategy { return columnName; } - entityName(entityName: string): string { + public entityName(entityName: string): string { return entityName; } - columnName(columnName: string): string { + public columnName(columnName: string): string { return columnName; } } diff --git a/src/Utils.ts b/src/Utils.ts index d6ba713..d62d204 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -9,13 +9,16 @@ export function LogError( console.error(`${packageVersion()} node@${process.version}`); console.error( `If you think this is a bug please open an issue including this log on ${ - (packagejson).bugs.url + (packagejson as any).bugs.url }` ); - if (isABug && !errObject) errObject = new Error().stack; - if (!!errObject) console.error(errObject); - // process.abort(); + if (isABug && !errObject) { + errObject = new Error().stack; + } + if (!!errObject) { + console.error(errObject); + } } export function packageVersion() { - return `${(packagejson).name}@${(packagejson).version}`; + return `${(packagejson as any).name}@${(packagejson as any).version}`; } diff --git a/src/drivers/AbstractDriver.ts b/src/drivers/AbstractDriver.ts index c72895e..1557341 100644 --- a/src/drivers/AbstractDriver.ts +++ b/src/drivers/AbstractDriver.ts @@ -1,129 +1,24 @@ -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 { - WithWidthColumnType, + WithLengthColumnType, WithPrecisionColumnType, - WithLengthColumnType + WithWidthColumnType } from "typeorm/driver/types/ColumnTypes"; import { AbstractNamingStrategy } from "../AbstractNamingStrategy"; +import { ColumnInfo } from "../models/ColumnInfo"; +import { DatabaseModel } from "../models/DatabaseModel"; +import { EntityInfo } from "../models/EntityInfo"; +import { RelationInfo } from "../models/RelationInfo"; +import * as TomgUtils from "../Utils"; export abstract class AbstractDriver { - changeColumnNames(dbModel: DatabaseModel) { - dbModel.entities.forEach(entity => { - entity.Columns.forEach(column => { - let newName = this.namingStrategy.columnName(column.tsName); - entity.Indexes.forEach(index => { - index.columns - .filter(column2 => { - return column2.name == column.tsName; - }) - .forEach(column2 => { - column2.name = newName; - }); - }); - dbModel.entities.forEach(entity2 => { - entity2.Columns.forEach(column2 => { - column2.relations - .filter(relation => { - return ( - relation.relatedTable == - entity.EntityName && - relation.relatedColumn == column.tsName - ); - }) - .map(v => { - v.relatedColumn = newName; - }); - column2.relations - .filter(relation => { - return ( - relation.relatedTable == - entity.EntityName && - relation.ownerColumn == column.tsName - ); - }) - .map(v => { - v.ownerColumn = newName; - }); - }); - }); - - column.tsName = newName; - }); - }); - } - changeEntityNames(dbModel: DatabaseModel) { - dbModel.entities.forEach(entity => { - let newName = this.namingStrategy.entityName(entity.EntityName); - dbModel.entities.forEach(entity2 => { - entity2.Columns.forEach(column => { - column.relations.forEach(relation => { - if (relation.ownerTable == entity.EntityName) - relation.ownerTable = newName; - if (relation.relatedTable == entity.EntityName) - relation.relatedTable = newName; - }); - }); - }); - entity.EntityName = newName; - }); - } - changeRelationNames(dbModel: DatabaseModel) { - dbModel.entities.forEach(entity => { - entity.Columns.forEach(column => { - column.relations.forEach(relation => { - if (true || !relation.isOwner) { - let newName = this.namingStrategy.relationName( - column.tsName, - relation, - dbModel - ); - dbModel.entities.forEach(entity2 => { - entity2.Columns.forEach(column2 => { - column2.relations.forEach(relation2 => { - if ( - relation2.relatedTable == - entity.EntityName && - relation2.ownerColumn == column.tsName - ) { - relation2.ownerColumn = newName; - } - if ( - relation2.relatedTable == - entity.EntityName && - relation2.relatedColumn == column.tsName - ) { - relation2.relatedColumn = newName; - } - if (relation.isOwner) { - entity.Indexes.forEach(ind => { - ind.columns.forEach(col => { - if (col.name == column.tsName) { - col.name = newName; - } - }); - }); - } - }); - }); - }); - column.tsName = newName; - } - }); - }); - }); - } - ColumnTypesWithWidth: WithWidthColumnType[] = [ + public ColumnTypesWithWidth: WithWidthColumnType[] = [ "tinyint", "smallint", "mediumint", "int", "bigint" ]; - ColumnTypesWithPrecision: WithPrecisionColumnType[] = [ + public ColumnTypesWithPrecision: WithPrecisionColumnType[] = [ "float", "double", "dec", @@ -143,7 +38,7 @@ export abstract class AbstractDriver { "timestamp with time zone", "timestamp with local time zone" ]; - ColumnTypesWithLength: WithLengthColumnType[] = [ + public ColumnTypesWithLength: WithLengthColumnType[] = [ "character varying", "varying character", "nvarchar", @@ -158,42 +53,149 @@ export abstract class AbstractDriver { "binary", "varbinary" ]; - namingStrategy: AbstractNamingStrategy; - generateRelationsIds: boolean; + public namingStrategy: AbstractNamingStrategy; + public generateRelationsIds: boolean; - FindManyToManyRelations(dbModel: DatabaseModel) { - let manyToManyEntities = dbModel.entities.filter(entity => { - return ( + public abstract GetAllTablesQuery: ( + schema: string + ) => Promise< + Array<{ + TABLE_SCHEMA: string; + TABLE_NAME: string; + }> + >; + public changeColumnNames(dbModel: DatabaseModel) { + dbModel.entities.forEach(entity => { + entity.Columns.forEach(column => { + const newName = this.namingStrategy.columnName(column.tsName); + entity.Indexes.forEach(index => { + index.columns + .filter(column2 => column2.name === column.tsName) + .forEach(column2 => (column2.name = newName)); + }); + dbModel.entities.forEach(entity2 => { + entity2.Columns.forEach(column2 => { + column2.relations + .filter( + relation => + relation.relatedTable === + entity.EntityName && + relation.relatedColumn === column.tsName + ) + .map(v => (v.relatedColumn = newName)); + column2.relations + .filter( + relation => + relation.relatedTable === + entity.EntityName && + relation.ownerColumn === column.tsName + ) + .map(v => (v.ownerColumn = newName)); + }); + }); + + column.tsName = newName; + }); + }); + } + public changeEntityNames(dbModel: DatabaseModel) { + dbModel.entities.forEach(entity => { + const newName = this.namingStrategy.entityName(entity.EntityName); + dbModel.entities.forEach(entity2 => { + entity2.Columns.forEach(column => { + column.relations.forEach(relation => { + if (relation.ownerTable === entity.EntityName) { + relation.ownerTable = newName; + } + if (relation.relatedTable === entity.EntityName) { + relation.relatedTable = newName; + } + }); + }); + }); + entity.EntityName = newName; + }); + } + public changeRelationNames(dbModel: DatabaseModel) { + dbModel.entities.forEach(entity => { + entity.Columns.forEach(column => { + column.relations.forEach(relation => { + const newName = this.namingStrategy.relationName( + column.tsName, + relation, + dbModel + ); + dbModel.entities.forEach(entity2 => { + entity2.Columns.forEach(column2 => { + column2.relations.forEach(relation2 => { + if ( + relation2.relatedTable === + entity.EntityName && + relation2.ownerColumn === column.tsName + ) { + relation2.ownerColumn = newName; + } + if ( + relation2.relatedTable === + entity.EntityName && + relation2.relatedColumn === column.tsName + ) { + relation2.relatedColumn = newName; + } + if (relation.isOwner) { + entity.Indexes.forEach(ind => { + ind.columns + .filter( + col => + col.name === column.tsName + ) + .forEach( + col => (col.name = newName) + ); + }); + } + }); + }); + }); + column.tsName = newName; + }); + }); + }); + } + + public FindManyToManyRelations(dbModel: DatabaseModel) { + const manyToManyEntities = dbModel.entities.filter( + entity => entity.Columns.filter(column => { return ( - column.relations.length == 1 && + column.relations.length === 1 && !column.relations[0].isOneToMany && column.relations[0].isOwner ); - }).length == entity.Columns.length - ); - }); + }).length === entity.Columns.length + ); manyToManyEntities.map(entity => { let relations: RelationInfo[] = []; - relations = entity.Columns.reduce((prev: RelationInfo[], curr) => { - return prev.concat(curr.relations); - }, relations); - let namesOfRelatedTables = relations + relations = entity.Columns.reduce( + (prev: RelationInfo[], curr) => prev.concat(curr.relations), + relations + ); + const namesOfRelatedTables = relations .map(v => v.relatedTable) - .filter((v, i, s) => s.indexOf(v) == i); - if (namesOfRelatedTables.length == 2) { - let relatedTable1 = dbModel.entities.filter( - v => v.EntityName == namesOfRelatedTables[0] - )[0]; + .filter((v, i, s) => s.indexOf(v) === i); + if (namesOfRelatedTables.length === 2) { + const relatedTable1 = dbModel.entities.find( + v => v.EntityName === namesOfRelatedTables[0] + )!; relatedTable1.Columns = relatedTable1.Columns.filter( v => !v.tsName .toLowerCase() .startsWith(entity.EntityName.toLowerCase()) ); - let relatedTable2 = dbModel.entities.filter( - v => v.EntityName == namesOfRelatedTables[1] - )[0]; + const relatedTable2 = dbModel.entities.find( + v => v.EntityName === namesOfRelatedTables[1] + )!; relatedTable2.Columns = relatedTable2.Columns.filter( v => !v.tsName @@ -201,13 +203,13 @@ export abstract class AbstractDriver { .startsWith(entity.EntityName.toLowerCase()) ); dbModel.entities = dbModel.entities.filter(ent => { - return ent.EntityName != entity.EntityName; + return ent.EntityName !== entity.EntityName; }); - let column1 = new ColumnInfo(); + const column1 = new ColumnInfo(); column1.tsName = namesOfRelatedTables[1]; - let col1Rel = new RelationInfo(); + const col1Rel = new RelationInfo(); col1Rel.relatedTable = namesOfRelatedTables[1]; col1Rel.relatedColumn = namesOfRelatedTables[1]; @@ -218,10 +220,10 @@ export abstract class AbstractDriver { column1.relations.push(col1Rel); relatedTable1.Columns.push(column1); - let column2 = new ColumnInfo(); + const column2 = new ColumnInfo(); column2.tsName = namesOfRelatedTables[0]; - let col2Rel = new RelationInfo(); + const col2Rel = new RelationInfo(); col2Rel.relatedTable = namesOfRelatedTables[0]; col2Rel.relatedColumn = namesOfRelatedTables[1]; @@ -232,7 +234,7 @@ export abstract class AbstractDriver { } }); } - async GetDataFromServer( + public async GetDataFromServer( database: string, server: string, port: number, @@ -244,10 +246,10 @@ export abstract class AbstractDriver { relationIds: boolean ): Promise { this.generateRelationsIds = relationIds; - let dbModel = {}; + const dbModel = {} as DatabaseModel; this.namingStrategy = namingStrategy; await this.ConnectToServer(database, server, port, user, password, ssl); - let sqlEscapedSchema = "'" + schema.split(",").join("','") + "'"; + const sqlEscapedSchema = "'" + schema.split(",").join("','") + "'"; dbModel.entities = await this.GetAllTables(sqlEscapedSchema); await this.GetCoulmnsFromEntity(dbModel.entities, sqlEscapedSchema); await this.GetIndexesFromEntity(dbModel.entities, sqlEscapedSchema); @@ -262,13 +264,7 @@ export abstract class AbstractDriver { return dbModel; } - private ApplyNamingStrategy(dbModel: DatabaseModel) { - this.changeRelationNames(dbModel); - this.changeEntityNames(dbModel); - this.changeColumnNames(dbModel); - } - - abstract async ConnectToServer( + public abstract async ConnectToServer( database: string, server: string, port: number, @@ -277,37 +273,28 @@ export abstract class AbstractDriver { ssl: boolean ); - abstract GetAllTablesQuery: ( - schema: string - ) => Promise< - { - TABLE_SCHEMA: string; - TABLE_NAME: string; - }[] - >; - - async GetAllTables(schema: string): Promise { - let response = await this.GetAllTablesQuery(schema); - let ret: EntityInfo[] = []; + public async GetAllTables(schema: string): Promise { + const response = await this.GetAllTablesQuery(schema); + const ret: EntityInfo[] = [] as EntityInfo[]; response.forEach(val => { - let ent: EntityInfo = new EntityInfo(); + const ent: EntityInfo = new EntityInfo(); ent.EntityName = val.TABLE_NAME; ent.Schema = val.TABLE_SCHEMA; - ent.Columns = []; - ent.Indexes = []; + ent.Columns = [] as ColumnInfo[]; + ent.Indexes = [] as IndexInfo[]; ret.push(ent); }); return ret; } - GetRelationsFromRelationTempInfo( - relationsTemp: RelationTempInfo[], + public GetRelationsFromRelationTempInfo( + relationsTemp: IRelationTempInfo[], entities: EntityInfo[] ) { relationsTemp.forEach(relationTmp => { - let ownerEntity = entities.find(entitity => { - return entitity.EntityName == relationTmp.ownerTable; - }); + const ownerEntity = entities.find( + entitity => entitity.EntityName === relationTmp.ownerTable + ); if (!ownerEntity) { TomgUtils.LogError( `Relation between tables ${relationTmp.ownerTable} and ${ @@ -316,9 +303,9 @@ export abstract class AbstractDriver { ); return; } - let referencedEntity = entities.find(entitity => { - return entitity.EntityName == relationTmp.referencedTable; - }); + const referencedEntity = entities.find( + entitity => entitity.EntityName === relationTmp.referencedTable + ); if (!referencedEntity) { TomgUtils.LogError( `Relation between tables ${relationTmp.ownerTable} and ${ @@ -332,12 +319,11 @@ export abstract class AbstractDriver { relationColumnIndex < relationTmp.ownerColumnsNames.length; relationColumnIndex++ ) { - let ownerColumn = ownerEntity.Columns.find(column => { - return ( - column.tsName == + const ownerColumn = ownerEntity.Columns.find( + column => + column.tsName === relationTmp.ownerColumnsNames[relationColumnIndex] - ); - }); + ); if (!ownerColumn) { TomgUtils.LogError( `Relation between tables ${ @@ -350,12 +336,11 @@ export abstract class AbstractDriver { ); return; } - let relatedColumn = referencedEntity.Columns.find(column => { - return ( - column.tsName == + const relatedColumn = referencedEntity.Columns.find( + column => + column.tsName === relationTmp.referencedColumnsNames[relationColumnIndex] - ); - }); + ); if (!relatedColumn) { TomgUtils.LogError( `Relation between tables ${ @@ -370,17 +355,16 @@ export abstract class AbstractDriver { } let isOneToMany: boolean; isOneToMany = false; - let index = ownerEntity.Indexes.find(index => { - return ( - index.isUnique && - index.columns.some(col => { - return col.name == ownerColumn!.tsName; - }) - ); - }); + const index = ownerEntity.Indexes.find( + ind => + ind.isUnique && + ind.columns.some( + col => col.name === ownerColumn!.tsName + ) + ); isOneToMany = !index; - let ownerRelation = new RelationInfo(); + const ownerRelation = new RelationInfo(); ownerRelation.actionOnDelete = relationTmp.actionOnDelete; ownerRelation.actionOnUpdate = relationTmp.actionOnUpdate; ownerRelation.isOwner = true; @@ -394,7 +378,7 @@ export abstract class AbstractDriver { let columnName = ownerEntity.EntityName; if ( - referencedEntity.Columns.some(v => v.tsName == columnName) + referencedEntity.Columns.some(v => v.tsName === columnName) ) { columnName = columnName + "_"; for (let i = 2; i <= referencedEntity.Columns.length; i++) { @@ -405,19 +389,20 @@ export abstract class AbstractDriver { ) + i.toString(); if ( referencedEntity.Columns.every( - v => v.tsName != columnName + v => v.tsName !== columnName ) - ) + ) { break; + } } } ownerRelation.ownerColumn = columnName; ownerColumn.relations.push(ownerRelation); if (isOneToMany) { - let col = new ColumnInfo(); + const col = new ColumnInfo(); col.tsName = columnName; - let referencedRelation = new RelationInfo(); + const referencedRelation = new RelationInfo(); col.relations.push(referencedRelation); referencedRelation.actionOnDelete = relationTmp.actionOnDelete; @@ -431,9 +416,9 @@ export abstract class AbstractDriver { referencedRelation.relationType = "OneToMany"; referencedEntity.Columns.push(col); } else { - let col = new ColumnInfo(); + const col = new ColumnInfo(); col.tsName = columnName; - let referencedRelation = new RelationInfo(); + const referencedRelation = new RelationInfo(); col.relations.push(referencedRelation); referencedRelation.actionOnDelete = relationTmp.actionOnDelete; @@ -451,31 +436,29 @@ export abstract class AbstractDriver { }); return entities; } - abstract async GetCoulmnsFromEntity( + public abstract async GetCoulmnsFromEntity( entities: EntityInfo[], schema: string ): Promise; - abstract async GetIndexesFromEntity( + public abstract async GetIndexesFromEntity( entities: EntityInfo[], schema: string ): Promise; - abstract async GetRelations( + public abstract async GetRelations( entities: EntityInfo[], schema: string ): Promise; - FindPrimaryColumnsFromIndexes(dbModel: DatabaseModel) { + public FindPrimaryColumnsFromIndexes(dbModel: DatabaseModel) { dbModel.entities.forEach(entity => { - let primaryIndex = entity.Indexes.find(v => v.isPrimaryKey); - entity.Columns.forEach(col => { - if ( + const primaryIndex = entity.Indexes.find(v => v.isPrimaryKey); + entity.Columns.filter( + col => primaryIndex && primaryIndex.columns.some( - cIndex => cIndex.name == col.tsName + cIndex => cIndex.name === col.tsName ) - ) - col.isPrimary = true; - }); + ).forEach(col => (col.isPrimary = true)); if ( !entity.Columns.some(v => { return v.isPrimary; @@ -489,9 +472,15 @@ export abstract class AbstractDriver { } }); } - abstract async DisconnectFromServer(); - abstract async CreateDB(dbName: string); - abstract async DropDB(dbName: string); - abstract async UseDB(dbName: string); - abstract async CheckIfDBExists(dbName: string): Promise; + public abstract async DisconnectFromServer(); + public abstract async CreateDB(dbName: string); + public abstract async DropDB(dbName: string); + public abstract async UseDB(dbName: string); + public abstract async CheckIfDBExists(dbName: string): Promise; + + private ApplyNamingStrategy(dbModel: DatabaseModel) { + this.changeRelationNames(dbModel); + this.changeEntityNames(dbModel); + this.changeColumnNames(dbModel); + } } diff --git a/src/drivers/MariaDbDriver.ts b/src/drivers/MariaDbDriver.ts index e0633a7..93c587a 100644 --- a/src/drivers/MariaDbDriver.ts +++ b/src/drivers/MariaDbDriver.ts @@ -1,5 +1,5 @@ import { MysqlDriver } from "./MysqlDriver"; export class MariaDbDriver extends MysqlDriver { - readonly EngineName: string = "MariaDb"; + public readonly EngineName: string = "MariaDb"; } diff --git a/src/drivers/MssqlDriver.ts b/src/drivers/MssqlDriver.ts index ac64a13..3b9b4fe 100644 --- a/src/drivers/MssqlDriver.ts +++ b/src/drivers/MssqlDriver.ts @@ -1,27 +1,28 @@ -import { AbstractDriver } from "./AbstractDriver"; import * as MSSQL from "mssql"; import { ColumnInfo } from "../models/ColumnInfo"; import { EntityInfo } from "../models/EntityInfo"; import * as TomgUtils from "../Utils"; +import { AbstractDriver } from "./AbstractDriver"; export class MssqlDriver extends AbstractDriver { - GetAllTablesQuery = async (schema: string) => { - let request = new MSSQL.Request(this.Connection); - let response: { + private Connection: MSSQL.ConnectionPool; + public GetAllTablesQuery = async (schema: string) => { + const request = new MSSQL.Request(this.Connection); + const response: Array<{ TABLE_SCHEMA: string; TABLE_NAME: string; - }[] = (await request.query( + }> = (await request.query( `SELECT TABLE_SCHEMA,TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE='BASE TABLE' and TABLE_SCHEMA in (${schema})` )).recordset; return response; }; - async GetCoulmnsFromEntity( + public async GetCoulmnsFromEntity( entities: EntityInfo[], schema: string ): Promise { - let request = new MSSQL.Request(this.Connection); - let response: { + const request = new MSSQL.Request(this.Connection); + const response: Array<{ TABLE_NAME: string; COLUMN_NAME: string; COLUMN_DEFAULT: string; @@ -32,7 +33,7 @@ export class MssqlDriver extends AbstractDriver { NUMERIC_SCALE: number; IsIdentity: number; IsUnique: number; - }[] = (await request.query(`SELECT TABLE_NAME,COLUMN_NAME,COLUMN_DEFAULT,IS_NULLABLE, + }> = (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, (SELECT count(*) @@ -49,116 +50,116 @@ export class MssqlDriver extends AbstractDriver { entities.forEach(ent => { response .filter(filterVal => { - return filterVal.TABLE_NAME == ent.EntityName; + return filterVal.TABLE_NAME === ent.EntityName; }) .forEach(resp => { - let colInfo: ColumnInfo = new ColumnInfo(); + const colInfo: ColumnInfo = new ColumnInfo(); colInfo.tsName = resp.COLUMN_NAME; colInfo.sqlName = resp.COLUMN_NAME; - colInfo.is_nullable = resp.IS_NULLABLE == "YES"; - colInfo.is_generated = resp.IsIdentity == 1; - colInfo.is_unique = resp.IsUnique == 1; + colInfo.isNullable = resp.IS_NULLABLE === "YES"; + colInfo.isGenerated = resp.IsIdentity === 1; + colInfo.isUnique = resp.IsUnique === 1; colInfo.default = resp.COLUMN_DEFAULT; - colInfo.sql_type = resp.DATA_TYPE; + colInfo.sqlType = resp.DATA_TYPE; switch (resp.DATA_TYPE) { case "bigint": - colInfo.ts_type = "string"; + colInfo.tsType = "string"; break; case "bit": - colInfo.ts_type = "boolean"; + colInfo.tsType = "boolean"; break; case "decimal": - colInfo.ts_type = "number"; + colInfo.tsType = "number"; break; case "int": - colInfo.ts_type = "number"; + colInfo.tsType = "number"; break; case "money": - colInfo.ts_type = "number"; + colInfo.tsType = "number"; break; case "numeric": - colInfo.ts_type = "number"; + colInfo.tsType = "number"; break; case "smallint": - colInfo.ts_type = "number"; + colInfo.tsType = "number"; break; case "smallmoney": - colInfo.ts_type = "number"; + colInfo.tsType = "number"; break; case "tinyint": - colInfo.ts_type = "number"; + colInfo.tsType = "number"; break; case "float": - colInfo.ts_type = "number"; + colInfo.tsType = "number"; break; case "real": - colInfo.ts_type = "number"; + colInfo.tsType = "number"; break; case "date": - colInfo.ts_type = "Date"; + colInfo.tsType = "Date"; break; case "datetime2": - colInfo.ts_type = "Date"; + colInfo.tsType = "Date"; break; case "datetime": - colInfo.ts_type = "Date"; + colInfo.tsType = "Date"; break; case "datetimeoffset": - colInfo.ts_type = "Date"; + colInfo.tsType = "Date"; break; case "smalldatetime": - colInfo.ts_type = "Date"; + colInfo.tsType = "Date"; break; case "time": - colInfo.ts_type = "Date"; + colInfo.tsType = "Date"; break; case "char": - colInfo.ts_type = "string"; + colInfo.tsType = "string"; break; case "text": - colInfo.ts_type = "string"; + colInfo.tsType = "string"; break; case "varchar": - colInfo.ts_type = "string"; + colInfo.tsType = "string"; break; case "nchar": - colInfo.ts_type = "string"; + colInfo.tsType = "string"; break; case "ntext": - colInfo.ts_type = "string"; + colInfo.tsType = "string"; break; case "nvarchar": - colInfo.ts_type = "string"; + colInfo.tsType = "string"; break; case "binary": - colInfo.ts_type = "Buffer"; + colInfo.tsType = "Buffer"; break; case "image": - colInfo.ts_type = "Buffer"; + colInfo.tsType = "Buffer"; break; case "varbinary": - colInfo.ts_type = "Buffer"; + colInfo.tsType = "Buffer"; break; case "hierarchyid": - colInfo.ts_type = "string"; + colInfo.tsType = "string"; break; case "sql_variant": - colInfo.ts_type = "string"; + colInfo.tsType = "string"; break; case "timestamp": - colInfo.ts_type = "Date"; + colInfo.tsType = "Date"; break; case "uniqueidentifier": - colInfo.ts_type = "string"; + colInfo.tsType = "string"; break; case "xml": - colInfo.ts_type = "string"; + colInfo.tsType = "string"; break; case "geometry": - colInfo.ts_type = "string"; + colInfo.tsType = "string"; break; case "geography": - colInfo.ts_type = "string"; + colInfo.tsType = "string"; break; default: TomgUtils.LogError( @@ -173,7 +174,7 @@ export class MssqlDriver extends AbstractDriver { if ( this.ColumnTypesWithPrecision.some( - v => v == colInfo.sql_type + v => v === colInfo.sqlType ) ) { colInfo.numericPrecision = resp.NUMERIC_PRECISION; @@ -181,7 +182,7 @@ export class MssqlDriver extends AbstractDriver { } if ( this.ColumnTypesWithLength.some( - v => v == colInfo.sql_type + v => v === colInfo.sqlType ) ) { colInfo.lenght = @@ -190,23 +191,25 @@ export class MssqlDriver extends AbstractDriver { : null; } - if (colInfo.sql_type) ent.Columns.push(colInfo); + if (colInfo.sqlType) { + ent.Columns.push(colInfo); + } }); }); return entities; } - async GetIndexesFromEntity( + public async GetIndexesFromEntity( entities: EntityInfo[], schema: string ): Promise { - let request = new MSSQL.Request(this.Connection); - let response: { + const request = new MSSQL.Request(this.Connection); + const response: Array<{ TableName: string; IndexName: string; ColumnName: string; - is_unique: number; - is_primary_key: number; - }[] = (await request.query(`SELECT + is_unique: boolean; + is_primary_key: boolean; + }> = (await request.query(`SELECT TableName = t.name, IndexName = ind.name, ColumnName = col.name, @@ -228,25 +231,23 @@ ORDER BY t.name, ind.name, ind.index_id, ic.key_ordinal;`)).recordset; entities.forEach(ent => { response - .filter(filterVal => { - return filterVal.TableName == ent.EntityName; - }) + .filter(filterVal => filterVal.TableName === ent.EntityName) .forEach(resp => { - let indexInfo: IndexInfo = {}; - let indexColumnInfo: IndexColumnInfo = {}; + let indexInfo: IndexInfo = {} as IndexInfo; + const indexColumnInfo: IndexColumnInfo = {} as IndexColumnInfo; if ( ent.Indexes.filter(filterVal => { - return filterVal.name == resp.IndexName; + return filterVal.name === resp.IndexName; }).length > 0 ) { indexInfo = ent.Indexes.filter(filterVal => { - return filterVal.name == resp.IndexName; + return filterVal.name === resp.IndexName; })[0]; } else { - indexInfo.columns = []; + indexInfo.columns = [] as IndexColumnInfo[]; indexInfo.name = resp.IndexName; - indexInfo.isUnique = resp.is_unique == 1; - indexInfo.isPrimaryKey = resp.is_primary_key == 1; + indexInfo.isUnique = resp.is_unique; + indexInfo.isPrimaryKey = resp.is_primary_key; ent.Indexes.push(indexInfo); } indexColumnInfo.name = resp.ColumnName; @@ -256,12 +257,12 @@ ORDER BY return entities; } - async GetRelations( + public async GetRelations( entities: EntityInfo[], schema: string ): Promise { - let request = new MSSQL.Request(this.Connection); - let response: { + const request = new MSSQL.Request(this.Connection); + const response: Array<{ TableWithForeignKey: string; FK_PartNo: number; ForeignKeyColumn: string; @@ -270,7 +271,7 @@ ORDER BY onDelete: "RESTRICT" | "CASCADE" | "SET_NULL" | "NO_ACTION"; onUpdate: "RESTRICT" | "CASCADE" | "SET_NULL" | "NO_ACTION"; object_id: number; - }[] = (await request.query(`select + }> = (await request.query(`select parentTable.name as TableWithForeignKey, fkc.constraint_column_id as FK_PartNo, parentColumn.name as ForeignKeyColumn, @@ -297,13 +298,13 @@ where fk.is_disabled=0 and fk.is_ms_shipped=0 and parentSchema.name in (${schema}) order by TableWithForeignKey, FK_PartNo`)).recordset; - let relationsTemp: RelationTempInfo[] = []; + const relationsTemp: IRelationTempInfo[] = [] as IRelationTempInfo[]; response.forEach(resp => { - let rels = relationsTemp.find(val => { - return val.object_id == resp.object_id; - }); - if (rels == undefined) { - rels = {}; + let rels = relationsTemp.find( + val => val.object_id === resp.object_id + ); + if (rels === undefined) { + rels = {} as IRelationTempInfo; rels.ownerColumnsNames = []; rels.referencedColumnsNames = []; switch (resp.onDelete) { @@ -315,7 +316,6 @@ order by break; default: rels.actionOnDelete = resp.onDelete; - break; } switch (resp.onUpdate) { @@ -327,7 +327,6 @@ order by break; default: rels.actionOnUpdate = resp.onUpdate; - break; } rels.object_id = resp.object_id; @@ -344,12 +343,12 @@ order by ); return entities; } - async DisconnectFromServer() { - if (this.Connection) await this.Connection.close(); + public async DisconnectFromServer() { + if (this.Connection) { + await this.Connection.close(); + } } - - private Connection: MSSQL.ConnectionPool; - async ConnectToServer( + public async ConnectToServer( database: string, server: string, port: number, @@ -357,19 +356,19 @@ order by password: string, ssl: boolean ) { - let config: MSSQL.config = { - database: database, - server: server, - port: port, - user: user, - password: password, + const config: MSSQL.config = { + database, options: { - encrypt: ssl, - appName: "typeorm-model-generator" - } + appName: "typeorm-model-generator", + encrypt: ssl + }, + password, + port, + server, + user }; - let promise = new Promise((resolve, reject) => { + const promise = new Promise((resolve, reject) => { this.Connection = new MSSQL.ConnectionPool(config, err => { if (!err) { resolve(true); @@ -386,21 +385,21 @@ order by await promise; } - async CreateDB(dbName: string) { - let request = new MSSQL.Request(this.Connection); + public async CreateDB(dbName: string) { + const request = new MSSQL.Request(this.Connection); await request.query(`CREATE DATABASE ${dbName}; `); } - async UseDB(dbName: string) { - let request = new MSSQL.Request(this.Connection); + public async UseDB(dbName: string) { + const request = new MSSQL.Request(this.Connection); await request.query(`USE ${dbName}; `); } - async DropDB(dbName: string) { - let request = new MSSQL.Request(this.Connection); + public async DropDB(dbName: string) { + const request = new MSSQL.Request(this.Connection); await request.query(`DROP DATABASE ${dbName}; `); } - async CheckIfDBExists(dbName: string): Promise { - let request = new MSSQL.Request(this.Connection); - let resp = await request.query( + public async CheckIfDBExists(dbName: string): Promise { + const request = new MSSQL.Request(this.Connection); + const resp = await request.query( `SELECT name FROM master.sys.databases WHERE name = N'${dbName}' ` ); return resp.recordset.length > 0; diff --git a/src/drivers/MysqlDriver.ts b/src/drivers/MysqlDriver.ts index 6777c78..ddc3313 100644 --- a/src/drivers/MysqlDriver.ts +++ b/src/drivers/MysqlDriver.ts @@ -1,14 +1,16 @@ -import { AbstractDriver } from "./AbstractDriver"; import * as MYSQL from "mysql"; import { ColumnInfo } from "../models/ColumnInfo"; import { EntityInfo } from "../models/EntityInfo"; import * as TomgUtils from "../Utils"; +import { AbstractDriver } from "./AbstractDriver"; export class MysqlDriver extends AbstractDriver { - readonly EngineName: string = "MySQL"; + public readonly EngineName: string = "MySQL"; - GetAllTablesQuery = async (schema: string) => { - let response = this.ExecQuery<{ + private Connection: MYSQL.Connection; + + public GetAllTablesQuery = async (schema: string) => { + const response = this.ExecQuery<{ TABLE_SCHEMA: string; TABLE_NAME: string; }>(`SELECT TABLE_SCHEMA, TABLE_NAME @@ -18,11 +20,11 @@ export class MysqlDriver extends AbstractDriver { return response; }; - async GetCoulmnsFromEntity( + public async GetCoulmnsFromEntity( entities: EntityInfo[], schema: string ): Promise { - let response = await this.ExecQuery<{ + const response = await this.ExecQuery<{ TABLE_NAME: string; COLUMN_NAME: string; COLUMN_DEFAULT: string; @@ -40,128 +42,126 @@ export class MysqlDriver extends AbstractDriver { FROM INFORMATION_SCHEMA.COLUMNS where TABLE_SCHEMA like DATABASE()`); entities.forEach(ent => { response - .filter(filterVal => { - return filterVal.TABLE_NAME == ent.EntityName; - }) + .filter(filterVal => filterVal.TABLE_NAME === ent.EntityName) .forEach(resp => { - let colInfo: ColumnInfo = new ColumnInfo(); + const colInfo: ColumnInfo = new ColumnInfo(); colInfo.tsName = resp.COLUMN_NAME; colInfo.sqlName = resp.COLUMN_NAME; - colInfo.is_nullable = resp.IS_NULLABLE == "YES"; - colInfo.is_generated = resp.IsIdentity == 1; - colInfo.is_unique = resp.column_key == "UNI"; + colInfo.isNullable = resp.IS_NULLABLE === "YES"; + colInfo.isGenerated = resp.IsIdentity === 1; + colInfo.isUnique = resp.column_key === "UNI"; colInfo.default = resp.COLUMN_DEFAULT; - colInfo.sql_type = resp.DATA_TYPE; + colInfo.sqlType = resp.DATA_TYPE; switch (resp.DATA_TYPE) { case "int": - colInfo.ts_type = "number"; + colInfo.tsType = "number"; break; case "tinyint": - if (resp.column_type == "tinyint(1)") { + if (resp.column_type === "tinyint(1)") { colInfo.width = 1; - colInfo.ts_type = "boolean"; + colInfo.tsType = "boolean"; } else { - colInfo.ts_type = "number"; + colInfo.tsType = "number"; } break; case "smallint": - colInfo.ts_type = "number"; + colInfo.tsType = "number"; break; case "mediumint": - colInfo.ts_type = "number"; + colInfo.tsType = "number"; break; case "bigint": - colInfo.ts_type = "string"; + colInfo.tsType = "string"; break; case "float": - colInfo.ts_type = "number"; + colInfo.tsType = "number"; break; case "double": - colInfo.ts_type = "number"; + colInfo.tsType = "number"; break; case "decimal": - colInfo.ts_type = "string"; + colInfo.tsType = "string"; break; case "date": - colInfo.ts_type = "string"; + colInfo.tsType = "string"; break; case "datetime": - colInfo.ts_type = "Date"; + colInfo.tsType = "Date"; break; case "timestamp": - colInfo.ts_type = "Date"; + colInfo.tsType = "Date"; break; case "time": - colInfo.ts_type = "string"; + colInfo.tsType = "string"; break; case "year": - colInfo.ts_type = "number"; + colInfo.tsType = "number"; break; case "char": - colInfo.ts_type = "string"; + colInfo.tsType = "string"; break; case "varchar": - colInfo.ts_type = "string"; + colInfo.tsType = "string"; break; case "blob": - colInfo.ts_type = "Buffer"; + colInfo.tsType = "Buffer"; break; case "text": - colInfo.ts_type = "string"; + colInfo.tsType = "string"; break; case "tinyblob": - colInfo.ts_type = "Buffer"; + colInfo.tsType = "Buffer"; break; case "tinytext": - colInfo.ts_type = "string"; + colInfo.tsType = "string"; break; case "mediumblob": - colInfo.ts_type = "Buffer"; + colInfo.tsType = "Buffer"; break; case "mediumtext": - colInfo.ts_type = "string"; + colInfo.tsType = "string"; break; case "longblob": - colInfo.ts_type = "Buffer"; + colInfo.tsType = "Buffer"; break; case "longtext": - colInfo.ts_type = "string"; + colInfo.tsType = "string"; break; case "enum": - colInfo.ts_type = "string"; + colInfo.tsType = "string"; colInfo.enumOptions = resp.column_type .substring(5, resp.column_type.length - 1) .replace(/\'/gi, '"'); break; case "json": - colInfo.ts_type = "Object"; + colInfo.tsType = "Object"; break; case "binary": - colInfo.ts_type = "Buffer"; + colInfo.tsType = "Buffer"; break; case "geometry": - colInfo.ts_type = "string"; + colInfo.tsType = "string"; break; case "point": - colInfo.ts_type = "string"; + colInfo.tsType = "string"; break; case "linestring": - colInfo.ts_type = "string"; + colInfo.tsType = "string"; break; case "polygon": - colInfo.ts_type = "string"; + colInfo.tsType = "string"; break; case "multipoint": - colInfo.ts_type = "string"; + colInfo.tsType = "string"; break; case "multilinestring": - colInfo.ts_type = "string"; + colInfo.tsType = "string"; break; case "multipolygon": - colInfo.ts_type = "string"; + colInfo.tsType = "string"; break; case "geometrycollection": - colInfo.ts_type = "string"; + colInfo.tsType = "string"; break; default: TomgUtils.LogError( @@ -175,7 +175,7 @@ export class MysqlDriver extends AbstractDriver { } if ( this.ColumnTypesWithPrecision.some( - v => v == colInfo.sql_type + v => v === colInfo.sqlType ) ) { colInfo.numericPrecision = resp.NUMERIC_PRECISION; @@ -183,7 +183,7 @@ export class MysqlDriver extends AbstractDriver { } if ( this.ColumnTypesWithLength.some( - v => v == colInfo.sql_type + v => v === colInfo.sqlType ) ) { colInfo.lenght = @@ -194,8 +194,8 @@ export class MysqlDriver extends AbstractDriver { if ( this.ColumnTypesWithWidth.some( v => - v == colInfo.sql_type && - colInfo.ts_type != "boolean" + v === colInfo.sqlType && + colInfo.tsType !== "boolean" ) ) { colInfo.width = @@ -204,16 +204,18 @@ export class MysqlDriver extends AbstractDriver { : null; } - if (colInfo.sql_type) ent.Columns.push(colInfo); + if (colInfo.sqlType) { + ent.Columns.push(colInfo); + } }); }); return entities; } - async GetIndexesFromEntity( + public async GetIndexesFromEntity( entities: EntityInfo[], schema: string ): Promise { - let response = await this.ExecQuery<{ + const response = await this.ExecQuery<{ TableName: string; IndexName: string; ColumnName: string; @@ -226,25 +228,23 @@ export class MysqlDriver extends AbstractDriver { `); entities.forEach(ent => { response - .filter(filterVal => { - return filterVal.TableName == ent.EntityName; - }) + .filter(filterVal => filterVal.TableName === ent.EntityName) .forEach(resp => { - let indexInfo: IndexInfo = {}; - let indexColumnInfo: IndexColumnInfo = {}; + let indexInfo: IndexInfo = {} as IndexInfo; + const indexColumnInfo: IndexColumnInfo = {} as IndexColumnInfo; if ( - ent.Indexes.filter(filterVal => { - return filterVal.name == resp.IndexName; - }).length > 0 + ent.Indexes.filter( + filterVal => filterVal.name === resp.IndexName + ).length > 0 ) { - indexInfo = ent.Indexes.filter(filterVal => { - return filterVal.name == resp.IndexName; - })[0]; + indexInfo = ent.Indexes.find( + filterVal => filterVal.name === resp.IndexName + )!; } else { - indexInfo.columns = []; + indexInfo.columns = [] as IndexColumnInfo[]; indexInfo.name = resp.IndexName; - indexInfo.isUnique = resp.is_unique == 1; - indexInfo.isPrimaryKey = resp.is_primary_key == 1; + indexInfo.isUnique = resp.is_unique === 1; + indexInfo.isPrimaryKey = resp.is_primary_key === 1; ent.Indexes.push(indexInfo); } indexColumnInfo.name = resp.ColumnName; @@ -254,11 +254,11 @@ export class MysqlDriver extends AbstractDriver { return entities; } - async GetRelations( + public async GetRelations( entities: EntityInfo[], schema: string ): Promise { - let response = await this.ExecQuery<{ + const response = await this.ExecQuery<{ TableWithForeignKey: string; FK_PartNo: number; ForeignKeyColumn: string; @@ -284,19 +284,19 @@ export class MysqlDriver extends AbstractDriver { TABLE_SCHEMA = SCHEMA() AND CU.REFERENCED_TABLE_NAME IS NOT NULL; `); - let relationsTemp: RelationTempInfo[] = []; + const relationsTemp: IRelationTempInfo[] = [] as IRelationTempInfo[]; response.forEach(resp => { - let rels = relationsTemp.find(val => { - return val.object_id == resp.object_id; - }); - if (rels == undefined) { - rels = {}; + let rels = relationsTemp.find( + val => val.object_id === resp.object_id + ); + if (rels === undefined) { + rels = {} as IRelationTempInfo; rels.ownerColumnsNames = []; rels.referencedColumnsNames = []; rels.actionOnDelete = - resp.onDelete == "NO_ACTION" ? null : resp.onDelete; + resp.onDelete === "NO_ACTION" ? null : resp.onDelete; rels.actionOnUpdate = - resp.onUpdate == "NO_ACTION" ? null : resp.onUpdate; + resp.onUpdate === "NO_ACTION" ? null : resp.onUpdate; rels.object_id = resp.object_id; rels.ownerTable = resp.TableWithForeignKey; rels.referencedTable = resp.TableReferenced; @@ -311,8 +311,8 @@ export class MysqlDriver extends AbstractDriver { ); return entities; } - async DisconnectFromServer() { - let promise = new Promise((resolve, reject) => { + public async DisconnectFromServer() { + const promise = new Promise((resolve, reject) => { this.Connection.end(err => { if (!err) { resolve(true); @@ -326,11 +326,11 @@ export class MysqlDriver extends AbstractDriver { } }); }); - if (this.Connection) await promise; + if (this.Connection) { + await promise; + } } - - private Connection: MYSQL.Connection; - async ConnectToServer( + public async ConnectToServer( database: string, server: string, port: number, @@ -341,26 +341,26 @@ export class MysqlDriver extends AbstractDriver { let config: MYSQL.ConnectionConfig; if (ssl) { config = { - database: database, + database, host: server, - port: port, - user: user, - password: password, + password, + port, ssl: { rejectUnauthorized: false - } + }, + user }; } else { config = { - database: database, + database, host: server, - port: port, - user: user, - password: password + password, + port, + user }; } - let promise = new Promise((resolve, reject) => { + const promise = new Promise((resolve, reject) => { this.Connection = MYSQL.createConnection(config); this.Connection.connect(err => { @@ -379,28 +379,28 @@ export class MysqlDriver extends AbstractDriver { await promise; } - async CreateDB(dbName: string) { + public async CreateDB(dbName: string) { await this.ExecQuery(`CREATE DATABASE ${dbName}; `); } - async UseDB(dbName: string) { + public async UseDB(dbName: string) { await this.ExecQuery(`USE ${dbName}; `); } - async DropDB(dbName: string) { + public async DropDB(dbName: string) { await this.ExecQuery(`DROP DATABASE ${dbName}; `); } - async CheckIfDBExists(dbName: string): Promise { - let resp = await this.ExecQuery( + public async CheckIfDBExists(dbName: string): Promise { + const resp = await this.ExecQuery( `SHOW DATABASES LIKE '${dbName}' ` ); return resp.length > 0; } - async ExecQuery(sql: string): Promise> { - let ret: Array = []; - let query = this.Connection.query(sql); - let stream = query.stream({}); - let promise = new Promise((resolve, reject) => { + public async ExecQuery(sql: string): Promise { + const ret: T[] = []; + const query = this.Connection.query(sql); + const stream = query.stream({}); + const promise = new Promise((resolve, reject) => { stream.on("data", chunk => { - ret.push((chunk)); + ret.push((chunk as any) as T); }); stream.on("error", err => reject(err)); stream.on("end", () => resolve(true)); diff --git a/src/drivers/OracleDriver.ts b/src/drivers/OracleDriver.ts index 751967c..bf9d143 100644 --- a/src/drivers/OracleDriver.ts +++ b/src/drivers/OracleDriver.ts @@ -1,10 +1,12 @@ -import { AbstractDriver } from "./AbstractDriver"; import { ColumnInfo } from "../models/ColumnInfo"; import { EntityInfo } from "../models/EntityInfo"; import * as TomgUtils from "../Utils"; +import { AbstractDriver } from "./AbstractDriver"; export class OracleDriver extends AbstractDriver { - Oracle: any; + public Oracle: any; + + private Connection: any /*Oracle.IConnection*/; constructor() { super(); try { @@ -16,21 +18,21 @@ export class OracleDriver extends AbstractDriver { } } - GetAllTablesQuery = async (schema: string) => { - let response: { + public GetAllTablesQuery = async (schema: string) => { + const response: Array<{ TABLE_SCHEMA: string; TABLE_NAME: string; - }[] = (await this.Connection.execute( + }> = (await this.Connection.execute( ` SELECT NULL AS TABLE_SCHEMA, TABLE_NAME FROM all_tables WHERE owner = (select user from dual)` )).rows!; return response; }; - async GetCoulmnsFromEntity( + public async GetCoulmnsFromEntity( entities: EntityInfo[], schema: string ): Promise { - let response: { + const response: Array<{ TABLE_NAME: string; COLUMN_NAME: string; DATA_DEFAULT: string; @@ -40,8 +42,8 @@ export class OracleDriver extends AbstractDriver { DATA_PRECISION: number; DATA_SCALE: number; IDENTITY_COLUMN: string; - IS_UNIQUE: Number; - }[] = (await this.Connection + IS_UNIQUE: number; + }> = (await this.Connection .execute(`SELECT utc.TABLE_NAME, utc.COLUMN_NAME, DATA_DEFAULT, NULLABLE, DATA_TYPE, DATA_LENGTH, DATA_PRECISION, DATA_SCALE, IDENTITY_COLUMN, (select count(*) from USER_CONS_COLUMNS ucc @@ -51,109 +53,107 @@ export class OracleDriver extends AbstractDriver { entities.forEach(ent => { response - .filter(filterVal => { - return filterVal.TABLE_NAME == ent.EntityName; - }) + .filter(filterVal => filterVal.TABLE_NAME === ent.EntityName) .forEach(resp => { - let colInfo: ColumnInfo = new ColumnInfo(); + const colInfo: ColumnInfo = new ColumnInfo(); colInfo.tsName = resp.COLUMN_NAME; colInfo.sqlName = resp.COLUMN_NAME; - colInfo.is_nullable = resp.NULLABLE == "Y"; - colInfo.is_generated = resp.IDENTITY_COLUMN == "YES"; + colInfo.isNullable = resp.NULLABLE === "Y"; + colInfo.isGenerated = resp.IDENTITY_COLUMN === "YES"; colInfo.default = !resp.DATA_DEFAULT || resp.DATA_DEFAULT.includes('"') ? null : resp.DATA_DEFAULT; - colInfo.is_unique = resp.IS_UNIQUE > 0; + colInfo.isUnique = resp.IS_UNIQUE > 0; resp.DATA_TYPE = resp.DATA_TYPE.replace(/\([0-9]+\)/g, ""); - colInfo.sql_type = resp.DATA_TYPE.toLowerCase(); + colInfo.sqlType = resp.DATA_TYPE.toLowerCase(); switch (resp.DATA_TYPE.toLowerCase()) { case "char": - colInfo.ts_type = "string"; + colInfo.tsType = "string"; break; case "nchar": - colInfo.ts_type = "string"; + colInfo.tsType = "string"; break; case "nvarchar2": - colInfo.ts_type = "string"; + colInfo.tsType = "string"; break; case "varchar2": - colInfo.ts_type = "string"; + colInfo.tsType = "string"; break; case "long": - colInfo.ts_type = "string"; + colInfo.tsType = "string"; break; case "raw": - colInfo.ts_type = "Buffer"; + colInfo.tsType = "Buffer"; break; case "long raw": - colInfo.ts_type = "Buffer"; + colInfo.tsType = "Buffer"; break; case "number": - colInfo.ts_type = "number"; + colInfo.tsType = "number"; break; case "numeric": - colInfo.ts_type = "number"; + colInfo.tsType = "number"; break; case "float": - colInfo.ts_type = "number"; + colInfo.tsType = "number"; break; case "dec": - colInfo.ts_type = "number"; + colInfo.tsType = "number"; break; case "decimal": - colInfo.ts_type = "number"; + colInfo.tsType = "number"; break; case "integer": - colInfo.ts_type = "number"; + colInfo.tsType = "number"; break; case "int": - colInfo.ts_type = "number"; + colInfo.tsType = "number"; break; case "smallint": - colInfo.ts_type = "number"; + colInfo.tsType = "number"; break; case "real": - colInfo.ts_type = "number"; + colInfo.tsType = "number"; break; case "double precision": - colInfo.ts_type = "number"; + colInfo.tsType = "number"; break; case "date": - colInfo.ts_type = "Date"; + colInfo.tsType = "Date"; break; case "timestamp": - colInfo.ts_type = "Date"; + colInfo.tsType = "Date"; break; case "timestamp with time zone": - colInfo.ts_type = "Date"; + colInfo.tsType = "Date"; break; case "timestamp with local time zone": - colInfo.ts_type = "Date"; + colInfo.tsType = "Date"; break; case "interval year to month": - colInfo.ts_type = "string"; + colInfo.tsType = "string"; break; case "interval day to second": - colInfo.ts_type = "string"; + colInfo.tsType = "string"; break; case "bfile": - colInfo.ts_type = "Buffer"; + colInfo.tsType = "Buffer"; break; case "blob": - colInfo.ts_type = "Buffer"; + colInfo.tsType = "Buffer"; break; case "clob": - colInfo.ts_type = "string"; + colInfo.tsType = "string"; break; case "nclob": - colInfo.ts_type = "string"; + colInfo.tsType = "string"; break; case "rowid": - colInfo.ts_type = "number"; + colInfo.tsType = "number"; break; case "urowid": - colInfo.ts_type = "number"; + colInfo.tsType = "number"; break; default: TomgUtils.LogError( @@ -163,7 +163,7 @@ export class OracleDriver extends AbstractDriver { } if ( this.ColumnTypesWithPrecision.some( - v => v == colInfo.sql_type + v => v === colInfo.sqlType ) ) { colInfo.numericPrecision = resp.DATA_PRECISION; @@ -171,29 +171,31 @@ export class OracleDriver extends AbstractDriver { } if ( this.ColumnTypesWithLength.some( - v => v == colInfo.sql_type + v => v === colInfo.sqlType ) ) { colInfo.lenght = resp.DATA_LENGTH > 0 ? resp.DATA_LENGTH : null; } - if (colInfo.sql_type) ent.Columns.push(colInfo); + if (colInfo.sqlType) { + ent.Columns.push(colInfo); + } }); }); return entities; } - async GetIndexesFromEntity( + public async GetIndexesFromEntity( entities: EntityInfo[], schema: string ): Promise { - let response: { + const response: Array<{ COLUMN_NAME: string; TABLE_NAME: string; INDEX_NAME: string; UNIQUENESS: string; ISPRIMARYKEY: number; - }[] = (await this.Connection + }> = (await this.Connection .execute(`SELECT ind.TABLE_NAME, ind.INDEX_NAME, col.COLUMN_NAME,ind.UNIQUENESS, CASE WHEN uc.CONSTRAINT_NAME IS NULL THEN 0 ELSE 1 END ISPRIMARYKEY FROM USER_INDEXES ind JOIN USER_IND_COLUMNS col ON ind.INDEX_NAME=col.INDEX_NAME @@ -202,25 +204,23 @@ export class OracleDriver extends AbstractDriver { entities.forEach(ent => { response - .filter(filterVal => { - return filterVal.TABLE_NAME == ent.EntityName; - }) + .filter(filterVal => filterVal.TABLE_NAME === ent.EntityName) .forEach(resp => { - let indexInfo: IndexInfo = {}; - let indexColumnInfo: IndexColumnInfo = {}; + let indexInfo: IndexInfo = {} as IndexInfo; + const indexColumnInfo: IndexColumnInfo = {} as IndexColumnInfo; if ( - ent.Indexes.filter(filterVal => { - return filterVal.name == resp.INDEX_NAME; - }).length > 0 + ent.Indexes.filter( + filterVal => filterVal.name === resp.INDEX_NAME + ).length > 0 ) { - indexInfo = ent.Indexes.filter(filterVal => { - return filterVal.name == resp.INDEX_NAME; - })[0]; + indexInfo = ent.Indexes.find( + filterVal => filterVal.name === resp.INDEX_NAME + )!; } else { - indexInfo.columns = []; + indexInfo.columns = [] as IndexColumnInfo[]; indexInfo.name = resp.INDEX_NAME; - indexInfo.isUnique = resp.UNIQUENESS == "UNIQUE"; - indexInfo.isPrimaryKey = resp.ISPRIMARYKEY == 1; + indexInfo.isUnique = resp.UNIQUENESS === "UNIQUE"; + indexInfo.isPrimaryKey = resp.ISPRIMARYKEY === 1; ent.Indexes.push(indexInfo); } indexColumnInfo.name = resp.COLUMN_NAME; @@ -230,11 +230,11 @@ export class OracleDriver extends AbstractDriver { return entities; } - async GetRelations( + public async GetRelations( entities: EntityInfo[], schema: string ): Promise { - let response: { + const response: Array<{ OWNER_TABLE_NAME: string; OWNER_POSITION: string; OWNER_COLUMN_NAME: string; @@ -242,7 +242,7 @@ export class OracleDriver extends AbstractDriver { CHILD_COLUMN_NAME: string; DELETE_RULE: "RESTRICT" | "CASCADE" | "SET NULL" | "NO ACTION"; CONSTRAINT_NAME: string; - }[] = (await this.Connection + }> = (await this.Connection .execute(`select owner.TABLE_NAME OWNER_TABLE_NAME,ownCol.POSITION OWNER_POSITION,ownCol.COLUMN_NAME OWNER_COLUMN_NAME, child.TABLE_NAME CHILD_TABLE_NAME ,childCol.COLUMN_NAME CHILD_COLUMN_NAME, owner.DELETE_RULE, @@ -254,17 +254,17 @@ export class OracleDriver extends AbstractDriver { ORDER BY OWNER_TABLE_NAME ASC, owner.CONSTRAINT_NAME ASC, OWNER_POSITION ASC`)) .rows!; - let relationsTemp: RelationTempInfo[] = []; + const relationsTemp: IRelationTempInfo[] = [] as IRelationTempInfo[]; response.forEach(resp => { - let rels = relationsTemp.find(val => { - return val.object_id == resp.CONSTRAINT_NAME; - }); - if (rels == undefined) { - rels = {}; + let rels = relationsTemp.find( + val => val.object_id === resp.CONSTRAINT_NAME + ); + if (rels === undefined) { + rels = {} as IRelationTempInfo; rels.ownerColumnsNames = []; rels.referencedColumnsNames = []; rels.actionOnDelete = - resp.DELETE_RULE == "NO ACTION" ? null : resp.DELETE_RULE; + resp.DELETE_RULE === "NO ACTION" ? null : resp.DELETE_RULE; rels.actionOnUpdate = null; rels.object_id = resp.CONSTRAINT_NAME; rels.ownerTable = resp.OWNER_TABLE_NAME; @@ -280,12 +280,12 @@ export class OracleDriver extends AbstractDriver { ); return entities; } - async DisconnectFromServer() { - if (this.Connection) await this.Connection.close(); + public async DisconnectFromServer() { + if (this.Connection) { + await this.Connection.close(); + } } - - private Connection: any /*Oracle.IConnection*/; - async ConnectToServer( + public async ConnectToServer( database: string, server: string, port: number, @@ -294,25 +294,25 @@ export class OracleDriver extends AbstractDriver { ssl: boolean ) { let config: any; - if (user == String(process.env.ORACLE_UsernameSys)) { + if (user === String(process.env.ORACLE_UsernameSys)) { config /*Oracle.IConnectionAttributes*/ = { - user: user, - password: password, connectString: `${server}:${port}/${database}`, externalAuth: ssl, - privilege: this.Oracle.SYSDBA + password, + privilege: this.Oracle.SYSDBA, + user }; } else { config /*Oracle.IConnectionAttributes*/ = { - user: user, - password: password, connectString: `${server}:${port}/${database}`, - externalAuth: ssl + externalAuth: ssl, + password, + user }; } - let that = this; - let promise = new Promise((resolve, reject) => { - this.Oracle.getConnection(config, function(err, connection) { + const that = this; + const promise = new Promise((resolve, reject) => { + this.Oracle.getConnection(config, (err, connection) => { if (!err) { that.Connection = connection; resolve(true); @@ -330,7 +330,7 @@ export class OracleDriver extends AbstractDriver { await promise; } - async CreateDB(dbName: string) { + public async CreateDB(dbName: string) { await this.Connection.execute( `CREATE USER ${dbName} IDENTIFIED BY ${String( process.env.ORACLE_Password @@ -338,12 +338,14 @@ export class OracleDriver extends AbstractDriver { ); await this.Connection.execute(`GRANT CONNECT TO ${dbName}`); } - async UseDB(dbName: string) {} - async DropDB(dbName: string) { + public async UseDB(dbName: string) { + // not supported + } + public async DropDB(dbName: string) { await this.Connection.execute(`DROP USER ${dbName} CASCADE`); } - async CheckIfDBExists(dbName: string): Promise { - var x = await this.Connection.execute( + public async CheckIfDBExists(dbName: string): Promise { + const x = await this.Connection.execute( `select count(*) as CNT from dba_users where username='${dbName.toUpperCase()}'` ); return x.rows[0][0] > 0 || x.rows[0].CNT; diff --git a/src/drivers/PostgresDriver.ts b/src/drivers/PostgresDriver.ts index b117522..164d788 100644 --- a/src/drivers/PostgresDriver.ts +++ b/src/drivers/PostgresDriver.ts @@ -1,27 +1,27 @@ -import { AbstractDriver } from "./AbstractDriver"; import * as PG from "pg"; import { ColumnInfo } from "../models/ColumnInfo"; import { EntityInfo } from "../models/EntityInfo"; import * as TomgUtils from "../Utils"; +import { AbstractDriver } from "./AbstractDriver"; export class PostgresDriver extends AbstractDriver { private Connection: PG.Client; - GetAllTablesQuery = async (schema: string) => { - let response: { + public GetAllTablesQuery = async (schema: string) => { + const response: Array<{ TABLE_SCHEMA: string; TABLE_NAME: string; - }[] = (await this.Connection.query( + }> = (await this.Connection.query( `SELECT table_schema as "TABLE_SCHEMA",table_name as "TABLE_NAME" FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE='BASE TABLE' AND table_schema in (${schema}) ` )).rows; return response; }; - async GetCoulmnsFromEntity( + public async GetCoulmnsFromEntity( entities: EntityInfo[], schema: string ): Promise { - let response: { + const response: Array<{ table_name: string; column_name: string; udt_name: string; @@ -32,8 +32,8 @@ export class PostgresDriver extends AbstractDriver { numeric_precision: number; numeric_scale: number; isidentity: string; - isunique: number; - }[] = (await this.Connection + isunique: string; + }> = (await this.Connection .query(`SELECT table_name,column_name,udt_name,column_default,is_nullable, data_type,character_maximum_length,numeric_precision,numeric_scale, case when column_default LIKE 'nextval%' then 'YES' else 'NO' end isidentity, @@ -50,28 +50,26 @@ export class PostgresDriver extends AbstractDriver { .rows; entities.forEach(ent => { response - .filter(filterVal => { - return filterVal.table_name == ent.EntityName; - }) + .filter(filterVal => filterVal.table_name === ent.EntityName) .forEach(resp => { - let colInfo: ColumnInfo = new ColumnInfo(); + const colInfo: ColumnInfo = new ColumnInfo(); colInfo.tsName = resp.column_name; colInfo.sqlName = resp.column_name; - colInfo.is_nullable = resp.is_nullable == "YES"; - colInfo.is_generated = resp.isidentity == "YES"; - colInfo.is_unique = resp.isunique == 1; - colInfo.default = colInfo.is_generated + colInfo.isNullable = resp.is_nullable === "YES"; + colInfo.isGenerated = resp.isidentity === "YES"; + colInfo.isUnique = resp.isunique === "1"; + colInfo.default = colInfo.isGenerated ? null : resp.column_default; - var columnTypes = this.MatchColumnTypes( + const columnTypes = this.MatchColumnTypes( resp.data_type, resp.udt_name ); if (!columnTypes.sql_type || !columnTypes.ts_type) { if ( - resp.data_type == "USER-DEFINED" || - resp.data_type == "ARRAY" + resp.data_type === "USER-DEFINED" || + resp.data_type === "ARRAY" ) { TomgUtils.LogError( `Unknown ${resp.data_type} column type: ${ @@ -91,19 +89,19 @@ export class PostgresDriver extends AbstractDriver { } return; } - colInfo.sql_type = columnTypes.sql_type; - colInfo.ts_type = columnTypes.ts_type; - colInfo.is_array = columnTypes.is_array; - if (colInfo.is_array) { - colInfo.ts_type = colInfo.ts_type + colInfo.sqlType = columnTypes.sql_type; + colInfo.tsType = columnTypes.ts_type; + colInfo.isArray = columnTypes.is_array; + if (colInfo.isArray) { + colInfo.tsType = colInfo.tsType .split("|") .map(x => x.replace("|", "").trim() + "[]") - .join(" | "); + .join(" | ") as any; } if ( this.ColumnTypesWithPrecision.some( - v => v == colInfo.sql_type + v => v === colInfo.sqlType ) ) { colInfo.numericPrecision = resp.numeric_precision; @@ -111,7 +109,7 @@ export class PostgresDriver extends AbstractDriver { } if ( this.ColumnTypesWithLength.some( - v => v == colInfo.sql_type + v => v === colInfo.sqlType ) ) { colInfo.lenght = @@ -121,7 +119,7 @@ export class PostgresDriver extends AbstractDriver { } if ( this.ColumnTypesWithWidth.some( - v => v == colInfo.sql_type + v => v === colInfo.sqlType ) ) { colInfo.width = @@ -129,7 +127,7 @@ export class PostgresDriver extends AbstractDriver { ? resp.character_maximum_length : null; } - if (colInfo.sql_type && colInfo.ts_type) { + if (colInfo.sqlType && colInfo.tsType) { ent.Columns.push(colInfo); } }); @@ -137,8 +135,8 @@ export class PostgresDriver extends AbstractDriver { return entities; } - MatchColumnTypes(data_type: string, udt_name: string) { - let ret: { + public MatchColumnTypes(dataType: string, udtName: string) { + const ret: { ts_type: | "number" | "string" @@ -153,8 +151,8 @@ export class PostgresDriver extends AbstractDriver { sql_type: string | null; is_array: boolean; } = { ts_type: null, sql_type: null, is_array: false }; - ret.sql_type = data_type; - switch (data_type) { + ret.sql_type = dataType; + switch (dataType) { case "int2": ret.ts_type = "number"; break; @@ -340,15 +338,15 @@ export class PostgresDriver extends AbstractDriver { ret.ts_type = "string"; break; case "ARRAY": - let z = this.MatchColumnTypes(udt_name.substring(1), udt_name); + const z = this.MatchColumnTypes(udtName.substring(1), udtName); ret.ts_type = z.ts_type; ret.sql_type = z.sql_type; ret.is_array = true; break; case "USER-DEFINED": - ret.sql_type = udt_name; + ret.sql_type = udtName; ret.ts_type = "string"; - switch (udt_name) { + switch (udtName) { case "citext": case "hstore": case "geometry": @@ -366,27 +364,27 @@ export class PostgresDriver extends AbstractDriver { } return ret; } - async GetIndexesFromEntity( + public async GetIndexesFromEntity( entities: EntityInfo[], schema: string ): Promise { - let response: { + const response: Array<{ tablename: string; indexname: string; columnname: string; is_unique: number; is_primary_key: number; - }[] = (await this.Connection.query(`SELECT + }> = (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' + WHEN ix.indisunique = true THEN 1 + ELSE 0 END AS is_unique, CASE - WHEN ix.indisprimary='true' THEN '1' - ELSE '0' + 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 @@ -402,29 +400,27 @@ export class PostgresDriver extends AbstractDriver { ORDER BY c.relname,f.attname;`)).rows; entities.forEach(ent => { response - .filter(filterVal => { - return filterVal.tablename == ent.EntityName; - }) + .filter(filterVal => filterVal.tablename === ent.EntityName) .forEach(resp => { - let indexInfo: IndexInfo = {}; - let indexColumnInfo: IndexColumnInfo = {}; + let indexInfo: IndexInfo = {} as IndexInfo; + const indexColumnInfo: IndexColumnInfo = {} as IndexColumnInfo; if ( - ent.Indexes.filter(filterVal => { - return filterVal.name == resp.indexname; - }).length > 0 + ent.Indexes.filter( + filterVal => filterVal.name === resp.indexname + ).length > 0 ) { - indexInfo = ent.Indexes.filter(filterVal => { - return filterVal.name == resp.indexname; - })[0]; + indexInfo = ent.Indexes.find( + filterVal => filterVal.name === resp.indexname + )!; } else { - indexInfo.columns = []; + indexInfo.columns = [] as IndexColumnInfo[]; indexInfo.name = resp.indexname; - indexInfo.isUnique = resp.is_unique == 1; - indexInfo.isPrimaryKey = resp.is_primary_key == 1; + indexInfo.isUnique = resp.is_unique === 1; + indexInfo.isPrimaryKey = resp.is_primary_key === 1; ent.Indexes.push(indexInfo); } indexColumnInfo.name = resp.columnname; - if (resp.is_primary_key == 0) { + if (resp.is_primary_key === 0) { indexInfo.isPrimaryKey = false; } indexInfo.columns.push(indexColumnInfo); @@ -433,11 +429,11 @@ export class PostgresDriver extends AbstractDriver { return entities; } - async GetRelations( + public async GetRelations( entities: EntityInfo[], schema: string ): Promise { - let response: { + const response: Array<{ tablewithforeignkey: string; fk_partno: number; foreignkeycolumn: string; @@ -446,7 +442,7 @@ export class PostgresDriver extends AbstractDriver { ondelete: "RESTRICT" | "CASCADE" | "SET NULL" | "NO ACTION"; onupdate: "RESTRICT" | "CASCADE" | "SET NULL" | "NO ACTION"; object_id: string; - }[] = (await this.Connection.query(`SELECT + }> = (await this.Connection.query(`SELECT con.relname AS tablewithforeignkey, att.attnum as fk_partno, att2.attname AS foreignkeycolumn, @@ -484,19 +480,19 @@ export class PostgresDriver extends AbstractDriver { AND att2.attrelid = con.conrelid AND att2.attnum = con.parent and rc.constraint_name= con.conname`)).rows; - let relationsTemp: RelationTempInfo[] = []; + const relationsTemp: IRelationTempInfo[] = [] as IRelationTempInfo[]; response.forEach(resp => { - let rels = relationsTemp.find(val => { - return val.object_id == resp.object_id; - }); - if (rels == undefined) { - rels = {}; + let rels = relationsTemp.find( + val => val.object_id === resp.object_id + ); + if (rels === undefined) { + rels = {} as IRelationTempInfo; rels.ownerColumnsNames = []; rels.referencedColumnsNames = []; rels.actionOnDelete = - resp.ondelete == "NO ACTION" ? null : resp.ondelete; + resp.ondelete === "NO ACTION" ? null : resp.ondelete; rels.actionOnUpdate = - resp.onupdate == "NO ACTION" ? null : resp.onupdate; + resp.onupdate === "NO ACTION" ? null : resp.onupdate; rels.object_id = resp.object_id; rels.ownerTable = resp.tablewithforeignkey; rels.referencedTable = resp.tablereferenced; @@ -511,9 +507,9 @@ export class PostgresDriver extends AbstractDriver { ); return entities; } - async DisconnectFromServer() { + public async DisconnectFromServer() { if (this.Connection) { - let promise = new Promise((resolve, reject) => { + const promise = new Promise((resolve, reject) => { this.Connection.end(err => { if (!err) { resolve(true); @@ -531,7 +527,7 @@ export class PostgresDriver extends AbstractDriver { } } - async ConnectToServer( + public async ConnectToServer( database: string, server: string, port: number, @@ -540,15 +536,15 @@ export class PostgresDriver extends AbstractDriver { ssl: boolean ) { this.Connection = new PG.Client({ - database: database, + database, host: server, - port: port, - user: user, - password: password, - ssl: ssl + password, + port, + ssl, + user }); - let promise = new Promise((resolve, reject) => { + const promise = new Promise((resolve, reject) => { this.Connection.connect(err => { if (!err) { resolve(true); @@ -566,17 +562,17 @@ export class PostgresDriver extends AbstractDriver { await promise; } - async CreateDB(dbName: string) { + public async CreateDB(dbName: string) { await this.Connection.query(`CREATE DATABASE ${dbName}; `); } - async UseDB(dbName: string) { + public async UseDB(dbName: string) { await this.Connection.query(`USE ${dbName}; `); } - async DropDB(dbName: string) { + public async DropDB(dbName: string) { await this.Connection.query(`DROP DATABASE ${dbName}; `); } - async CheckIfDBExists(dbName: string): Promise { - let resp = await this.Connection.query( + public async CheckIfDBExists(dbName: string): Promise { + const resp = await this.Connection.query( `SELECT datname FROM pg_database WHERE datname ='${dbName}' ` ); return resp.rowCount > 0; diff --git a/src/drivers/SqliteDriver.ts b/src/drivers/SqliteDriver.ts index 9768316..5e1cfc1 100644 --- a/src/drivers/SqliteDriver.ts +++ b/src/drivers/SqliteDriver.ts @@ -1,24 +1,24 @@ -import { AbstractDriver } from "./AbstractDriver"; import { ColumnInfo } from "../models/ColumnInfo"; import { EntityInfo } from "../models/EntityInfo"; import * as TomgUtils from "../Utils"; +import { AbstractDriver } from "./AbstractDriver"; export class SqliteDriver extends AbstractDriver { - sqlite = require("sqlite3").verbose(); - db: any; - tablesWithGeneratedPrimaryKey: String[] = new Array(); - GetAllTablesQuery: any; + public sqlite = require("sqlite3").verbose(); + public db: any; + public tablesWithGeneratedPrimaryKey: string[] = new Array(); + public GetAllTablesQuery: any; - async GetAllTables(schema: string): Promise { - let ret: EntityInfo[] = []; - let rows = await this.ExecQuery<{ tbl_name: string; sql: string }>( + public async GetAllTables(schema: string): Promise { + const ret: EntityInfo[] = [] as EntityInfo[]; + const rows = await this.ExecQuery<{ tbl_name: string; sql: string }>( `SELECT tbl_name, sql FROM "sqlite_master" WHERE "type" = 'table' AND name NOT LIKE 'sqlite_%'` ); rows.forEach(val => { - let ent: EntityInfo = new EntityInfo(); + const ent: EntityInfo = new EntityInfo(); ent.EntityName = val.tbl_name; - ent.Columns = []; - ent.Indexes = []; + ent.Columns = [] as ColumnInfo[]; + ent.Indexes = [] as IndexInfo[]; if (val.sql.includes("AUTOINCREMENT")) { this.tablesWithGeneratedPrimaryKey.push(ent.EntityName); } @@ -26,12 +26,12 @@ export class SqliteDriver extends AbstractDriver { }); return ret; } - async GetCoulmnsFromEntity( + public async GetCoulmnsFromEntity( entities: EntityInfo[], schema: string ): Promise { for (const ent of entities) { - let response = await this.ExecQuery<{ + const response = await this.ExecQuery<{ cid: number; name: string; type: string; @@ -40,163 +40,164 @@ export class SqliteDriver extends AbstractDriver { pk: number; }>(`PRAGMA table_info('${ent.EntityName}');`); response.forEach(resp => { - let colInfo: ColumnInfo = new ColumnInfo(); + const colInfo: ColumnInfo = new ColumnInfo(); colInfo.tsName = resp.name; colInfo.sqlName = resp.name; - colInfo.is_nullable = resp.notnull == 0; + colInfo.isNullable = resp.notnull === 0; colInfo.isPrimary = resp.pk > 0; colInfo.default = resp.dflt_value ? resp.dflt_value : null; - colInfo.sql_type = resp.type + colInfo.sqlType = resp.type .replace(/\([0-9 ,]+\)/g, "") .toLowerCase() .trim(); - colInfo.is_generated = + colInfo.isGenerated = colInfo.isPrimary && this.tablesWithGeneratedPrimaryKey.includes(ent.EntityName); - switch (colInfo.sql_type) { + switch (colInfo.sqlType) { case "int": - colInfo.ts_type = "number"; + colInfo.tsType = "number"; break; case "integer": - colInfo.ts_type = "number"; + colInfo.tsType = "number"; break; case "int2": - colInfo.ts_type = "number"; + colInfo.tsType = "number"; break; case "int8": - colInfo.ts_type = "number"; + colInfo.tsType = "number"; break; case "tinyint": - colInfo.ts_type = "number"; + colInfo.tsType = "number"; break; case "smallint": - colInfo.ts_type = "number"; + colInfo.tsType = "number"; break; case "mediumint": - colInfo.ts_type = "number"; + colInfo.tsType = "number"; break; case "bigint": - colInfo.ts_type = "string"; + colInfo.tsType = "string"; break; case "unsigned big int": - colInfo.ts_type = "string"; + colInfo.tsType = "string"; break; case "character": - colInfo.ts_type = "string"; + colInfo.tsType = "string"; break; case "varchar": - colInfo.ts_type = "string"; + colInfo.tsType = "string"; break; case "varying character": - colInfo.ts_type = "string"; + colInfo.tsType = "string"; break; case "nchar": - colInfo.ts_type = "string"; + colInfo.tsType = "string"; break; case "native character": - colInfo.ts_type = "string"; + colInfo.tsType = "string"; break; case "nvarchar": - colInfo.ts_type = "string"; + colInfo.tsType = "string"; break; case "text": - colInfo.ts_type = "string"; + colInfo.tsType = "string"; break; case "blob": - colInfo.ts_type = "Buffer"; + colInfo.tsType = "Buffer"; break; case "clob": - colInfo.ts_type = "string"; + colInfo.tsType = "string"; break; case "real": - colInfo.ts_type = "number"; + colInfo.tsType = "number"; break; case "double": - colInfo.ts_type = "number"; + colInfo.tsType = "number"; break; case "double precision": - colInfo.ts_type = "number"; + colInfo.tsType = "number"; break; case "float": - colInfo.ts_type = "number"; + colInfo.tsType = "number"; break; case "numeric": - colInfo.ts_type = "number"; + colInfo.tsType = "number"; break; case "decimal": - colInfo.ts_type = "number"; + colInfo.tsType = "number"; break; case "boolean": - colInfo.ts_type = "boolean"; + colInfo.tsType = "boolean"; break; case "date": - colInfo.ts_type = "string"; + colInfo.tsType = "string"; break; case "datetime": - colInfo.ts_type = "Date"; + colInfo.tsType = "Date"; break; default: - console.log(colInfo.sql_type.toLowerCase().trim()); TomgUtils.LogError( `Unknown column type: ${ - colInfo.sql_type + colInfo.sqlType } table name: ${ent.EntityName} column name: ${ resp.name }` ); break; } - let options = resp.type.match(/\([0-9 ,]+\)/g); + const options = resp.type.match(/\([0-9 ,]+\)/g); if ( this.ColumnTypesWithPrecision.some( - v => v == colInfo.sql_type + v => v === colInfo.sqlType ) && options ) { - colInfo.numericPrecision = options[0] + colInfo.numericPrecision = options[0] .substring(1, options[0].length - 1) - .split(",")[0]; - colInfo.numericScale = options[0] + .split(",")[0] as any; + colInfo.numericScale = options[0] .substring(1, options[0].length - 1) - .split(",")[1]; + .split(",")[1] as any; } if ( this.ColumnTypesWithLength.some( - v => v == colInfo.sql_type + v => v === colInfo.sqlType ) && options ) { - colInfo.lenght = options[0].substring( + colInfo.lenght = options[0].substring( 1, options[0].length - 1 - ); + ) as any; } if ( this.ColumnTypesWithWidth.some( v => - v == colInfo.sql_type && - colInfo.ts_type != "boolean" + v === colInfo.sqlType && + colInfo.tsType !== "boolean" ) && options ) { - colInfo.width = options[0].substring( + colInfo.width = options[0].substring( 1, options[0].length - 1 - ); + ) as any; } - if (colInfo.sql_type) ent.Columns.push(colInfo); + if (colInfo.sqlType) { + ent.Columns.push(colInfo); + } }); } return entities; } - async GetIndexesFromEntity( + public async GetIndexesFromEntity( entities: EntityInfo[], schema: string ): Promise { for (const ent of entities) { - let response = await this.ExecQuery<{ + const response = await this.ExecQuery<{ seq: number; name: string; unique: number; @@ -204,36 +205,36 @@ export class SqliteDriver extends AbstractDriver { partial: number; }>(`PRAGMA index_list('${ent.EntityName}');`); for (const resp of response) { - let indexColumnsResponse = await this.ExecQuery<{ + const indexColumnsResponse = await this.ExecQuery<{ seqno: number; cid: number; name: string; }>(`PRAGMA index_info('${resp.name}');`); indexColumnsResponse.forEach(element => { - let indexInfo: IndexInfo = {}; - let indexColumnInfo: IndexColumnInfo = {}; + let indexInfo: IndexInfo = {} as IndexInfo; + const indexColumnInfo: IndexColumnInfo = {} as IndexColumnInfo; if ( ent.Indexes.filter(filterVal => { - return filterVal.name == resp.name; + return filterVal.name === resp.name; }).length > 0 ) { - indexInfo = ent.Indexes.filter(filterVal => { - return filterVal.name == resp.name; - })[0]; + indexInfo = ent.Indexes.find( + filterVal => filterVal.name === resp.name + )!; } else { - indexInfo.columns = []; + indexInfo.columns = [] as IndexColumnInfo[]; indexInfo.name = resp.name; - indexInfo.isUnique = resp.unique == 1; + indexInfo.isUnique = resp.unique === 1; ent.Indexes.push(indexInfo); } indexColumnInfo.name = element.name; if ( - indexColumnsResponse.length == 1 && + indexColumnsResponse.length === 1 && indexInfo.isUnique ) { ent.Columns.filter( - v => v.tsName == indexColumnInfo.name - ).map(v => (v.is_unique = true)); + v => v.tsName === indexColumnInfo.name + ).map(v => (v.isUnique = true)); } indexInfo.columns.push(indexColumnInfo); }); @@ -242,12 +243,12 @@ export class SqliteDriver extends AbstractDriver { return entities; } - async GetRelations( + public async GetRelations( entities: EntityInfo[], schema: string ): Promise { for (const entity of entities) { - let response = await this.ExecQuery<{ + const response = await this.ExecQuery<{ id: number; seq: number; table: string; @@ -257,15 +258,15 @@ export class SqliteDriver extends AbstractDriver { on_delete: "RESTRICT" | "CASCADE" | "SET NULL" | "NO ACTION"; match: string; }>(`PRAGMA foreign_key_list('${entity.EntityName}');`); - let relationsTemp: RelationTempInfo[] = []; + const relationsTemp: IRelationTempInfo[] = [] as IRelationTempInfo[]; response.forEach(resp => { - let rels = {}; + const rels = {} as IRelationTempInfo; rels.ownerColumnsNames = []; rels.referencedColumnsNames = []; rels.actionOnDelete = - resp.on_delete == "NO ACTION" ? null : resp.on_delete; + resp.on_delete === "NO ACTION" ? null : resp.on_delete; rels.actionOnUpdate = - resp.on_update == "NO ACTION" ? null : resp.on_update; + resp.on_update === "NO ACTION" ? null : resp.on_update; rels.ownerTable = entity.EntityName; rels.referencedTable = resp.table; relationsTemp.push(rels); @@ -279,11 +280,11 @@ export class SqliteDriver extends AbstractDriver { } return entities; } - async DisconnectFromServer() { + public async DisconnectFromServer() { this.db.close(); } - async ConnectToServer( + public async ConnectToServer( database: string, server: string, port: number, @@ -294,12 +295,18 @@ export class SqliteDriver extends AbstractDriver { await this.UseDB(database); } - async CreateDB(dbName: string) {} - async UseDB(dbName: string) { - let promise = new Promise((resolve, reject) => { + public async CreateDB(dbName: string) { + // not supported + } + public async UseDB(dbName: string) { + const promise = new Promise((resolve, reject) => { this.db = new this.sqlite.Database(dbName, err => { if (err) { - console.error(err.message); + TomgUtils.LogError( + "Error connecting to SQLite database.", + false, + err.message + ); reject(err); return; } @@ -308,16 +315,18 @@ export class SqliteDriver extends AbstractDriver { }); return promise; } - async DropDB(dbName: string) {} - async CheckIfDBExists(dbName: string): Promise { + public async DropDB(dbName: string) { + // not supported + } + public async CheckIfDBExists(dbName: string): Promise { return true; } - async ExecQuery(sql: string): Promise> { + public async ExecQuery(sql: string): Promise { let ret: any; - let promise = new Promise((resolve, reject) => { + const promise = new Promise((resolve, reject) => { this.db.serialize(() => { - this.db.all(sql, [], function(err, row) { + this.db.all(sql, [], (err, row) => { if (!err) { ret = row; resolve(true); diff --git a/src/entity.mst b/src/entity.mst index 6834464..0dd8ee7 100644 --- a/src/entity.mst +++ b/src/entity.mst @@ -8,24 +8,24 @@ import {Index,Entity, PrimaryColumn, PrimaryGeneratedColumn, Column, OneToOne, O {{/isPrimaryKey}}{{/Indexes}}export class {{toEntityName EntityName}} { {{#Columns}} - {{^relations}}{{#is_generated}} @PrimaryGeneratedColumn({ - type:"{{sql_type}}", {{/is_generated}}{{^is_generated}} @Column("{{sql_type}}",{ {{#is_nullable}} - nullable:true,{{/is_nullable}}{{^is_nullable}} - nullable:false,{{/is_nullable}}{{#isPrimary}} - primary:{{isPrimary}},{{/isPrimary}}{{/is_generated}}{{#is_unique}} - unique: true,{{/is_unique}}{{#lenght}} + {{^relations}}{{#isGenerated}} @PrimaryGeneratedColumn({ + type:"{{sqlType}}", {{/isGenerated}}{{^isGenerated}} @Column("{{sqlType}}",{ {{#isNullable}} + nullable:true,{{/isNullable}}{{^isNullable}} + nullable:false,{{/isNullable}}{{#isPrimary}} + primary:{{isPrimary}},{{/isPrimary}}{{/isGenerated}}{{#isUnique}} + unique: true,{{/isUnique}}{{#lenght}} length:{{.}},{{/lenght}}{{#width}} width:{{.}},{{/width}}{{#default}} default:"{{.}}",{{/default}}{{#numericPrecision}} precision:{{.}},{{/numericPrecision}}{{#numericScale}} scale:{{.}},{{/numericScale}}{{#enumOptions}} - enum:[{{.}}],{{/enumOptions}}{{#is_array}} - array:{{is_array}},{{/is_array}} + enum:[{{.}}],{{/enumOptions}}{{#isArray}} + array:{{isArray}},{{/isArray}} name:"{{sqlName}}" }) - {{printPropertyVisibility}}{{toPropertyName tsName}}:{{ts_type}}{{#is_nullable}} | null{{/is_nullable}}; + {{printPropertyVisibility}}{{toPropertyName tsName}}:{{tsType}}{{#isNullable}} | null{{/isNullable}}; {{/relations}}{{#relations}} - @{{relationType}}(type=>{{toEntityName relatedTable}}, {{toEntityName relatedTable}}=>{{toEntityName relatedTable}}.{{#if isOwner}}{{toPropertyName ownerColumn}},{ {{#../isPrimary}}primary:true,{{/../isPrimary}}{{^../is_nullable}} nullable:false,{{/../is_nullable}}{{#actionOnDelete}}onDelete: '{{.}}',{{/actionOnDelete}}{{#actionOnUpdate}}onUpdate: '{{.}}'{{/actionOnUpdate}} }{{else}}{{toPropertyName relatedColumn}}{{#if (or actionOnDelete actionOnUpdate ) }}{{#actionOnDelete}},{ onDelete: '{{.}}' ,{{/actionOnDelete}}{{#actionOnUpdate}}onUpdate: '{{.}}'{{/actionOnUpdate}} }{{/if}}{{/if}}){{#isOwner}} + @{{relationType}}(type=>{{toEntityName relatedTable}}, {{toEntityName relatedTable}}=>{{toEntityName relatedTable}}.{{#if isOwner}}{{toPropertyName ownerColumn}},{ {{#../isPrimary}}primary:true,{{/../isPrimary}}{{^../isNullable}} nullable:false,{{/../isNullable}}{{#actionOnDelete}}onDelete: '{{.}}',{{/actionOnDelete}}{{#actionOnUpdate}}onUpdate: '{{.}}'{{/actionOnUpdate}} }{{else}}{{toPropertyName relatedColumn}}{{#if (or actionOnDelete actionOnUpdate ) }}{{#actionOnDelete}},{ onDelete: '{{.}}' ,{{/actionOnDelete}}{{#actionOnUpdate}}onUpdate: '{{.}}'{{/actionOnUpdate}} }{{/if}}{{/if}}){{#isOwner}} {{#if isManyToMany}}@JoinTable(){{else}}@JoinColumn({ name:'{{ ../sqlName}}'}){{/if}}{{/isOwner}} {{#if (or isOneToMany isManyToMany)}}{{printPropertyVisibility}}{{toPropertyName ../tsName}}:{{toLazy (concat (toEntityName relatedTable) "[]")}}; {{else}}{{printPropertyVisibility}}{{toPropertyName ../tsName}}:{{toLazy (concat (toEntityName relatedTable) ' | null')}}; @@ -33,7 +33,7 @@ import {Index,Entity, PrimaryColumn, PrimaryGeneratedColumn, Column, OneToOne, O {{#if relationIdField }} @RelationId(({{../../EntityName}}: {{../../EntityName}}) => {{../../EntityName}}.{{toPropertyName ../tsName}}) - {{toPropertyName ../tsName}}Id: {{#if isOneToOne}}{{toLazy ../ts_type}}{{else}}{{toLazy (concat ../ts_type "[]")}}{{/if}};{{/if}}{{/relations}} + {{toPropertyName ../tsName}}Id: {{#if isOneToOne}}{{toLazy ../tsType}}{{else}}{{toLazy (concat ../tsType "[]")}}{{/if}};{{/if}}{{/relations}} {{/Columns}} {{#if GenerateConstructor}} constructor(init?: Partial<{{toEntityName EntityName}}>) { diff --git a/src/index.ts b/src/index.ts index fcdb6f1..6e36e54 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,29 +1,29 @@ +import path = require("path"); +import * as Yargs from "yargs"; +import { AbstractNamingStrategy } from "./AbstractNamingStrategy"; import { AbstractDriver } from "./drivers/AbstractDriver"; +import { MariaDbDriver } from "./drivers/MariaDbDriver"; import { MssqlDriver } from "./drivers/MssqlDriver"; +import { MysqlDriver } from "./drivers/MysqlDriver"; +import { OracleDriver } from "./drivers/OracleDriver"; import { PostgresDriver } from "./drivers/PostgresDriver"; import { SqliteDriver } from "./drivers/SqliteDriver"; -import { MysqlDriver } from "./drivers/MysqlDriver"; -import { MariaDbDriver } from "./drivers/MariaDbDriver"; -import { OracleDriver } from "./drivers/OracleDriver"; import { Engine } from "./Engine"; -import * as Yargs from "yargs"; -import * as TomgUtils from "./Utils"; -import path = require("path"); -import { AbstractNamingStrategy } from "./AbstractNamingStrategy"; import { NamingStrategy } from "./NamingStrategy"; +import * as TomgUtils from "./Utils"; -var argv = Yargs.usage( +const argv = Yargs.usage( "Usage: typeorm-model-generator -h -d -p [port] -u -x [password] -e [engine]" ) .option("h", { alias: "host", - describe: "IP adress/Hostname for database server", - default: "127.0.0.1" + default: "127.0.0.1", + describe: "IP adress/Hostname for database server" }) .option("d", { alias: "database", - describe: "Database name(or path for sqlite)", - demand: true + demand: true, + describe: "Database name(or path for sqlite)" }) .option("u", { alias: "user", @@ -31,8 +31,8 @@ var argv = Yargs.usage( }) .option("x", { alias: "pass", - describe: "Password for database server", - default: "" + default: "", + describe: "Password for database server" }) .option("p", { alias: "port", @@ -40,14 +40,14 @@ var argv = Yargs.usage( }) .option("e", { alias: "engine", - describe: "Database engine", choices: ["mssql", "postgres", "mysql", "mariadb", "oracle", "sqlite"], - default: "mssql" + default: "mssql", + describe: "Database engine" }) .option("o", { alias: "output", - describe: "Where to place generated models", - default: path.resolve(process.cwd(), "output") + default: path.resolve(process.cwd(), "output"), + describe: "Where to place generated models" }) .option("s", { alias: "schema", @@ -60,50 +60,50 @@ var argv = Yargs.usage( }) .option("noConfig", { boolean: true, - describe: `Doesn't create tsconfig.json and ormconfig.json`, - default: false + default: false, + describe: `Doesn't create tsconfig.json and ormconfig.json` }) .option("cf", { alias: "case-file", - describe: "Convert file names to specified case", choices: ["pascal", "param", "camel", "none"], - default: "none" + default: "none", + describe: "Convert file names to specified case" }) .option("ce", { alias: "case-entity", - describe: "Convert class names to specified case", choices: ["pascal", "camel", "none"], - default: "none" + default: "none", + describe: "Convert class names to specified case" }) .option("cp", { alias: "case-property", - describe: "Convert property names to specified case", choices: ["pascal", "camel", "none"], - default: "none" + default: "none", + describe: "Convert property names to specified case" }) .option("pv", { alias: "property-visibility", - describe: "Defines which visibility should have the generated property", choices: ["public", "protected", "private", "none"], - default: "none" + default: "none", + describe: "Defines which visibility should have the generated property" }) .option("lazy", { - describe: "Generate lazy relations", boolean: true, - default: false + default: false, + describe: "Generate lazy relations" }) .option("namingStrategy", { describe: "Use custom naming strategy" }) .option("relationIds", { - describe: "Generate RelationId fields", boolean: true, - default: false + default: false, + describe: "Generate RelationId fields" }) .option("generateConstructor", { - describe: "Generate constructor allowing partial initialization", boolean: true, - default: false + default: false, + describe: "Generate constructor allowing partial initialization" }).argv; let driver: AbstractDriver; @@ -147,32 +147,33 @@ switch (argv.e) { throw new Error("Database engine not recognized."); } let namingStrategy: AbstractNamingStrategy; -if (argv.namingStrategy && argv.namingStrategy != "") { - let req = require(argv.namingStrategy); +if (argv.namingStrategy && argv.namingStrategy !== "") { + // tslint:disable-next-line:no-var-requires + const req = require(argv.namingStrategy); namingStrategy = new req.NamingStrategy(); } else { namingStrategy = new NamingStrategy(); } -let engine = new Engine(driver, { - host: argv.h, - port: parseInt(argv.p) || standardPort, +const engine = new Engine(driver, { + constructor: argv.generateConstructor, + convertCaseEntity: argv.ce, + convertCaseFile: argv.cf, + convertCaseProperty: argv.cp, databaseName: argv.d ? argv.d.toString() : null, - user: argv.u ? argv.u.toString() : standardUser, - password: argv.x ? argv.x.toString() : null, databaseType: argv.e, + host: argv.h, + lazy: argv.lazy, + namingStrategy, + noConfigs: argv.noConfig, + password: argv.x ? argv.x.toString() : null, + port: parseInt(argv.p, 10) || standardPort, + propertyVisibility: argv.pv, + relationIds: argv.relationIds, resultsPath: argv.o ? argv.o.toString() : null, schemaName: argv.s ? argv.s.toString() : standardSchema, ssl: argv.ssl, - noConfigs: argv.noConfig, - convertCaseFile: argv.cf, - convertCaseEntity: argv.ce, - convertCaseProperty: argv.cp, - propertyVisibility: argv.pv, - lazy: argv.lazy, - constructor: argv.generateConstructor, - relationIds: argv.relationIds, - namingStrategy: namingStrategy + user: argv.u ? argv.u.toString() : standardUser }); console.log(TomgUtils.packageVersion()); diff --git a/src/models/ColumnInfo.ts b/src/models/ColumnInfo.ts index 056c2f7..8cdaea3 100644 --- a/src/models/ColumnInfo.ts +++ b/src/models/ColumnInfo.ts @@ -1,12 +1,12 @@ import { RelationInfo } from "./RelationInfo"; export class ColumnInfo { - tsName: string = ""; - sqlName: string = ""; - default: string | null = null; - is_nullable: boolean = false; - is_unique: boolean = false; - ts_type: + public tsName: string = ""; + public sqlName: string = ""; + public default: string | null = null; + public isNullable: boolean = false; + public isUnique: boolean = false; + public tsType: | "number" | "string" | "boolean" @@ -16,16 +16,16 @@ export class ColumnInfo { | "string | Object" | "string | string[]" | "any"; - sql_type: string; - lenght: number | null = null; - width: number | null = null; - isPrimary: boolean = false; - is_generated: boolean = false; - is_array: boolean = false; - numericPrecision: number | null = null; - numericScale: number | null = null; - enumOptions: string | null = null; - relations: RelationInfo[]; + public sqlType: string; + public lenght: number | null = null; + public width: number | null = null; + public isPrimary: boolean = false; + public isGenerated: boolean = false; + public isArray: boolean = false; + public numericPrecision: number | null = null; + public numericScale: number | null = null; + public enumOptions: string | null = null; + public relations: RelationInfo[]; constructor() { this.relations = []; } diff --git a/src/models/DatabaseModel.ts b/src/models/DatabaseModel.ts index 27c6b7b..8dd6410 100644 --- a/src/models/DatabaseModel.ts +++ b/src/models/DatabaseModel.ts @@ -1,4 +1,4 @@ import { EntityInfo } from "./EntityInfo"; export class DatabaseModel { - entities: EntityInfo[]; + public entities: EntityInfo[]; } diff --git a/src/models/EntityInfo.ts b/src/models/EntityInfo.ts index 024a0e0..82d90ed 100644 --- a/src/models/EntityInfo.ts +++ b/src/models/EntityInfo.ts @@ -1,24 +1,25 @@ import { ColumnInfo } from "./ColumnInfo"; export class EntityInfo { - EntityName: string; - Columns: ColumnInfo[]; - Imports: string[]; - UniqueImports: string[]; - Indexes: IndexInfo[]; - Schema: string; - GenerateConstructor: boolean; + public EntityName: string; + public Columns: ColumnInfo[]; + public Imports: string[]; + public UniqueImports: string[]; + public Indexes: IndexInfo[]; + public Schema: string; + public GenerateConstructor: boolean; - relationImports(): any { - var imports: string[] = []; + public relationImports() { + const imports: string[] = []; this.Columns.forEach(column => { column.relations.forEach(relation => { - if (this.EntityName != relation.relatedTable) + if (this.EntityName !== relation.relatedTable) { imports.push(relation.relatedTable); + } }); }); - this.UniqueImports = imports.filter(function(elem, index, self) { - return index == self.indexOf(elem); - }); + this.UniqueImports = imports.filter( + (elem, index, self) => index === self.indexOf(elem) + ); } } diff --git a/src/models/RelationInfo.ts b/src/models/RelationInfo.ts index fb74a3f..6dd8b3c 100644 --- a/src/models/RelationInfo.ts +++ b/src/models/RelationInfo.ts @@ -1,30 +1,35 @@ export class RelationInfo { - isOwner: boolean; - relationType: "OneToOne" | "OneToMany" | "ManyToOne" | "ManyToMany"; - relatedTable: string; - relatedColumn: string; - ownerTable: string; - ownerColumn: string; - actionOnDelete: + public isOwner: boolean; + public relationType: "OneToOne" | "OneToMany" | "ManyToOne" | "ManyToMany"; + public relatedTable: string; + public relatedColumn: string; + public ownerTable: string; + public ownerColumn: string; + public actionOnDelete: | "RESTRICT" | "CASCADE" | "SET NULL" | "DEFAULT" | "NO ACTION" | null; - actionOnUpdate: "RESTRICT" | "CASCADE" | "SET NULL" | "DEFAULT" | null; - relationIdField: boolean = false; + public actionOnUpdate: + | "RESTRICT" + | "CASCADE" + | "SET NULL" + | "DEFAULT" + | null; + public relationIdField: boolean = false; get isOneToMany(): boolean { - return this.relationType == "OneToMany"; + return this.relationType === "OneToMany"; } get isManyToMany(): boolean { - return this.relationType == "ManyToMany"; + return this.relationType === "ManyToMany"; } get isOneToOne(): boolean { - return this.relationType == "OneToOne"; + return this.relationType === "OneToOne"; } get isManyToOne(): boolean { - return this.relationType == "ManyToOne"; + return this.relationType === "ManyToOne"; } } diff --git a/src/models/RelationTempInfo.ts b/src/models/RelationTempInfo.ts index 0081955..1c4f8d8 100644 --- a/src/models/RelationTempInfo.ts +++ b/src/models/RelationTempInfo.ts @@ -1,4 +1,4 @@ -interface RelationTempInfo { +interface IRelationTempInfo { ownerTable: string; ownerColumnsNames: string[]; referencedTable: string; diff --git a/src/tslint.json b/src/tslint.json new file mode 100644 index 0000000..bd2c46b --- /dev/null +++ b/src/tslint.json @@ -0,0 +1,11 @@ +{ + "defaultSeverity": "error", + "extends": [ + "tslint:recommended", "tslint-config-prettier" + ], + "jsRules": {}, + "rules": { + "no-console":false + }, + "rulesDirectory": [] +} diff --git a/test/drivers/MssqlDriver.test.ts b/test/drivers/MssqlDriver.test.ts index 5cf0fa3..8ddb9c1 100644 --- a/test/drivers/MssqlDriver.test.ts +++ b/test/drivers/MssqlDriver.test.ts @@ -1,30 +1,30 @@ import { expect } from "chai"; -import { MssqlDriver } from '../../src/drivers/MssqlDriver' -import * as Sinon from 'sinon' import * as MSSQL from 'mssql' -import { EntityInfo } from '../../src/models/EntityInfo' +import { IColumnMetadata, Table } from "mssql"; +import * as Sinon from 'sinon' +import { MssqlDriver } from '../../src/drivers/MssqlDriver' import { ColumnInfo } from '../../src/models/ColumnInfo' +import { EntityInfo } from '../../src/models/EntityInfo' import { RelationInfo } from '../../src/models/RelationInfo' -import { Table, IColumnMetadata } from "mssql"; import { NamingStrategy } from "../../src/NamingStrategy"; class fakeResponse implements MSSQL.IResult { - recordsets: MSSQL.IRecordSet[]; - recordset: MSSQL.IRecordSet; - rowsAffected: number[]; - output: { [key: string]: any; }; + public recordsets: Array>; + public recordset: MSSQL.IRecordSet; + public rowsAffected: number[]; + public output: { [key: string]: any; }; } class fakeRecordset extends Array implements MSSQL.IRecordSet{ - columns: IColumnMetadata; - toTable(): Table { + public columns: IColumnMetadata; + public toTable(): Table { return new Table(); } } describe('MssqlDriver', function () { let driver: MssqlDriver - let sandbox = Sinon.sandbox.create() + const sandbox = Sinon.sandbox.create() beforeEach(() => { driver = new MssqlDriver(); @@ -40,19 +40,19 @@ describe('MssqlDriver', function () { .returns( { query: (q) => { - let response = new fakeResponse(); + const response = new fakeResponse(); response.recordset = new fakeRecordset(); response.recordset.push({ TABLE_SCHEMA: 'schema', TABLE_NAME: 'name' }) return response; } }) - let result = await driver.GetAllTables('schema') - let expectedResult = []; - let y = new EntityInfo(); + const result = await driver.GetAllTables('schema') + const expectedResult = [] as EntityInfo[]; + const y = new EntityInfo(); y.EntityName = 'name' y.Schema='schema' - y.Columns = []; - y.Indexes = []; + y.Columns = [] as ColumnInfo[]; + y.Indexes = [] as IndexInfo[]; expectedResult.push(y) expect(result).to.be.deep.equal(expectedResult) }) @@ -61,7 +61,7 @@ describe('MssqlDriver', function () { .returns( { query: (q) => { - let response = new fakeResponse(); + const response = new fakeResponse(); response.recordset = new fakeRecordset(); response.recordset.push({ TABLE_NAME: 'name', CHARACTER_MAXIMUM_LENGTH: 0, @@ -73,32 +73,32 @@ describe('MssqlDriver', function () { } }) - let entities = []; - let y = new EntityInfo(); + const entities = [] as EntityInfo[]; + const y = new EntityInfo(); y.EntityName = 'name' - y.Columns = []; - y.Indexes = []; + y.Columns = [] as ColumnInfo[]; + y.Indexes = [] as IndexInfo[]; entities.push(y) - var expected: EntityInfo[] = JSON.parse(JSON.stringify(entities)); + const expected: EntityInfo[] = JSON.parse(JSON.stringify(entities)); expected[0].Columns.push({ lenght: null, default: 'a', - is_nullable: true, + isNullable: true, isPrimary: false, - is_generated: true, + isGenerated: true, tsName: 'name', sqlName: 'name', numericPrecision: null, numericScale: null, width: null, - sql_type: 'int', - ts_type: 'number', + sqlType: 'int', + tsType: 'number', enumOptions: null, - is_unique:false, - is_array:false, - relations: [], + isUnique:false, + isArray:false, + relations: [] as RelationInfo[], }) - let result = await driver.GetCoulmnsFromEntity(entities, 'schema'); + const result = await driver.GetCoulmnsFromEntity(entities, 'schema'); expect(result).to.be.deep.equal(expected) }) it('should find primary indexes') diff --git a/test/integration/entityTypes.test.ts b/test/integration/entityTypes.test.ts index 10e570f..aa3fc63 100644 --- a/test/integration/entityTypes.test.ts +++ b/test/integration/entityTypes.test.ts @@ -1,41 +1,41 @@ require('dotenv').config() -import "reflect-metadata"; +import { expect } from "chai"; import fs = require('fs-extra'); import path = require('path') -import { expect } from "chai"; +import "reflect-metadata"; import { EntityFileToJson } from "../utils/EntityFileToJson"; -var chai = require('chai'); -var chaiSubset = require('chai-subset'); +const chai = require('chai'); +const chaiSubset = require('chai-subset'); import * as ts from "typescript"; -import * as GTU from "../utils/GeneralTestUtils" import { Engine } from "../../src/Engine"; +import * as GTU from "../utils/GeneralTestUtils" chai.use(chaiSubset); describe("Platform specyfic types", async function () { this.timeout(30000) - this.slow(5000)//compiling created models takes time + this.slow(5000)// compiling created models takes time - let dbDrivers: string[] = [] - if (process.env.SQLITE_Skip == '0') dbDrivers.push('sqlite') - if (process.env.POSTGRES_Skip == '0') dbDrivers.push('postgres') - if (process.env.MYSQL_Skip == '0') dbDrivers.push('mysql') - if (process.env.MARIADB_Skip == '0') dbDrivers.push('mariadb') - if (process.env.MSSQL_Skip == '0') dbDrivers.push('mssql') - if (process.env.ORACLE_Skip == '0') dbDrivers.push('oracle') + const dbDrivers: string[] = [] + if (process.env.SQLITE_Skip == '0') { dbDrivers.push('sqlite') } + if (process.env.POSTGRES_Skip == '0') { dbDrivers.push('postgres') } + if (process.env.MYSQL_Skip == '0') { dbDrivers.push('mysql') } + if (process.env.MARIADB_Skip == '0') { dbDrivers.push('mariadb') } + if (process.env.MSSQL_Skip == '0') { dbDrivers.push('mssql') } + if (process.env.ORACLE_Skip == '0') { dbDrivers.push('oracle') } - let examplesPathJS = path.resolve(process.cwd(), 'dist/test/integration/entityTypes') - let examplesPathTS = path.resolve(process.cwd(), 'test/integration/entityTypes') - let files = fs.readdirSync(examplesPathTS) + const examplesPathJS = path.resolve(process.cwd(), 'dist/test/integration/entityTypes') + const examplesPathTS = path.resolve(process.cwd(), 'test/integration/entityTypes') + const files = fs.readdirSync(examplesPathTS) - for (let dbDriver of dbDrivers) { - for (let folder of files) { + for (const dbDriver of dbDrivers) { + for (const folder of files) { if (dbDriver == folder) { it(dbDriver, async function () { - let filesOrgPathJS = path.resolve(examplesPathJS, folder, 'entity') - let filesOrgPathTS = path.resolve(examplesPathTS, folder, 'entity') - let resultsPath = path.resolve(process.cwd(), `output`) + const filesOrgPathJS = path.resolve(examplesPathJS, folder, 'entity') + const filesOrgPathTS = path.resolve(examplesPathTS, folder, 'entity') + const resultsPath = path.resolve(process.cwd(), `output`) fs.removeSync(resultsPath) let engine: Engine; @@ -60,29 +60,27 @@ describe("Platform specyfic types", async function () { break; default: console.log(`Unknown engine type`); - engine = {} + engine = {} as Engine break; } await engine.createModelFromDatabase() - let filesGenPath = path.resolve(resultsPath, 'entities') + const filesGenPath = path.resolve(resultsPath, 'entities') - let filesOrg = fs.readdirSync(filesOrgPathTS).filter(function (this, val, ind, arr) { return val.toString().endsWith('.ts') }) - let filesGen = fs.readdirSync(filesGenPath).filter(function (this, val, ind, arr) { return val.toString().endsWith('.ts') }) + const filesOrg = fs.readdirSync(filesOrgPathTS).filter((val) => val.toString().endsWith('.ts')) + const filesGen = fs.readdirSync(filesGenPath).filter((val) => val.toString().endsWith('.ts')) expect(filesOrg, 'Errors detected in model comparision').to.be.deep.equal(filesGen) - for (let file of filesOrg) { - let entftj = new EntityFileToJson(); - let jsonEntityOrg = entftj.convert(fs.readFileSync(path.resolve(filesOrgPathTS, file))) - let jsonEntityGen = entftj.convert(fs.readFileSync(path.resolve(filesGenPath, file))) + for (const file of filesOrg) { + const entftj = new EntityFileToJson(); + const jsonEntityOrg = entftj.convert(fs.readFileSync(path.resolve(filesOrgPathTS, file))) + const jsonEntityGen = entftj.convert(fs.readFileSync(path.resolve(filesGenPath, file))) expect(jsonEntityGen, `Error in file ${file}`).to.containSubset(jsonEntityOrg) } const currentDirectoryFiles = fs.readdirSync(filesGenPath). - filter(fileName => fileName.length >= 3 && fileName.substr(fileName.length - 3, 3) === ".ts").map(v => { - return path.resolve(filesGenPath, v) - }) - let compileErrors = GTU.compileTsFiles(currentDirectoryFiles, { + filter(fileName => fileName.length >= 3 && fileName.substr(fileName.length - 3, 3) === ".ts").map(v => path.resolve(filesGenPath, v)) + const compileErrors = GTU.compileTsFiles(currentDirectoryFiles, { experimentalDecorators: true, sourceMap: false, emitDecoratorMetadata: true, diff --git a/test/integration/githubIssues.test.ts b/test/integration/githubIssues.test.ts index 1c348ed..1b33c4b 100644 --- a/test/integration/githubIssues.test.ts +++ b/test/integration/githubIssues.test.ts @@ -1,14 +1,14 @@ require('dotenv').config() -import "reflect-metadata"; -import { createConnection, ConnectionOptions, Connection } from "typeorm"; +import { expect } from "chai"; import fs = require('fs-extra'); import path = require('path') -import { Engine } from "../../src/Engine"; -import { expect } from "chai"; +import "reflect-metadata"; import * as Sinon from 'sinon' +import { Connection, ConnectionOptions, createConnection } from "typeorm"; +import { Engine } from "../../src/Engine"; import { EntityFileToJson } from "../utils/EntityFileToJson"; -var chai = require('chai'); -var chaiSubset = require('chai-subset'); +const chai = require('chai'); +const chaiSubset = require('chai-subset'); import * as ts from "typescript"; import * as GTU from "../utils/GeneralTestUtils" @@ -17,29 +17,30 @@ chai.use(chaiSubset); describe("GitHub issues", async function () { this.timeout(30000) - this.slow(5000)//compiling created models takes time + this.slow(5000)// compiling created models takes time - let dbDrivers: string[] = [] - if (process.env.SQLITE_Skip == '0') dbDrivers.push('sqlite') - if (process.env.POSTGRES_Skip == '0') dbDrivers.push('postgres') - if (process.env.MYSQL_Skip == '0') dbDrivers.push('mysql') - if (process.env.MARIADB_Skip == '0') dbDrivers.push('mariadb') - if (process.env.MSSQL_Skip == '0') dbDrivers.push('mssql') - if (process.env.ORACLE_Skip == '0') dbDrivers.push('oracle') + const dbDrivers: string[] = [] + if (process.env.SQLITE_Skip == '0') { dbDrivers.push('sqlite') } + if (process.env.POSTGRES_Skip == '0') { dbDrivers.push('postgres') } + if (process.env.MYSQL_Skip == '0') { dbDrivers.push('mysql') } + if (process.env.MARIADB_Skip == '0') { dbDrivers.push('mariadb') } + if (process.env.MSSQL_Skip == '0') { dbDrivers.push('mssql') } + if (process.env.ORACLE_Skip == '0') { dbDrivers.push('oracle') } - let examplesPathJS = path.resolve(process.cwd(), 'dist/test/integration/github-issues') - let examplesPathTS = path.resolve(process.cwd(), 'test/integration/github-issues') - let files = fs.readdirSync(examplesPathTS) + const examplesPathJS = path.resolve(process.cwd(), 'dist/test/integration/github-issues') + const examplesPathTS = path.resolve(process.cwd(), 'test/integration/github-issues') + const files = fs.readdirSync(examplesPathTS) - for (let folder of files) { + for (const folder of files) { describe(`#${folder}`, async function () { - for (let dbDriver of dbDrivers) { + for (const dbDriver of dbDrivers) { switch (folder) { case '39': - if (dbDriver == 'mysql' || dbDriver == 'mariadb' || dbDriver == 'oracle' || dbDriver == 'sqlite') + if (dbDriver == 'mysql' || dbDriver == 'mariadb' || dbDriver == 'oracle' || dbDriver == 'sqlite') { continue; + } break; default: break; @@ -47,9 +48,9 @@ describe("GitHub issues", async function () { it(dbDriver, async function () { - let filesOrgPathJS = path.resolve(examplesPathJS, folder, 'entity') - let filesOrgPathTS = path.resolve(examplesPathTS, folder, 'entity') - let resultsPath = path.resolve(process.cwd(), `output`) + const filesOrgPathJS = path.resolve(examplesPathJS, folder, 'entity') + const filesOrgPathTS = path.resolve(examplesPathTS, folder, 'entity') + const resultsPath = path.resolve(process.cwd(), `output`) fs.removeSync(resultsPath) let engine: Engine; @@ -74,7 +75,7 @@ describe("GitHub issues", async function () { break; default: console.log(`Unknown engine type`); - engine = {} + engine = {} as Engine break; } @@ -87,24 +88,22 @@ describe("GitHub issues", async function () { } await engine.createModelFromDatabase() - let filesGenPath = path.resolve(resultsPath, 'entities') + const filesGenPath = path.resolve(resultsPath, 'entities') - let filesOrg = fs.readdirSync(filesOrgPathTS).filter(function (this, val) { return val.toString().endsWith('.ts') }) - let filesGen = fs.readdirSync(filesGenPath).filter(function (this, val) { return val.toString().endsWith('.ts') }) + const filesOrg = fs.readdirSync(filesOrgPathTS).filter((val) => val.toString().endsWith('.ts')) + const filesGen = fs.readdirSync(filesGenPath).filter((val) => val.toString().endsWith('.ts')) expect(filesOrg, 'Errors detected in model comparision').to.be.deep.equal(filesGen) - for (let file of filesOrg) { - let entftj = new EntityFileToJson(); - let jsonEntityOrg = entftj.convert(fs.readFileSync(path.resolve(filesOrgPathTS, file))) - let jsonEntityGen = entftj.convert(fs.readFileSync(path.resolve(filesGenPath, file))) + for (const file of filesOrg) { + const entftj = new EntityFileToJson(); + const jsonEntityOrg = entftj.convert(fs.readFileSync(path.resolve(filesOrgPathTS, file))) + const jsonEntityGen = entftj.convert(fs.readFileSync(path.resolve(filesGenPath, file))) expect(jsonEntityGen, `Error in file ${file}`).to.containSubset(jsonEntityOrg) } const currentDirectoryFiles = fs.readdirSync(filesGenPath). - filter(fileName => fileName.length >= 3 && fileName.substr(fileName.length - 3, 3) === ".ts").map(v => { - return path.resolve(filesGenPath, v) - }) - let compileErrors = GTU.compileTsFiles(currentDirectoryFiles, { + filter(fileName => fileName.length >= 3 && fileName.substr(fileName.length - 3, 3) === ".ts").map(v => path.resolve(filesGenPath, v)) + const compileErrors = GTU.compileTsFiles(currentDirectoryFiles, { experimentalDecorators: true, sourceMap: false, emitDecoratorMetadata: true, diff --git a/test/integration/integration.test.ts b/test/integration/integration.test.ts index d75bb1a..516d88c 100644 --- a/test/integration/integration.test.ts +++ b/test/integration/integration.test.ts @@ -1,12 +1,12 @@ require('dotenv').config() -import "reflect-metadata"; +import { expect } from "chai"; import fs = require('fs-extra'); import path = require('path') +import "reflect-metadata"; import { Engine } from "../../src/Engine"; -import { expect } from "chai"; import { EntityFileToJson } from "../utils/EntityFileToJson"; -var chai = require('chai'); -var chaiSubset = require('chai-subset'); +const chai = require('chai'); +const chaiSubset = require('chai-subset'); import * as ts from "typescript"; import * as GTU from "../utils/GeneralTestUtils" @@ -14,27 +14,27 @@ chai.use(chaiSubset); describe("TypeOrm examples", async function () { this.timeout(30000) - this.slow(5000)//compiling created models takes time + this.slow(5000)// compiling created models takes time - let dbDrivers: string[] = [] - if (process.env.SQLITE_Skip == '0') dbDrivers.push('sqlite') - if (process.env.POSTGRES_Skip == '0') dbDrivers.push('postgres') - if (process.env.MYSQL_Skip == '0') dbDrivers.push('mysql') - if (process.env.MARIADB_Skip == '0') dbDrivers.push('mariadb') - if (process.env.MSSQL_Skip == '0') dbDrivers.push('mssql') - if (process.env.ORACLE_Skip == '0') dbDrivers.push('oracle') + const dbDrivers: string[] = [] + if (process.env.SQLITE_Skip == '0') { dbDrivers.push('sqlite') } + if (process.env.POSTGRES_Skip == '0') { dbDrivers.push('postgres') } + if (process.env.MYSQL_Skip == '0') { dbDrivers.push('mysql') } + if (process.env.MARIADB_Skip == '0') { dbDrivers.push('mariadb') } + if (process.env.MSSQL_Skip == '0') { dbDrivers.push('mssql') } + if (process.env.ORACLE_Skip == '0') { dbDrivers.push('oracle') } - let examplesPathJS = path.resolve(process.cwd(), 'dist/test/integration/examples') - let examplesPathTS = path.resolve(process.cwd(), 'test/integration/examples') - let files = fs.readdirSync(examplesPathTS) + const examplesPathJS = path.resolve(process.cwd(), 'dist/test/integration/examples') + const examplesPathTS = path.resolve(process.cwd(), 'test/integration/examples') + const files = fs.readdirSync(examplesPathTS) - for (let folder of files) { + for (const folder of files) { describe(folder, async function () { - for (let dbDriver of dbDrivers) { + for (const dbDriver of dbDrivers) { it(dbDriver, async function () { - let filesOrgPathJS = path.resolve(examplesPathJS, folder, 'entity') - let filesOrgPathTS = path.resolve(examplesPathTS, folder, 'entity') - let resultsPath = path.resolve(process.cwd(), `output`) + const filesOrgPathJS = path.resolve(examplesPathJS, folder, 'entity') + const filesOrgPathTS = path.resolve(examplesPathTS, folder, 'entity') + const resultsPath = path.resolve(process.cwd(), `output`) fs.removeSync(resultsPath) let engine: Engine; @@ -59,7 +59,7 @@ describe("TypeOrm examples", async function () { break; default: console.log(`Unknown engine type`); - engine = {} + engine = {} as Engine break; } if (folder == 'sample18-lazy-relations') { @@ -67,24 +67,22 @@ describe("TypeOrm examples", async function () { } await engine.createModelFromDatabase() - let filesGenPath = path.resolve(resultsPath, 'entities') + const filesGenPath = path.resolve(resultsPath, 'entities') - let filesOrg = fs.readdirSync(filesOrgPathTS).filter(function (this, val) { return val.toString().endsWith('.ts') }) - let filesGen = fs.readdirSync(filesGenPath).filter(function (this, val) { return val.toString().endsWith('.ts') }) + const filesOrg = fs.readdirSync(filesOrgPathTS).filter((val) => val.toString().endsWith('.ts')) + const filesGen = fs.readdirSync(filesGenPath).filter((val) => val.toString().endsWith('.ts')) expect(filesOrg, 'Errors detected in model comparision').to.be.deep.equal(filesGen) - for (let file of filesOrg) { - let entftj = new EntityFileToJson(); - let jsonEntityOrg = entftj.convert(fs.readFileSync(path.resolve(filesOrgPathTS, file))) - let jsonEntityGen = entftj.convert(fs.readFileSync(path.resolve(filesGenPath, file))) + for (const file of filesOrg) { + const entftj = new EntityFileToJson(); + const jsonEntityOrg = entftj.convert(fs.readFileSync(path.resolve(filesOrgPathTS, file))) + const jsonEntityGen = entftj.convert(fs.readFileSync(path.resolve(filesGenPath, file))) expect(jsonEntityGen, `Error in file ${file}`).to.containSubset(jsonEntityOrg) } const currentDirectoryFiles = fs.readdirSync(filesGenPath). - filter(fileName => fileName.length >= 3 && fileName.substr(fileName.length - 3, 3) === ".ts").map(v => { - return path.resolve(filesGenPath, v) - }) - let compileErrors = GTU.compileTsFiles(currentDirectoryFiles, { + filter(fileName => fileName.length >= 3 && fileName.substr(fileName.length - 3, 3) === ".ts").map(v => path.resolve(filesGenPath, v)) + const compileErrors = GTU.compileTsFiles(currentDirectoryFiles, { experimentalDecorators: true, sourceMap: false, emitDecoratorMetadata: true, diff --git a/test/utils/EntityFileToJson.ts b/test/utils/EntityFileToJson.ts index 89c6d84..1a88308 100644 --- a/test/utils/EntityFileToJson.ts +++ b/test/utils/EntityFileToJson.ts @@ -1,11 +1,9 @@ export class EntityFileToJson { - getEntityOptions(trimmedLine: string, ent: EntityJson) { - let decoratorParameters = trimmedLine.slice(trimmedLine.indexOf('(') + 1, trimmedLine.lastIndexOf(')')) + public getEntityOptions(trimmedLine: string, ent: EntityJson) { + const decoratorParameters = trimmedLine.slice(trimmedLine.indexOf('(') + 1, trimmedLine.lastIndexOf(')')) if (decoratorParameters.length > 0) { - if (decoratorParameters[0] == '"' && decoratorParameters.endsWith('"')) { - - } else { + if (decoratorParameters[0] != '"' || !decoratorParameters.endsWith('"')) { 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] @@ -14,14 +12,12 @@ export class EntityFileToJson { } } } - getColumnOptionsAndType(trimmedLine: string, col: EntityColumn) { - let decoratorParameters = trimmedLine.slice(trimmedLine.indexOf('(') + 1, trimmedLine.lastIndexOf(')')) - let primaryGeneratedColumn = trimmedLine.substring(0, trimmedLine.indexOf('('))=='@PrimaryGeneratedColumn' + public getColumnOptionsAndType(trimmedLine: string, col: EntityColumn) { + const decoratorParameters = trimmedLine.slice(trimmedLine.indexOf('(') + 1, trimmedLine.lastIndexOf(')')) + const primaryGeneratedColumn = trimmedLine.substring(0, trimmedLine.indexOf('('))=='@PrimaryGeneratedColumn' if (decoratorParameters.length > 0) { if (decoratorParameters.search(',') > 0 && !primaryGeneratedColumn) { - col.columnTypes = decoratorParameters.substring(0, decoratorParameters.indexOf(',')).trim().split('|').map(function (x) { - return x; - }); + col.columnTypes = decoratorParameters.substring(0, decoratorParameters.indexOf(',')).trim().split('|'); 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] @@ -29,10 +25,7 @@ export class EntityFileToJson { col.columnOptions = JSON.parse(badJSON.replace(/(['"])?([a-z0-9A-Z_]+)(['"])?:/g, '"$2": ')) } else { if (decoratorParameters[0] == '"' && decoratorParameters.endsWith('"')) { - col.columnTypes = decoratorParameters.split('|').map(function (x) { - x = x.trim(); - return x; - }); + col.columnTypes = decoratorParameters.split('|').map( x=>x.trim()) } else { let badJSON = !primaryGeneratedColumn ? decoratorParameters.substring(decoratorParameters.indexOf(',') + 1) : decoratorParameters badJSON = badJSON.trim() @@ -44,33 +37,31 @@ export class EntityFileToJson { } } } - getRelationOptions(trimmedLine:string, col:EntityColumn){ - let decoratorParameters = trimmedLine.slice(trimmedLine.indexOf('(') + 1, trimmedLine.lastIndexOf(')')) + public getRelationOptions(trimmedLine:string, col:EntityColumn){ + const decoratorParameters = trimmedLine.slice(trimmedLine.indexOf('(') + 1, trimmedLine.lastIndexOf(')')) if (decoratorParameters.length > 0) { - let params = decoratorParameters.match(/(,)(?!([^{]*}))/g) + const params = decoratorParameters.match(/(,)(?!([^{]*}))/g) if ( params && params.length == 2) { let badJSON = decoratorParameters.substring( decoratorParameters.lastIndexOf('{'),decoratorParameters.lastIndexOf('}')+1).trim() if (badJSON.lastIndexOf(',') == badJSON.length - 3) { badJSON = badJSON.slice(0, badJSON.length - 3) + badJSON[badJSON.length - 2] + badJSON[badJSON.length - 1] } col.columnOptions = JSON.parse(badJSON.replace(/(')/g,`"`).replace(/(['"])?([a-z0-9A-Z_]+)(['"])?:/g, '"$2": ')) - } else { - } } } - getIndexOptions(trimmedLine: string, ind: EntityIndex) { - let decoratorParameters = trimmedLine.slice(trimmedLine.indexOf('(') + 1, trimmedLine.lastIndexOf(')')) + public getIndexOptions(trimmedLine: string, ind: EntityIndex) { + const decoratorParameters = trimmedLine.slice(trimmedLine.indexOf('(') + 1, trimmedLine.lastIndexOf(')')) if (decoratorParameters.length > 0) { - let containsTables = decoratorParameters.search('\\[') > -1 - let containsOptions = decoratorParameters.search('{') > -1 - let containsName = decoratorParameters.search('"') > -1//TODO:no name, but fields as string[] + const containsTables = decoratorParameters.search('\\[') > -1 + const containsOptions = decoratorParameters.search('{') > -1 + const containsName = decoratorParameters.search('"') > -1 if (containsName) { ind.indexName = decoratorParameters.slice(decoratorParameters.indexOf('"') + 1, decoratorParameters.substr(decoratorParameters.indexOf('"') + 1).indexOf('"')) } if (containsTables) { - let columnsStr = decoratorParameters.slice(decoratorParameters.indexOf('[') + 1, decoratorParameters.indexOf(']')) + const columnsStr = decoratorParameters.slice(decoratorParameters.indexOf('[') + 1, decoratorParameters.indexOf(']')) ind.columnNames.push(...columnsStr.split(',').map((val) => { let colName = '' if (val.search('\\.') > -1) { @@ -79,12 +70,10 @@ export class EntityFileToJson { colName = val.slice(val.indexOf('"') + 1, val.lastIndexOf('"')) } return colName - }).filter(v => { - return v.length > 0 - })) + }).filter(v => v.length > 0)) } if (containsOptions) { - let optionsStr = decoratorParameters.slice(decoratorParameters.indexOf('{') + 1, decoratorParameters.indexOf('}')) + const optionsStr = decoratorParameters.slice(decoratorParameters.indexOf('{') + 1, decoratorParameters.indexOf('}')) optionsStr.split(',').forEach((v) => { if (v.split(':').length - 1 > 0) { switch (optionsStr.split(':')[0].trim()) { @@ -102,23 +91,25 @@ export class EntityFileToJson { } } - convert(entityFile: Buffer): EntityJson { - let retVal = new EntityJson(); + public convert(entityFile: Buffer): EntityJson { + const retVal = new EntityJson(); let isInClassBody = false; let isMultilineStatement = false; let priorPartOfMultilineStatement = ''; - let lines = entityFile.toString().replace('\r', '').split('\n'); - for (let line of lines) { + const lines = entityFile.toString().replace('\r', '').split('\n'); + for (const line of lines) { let trimmedLine = line.trim(); if (trimmedLine.startsWith('//')) { continue; } - if (isMultilineStatement) + if (isMultilineStatement) { trimmedLine = priorPartOfMultilineStatement + ' ' + trimmedLine - if (trimmedLine.length == 0) + } + if (trimmedLine.length == 0) { continue; + } else if (!isInClassBody) { if (trimmedLine.startsWith('import')) { continue; @@ -142,7 +133,7 @@ export class EntityFileToJson { continue; } else { isMultilineStatement = false; - let ind = new EntityIndex() + const ind = new EntityIndex() this.getIndexOptions(trimmedLine, ind) retVal.indicies.push(ind); continue; @@ -156,7 +147,7 @@ export class EntityFileToJson { continue; } else { isMultilineStatement = false; - let col = new EntityColumn() + const col = new EntityColumn() this.getColumnOptionsAndType(trimmedLine, col) retVal.columns.push(col); continue; @@ -168,9 +159,9 @@ export class EntityFileToJson { continue; } else { isMultilineStatement = false; - let col = new EntityColumn() + const col = new EntityColumn() this.getColumnOptionsAndType(trimmedLine, col) - col.columnOptions['primary'] = true + col.columnOptions.primary = true retVal.columns.push(col); continue; } @@ -181,7 +172,7 @@ export class EntityFileToJson { continue; } else { isMultilineStatement = false; - let col = new EntityColumn() + const col = new EntityColumn() this.getColumnOptionsAndType(trimmedLine, col) retVal.columns.push(col); continue; @@ -193,10 +184,10 @@ export class EntityFileToJson { continue; } else { isMultilineStatement = false; - let col = new EntityColumn() + const col = new EntityColumn() this.getColumnOptionsAndType(trimmedLine, col) - col.columnOptions['primary'] = true - col.columnOptions['generated'] = true + col.columnOptions.primary = true + col.columnOptions.generated = true retVal.columns.push(col); continue; } @@ -207,7 +198,7 @@ export class EntityFileToJson { continue; } else { isMultilineStatement = false; - let column = new EntityColumn() + const column = new EntityColumn() retVal.columns.push(column) column.relationType = "ManyToOne" column.isOwnerOfRelation = true; @@ -220,7 +211,7 @@ export class EntityFileToJson { continue; } else { isMultilineStatement = false; - let column = new EntityColumn() + const column = new EntityColumn() retVal.columns.push(column) column.relationType = "OneToMany" continue; @@ -232,7 +223,7 @@ export class EntityFileToJson { continue; } else { isMultilineStatement = false; - let column = new EntityColumn() + const column = new EntityColumn() retVal.columns.push(column) column.relationType = "ManyToMany" continue; @@ -244,7 +235,7 @@ export class EntityFileToJson { continue; } else { isMultilineStatement = false; - let column = new EntityColumn() + const column = new EntityColumn() retVal.columns.push(column) column.relationType = "OneToOne" this.getRelationOptions(trimmedLine,column); @@ -277,7 +268,7 @@ export class EntityFileToJson { continue; } else { isMultilineStatement = false; - let ind = new EntityIndex() + const ind = new EntityIndex() this.getIndexOptions(trimmedLine, ind) retVal.indicies.push(ind); continue; @@ -293,7 +284,7 @@ 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? + // TODO:Should check if null only column is nullable? let colTypes=trimmedLine.split(':')[1].split(';')[0].trim(); if (colTypes.startsWith('Promise<')) { colTypes=colTypes.substring(8,colTypes.length-1) @@ -301,15 +292,15 @@ export class EntityFileToJson { } retVal.columns[retVal.columns.length - 1].columnTypes = colTypes.split('|').map(function (x) { if (x == 'any') { - x = 'string' //for json columns + x = 'string' // for json columns } x = x.trim(); return x; }); - if (!retVal.columns[retVal.columns.length - 1].columnTypes.some(function (this, val, ind, arr) { - return val == "null" ? true : false; - })) retVal.columns[retVal.columns.length - 1].columnTypes.push('null') + if (!retVal.columns[retVal.columns.length - 1].columnTypes.some( (val) => val == "null" ? true : false)) { + retVal.columns[retVal.columns.length - 1].columnTypes.push('null') + } if (retVal.indicies.length > 0 && retVal.indicies[retVal.indicies.length - 1].columnNames.length == 0) { retVal.indicies[retVal.indicies.length - 1].columnNames.push(retVal.columns[retVal.columns.length - 1].columnName) } @@ -328,41 +319,43 @@ export class EntityFileToJson { } retVal.columns = retVal.columns.map(col => { - if (col.columnName.endsWith('Id')) + if (col.columnName.endsWith('Id')) { col.columnName = col.columnName.substr(0, col.columnName.length - 2) + } return col; }) retVal.indicies = retVal.indicies.map(ind => { ind.columnNames = ind.columnNames.map(colName => { - if (colName.endsWith('Id')) + if (colName.endsWith('Id')) { colName = colName.substr(0, colName.length - 2) + } return colName; }) return ind; }) return retVal; } - isPartOfMultilineStatement(statement: string) { - let matchStarting = statement.split('(').length+statement.split('{').length - let matchEnding = statement.split(')').length+statement.split('}').length + public isPartOfMultilineStatement(statement: string) { + const matchStarting = statement.split('(').length+statement.split('{').length + const matchEnding = statement.split(')').length+statement.split('}').length return !(matchStarting == matchEnding) } } class EntityJson { - entityName: string - entityOptions: any = {} - columns: EntityColumn[] = []; - indicies: EntityIndex[] = []; + public entityName: string + public entityOptions: any = {} + public columns: EntityColumn[] = [] as EntityColumn[]; + public indicies: EntityIndex[] = [] as EntityIndex[]; } class EntityColumn { - columnName: string - columnTypes: string[] = [] - columnOptions: any = {} - relationType: "OneToOne" | "OneToMany" | "ManyToOne" | "ManyToMany" | "None" = "None" - isOwnerOfRelation: boolean = false; + public columnName: string + public columnTypes: string[] = [] + public columnOptions: any = {} + public relationType: "OneToOne" | "OneToMany" | "ManyToOne" | "ManyToMany" | "None" = "None" + public isOwnerOfRelation: boolean = false; } class EntityIndex { - indexName: string - columnNames: string[] = [] - isUnique: boolean = false + public indexName: string + public columnNames: string[] = [] + public isUnique: boolean = false } diff --git a/test/utils/GeneralTestUtils.ts b/test/utils/GeneralTestUtils.ts index f895b76..e3c3c47 100644 --- a/test/utils/GeneralTestUtils.ts +++ b/test/utils/GeneralTestUtils.ts @@ -1,16 +1,16 @@ +import path = require('path') +import { ConnectionOptions, createConnection } from "typeorm"; import * as ts from "typescript"; +import * as yn from "yn" +import { AbstractNamingStrategy } from "../../src/AbstractNamingStrategy"; import { AbstractDriver } from "../../src/drivers/AbstractDriver"; -import { MssqlDriver } from "../../src/drivers/MssqlDriver"; -import { PostgresDriver } from "../../src/drivers/PostgresDriver"; -import { MysqlDriver } from "../../src/drivers/MysqlDriver"; import { MariaDbDriver } from "../../src/drivers/MariaDbDriver"; +import { MssqlDriver } from "../../src/drivers/MssqlDriver"; +import { MysqlDriver } from "../../src/drivers/MysqlDriver"; import { OracleDriver } from "../../src/drivers/OracleDriver"; +import { PostgresDriver } from "../../src/drivers/PostgresDriver"; import { SqliteDriver } from "../../src/drivers/SqliteDriver"; import { Engine } from "../../src/Engine"; -import { createConnection, ConnectionOptions } from "typeorm"; -import * as yn from "yn" -import path = require('path') -import { AbstractNamingStrategy } from "../../src/AbstractNamingStrategy"; import { NamingStrategy } from "../../src/NamingStrategy"; export async function createMSSQLModels(filesOrgPath: string, resultsPath: string): Promise { @@ -19,12 +19,13 @@ 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))) + 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 = { + const connOpt: ConnectionOptions = { database: String(process.env.MSSQL_Database), host: String(process.env.MSSQL_Host), password: String(process.env.MSSQL_Password), @@ -36,7 +37,7 @@ export async function createMSSQLModels(filesOrgPath: string, resultsPath: strin entities: [path.resolve(filesOrgPath, '*.js')], } - let schemas = 'dbo,sch1,sch2' + const schemas = 'dbo,sch1,sch2' let conn = await createConnection(connOpt) let queryRunner = conn.createQueryRunner() for (const sch of schemas.split(',')) { @@ -44,13 +45,14 @@ export async function createMSSQLModels(filesOrgPath: string, resultsPath: strin } await conn.synchronize(); - if (conn.isConnected) + if (conn.isConnected) { await conn.close() + } - let namingStrategy: AbstractNamingStrategy = new NamingStrategy(); + const namingStrategy: AbstractNamingStrategy = new NamingStrategy(); driver = new MssqlDriver(); - let engine = new Engine( + const engine = new Engine( driver, { host: String(process.env.MSSQL_Host), port: Number(process.env.MSSQL_Port), @@ -58,7 +60,7 @@ export async function createMSSQLModels(filesOrgPath: string, resultsPath: strin user: String(process.env.MSSQL_Username), password: String(process.env.MSSQL_Password), databaseType: 'mssql', - resultsPath: resultsPath, + resultsPath, schemaName: 'dbo,sch1,sch2', ssl: yn(process.env.MSSQL_SSL), noConfigs: false, @@ -68,7 +70,7 @@ export async function createMSSQLModels(filesOrgPath: string, resultsPath: strin propertyVisibility: 'none', lazy: false, constructor: false, - namingStrategy: namingStrategy, + namingStrategy, relationIds: false }); @@ -78,8 +80,9 @@ export async function createMSSQLModels(filesOrgPath: string, resultsPath: strin await queryRunner.createSchema(sch, true); } await conn.synchronize(); - if (conn.isConnected) + if (conn.isConnected) { await conn.close() + } return engine; } @@ -89,12 +92,13 @@ 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))) + 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 = { + const connOpt: ConnectionOptions = { database: String(process.env.POSTGRES_Database), host: String(process.env.POSTGRES_Host), password: String(process.env.POSTGRES_Password), @@ -106,7 +110,7 @@ export async function createPostgresModels(filesOrgPath: string, resultsPath: st entities: [path.resolve(filesOrgPath, '*.js')], } - let schemas = 'public,sch1,sch2' + const schemas = 'public,sch1,sch2' let conn = await createConnection(connOpt) let queryRunner = conn.createQueryRunner() for (const sch of schemas.split(',')) { @@ -114,12 +118,13 @@ export async function createPostgresModels(filesOrgPath: string, resultsPath: st } await conn.synchronize(); - if (conn.isConnected) + if (conn.isConnected) { await conn.close() - let namingStrategy: AbstractNamingStrategy = new NamingStrategy(); + } + const namingStrategy: AbstractNamingStrategy = new NamingStrategy(); driver = new PostgresDriver(); - let engine = new Engine( + const engine = new Engine( driver, { host: String(process.env.POSTGRES_Host), port: Number(process.env.POSTGRES_Port), @@ -127,7 +132,7 @@ export async function createPostgresModels(filesOrgPath: string, resultsPath: st user: String(process.env.POSTGRES_Username), password: String(process.env.POSTGRES_Password), databaseType: 'postgres', - resultsPath: resultsPath, + resultsPath, schemaName: 'public,sch1,sch2', ssl: yn(process.env.POSTGRES_SSL), noConfigs: false, @@ -137,7 +142,7 @@ export async function createPostgresModels(filesOrgPath: string, resultsPath: st propertyVisibility: 'none', lazy: false, constructor: false, - namingStrategy: namingStrategy, + namingStrategy, relationIds: false }); @@ -147,8 +152,9 @@ export async function createPostgresModels(filesOrgPath: string, resultsPath: st await queryRunner.createSchema(sch, true); } await conn.synchronize(); - if (conn.isConnected) + if (conn.isConnected) { await conn.close() + } return engine; } @@ -158,12 +164,13 @@ export async function createSQLiteModels(filesOrgPath: string, resultsPath: stri driver = new SqliteDriver(); await driver.ConnectToServer(String(process.env.SQLITE_Database), '', 0, '', '', false); - if (await driver.CheckIfDBExists(String(process.env.SQLITE_Database))) + if (await driver.CheckIfDBExists(String(process.env.SQLITE_Database))) { await driver.DropDB(String(process.env.SQLITE_Database)); + } await driver.CreateDB(String(process.env.SQLITE_Database)); await driver.DisconnectFromServer(); - let connOpt: ConnectionOptions = { + const connOpt: ConnectionOptions = { database: String(process.env.SQLITE_Database), type: 'sqlite', dropSchema: true, @@ -175,12 +182,13 @@ export async function createSQLiteModels(filesOrgPath: string, resultsPath: stri let queryRunner = conn.createQueryRunner() await conn.synchronize(); - if (conn.isConnected) + if (conn.isConnected) { await conn.close() - let namingStrategy: AbstractNamingStrategy = new NamingStrategy(); + } + const namingStrategy: AbstractNamingStrategy = new NamingStrategy(); driver = new SqliteDriver(); - let engine = new Engine( + const engine = new Engine( driver, { host: '', port: 0, @@ -188,7 +196,7 @@ export async function createSQLiteModels(filesOrgPath: string, resultsPath: stri user: '', password: '', databaseType: 'sqlite', - resultsPath: resultsPath, + resultsPath, schemaName: '', ssl: false, noConfigs: false, @@ -198,15 +206,16 @@ export async function createSQLiteModels(filesOrgPath: string, resultsPath: stri propertyVisibility: 'none', lazy: false, constructor: false, - namingStrategy: namingStrategy, + namingStrategy, relationIds: false }); conn = await createConnection(connOpt) queryRunner = conn.createQueryRunner() await conn.synchronize(); - if (conn.isConnected) + if (conn.isConnected) { await conn.close() + } return engine; } @@ -216,12 +225,13 @@ 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))) + 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 = { + const connOpt: ConnectionOptions = { database: String(process.env.MYSQL_Database), host: String(process.env.MYSQL_Host), password: String(process.env.MYSQL_Password), @@ -232,14 +242,15 @@ export async function createMysqlModels(filesOrgPath: string, resultsPath: strin synchronize: true, entities: [path.resolve(filesOrgPath, '*.js')], } - let conn = await createConnection(connOpt) + const conn = await createConnection(connOpt) - if (conn.isConnected) + if (conn.isConnected) { await conn.close() - let namingStrategy: AbstractNamingStrategy = new NamingStrategy(); + } + const namingStrategy: AbstractNamingStrategy = new NamingStrategy(); driver = new MysqlDriver(); - let engine = new Engine( + const engine = new Engine( driver, { host: String(process.env.MYSQL_Host), port: Number(process.env.MYSQL_Port), @@ -247,7 +258,7 @@ export async function createMysqlModels(filesOrgPath: string, resultsPath: strin user: String(process.env.MYSQL_Username), password: String(process.env.MYSQL_Password), databaseType: 'mysql', - resultsPath: resultsPath, + resultsPath, schemaName: 'ignored', ssl: yn(process.env.MYSQL_SSL), noConfigs: false, @@ -257,7 +268,7 @@ export async function createMysqlModels(filesOrgPath: string, resultsPath: strin propertyVisibility: 'none', lazy: false, constructor: false, - namingStrategy: namingStrategy, + namingStrategy, relationIds: false }); @@ -268,12 +279,13 @@ 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))) + 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 = { + const connOpt: ConnectionOptions = { database: String(process.env.MARIADB_Database), host: String(process.env.MARIADB_Host), password: String(process.env.MARIADB_Password), @@ -284,14 +296,15 @@ export async function createMariaDBModels(filesOrgPath: string, resultsPath: str synchronize: true, entities: [path.resolve(filesOrgPath, '*.js')], } - let conn = await createConnection(connOpt) + const conn = await createConnection(connOpt) - if (conn.isConnected) + if (conn.isConnected) { await conn.close() - let namingStrategy: AbstractNamingStrategy = new NamingStrategy(); + } + const namingStrategy: AbstractNamingStrategy = new NamingStrategy(); driver = new MariaDbDriver(); - let engine = new Engine( + const engine = new Engine( driver, { host: String(process.env.MARIADB_Host), port: Number(process.env.MARIADB_Port), @@ -299,7 +312,7 @@ export async function createMariaDBModels(filesOrgPath: string, resultsPath: str user: String(process.env.MARIADB_Username), password: String(process.env.MARIADB_Password), databaseType: 'mariadb', - resultsPath: resultsPath, + resultsPath, schemaName: 'ignored', ssl: yn(process.env.MARIADB_SSL), noConfigs: false, @@ -309,7 +322,7 @@ export async function createMariaDBModels(filesOrgPath: string, resultsPath: str propertyVisibility: 'none', lazy: false, constructor: false, - namingStrategy: namingStrategy, + namingStrategy, relationIds: false }); @@ -323,12 +336,13 @@ export async function createOracleDBModels(filesOrgPath: string, resultsPath: st driver = new OracleDriver(); await driver.ConnectToServer(String(process.env.ORACLE_Database), String(process.env.ORACLE_Host), Number(process.env.ORACLE_Port), String(process.env.ORACLE_UsernameSys), String(process.env.ORACLE_PasswordSys), yn(process.env.ORACLE_SSL)); - if (await driver.CheckIfDBExists(String(process.env.ORACLE_Username))) + if (await driver.CheckIfDBExists(String(process.env.ORACLE_Username))) { await driver.DropDB(String(process.env.ORACLE_Username)); + } await driver.CreateDB(String(process.env.ORACLE_Username)); await driver.DisconnectFromServer(); - let connOpt: ConnectionOptions = { + const connOpt: ConnectionOptions = { database: String(process.env.ORACLE_Database), sid: String(process.env.ORACLE_Database), host: String(process.env.ORACLE_Host), @@ -339,14 +353,15 @@ export async function createOracleDBModels(filesOrgPath: string, resultsPath: st synchronize: true, entities: [path.resolve(filesOrgPath, '*.js')], } - let conn = await createConnection(connOpt) + const conn = await createConnection(connOpt) - if (conn.isConnected) + if (conn.isConnected) { await conn.close() - let namingStrategy: AbstractNamingStrategy = new NamingStrategy(); + } + const namingStrategy: AbstractNamingStrategy = new NamingStrategy(); driver = new OracleDriver(); - let engine = new Engine( + const engine = new Engine( driver, { host: String(process.env.ORACLE_Host), port: Number(process.env.ORACLE_Port), @@ -354,7 +369,7 @@ export async function createOracleDBModels(filesOrgPath: string, resultsPath: st user: String(process.env.ORACLE_Username), password: String(process.env.ORACLE_Password), databaseType: 'oracle', - resultsPath: resultsPath, + resultsPath, schemaName: String(process.env.ORACLE_Username), ssl: yn(process.env.ORACLE_SSL), noConfigs: false, @@ -364,7 +379,7 @@ export async function createOracleDBModels(filesOrgPath: string, resultsPath: st propertyVisibility: 'none', lazy: false, constructor: false, - namingStrategy: namingStrategy, + namingStrategy, relationIds: false }); @@ -372,16 +387,16 @@ export async function createOracleDBModels(filesOrgPath: string, resultsPath: st } export function compileTsFiles(fileNames: string[], options: ts.CompilerOptions): boolean { - let program = ts.createProgram(fileNames, options); - let emitResult = program.emit(); + const program = ts.createProgram(fileNames, options); + const emitResult = program.emit(); let compileErrors = false; - let preDiagnostics = ts.getPreEmitDiagnostics(program); + const preDiagnostics = ts.getPreEmitDiagnostics(program); - let allDiagnostics = [...preDiagnostics, ...emitResult.diagnostics]; + const allDiagnostics = [...preDiagnostics, ...emitResult.diagnostics]; allDiagnostics.forEach(diagnostic => { - let lineAndCharacter = diagnostic.file!.getLineAndCharacterOfPosition(diagnostic.start!); - let message = ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n'); + const lineAndCharacter = diagnostic.file!.getLineAndCharacterOfPosition(diagnostic.start!); + const message = ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n'); console.log(`${diagnostic.file!.fileName} (${lineAndCharacter.line + 1},${lineAndCharacter.character + 1}): ${message}`); compileErrors = true; });