diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..44ccaa3 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,5 @@ + +test/integration/defaultValues/**/*.ts +test/integration/entityTypes/**/*.ts +test/integration/examples/**/*.ts +test/integration/github-issues/**/*.ts \ No newline at end of file diff --git a/.eslintrc.js b/.eslintrc.js index 4d6e44e..b2ae4ed 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,6 +1,7 @@ module.exports = { env: { - node: true + node: true, + mocha: true }, extends: [ "airbnb-base", @@ -39,5 +40,14 @@ module.exports = { extensions: [".js", ".jsx", ".ts", ".tsx"] } } - } + }, + overrides: [ + { + files: ["**/*.test.ts"], + rules: { + "no-unused-expressions": "off", + "func-names": "off" + } + } + ] }; diff --git a/package-lock.json b/package-lock.json index f9fa7c6..adc8543 100644 --- a/package-lock.json +++ b/package-lock.json @@ -382,6 +382,15 @@ "integrity": "sha512-UVjo2oH79aRNcsDlFlnQ/iJ67Jd7j6uSg7jUJP/RZ/nUjAh5ElmnwlD5K/6eGgETJUgCHkiWn91B8JjXQ6ubAw==", "dev": true }, + "@types/yn": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/yn/-/yn-3.1.0.tgz", + "integrity": "sha512-Qs2tU/syFYlALjR3EoT+NcvpMwAd6voSiDxW+c8bhAN1WbzQUnRfWTmttORf4R1WqDUT+dvHKj+llupSxs0O/w==", + "dev": true, + "requires": { + "yn": "*" + } + }, "@typescript-eslint/eslint-plugin": { "version": "1.13.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-1.13.0.tgz", @@ -3859,6 +3868,12 @@ } } }, + "oracledb": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/oracledb/-/oracledb-4.0.0.tgz", + "integrity": "sha512-5yB1QR36TrO0hDe6BfSYWVZgfMLOaS7TJ1+iT9qvcmXTQacfUFeAHRVWu2XM4+Adpy8JhxSHQPXXp5+iJ0waug==", + "dev": true + }, "os-homedir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", diff --git a/package.json b/package.json index 63a5217..cf0d644 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "start": "ts-node ./src/index.ts", "pretest": "tsc --noEmit", "test": "nyc --reporter=lcov ts-node ./node_modules/mocha/bin/_mocha test/**/*.test.ts -- -R spec --bail", - "posttest": "eslint ./src/*.ts ./src/**/*.ts", + "posttest": "eslint ./**/*.ts ./src/**/*.ts ./test/**/*.ts", "clean": "rimraf coverage output", "prettier": "prettier --write ./src/*.ts ./src/**/*.ts" }, @@ -53,6 +53,7 @@ "@types/sinon": "^7.0.13", "@types/sqlite3": "^3.1.5", "@types/yargs": "^12.0.1", + "@types/yn": "^3.1.0", "@typescript-eslint/eslint-plugin": "^1.13.0", "@typescript-eslint/parser": "^1.13.0", "@typescript-eslint/typescript-estree": "^1.13.0", diff --git a/src/typings.d.ts b/src/typings.d.ts deleted file mode 100644 index 4b3471f..0000000 --- a/src/typings.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -declare module "*.json" { - const value: any; - export default value; -} diff --git a/test/drivers/MssqlDriver.test.ts b/test/drivers/MssqlDriver.test.ts index c9b3640..4a15204 100644 --- a/test/drivers/MssqlDriver.test.ts +++ b/test/drivers/MssqlDriver.test.ts @@ -1,6 +1,5 @@ import { expect } from "chai"; import * as MSSQL from "mssql"; -import { IColumnMetadata, Table } from "mssql"; import * as Sinon from "sinon"; import MssqlDriver from "../../src/drivers/MssqlDriver"; import EntityInfo from "../../src/models/EntityInfo"; @@ -8,17 +7,22 @@ import ColumnInfo from "../../src/models/ColumnInfo"; import IndexInfo from "../../src/models/IndexInfo"; import RelationInfo from "../../src/models/RelationInfo"; -class fakeResponse implements MSSQL.IResult { - public recordsets: Array>; - public recordset: MSSQL.IRecordSet; - public rowsAffected: number[]; - public output: { [key: string]: any }; +interface FakeResponse extends MSSQL.IResult { + recordsets: MSSQL.IRecordSet[]; + + recordset: MSSQL.IRecordSet; + + rowsAffected: number[]; + + output: { [key: string]: any }; } -class fakeRecordset extends Array implements MSSQL.IRecordSet { - public columns: IColumnMetadata; - public toTable(): Table { - return new Table(); +class FakeRecordset extends Array implements MSSQL.IRecordSet { + public columns: MSSQL.IColumnMetadata; + + // eslint-disable-next-line class-methods-use-this + public toTable(): MSSQL.Table { + return new MSSQL.Table(); } } @@ -36,9 +40,9 @@ describe("MssqlDriver", function() { it("should get tables info", async () => { sandbox.stub(MSSQL, "Request").returns({ - query: q => { - const response = new fakeResponse(); - response.recordset = new fakeRecordset(); + query: () => { + const response = {} as FakeResponse; + response.recordset = new FakeRecordset(); response.recordset.push({ TABLE_SCHEMA: "schema", TABLE_NAME: "name" @@ -60,9 +64,9 @@ describe("MssqlDriver", function() { }); it("should get columns info", async () => { sandbox.stub(MSSQL, "Request").returns({ - query: q => { - const response = new fakeResponse(); - response.recordset = new fakeRecordset(); + query: () => { + const response = {} as FakeResponse; + response.recordset = new FakeRecordset(); response.recordset.push({ TABLE_NAME: "name", CHARACTER_MAXIMUM_LENGTH: 0, diff --git a/test/integration/runTestsFromPath.test.ts b/test/integration/runTestsFromPath.test.ts index e6ca1af..47674a5 100644 --- a/test/integration/runTestsFromPath.test.ts +++ b/test/integration/runTestsFromPath.test.ts @@ -1,23 +1,24 @@ -require("dotenv").config(); import "reflect-metadata"; import { expect } from "chai"; -import fs = require("fs-extra"); -import path = require("path"); -import { EntityFileToJson } from "../utils/EntityFileToJson"; +import * as ts from "typescript"; +import EntityFileToJson from "../utils/EntityFileToJson"; import { createDriver, - createModelFromDatabase, dataCollectionPhase, modelCustomizationPhase, modelGenerationPhase } from "../../src/Engine"; -import * as ts from "typescript"; import * as GTU from "../utils/GeneralTestUtils"; +import EntityInfo from "../../src/models/EntityInfo"; +import IConnectionOptions from "../../src/IConnectionOptions"; + +import fs = require("fs-extra"); +import path = require("path"); import chaiSubset = require("chai-subset"); import chai = require("chai"); import yn = require("yn"); -import EntityInfo from "../../src/models/EntityInfo"; -import IConnectionOptions from "../../src/IConnectionOptions"; + +require("dotenv").config(); chai.use(chaiSubset); @@ -37,16 +38,16 @@ describe("GitHub issues", async function() { this.timeout(60000); this.slow(10000); // compiling created models takes time const testPartialPath = "test/integration/github-issues"; - runTestsFromPath(testPartialPath, false); + await runTestsFromPath(testPartialPath, false); }); describe("TypeOrm examples", async function() { this.timeout(60000); this.slow(10000); // compiling created models takes time const testPartialPath = "test/integration/examples"; - runTestsFromPath(testPartialPath, false); + await runTestsFromPath(testPartialPath, false); }); -export async function runTestsFromPath( +async function runTestsFromPath( testPartialPath: string, isDbSpecific: boolean ) { @@ -55,21 +56,22 @@ export async function runTestsFromPath( fs.mkdirSync(resultsPath); } const dbDrivers: string[] = GTU.getEnabledDbDrivers(); - for (const dbDriver of dbDrivers) { + dbDrivers.forEach(dbDriver => { const newDirPath = path.resolve(resultsPath, dbDriver); if (!fs.existsSync(newDirPath)) { fs.mkdirSync(newDirPath); } - } + }); const files = fs.readdirSync(path.resolve(process.cwd(), testPartialPath)); if (isDbSpecific) { await runTest(dbDrivers, testPartialPath, files); } else { - for (const folder of files) { + files.forEach(folder => { runTestForMultipleDrivers(folder, dbDrivers, testPartialPath); - } + }); } } + function runTestForMultipleDrivers( testName: string, dbDrivers: string[], @@ -191,22 +193,21 @@ function compareGeneratedFiles(filesOrgPathTS: string, filesGenPath: string) { expect(filesOrg, "Errors detected in model comparision").to.be.deep.equal( filesGen ); - for (const file of filesOrg) { - const entftj = new EntityFileToJson(); - const jsonEntityOrg = entftj.convert( + filesOrg.forEach(file => { + const jsonEntityOrg = EntityFileToJson.convert( fs.readFileSync(path.resolve(filesOrgPathTS, file)) ); - const jsonEntityGen = entftj.convert( + const jsonEntityGen = EntityFileToJson.convert( fs.readFileSync(path.resolve(filesGenPath, file)) ); expect(jsonEntityGen, `Error in file ${file}`).to.containSubset( jsonEntityOrg ); - } + }); } function compileGeneratedModel(filesGenPath: string, drivers: string[]) { - let currentDirectoryFiles: string[] = []; + const currentDirectoryFiles: string[] = []; drivers.forEach(driver => { const entitiesPath = path.resolve(filesGenPath, driver, "entities"); if (fs.existsSync(entitiesPath)) { @@ -263,6 +264,7 @@ async function prepareTestRuns( generationOptions.lazy = true; break; case "144": + // eslint-disable-next-line no-case-declarations let connectionOptions: IConnectionOptions; switch (dbDriver) { case "mysql": @@ -296,10 +298,10 @@ async function prepareTestRuns( await driver.ConnectToServer(connectionOptions!); if (!(await driver.CheckIfDBExists("db1"))) { - var x = await driver.CreateDB("db1"); + await driver.CreateDB("db1"); } if (!(await driver.CheckIfDBExists("db2"))) { - var t = await driver.CreateDB("db2"); + await driver.CreateDB("db2"); } await driver.DisconnectFromServer(); break; diff --git a/test/utils/EntityFileToJson.ts b/test/utils/EntityFileToJson.ts index 237ec8f..981c10c 100644 --- a/test/utils/EntityFileToJson.ts +++ b/test/utils/EntityFileToJson.ts @@ -1,361 +1,515 @@ -export class EntityFileToJson { - public getEntityOptions(trimmedLine: string, ent: EntityJson) { - const decoratorParameters = trimmedLine.slice(trimmedLine.indexOf('(') + 1, trimmedLine.lastIndexOf(')')) +/* eslint-disable max-classes-per-file */ +class EntityJson { + public entityName: string; + + public entityOptions: any = {}; + + public columns: EntityColumn[] = [] as EntityColumn[]; + + public indicies: EntityIndex[] = [] as EntityIndex[]; +} +class EntityColumn { + public columnName: string; + + public columnTypes: string[] = []; + + public columnOptions: any = {}; + + public relationType: + | "OneToOne" + | "OneToMany" + | "ManyToOne" + | "ManyToMany" + | "None" = "None"; + + public isOwnerOfRelation: boolean = false; +} +class EntityIndex { + public indexName: string; + + public columnNames: string[] = []; + + public isUnique: boolean = false; +} + +export default class EntityFileToJson { + public static getEntityOptions(trimmedLine: string, ent: EntityJson) { + const decoratorParameters = trimmedLine.slice( + trimmedLine.indexOf("(") + 1, + trimmedLine.lastIndexOf(")") + ); if (decoratorParameters.length > 0) { - 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] + 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]; } - ent.entityOptions = JSON.parse(badJSON.replace(/(['"])?([a-z0-9A-Z_]+)(['"])?:/g, '"$2": ')) + ent.entityOptions = JSON.parse( + badJSON.replace(/(['"])?([a-z0-9A-Z_]+)(['"])?:/g, '"$2": ') + ); } } } - public getColumnOptionsAndType(trimmedLine: string, col: EntityColumn) { - const decoratorParameters = trimmedLine.slice(trimmedLine.indexOf('(') + 1, trimmedLine.lastIndexOf(')')) - const primaryGeneratedColumn = trimmedLine.substring(0, trimmedLine.indexOf('('))=='@PrimaryGeneratedColumn' + + public static 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('|'); - 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] + if ( + decoratorParameters.search(",") > 0 && + !primaryGeneratedColumn + ) { + 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]; } - badJSON = badJSON.replace(/default: \(\) => (.*)/, `default: $1`) - col.columnOptions = JSON.parse(badJSON.replace(/(['"])?([a-z0-9A-Z_]+)(['"])?:/g, '"$2": ')) + badJSON = badJSON.replace( + /default: \(\) => (.*)/, + `default: $1` + ); + col.columnOptions = JSON.parse( + badJSON.replace(/(['"])?([a-z0-9A-Z_]+)(['"])?:/g, '"$2": ') + ); + } else if ( + decoratorParameters[0] === '"' && + decoratorParameters.endsWith('"') + ) { + col.columnTypes = decoratorParameters + .split("|") + .map(x => x.trim()); } else { - if (decoratorParameters[0] == '"' && decoratorParameters.endsWith('"')) { - col.columnTypes = decoratorParameters.split('|').map( x=>x.trim()) - } else { - let badJSON = !primaryGeneratedColumn ? decoratorParameters.substring(decoratorParameters.indexOf(',') + 1) : decoratorParameters - badJSON = badJSON.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(/(['"])?([a-z0-9A-Z_]+)(['"])?:/g, '"$2": ')) + let badJSON = !primaryGeneratedColumn + ? decoratorParameters.substring( + decoratorParameters.indexOf(",") + 1 + ) + : decoratorParameters; + badJSON = badJSON.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(/(['"])?([a-z0-9A-Z_]+)(['"])?:/g, '"$2": ') + ); } } } - public getRelationOptions(trimmedLine:string, col:EntityColumn){ - const decoratorParameters = trimmedLine.slice(trimmedLine.indexOf('(') + 1, trimmedLine.lastIndexOf(')')) - if (decoratorParameters.length > 0) { - 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] + + public static getRelationOptions(trimmedLine: string, col: EntityColumn) { + const decoratorParameters = trimmedLine.slice( + trimmedLine.indexOf("(") + 1, + trimmedLine.lastIndexOf(")") + ); + if (decoratorParameters.length > 0) { + 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": ')) + col.columnOptions = JSON.parse( + badJSON + .replace(/(')/g, `"`) + .replace(/(['"])?([a-z0-9A-Z_]+)(['"])?:/g, '"$2": ') + ); } } } - public getIndexOptions(trimmedLine: string, ind: EntityIndex) { - const decoratorParameters = trimmedLine.slice(trimmedLine.indexOf('(') + 1, trimmedLine.lastIndexOf(')')) + + public static getIndexOptions(trimmedLine: string, ind: EntityIndex) { + const decoratorParameters = trimmedLine.slice( + trimmedLine.indexOf("(") + 1, + trimmedLine.lastIndexOf(")") + ); if (decoratorParameters.length > 0) { - const containsTables = decoratorParameters.search('\\[') > -1 - const containsOptions = decoratorParameters.search('{') > -1 - const containsName = decoratorParameters.search('"') > -1 + 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('"')) + ind.indexName = decoratorParameters.slice( + decoratorParameters.indexOf('"') + 1, + decoratorParameters + .substr(decoratorParameters.indexOf('"') + 1) + .indexOf('"') + ); } if (containsTables) { - const columnsStr = decoratorParameters.slice(decoratorParameters.indexOf('[') + 1, decoratorParameters.indexOf(']')) - ind.columnNames.push(...columnsStr.split(',').map((val) => { - let colName = '' - if (val.search('\\.') > -1) { - colName = val.split('.')[1] - } else { - colName = val.slice(val.indexOf('"') + 1, val.lastIndexOf('"')) - } - return colName - }).filter(v => v.length > 0)) + const columnsStr = decoratorParameters.slice( + decoratorParameters.indexOf("[") + 1, + decoratorParameters.indexOf("]") + ); + ind.columnNames.push( + ...columnsStr + .split(",") + .map(val => { + let colName = ""; + if (val.search("\\.") > -1) { + [, colName] = val.split("."); + } else { + colName = val.slice( + val.indexOf('"') + 1, + val.lastIndexOf('"') + ); + } + return colName; + }) + .filter(v => v.length > 0) + ); } if (containsOptions) { - const optionsStr = decoratorParameters.slice(decoratorParameters.indexOf('{') + 1, decoratorParameters.indexOf('}')) - optionsStr.split(',').forEach((v) => { - if (v.split(':').length - 1 > 0) { - switch (optionsStr.split(':')[0].trim()) { + const optionsStr = decoratorParameters.slice( + decoratorParameters.indexOf("{") + 1, + decoratorParameters.indexOf("}") + ); + optionsStr.split(",").forEach(v => { + if (v.split(":").length - 1 > 0) { + switch (optionsStr.split(":")[0].trim()) { case "unique": - ind.isUnique = optionsStr.split(':')[1].trim() == 'true' ? true : false; + ind.isUnique = + optionsStr.split(":")[1].trim() === "true"; break; default: - console.log(`[EntityFileToJson:convert] Index option not recognized ${ind.indexName}:`) - console.log(`${optionsStr}`) + console.log( + `[EntityFileToJson:convert] Index option not recognized ${ind.indexName}:` + ); + console.log(`${optionsStr}`); break; } } - }) + }); } } } - public convert(entityFile: Buffer): EntityJson { + public static convert(entityFile: Buffer): EntityJson { const retVal = new EntityJson(); let isInClassBody = false; let isMultilineStatement = false; - let priorPartOfMultilineStatement = ''; + let priorPartOfMultilineStatement = ""; - const lines = entityFile.toString().replace('\r', '').split('\n'); - for (const line of lines) { + const lines = entityFile + .toString() + .replace("\r", "") + .split("\n"); + lines.forEach(line => { let trimmedLine = line.trim(); - if (trimmedLine.startsWith('//')) { - continue; + if (trimmedLine.startsWith("//")) { + return; } if (isMultilineStatement) { - trimmedLine = priorPartOfMultilineStatement + ' ' + trimmedLine + trimmedLine = `${priorPartOfMultilineStatement} ${trimmedLine}`; } - if (trimmedLine.length == 0) { - continue; + if (trimmedLine.length === 0) { + return; } - else if (!isInClassBody) { - if (trimmedLine.startsWith('import')) { - continue; - } else if (trimmedLine.startsWith('@Entity')) { - if (this.isPartOfMultilineStatement(trimmedLine)) { + if (!isInClassBody) { + if (trimmedLine.startsWith("import")) { + return; + } + if (trimmedLine.startsWith("@Entity")) { + if ( + EntityFileToJson.isPartOfMultilineStatement(trimmedLine) + ) { isMultilineStatement = true; priorPartOfMultilineStatement = trimmedLine; - continue; } else { - this.getEntityOptions(trimmedLine, retVal); - continue; + EntityFileToJson.getEntityOptions(trimmedLine, retVal); } - } else if (trimmedLine.startsWith('export class')) { - retVal.entityName = trimmedLine.substring(trimmedLine.indexOf('class') + 5, trimmedLine.lastIndexOf('{')).trim().toLowerCase() + return; + } + if (trimmedLine.startsWith("export class")) { + retVal.entityName = trimmedLine + .substring( + trimmedLine.indexOf("class") + 5, + trimmedLine.lastIndexOf("{") + ) + .trim() + .toLowerCase(); isInClassBody = true; - continue; - } else if (trimmedLine.startsWith('@Index')) { - if (this.isPartOfMultilineStatement(trimmedLine)) { - isMultilineStatement = true; - priorPartOfMultilineStatement = trimmedLine; - continue; - } else { - isMultilineStatement = false; - const ind = new EntityIndex() - this.getIndexOptions(trimmedLine, ind) - retVal.indicies.push(ind); - continue; - } + return; } - } else { - if (trimmedLine.startsWith('@Column')) { - if (this.isPartOfMultilineStatement(trimmedLine)) { + if (trimmedLine.startsWith("@Index")) { + if ( + EntityFileToJson.isPartOfMultilineStatement(trimmedLine) + ) { isMultilineStatement = true; priorPartOfMultilineStatement = trimmedLine; - continue; } else { isMultilineStatement = false; - const col = new EntityColumn() - this.getColumnOptionsAndType(trimmedLine, col) - retVal.columns.push(col); - continue; - } - } else if (trimmedLine.startsWith('@PrimaryColumn')) { - if (this.isPartOfMultilineStatement(trimmedLine)) { - isMultilineStatement = true; - priorPartOfMultilineStatement = trimmedLine; - continue; - } else { - isMultilineStatement = false; - const col = new EntityColumn() - this.getColumnOptionsAndType(trimmedLine, col) - col.columnOptions.primary = true - retVal.columns.push(col); - continue; - } - } else if (trimmedLine.startsWith('@VersionColumn')) { - if (this.isPartOfMultilineStatement(trimmedLine)) { - isMultilineStatement = true; - priorPartOfMultilineStatement = trimmedLine; - continue; - } else { - isMultilineStatement = false; - const col = new EntityColumn() - this.getColumnOptionsAndType(trimmedLine, col) - retVal.columns.push(col); - continue; - } - } else if (trimmedLine.startsWith('@PrimaryGeneratedColumn')) { - if (this.isPartOfMultilineStatement(trimmedLine)) { - isMultilineStatement = true; - priorPartOfMultilineStatement = trimmedLine; - continue; - } else { - isMultilineStatement = false; - const col = new EntityColumn() - this.getColumnOptionsAndType(trimmedLine, col) - col.columnOptions.primary = true - col.columnOptions.generated = true - retVal.columns.push(col); - continue; - } - } else if (trimmedLine.startsWith('@ManyToOne')) { - if (this.isPartOfMultilineStatement(trimmedLine)) { - isMultilineStatement = true; - priorPartOfMultilineStatement = trimmedLine; - continue; - } else { - isMultilineStatement = false; - const column = new EntityColumn() - retVal.columns.push(column) - column.relationType = "ManyToOne" - column.isOwnerOfRelation = true; - continue; - } - } else if (trimmedLine.startsWith('@OneToMany')) { - if (this.isPartOfMultilineStatement(trimmedLine)) { - isMultilineStatement = true; - priorPartOfMultilineStatement = trimmedLine; - continue; - } else { - isMultilineStatement = false; - const column = new EntityColumn() - retVal.columns.push(column) - column.relationType = "OneToMany" - continue; - } - } else if (trimmedLine.startsWith('@ManyToMany')) { - if (this.isPartOfMultilineStatement(trimmedLine)) { - isMultilineStatement = true; - priorPartOfMultilineStatement = trimmedLine; - continue; - } else { - isMultilineStatement = false; - const column = new EntityColumn() - retVal.columns.push(column) - column.relationType = "ManyToMany" - continue; - } - } else if (trimmedLine.startsWith('@OneToOne')) { - if (this.isPartOfMultilineStatement(trimmedLine)) { - isMultilineStatement = true; - priorPartOfMultilineStatement = trimmedLine; - continue; - } else { - isMultilineStatement = false; - const column = new EntityColumn() - retVal.columns.push(column) - column.relationType = "OneToOne" - this.getRelationOptions(trimmedLine,column); - continue; - } - } else if (trimmedLine.startsWith('@JoinColumn')) { - if (this.isPartOfMultilineStatement(trimmedLine)) { - isMultilineStatement = true; - priorPartOfMultilineStatement = trimmedLine; - continue; - } else { - isMultilineStatement = false; - retVal.columns[retVal.columns.length - 1].isOwnerOfRelation = true; - continue; - } - } else if (trimmedLine.startsWith('@JoinTable')) { - if (this.isPartOfMultilineStatement(trimmedLine)) { - isMultilineStatement = true; - priorPartOfMultilineStatement = trimmedLine; - continue; - } else { - isMultilineStatement = false; - retVal.columns[retVal.columns.length - 1].isOwnerOfRelation = true; - continue; - } - } else if (trimmedLine.startsWith('@Index')) { - if (this.isPartOfMultilineStatement(trimmedLine)) { - isMultilineStatement = true; - priorPartOfMultilineStatement = trimmedLine; - continue; - } else { - isMultilineStatement = false; - const ind = new EntityIndex() - this.getIndexOptions(trimmedLine, ind) + const ind = new EntityIndex(); + EntityFileToJson.getIndexOptions(trimmedLine, ind); retVal.indicies.push(ind); - continue; } - } else if (trimmedLine.startsWith('constructor')) { - if (this.isPartOfMultilineStatement(trimmedLine)) { - isMultilineStatement = true; - priorPartOfMultilineStatement = trimmedLine; - continue; - } else { - isMultilineStatement = false; - continue; - } - } 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? - let colTypes=trimmedLine.split(':')[1].split(';')[0].trim(); - if (colTypes.startsWith('Promise<')) { - colTypes=colTypes.substring(8,colTypes.length-1) - retVal.columns[retVal.columns.length - 1].columnOptions.isLazy=true; - } - retVal.columns[retVal.columns.length - 1].columnTypes = colTypes.split('|').map(function (x) { - if (x == 'any') { - x = 'string' // for json columns - } - x = x.trim(); - return x; - }); - - 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) - } - continue - } else if (trimmedLine == '}') { - isInClassBody = false; - continue; - } - else { - console.log(`[EntityFileToJson:convert] Line not recognized in entity ${retVal.entityName}:`) - console.log(`${trimmedLine}`) + return; } } - console.log(`[EntityFileToJson:convert] Line not recognized in entity ${retVal.entityName}:`) - console.log(`${trimmedLine}`) - } + if (trimmedLine.startsWith("@Column")) { + if (EntityFileToJson.isPartOfMultilineStatement(trimmedLine)) { + isMultilineStatement = true; + priorPartOfMultilineStatement = trimmedLine; + } else { + isMultilineStatement = false; + const col = new EntityColumn(); + EntityFileToJson.getColumnOptionsAndType(trimmedLine, col); + retVal.columns.push(col); + } + return; + } + if (trimmedLine.startsWith("@PrimaryColumn")) { + if (EntityFileToJson.isPartOfMultilineStatement(trimmedLine)) { + isMultilineStatement = true; + priorPartOfMultilineStatement = trimmedLine; + } else { + isMultilineStatement = false; + const col = new EntityColumn(); + EntityFileToJson.getColumnOptionsAndType(trimmedLine, col); + col.columnOptions.primary = true; + retVal.columns.push(col); + } + return; + } + if (trimmedLine.startsWith("@VersionColumn")) { + if (EntityFileToJson.isPartOfMultilineStatement(trimmedLine)) { + isMultilineStatement = true; + priorPartOfMultilineStatement = trimmedLine; + } else { + isMultilineStatement = false; + const col = new EntityColumn(); + EntityFileToJson.getColumnOptionsAndType(trimmedLine, col); + retVal.columns.push(col); + } + return; + } + if (trimmedLine.startsWith("@PrimaryGeneratedColumn")) { + if (EntityFileToJson.isPartOfMultilineStatement(trimmedLine)) { + isMultilineStatement = true; + priorPartOfMultilineStatement = trimmedLine; + } else { + isMultilineStatement = false; + const col = new EntityColumn(); + EntityFileToJson.getColumnOptionsAndType(trimmedLine, col); + col.columnOptions.primary = true; + col.columnOptions.generated = true; + retVal.columns.push(col); + } + return; + } + if (trimmedLine.startsWith("@ManyToOne")) { + if (EntityFileToJson.isPartOfMultilineStatement(trimmedLine)) { + isMultilineStatement = true; + priorPartOfMultilineStatement = trimmedLine; + } else { + isMultilineStatement = false; + const column = new EntityColumn(); + retVal.columns.push(column); + column.relationType = "ManyToOne"; + column.isOwnerOfRelation = true; + } + return; + } + if (trimmedLine.startsWith("@OneToMany")) { + if (EntityFileToJson.isPartOfMultilineStatement(trimmedLine)) { + isMultilineStatement = true; + priorPartOfMultilineStatement = trimmedLine; + } else { + isMultilineStatement = false; + const column = new EntityColumn(); + retVal.columns.push(column); + column.relationType = "OneToMany"; + } + return; + } + if (trimmedLine.startsWith("@ManyToMany")) { + if (EntityFileToJson.isPartOfMultilineStatement(trimmedLine)) { + isMultilineStatement = true; + priorPartOfMultilineStatement = trimmedLine; + } else { + isMultilineStatement = false; + const column = new EntityColumn(); + retVal.columns.push(column); + column.relationType = "ManyToMany"; + } + return; + } + if (trimmedLine.startsWith("@OneToOne")) { + if (EntityFileToJson.isPartOfMultilineStatement(trimmedLine)) { + isMultilineStatement = true; + priorPartOfMultilineStatement = trimmedLine; + } else { + isMultilineStatement = false; + const column = new EntityColumn(); + retVal.columns.push(column); + column.relationType = "OneToOne"; + EntityFileToJson.getRelationOptions(trimmedLine, column); + } + return; + } + if (trimmedLine.startsWith("@JoinColumn")) { + if (EntityFileToJson.isPartOfMultilineStatement(trimmedLine)) { + isMultilineStatement = true; + priorPartOfMultilineStatement = trimmedLine; + } else { + isMultilineStatement = false; + retVal.columns[ + retVal.columns.length - 1 + ].isOwnerOfRelation = true; + } + return; + } + if (trimmedLine.startsWith("@JoinTable")) { + if (EntityFileToJson.isPartOfMultilineStatement(trimmedLine)) { + isMultilineStatement = true; + priorPartOfMultilineStatement = trimmedLine; + } else { + isMultilineStatement = false; + retVal.columns[ + retVal.columns.length - 1 + ].isOwnerOfRelation = true; + } + return; + } + if (trimmedLine.startsWith("@Index")) { + if (EntityFileToJson.isPartOfMultilineStatement(trimmedLine)) { + isMultilineStatement = true; + priorPartOfMultilineStatement = trimmedLine; + } else { + isMultilineStatement = false; + const ind = new EntityIndex(); + EntityFileToJson.getIndexOptions(trimmedLine, ind); + retVal.indicies.push(ind); + } + return; + } + if (trimmedLine.startsWith("constructor")) { + if (EntityFileToJson.isPartOfMultilineStatement(trimmedLine)) { + isMultilineStatement = true; + priorPartOfMultilineStatement = trimmedLine; + } else { + isMultilineStatement = false; + } + return; + } + 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? + let colTypes = trimmedLine + .split(":")[1] + .split(";")[0] + .trim(); + if (colTypes.startsWith("Promise<")) { + colTypes = colTypes.substring(8, colTypes.length - 1); + retVal.columns[ + retVal.columns.length - 1 + ].columnOptions.isLazy = true; + } + retVal.columns[ + retVal.columns.length - 1 + ].columnTypes = colTypes.split("|").map(x => { + if (x === "any") { + x = "string"; // for json columns + } + x = x.trim(); + return x; + }); + + if ( + !retVal.columns[retVal.columns.length - 1].columnTypes.some( + val => val === "null" + ) + ) { + 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 + ); + } + return; + } + if (trimmedLine === "}") { + isInClassBody = false; + return; + } + console.log( + `[EntityFileToJson:convert] Line not recognized in entity ${retVal.entityName}:` + ); + console.log(`${trimmedLine}`); + }); retVal.columns = retVal.columns.map(col => { - if (col.columnName.endsWith('Id')) { - col.columnName = col.columnName.substr(0, col.columnName.length - 2) + 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')) { - colName = colName.substr(0, colName.length - 2) + if (colName.endsWith("Id")) { + colName = colName.substr(0, colName.length - 2); } return colName; - }) + }); return ind; - }) + }); return retVal; } - public isPartOfMultilineStatement(statement: string) { - const matchStarting = statement.split('(').length+statement.split('{').length - const matchEnding = statement.split(')').length+statement.split('}').length - return !(matchStarting == matchEnding) + + public static isPartOfMultilineStatement(statement: string) { + const matchStarting = + statement.split("(").length + statement.split("{").length; + const matchEnding = + statement.split(")").length + statement.split("}").length; + return !(matchStarting === matchEnding); } } -class EntityJson { - public entityName: string - public entityOptions: any = {} - public columns: EntityColumn[] = [] as EntityColumn[]; - public indicies: EntityIndex[] = [] as EntityIndex[]; -} -class EntityColumn { - public columnName: string - public columnTypes: string[] = [] - public columnOptions: any = {} - public relationType: "OneToOne" | "OneToMany" | "ManyToOne" | "ManyToMany" | "None" = "None" - public isOwnerOfRelation: boolean = false; -} -class EntityIndex { - public indexName: string - public columnNames: string[] = [] - public isUnique: boolean = false -} +/* eslint-enable max-classes-per-file */ diff --git a/test/utils/GeneralTestUtils.ts b/test/utils/GeneralTestUtils.ts index 9ddc00e..b49767b 100644 --- a/test/utils/GeneralTestUtils.ts +++ b/test/utils/GeneralTestUtils.ts @@ -1,20 +1,19 @@ -import path = require("path"); import { ConnectionOptions, createConnection } from "typeorm"; import * as ts from "typescript"; import * as yn from "yn"; import IGenerationOptions from "../../src/IGenerationOptions"; import IConnectionOptions from "../../src/IConnectionOptions"; -import AbstractDriver from "../../src/drivers/AbstractDriver"; import MssqlDriver from "../../src/drivers/MssqlDriver"; import MariaDbDriver from "../../src/drivers/MariaDbDriver"; import PostgresDriver from "../../src/drivers/PostgresDriver"; -import SqliteDriver from "../../src/drivers/SqliteDriver"; import OracleDriver from "../../src/drivers/OracleDriver"; import MysqlDriver from "../../src/drivers/MysqlDriver"; +import path = require("path"); + export function getGenerationOptions(resultsPath: string): IGenerationOptions { return { - resultsPath: resultsPath, + resultsPath, noConfigs: false, convertCaseEntity: "none", convertCaseFile: "none", @@ -31,8 +30,7 @@ export function getGenerationOptions(resultsPath: string): IGenerationOptions { export async function createMSSQLModels( filesOrgPath: string ): Promise { - let driver: AbstractDriver; - driver = new MssqlDriver(); + const driver = new MssqlDriver(); const connectionOptions: IConnectionOptions = { host: String(process.env.MSSQL_Host), port: Number(process.env.MSSQL_Port), @@ -66,11 +64,11 @@ export async function createMSSQLModels( }; const schemas = "dbo,sch1,sch2"; - let conn = await createConnection(connOpt); - let queryRunner = conn.createQueryRunner(); - for (const sch of schemas.split(",")) { - await queryRunner.createSchema(sch, true); - } + const conn = await createConnection(connOpt); + const queryRunner = conn.createQueryRunner(); + await Promise.all( + schemas.split(",").map(sch => queryRunner.createSchema(sch, true)) + ); await conn.synchronize(); if (conn.isConnected) { @@ -83,8 +81,7 @@ export async function createMSSQLModels( export async function createPostgresModels( filesOrgPath: string ): Promise { - let driver: AbstractDriver; - driver = new PostgresDriver(); + const driver = new PostgresDriver(); const connectionOptions: IConnectionOptions = { host: String(process.env.POSTGRES_Host), port: Number(process.env.POSTGRES_Port), @@ -118,11 +115,11 @@ export async function createPostgresModels( }; const schemas = "public,sch1,sch2"; - let conn = await createConnection(connOpt); - let queryRunner = conn.createQueryRunner(); - for (const sch of schemas.split(",")) { - await queryRunner.createSchema(sch, true); - } + const conn = await createConnection(connOpt); + const queryRunner = conn.createQueryRunner(); + await Promise.all( + schemas.split(",").map(sch => queryRunner.createSchema(sch, true)) + ); await conn.synchronize(); if (conn.isConnected) { @@ -135,8 +132,6 @@ export async function createPostgresModels( export async function createSQLiteModels( filesOrgPath: string ): Promise { - let driver: AbstractDriver; - driver = new SqliteDriver(); const connectionOptions: IConnectionOptions = { host: "", port: 0, @@ -147,13 +142,6 @@ export async function createSQLiteModels( schemaName: "", ssl: false }; - await driver.ConnectToServer(connectionOptions); - - 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(); const connOpt: ConnectionOptions = { database: String(process.env.SQLITE_Database), @@ -164,7 +152,7 @@ export async function createSQLiteModels( name: "sqlite" }; - let conn = await createConnection(connOpt); + const conn = await createConnection(connOpt); await conn.synchronize(); if (conn.isConnected) { @@ -177,8 +165,7 @@ export async function createSQLiteModels( export async function createMysqlModels( filesOrgPath: string ): Promise { - let driver: AbstractDriver; - driver = new MysqlDriver(); + const driver = new MysqlDriver(); const connectionOptions: IConnectionOptions = { host: String(process.env.MYSQL_Host), port: Number(process.env.MYSQL_Port), @@ -220,8 +207,7 @@ export async function createMysqlModels( export async function createMariaDBModels( filesOrgPath: string ): Promise { - let driver: AbstractDriver; - driver = new MariaDbDriver(); + const driver = new MariaDbDriver(); const connectionOptions: IConnectionOptions = { host: String(process.env.MARIADB_Host), port: Number(process.env.MARIADB_Port), @@ -264,8 +250,7 @@ export async function createMariaDBModels( export async function createOracleDBModels( filesOrgPath: string ): Promise { - let driver: AbstractDriver; - driver = new OracleDriver(); + const driver = new OracleDriver(); const connectionOptions: IConnectionOptions = { host: String(process.env.ORACLE_Host), @@ -339,22 +324,22 @@ export function compileTsFiles( export function getEnabledDbDrivers() { const dbDrivers: string[] = []; - if (process.env.SQLITE_Skip == "0") { + if (process.env.SQLITE_Skip === "0") { dbDrivers.push("sqlite"); } - if (process.env.POSTGRES_Skip == "0") { + if (process.env.POSTGRES_Skip === "0") { dbDrivers.push("postgres"); } - if (process.env.MYSQL_Skip == "0") { + if (process.env.MYSQL_Skip === "0") { dbDrivers.push("mysql"); } - if (process.env.MARIADB_Skip == "0") { + if (process.env.MARIADB_Skip === "0") { dbDrivers.push("mariadb"); } - if (process.env.MSSQL_Skip == "0") { + if (process.env.MSSQL_Skip === "0") { dbDrivers.push("mssql"); } - if (process.env.ORACLE_Skip == "0") { + if (process.env.ORACLE_Skip === "0") { dbDrivers.push("oracle"); } return dbDrivers;