From 7a2395ab2a1b6512734c2dd8fd2c562a47db3c0d Mon Sep 17 00:00:00 2001 From: Kononnable Date: Mon, 23 Sep 2019 22:53:09 +0200 Subject: [PATCH 01/84] move old models to temporary folder --- src/AbstractNamingStrategy.ts | 6 +++--- src/Engine.ts | 2 +- src/NamingStrategy.ts | 4 ++-- src/drivers/AbstractDriver.ts | 10 +++++----- src/drivers/MssqlDriver.ts | 10 +++++----- src/drivers/MysqlDriver.ts | 10 +++++----- src/drivers/OracleDriver.ts | 10 +++++----- src/drivers/PostgresDriver.ts | 10 +++++----- src/drivers/SqliteDriver.ts | 10 +++++----- src/{models => oldModels}/ColumnInfo.ts | 0 src/{models => oldModels}/EntityInfo.ts | 0 src/{models => oldModels}/IndexColumnInfo.ts | 0 src/{models => oldModels}/IndexInfo.ts | 0 src/{models => oldModels}/RelationInfo.ts | 0 src/{models => oldModels}/RelationTempInfo.ts | 0 test/drivers/MssqlDriver.test.ts | 8 ++++---- test/integration/runTestsFromPath.test.ts | 2 +- 17 files changed, 41 insertions(+), 41 deletions(-) rename src/{models => oldModels}/ColumnInfo.ts (100%) rename src/{models => oldModels}/EntityInfo.ts (100%) rename src/{models => oldModels}/IndexColumnInfo.ts (100%) rename src/{models => oldModels}/IndexInfo.ts (100%) rename src/{models => oldModels}/RelationInfo.ts (100%) rename src/{models => oldModels}/RelationTempInfo.ts (100%) diff --git a/src/AbstractNamingStrategy.ts b/src/AbstractNamingStrategy.ts index b568992..4626962 100644 --- a/src/AbstractNamingStrategy.ts +++ b/src/AbstractNamingStrategy.ts @@ -1,6 +1,6 @@ -import RelationInfo from "./models/RelationInfo"; -import EntityInfo from "./models/EntityInfo"; -import ColumnInfo from "./models/ColumnInfo"; +import RelationInfo from "./oldModels/RelationInfo"; +import EntityInfo from "./oldModels/EntityInfo"; +import ColumnInfo from "./oldModels/ColumnInfo"; export default abstract class AbstractNamingStrategy { public abstract relationName( diff --git a/src/Engine.ts b/src/Engine.ts index 687d26b..ecfcfee 100644 --- a/src/Engine.ts +++ b/src/Engine.ts @@ -6,7 +6,7 @@ import MssqlDriver from "./drivers/MssqlDriver"; import MariaDbDriver from "./drivers/MariaDbDriver"; import IConnectionOptions from "./IConnectionOptions"; import IGenerationOptions from "./IGenerationOptions"; -import EntityInfo from "./models/EntityInfo"; +import EntityInfo from "./oldModels/EntityInfo"; import PostgresDriver from "./drivers/PostgresDriver"; import MysqlDriver from "./drivers/MysqlDriver"; import OracleDriver from "./drivers/OracleDriver"; diff --git a/src/NamingStrategy.ts b/src/NamingStrategy.ts index bcdde51..9b3593a 100644 --- a/src/NamingStrategy.ts +++ b/src/NamingStrategy.ts @@ -1,6 +1,6 @@ import AbstractNamingStrategy from "./AbstractNamingStrategy"; -import RelationInfo from "./models/RelationInfo"; -import EntityInfo from "./models/EntityInfo"; +import RelationInfo from "./oldModels/RelationInfo"; +import EntityInfo from "./oldModels/EntityInfo"; import changeCase = require("change-case"); diff --git a/src/drivers/AbstractDriver.ts b/src/drivers/AbstractDriver.ts index 171444b..30c7246 100644 --- a/src/drivers/AbstractDriver.ts +++ b/src/drivers/AbstractDriver.ts @@ -5,12 +5,12 @@ import { } from "typeorm/driver/types/ColumnTypes"; import { DataTypeDefaults } from "typeorm/driver/types/DataTypeDefaults"; import * as TomgUtils from "../Utils"; -import EntityInfo from "../models/EntityInfo"; -import RelationInfo from "../models/RelationInfo"; -import ColumnInfo from "../models/ColumnInfo"; +import EntityInfo from "../oldModels/EntityInfo"; +import RelationInfo from "../oldModels/RelationInfo"; +import ColumnInfo from "../oldModels/ColumnInfo"; import IConnectionOptions from "../IConnectionOptions"; -import IndexInfo from "../models/IndexInfo"; -import RelationTempInfo from "../models/RelationTempInfo"; +import IndexInfo from "../oldModels/IndexInfo"; +import RelationTempInfo from "../oldModels/RelationTempInfo"; export default abstract class AbstractDriver { public abstract standardPort: number; diff --git a/src/drivers/MssqlDriver.ts b/src/drivers/MssqlDriver.ts index 2aed97b..fd887ab 100644 --- a/src/drivers/MssqlDriver.ts +++ b/src/drivers/MssqlDriver.ts @@ -4,11 +4,11 @@ import * as TypeormDriver from "typeorm/driver/sqlserver/SqlServerDriver"; import { DataTypeDefaults } from "typeorm/driver/types/DataTypeDefaults"; import * as TomgUtils from "../Utils"; import AbstractDriver from "./AbstractDriver"; -import EntityInfo from "../models/EntityInfo"; -import ColumnInfo from "../models/ColumnInfo"; -import IndexInfo from "../models/IndexInfo"; -import IndexColumnInfo from "../models/IndexColumnInfo"; -import RelationTempInfo from "../models/RelationTempInfo"; +import EntityInfo from "../oldModels/EntityInfo"; +import ColumnInfo from "../oldModels/ColumnInfo"; +import IndexInfo from "../oldModels/IndexInfo"; +import IndexColumnInfo from "../oldModels/IndexColumnInfo"; +import RelationTempInfo from "../oldModels/RelationTempInfo"; import IConnectionOptions from "../IConnectionOptions"; export default class MssqlDriver extends AbstractDriver { diff --git a/src/drivers/MysqlDriver.ts b/src/drivers/MysqlDriver.ts index 9878739..a13225b 100644 --- a/src/drivers/MysqlDriver.ts +++ b/src/drivers/MysqlDriver.ts @@ -4,11 +4,11 @@ import * as TypeormDriver from "typeorm/driver/mysql/MysqlDriver"; import { DataTypeDefaults } from "typeorm/driver/types/DataTypeDefaults"; import * as TomgUtils from "../Utils"; import AbstractDriver from "./AbstractDriver"; -import EntityInfo from "../models/EntityInfo"; -import ColumnInfo from "../models/ColumnInfo"; -import IndexInfo from "../models/IndexInfo"; -import IndexColumnInfo from "../models/IndexColumnInfo"; -import RelationTempInfo from "../models/RelationTempInfo"; +import EntityInfo from "../oldModels/EntityInfo"; +import ColumnInfo from "../oldModels/ColumnInfo"; +import IndexInfo from "../oldModels/IndexInfo"; +import IndexColumnInfo from "../oldModels/IndexColumnInfo"; +import RelationTempInfo from "../oldModels/RelationTempInfo"; import IConnectionOptions from "../IConnectionOptions"; export default class MysqlDriver extends AbstractDriver { diff --git a/src/drivers/OracleDriver.ts b/src/drivers/OracleDriver.ts index 2c7a208..d757c20 100644 --- a/src/drivers/OracleDriver.ts +++ b/src/drivers/OracleDriver.ts @@ -2,11 +2,11 @@ import * as TypeormDriver from "typeorm/driver/oracle/OracleDriver"; import { DataTypeDefaults } from "typeorm/driver/types/DataTypeDefaults"; import * as TomgUtils from "../Utils"; import AbstractDriver from "./AbstractDriver"; -import EntityInfo from "../models/EntityInfo"; -import ColumnInfo from "../models/ColumnInfo"; -import IndexInfo from "../models/IndexInfo"; -import IndexColumnInfo from "../models/IndexColumnInfo"; -import RelationTempInfo from "../models/RelationTempInfo"; +import EntityInfo from "../oldModels/EntityInfo"; +import ColumnInfo from "../oldModels/ColumnInfo"; +import IndexInfo from "../oldModels/IndexInfo"; +import IndexColumnInfo from "../oldModels/IndexColumnInfo"; +import RelationTempInfo from "../oldModels/RelationTempInfo"; import IConnectionOptions from "../IConnectionOptions"; export default class OracleDriver extends AbstractDriver { diff --git a/src/drivers/PostgresDriver.ts b/src/drivers/PostgresDriver.ts index 9dbb560..0ed8c2e 100644 --- a/src/drivers/PostgresDriver.ts +++ b/src/drivers/PostgresDriver.ts @@ -4,11 +4,11 @@ import * as TypeormDriver from "typeorm/driver/postgres/PostgresDriver"; import { DataTypeDefaults } from "typeorm/driver/types/DataTypeDefaults"; import * as TomgUtils from "../Utils"; import AbstractDriver from "./AbstractDriver"; -import EntityInfo from "../models/EntityInfo"; -import ColumnInfo from "../models/ColumnInfo"; -import IndexInfo from "../models/IndexInfo"; -import IndexColumnInfo from "../models/IndexColumnInfo"; -import RelationTempInfo from "../models/RelationTempInfo"; +import EntityInfo from "../oldModels/EntityInfo"; +import ColumnInfo from "../oldModels/ColumnInfo"; +import IndexInfo from "../oldModels/IndexInfo"; +import IndexColumnInfo from "../oldModels/IndexColumnInfo"; +import RelationTempInfo from "../oldModels/RelationTempInfo"; import IConnectionOptions from "../IConnectionOptions"; export default class PostgresDriver extends AbstractDriver { diff --git a/src/drivers/SqliteDriver.ts b/src/drivers/SqliteDriver.ts index 5dbadc5..f5f57e8 100644 --- a/src/drivers/SqliteDriver.ts +++ b/src/drivers/SqliteDriver.ts @@ -4,11 +4,11 @@ import { DataTypeDefaults } from "typeorm/driver/types/DataTypeDefaults"; import * as sqliteLib from "sqlite3"; import * as TomgUtils from "../Utils"; import AbstractDriver from "./AbstractDriver"; -import EntityInfo from "../models/EntityInfo"; -import ColumnInfo from "../models/ColumnInfo"; -import IndexInfo from "../models/IndexInfo"; -import IndexColumnInfo from "../models/IndexColumnInfo"; -import RelationTempInfo from "../models/RelationTempInfo"; +import EntityInfo from "../oldModels/EntityInfo"; +import ColumnInfo from "../oldModels/ColumnInfo"; +import IndexInfo from "../oldModels/IndexInfo"; +import IndexColumnInfo from "../oldModels/IndexColumnInfo"; +import RelationTempInfo from "../oldModels/RelationTempInfo"; import IConnectionOptions from "../IConnectionOptions"; export default class SqliteDriver extends AbstractDriver { diff --git a/src/models/ColumnInfo.ts b/src/oldModels/ColumnInfo.ts similarity index 100% rename from src/models/ColumnInfo.ts rename to src/oldModels/ColumnInfo.ts diff --git a/src/models/EntityInfo.ts b/src/oldModels/EntityInfo.ts similarity index 100% rename from src/models/EntityInfo.ts rename to src/oldModels/EntityInfo.ts diff --git a/src/models/IndexColumnInfo.ts b/src/oldModels/IndexColumnInfo.ts similarity index 100% rename from src/models/IndexColumnInfo.ts rename to src/oldModels/IndexColumnInfo.ts diff --git a/src/models/IndexInfo.ts b/src/oldModels/IndexInfo.ts similarity index 100% rename from src/models/IndexInfo.ts rename to src/oldModels/IndexInfo.ts diff --git a/src/models/RelationInfo.ts b/src/oldModels/RelationInfo.ts similarity index 100% rename from src/models/RelationInfo.ts rename to src/oldModels/RelationInfo.ts diff --git a/src/models/RelationTempInfo.ts b/src/oldModels/RelationTempInfo.ts similarity index 100% rename from src/models/RelationTempInfo.ts rename to src/oldModels/RelationTempInfo.ts diff --git a/test/drivers/MssqlDriver.test.ts b/test/drivers/MssqlDriver.test.ts index 4a15204..2381625 100644 --- a/test/drivers/MssqlDriver.test.ts +++ b/test/drivers/MssqlDriver.test.ts @@ -2,10 +2,10 @@ import { expect } from "chai"; import * as MSSQL from "mssql"; import * as Sinon from "sinon"; import MssqlDriver from "../../src/drivers/MssqlDriver"; -import EntityInfo from "../../src/models/EntityInfo"; -import ColumnInfo from "../../src/models/ColumnInfo"; -import IndexInfo from "../../src/models/IndexInfo"; -import RelationInfo from "../../src/models/RelationInfo"; +import EntityInfo from "../../src/oldModels/EntityInfo"; +import ColumnInfo from "../../src/oldModels/ColumnInfo"; +import IndexInfo from "../../src/oldModels/IndexInfo"; +import RelationInfo from "../../src/oldModels/RelationInfo"; interface FakeResponse extends MSSQL.IResult { recordsets: MSSQL.IRecordSet[]; diff --git a/test/integration/runTestsFromPath.test.ts b/test/integration/runTestsFromPath.test.ts index 47674a5..24d9294 100644 --- a/test/integration/runTestsFromPath.test.ts +++ b/test/integration/runTestsFromPath.test.ts @@ -9,7 +9,7 @@ import { modelGenerationPhase } from "../../src/Engine"; import * as GTU from "../utils/GeneralTestUtils"; -import EntityInfo from "../../src/models/EntityInfo"; +import EntityInfo from "../../src/oldModels/EntityInfo"; import IConnectionOptions from "../../src/IConnectionOptions"; import fs = require("fs-extra"); From a13da7848e56fcc5e3d2c7f079a18a3b23a4755a Mon Sep 17 00:00:00 2001 From: Kononnable Date: Thu, 26 Sep 2019 20:35:10 +0200 Subject: [PATCH 02/84] new model files --- src/models/Column.ts | 33 +++++++++++++++++++++++++++++++++ src/models/Entity.ts | 15 +++++++++++++++ src/models/Index.ts | 5 +++++ src/models/Relation.ts | 19 +++++++++++++++++++ 4 files changed, 72 insertions(+) create mode 100644 src/models/Column.ts create mode 100644 src/models/Entity.ts create mode 100644 src/models/Index.ts create mode 100644 src/models/Relation.ts diff --git a/src/models/Column.ts b/src/models/Column.ts new file mode 100644 index 0000000..5f3fa82 --- /dev/null +++ b/src/models/Column.ts @@ -0,0 +1,33 @@ +import { ColumnType } from "typeorm"; + +export type Column = { + primary?: boolean; + + sqlType: ColumnType; + + typescriptType: any; + + name?: string; + + length?: number; + + width?: number; + + nullable?: boolean; + + generated?: true | "increment" | "uuid"; + + unique?: boolean; + + default?: boolean; + + precision?: number; + + scale?: number; + + unsigned?: boolean; + + enum?: string[]; + + array?: boolean; +}; diff --git a/src/models/Entity.ts b/src/models/Entity.ts new file mode 100644 index 0000000..c3a28db --- /dev/null +++ b/src/models/Entity.ts @@ -0,0 +1,15 @@ +import { Column } from "./Column"; +import { Relation } from "./Relation"; +import { Index } from "./Index"; + +export type Entity = { + sqlName: string; + typescriptName?: string; + + database?: string; + schema?: string; + + columns: Column[]; + relations?: Relation[]; + indices?: Index[]; +}; diff --git a/src/models/Index.ts b/src/models/Index.ts new file mode 100644 index 0000000..0de83cc --- /dev/null +++ b/src/models/Index.ts @@ -0,0 +1,5 @@ +export type Index = { + name?: string; + columns?: ((object?: any) => any[] | { [key: string]: number }) | string[]; + unique?: boolean; +}; diff --git a/src/models/Relation.ts b/src/models/Relation.ts new file mode 100644 index 0000000..153d4ec --- /dev/null +++ b/src/models/Relation.ts @@ -0,0 +1,19 @@ +import { OnUpdateType } from "typeorm/metadata/types/OnUpdateType"; +import { OnDeleteType } from "typeorm/metadata/types/OnDeleteType"; +import { RelationType } from "typeorm/metadata/types/RelationTypes"; +import { JoinTableOptions, JoinColumnOptions } from "typeorm"; +import { JoinTableMultipleColumnsOptions } from "typeorm/decorator/options/JoinTableMultipleColumnsOptions"; + +export type Relation = { + target: Function | string; + type: RelationType; + inverseSide?: string; + // lazy?: boolean; + // eager?: boolean; + // primary?: boolean; + joinTable?: boolean | JoinTableOptions | JoinTableMultipleColumnsOptions; + joinColumn?: boolean | JoinColumnOptions; + nullable?: boolean; + onDelete?: OnDeleteType; + onUpdate?: OnUpdateType; +}; From fb529bca0bdf8f5d86fe5545dd186408be4b5ee1 Mon Sep 17 00:00:00 2001 From: Kononnable Date: Tue, 1 Oct 2019 22:36:37 +0200 Subject: [PATCH 03/84] changes in model, basic template file --- src/Engine.ts | 104 +++++++++++++++++++++++++++++++++-------- src/entity.mst | 27 +++++++++++ src/models/Column.ts | 44 +++++++---------- src/models/Entity.ts | 2 +- src/models/Relation.ts | 23 ++++----- 5 files changed, 138 insertions(+), 62 deletions(-) diff --git a/src/Engine.ts b/src/Engine.ts index ecfcfee..23c4bc5 100644 --- a/src/Engine.ts +++ b/src/Engine.ts @@ -17,6 +17,7 @@ import AbstractNamingStrategy from "./AbstractNamingStrategy"; import changeCase = require("change-case"); import fs = require("fs"); import path = require("path"); +import { Entity } from "./models/Entity"; export function createDriver(driverName: string): AbstractDriver { switch (driverName) { @@ -43,20 +44,80 @@ export async function createModelFromDatabase( connectionOptions: IConnectionOptions, generationOptions: IGenerationOptions ) { - let dbModel = await dataCollectionPhase(driver, connectionOptions); - if (dbModel.length === 0) { - TomgUtils.LogError( - "Tables not found in selected database. Skipping creation of typeorm model.", - false - ); - return; - } - dbModel = modelCustomizationPhase( - dbModel, - generationOptions, - driver.defaultValues - ); - modelGenerationPhase(connectionOptions, generationOptions, dbModel); + // let dbModel = await dataCollectionPhase(driver, connectionOptions); + // if (dbModel.length === 0) { + // TomgUtils.LogError( + // "Tables not found in selected database. Skipping creation of typeorm model.", + // false + // ); + // return; + // } + // dbModel = modelCustomizationPhase( + // dbModel, + // generationOptions, + // driver.defaultValues + // ); + const dbModel: Entity = { + sqlName: "sqlName", + tscName: "typescriptName", + schema: "schema", + database: "database", + columns: [ + { + tscType: "typescriptType", + tscName: "tscName", + options: { + name: "sqlName", + type: "integer", + length: 2, + scale: 2 + } + }, + { + tscType: "typescriptType", + tscName: "tscName", + options: { + name: "sqlName", + type: "integer", + length: 2, + scale: 2 + } + } + ], + indices: [ + { + columns: ["columns"], + name: "name" + }, + { + columns: ["columns"], + name: "name" + } + ], + relations: [ + { + relationType: "OneToMany", + relatedField: "relatedField", + fieldName: "relation", + relatedTable: "any", + relationOptions: { + onUpdate: "CASCADE", + onDelete: "NO ACTION" + } + }, + { + relationType: "OneToOne", + relatedField: "relatedField", + fieldName: "relation", + relatedTable: "any", + relationOptions: { + onUpdate: "CASCADE", + onDelete: "NO ACTION" + } + } + ] + }; + modelGenerationPhase(connectionOptions, generationOptions, [dbModel]); } export async function dataCollectionPhase( driver: AbstractDriver, @@ -172,7 +233,7 @@ function setRelationId( export function modelGenerationPhase( connectionOptions: IConnectionOptions, generationOptions: IGenerationOptions, - databaseModel: EntityInfo[] + databaseModel: Entity[] ) { createHandlebarsHelpers(generationOptions); const templatePath = path.resolve(__dirname, "entity.mst"); @@ -197,16 +258,16 @@ export function modelGenerationPhase( let casedFileName = ""; switch (generationOptions.convertCaseFile) { case "camel": - casedFileName = changeCase.camelCase(element.tsEntityName); + casedFileName = changeCase.camelCase(element.tscName); break; case "param": - casedFileName = changeCase.paramCase(element.tsEntityName); + casedFileName = changeCase.paramCase(element.tscName); break; case "pascal": - casedFileName = changeCase.pascalCase(element.tsEntityName); + casedFileName = changeCase.pascalCase(element.tscName); break; case "none": - casedFileName = element.tsEntityName; + casedFileName = element.tscName; break; default: throw new Error("Unknown case style"); @@ -221,6 +282,11 @@ export function modelGenerationPhase( } function createHandlebarsHelpers(generationOptions: IGenerationOptions) { + Handlebars.registerHelper("json", context => { + const json = JSON.stringify(context); + const withoutQuotes = json.replace(/"([^(")"]+)":/g, "$1:"); + return withoutQuotes.slice(1, withoutQuotes.length - 1); + }); Handlebars.registerHelper("curly", open => (open ? "{" : "}")); Handlebars.registerHelper("toEntityName", str => { let retStr = ""; diff --git a/src/entity.mst b/src/entity.mst index e809475..f68900e 100644 --- a/src/entity.mst +++ b/src/entity.mst @@ -1,3 +1,30 @@ +{{#*inline "Index"}} +@Index("{{name}}") +{{/inline}} +{{#*inline "Column"}} +{{#generated}}@PrimaryGeneratedColumn({ {{/generated}}{{^generated}}@Column({ {{#primary}}primary:{{primary}},{{/primary}}{{/generated}}{{json options}} }) +{{tscName}}:{{tscType}}; + +{{/inline}} +{{#*inline "Relation"}} +@{{relationType}}(()=>{{relatedTable}},{{relatedTable}}=>{{relatedTable}}.{{relatedField}},{ {{json relationOptions}} }) +{{fieldName}}:{{relatedTable}}; + +{{/inline}} +{{#*inline "Entity"}} +{{#indices}}{{> Index}}{{/indices~}} +@Entity("{{sqlName}}",{schema:"{{schema}}",database:"{{database}}"}) +export class {{tscName}} { + +{{#columns}}{{> Column}}{{/columns~}} +{{#relations}}{{> Relation}}{{/relations~}} +} +{{/inline}} + +{{~> Entity}} + + + import {BaseEntity,Column,Entity,Index,JoinColumn,JoinTable,ManyToMany,ManyToOne,OneToMany,OneToOne,PrimaryColumn,PrimaryGeneratedColumn,RelationId} from "typeorm"; {{relationImports}}{{#each UniqueImports}}import {{curly true}}{{toEntityName this}}{{curly false}} from "./{{toFileName this}}"; {{/each}} diff --git a/src/models/Column.ts b/src/models/Column.ts index 5f3fa82..e5f8c5c 100644 --- a/src/models/Column.ts +++ b/src/models/Column.ts @@ -1,33 +1,23 @@ import { ColumnType } from "typeorm"; export type Column = { + tscType: any; + tscName: string; + primary?: boolean; - - sqlType: ColumnType; - - typescriptType: any; - - name?: string; - - length?: number; - - width?: number; - - nullable?: boolean; - generated?: true | "increment" | "uuid"; - - unique?: boolean; - - default?: boolean; - - precision?: number; - - scale?: number; - - unsigned?: boolean; - - enum?: string[]; - - array?: boolean; + options: { + type: ColumnType; + name: string; + length?: number; + width?: number; + nullable?: boolean; + unique?: boolean; // ? + default?: boolean; + precision?: number; + scale?: number; + unsigned?: boolean; + enum?: string[]; + array?: boolean; // ? + }; }; diff --git a/src/models/Entity.ts b/src/models/Entity.ts index c3a28db..126f6ad 100644 --- a/src/models/Entity.ts +++ b/src/models/Entity.ts @@ -4,7 +4,7 @@ import { Index } from "./Index"; export type Entity = { sqlName: string; - typescriptName?: string; + tscName: string; database?: string; schema?: string; diff --git a/src/models/Relation.ts b/src/models/Relation.ts index 153d4ec..d3ef883 100644 --- a/src/models/Relation.ts +++ b/src/models/Relation.ts @@ -1,19 +1,12 @@ -import { OnUpdateType } from "typeorm/metadata/types/OnUpdateType"; -import { OnDeleteType } from "typeorm/metadata/types/OnDeleteType"; -import { RelationType } from "typeorm/metadata/types/RelationTypes"; -import { JoinTableOptions, JoinColumnOptions } from "typeorm"; +import { JoinColumnOptions, RelationOptions } from "typeorm"; import { JoinTableMultipleColumnsOptions } from "typeorm/decorator/options/JoinTableMultipleColumnsOptions"; export type Relation = { - target: Function | string; - type: RelationType; - inverseSide?: string; - // lazy?: boolean; - // eager?: boolean; - // primary?: boolean; - joinTable?: boolean | JoinTableOptions | JoinTableMultipleColumnsOptions; - joinColumn?: boolean | JoinColumnOptions; - nullable?: boolean; - onDelete?: OnDeleteType; - onUpdate?: OnUpdateType; + relationType: "OneToOne" | "OneToMany" | "ManyToOne" | "ManyToMany"; + relatedTable: string; + relatedField: string; + fieldName: string; + relationOptions: RelationOptions; + joinColumnOptions?: JoinColumnOptions[]; + joinTableOptions?: JoinTableMultipleColumnsOptions; }; From ab23f71756b9919b05ada6f3fcf0409b5522296c Mon Sep 17 00:00:00 2001 From: Kononnable Date: Wed, 2 Oct 2019 14:04:23 +0200 Subject: [PATCH 04/84] temporatry disabling part of code --- src/drivers/AbstractDriver.ts | 53 ++-- src/drivers/MssqlDriver.ts | 357 +++++++++++----------- src/drivers/MysqlDriver.ts | 147 ++++----- src/drivers/OracleDriver.ts | 311 +++++++++---------- src/drivers/PostgresDriver.ts | 237 +++++++------- src/drivers/SqliteDriver.ts | 345 ++++++++++----------- src/models/Column.ts | 2 +- test/drivers/MssqlDriver.test.ts | 15 +- test/integration/runTestsFromPath.test.ts | 116 +++---- 9 files changed, 801 insertions(+), 782 deletions(-) diff --git a/src/drivers/AbstractDriver.ts b/src/drivers/AbstractDriver.ts index 30c7246..ad5b5dc 100644 --- a/src/drivers/AbstractDriver.ts +++ b/src/drivers/AbstractDriver.ts @@ -11,6 +11,7 @@ import ColumnInfo from "../oldModels/ColumnInfo"; import IConnectionOptions from "../IConnectionOptions"; import IndexInfo from "../oldModels/IndexInfo"; import RelationTempInfo from "../oldModels/RelationTempInfo"; +import { Entity } from "../models/Entity"; export default abstract class AbstractDriver { public abstract standardPort: number; @@ -159,8 +160,8 @@ export default abstract class AbstractDriver { public async GetDataFromServer( connectionOptons: IConnectionOptions - ): Promise { - let dbModel = [] as EntityInfo[]; + ): Promise { + let dbModel = [] as Entity[]; await this.ConnectToServer(connectionOptons); const sqlEscapedSchema = AbstractDriver.escapeCommaSeparatedList( connectionOptons.schemaName @@ -174,19 +175,20 @@ export default abstract class AbstractDriver { sqlEscapedSchema, connectionOptons.databaseName ); - await this.GetIndexesFromEntity( - dbModel, - sqlEscapedSchema, - connectionOptons.databaseName - ); - dbModel = await this.GetRelations( - dbModel, - sqlEscapedSchema, - connectionOptons.databaseName - ); + // TODO: Uncomment + // await this.GetIndexesFromEntity( + // dbModel, + // sqlEscapedSchema, + // connectionOptons.databaseName + // ); + // dbModel = await this.GetRelations( + // dbModel, + // sqlEscapedSchema, + // connectionOptons.databaseName + // ); await this.DisconnectFromServer(); - dbModel = AbstractDriver.FindManyToManyRelations(dbModel); - AbstractDriver.FindPrimaryColumnsFromIndexes(dbModel); + // dbModel = AbstractDriver.FindManyToManyRelations(dbModel); + // AbstractDriver.FindPrimaryColumnsFromIndexes(dbModel); return dbModel; } @@ -195,18 +197,17 @@ export default abstract class AbstractDriver { public async GetAllTables( schema: string, dbNames: string - ): Promise { + ): Promise { const response = await this.GetAllTablesQuery(schema, dbNames); - const ret: EntityInfo[] = [] as EntityInfo[]; + const ret: Entity[] = [] as Entity[]; response.forEach(val => { - const ent: EntityInfo = new EntityInfo(); - ent.tsEntityName = val.TABLE_NAME; - ent.sqlEntityName = val.TABLE_NAME; - ent.Schema = val.TABLE_SCHEMA; - ent.Columns = [] as ColumnInfo[]; - ent.Indexes = [] as IndexInfo[]; - ent.Database = dbNames.includes(",") ? val.DB_NAME : ""; - ret.push(ent); + ret.push({ + columns: [], + sqlName: val.TABLE_NAME, + tscName: val.TABLE_NAME, + database: dbNames.includes(",") ? val.DB_NAME : "", + schema: val.TABLE_SCHEMA + }); }); return ret; } @@ -374,10 +375,10 @@ export default abstract class AbstractDriver { } public abstract async GetCoulmnsFromEntity( - entities: EntityInfo[], + entities: Entity[], schema: string, dbNames: string - ): Promise; + ): Promise; public abstract async GetIndexesFromEntity( entities: EntityInfo[], diff --git a/src/drivers/MssqlDriver.ts b/src/drivers/MssqlDriver.ts index fd887ab..290e786 100644 --- a/src/drivers/MssqlDriver.ts +++ b/src/drivers/MssqlDriver.ts @@ -10,6 +10,7 @@ import IndexInfo from "../oldModels/IndexInfo"; import IndexColumnInfo from "../oldModels/IndexColumnInfo"; import RelationTempInfo from "../oldModels/RelationTempInfo"; import IConnectionOptions from "../IConnectionOptions"; +import { Entity } from "../models/Entity"; export default class MssqlDriver extends AbstractDriver { public defaultValues: DataTypeDefaults = new TypeormDriver.SqlServerDriver({ @@ -40,187 +41,189 @@ WHERE TABLE_TYPE='BASE TABLE' and TABLE_SCHEMA in (${schema}) AND TABLE_CATALOG }; public async GetCoulmnsFromEntity( - entities: EntityInfo[], + entities: Entity[], schema: string, dbNames: string - ): Promise { - const request = new MSSQL.Request(this.Connection); - const response: { - TABLE_NAME: string; - COLUMN_NAME: string; - COLUMN_DEFAULT: string; - IS_NULLABLE: string; - DATA_TYPE: string; - CHARACTER_MAXIMUM_LENGTH: number; - NUMERIC_PRECISION: number; - NUMERIC_SCALE: number; - IsIdentity: number; - IsUnique: number; - }[] = (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(*) - FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS tc - inner join INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE cu - on cu.CONSTRAINT_NAME = tc.CONSTRAINT_NAME - where - tc.CONSTRAINT_TYPE = 'UNIQUE' - and tc.TABLE_NAME = c.TABLE_NAME - and cu.COLUMN_NAME = c.COLUMN_NAME - and tc.TABLE_SCHEMA=c.TABLE_SCHEMA) IsUnique - FROM INFORMATION_SCHEMA.COLUMNS c - where TABLE_SCHEMA in (${schema}) AND TABLE_CATALOG in (${MssqlDriver.escapeCommaSeparatedList( - dbNames - )}) - order by ordinal_position`)).recordset; - entities.forEach(ent => { - response - .filter(filterVal => { - return filterVal.TABLE_NAME === ent.tsEntityName; - }) - .forEach(resp => { - const colInfo: ColumnInfo = new ColumnInfo(); - colInfo.tsName = resp.COLUMN_NAME; - colInfo.options.name = resp.COLUMN_NAME; - colInfo.options.nullable = resp.IS_NULLABLE === "YES"; - colInfo.options.generated = resp.IsIdentity === 1; - colInfo.options.unique = resp.IsUnique === 1; - colInfo.options.default = MssqlDriver.ReturnDefaultValueFunction( - resp.COLUMN_DEFAULT - ); - colInfo.options.type = resp.DATA_TYPE as any; - switch (resp.DATA_TYPE) { - case "bigint": - colInfo.tsType = "string"; - break; - case "bit": - colInfo.tsType = "boolean"; - break; - case "decimal": - colInfo.tsType = "number"; - break; - case "int": - colInfo.tsType = "number"; - break; - case "money": - colInfo.tsType = "number"; - break; - case "numeric": - colInfo.tsType = "number"; - break; - case "smallint": - colInfo.tsType = "number"; - break; - case "smallmoney": - colInfo.tsType = "number"; - break; - case "tinyint": - colInfo.tsType = "number"; - break; - case "float": - colInfo.tsType = "number"; - break; - case "real": - colInfo.tsType = "number"; - break; - case "date": - colInfo.tsType = "Date"; - break; - case "datetime2": - colInfo.tsType = "Date"; - break; - case "datetime": - colInfo.tsType = "Date"; - break; - case "datetimeoffset": - colInfo.tsType = "Date"; - break; - case "smalldatetime": - colInfo.tsType = "Date"; - break; - case "time": - colInfo.tsType = "Date"; - break; - case "char": - colInfo.tsType = "string"; - break; - case "text": - colInfo.tsType = "string"; - break; - case "varchar": - colInfo.tsType = "string"; - break; - case "nchar": - colInfo.tsType = "string"; - break; - case "ntext": - colInfo.tsType = "string"; - break; - case "nvarchar": - colInfo.tsType = "string"; - break; - case "binary": - colInfo.tsType = "Buffer"; - break; - case "image": - colInfo.tsType = "Buffer"; - break; - case "varbinary": - colInfo.tsType = "Buffer"; - break; - case "hierarchyid": - colInfo.tsType = "string"; - break; - case "sql_variant": - colInfo.tsType = "string"; - break; - case "timestamp": - colInfo.tsType = "Date"; - break; - case "uniqueidentifier": - colInfo.tsType = "string"; - break; - case "xml": - colInfo.tsType = "string"; - break; - case "geometry": - colInfo.tsType = "string"; - break; - case "geography": - colInfo.tsType = "string"; - break; - default: - TomgUtils.LogError( - `Unknown column type: ${resp.DATA_TYPE} table name: ${resp.TABLE_NAME} column name: ${resp.COLUMN_NAME}` - ); - break; - } + ): Promise { + throw new Error(); + // TODO: Remove + // const request = new MSSQL.Request(this.Connection); + // const response: { + // TABLE_NAME: string; + // COLUMN_NAME: string; + // COLUMN_DEFAULT: string; + // IS_NULLABLE: string; + // DATA_TYPE: string; + // CHARACTER_MAXIMUM_LENGTH: number; + // NUMERIC_PRECISION: number; + // NUMERIC_SCALE: number; + // IsIdentity: number; + // IsUnique: number; + // }[] = (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(*) + // FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS tc + // inner join INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE cu + // on cu.CONSTRAINT_NAME = tc.CONSTRAINT_NAME + // where + // tc.CONSTRAINT_TYPE = 'UNIQUE' + // and tc.TABLE_NAME = c.TABLE_NAME + // and cu.COLUMN_NAME = c.COLUMN_NAME + // and tc.TABLE_SCHEMA=c.TABLE_SCHEMA) IsUnique + // FROM INFORMATION_SCHEMA.COLUMNS c + // where TABLE_SCHEMA in (${schema}) AND TABLE_CATALOG in (${MssqlDriver.escapeCommaSeparatedList( + // dbNames + // )}) + // order by ordinal_position`)).recordset; + // entities.forEach(ent => { + // response + // .filter(filterVal => { + // return filterVal.TABLE_NAME === ent.tsEntityName; + // }) + // .forEach(resp => { + // const colInfo: ColumnInfo = new ColumnInfo(); + // colInfo.tsName = resp.COLUMN_NAME; + // colInfo.options.name = resp.COLUMN_NAME; + // colInfo.options.nullable = resp.IS_NULLABLE === "YES"; + // colInfo.options.generated = resp.IsIdentity === 1; + // colInfo.options.unique = resp.IsUnique === 1; + // colInfo.options.default = MssqlDriver.ReturnDefaultValueFunction( + // resp.COLUMN_DEFAULT + // ); + // colInfo.options.type = resp.DATA_TYPE as any; + // switch (resp.DATA_TYPE) { + // case "bigint": + // colInfo.tsType = "string"; + // break; + // case "bit": + // colInfo.tsType = "boolean"; + // break; + // case "decimal": + // colInfo.tsType = "number"; + // break; + // case "int": + // colInfo.tsType = "number"; + // break; + // case "money": + // colInfo.tsType = "number"; + // break; + // case "numeric": + // colInfo.tsType = "number"; + // break; + // case "smallint": + // colInfo.tsType = "number"; + // break; + // case "smallmoney": + // colInfo.tsType = "number"; + // break; + // case "tinyint": + // colInfo.tsType = "number"; + // break; + // case "float": + // colInfo.tsType = "number"; + // break; + // case "real": + // colInfo.tsType = "number"; + // break; + // case "date": + // colInfo.tsType = "Date"; + // break; + // case "datetime2": + // colInfo.tsType = "Date"; + // break; + // case "datetime": + // colInfo.tsType = "Date"; + // break; + // case "datetimeoffset": + // colInfo.tsType = "Date"; + // break; + // case "smalldatetime": + // colInfo.tsType = "Date"; + // break; + // case "time": + // colInfo.tsType = "Date"; + // break; + // case "char": + // colInfo.tsType = "string"; + // break; + // case "text": + // colInfo.tsType = "string"; + // break; + // case "varchar": + // colInfo.tsType = "string"; + // break; + // case "nchar": + // colInfo.tsType = "string"; + // break; + // case "ntext": + // colInfo.tsType = "string"; + // break; + // case "nvarchar": + // colInfo.tsType = "string"; + // break; + // case "binary": + // colInfo.tsType = "Buffer"; + // break; + // case "image": + // colInfo.tsType = "Buffer"; + // break; + // case "varbinary": + // colInfo.tsType = "Buffer"; + // break; + // case "hierarchyid": + // colInfo.tsType = "string"; + // break; + // case "sql_variant": + // colInfo.tsType = "string"; + // break; + // case "timestamp": + // colInfo.tsType = "Date"; + // break; + // case "uniqueidentifier": + // colInfo.tsType = "string"; + // break; + // case "xml": + // colInfo.tsType = "string"; + // break; + // case "geometry": + // colInfo.tsType = "string"; + // break; + // case "geography": + // colInfo.tsType = "string"; + // break; + // default: + // TomgUtils.LogError( + // `Unknown column type: ${resp.DATA_TYPE} table name: ${resp.TABLE_NAME} column name: ${resp.COLUMN_NAME}` + // ); + // break; + // } - if ( - this.ColumnTypesWithPrecision.some( - v => v === colInfo.options.type - ) - ) { - colInfo.options.precision = resp.NUMERIC_PRECISION; - colInfo.options.scale = resp.NUMERIC_SCALE; - } - if ( - this.ColumnTypesWithLength.some( - v => v === colInfo.options.type - ) - ) { - colInfo.options.length = - resp.CHARACTER_MAXIMUM_LENGTH > 0 - ? resp.CHARACTER_MAXIMUM_LENGTH - : undefined; - } + // if ( + // this.ColumnTypesWithPrecision.some( + // v => v === colInfo.options.type + // ) + // ) { + // colInfo.options.precision = resp.NUMERIC_PRECISION; + // colInfo.options.scale = resp.NUMERIC_SCALE; + // } + // if ( + // this.ColumnTypesWithLength.some( + // v => v === colInfo.options.type + // ) + // ) { + // colInfo.options.length = + // resp.CHARACTER_MAXIMUM_LENGTH > 0 + // ? resp.CHARACTER_MAXIMUM_LENGTH + // : undefined; + // } - if (colInfo.options.type) { - ent.Columns.push(colInfo); - } - }); - }); - return entities; + // if (colInfo.options.type) { + // ent.Columns.push(colInfo); + // } + // }); + // }); + // return entities; } public async GetIndexesFromEntity( diff --git a/src/drivers/MysqlDriver.ts b/src/drivers/MysqlDriver.ts index a13225b..07e3e4f 100644 --- a/src/drivers/MysqlDriver.ts +++ b/src/drivers/MysqlDriver.ts @@ -10,6 +10,8 @@ import IndexInfo from "../oldModels/IndexInfo"; import IndexColumnInfo from "../oldModels/IndexColumnInfo"; import RelationTempInfo from "../oldModels/RelationTempInfo"; import IConnectionOptions from "../IConnectionOptions"; +import { Entity } from "../models/Entity"; +import { Column } from "../models/Column"; export default class MysqlDriver extends AbstractDriver { public defaultValues: DataTypeDefaults = new TypeormDriver.MysqlDriver({ @@ -41,10 +43,10 @@ export default class MysqlDriver extends AbstractDriver { }; public async GetCoulmnsFromEntity( - entities: EntityInfo[], + entities: Entity[], schema: string, dbNames: string - ): Promise { + ): Promise { const response = await this.ExecQuery<{ TABLE_NAME: string; COLUMN_NAME: string; @@ -66,150 +68,149 @@ export default class MysqlDriver extends AbstractDriver { order by ordinal_position`); entities.forEach(ent => { response - .filter(filterVal => filterVal.TABLE_NAME === ent.tsEntityName) + .filter(filterVal => filterVal.TABLE_NAME === ent.tscName) .forEach(resp => { - const colInfo: ColumnInfo = new ColumnInfo(); - colInfo.tsName = resp.COLUMN_NAME; - colInfo.options.name = resp.COLUMN_NAME; - colInfo.options.nullable = resp.IS_NULLABLE === "YES"; - colInfo.options.generated = resp.IsIdentity === 1; - colInfo.options.unique = resp.COLUMN_KEY === "UNI"; - colInfo.options.default = MysqlDriver.ReturnDefaultValueFunction( + const tscName = resp.COLUMN_NAME; + let tscType = ""; + const options: Partial = {}; + options.name = resp.COLUMN_NAME; + options.nullable = resp.IS_NULLABLE === "YES"; + const generated = resp.IsIdentity === 1 ? true : undefined; + options.unique = resp.COLUMN_KEY === "UNI"; + options.default = MysqlDriver.ReturnDefaultValueFunction( resp.COLUMN_DEFAULT ); - colInfo.options.type = resp.DATA_TYPE as any; - colInfo.options.unsigned = resp.COLUMN_TYPE.endsWith( - " unsigned" - ); + options.type = resp.DATA_TYPE as any; + options.unsigned = resp.COLUMN_TYPE.endsWith(" unsigned"); switch (resp.DATA_TYPE) { case "int": - colInfo.tsType = "number"; + tscType = "number"; break; case "bit": if (resp.COLUMN_TYPE === "bit(1)") { - colInfo.options.width = 1; - colInfo.tsType = "boolean"; + options.width = 1; + tscType = "boolean"; } else { - colInfo.tsType = "number"; + tscType = "number"; } break; case "tinyint": if (resp.COLUMN_TYPE === "tinyint(1)") { - colInfo.options.width = 1; - colInfo.tsType = "boolean"; + options.width = 1; + tscType = "boolean"; } else { - colInfo.tsType = "number"; + tscType = "number"; } break; case "smallint": - colInfo.tsType = "number"; + tscType = "number"; break; case "mediumint": - colInfo.tsType = "number"; + tscType = "number"; break; case "bigint": - colInfo.tsType = "string"; + tscType = "string"; break; case "float": - colInfo.tsType = "number"; + tscType = "number"; break; case "double": - colInfo.tsType = "number"; + tscType = "number"; break; case "decimal": - colInfo.tsType = "string"; + tscType = "string"; break; case "date": - colInfo.tsType = "string"; + tscType = "string"; break; case "datetime": - colInfo.tsType = "Date"; + tscType = "Date"; break; case "timestamp": - colInfo.tsType = "Date"; + tscType = "Date"; break; case "time": - colInfo.tsType = "string"; + tscType = "string"; break; case "year": - colInfo.tsType = "number"; + tscType = "number"; break; case "char": - colInfo.tsType = "string"; + tscType = "string"; break; case "varchar": - colInfo.tsType = "string"; + tscType = "string"; break; case "blob": - colInfo.tsType = "Buffer"; + tscType = "Buffer"; break; case "text": - colInfo.tsType = "string"; + tscType = "string"; break; case "tinyblob": - colInfo.tsType = "Buffer"; + tscType = "Buffer"; break; case "tinytext": - colInfo.tsType = "string"; + tscType = "string"; break; case "mediumblob": - colInfo.tsType = "Buffer"; + tscType = "Buffer"; break; case "mediumtext": - colInfo.tsType = "string"; + tscType = "string"; break; case "longblob": - colInfo.tsType = "Buffer"; + tscType = "Buffer"; break; case "longtext": - colInfo.tsType = "string"; + tscType = "string"; break; case "enum": - colInfo.tsType = resp.COLUMN_TYPE.substring( + tscType = resp.COLUMN_TYPE.substring( 5, resp.COLUMN_TYPE.length - 1 ) .replace(/'/gi, '"') .replace(/","/gi, '" | "'); - colInfo.options.enum = resp.COLUMN_TYPE.substring( + options.enum = resp.COLUMN_TYPE.substring( 5, resp.COLUMN_TYPE.length - 1 ).replace(/'/gi, '"'); break; case "json": - colInfo.tsType = "object"; + tscType = "object"; break; case "binary": - colInfo.tsType = "Buffer"; + tscType = "Buffer"; break; case "varbinary": - colInfo.tsType = "Buffer"; + tscType = "Buffer"; break; case "geometry": - colInfo.tsType = "string"; + tscType = "string"; break; case "point": - colInfo.tsType = "string"; + tscType = "string"; break; case "linestring": - colInfo.tsType = "string"; + tscType = "string"; break; case "polygon": - colInfo.tsType = "string"; + tscType = "string"; break; case "multipoint": - colInfo.tsType = "string"; + tscType = "string"; break; case "multilinestring": - colInfo.tsType = "string"; + tscType = "string"; break; case "multipolygon": - colInfo.tsType = "string"; + tscType = "string"; break; case "geometrycollection": case "geomcollection": - colInfo.options.type = "geometrycollection"; - colInfo.tsType = "string"; + options.type = "geometrycollection"; + tscType = "string"; break; default: TomgUtils.LogError( @@ -219,37 +220,39 @@ export default class MysqlDriver extends AbstractDriver { } if ( this.ColumnTypesWithPrecision.some( - v => v === colInfo.options.type + v => v === options.type ) ) { - colInfo.options.precision = resp.NUMERIC_PRECISION; - colInfo.options.scale = resp.NUMERIC_SCALE; + options.precision = resp.NUMERIC_PRECISION; + options.scale = resp.NUMERIC_SCALE; } if ( - this.ColumnTypesWithLength.some( - v => v === colInfo.options.type - ) + this.ColumnTypesWithLength.some(v => v === options.type) ) { - colInfo.options.length = + options.length = resp.CHARACTER_MAXIMUM_LENGTH > 0 ? resp.CHARACTER_MAXIMUM_LENGTH : undefined; } if ( this.ColumnTypesWithWidth.some( - v => - v === colInfo.options.type && - colInfo.tsType !== "boolean" + v => v === options.type && tscType !== "boolean" ) ) { - colInfo.options.width = + options.width = resp.CHARACTER_MAXIMUM_LENGTH > 0 ? resp.CHARACTER_MAXIMUM_LENGTH : undefined; } - if (colInfo.options.type) { - ent.Columns.push(colInfo); + if (options.type) { + ent.columns.push({ + generated, + options, + tscName, + tscType, + primary + }); } }); }); @@ -463,11 +466,11 @@ export default class MysqlDriver extends AbstractDriver { } private static ReturnDefaultValueFunction( - defVal: string | null - ): string | null { + defVal: string | undefined + ): string | undefined { let defaultValue = defVal; if (!defaultValue || defaultValue === "NULL") { - return null; + return undefined; } if (defaultValue.toLowerCase() === "current_timestamp()") { defaultValue = "CURRENT_TIMESTAMP"; diff --git a/src/drivers/OracleDriver.ts b/src/drivers/OracleDriver.ts index d757c20..94439ad 100644 --- a/src/drivers/OracleDriver.ts +++ b/src/drivers/OracleDriver.ts @@ -8,6 +8,7 @@ import IndexInfo from "../oldModels/IndexInfo"; import IndexColumnInfo from "../oldModels/IndexColumnInfo"; import RelationTempInfo from "../oldModels/RelationTempInfo"; import IConnectionOptions from "../IConnectionOptions"; +import { Entity } from "../models/Entity"; export default class OracleDriver extends AbstractDriver { public defaultValues: DataTypeDefaults = new TypeormDriver.OracleDriver({ @@ -47,163 +48,163 @@ export default class OracleDriver extends AbstractDriver { return response; }; - public async GetCoulmnsFromEntity( - entities: EntityInfo[] - ): Promise { - const response: { - TABLE_NAME: string; - COLUMN_NAME: string; - DATA_DEFAULT: string; - NULLABLE: string; - DATA_TYPE: string; - DATA_LENGTH: number; - DATA_PRECISION: number; - DATA_SCALE: number; - IDENTITY_COLUMN: string; - 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 - JOIN USER_CONSTRAINTS uc ON uc.CONSTRAINT_NAME = ucc.CONSTRAINT_NAME and uc.CONSTRAINT_TYPE='U' - where ucc.column_name = utc.COLUMN_NAME AND ucc.table_name = utc.TABLE_NAME) IS_UNIQUE - FROM USER_TAB_COLUMNS utc`)).rows!; + public async GetCoulmnsFromEntity(entities: Entity[]): Promise { + throw new Error(); + // TODO: Remove + // const response: { + // TABLE_NAME: string; + // COLUMN_NAME: string; + // DATA_DEFAULT: string; + // NULLABLE: string; + // DATA_TYPE: string; + // DATA_LENGTH: number; + // DATA_PRECISION: number; + // DATA_SCALE: number; + // IDENTITY_COLUMN: string; + // 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 + // JOIN USER_CONSTRAINTS uc ON uc.CONSTRAINT_NAME = ucc.CONSTRAINT_NAME and uc.CONSTRAINT_TYPE='U' + // where ucc.column_name = utc.COLUMN_NAME AND ucc.table_name = utc.TABLE_NAME) IS_UNIQUE + // FROM USER_TAB_COLUMNS utc`)).rows!; - entities.forEach(ent => { - response - .filter(filterVal => filterVal.TABLE_NAME === ent.tsEntityName) - .forEach(resp => { - const colInfo: ColumnInfo = new ColumnInfo(); - colInfo.tsName = resp.COLUMN_NAME; - colInfo.options.name = resp.COLUMN_NAME; - colInfo.options.nullable = resp.NULLABLE === "Y"; - colInfo.options.generated = resp.IDENTITY_COLUMN === "YES"; - colInfo.options.default = - !resp.DATA_DEFAULT || resp.DATA_DEFAULT.includes('"') - ? null - : OracleDriver.ReturnDefaultValueFunction( - resp.DATA_DEFAULT - ); - colInfo.options.unique = resp.IS_UNIQUE > 0; - const DATA_TYPE = resp.DATA_TYPE.replace(/\([0-9]+\)/g, ""); - colInfo.options.type = DATA_TYPE.toLowerCase() as any; - switch (DATA_TYPE.toLowerCase()) { - case "char": - colInfo.tsType = "string"; - break; - case "nchar": - colInfo.tsType = "string"; - break; - case "nvarchar2": - colInfo.tsType = "string"; - break; - case "varchar2": - colInfo.tsType = "string"; - break; - case "long": - colInfo.tsType = "string"; - break; - case "raw": - colInfo.tsType = "Buffer"; - break; - case "long raw": - colInfo.tsType = "Buffer"; - break; - case "number": - colInfo.tsType = "number"; - break; - case "numeric": - colInfo.tsType = "number"; - break; - case "float": - colInfo.tsType = "number"; - break; - case "dec": - colInfo.tsType = "number"; - break; - case "decimal": - colInfo.tsType = "number"; - break; - case "integer": - colInfo.tsType = "number"; - break; - case "int": - colInfo.tsType = "number"; - break; - case "smallint": - colInfo.tsType = "number"; - break; - case "real": - colInfo.tsType = "number"; - break; - case "double precision": - colInfo.tsType = "number"; - break; - case "date": - colInfo.tsType = "Date"; - break; - case "timestamp": - colInfo.tsType = "Date"; - break; - case "timestamp with time zone": - colInfo.tsType = "Date"; - break; - case "timestamp with local time zone": - colInfo.tsType = "Date"; - break; - case "interval year to month": - colInfo.tsType = "string"; - break; - case "interval day to second": - colInfo.tsType = "string"; - break; - case "bfile": - colInfo.tsType = "Buffer"; - break; - case "blob": - colInfo.tsType = "Buffer"; - break; - case "clob": - colInfo.tsType = "string"; - break; - case "nclob": - colInfo.tsType = "string"; - break; - case "rowid": - colInfo.tsType = "number"; - break; - case "urowid": - colInfo.tsType = "number"; - break; - default: - TomgUtils.LogError( - `Unknown column type:${DATA_TYPE}` - ); - break; - } - if ( - this.ColumnTypesWithPrecision.some( - v => v === colInfo.options.type - ) - ) { - colInfo.options.precision = resp.DATA_PRECISION; - colInfo.options.scale = resp.DATA_SCALE; - } - if ( - this.ColumnTypesWithLength.some( - v => v === colInfo.options.type - ) - ) { - colInfo.options.length = - resp.DATA_LENGTH > 0 ? resp.DATA_LENGTH : undefined; - } + // entities.forEach(ent => { + // response + // .filter(filterVal => filterVal.TABLE_NAME === ent.tsEntityName) + // .forEach(resp => { + // const colInfo: ColumnInfo = new ColumnInfo(); + // colInfo.tsName = resp.COLUMN_NAME; + // colInfo.options.name = resp.COLUMN_NAME; + // colInfo.options.nullable = resp.NULLABLE === "Y"; + // colInfo.options.generated = resp.IDENTITY_COLUMN === "YES"; + // colInfo.options.default = + // !resp.DATA_DEFAULT || resp.DATA_DEFAULT.includes('"') + // ? null + // : OracleDriver.ReturnDefaultValueFunction( + // resp.DATA_DEFAULT + // ); + // colInfo.options.unique = resp.IS_UNIQUE > 0; + // const DATA_TYPE = resp.DATA_TYPE.replace(/\([0-9]+\)/g, ""); + // colInfo.options.type = DATA_TYPE.toLowerCase() as any; + // switch (DATA_TYPE.toLowerCase()) { + // case "char": + // colInfo.tsType = "string"; + // break; + // case "nchar": + // colInfo.tsType = "string"; + // break; + // case "nvarchar2": + // colInfo.tsType = "string"; + // break; + // case "varchar2": + // colInfo.tsType = "string"; + // break; + // case "long": + // colInfo.tsType = "string"; + // break; + // case "raw": + // colInfo.tsType = "Buffer"; + // break; + // case "long raw": + // colInfo.tsType = "Buffer"; + // break; + // case "number": + // colInfo.tsType = "number"; + // break; + // case "numeric": + // colInfo.tsType = "number"; + // break; + // case "float": + // colInfo.tsType = "number"; + // break; + // case "dec": + // colInfo.tsType = "number"; + // break; + // case "decimal": + // colInfo.tsType = "number"; + // break; + // case "integer": + // colInfo.tsType = "number"; + // break; + // case "int": + // colInfo.tsType = "number"; + // break; + // case "smallint": + // colInfo.tsType = "number"; + // break; + // case "real": + // colInfo.tsType = "number"; + // break; + // case "double precision": + // colInfo.tsType = "number"; + // break; + // case "date": + // colInfo.tsType = "Date"; + // break; + // case "timestamp": + // colInfo.tsType = "Date"; + // break; + // case "timestamp with time zone": + // colInfo.tsType = "Date"; + // break; + // case "timestamp with local time zone": + // colInfo.tsType = "Date"; + // break; + // case "interval year to month": + // colInfo.tsType = "string"; + // break; + // case "interval day to second": + // colInfo.tsType = "string"; + // break; + // case "bfile": + // colInfo.tsType = "Buffer"; + // break; + // case "blob": + // colInfo.tsType = "Buffer"; + // break; + // case "clob": + // colInfo.tsType = "string"; + // break; + // case "nclob": + // colInfo.tsType = "string"; + // break; + // case "rowid": + // colInfo.tsType = "number"; + // break; + // case "urowid": + // colInfo.tsType = "number"; + // break; + // default: + // TomgUtils.LogError( + // `Unknown column type:${DATA_TYPE}` + // ); + // break; + // } + // if ( + // this.ColumnTypesWithPrecision.some( + // v => v === colInfo.options.type + // ) + // ) { + // colInfo.options.precision = resp.DATA_PRECISION; + // colInfo.options.scale = resp.DATA_SCALE; + // } + // if ( + // this.ColumnTypesWithLength.some( + // v => v === colInfo.options.type + // ) + // ) { + // colInfo.options.length = + // resp.DATA_LENGTH > 0 ? resp.DATA_LENGTH : undefined; + // } - if (colInfo.options.type) { - ent.Columns.push(colInfo); - } - }); - }); - return entities; + // if (colInfo.options.type) { + // ent.Columns.push(colInfo); + // } + // }); + // }); + // return entities; } public async GetIndexesFromEntity( diff --git a/src/drivers/PostgresDriver.ts b/src/drivers/PostgresDriver.ts index 0ed8c2e..f276db0 100644 --- a/src/drivers/PostgresDriver.ts +++ b/src/drivers/PostgresDriver.ts @@ -10,6 +10,7 @@ import IndexInfo from "../oldModels/IndexInfo"; import IndexColumnInfo from "../oldModels/IndexColumnInfo"; import RelationTempInfo from "../oldModels/RelationTempInfo"; import IConnectionOptions from "../IConnectionOptions"; +import { Entity } from "../models/Entity"; export default class PostgresDriver extends AbstractDriver { public defaultValues: DataTypeDefaults = new TypeormDriver.PostgresDriver({ @@ -36,126 +37,128 @@ export default class PostgresDriver extends AbstractDriver { }; public async GetCoulmnsFromEntity( - entities: EntityInfo[], + entities: Entity[], schema: string - ): Promise { - const response: { - table_name: string; - column_name: string; - udt_name: string; - column_default: string; - is_nullable: string; - data_type: string; - character_maximum_length: number; - numeric_precision: number; - numeric_scale: number; - isidentity: string; - isunique: string; - enumvalues: string | null; - }[] = (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, - (SELECT count(*) - FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS tc - inner join INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE cu - on cu.CONSTRAINT_NAME = tc.CONSTRAINT_NAME - where - tc.CONSTRAINT_TYPE = 'UNIQUE' - and tc.TABLE_NAME = c.TABLE_NAME - and cu.COLUMN_NAME = c.COLUMN_NAME - and tc.TABLE_SCHEMA=c.TABLE_SCHEMA) IsUnique, - (SELECT -string_agg(enumlabel, ',') -FROM "pg_enum" "e" -INNER JOIN "pg_type" "t" ON "t"."oid" = "e"."enumtypid" -INNER JOIN "pg_namespace" "n" ON "n"."oid" = "t"."typnamespace" -WHERE "n"."nspname" = table_schema AND "t"."typname"=udt_name - ) enumValues - FROM INFORMATION_SCHEMA.COLUMNS c - where table_schema in (${schema}) - order by ordinal_position`)).rows; - entities.forEach(ent => { - response - .filter(filterVal => filterVal.table_name === ent.tsEntityName) - .forEach(resp => { - const colInfo: ColumnInfo = new ColumnInfo(); - colInfo.tsName = resp.column_name; - colInfo.options.name = resp.column_name; - colInfo.options.nullable = resp.is_nullable === "YES"; - colInfo.options.generated = resp.isidentity === "YES"; - colInfo.options.unique = resp.isunique === "1"; - colInfo.options.default = colInfo.options.generated - ? null - : PostgresDriver.ReturnDefaultValueFunction( - resp.column_default - ); + ): Promise { + throw new Error(); + // TODO: Remove + // const response: { + // table_name: string; + // column_name: string; + // udt_name: string; + // column_default: string; + // is_nullable: string; + // data_type: string; + // character_maximum_length: number; + // numeric_precision: number; + // numeric_scale: number; + // isidentity: string; + // isunique: string; + // enumvalues: string | null; + // }[] = (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, + // (SELECT count(*) + // FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS tc + // inner join INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE cu + // on cu.CONSTRAINT_NAME = tc.CONSTRAINT_NAME + // where + // tc.CONSTRAINT_TYPE = 'UNIQUE' + // and tc.TABLE_NAME = c.TABLE_NAME + // and cu.COLUMN_NAME = c.COLUMN_NAME + // and tc.TABLE_SCHEMA=c.TABLE_SCHEMA) IsUnique, + // (SELECT + // string_agg(enumlabel, ',') + // FROM "pg_enum" "e" + // INNER JOIN "pg_type" "t" ON "t"."oid" = "e"."enumtypid" + // INNER JOIN "pg_namespace" "n" ON "n"."oid" = "t"."typnamespace" + // WHERE "n"."nspname" = table_schema AND "t"."typname"=udt_name + // ) enumValues + // FROM INFORMATION_SCHEMA.COLUMNS c + // where table_schema in (${schema}) + // order by ordinal_position`)).rows; + // entities.forEach(ent => { + // response + // .filter(filterVal => filterVal.table_name === ent.tsEntityName) + // .forEach(resp => { + // const colInfo: ColumnInfo = new ColumnInfo(); + // colInfo.tsName = resp.column_name; + // colInfo.options.name = resp.column_name; + // colInfo.options.nullable = resp.is_nullable === "YES"; + // colInfo.options.generated = resp.isidentity === "YES"; + // colInfo.options.unique = resp.isunique === "1"; + // colInfo.options.default = colInfo.options.generated + // ? null + // : PostgresDriver.ReturnDefaultValueFunction( + // resp.column_default + // ); - const columnTypes = this.MatchColumnTypes( - resp.data_type, - resp.udt_name, - resp.enumvalues - ); - if (!columnTypes.sqlType || !columnTypes.tsType) { - if ( - resp.data_type === "USER-DEFINED" || - resp.data_type === "ARRAY" - ) { - TomgUtils.LogError( - `Unknown ${resp.data_type} column type: ${resp.udt_name} table name: ${resp.table_name} column name: ${resp.column_name}` - ); - } else { - TomgUtils.LogError( - `Unknown column type: ${resp.data_type} table name: ${resp.table_name} column name: ${resp.column_name}` - ); - } - return; - } - colInfo.options.type = columnTypes.sqlType as any; - colInfo.tsType = columnTypes.tsType; - colInfo.options.array = columnTypes.isArray; - colInfo.options.enum = columnTypes.enumValues; - if (colInfo.options.array) { - colInfo.tsType = colInfo.tsType - .split("|") - .map(x => `${x.replace("|", "").trim()}[]`) - .join(" | ") as any; - } + // const columnTypes = this.MatchColumnTypes( + // resp.data_type, + // resp.udt_name, + // resp.enumvalues + // ); + // if (!columnTypes.sqlType || !columnTypes.tsType) { + // if ( + // resp.data_type === "USER-DEFINED" || + // resp.data_type === "ARRAY" + // ) { + // TomgUtils.LogError( + // `Unknown ${resp.data_type} column type: ${resp.udt_name} table name: ${resp.table_name} column name: ${resp.column_name}` + // ); + // } else { + // TomgUtils.LogError( + // `Unknown column type: ${resp.data_type} table name: ${resp.table_name} column name: ${resp.column_name}` + // ); + // } + // return; + // } + // colInfo.options.type = columnTypes.sqlType as any; + // colInfo.tsType = columnTypes.tsType; + // colInfo.options.array = columnTypes.isArray; + // colInfo.options.enum = columnTypes.enumValues; + // if (colInfo.options.array) { + // colInfo.tsType = colInfo.tsType + // .split("|") + // .map(x => `${x.replace("|", "").trim()}[]`) + // .join(" | ") as any; + // } - if ( - this.ColumnTypesWithPrecision.some( - v => v === colInfo.options.type - ) - ) { - colInfo.options.precision = resp.numeric_precision; - colInfo.options.scale = resp.numeric_scale; - } - if ( - this.ColumnTypesWithLength.some( - v => v === colInfo.options.type - ) - ) { - colInfo.options.length = - resp.character_maximum_length > 0 - ? resp.character_maximum_length - : undefined; - } - if ( - this.ColumnTypesWithWidth.some( - v => v === colInfo.options.type - ) - ) { - colInfo.options.width = - resp.character_maximum_length > 0 - ? resp.character_maximum_length - : undefined; - } - if (colInfo.options.type && colInfo.tsType) { - ent.Columns.push(colInfo); - } - }); - }); - return entities; + // if ( + // this.ColumnTypesWithPrecision.some( + // v => v === colInfo.options.type + // ) + // ) { + // colInfo.options.precision = resp.numeric_precision; + // colInfo.options.scale = resp.numeric_scale; + // } + // if ( + // this.ColumnTypesWithLength.some( + // v => v === colInfo.options.type + // ) + // ) { + // colInfo.options.length = + // resp.character_maximum_length > 0 + // ? resp.character_maximum_length + // : undefined; + // } + // if ( + // this.ColumnTypesWithWidth.some( + // v => v === colInfo.options.type + // ) + // ) { + // colInfo.options.width = + // resp.character_maximum_length > 0 + // ? resp.character_maximum_length + // : undefined; + // } + // if (colInfo.options.type && colInfo.tsType) { + // ent.Columns.push(colInfo); + // } + // }); + // }); + // return entities; } public MatchColumnTypes( diff --git a/src/drivers/SqliteDriver.ts b/src/drivers/SqliteDriver.ts index f5f57e8..2fa5441 100644 --- a/src/drivers/SqliteDriver.ts +++ b/src/drivers/SqliteDriver.ts @@ -10,6 +10,7 @@ import IndexInfo from "../oldModels/IndexInfo"; import IndexColumnInfo from "../oldModels/IndexColumnInfo"; import RelationTempInfo from "../oldModels/RelationTempInfo"; import IConnectionOptions from "../IConnectionOptions"; +import { Entity } from "../models/Entity"; export default class SqliteDriver extends AbstractDriver { public defaultValues: DataTypeDefaults = new TypeormDriver.SqliteDriver({ @@ -30,190 +31,190 @@ export default class SqliteDriver extends AbstractDriver { public GetAllTablesQuery: any; - public async GetAllTables(): Promise { - const ret: EntityInfo[] = [] as EntityInfo[]; + public async GetAllTables(): Promise { + const ret: Entity[] = [] as Entity[]; 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 => { - const ent: EntityInfo = new EntityInfo(); - ent.tsEntityName = val.tbl_name; - ent.Columns = [] as ColumnInfo[]; - ent.Indexes = [] as IndexInfo[]; if (val.sql.includes("AUTOINCREMENT")) { - this.tablesWithGeneratedPrimaryKey.push(ent.tsEntityName); + this.tablesWithGeneratedPrimaryKey.push(val.tbl_name); } - ret.push(ent); + ret.push({ + columns: [], + sqlName: val.tbl_name, + tscName: val.tbl_name + }); }); return ret; } - public async GetCoulmnsFromEntity( - entities: EntityInfo[] - ): Promise { - await Promise.all( - entities.map(async ent => { - const response = await this.ExecQuery<{ - cid: number; - name: string; - type: string; - notnull: number; - dflt_value: string; - pk: number; - }>(`PRAGMA table_info('${ent.tsEntityName}');`); - response.forEach(resp => { - const colInfo: ColumnInfo = new ColumnInfo(); - colInfo.tsName = resp.name; - colInfo.options.name = resp.name; - colInfo.options.nullable = resp.notnull === 0; - colInfo.options.primary = resp.pk > 0; - colInfo.options.default = SqliteDriver.ReturnDefaultValueFunction( - resp.dflt_value - ); - colInfo.options.type = resp.type - .replace(/\([0-9 ,]+\)/g, "") - .toLowerCase() - .trim() as any; - colInfo.options.generated = - colInfo.options.primary && - this.tablesWithGeneratedPrimaryKey.includes( - ent.tsEntityName - ); - switch (colInfo.options.type) { - case "int": - colInfo.tsType = "number"; - break; - case "integer": - colInfo.tsType = "number"; - break; - case "int2": - colInfo.tsType = "number"; - break; - case "int8": - colInfo.tsType = "number"; - break; - case "tinyint": - colInfo.tsType = "number"; - break; - case "smallint": - colInfo.tsType = "number"; - break; - case "mediumint": - colInfo.tsType = "number"; - break; - case "bigint": - colInfo.tsType = "string"; - break; - case "unsigned big int": - colInfo.tsType = "string"; - break; - case "character": - colInfo.tsType = "string"; - break; - case "varchar": - colInfo.tsType = "string"; - break; - case "varying character": - colInfo.tsType = "string"; - break; - case "nchar": - colInfo.tsType = "string"; - break; - case "native character": - colInfo.tsType = "string"; - break; - case "nvarchar": - colInfo.tsType = "string"; - break; - case "text": - colInfo.tsType = "string"; - break; - case "blob": - colInfo.tsType = "Buffer"; - break; - case "clob": - colInfo.tsType = "string"; - break; - case "real": - colInfo.tsType = "number"; - break; - case "double": - colInfo.tsType = "number"; - break; - case "double precision": - colInfo.tsType = "number"; - break; - case "float": - colInfo.tsType = "number"; - break; - case "numeric": - colInfo.tsType = "number"; - break; - case "decimal": - colInfo.tsType = "number"; - break; - case "boolean": - colInfo.tsType = "boolean"; - break; - case "date": - colInfo.tsType = "string"; - break; - case "datetime": - colInfo.tsType = "Date"; - break; - default: - TomgUtils.LogError( - `Unknown column type: ${colInfo.options.type} table name: ${ent.tsEntityName} column name: ${resp.name}` - ); - break; - } - const options = resp.type.match(/\([0-9 ,]+\)/g); - if ( - this.ColumnTypesWithPrecision.some( - v => v === colInfo.options.type - ) && - options - ) { - colInfo.options.precision = options[0] - .substring(1, options[0].length - 1) - .split(",")[0] as any; - colInfo.options.scale = options[0] - .substring(1, options[0].length - 1) - .split(",")[1] as any; - } - if ( - this.ColumnTypesWithLength.some( - v => v === colInfo.options.type - ) && - options - ) { - colInfo.options.length = options[0].substring( - 1, - options[0].length - 1 - ) as any; - } - if ( - this.ColumnTypesWithWidth.some( - v => - v === colInfo.options.type && - colInfo.tsType !== "boolean" - ) && - options - ) { - colInfo.options.width = options[0].substring( - 1, - options[0].length - 1 - ) as any; - } + public async GetCoulmnsFromEntity(entities: Entity[]): Promise { + throw new Error(); + // TODO: Remove + // await Promise.all( + // entities.map(async ent => { + // const response = await this.ExecQuery<{ + // cid: number; + // name: string; + // type: string; + // notnull: number; + // dflt_value: string; + // pk: number; + // }>(`PRAGMA table_info('${ent.tsEntityName}');`); + // response.forEach(resp => { + // const colInfo: ColumnInfo = new ColumnInfo(); + // colInfo.tsName = resp.name; + // colInfo.options.name = resp.name; + // colInfo.options.nullable = resp.notnull === 0; + // colInfo.options.primary = resp.pk > 0; + // colInfo.options.default = SqliteDriver.ReturnDefaultValueFunction( + // resp.dflt_value + // ); + // colInfo.options.type = resp.type + // .replace(/\([0-9 ,]+\)/g, "") + // .toLowerCase() + // .trim() as any; + // colInfo.options.generated = + // colInfo.options.primary && + // this.tablesWithGeneratedPrimaryKey.includes( + // ent.tsEntityName + // ); + // switch (colInfo.options.type) { + // case "int": + // colInfo.tsType = "number"; + // break; + // case "integer": + // colInfo.tsType = "number"; + // break; + // case "int2": + // colInfo.tsType = "number"; + // break; + // case "int8": + // colInfo.tsType = "number"; + // break; + // case "tinyint": + // colInfo.tsType = "number"; + // break; + // case "smallint": + // colInfo.tsType = "number"; + // break; + // case "mediumint": + // colInfo.tsType = "number"; + // break; + // case "bigint": + // colInfo.tsType = "string"; + // break; + // case "unsigned big int": + // colInfo.tsType = "string"; + // break; + // case "character": + // colInfo.tsType = "string"; + // break; + // case "varchar": + // colInfo.tsType = "string"; + // break; + // case "varying character": + // colInfo.tsType = "string"; + // break; + // case "nchar": + // colInfo.tsType = "string"; + // break; + // case "native character": + // colInfo.tsType = "string"; + // break; + // case "nvarchar": + // colInfo.tsType = "string"; + // break; + // case "text": + // colInfo.tsType = "string"; + // break; + // case "blob": + // colInfo.tsType = "Buffer"; + // break; + // case "clob": + // colInfo.tsType = "string"; + // break; + // case "real": + // colInfo.tsType = "number"; + // break; + // case "double": + // colInfo.tsType = "number"; + // break; + // case "double precision": + // colInfo.tsType = "number"; + // break; + // case "float": + // colInfo.tsType = "number"; + // break; + // case "numeric": + // colInfo.tsType = "number"; + // break; + // case "decimal": + // colInfo.tsType = "number"; + // break; + // case "boolean": + // colInfo.tsType = "boolean"; + // break; + // case "date": + // colInfo.tsType = "string"; + // break; + // case "datetime": + // colInfo.tsType = "Date"; + // break; + // default: + // TomgUtils.LogError( + // `Unknown column type: ${colInfo.options.type} table name: ${ent.tsEntityName} column name: ${resp.name}` + // ); + // break; + // } + // const options = resp.type.match(/\([0-9 ,]+\)/g); + // if ( + // this.ColumnTypesWithPrecision.some( + // v => v === colInfo.options.type + // ) && + // options + // ) { + // colInfo.options.precision = options[0] + // .substring(1, options[0].length - 1) + // .split(",")[0] as any; + // colInfo.options.scale = options[0] + // .substring(1, options[0].length - 1) + // .split(",")[1] as any; + // } + // if ( + // this.ColumnTypesWithLength.some( + // v => v === colInfo.options.type + // ) && + // options + // ) { + // colInfo.options.length = options[0].substring( + // 1, + // options[0].length - 1 + // ) as any; + // } + // if ( + // this.ColumnTypesWithWidth.some( + // v => + // v === colInfo.options.type && + // colInfo.tsType !== "boolean" + // ) && + // options + // ) { + // colInfo.options.width = options[0].substring( + // 1, + // options[0].length - 1 + // ) as any; + // } - if (colInfo.options.type) { - ent.Columns.push(colInfo); - } - }); - }) - ); + // if (colInfo.options.type) { + // ent.Columns.push(colInfo); + // } + // }); + // }) + // ); - return entities; + // return entities; } public async GetIndexesFromEntity( diff --git a/src/models/Column.ts b/src/models/Column.ts index e5f8c5c..c0c77ca 100644 --- a/src/models/Column.ts +++ b/src/models/Column.ts @@ -13,7 +13,7 @@ export type Column = { width?: number; nullable?: boolean; unique?: boolean; // ? - default?: boolean; + default?: string; // ? precision?: number; scale?: number; unsigned?: boolean; diff --git a/test/drivers/MssqlDriver.test.ts b/test/drivers/MssqlDriver.test.ts index 2381625..1616a62 100644 --- a/test/drivers/MssqlDriver.test.ts +++ b/test/drivers/MssqlDriver.test.ts @@ -103,12 +103,15 @@ describe("MssqlDriver", function() { tsType: "number", relations: [] as RelationInfo[] }); - const result = await driver.GetCoulmnsFromEntity( - entities, - "schema", - "db" - ); - expect(result).to.be.deep.equal(expected); + + throw new Error(); + // TODO: Remove + // const result = await driver.GetCoulmnsFromEntity( + // entities, + // "schema", + // "db" + // ); + // expect(result).to.be.deep.equal(expected); }); it("should find primary indexes"); it("should get indexes info"); diff --git a/test/integration/runTestsFromPath.test.ts b/test/integration/runTestsFromPath.test.ts index 24d9294..db648db 100644 --- a/test/integration/runTestsFromPath.test.ts +++ b/test/integration/runTestsFromPath.test.ts @@ -80,48 +80,50 @@ function runTestForMultipleDrivers( it(testName, async function() { const driversToRun = selectDriversForSpecyficTest(); const modelGenerationPromises = driversToRun.map(async dbDriver => { - const { - generationOptions, - driver, - connectionOptions, - resultsPath, - filesOrgPathTS - } = await prepareTestRuns(testPartialPath, testName, dbDriver); - let dbModel: EntityInfo[] = []; - switch (testName) { - case "144": - dbModel = await dataCollectionPhase( - driver, - Object.assign(connectionOptions, { - databaseName: "db1,db2" - }) - ); - break; + throw new Error(); + // TODO: Remove + // const { + // generationOptions, + // driver, + // connectionOptions, + // resultsPath, + // filesOrgPathTS + // } = await prepareTestRuns(testPartialPath, testName, dbDriver); + // let dbModel: EntityInfo[] = []; + // switch (testName) { + // case "144": + // dbModel = await dataCollectionPhase( + // driver, + // Object.assign(connectionOptions, { + // databaseName: "db1,db2" + // }) + // ); + // break; - default: - dbModel = await dataCollectionPhase( - driver, - connectionOptions - ); - break; - } + // default: + // dbModel = await dataCollectionPhase( + // driver, + // connectionOptions + // ); + // break; + // } - dbModel = modelCustomizationPhase( - dbModel, - generationOptions, - driver.defaultValues - ); - modelGenerationPhase(connectionOptions, generationOptions, dbModel); - const filesGenPath = path.resolve(resultsPath, "entities"); - compareGeneratedFiles(filesOrgPathTS, filesGenPath); - return { - dbModel, - generationOptions, - connectionOptions, - resultsPath, - filesOrgPathTS, - dbDriver - }; + // dbModel = modelCustomizationPhase( + // dbModel, + // generationOptions, + // driver.defaultValues + // ); + // modelGenerationPhase(connectionOptions, generationOptions, dbModel); + // const filesGenPath = path.resolve(resultsPath, "entities"); + // compareGeneratedFiles(filesOrgPathTS, filesGenPath); + // return { + // dbModel, + // generationOptions, + // connectionOptions, + // resultsPath, + // filesOrgPathTS, + // dbDriver + // }; }); await Promise.all(modelGenerationPromises); compileGeneratedModel(path.resolve(process.cwd(), `output`), dbDrivers); @@ -162,22 +164,24 @@ async function runTest( filesOrgPathTS } = await prepareTestRuns(testPartialPath, dbDriver, dbDriver); let dbModel = await dataCollectionPhase(driver, connectionOptions); - dbModel = modelCustomizationPhase( - dbModel, - generationOptions, - driver.defaultValues - ); - modelGenerationPhase(connectionOptions, generationOptions, dbModel); - const filesGenPath = path.resolve(resultsPath, "entities"); - compareGeneratedFiles(filesOrgPathTS, filesGenPath); - return { - dbModel, - generationOptions, - connectionOptions, - resultsPath, - filesOrgPathTS, - dbDriver - }; + throw new Error(); + // TODO: Remove + // dbModel = modelCustomizationPhase( + // dbModel, + // generationOptions, + // driver.defaultValues + // ); + // modelGenerationPhase(connectionOptions, generationOptions, dbModel); + // const filesGenPath = path.resolve(resultsPath, "entities"); + // compareGeneratedFiles(filesOrgPathTS, filesGenPath); + // return { + // dbModel, + // generationOptions, + // connectionOptions, + // resultsPath, + // filesOrgPathTS, + // dbDriver + // }; }); await Promise.all(modelGenerationPromises); compileGeneratedModel(path.resolve(process.cwd(), `output`), dbDrivers); From 76f3ed2ad2f0ad6afd50991217d7c3309bae999e Mon Sep 17 00:00:00 2001 From: Kononnable Date: Wed, 2 Oct 2019 19:39:43 +0200 Subject: [PATCH 05/84] mssql driver without relations --- src/Engine.ts | 138 +++++++++++++++++----------------- src/drivers/AbstractDriver.ts | 16 ++-- src/drivers/MssqlDriver.ts | 138 +++++++++++++++++----------------- src/drivers/MysqlDriver.ts | 53 +++++++------ src/drivers/OracleDriver.ts | 82 ++++++++++---------- src/drivers/PostgresDriver.ts | 124 +++++++++++++++--------------- src/drivers/SqliteDriver.ts | 112 +++++++++++++-------------- src/entity.mst | 2 +- src/models/Column.ts | 4 +- src/models/Entity.ts | 4 +- src/models/Index.ts | 9 ++- 11 files changed, 346 insertions(+), 336 deletions(-) diff --git a/src/Engine.ts b/src/Engine.ts index 23c4bc5..093f996 100644 --- a/src/Engine.ts +++ b/src/Engine.ts @@ -44,80 +44,80 @@ export async function createModelFromDatabase( connectionOptions: IConnectionOptions, generationOptions: IGenerationOptions ) { - // let dbModel = await dataCollectionPhase(driver, connectionOptions); - // if (dbModel.length === 0) { - // TomgUtils.LogError( - // "Tables not found in selected database. Skipping creation of typeorm model.", - // false - // ); - // return; - // } + let dbModel = await dataCollectionPhase(driver, connectionOptions); + if (dbModel.length === 0) { + TomgUtils.LogError( + "Tables not found in selected database. Skipping creation of typeorm model.", + false + ); + return; + } // dbModel = modelCustomizationPhase( // dbModel, // generationOptions, // driver.defaultValues // ); - const dbModel: Entity = { - sqlName: "sqlName", - tscName: "typescriptName", - schema: "schema", - database: "database", - columns: [ - { - tscType: "typescriptType", - tscName: "tscName", - options: { - name: "sqlName", - type: "integer", - length: 2, - scale: 2 - } - }, - { - tscType: "typescriptType", - tscName: "tscName", - options: { - name: "sqlName", - type: "integer", - length: 2, - scale: 2 - } - } - ], - indices: [ - { - columns: ["columns"], - name: "name" - }, - { - columns: ["columns"], - name: "name" - } - ], - relations: [ - { - relationType: "OneToMany", - relatedField: "relatedField", - fieldName: "relation", - relatedTable: "any", - relationOptions: { - onUpdate: "CASCADE", - onDelete: "NO ACTION" - } - }, - { - relationType: "OneToOne", - relatedField: "relatedField", - fieldName: "relation", - relatedTable: "any", - relationOptions: { - onUpdate: "CASCADE", - onDelete: "NO ACTION" - } - } - ] - }; - modelGenerationPhase(connectionOptions, generationOptions, [dbModel]); + // const dbModel: Entity = { + // sqlName: "sqlName", + // tscName: "typescriptName", + // schema: "schema", + // database: "database", + // columns: [ + // { + // tscType: "typescriptType", + // tscName: "tscName", + // options: { + // name: "sqlName", + // type: "integer", + // length: 2, + // scale: 2 + // } + // }, + // { + // tscType: "typescriptType", + // tscName: "tscName", + // options: { + // name: "sqlName", + // type: "integer", + // length: 2, + // scale: 2 + // } + // } + // ], + // indices: [ + // { + // columns: ["columns"], + // name: "name" + // }, + // { + // columns: ["columns"], + // name: "name" + // } + // ], + // relations: [ + // { + // relationType: "OneToMany", + // relatedField: "relatedField", + // fieldName: "relation", + // relatedTable: "any", + // relationOptions: { + // onUpdate: "CASCADE", + // onDelete: "NO ACTION" + // } + // }, + // { + // relationType: "OneToOne", + // relatedField: "relatedField", + // fieldName: "relation", + // relatedTable: "any", + // relationOptions: { + // onUpdate: "CASCADE", + // onDelete: "NO ACTION" + // } + // } + // ] + // }; + modelGenerationPhase(connectionOptions, generationOptions, dbModel); } export async function dataCollectionPhase( driver: AbstractDriver, diff --git a/src/drivers/AbstractDriver.ts b/src/drivers/AbstractDriver.ts index ad5b5dc..b34d1e4 100644 --- a/src/drivers/AbstractDriver.ts +++ b/src/drivers/AbstractDriver.ts @@ -175,12 +175,12 @@ export default abstract class AbstractDriver { sqlEscapedSchema, connectionOptons.databaseName ); + await this.GetIndexesFromEntity( + dbModel, + sqlEscapedSchema, + connectionOptons.databaseName + ); // TODO: Uncomment - // await this.GetIndexesFromEntity( - // dbModel, - // sqlEscapedSchema, - // connectionOptons.databaseName - // ); // dbModel = await this.GetRelations( // dbModel, // sqlEscapedSchema, @@ -203,6 +203,8 @@ export default abstract class AbstractDriver { response.forEach(val => { ret.push({ columns: [], + indices: [], + relations: [], sqlName: val.TABLE_NAME, tscName: val.TABLE_NAME, database: dbNames.includes(",") ? val.DB_NAME : "", @@ -381,10 +383,10 @@ export default abstract class AbstractDriver { ): Promise; public abstract async GetIndexesFromEntity( - entities: EntityInfo[], + entities: Entity[], schema: string, dbNames: string - ): Promise; + ): Promise; public abstract async GetRelations( entities: EntityInfo[], diff --git a/src/drivers/MssqlDriver.ts b/src/drivers/MssqlDriver.ts index 290e786..e59ee8e 100644 --- a/src/drivers/MssqlDriver.ts +++ b/src/drivers/MssqlDriver.ts @@ -227,77 +227,79 @@ WHERE TABLE_TYPE='BASE TABLE' and TABLE_SCHEMA in (${schema}) AND TABLE_CATALOG } public async GetIndexesFromEntity( - entities: EntityInfo[], + entities: Entity[], schema: string, dbNames: string - ): Promise { - const request = new MSSQL.Request(this.Connection); - const response: { - TableName: string; - IndexName: string; - ColumnName: string; - is_unique: boolean; - is_primary_key: boolean; - }[] = []; - await Promise.all( - dbNames.split(",").map(async dbName => { - await this.UseDB(dbName); - const resp: { - TableName: string; - IndexName: string; - ColumnName: string; - is_unique: boolean; - is_primary_key: boolean; - }[] = (await request.query(`SELECT - TableName = t.name, - IndexName = ind.name, - ColumnName = col.name, - ind.is_unique, - ind.is_primary_key - FROM - sys.indexes ind - INNER JOIN - sys.index_columns ic ON ind.object_id = ic.object_id and ind.index_id = ic.index_id - INNER JOIN - sys.columns col ON ic.object_id = col.object_id and ic.column_id = col.column_id - INNER JOIN - sys.tables t ON ind.object_id = t.object_id - INNER JOIN - sys.schemas s on s.schema_id=t.schema_id - WHERE - t.is_ms_shipped = 0 and s.name in (${schema}) - ORDER BY - t.name, ind.name, ind.index_id, ic.key_ordinal;`)).recordset; - response.push(...resp); - }) - ); - entities.forEach(ent => { - response - .filter(filterVal => filterVal.TableName === ent.tsEntityName) - .forEach(resp => { - let indexInfo: IndexInfo = {} as IndexInfo; - const indexColumnInfo: IndexColumnInfo = {} as IndexColumnInfo; - if ( - ent.Indexes.filter(filterVal => { - return filterVal.name === resp.IndexName; - }).length > 0 - ) { - [indexInfo] = ent.Indexes.filter(filterVal => { - return filterVal.name === resp.IndexName; - }); - } else { - indexInfo.columns = [] as IndexColumnInfo[]; - indexInfo.name = resp.IndexName; - indexInfo.isUnique = resp.is_unique; - indexInfo.isPrimaryKey = resp.is_primary_key; - ent.Indexes.push(indexInfo); - } - indexColumnInfo.name = resp.ColumnName; - indexInfo.columns.push(indexColumnInfo); - }); - }); + ): Promise { + throw new Error(); + // TODO: Remove + // const request = new MSSQL.Request(this.Connection); + // const response: { + // TableName: string; + // IndexName: string; + // ColumnName: string; + // is_unique: boolean; + // is_primary_key: boolean; + // }[] = []; + // await Promise.all( + // dbNames.split(",").map(async dbName => { + // await this.UseDB(dbName); + // const resp: { + // TableName: string; + // IndexName: string; + // ColumnName: string; + // is_unique: boolean; + // is_primary_key: boolean; + // }[] = (await request.query(`SELECT + // TableName = t.name, + // IndexName = ind.name, + // ColumnName = col.name, + // ind.is_unique, + // ind.is_primary_key + // FROM + // sys.indexes ind + // INNER JOIN + // sys.index_columns ic ON ind.object_id = ic.object_id and ind.index_id = ic.index_id + // INNER JOIN + // sys.columns col ON ic.object_id = col.object_id and ic.column_id = col.column_id + // INNER JOIN + // sys.tables t ON ind.object_id = t.object_id + // INNER JOIN + // sys.schemas s on s.schema_id=t.schema_id + // WHERE + // t.is_ms_shipped = 0 and s.name in (${schema}) + // ORDER BY + // t.name, ind.name, ind.index_id, ic.key_ordinal;`)).recordset; + // response.push(...resp); + // }) + // ); + // entities.forEach(ent => { + // response + // .filter(filterVal => filterVal.TableName === ent.tsEntityName) + // .forEach(resp => { + // let indexInfo: IndexInfo = {} as IndexInfo; + // const indexColumnInfo: IndexColumnInfo = {} as IndexColumnInfo; + // if ( + // ent.Indexes.filter(filterVal => { + // return filterVal.name === resp.IndexName; + // }).length > 0 + // ) { + // [indexInfo] = ent.Indexes.filter(filterVal => { + // return filterVal.name === resp.IndexName; + // }); + // } else { + // indexInfo.columns = [] as IndexColumnInfo[]; + // indexInfo.name = resp.IndexName; + // indexInfo.isUnique = resp.is_unique; + // indexInfo.isPrimaryKey = resp.is_primary_key; + // ent.Indexes.push(indexInfo); + // } + // indexColumnInfo.name = resp.ColumnName; + // indexInfo.columns.push(indexColumnInfo); + // }); + // }); - return entities; + // return entities; } public async GetRelations( diff --git a/src/drivers/MysqlDriver.ts b/src/drivers/MysqlDriver.ts index 07e3e4f..cab7cb8 100644 --- a/src/drivers/MysqlDriver.ts +++ b/src/drivers/MysqlDriver.ts @@ -12,6 +12,7 @@ import RelationTempInfo from "../oldModels/RelationTempInfo"; import IConnectionOptions from "../IConnectionOptions"; import { Entity } from "../models/Entity"; import { Column } from "../models/Column"; +import { Index } from "../models/Index"; export default class MysqlDriver extends AbstractDriver { public defaultValues: DataTypeDefaults = new TypeormDriver.MysqlDriver({ @@ -248,10 +249,9 @@ export default class MysqlDriver extends AbstractDriver { if (options.type) { ent.columns.push({ generated, - options, + options: { type: "integer", name: "", ...options }, // TODO: Change tscName, - tscType, - primary + tscType }); } }); @@ -260,10 +260,10 @@ export default class MysqlDriver extends AbstractDriver { } public async GetIndexesFromEntity( - entities: EntityInfo[], + entities: Entity[], schema: string, dbNames: string - ): Promise { + ): Promise { const response = await this.ExecQuery<{ TableName: string; IndexName: string; @@ -277,29 +277,28 @@ export default class MysqlDriver extends AbstractDriver { dbNames )})`); entities.forEach(ent => { - response - .filter(filterVal => filterVal.TableName === ent.tsEntityName) - .forEach(resp => { - let indexInfo: IndexInfo = {} as IndexInfo; - const indexColumnInfo: IndexColumnInfo = {} as IndexColumnInfo; - if ( - ent.Indexes.filter( - filterVal => filterVal.name === resp.IndexName - ).length > 0 - ) { - indexInfo = ent.Indexes.find( - filterVal => filterVal.name === resp.IndexName - )!; - } else { - indexInfo.columns = [] as IndexColumnInfo[]; - indexInfo.name = resp.IndexName; - indexInfo.isUnique = resp.is_unique === 1; - indexInfo.isPrimaryKey = resp.is_primary_key === 1; - ent.Indexes.push(indexInfo); - } - indexColumnInfo.name = resp.ColumnName; - indexInfo.columns.push(indexColumnInfo); + const entityIndices = response.filter( + filterVal => filterVal.TableName === ent.tscName + ); + const indexNames = new Set(entityIndices.map(v => v.IndexName)); + indexNames.forEach(indexName => { + const records = entityIndices.filter( + v => v.IndexName === indexName + ); + + const indexInfo: Index = { + name: indexName, + columns: [], + options: {} + }; + if (records[0].is_primary_key === 1) indexInfo.primary = true; + if (records[0].is_unique === 1) indexInfo.options.unique = true; + + records.forEach(record => { + indexInfo.columns.push(record.ColumnName); }); + ent.indices.push(indexInfo); + }); }); return entities; diff --git a/src/drivers/OracleDriver.ts b/src/drivers/OracleDriver.ts index 94439ad..9341774 100644 --- a/src/drivers/OracleDriver.ts +++ b/src/drivers/OracleDriver.ts @@ -207,49 +207,49 @@ export default class OracleDriver extends AbstractDriver { // return entities; } - public async GetIndexesFromEntity( - entities: EntityInfo[] - ): Promise { - const response: { - COLUMN_NAME: string; - TABLE_NAME: string; - INDEX_NAME: string; - UNIQUENESS: string; - ISPRIMARYKEY: number; - }[] = (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 - LEFT JOIN USER_CONSTRAINTS uc ON uc.INDEX_NAME = ind.INDEX_NAME - ORDER BY col.INDEX_NAME ASC ,col.COLUMN_POSITION ASC`)).rows!; + public async GetIndexesFromEntity(entities: Entity[]): Promise { + throw new Error(); + // TODO: Remove + // const response: { + // COLUMN_NAME: string; + // TABLE_NAME: string; + // INDEX_NAME: string; + // UNIQUENESS: string; + // ISPRIMARYKEY: number; + // }[] = (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 + // LEFT JOIN USER_CONSTRAINTS uc ON uc.INDEX_NAME = ind.INDEX_NAME + // ORDER BY col.INDEX_NAME ASC ,col.COLUMN_POSITION ASC`)).rows!; - entities.forEach(ent => { - response - .filter(filterVal => filterVal.TABLE_NAME === ent.tsEntityName) - .forEach(resp => { - let indexInfo: IndexInfo = {} as IndexInfo; - const indexColumnInfo: IndexColumnInfo = {} as IndexColumnInfo; - if ( - ent.Indexes.filter( - filterVal => filterVal.name === resp.INDEX_NAME - ).length > 0 - ) { - indexInfo = ent.Indexes.find( - filterVal => filterVal.name === resp.INDEX_NAME - )!; - } else { - indexInfo.columns = [] as IndexColumnInfo[]; - indexInfo.name = resp.INDEX_NAME; - indexInfo.isUnique = resp.UNIQUENESS === "UNIQUE"; - indexInfo.isPrimaryKey = resp.ISPRIMARYKEY === 1; - ent.Indexes.push(indexInfo); - } - indexColumnInfo.name = resp.COLUMN_NAME; - indexInfo.columns.push(indexColumnInfo); - }); - }); + // entities.forEach(ent => { + // response + // .filter(filterVal => filterVal.TABLE_NAME === ent.tsEntityName) + // .forEach(resp => { + // let indexInfo: IndexInfo = {} as IndexInfo; + // const indexColumnInfo: IndexColumnInfo = {} as IndexColumnInfo; + // if ( + // ent.Indexes.filter( + // filterVal => filterVal.name === resp.INDEX_NAME + // ).length > 0 + // ) { + // indexInfo = ent.Indexes.find( + // filterVal => filterVal.name === resp.INDEX_NAME + // )!; + // } else { + // indexInfo.columns = [] as IndexColumnInfo[]; + // indexInfo.name = resp.INDEX_NAME; + // indexInfo.isUnique = resp.UNIQUENESS === "UNIQUE"; + // indexInfo.isPrimaryKey = resp.ISPRIMARYKEY === 1; + // ent.Indexes.push(indexInfo); + // } + // indexColumnInfo.name = resp.COLUMN_NAME; + // indexInfo.columns.push(indexColumnInfo); + // }); + // }); - return entities; + // return entities; } public async GetRelations(entities: EntityInfo[]): Promise { diff --git a/src/drivers/PostgresDriver.ts b/src/drivers/PostgresDriver.ts index f276db0..774a394 100644 --- a/src/drivers/PostgresDriver.ts +++ b/src/drivers/PostgresDriver.ts @@ -401,69 +401,71 @@ export default class PostgresDriver extends AbstractDriver { } public async GetIndexesFromEntity( - entities: EntityInfo[], + entities: Entity[], schema: string - ): Promise { - const response: { - tablename: string; - indexname: string; - columnname: string; - is_unique: number; - is_primary_key: number; - }[] = (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 - END AS is_unique, - CASE - 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 - JOIN pg_type t ON t.oid = f.atttypid - LEFT JOIN pg_attrdef d ON d.adrelid = c.oid AND d.adnum = f.attnum - LEFT JOIN pg_namespace n ON n.oid = c.relnamespace - LEFT JOIN pg_index AS ix ON f.attnum = ANY(ix.indkey) and c.oid = f.attrelid and c.oid = ix.indrelid - LEFT JOIN pg_class AS i ON ix.indexrelid = i.oid - WHERE c.relkind = 'r'::char - AND n.nspname in (${schema}) - AND f.attnum > 0 - AND i.oid<>0 - ORDER BY c.relname,f.attname;`)).rows; - entities.forEach(ent => { - response - .filter(filterVal => filterVal.tablename === ent.tsEntityName) - .forEach(resp => { - let indexInfo: IndexInfo = {} as IndexInfo; - const indexColumnInfo: IndexColumnInfo = {} as IndexColumnInfo; - if ( - ent.Indexes.filter( - filterVal => filterVal.name === resp.indexname - ).length > 0 - ) { - indexInfo = ent.Indexes.find( - filterVal => filterVal.name === resp.indexname - )!; - } else { - indexInfo.columns = [] as IndexColumnInfo[]; - indexInfo.name = resp.indexname; - 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) { - indexInfo.isPrimaryKey = false; - } - indexInfo.columns.push(indexColumnInfo); - }); - }); + ): Promise { + throw new Error(); + // TODO: Remove + // const response: { + // tablename: string; + // indexname: string; + // columnname: string; + // is_unique: number; + // is_primary_key: number; + // }[] = (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 + // END AS is_unique, + // CASE + // 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 + // JOIN pg_type t ON t.oid = f.atttypid + // LEFT JOIN pg_attrdef d ON d.adrelid = c.oid AND d.adnum = f.attnum + // LEFT JOIN pg_namespace n ON n.oid = c.relnamespace + // LEFT JOIN pg_index AS ix ON f.attnum = ANY(ix.indkey) and c.oid = f.attrelid and c.oid = ix.indrelid + // LEFT JOIN pg_class AS i ON ix.indexrelid = i.oid + // WHERE c.relkind = 'r'::char + // AND n.nspname in (${schema}) + // AND f.attnum > 0 + // AND i.oid<>0 + // ORDER BY c.relname,f.attname;`)).rows; + // entities.forEach(ent => { + // response + // .filter(filterVal => filterVal.tablename === ent.tsEntityName) + // .forEach(resp => { + // let indexInfo: IndexInfo = {} as IndexInfo; + // const indexColumnInfo: IndexColumnInfo = {} as IndexColumnInfo; + // if ( + // ent.Indexes.filter( + // filterVal => filterVal.name === resp.indexname + // ).length > 0 + // ) { + // indexInfo = ent.Indexes.find( + // filterVal => filterVal.name === resp.indexname + // )!; + // } else { + // indexInfo.columns = [] as IndexColumnInfo[]; + // indexInfo.name = resp.indexname; + // 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) { + // indexInfo.isPrimaryKey = false; + // } + // indexInfo.columns.push(indexColumnInfo); + // }); + // }); - return entities; + // return entities; } public async GetRelations( diff --git a/src/drivers/SqliteDriver.ts b/src/drivers/SqliteDriver.ts index 2fa5441..1cdab2f 100644 --- a/src/drivers/SqliteDriver.ts +++ b/src/drivers/SqliteDriver.ts @@ -42,6 +42,8 @@ export default class SqliteDriver extends AbstractDriver { } ret.push({ columns: [], + indices: [], + relations: [], sqlName: val.tbl_name, tscName: val.tbl_name }); @@ -217,62 +219,62 @@ export default class SqliteDriver extends AbstractDriver { // return entities; } - public async GetIndexesFromEntity( - entities: EntityInfo[] - ): Promise { - await Promise.all( - entities.map(async ent => { - const response = await this.ExecQuery<{ - seq: number; - name: string; - unique: number; - origin: string; - partial: number; - }>(`PRAGMA index_list('${ent.tsEntityName}');`); - await Promise.all( - response.map(async resp => { - const indexColumnsResponse = await this.ExecQuery<{ - seqno: number; - cid: number; - name: string; - }>(`PRAGMA index_info('${resp.name}');`); - indexColumnsResponse.forEach(element => { - let indexInfo: IndexInfo = {} as IndexInfo; - const indexColumnInfo: IndexColumnInfo = {} as IndexColumnInfo; - if ( - ent.Indexes.filter(filterVal => { - return filterVal.name === resp.name; - }).length > 0 - ) { - indexInfo = ent.Indexes.find( - filterVal => filterVal.name === resp.name - )!; - } else { - indexInfo.columns = [] as IndexColumnInfo[]; - indexInfo.name = resp.name; - indexInfo.isUnique = resp.unique === 1; - ent.Indexes.push(indexInfo); - } - indexColumnInfo.name = element.name; - if ( - indexColumnsResponse.length === 1 && - indexInfo.isUnique - ) { - ent.Columns.filter( - v => v.tsName === indexColumnInfo.name - ).forEach(v => { - // eslint-disable-next-line no-param-reassign - v.options.unique = true; - }); - } - indexInfo.columns.push(indexColumnInfo); - }); - }) - ); - }) - ); + public async GetIndexesFromEntity(entities: Entity[]): Promise { + throw new Error(); + // TODO: Remove + // await Promise.all( + // entities.map(async ent => { + // const response = await this.ExecQuery<{ + // seq: number; + // name: string; + // unique: number; + // origin: string; + // partial: number; + // }>(`PRAGMA index_list('${ent.tsEntityName}');`); + // await Promise.all( + // response.map(async resp => { + // const indexColumnsResponse = await this.ExecQuery<{ + // seqno: number; + // cid: number; + // name: string; + // }>(`PRAGMA index_info('${resp.name}');`); + // indexColumnsResponse.forEach(element => { + // let indexInfo: IndexInfo = {} as IndexInfo; + // const indexColumnInfo: IndexColumnInfo = {} as IndexColumnInfo; + // if ( + // ent.Indexes.filter(filterVal => { + // return filterVal.name === resp.name; + // }).length > 0 + // ) { + // indexInfo = ent.Indexes.find( + // filterVal => filterVal.name === resp.name + // )!; + // } else { + // indexInfo.columns = [] as IndexColumnInfo[]; + // indexInfo.name = resp.name; + // indexInfo.isUnique = resp.unique === 1; + // ent.Indexes.push(indexInfo); + // } + // indexColumnInfo.name = element.name; + // if ( + // indexColumnsResponse.length === 1 && + // indexInfo.isUnique + // ) { + // ent.Columns.filter( + // v => v.tsName === indexColumnInfo.name + // ).forEach(v => { + // // eslint-disable-next-line no-param-reassign + // v.options.unique = true; + // }); + // } + // indexInfo.columns.push(indexColumnInfo); + // }); + // }) + // ); + // }) + // ); - return entities; + // return entities; } public async GetRelations(entities: EntityInfo[]): Promise { diff --git a/src/entity.mst b/src/entity.mst index f68900e..0bb9c67 100644 --- a/src/entity.mst +++ b/src/entity.mst @@ -1,5 +1,5 @@ {{#*inline "Index"}} -@Index("{{name}}") +@Index("{{name}}",[{{#columns}}"{{.}}",{{/columns~}}],{ {{json options}} }) {{/inline}} {{#*inline "Column"}} {{#generated}}@PrimaryGeneratedColumn({ {{/generated}}{{^generated}}@Column({ {{#primary}}primary:{{primary}},{{/primary}}{{/generated}}{{json options}} }) diff --git a/src/models/Column.ts b/src/models/Column.ts index c0c77ca..3f43c33 100644 --- a/src/models/Column.ts +++ b/src/models/Column.ts @@ -7,7 +7,7 @@ export type Column = { primary?: boolean; generated?: true | "increment" | "uuid"; options: { - type: ColumnType; + type: ColumnType | string; // todo: remove ? name: string; length?: number; width?: number; @@ -17,7 +17,7 @@ export type Column = { precision?: number; scale?: number; unsigned?: boolean; - enum?: string[]; + enum?: string; // string[]; array?: boolean; // ? }; }; diff --git a/src/models/Entity.ts b/src/models/Entity.ts index 126f6ad..7a99347 100644 --- a/src/models/Entity.ts +++ b/src/models/Entity.ts @@ -10,6 +10,6 @@ export type Entity = { schema?: string; columns: Column[]; - relations?: Relation[]; - indices?: Index[]; + relations: Relation[]; + indices: Index[]; }; diff --git a/src/models/Index.ts b/src/models/Index.ts index 0de83cc..1f171fa 100644 --- a/src/models/Index.ts +++ b/src/models/Index.ts @@ -1,5 +1,8 @@ export type Index = { - name?: string; - columns?: ((object?: any) => any[] | { [key: string]: number }) | string[]; - unique?: boolean; + name: string; + columns: string[]; + options: { + unique?: boolean; + }; + primary?: boolean; }; From 130c68245830e303af5563f1c05c6771e9996d3c Mon Sep 17 00:00:00 2001 From: Kononnable Date: Thu, 3 Oct 2019 23:34:48 +0200 Subject: [PATCH 06/84] mysql relations rewrite --- src/drivers/AbstractDriver.ts | 198 ++++++++++++++++---------------- src/drivers/MssqlDriver.ts | 200 +++++++++++++++++---------------- src/drivers/MysqlDriver.ts | 57 ++++++---- src/drivers/OracleDriver.ts | 92 +++++++-------- src/drivers/PostgresDriver.ts | 158 +++++++++++++------------- src/drivers/SqliteDriver.ts | 90 +++++++-------- src/models/RelationInternal.ts | 12 ++ 7 files changed, 419 insertions(+), 388 deletions(-) create mode 100644 src/models/RelationInternal.ts diff --git a/src/drivers/AbstractDriver.ts b/src/drivers/AbstractDriver.ts index b34d1e4..e8a94f7 100644 --- a/src/drivers/AbstractDriver.ts +++ b/src/drivers/AbstractDriver.ts @@ -3,15 +3,16 @@ import { WithPrecisionColumnType, WithWidthColumnType } from "typeorm/driver/types/ColumnTypes"; +import { JoinColumnOptions } from "typeorm"; import { DataTypeDefaults } from "typeorm/driver/types/DataTypeDefaults"; import * as TomgUtils from "../Utils"; import EntityInfo from "../oldModels/EntityInfo"; import RelationInfo from "../oldModels/RelationInfo"; import ColumnInfo from "../oldModels/ColumnInfo"; import IConnectionOptions from "../IConnectionOptions"; -import IndexInfo from "../oldModels/IndexInfo"; -import RelationTempInfo from "../oldModels/RelationTempInfo"; import { Entity } from "../models/Entity"; +import { RelationInternal } from "../models/RelationInternal"; +import { Relation } from "../models/Relation"; export default abstract class AbstractDriver { public abstract standardPort: number; @@ -180,12 +181,11 @@ export default abstract class AbstractDriver { sqlEscapedSchema, connectionOptons.databaseName ); - // TODO: Uncomment - // dbModel = await this.GetRelations( - // dbModel, - // sqlEscapedSchema, - // connectionOptons.databaseName - // ); + dbModel = await this.GetRelations( + dbModel, + sqlEscapedSchema, + connectionOptons.databaseName + ); await this.DisconnectFromServer(); // dbModel = AbstractDriver.FindManyToManyRelations(dbModel); // AbstractDriver.FindPrimaryColumnsFromIndexes(dbModel); @@ -215,20 +215,20 @@ export default abstract class AbstractDriver { } public static GetRelationsFromRelationTempInfo( - relationsTemp: RelationTempInfo[], - entities: EntityInfo[] + relationsTemp: RelationInternal[], + entities: Entity[] ) { relationsTemp.forEach(relationTmp => { - if (relationTmp.ownerColumnsNames.length > 1) { + if (relationTmp.ownerColumns.length > 1) { const relatedTable = entities.find( - entity => entity.tsEntityName === relationTmp.ownerTable + entity => entity.tscName === relationTmp.ownerTable.tscName )!; if ( - relatedTable.Columns.length !== - relationTmp.ownerColumnsNames.length * 2 + relatedTable.columns.length !== + relationTmp.ownerColumns.length * 2 ) { TomgUtils.LogError( - `Relation between tables ${relationTmp.ownerTable} and ${relationTmp.referencedTable} wasn't generated correctly - complex relationships aren't supported yet.`, + `Relation between tables ${relationTmp.ownerTable.sqlName} and ${relationTmp.relatedTable.sqlName} wasn't generated correctly - complex relationships aren't supported yet.`, false ); return; @@ -236,12 +236,13 @@ export default abstract class AbstractDriver { const secondRelation = relationsTemp.find( relation => - relation.ownerTable === relatedTable.tsEntityName && - relation.referencedTable !== relationTmp.referencedTable + relation.ownerTable.tscName === relatedTable.tscName && + relation.relatedTable.tscName !== + relationTmp.relatedTable.tscName )!; if (!secondRelation) { TomgUtils.LogError( - `Relation between tables ${relationTmp.ownerTable} and ${relationTmp.referencedTable} wasn't generated correctly - complex relationships aren't supported yet.`, + `Relation between tables ${relationTmp.ownerTable.sqlName} and ${relationTmp.relatedTable.sqlName} wasn't generated correctly - complex relationships aren't supported yet.`, false ); return; @@ -249,133 +250,126 @@ export default abstract class AbstractDriver { } const ownerEntity = entities.find( - entitity => entitity.tsEntityName === relationTmp.ownerTable + entity => entity.tscName === relationTmp.ownerTable.tscName ); if (!ownerEntity) { TomgUtils.LogError( - `Relation between tables ${relationTmp.ownerTable} and ${relationTmp.referencedTable} didn't found entity model ${relationTmp.ownerTable}.` + `Relation between tables ${relationTmp.ownerTable.sqlName} and ${relationTmp.relatedTable.sqlName} didn't found entity model ${relationTmp.ownerTable.sqlName}.` ); return; } const referencedEntity = entities.find( - entitity => - entitity.tsEntityName === relationTmp.referencedTable + entity => entity.tscName === relationTmp.relatedTable.tscName ); if (!referencedEntity) { TomgUtils.LogError( - `Relation between tables ${relationTmp.ownerTable} and ${relationTmp.referencedTable} didn't found entity model ${relationTmp.referencedTable}.` + `Relation between tables ${relationTmp.ownerTable.sqlName} and ${relationTmp.relatedTable.sqlName} didn't found entity model ${relationTmp.relatedTable.sqlName}.` ); return; } for ( let relationColumnIndex = 0; - relationColumnIndex < relationTmp.ownerColumnsNames.length; + relationColumnIndex < relationTmp.ownerColumns.length; relationColumnIndex++ ) { - const ownerColumn = ownerEntity.Columns.find( + const ownerColumn = ownerEntity.columns.find( column => - column.tsName === - relationTmp.ownerColumnsNames[relationColumnIndex] + column.tscName === + relationTmp.ownerColumns[relationColumnIndex] ); if (!ownerColumn) { TomgUtils.LogError( - `Relation between tables ${relationTmp.ownerTable} and ${relationTmp.referencedTable} didn't found entity column ${relationTmp.ownerTable}.${ownerColumn}.` + `Relation between tables ${relationTmp.ownerTable.sqlName} and ${relationTmp.relatedTable.sqlName} didn't found entity column ${relationTmp.ownerTable.sqlName}.${ownerColumn}.` ); return; } - const relatedColumn = referencedEntity.Columns.find( + const relatedColumn = referencedEntity.columns.find( column => - column.tsName === - relationTmp.referencedColumnsNames[relationColumnIndex] + column.tscName === + relationTmp.relatedColumns[relationColumnIndex] ); if (!relatedColumn) { TomgUtils.LogError( - `Relation between tables ${relationTmp.ownerTable} and ${relationTmp.referencedTable} didn't found entity column ${relationTmp.referencedTable}.${relatedColumn}.` + `Relation between tables ${relationTmp.ownerTable.sqlName} and ${relationTmp.relatedTable.sqlName} didn't found entity column ${relationTmp.relatedTable.sqlName}.${relatedColumn}.` ); return; } let isOneToMany: boolean; isOneToMany = false; - const index = ownerEntity.Indexes.find( + const index = ownerEntity.indices.find( ind => - ind.isUnique && + ind.options.unique && ind.columns.length === 1 && - ind.columns[0].name === ownerColumn!.tsName + ind.columns[0] === ownerColumn!.tscName ); isOneToMany = !index; - const ownerRelation = new RelationInfo(); - ownerRelation.actionOnDelete = relationTmp.actionOnDelete; - ownerRelation.actionOnUpdate = relationTmp.actionOnUpdate; - ownerRelation.isOwner = true; - ownerRelation.relatedColumn = relatedColumn.tsName.toLowerCase(); - ownerRelation.relatedTable = relationTmp.referencedTable; - ownerRelation.ownerTable = relationTmp.ownerTable; - ownerRelation.relationType = isOneToMany - ? "ManyToOne" - : "OneToOne"; - - let columnName = ownerEntity.tsEntityName; - if ( - referencedEntity.Columns.some(v => v.tsName === columnName) - ) { - columnName += "_"; - for (let i = 2; i <= referencedEntity.Columns.length; i++) { - columnName = - columnName.substring( - 0, - columnName.length - i.toString().length - ) + i.toString(); - if ( - referencedEntity.Columns.every( - v => v.tsName !== columnName - ) - ) { - break; + const ownerRelation: Relation = { + fieldName: AbstractDriver.findNameForNewField( + relationTmp.relatedTable.tscName, + ownerEntity + ), + joinColumnOptions: relationTmp.ownerColumns.map( + (v, idx) => { + const retVal: JoinColumnOptions = { + name: v, + referencedColumnName: + relationTmp.relatedColumns[idx] + }; + return retVal; } - } - } + ), + relatedField: AbstractDriver.findNameForNewField( + relationTmp.ownerTable.tscName, + relationTmp.relatedTable + ), + relatedTable: relationTmp.relatedTable.tscName, + relationOptions: { + onDelete: relationTmp.onDelete, + onUpdate: relationTmp.onUpdate + }, + relationType: isOneToMany ? "OneToMany" : "OneToOne" + }; + const relatedRelation: Relation = { + fieldName: ownerRelation.relatedField, + relatedField: ownerRelation.fieldName, + relatedTable: relationTmp.ownerTable.tscName, + relationOptions: ownerRelation.relationOptions, + relationType: isOneToMany ? "ManyToOne" : "OneToOne" + }; - ownerRelation.ownerColumn = columnName; - ownerColumn.relations.push(ownerRelation); - if (isOneToMany) { - const col = new ColumnInfo(); - col.tsName = columnName; - const referencedRelation = new RelationInfo(); - col.relations.push(referencedRelation); - referencedRelation.actionOnDelete = - relationTmp.actionOnDelete; - referencedRelation.actionOnUpdate = - relationTmp.actionOnUpdate; - referencedRelation.isOwner = false; - referencedRelation.relatedColumn = ownerColumn.tsName; - referencedRelation.relatedTable = relationTmp.ownerTable; - referencedRelation.ownerTable = relationTmp.referencedTable; - referencedRelation.ownerColumn = relatedColumn.tsName; - referencedRelation.relationType = "OneToMany"; - referencedEntity.Columns.push(col); - } else { - const col = new ColumnInfo(); - col.tsName = columnName; - const referencedRelation = new RelationInfo(); - col.relations.push(referencedRelation); - referencedRelation.actionOnDelete = - relationTmp.actionOnDelete; - referencedRelation.actionOnUpdate = - relationTmp.actionOnUpdate; - referencedRelation.isOwner = false; - referencedRelation.relatedColumn = ownerColumn.tsName; - referencedRelation.relatedTable = relationTmp.ownerTable; - referencedRelation.ownerTable = relationTmp.referencedTable; - referencedRelation.ownerColumn = relatedColumn.tsName; - referencedRelation.relationType = "OneToOne"; - referencedEntity.Columns.push(col); - } + ownerEntity.relations.push(ownerRelation); + relationTmp.relatedTable.relations.push(relatedRelation); } }); return entities; } + private static findNameForNewField(_fieldName: string, entity: Entity) { + let fieldName = _fieldName; + const validNameCondition = + entity.columns.every(v => v.tscName !== fieldName) && + entity.relations.every(v => v.fieldName !== fieldName); + if (validNameCondition) { + fieldName += "_"; + for ( + let i = 2; + i <= entity.columns.length + entity.relations.length; + i++ + ) { + fieldName = + fieldName.substring( + 0, + fieldName.length - i.toString().length + ) + i.toString(); + if (validNameCondition) { + break; + } + } + } + return fieldName; + } + public abstract async GetCoulmnsFromEntity( entities: Entity[], schema: string, @@ -389,10 +383,10 @@ export default abstract class AbstractDriver { ): Promise; public abstract async GetRelations( - entities: EntityInfo[], + entities: Entity[], schema: string, dbNames: string - ): Promise; + ): Promise; public static FindPrimaryColumnsFromIndexes(dbModel: EntityInfo[]) { dbModel.forEach(entity => { diff --git a/src/drivers/MssqlDriver.ts b/src/drivers/MssqlDriver.ts index e59ee8e..057357b 100644 --- a/src/drivers/MssqlDriver.ts +++ b/src/drivers/MssqlDriver.ts @@ -303,107 +303,109 @@ WHERE TABLE_TYPE='BASE TABLE' and TABLE_SCHEMA in (${schema}) AND TABLE_CATALOG } public async GetRelations( - entities: EntityInfo[], + entities: Entity[], schema: string, dbNames: string - ): Promise { - const request = new MSSQL.Request(this.Connection); - const response: { - TableWithForeignKey: string; - FK_PartNo: number; - ForeignKeyColumn: string; - TableReferenced: string; - ForeignKeyColumnReferenced: string; - onDelete: "RESTRICT" | "CASCADE" | "SET_NULL" | "NO_ACTION"; - onUpdate: "RESTRICT" | "CASCADE" | "SET_NULL" | "NO_ACTION"; - objectId: number; - }[] = []; - await Promise.all( - dbNames.split(",").map(async dbName => { - await this.UseDB(dbName); - const resp: { - TableWithForeignKey: string; - FK_PartNo: number; - ForeignKeyColumn: string; - TableReferenced: string; - ForeignKeyColumnReferenced: string; - onDelete: "RESTRICT" | "CASCADE" | "SET_NULL" | "NO_ACTION"; - onUpdate: "RESTRICT" | "CASCADE" | "SET_NULL" | "NO_ACTION"; - objectId: number; - }[] = (await request.query(`select - parentTable.name as TableWithForeignKey, - fkc.constraint_column_id as FK_PartNo, - parentColumn.name as ForeignKeyColumn, - referencedTable.name as TableReferenced, - referencedColumn.name as ForeignKeyColumnReferenced, - fk.delete_referential_action_desc as onDelete, - fk.update_referential_action_desc as onUpdate, - fk.object_id as objectId -from - sys.foreign_keys fk -inner join - sys.foreign_key_columns as fkc on fkc.constraint_object_id=fk.object_id -inner join - sys.tables as parentTable on fkc.parent_object_id = parentTable.object_id -inner join - sys.columns as parentColumn on fkc.parent_object_id = parentColumn.object_id and fkc.parent_column_id = parentColumn.column_id -inner join - sys.tables as referencedTable on fkc.referenced_object_id = referencedTable.object_id -inner join - sys.columns as referencedColumn on fkc.referenced_object_id = referencedColumn.object_id and fkc.referenced_column_id = referencedColumn.column_id -inner join - sys.schemas as parentSchema on parentSchema.schema_id=parentTable.schema_id -where - fk.is_disabled=0 and fk.is_ms_shipped=0 and parentSchema.name in (${schema}) -order by - TableWithForeignKey, FK_PartNo`)).recordset; - response.push(...resp); - }) - ); - const relationsTemp: RelationTempInfo[] = [] as RelationTempInfo[]; - response.forEach(resp => { - let rels = relationsTemp.find( - val => val.objectId === resp.objectId - ); - if (rels === undefined) { - rels = {} as RelationTempInfo; - rels.ownerColumnsNames = []; - rels.referencedColumnsNames = []; - switch (resp.onDelete) { - case "NO_ACTION": - rels.actionOnDelete = null; - break; - case "SET_NULL": - rels.actionOnDelete = "SET NULL"; - break; - default: - rels.actionOnDelete = resp.onDelete; - break; - } - switch (resp.onUpdate) { - case "NO_ACTION": - rels.actionOnUpdate = null; - break; - case "SET_NULL": - rels.actionOnUpdate = "SET NULL"; - break; - default: - rels.actionOnUpdate = resp.onUpdate; - break; - } - rels.objectId = resp.objectId; - rels.ownerTable = resp.TableWithForeignKey; - rels.referencedTable = resp.TableReferenced; - relationsTemp.push(rels); - } - rels.ownerColumnsNames.push(resp.ForeignKeyColumn); - rels.referencedColumnsNames.push(resp.ForeignKeyColumnReferenced); - }); - const retVal = MssqlDriver.GetRelationsFromRelationTempInfo( - relationsTemp, - entities - ); - return retVal; + ): Promise { + throw new Error(); + // TODO: Remove + // const request = new MSSQL.Request(this.Connection); + // const response: { + // TableWithForeignKey: string; + // FK_PartNo: number; + // ForeignKeyColumn: string; + // TableReferenced: string; + // ForeignKeyColumnReferenced: string; + // onDelete: "RESTRICT" | "CASCADE" | "SET_NULL" | "NO_ACTION"; + // onUpdate: "RESTRICT" | "CASCADE" | "SET_NULL" | "NO_ACTION"; + // objectId: number; + // }[] = []; + // await Promise.all( + // dbNames.split(",").map(async dbName => { + // await this.UseDB(dbName); + // const resp: { + // TableWithForeignKey: string; + // FK_PartNo: number; + // ForeignKeyColumn: string; + // TableReferenced: string; + // ForeignKeyColumnReferenced: string; + // onDelete: "RESTRICT" | "CASCADE" | "SET_NULL" | "NO_ACTION"; + // onUpdate: "RESTRICT" | "CASCADE" | "SET_NULL" | "NO_ACTION"; + // objectId: number; + // }[] = (await request.query(`select + // parentTable.name as TableWithForeignKey, + // fkc.constraint_column_id as FK_PartNo, + // parentColumn.name as ForeignKeyColumn, + // referencedTable.name as TableReferenced, + // referencedColumn.name as ForeignKeyColumnReferenced, + // fk.delete_referential_action_desc as onDelete, + // fk.update_referential_action_desc as onUpdate, + // fk.object_id as objectId + // from + // sys.foreign_keys fk + // inner join + // sys.foreign_key_columns as fkc on fkc.constraint_object_id=fk.object_id + // inner join + // sys.tables as parentTable on fkc.parent_object_id = parentTable.object_id + // inner join + // sys.columns as parentColumn on fkc.parent_object_id = parentColumn.object_id and fkc.parent_column_id = parentColumn.column_id + // inner join + // sys.tables as referencedTable on fkc.referenced_object_id = referencedTable.object_id + // inner join + // sys.columns as referencedColumn on fkc.referenced_object_id = referencedColumn.object_id and fkc.referenced_column_id = referencedColumn.column_id + // inner join + // sys.schemas as parentSchema on parentSchema.schema_id=parentTable.schema_id + // where + // fk.is_disabled=0 and fk.is_ms_shipped=0 and parentSchema.name in (${schema}) + // order by + // TableWithForeignKey, FK_PartNo`)).recordset; + // response.push(...resp); + // }) + // ); + // const relationsTemp: RelationTempInfo[] = [] as RelationTempInfo[]; + // response.forEach(resp => { + // let rels = relationsTemp.find( + // val => val.objectId === resp.objectId + // ); + // if (rels === undefined) { + // rels = {} as RelationTempInfo; + // rels.ownerColumnsNames = []; + // rels.referencedColumnsNames = []; + // switch (resp.onDelete) { + // case "NO_ACTION": + // rels.actionOnDelete = null; + // break; + // case "SET_NULL": + // rels.actionOnDelete = "SET NULL"; + // break; + // default: + // rels.actionOnDelete = resp.onDelete; + // break; + // } + // switch (resp.onUpdate) { + // case "NO_ACTION": + // rels.actionOnUpdate = null; + // break; + // case "SET_NULL": + // rels.actionOnUpdate = "SET NULL"; + // break; + // default: + // rels.actionOnUpdate = resp.onUpdate; + // break; + // } + // rels.objectId = resp.objectId; + // rels.ownerTable = resp.TableWithForeignKey; + // rels.referencedTable = resp.TableReferenced; + // relationsTemp.push(rels); + // } + // rels.ownerColumnsNames.push(resp.ForeignKeyColumn); + // rels.referencedColumnsNames.push(resp.ForeignKeyColumnReferenced); + // }); + // const retVal = MssqlDriver.GetRelationsFromRelationTempInfo( + // relationsTemp, + // entities + // ); + // return retVal; } public async DisconnectFromServer() { diff --git a/src/drivers/MysqlDriver.ts b/src/drivers/MysqlDriver.ts index cab7cb8..e9fcf65 100644 --- a/src/drivers/MysqlDriver.ts +++ b/src/drivers/MysqlDriver.ts @@ -13,6 +13,7 @@ import IConnectionOptions from "../IConnectionOptions"; import { Entity } from "../models/Entity"; import { Column } from "../models/Column"; import { Index } from "../models/Index"; +import { RelationInternal } from "../models/RelationInternal"; export default class MysqlDriver extends AbstractDriver { public defaultValues: DataTypeDefaults = new TypeormDriver.MysqlDriver({ @@ -305,10 +306,10 @@ export default class MysqlDriver extends AbstractDriver { } public async GetRelations( - entities: EntityInfo[], + entities: Entity[], schema: string, dbNames: string - ): Promise { + ): Promise { const response = await this.ExecQuery<{ TableWithForeignKey: string; FK_PartNo: number; @@ -336,27 +337,43 @@ export default class MysqlDriver extends AbstractDriver { TABLE_SCHEMA IN (${MysqlDriver.escapeCommaSeparatedList(dbNames)}) AND CU.REFERENCED_TABLE_NAME IS NOT NULL; `); - const relationsTemp: RelationTempInfo[] = [] as RelationTempInfo[]; - response.forEach(resp => { - let rels = relationsTemp.find( - val => val.objectId === resp.object_id + const relationsTemp: RelationInternal[] = [] as RelationInternal[]; + const relationKeys = new Set(response.map(v => v.object_id)); + + relationKeys.forEach(relationId => { + const rows = response.filter(v => v.object_id === relationId); + const ownerTable = entities.find( + v => v.sqlName === rows[0].TableWithForeignKey ); - if (rels === undefined) { - rels = {} as RelationTempInfo; - rels.ownerColumnsNames = []; - rels.referencedColumnsNames = []; - rels.actionOnDelete = - resp.onDelete === "NO_ACTION" ? null : resp.onDelete; - rels.actionOnUpdate = - resp.onUpdate === "NO_ACTION" ? null : resp.onUpdate; - rels.objectId = resp.object_id; - rels.ownerTable = resp.TableWithForeignKey; - rels.referencedTable = resp.TableReferenced; - relationsTemp.push(rels); + const relatedTable = entities.find( + v => v.sqlName === rows[0].TableReferenced + ); + + if (!ownerTable || !relatedTable) { + TomgUtils.LogError( + `Relation between tables ${rows[0].TableWithForeignKey} and ${rows[0].TableReferenced} wasn't found in entity model.`, + true + ); + return; } - rels.ownerColumnsNames.push(resp.ForeignKeyColumn); - rels.referencedColumnsNames.push(resp.ForeignKeyColumnReferenced); + const internal: RelationInternal = { + ownerColumns: [], + relatedColumns: [], + ownerTable, + relatedTable + }; + if (rows[0].onDelete !== "NO_ACTION") { + internal.onDelete = rows[0].onDelete; + } + if (rows[0].onUpdate !== "NO_ACTION") { + internal.onUpdate = rows[0].onUpdate; + } + rows.forEach(row => { + internal.ownerColumns.push(row.ForeignKeyColumn); + internal.relatedColumns.push(row.ForeignKeyColumnReferenced); + }); }); + const retVal = MysqlDriver.GetRelationsFromRelationTempInfo( relationsTemp, entities diff --git a/src/drivers/OracleDriver.ts b/src/drivers/OracleDriver.ts index 9341774..d58eeba 100644 --- a/src/drivers/OracleDriver.ts +++ b/src/drivers/OracleDriver.ts @@ -252,52 +252,54 @@ export default class OracleDriver extends AbstractDriver { // return entities; } - public async GetRelations(entities: EntityInfo[]): Promise { - const response: { - OWNER_TABLE_NAME: string; - OWNER_POSITION: string; - OWNER_COLUMN_NAME: string; - CHILD_TABLE_NAME: string; - CHILD_COLUMN_NAME: string; - DELETE_RULE: "RESTRICT" | "CASCADE" | "SET NULL" | "NO ACTION"; - CONSTRAINT_NAME: string; - }[] = (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, - owner.CONSTRAINT_NAME - from user_constraints owner - join user_constraints child on owner.r_constraint_name=child.CONSTRAINT_NAME and child.constraint_type in ('P','U') - JOIN USER_CONS_COLUMNS ownCol ON owner.CONSTRAINT_NAME = ownCol.CONSTRAINT_NAME - JOIN USER_CONS_COLUMNS childCol ON child.CONSTRAINT_NAME = childCol.CONSTRAINT_NAME AND ownCol.POSITION=childCol.POSITION - ORDER BY OWNER_TABLE_NAME ASC, owner.CONSTRAINT_NAME ASC, OWNER_POSITION ASC`)) - .rows!; + public async GetRelations(entities: Entity[]): Promise { + throw new Error(); + // TODO: Remove + // const response: { + // OWNER_TABLE_NAME: string; + // OWNER_POSITION: string; + // OWNER_COLUMN_NAME: string; + // CHILD_TABLE_NAME: string; + // CHILD_COLUMN_NAME: string; + // DELETE_RULE: "RESTRICT" | "CASCADE" | "SET NULL" | "NO ACTION"; + // CONSTRAINT_NAME: string; + // }[] = (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, + // owner.CONSTRAINT_NAME + // from user_constraints owner + // join user_constraints child on owner.r_constraint_name=child.CONSTRAINT_NAME and child.constraint_type in ('P','U') + // JOIN USER_CONS_COLUMNS ownCol ON owner.CONSTRAINT_NAME = ownCol.CONSTRAINT_NAME + // JOIN USER_CONS_COLUMNS childCol ON child.CONSTRAINT_NAME = childCol.CONSTRAINT_NAME AND ownCol.POSITION=childCol.POSITION + // ORDER BY OWNER_TABLE_NAME ASC, owner.CONSTRAINT_NAME ASC, OWNER_POSITION ASC`)) + // .rows!; - const relationsTemp: RelationTempInfo[] = [] as RelationTempInfo[]; - response.forEach(resp => { - let rels = relationsTemp.find( - val => val.objectId === resp.CONSTRAINT_NAME - ); - if (rels === undefined) { - rels = {} as RelationTempInfo; - rels.ownerColumnsNames = []; - rels.referencedColumnsNames = []; - rels.actionOnDelete = - resp.DELETE_RULE === "NO ACTION" ? null : resp.DELETE_RULE; - rels.actionOnUpdate = null; - rels.objectId = resp.CONSTRAINT_NAME; - rels.ownerTable = resp.OWNER_TABLE_NAME; - rels.referencedTable = resp.CHILD_TABLE_NAME; - relationsTemp.push(rels); - } - rels.ownerColumnsNames.push(resp.OWNER_COLUMN_NAME); - rels.referencedColumnsNames.push(resp.CHILD_COLUMN_NAME); - }); - const retVal = OracleDriver.GetRelationsFromRelationTempInfo( - relationsTemp, - entities - ); - return retVal; + // const relationsTemp: RelationTempInfo[] = [] as RelationTempInfo[]; + // response.forEach(resp => { + // let rels = relationsTemp.find( + // val => val.objectId === resp.CONSTRAINT_NAME + // ); + // if (rels === undefined) { + // rels = {} as RelationTempInfo; + // rels.ownerColumnsNames = []; + // rels.referencedColumnsNames = []; + // rels.actionOnDelete = + // resp.DELETE_RULE === "NO ACTION" ? null : resp.DELETE_RULE; + // rels.actionOnUpdate = null; + // rels.objectId = resp.CONSTRAINT_NAME; + // rels.ownerTable = resp.OWNER_TABLE_NAME; + // rels.referencedTable = resp.CHILD_TABLE_NAME; + // relationsTemp.push(rels); + // } + // rels.ownerColumnsNames.push(resp.OWNER_COLUMN_NAME); + // rels.referencedColumnsNames.push(resp.CHILD_COLUMN_NAME); + // }); + // const retVal = OracleDriver.GetRelationsFromRelationTempInfo( + // relationsTemp, + // entities + // ); + // return retVal; } public async DisconnectFromServer() { diff --git a/src/drivers/PostgresDriver.ts b/src/drivers/PostgresDriver.ts index 774a394..02c5615 100644 --- a/src/drivers/PostgresDriver.ts +++ b/src/drivers/PostgresDriver.ts @@ -469,85 +469,87 @@ export default class PostgresDriver extends AbstractDriver { } public async GetRelations( - entities: EntityInfo[], + entities: Entity[], schema: string - ): Promise { - const response: { - tablewithforeignkey: string; - fk_partno: number; - foreignkeycolumn: string; - tablereferenced: string; - foreignkeycolumnreferenced: string; - ondelete: "RESTRICT" | "CASCADE" | "SET NULL" | "NO ACTION"; - onupdate: "RESTRICT" | "CASCADE" | "SET NULL" | "NO ACTION"; - object_id: string; - // Distinct because of note in https://www.postgresql.org/docs/9.1/information-schema.html - }[] = (await this.Connection.query(`SELECT DISTINCT - con.relname AS tablewithforeignkey, - att.attnum as fk_partno, - att2.attname AS foreignkeycolumn, - cl.relname AS tablereferenced, - att.attname AS foreignkeycolumnreferenced, - delete_rule as ondelete, - update_rule as onupdate, - concat(con.conname,con.conrelid,con.confrelid) as object_id - FROM ( - SELECT - unnest(con1.conkey) AS parent, - unnest(con1.confkey) AS child, - con1.confrelid, - con1.conrelid, - cl_1.relname, - con1.conname, - nspname - FROM - pg_class cl_1, - pg_namespace ns, - pg_constraint con1 - WHERE - con1.contype = 'f'::"char" - AND cl_1.relnamespace = ns.oid - AND con1.conrelid = cl_1.oid - and nspname in (${schema}) - ) con, - pg_attribute att, - pg_class cl, - pg_attribute att2, - information_schema.referential_constraints rc - WHERE - att.attrelid = con.confrelid - AND att.attnum = con.child - AND cl.oid = con.confrelid - AND att2.attrelid = con.conrelid - AND att2.attnum = con.parent - AND rc.constraint_name= con.conname AND constraint_catalog=current_database() AND rc.constraint_schema=nspname - `)).rows; - const relationsTemp: RelationTempInfo[] = [] as RelationTempInfo[]; - response.forEach(resp => { - let rels = relationsTemp.find( - val => val.objectId === resp.object_id - ); - if (rels === undefined) { - rels = {} as RelationTempInfo; - rels.ownerColumnsNames = []; - rels.referencedColumnsNames = []; - rels.actionOnDelete = - resp.ondelete === "NO ACTION" ? null : resp.ondelete; - rels.actionOnUpdate = - resp.onupdate === "NO ACTION" ? null : resp.onupdate; - rels.objectId = resp.object_id; - rels.ownerTable = resp.tablewithforeignkey; - rels.referencedTable = resp.tablereferenced; - relationsTemp.push(rels); - } - rels.ownerColumnsNames.push(resp.foreignkeycolumn); - rels.referencedColumnsNames.push(resp.foreignkeycolumnreferenced); - }); - const retVal = PostgresDriver.GetRelationsFromRelationTempInfo( - relationsTemp, - entities - ); - return retVal; + ): Promise { + throw new Error(); + // TODO: Remove + // const response: { + // tablewithforeignkey: string; + // fk_partno: number; + // foreignkeycolumn: string; + // tablereferenced: string; + // foreignkeycolumnreferenced: string; + // ondelete: "RESTRICT" | "CASCADE" | "SET NULL" | "NO ACTION"; + // onupdate: "RESTRICT" | "CASCADE" | "SET NULL" | "NO ACTION"; + // object_id: string; + // // Distinct because of note in https://www.postgresql.org/docs/9.1/information-schema.html + // }[] = (await this.Connection.query(`SELECT DISTINCT + // con.relname AS tablewithforeignkey, + // att.attnum as fk_partno, + // att2.attname AS foreignkeycolumn, + // cl.relname AS tablereferenced, + // att.attname AS foreignkeycolumnreferenced, + // delete_rule as ondelete, + // update_rule as onupdate, + // concat(con.conname,con.conrelid,con.confrelid) as object_id + // FROM ( + // SELECT + // unnest(con1.conkey) AS parent, + // unnest(con1.confkey) AS child, + // con1.confrelid, + // con1.conrelid, + // cl_1.relname, + // con1.conname, + // nspname + // FROM + // pg_class cl_1, + // pg_namespace ns, + // pg_constraint con1 + // WHERE + // con1.contype = 'f'::"char" + // AND cl_1.relnamespace = ns.oid + // AND con1.conrelid = cl_1.oid + // and nspname in (${schema}) + // ) con, + // pg_attribute att, + // pg_class cl, + // pg_attribute att2, + // information_schema.referential_constraints rc + // WHERE + // att.attrelid = con.confrelid + // AND att.attnum = con.child + // AND cl.oid = con.confrelid + // AND att2.attrelid = con.conrelid + // AND att2.attnum = con.parent + // AND rc.constraint_name= con.conname AND constraint_catalog=current_database() AND rc.constraint_schema=nspname + // `)).rows; + // const relationsTemp: RelationTempInfo[] = [] as RelationTempInfo[]; + // response.forEach(resp => { + // let rels = relationsTemp.find( + // val => val.objectId === resp.object_id + // ); + // if (rels === undefined) { + // rels = {} as RelationTempInfo; + // rels.ownerColumnsNames = []; + // rels.referencedColumnsNames = []; + // rels.actionOnDelete = + // resp.ondelete === "NO ACTION" ? null : resp.ondelete; + // rels.actionOnUpdate = + // resp.onupdate === "NO ACTION" ? null : resp.onupdate; + // rels.objectId = resp.object_id; + // rels.ownerTable = resp.tablewithforeignkey; + // rels.referencedTable = resp.tablereferenced; + // relationsTemp.push(rels); + // } + // rels.ownerColumnsNames.push(resp.foreignkeycolumn); + // rels.referencedColumnsNames.push(resp.foreignkeycolumnreferenced); + // }); + // const retVal = PostgresDriver.GetRelationsFromRelationTempInfo( + // relationsTemp, + // entities + // ); + // return retVal; } public async DisconnectFromServer() { diff --git a/src/drivers/SqliteDriver.ts b/src/drivers/SqliteDriver.ts index 1cdab2f..fac4571 100644 --- a/src/drivers/SqliteDriver.ts +++ b/src/drivers/SqliteDriver.ts @@ -277,50 +277,52 @@ export default class SqliteDriver extends AbstractDriver { // return entities; } - public async GetRelations(entities: EntityInfo[]): Promise { - let retVal = entities; - await Promise.all( - retVal.map(async entity => { - const response = await this.ExecQuery<{ - id: number; - seq: number; - table: string; - from: string; - to: string; - on_update: - | "RESTRICT" - | "CASCADE" - | "SET NULL" - | "NO ACTION"; - on_delete: - | "RESTRICT" - | "CASCADE" - | "SET NULL" - | "NO ACTION"; - match: string; - }>(`PRAGMA foreign_key_list('${entity.tsEntityName}');`); - const relationsTemp: RelationTempInfo[] = [] as RelationTempInfo[]; - response.forEach(resp => { - const rels = {} as RelationTempInfo; - rels.ownerColumnsNames = []; - rels.referencedColumnsNames = []; - rels.actionOnDelete = - resp.on_delete === "NO ACTION" ? null : resp.on_delete; - rels.actionOnUpdate = - resp.on_update === "NO ACTION" ? null : resp.on_update; - rels.ownerTable = entity.tsEntityName; - rels.referencedTable = resp.table; - relationsTemp.push(rels); - rels.ownerColumnsNames.push(resp.from); - rels.referencedColumnsNames.push(resp.to); - }); - retVal = SqliteDriver.GetRelationsFromRelationTempInfo( - relationsTemp, - retVal - ); - }) - ); - return retVal; + public async GetRelations(entities: Entity[]): Promise { + throw new Error(); + // TODO: Remove + // let retVal = entities; + // await Promise.all( + // retVal.map(async entity => { + // const response = await this.ExecQuery<{ + // id: number; + // seq: number; + // table: string; + // from: string; + // to: string; + // on_update: + // | "RESTRICT" + // | "CASCADE" + // | "SET NULL" + // | "NO ACTION"; + // on_delete: + // | "RESTRICT" + // | "CASCADE" + // | "SET NULL" + // | "NO ACTION"; + // match: string; + // }>(`PRAGMA foreign_key_list('${entity.tsEntityName}');`); + // const relationsTemp: RelationTempInfo[] = [] as RelationTempInfo[]; + // response.forEach(resp => { + // const rels = {} as RelationTempInfo; + // rels.ownerColumnsNames = []; + // rels.referencedColumnsNames = []; + // rels.actionOnDelete = + // resp.on_delete === "NO ACTION" ? null : resp.on_delete; + // rels.actionOnUpdate = + // resp.on_update === "NO ACTION" ? null : resp.on_update; + // rels.ownerTable = entity.tsEntityName; + // rels.referencedTable = resp.table; + // relationsTemp.push(rels); + // rels.ownerColumnsNames.push(resp.from); + // rels.referencedColumnsNames.push(resp.to); + // }); + // retVal = SqliteDriver.GetRelationsFromRelationTempInfo( + // relationsTemp, + // retVal + // ); + // }) + // ); + // return retVal; } public async DisconnectFromServer() { diff --git a/src/models/RelationInternal.ts b/src/models/RelationInternal.ts new file mode 100644 index 0000000..0d3923a --- /dev/null +++ b/src/models/RelationInternal.ts @@ -0,0 +1,12 @@ +import { OnDeleteType } from "typeorm/metadata/types/OnDeleteType"; +import { OnUpdateType } from "typeorm/metadata/types/OnUpdateType"; +import { Entity } from "./Entity"; + +export type RelationInternal = { + ownerTable: Entity; + relatedTable: Entity; + ownerColumns: string[]; + relatedColumns: string[]; + onDelete?: OnDeleteType; + onUpdate?: OnUpdateType; +}; From 113e2ff3bfdc80d07b1c7e5c5e9786ba5407aa4c Mon Sep 17 00:00:00 2001 From: Kononnable Date: Fri, 4 Oct 2019 23:43:31 +0200 Subject: [PATCH 07/84] prettyfying generated models, fixing some of the tests --- package-lock.json | 9 +- package.json | 3 +- src/Engine.ts | 6 +- src/drivers/AbstractDriver.ts | 37 ++++--- src/drivers/MysqlDriver.ts | 42 ++++---- src/entity.mst | 8 +- src/models/Column.ts | 6 +- test/drivers/MssqlDriver.test.ts | 3 +- test/integration/runTestsFromPath.test.ts | 114 +++++++++++----------- test/utils/EntityFileToJson.ts | 21 +++- 10 files changed, 140 insertions(+), 109 deletions(-) diff --git a/package-lock.json b/package-lock.json index 140eebf..8afdab2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -352,6 +352,12 @@ "moment": ">=2.14.0" } }, + "@types/prettier": { + "version": "1.18.3", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-1.18.3.tgz", + "integrity": "sha512-48rnerQdcZ26odp+HOvDGX8IcUkYOCuMc2BodWYTe956MqkHlOGAG4oFQ83cjZ0a4GAgj7mb4GUClxYd2Hlodg==", + "dev": true + }, "@types/sinon": { "version": "7.0.13", "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-7.0.13.tgz", @@ -4243,8 +4249,7 @@ "prettier": { "version": "1.18.2", "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.18.2.tgz", - "integrity": "sha512-OeHeMc0JhFE9idD4ZdtNibzY0+TPHSpSSb9h8FqtP+YnoZZ1sl8Vc9b1sasjfymH3SonAF4QcA2+mzHPhMvIiw==", - "dev": true + "integrity": "sha512-OeHeMc0JhFE9idD4ZdtNibzY0+TPHSpSSb9h8FqtP+YnoZZ1sl8Vc9b1sasjfymH3SonAF4QcA2+mzHPhMvIiw==" }, "progress": { "version": "2.0.3", diff --git a/package.json b/package.json index 52324d8..f4af5e7 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "mssql": "^5.1.0", "mysql": "^2.17.1", "pg": "^7.12.0", + "prettier": "^1.18.2", "reflect-metadata": "^0.1.13", "sqlite3": "^4.0.9", "typeorm": "^0.2.18", @@ -51,6 +52,7 @@ "@types/node": "^12.6.9", "@types/oracledb": "^3.1.3", "@types/pg": "^7.4.14", + "@types/prettier": "^1.18.3", "@types/sinon": "^7.0.13", "@types/sqlite3": "^3.1.5", "@types/yargs": "^12.0.1", @@ -72,7 +74,6 @@ "mocha": "^6.2.0", "ncp": "^2.0.0", "nyc": "^14.1.1", - "prettier": "^1.18.2", "rimraf": "^2.6.3", "sinon": "^7.3.2", "sinon-chai": "^3.3.0", diff --git a/src/Engine.ts b/src/Engine.ts index 093f996..dee0712 100644 --- a/src/Engine.ts +++ b/src/Engine.ts @@ -1,4 +1,5 @@ import * as Handlebars from "handlebars"; +import * as Prettier from "prettier"; import { DataTypeDefaults } from "typeorm/driver/types/DataTypeDefaults"; import * as TomgUtils from "./Utils"; import AbstractDriver from "./drivers/AbstractDriver"; @@ -13,11 +14,11 @@ import OracleDriver from "./drivers/OracleDriver"; import SqliteDriver from "./drivers/SqliteDriver"; import NamingStrategy from "./NamingStrategy"; import AbstractNamingStrategy from "./AbstractNamingStrategy"; +import { Entity } from "./models/Entity"; import changeCase = require("change-case"); import fs = require("fs"); import path = require("path"); -import { Entity } from "./models/Entity"; export function createDriver(driverName: string): AbstractDriver { switch (driverName) { @@ -274,7 +275,8 @@ export function modelGenerationPhase( } const resultFilePath = path.resolve(entitesPath, `${casedFileName}.ts`); const rendered = compliedTemplate(element); - fs.writeFileSync(resultFilePath, rendered, { + const formatted = Prettier.format(rendered, { parser: "typescript" }); + fs.writeFileSync(resultFilePath, formatted, { encoding: "UTF-8", flag: "w" }); diff --git a/src/drivers/AbstractDriver.ts b/src/drivers/AbstractDriver.ts index e8a94f7..3907077 100644 --- a/src/drivers/AbstractDriver.ts +++ b/src/drivers/AbstractDriver.ts @@ -188,7 +188,7 @@ export default abstract class AbstractDriver { ); await this.DisconnectFromServer(); // dbModel = AbstractDriver.FindManyToManyRelations(dbModel); - // AbstractDriver.FindPrimaryColumnsFromIndexes(dbModel); + AbstractDriver.FindPrimaryColumnsFromIndexes(dbModel); return dbModel; } @@ -388,28 +388,27 @@ export default abstract class AbstractDriver { dbNames: string ): Promise; - public static FindPrimaryColumnsFromIndexes(dbModel: EntityInfo[]) { + public static FindPrimaryColumnsFromIndexes(dbModel: Entity[]) { dbModel.forEach(entity => { - const primaryIndex = entity.Indexes.find(v => v.isPrimaryKey); - entity.Columns.filter( - col => - primaryIndex && - primaryIndex.columns.some( - cIndex => cIndex.name === col.tsName - ) - ).forEach(col => { - // eslint-disable-next-line no-param-reassign - col.options.primary = true; - }); + const primaryIndex = entity.indices.find(v => v.primary); + entity.columns + .filter( + col => + primaryIndex && + primaryIndex.columns.some( + cIndex => cIndex === col.tscName + ) + ) + .forEach(col => { + // eslint-disable-next-line no-param-reassign + col.primary = true; + }); if ( - !entity.Columns.some(v => { - return !!v.options.primary; + !entity.columns.some(v => { + return !!v.primary; }) ) { - TomgUtils.LogError( - `Table ${entity.tsEntityName} has no PK.`, - false - ); + TomgUtils.LogError(`Table ${entity.tscName} has no PK.`, false); } }); } diff --git a/src/drivers/MysqlDriver.ts b/src/drivers/MysqlDriver.ts index e9fcf65..b5d812b 100644 --- a/src/drivers/MysqlDriver.ts +++ b/src/drivers/MysqlDriver.ts @@ -56,8 +56,8 @@ export default class MysqlDriver extends AbstractDriver { IS_NULLABLE: string; DATA_TYPE: string; CHARACTER_MAXIMUM_LENGTH: number; - NUMERIC_PRECISION: number; - NUMERIC_SCALE: number; + NUMERIC_PRECISION: number | null; + NUMERIC_SCALE: number | null; IsIdentity: number; COLUMN_TYPE: string; COLUMN_KEY: string; @@ -76,21 +76,21 @@ export default class MysqlDriver extends AbstractDriver { let tscType = ""; const options: Partial = {}; options.name = resp.COLUMN_NAME; - options.nullable = resp.IS_NULLABLE === "YES"; const generated = resp.IsIdentity === 1 ? true : undefined; - options.unique = resp.COLUMN_KEY === "UNI"; - options.default = MysqlDriver.ReturnDefaultValueFunction( + const defaultValue = MysqlDriver.ReturnDefaultValueFunction( resp.COLUMN_DEFAULT ); - options.type = resp.DATA_TYPE as any; - options.unsigned = resp.COLUMN_TYPE.endsWith(" unsigned"); + let columnType = resp.DATA_TYPE; + if (resp.IS_NULLABLE === "YES") options.nullable = true; + if (resp.COLUMN_KEY === "UNI") options.unique = true; + if (resp.COLUMN_TYPE.endsWith(" unsigned")) + options.unsigned = true; switch (resp.DATA_TYPE) { case "int": tscType = "number"; break; case "bit": if (resp.COLUMN_TYPE === "bit(1)") { - options.width = 1; tscType = "boolean"; } else { tscType = "number"; @@ -177,7 +177,9 @@ export default class MysqlDriver extends AbstractDriver { options.enum = resp.COLUMN_TYPE.substring( 5, resp.COLUMN_TYPE.length - 1 - ).replace(/'/gi, '"'); + ) + .replace(/'/gi, "") + .split(","); break; case "json": tscType = "object"; @@ -211,7 +213,7 @@ export default class MysqlDriver extends AbstractDriver { break; case "geometrycollection": case "geomcollection": - options.type = "geometrycollection"; + columnType = "geometrycollection"; tscType = "string"; break; default: @@ -222,14 +224,18 @@ export default class MysqlDriver extends AbstractDriver { } if ( this.ColumnTypesWithPrecision.some( - v => v === options.type + v => v === columnType ) ) { - options.precision = resp.NUMERIC_PRECISION; - options.scale = resp.NUMERIC_SCALE; + if (resp.NUMERIC_PRECISION !== null) { + options.precision = resp.NUMERIC_PRECISION; + } + if (resp.NUMERIC_SCALE !== null) { + options.scale = resp.NUMERIC_SCALE; + } } if ( - this.ColumnTypesWithLength.some(v => v === options.type) + this.ColumnTypesWithLength.some(v => v === columnType) ) { options.length = resp.CHARACTER_MAXIMUM_LENGTH > 0 @@ -238,7 +244,7 @@ export default class MysqlDriver extends AbstractDriver { } if ( this.ColumnTypesWithWidth.some( - v => v === options.type && tscType !== "boolean" + v => v === columnType && tscType !== "boolean" ) ) { options.width = @@ -247,10 +253,12 @@ export default class MysqlDriver extends AbstractDriver { : undefined; } - if (options.type) { + if (columnType) { ent.columns.push({ generated, - options: { type: "integer", name: "", ...options }, // TODO: Change + type: columnType, + default: defaultValue, + options: { name: "", ...options }, // TODO: Change tscName, tscType }); diff --git a/src/entity.mst b/src/entity.mst index 0bb9c67..403f851 100644 --- a/src/entity.mst +++ b/src/entity.mst @@ -2,7 +2,7 @@ @Index("{{name}}",[{{#columns}}"{{.}}",{{/columns~}}],{ {{json options}} }) {{/inline}} {{#*inline "Column"}} -{{#generated}}@PrimaryGeneratedColumn({ {{/generated}}{{^generated}}@Column({ {{#primary}}primary:{{primary}},{{/primary}}{{/generated}}{{json options}} }) +{{#generated}}@PrimaryGeneratedColumn({ type:"{{type}}", {{/generated}}{{^generated}}@Column("{{type}}",{ {{#primary}}primary:{{primary}},{{/primary}}{{/generated}}{{json options}}{{#default}},default: {{.}},{{/default}} }) {{tscName}}:{{tscType}}; {{/inline}} @@ -21,11 +21,12 @@ export class {{tscName}} { } {{/inline}} +import {BaseEntity,Column,Entity,Index,JoinColumn,JoinTable,ManyToMany,ManyToOne,OneToMany,OneToOne,PrimaryColumn,PrimaryGeneratedColumn,RelationId} from "typeorm"; + {{~> Entity}} - -import {BaseEntity,Column,Entity,Index,JoinColumn,JoinTable,ManyToMany,ManyToOne,OneToMany,OneToOne,PrimaryColumn,PrimaryGeneratedColumn,RelationId} from "typeorm"; +{{!-- {{relationImports}}{{#each UniqueImports}}import {{curly true}}{{toEntityName this}}{{curly false}} from "./{{toFileName this}}"; {{/each}} @@ -71,3 +72,4 @@ import {BaseEntity,Column,Entity,Index,JoinColumn,JoinTable,ManyToMany,ManyToOne } {{/if}} } +--}} \ No newline at end of file diff --git a/src/models/Column.ts b/src/models/Column.ts index 3f43c33..f62b867 100644 --- a/src/models/Column.ts +++ b/src/models/Column.ts @@ -3,21 +3,21 @@ import { ColumnType } from "typeorm"; export type Column = { tscType: any; tscName: string; + type: ColumnType | string; // todo: remove ? primary?: boolean; generated?: true | "increment" | "uuid"; + default?: string; // ? options: { - type: ColumnType | string; // todo: remove ? name: string; length?: number; width?: number; nullable?: boolean; unique?: boolean; // ? - default?: string; // ? precision?: number; scale?: number; unsigned?: boolean; - enum?: string; // string[]; + enum?: string[]; array?: boolean; // ? }; }; diff --git a/test/drivers/MssqlDriver.test.ts b/test/drivers/MssqlDriver.test.ts index 1616a62..5c815b9 100644 --- a/test/drivers/MssqlDriver.test.ts +++ b/test/drivers/MssqlDriver.test.ts @@ -26,7 +26,8 @@ class FakeRecordset extends Array implements MSSQL.IRecordSet { } } -describe("MssqlDriver", function() { +// TODO: Remove +describe.skip("MssqlDriver", function() { let driver: MssqlDriver; const sandbox = Sinon.sandbox.create(); diff --git a/test/integration/runTestsFromPath.test.ts b/test/integration/runTestsFromPath.test.ts index db648db..ab1a915 100644 --- a/test/integration/runTestsFromPath.test.ts +++ b/test/integration/runTestsFromPath.test.ts @@ -17,6 +17,7 @@ import path = require("path"); import chaiSubset = require("chai-subset"); import chai = require("chai"); import yn = require("yn"); +import { Entity } from "../../src/models/Entity"; require("dotenv").config(); @@ -80,50 +81,48 @@ function runTestForMultipleDrivers( it(testName, async function() { const driversToRun = selectDriversForSpecyficTest(); const modelGenerationPromises = driversToRun.map(async dbDriver => { - throw new Error(); + const { + generationOptions, + driver, + connectionOptions, + resultsPath, + filesOrgPathTS + } = await prepareTestRuns(testPartialPath, testName, dbDriver); + let dbModel: Entity[] = []; + switch (testName) { + case "144": + dbModel = await dataCollectionPhase( + driver, + Object.assign(connectionOptions, { + databaseName: "db1,db2" + }) + ); + break; + + default: + dbModel = await dataCollectionPhase( + driver, + connectionOptions + ); + break; + } // TODO: Remove - // const { - // generationOptions, - // driver, - // connectionOptions, - // resultsPath, - // filesOrgPathTS - // } = await prepareTestRuns(testPartialPath, testName, dbDriver); - // let dbModel: EntityInfo[] = []; - // switch (testName) { - // case "144": - // dbModel = await dataCollectionPhase( - // driver, - // Object.assign(connectionOptions, { - // databaseName: "db1,db2" - // }) - // ); - // break; - - // default: - // dbModel = await dataCollectionPhase( - // driver, - // connectionOptions - // ); - // break; - // } - - // dbModel = modelCustomizationPhase( - // dbModel, - // generationOptions, - // driver.defaultValues - // ); - // modelGenerationPhase(connectionOptions, generationOptions, dbModel); - // const filesGenPath = path.resolve(resultsPath, "entities"); - // compareGeneratedFiles(filesOrgPathTS, filesGenPath); - // return { - // dbModel, - // generationOptions, - // connectionOptions, - // resultsPath, - // filesOrgPathTS, - // dbDriver - // }; + // dbModel = modelCustomizationPhase( + // dbModel, + // generationOptions, + // driver.defaultValues + // ); + modelGenerationPhase(connectionOptions, generationOptions, dbModel); + const filesGenPath = path.resolve(resultsPath, "entities"); + compareGeneratedFiles(filesOrgPathTS, filesGenPath); + return { + dbModel, + generationOptions, + connectionOptions, + resultsPath, + filesOrgPathTS, + dbDriver + }; }); await Promise.all(modelGenerationPromises); compileGeneratedModel(path.resolve(process.cwd(), `output`), dbDrivers); @@ -164,24 +163,23 @@ async function runTest( filesOrgPathTS } = await prepareTestRuns(testPartialPath, dbDriver, dbDriver); let dbModel = await dataCollectionPhase(driver, connectionOptions); - throw new Error(); // TODO: Remove // dbModel = modelCustomizationPhase( // dbModel, // generationOptions, // driver.defaultValues // ); - // modelGenerationPhase(connectionOptions, generationOptions, dbModel); - // const filesGenPath = path.resolve(resultsPath, "entities"); - // compareGeneratedFiles(filesOrgPathTS, filesGenPath); - // return { - // dbModel, - // generationOptions, - // connectionOptions, - // resultsPath, - // filesOrgPathTS, - // dbDriver - // }; + modelGenerationPhase(connectionOptions, generationOptions, dbModel); + const filesGenPath = path.resolve(resultsPath, "entities"); + compareGeneratedFiles(filesOrgPathTS, filesGenPath); + return { + dbModel, + generationOptions, + connectionOptions, + resultsPath, + filesOrgPathTS, + dbDriver + }; }); await Promise.all(modelGenerationPromises); compileGeneratedModel(path.resolve(process.cwd(), `output`), dbDrivers); @@ -198,12 +196,12 @@ function compareGeneratedFiles(filesOrgPathTS: string, filesGenPath: string) { filesGen ); filesOrg.forEach(file => { - const jsonEntityOrg = EntityFileToJson.convert( - fs.readFileSync(path.resolve(filesOrgPathTS, file)) - ); const jsonEntityGen = EntityFileToJson.convert( fs.readFileSync(path.resolve(filesGenPath, file)) ); + const jsonEntityOrg = EntityFileToJson.convert( + fs.readFileSync(path.resolve(filesOrgPathTS, file)) + ); expect(jsonEntityGen, `Error in file ${file}`).to.containSubset( jsonEntityOrg ); diff --git a/test/utils/EntityFileToJson.ts b/test/utils/EntityFileToJson.ts index 981c10c..73d9f2b 100644 --- a/test/utils/EntityFileToJson.ts +++ b/test/utils/EntityFileToJson.ts @@ -92,9 +92,16 @@ export default class EntityFileToJson { /default: \(\) => (.*)/, `default: $1` ); - col.columnOptions = JSON.parse( - badJSON.replace(/(['"])?([a-z0-9A-Z_]+)(['"])?:/g, '"$2": ') - ); + try { + col.columnOptions = JSON.parse( + badJSON.replace( + /(['"])?([a-z0-9A-Z_]+)(['"])?:/g, + '"$2": ' + ) + ); + } catch (error) { + debugger; + } } else if ( decoratorParameters[0] === '"' && decoratorParameters.endsWith('"') @@ -241,6 +248,14 @@ export default class EntityFileToJson { } if (!isInClassBody) { if (trimmedLine.startsWith("import")) { + if ( + EntityFileToJson.isPartOfMultilineStatement(trimmedLine) + ) { + isMultilineStatement = true; + priorPartOfMultilineStatement = trimmedLine; + } else { + isMultilineStatement = false; + } return; } if (trimmedLine.startsWith("@Entity")) { From e86a26d279b5e99981fd971ae642bd5573bec9f3 Mon Sep 17 00:00:00 2001 From: Kononnable Date: Sun, 6 Oct 2019 16:21:12 +0200 Subject: [PATCH 08/84] more tests passing --- src/Engine.ts | 50 ++++++++------ src/drivers/AbstractDriver.ts | 67 +++++++++++++++---- src/drivers/MysqlDriver.ts | 1 + src/drivers/SqliteDriver.ts | 3 +- src/entity.mst | 14 ++-- src/models/Entity.ts | 1 + src/models/Relation.ts | 2 +- .../sample1-simple-entity/entity/Post.ts | 13 ++-- test/integration/runTestsFromPath.test.ts | 22 +++--- test/utils/EntityFileToJson.ts | 2 +- test/utils/GeneralTestUtils.ts | 4 +- 11 files changed, 118 insertions(+), 61 deletions(-) diff --git a/src/Engine.ts b/src/Engine.ts index dee0712..c256f2c 100644 --- a/src/Engine.ts +++ b/src/Engine.ts @@ -53,11 +53,11 @@ export async function createModelFromDatabase( ); return; } - // dbModel = modelCustomizationPhase( - // dbModel, - // generationOptions, - // driver.defaultValues - // ); + dbModel = modelCustomizationPhase( + dbModel, + generationOptions, + driver.defaultValues + ); // const dbModel: Entity = { // sqlName: "sqlName", // tscName: "typescriptName", @@ -128,7 +128,7 @@ export async function dataCollectionPhase( } export function modelCustomizationPhase( - dbModel: EntityInfo[], + dbModel: Entity[], generationOptions: IGenerationOptions, defaultValues: DataTypeDefaults ) { @@ -144,9 +144,10 @@ export function modelCustomizationPhase( namingStrategy = new NamingStrategy(); } let retVal = setRelationId(generationOptions, dbModel); - retVal = applyNamingStrategy(namingStrategy, retVal); - retVal = addImportsAndGenerationOptions(retVal, generationOptions); - retVal = removeColumnDefaultProperties(retVal, defaultValues); + // TODO: + // retVal = applyNamingStrategy(namingStrategy, retVal); + // retVal = addImportsAndGenerationOptions(retVal, generationOptions); + // retVal = removeColumnDefaultProperties(retVal, defaultValues); return retVal; } function removeColumnDefaultProperties( @@ -216,19 +217,17 @@ function addImportsAndGenerationOptions( return dbModel; } -function setRelationId( - generationOptions: IGenerationOptions, - model: EntityInfo[] -) { - if (generationOptions.relationIds) { - model.forEach(ent => { - ent.Columns.forEach(col => { - col.relations.forEach(rel => { - rel.relationIdField = rel.isOwner; - }); - }); - }); - } +function setRelationId(generationOptions: IGenerationOptions, model: Entity[]) { + // TODO: + // if (generationOptions.relationIds) { + // model.forEach(ent => { + // ent.columns.forEach(col => { + // col.relations.forEach(rel => { + // rel.relationIdField = rel.isOwner; + // }); + // }); + // }); + // } return model; } export function modelGenerationPhase( @@ -310,6 +309,13 @@ function createHandlebarsHelpers(generationOptions: IGenerationOptions) { Handlebars.registerHelper("concat", (stra, strb) => { return stra + strb; }); + Handlebars.registerHelper("toFileImports", (set: Set) => { + return [...set].reduce( + (pv, cv) => + `${pv}import { {{toEntityName ${cv}}} } from './{{toFileName ${cv}}};`, + "" + ); + }); Handlebars.registerHelper("toFileName", str => { let retStr = ""; switch (generationOptions.convertCaseFile) { diff --git a/src/drivers/AbstractDriver.ts b/src/drivers/AbstractDriver.ts index 3907077..273cc35 100644 --- a/src/drivers/AbstractDriver.ts +++ b/src/drivers/AbstractDriver.ts @@ -160,35 +160,49 @@ export default abstract class AbstractDriver { } public async GetDataFromServer( - connectionOptons: IConnectionOptions + connectionOptions: IConnectionOptions ): Promise { let dbModel = [] as Entity[]; - await this.ConnectToServer(connectionOptons); + await this.ConnectToServer(connectionOptions); const sqlEscapedSchema = AbstractDriver.escapeCommaSeparatedList( - connectionOptons.schemaName + connectionOptions.schemaName ); dbModel = await this.GetAllTables( sqlEscapedSchema, - connectionOptons.databaseName + connectionOptions.databaseName ); await this.GetCoulmnsFromEntity( dbModel, sqlEscapedSchema, - connectionOptons.databaseName + connectionOptions.databaseName ); await this.GetIndexesFromEntity( dbModel, sqlEscapedSchema, - connectionOptons.databaseName + connectionOptions.databaseName ); + AbstractDriver.FindPrimaryColumnsFromIndexes(dbModel); dbModel = await this.GetRelations( dbModel, sqlEscapedSchema, - connectionOptons.databaseName + connectionOptions.databaseName ); await this.DisconnectFromServer(); // dbModel = AbstractDriver.FindManyToManyRelations(dbModel); - AbstractDriver.FindPrimaryColumnsFromIndexes(dbModel); + dbModel = AbstractDriver.FindFileImports(dbModel); + return dbModel; + } + + private static FindFileImports(dbModel: Entity[]) { + dbModel.forEach(entity => { + entity.relations.forEach(relation => { + if ( + !entity.fileImports.some(v => v === relation.relatedTable) + ) { + entity.fileImports.push(relation.relatedTable); + } + }); + }); return dbModel; } @@ -208,7 +222,8 @@ export default abstract class AbstractDriver { sqlName: val.TABLE_NAME, tscName: val.TABLE_NAME, database: dbNames.includes(",") ? val.DB_NAME : "", - schema: val.TABLE_SCHEMA + schema: val.TABLE_SCHEMA, + fileImports: [] }); }); return ret; @@ -304,11 +319,35 @@ export default abstract class AbstractDriver { ); isOneToMany = !index; - const ownerRelation: Relation = { - fieldName: AbstractDriver.findNameForNewField( + if (true) { + // TODO: RelationId + ownerEntity.columns = ownerEntity.columns.filter( + v => + !relationTmp.ownerColumns.some( + u => u === v.tscName + ) || v.primary + ); + relationTmp.relatedTable.columns = relationTmp.relatedTable.columns.filter( + v => + !relationTmp.relatedColumns.some( + u => u === v.tscName + ) || v.primary + ); + } + let fieldName = ""; + if (relationTmp.ownerColumns.length === 1) { + fieldName = AbstractDriver.findNameForNewField( + ownerColumn.tscName, + ownerEntity + ); + } else { + fieldName = AbstractDriver.findNameForNewField( relationTmp.relatedTable.tscName, ownerEntity - ), + ); + } + const ownerRelation: Relation = { + fieldName, joinColumnOptions: relationTmp.ownerColumns.map( (v, idx) => { const retVal: JoinColumnOptions = { @@ -334,7 +373,7 @@ export default abstract class AbstractDriver { fieldName: ownerRelation.relatedField, relatedField: ownerRelation.fieldName, relatedTable: relationTmp.ownerTable.tscName, - relationOptions: ownerRelation.relationOptions, + // relationOptions: ownerRelation.relationOptions, relationType: isOneToMany ? "ManyToOne" : "OneToOne" }; @@ -350,7 +389,7 @@ export default abstract class AbstractDriver { const validNameCondition = entity.columns.every(v => v.tscName !== fieldName) && entity.relations.every(v => v.fieldName !== fieldName); - if (validNameCondition) { + if (!validNameCondition) { fieldName += "_"; for ( let i = 2; diff --git a/src/drivers/MysqlDriver.ts b/src/drivers/MysqlDriver.ts index b5d812b..8531daf 100644 --- a/src/drivers/MysqlDriver.ts +++ b/src/drivers/MysqlDriver.ts @@ -380,6 +380,7 @@ export default class MysqlDriver extends AbstractDriver { internal.ownerColumns.push(row.ForeignKeyColumn); internal.relatedColumns.push(row.ForeignKeyColumnReferenced); }); + relationsTemp.push(internal); }); const retVal = MysqlDriver.GetRelationsFromRelationTempInfo( diff --git a/src/drivers/SqliteDriver.ts b/src/drivers/SqliteDriver.ts index fac4571..7a84e5d 100644 --- a/src/drivers/SqliteDriver.ts +++ b/src/drivers/SqliteDriver.ts @@ -45,7 +45,8 @@ export default class SqliteDriver extends AbstractDriver { indices: [], relations: [], sqlName: val.tbl_name, - tscName: val.tbl_name + tscName: val.tbl_name, + fileImports: [] }); }); return ret; diff --git a/src/entity.mst b/src/entity.mst index 403f851..2ad37df 100644 --- a/src/entity.mst +++ b/src/entity.mst @@ -1,20 +1,25 @@ {{#*inline "Index"}} @Index("{{name}}",[{{#columns}}"{{.}}",{{/columns~}}],{ {{json options}} }) {{/inline}} +{{#*inline "Import"}} +import { {{toEntityName .}} } from './{{toFileName .}}' +{{/inline}} {{#*inline "Column"}} {{#generated}}@PrimaryGeneratedColumn({ type:"{{type}}", {{/generated}}{{^generated}}@Column("{{type}}",{ {{#primary}}primary:{{primary}},{{/primary}}{{/generated}}{{json options}}{{#default}},default: {{.}},{{/default}} }) -{{tscName}}:{{tscType}}; +{{toPropertyName tscName}}:{{tscType}}; {{/inline}} {{#*inline "Relation"}} -@{{relationType}}(()=>{{relatedTable}},{{relatedTable}}=>{{relatedTable}}.{{relatedField}},{ {{json relationOptions}} }) -{{fieldName}}:{{relatedTable}}; +@{{relationType}}(()=>{{toEntityName relatedTable}},{{toEntityName relatedTable}}=>{{toEntityName relatedTable}}.{{toPropertyName relatedField}}{{#if (or joinColumnOptions joinTableOptions)}},{ {{json relationOptions}} }{{/if}}) +{{#if joinColumnOptions}}@JoinColumn({{json joinColumnOptions}}){{/if}} +{{#if joinTableOptions}}@JoinTable{{json joinTableOptions}}){{/if}} +{{toPropertyName fieldName}}:{{toEntityName relatedTable}}; {{/inline}} {{#*inline "Entity"}} {{#indices}}{{> Index}}{{/indices~}} @Entity("{{sqlName}}",{schema:"{{schema}}",database:"{{database}}"}) -export class {{tscName}} { +export class {{toEntityName tscName}} { {{#columns}}{{> Column}}{{/columns~}} {{#relations}}{{> Relation}}{{/relations~}} @@ -22,6 +27,7 @@ export class {{tscName}} { {{/inline}} import {BaseEntity,Column,Entity,Index,JoinColumn,JoinTable,ManyToMany,ManyToOne,OneToMany,OneToOne,PrimaryColumn,PrimaryGeneratedColumn,RelationId} from "typeorm"; +{{#fileImports}}{{> Import}}{{/fileImports~}} {{~> Entity}} diff --git a/src/models/Entity.ts b/src/models/Entity.ts index 7a99347..9a2c566 100644 --- a/src/models/Entity.ts +++ b/src/models/Entity.ts @@ -12,4 +12,5 @@ export type Entity = { columns: Column[]; relations: Relation[]; indices: Index[]; + fileImports: string[]; }; diff --git a/src/models/Relation.ts b/src/models/Relation.ts index d3ef883..c8cb02f 100644 --- a/src/models/Relation.ts +++ b/src/models/Relation.ts @@ -6,7 +6,7 @@ export type Relation = { relatedTable: string; relatedField: string; fieldName: string; - relationOptions: RelationOptions; + relationOptions?: RelationOptions; joinColumnOptions?: JoinColumnOptions[]; joinTableOptions?: JoinTableMultipleColumnsOptions; }; diff --git a/test/integration/examples/sample1-simple-entity/entity/Post.ts b/test/integration/examples/sample1-simple-entity/entity/Post.ts index acc4bc1..3511066 100644 --- a/test/integration/examples/sample1-simple-entity/entity/Post.ts +++ b/test/integration/examples/sample1-simple-entity/entity/Post.ts @@ -1,8 +1,13 @@ -import { Column, Entity, PrimaryGeneratedColumn, Index, Generated } from "typeorm"; +import { + Column, + Entity, + PrimaryGeneratedColumn, + Index, + Generated +} from "typeorm"; @Entity("Post") export class Post { - @PrimaryGeneratedColumn() id: number; @@ -13,8 +18,8 @@ export class Post { text: string; @Column("int", { - nullable: false + // Columns are non-nullable by default + // nullable: false }) likesCount: number; - } diff --git a/test/integration/runTestsFromPath.test.ts b/test/integration/runTestsFromPath.test.ts index ab1a915..2b37def 100644 --- a/test/integration/runTestsFromPath.test.ts +++ b/test/integration/runTestsFromPath.test.ts @@ -106,12 +106,11 @@ function runTestForMultipleDrivers( ); break; } - // TODO: Remove - // dbModel = modelCustomizationPhase( - // dbModel, - // generationOptions, - // driver.defaultValues - // ); + dbModel = modelCustomizationPhase( + dbModel, + generationOptions, + driver.defaultValues + ); modelGenerationPhase(connectionOptions, generationOptions, dbModel); const filesGenPath = path.resolve(resultsPath, "entities"); compareGeneratedFiles(filesOrgPathTS, filesGenPath); @@ -163,12 +162,11 @@ async function runTest( filesOrgPathTS } = await prepareTestRuns(testPartialPath, dbDriver, dbDriver); let dbModel = await dataCollectionPhase(driver, connectionOptions); - // TODO: Remove - // dbModel = modelCustomizationPhase( - // dbModel, - // generationOptions, - // driver.defaultValues - // ); + dbModel = modelCustomizationPhase( + dbModel, + generationOptions, + driver.defaultValues + ); modelGenerationPhase(connectionOptions, generationOptions, dbModel); const filesGenPath = path.resolve(resultsPath, "entities"); compareGeneratedFiles(filesOrgPathTS, filesGenPath); diff --git a/test/utils/EntityFileToJson.ts b/test/utils/EntityFileToJson.ts index 73d9f2b..902e595 100644 --- a/test/utils/EntityFileToJson.ts +++ b/test/utils/EntityFileToJson.ts @@ -173,7 +173,7 @@ export default class EntityFileToJson { decoratorParameters.indexOf('"') + 1, decoratorParameters .substr(decoratorParameters.indexOf('"') + 1) - .indexOf('"') + .indexOf('"') + 1 ); } if (containsTables) { diff --git a/test/utils/GeneralTestUtils.ts b/test/utils/GeneralTestUtils.ts index 8c4af84..00b7e23 100644 --- a/test/utils/GeneralTestUtils.ts +++ b/test/utils/GeneralTestUtils.ts @@ -15,9 +15,9 @@ export function getGenerationOptions(resultsPath: string): IGenerationOptions { return { resultsPath, noConfigs: false, - convertCaseEntity: "none", + convertCaseEntity: "none", // TODO: Change to lib defaults convertCaseFile: "none", - convertCaseProperty: "none", + convertCaseProperty: "camel", propertyVisibility: "none", lazy: false, generateConstructor: false, From 099f4bcc9a80b26f657e6cde42631efc4c89e2d7 Mon Sep 17 00:00:00 2001 From: Kononnable Date: Mon, 7 Oct 2019 13:42:48 +0200 Subject: [PATCH 09/84] more tests passing --- src/AbstractNamingStrategy.ts | 16 ++-- src/Engine.ts | 164 +++++++++++++++------------------- src/NamingStrategy.ts | 26 +++--- src/drivers/AbstractDriver.ts | 20 ++--- src/entity.mst | 2 +- 5 files changed, 99 insertions(+), 129 deletions(-) diff --git a/src/AbstractNamingStrategy.ts b/src/AbstractNamingStrategy.ts index 4626962..007562d 100644 --- a/src/AbstractNamingStrategy.ts +++ b/src/AbstractNamingStrategy.ts @@ -1,15 +1,11 @@ -import RelationInfo from "./oldModels/RelationInfo"; -import EntityInfo from "./oldModels/EntityInfo"; -import ColumnInfo from "./oldModels/ColumnInfo"; +import { Relation } from "./models/Relation"; +import { Entity } from "./models/Entity"; +import { Column } from "./models/Column"; export default abstract class AbstractNamingStrategy { - public abstract relationName( - columnName: string, - relation: RelationInfo, - dbModel: EntityInfo[] - ): string; + public abstract relationName(relation: Relation, owner: Entity): string; - public abstract entityName(entityName: string, entity?: EntityInfo): string; + public abstract entityName(entityName: string, entity?: Entity): string; - public abstract columnName(columnName: string, column?: ColumnInfo): string; + public abstract columnName(columnName: string, column?: Column): string; } diff --git a/src/Engine.ts b/src/Engine.ts index c256f2c..e79e5d8 100644 --- a/src/Engine.ts +++ b/src/Engine.ts @@ -145,7 +145,7 @@ export function modelCustomizationPhase( } let retVal = setRelationId(generationOptions, dbModel); // TODO: - // retVal = applyNamingStrategy(namingStrategy, retVal); + retVal = applyNamingStrategy(namingStrategy, retVal); // retVal = addImportsAndGenerationOptions(retVal, generationOptions); // retVal = removeColumnDefaultProperties(retVal, defaultValues); return retVal; @@ -306,9 +306,18 @@ function createHandlebarsHelpers(generationOptions: IGenerationOptions) { } return retStr; }); - Handlebars.registerHelper("concat", (stra, strb) => { + Handlebars.registerHelper("concat", (stra: string, strb: string) => { return stra + strb; }); + Handlebars.registerHelper("contains", function contains( + searchTerm: string, + target: string, + options + ) { + return target.indexOf(searchTerm) > -1 + ? options.fn(this) + : options.inverse(this); + }); Handlebars.registerHelper("toFileImports", (set: Set) => { return [...set].reduce( (pv, cv) => @@ -448,124 +457,93 @@ function createTypeOrmConfig( } function applyNamingStrategy( namingStrategy: AbstractNamingStrategy, - dbModel: EntityInfo[] + dbModel: Entity[] ) { let retval = changeRelationNames(dbModel); retval = changeEntityNames(retval); retval = changeColumnNames(retval); return retval; - function changeRelationNames(model: EntityInfo[]) { + function changeRelationNames(model: Entity[]) { model.forEach(entity => { - entity.Columns.forEach(column => { - column.relations.forEach(relation => { - const newName = namingStrategy.relationName( - column.tsName, - relation, - model - ); - model.forEach(entity2 => { - entity2.Columns.forEach(column2 => { - column2.relations.forEach(relation2 => { - if ( - relation2.relatedTable === - entity.tsEntityName && - relation2.ownerColumn === column.tsName - ) { - relation2.ownerColumn = newName; - } - if ( - relation2.relatedTable === - entity.tsEntityName && - 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; - }); - }); - } - }); - }); + entity.relations.forEach(relation => { + const oldName = relation.fieldName; + const newName = namingStrategy.relationName(relation, entity); + + const relatedEntity = model.find( + v => v.tscName === relation.relatedTable + )!; + const relation2 = relatedEntity.relations.find( + v => v.fieldName === relation.relatedField + )!; + + relation.fieldName = newName; + relation2.relatedField = newName; + + if (relation.relationOptions) { + entity.indices.forEach(ind => { + ind.columns.map(column2 => + column2 === oldName ? newName : column2 + ); }); - column.tsName = newName; - }); + } }); }); return dbModel; } - function changeColumnNames(model: EntityInfo[]) { + function changeColumnNames(model: Entity[]) { model.forEach(entity => { - entity.Columns.forEach(column => { + entity.columns.forEach(column => { const newName = namingStrategy.columnName( - column.tsName, + column.tscName, column ); - entity.Indexes.forEach(index => { - index.columns - .filter(column2 => column2.name === column.tsName) - .forEach(column2 => { - column2.name = newName; - }); - }); - model.forEach(entity2 => { - entity2.Columns.forEach(column2 => { - column2.relations - .filter( - relation => - relation.relatedTable === - entity.tsEntityName && - relation.relatedColumn === column.tsName - ) - .forEach(v => { - v.relatedColumn = newName; - }); - column2.relations - .filter( - relation => - relation.relatedTable === - entity.tsEntityName && - relation.ownerColumn === column.tsName - ) - .forEach(v => { - v.ownerColumn = newName; - }); - }); + entity.indices.forEach(index => { + index.columns.map(column2 => + column2 === column.tscName ? newName : column2 + ); }); + // TODO: Should relational columns be changed by both changeRelationNames and changeColumnNames? + // model.forEach(entity2 => { + // entity2.columns.forEach(column2 => { + // column2.relations + // .filter( + // relation => + // relation.relatedTable === entity.tscName && + // relation.relatedColumn === column.tscName + // ) + // .forEach(v => { + // v.relatedColumn = newName; + // }); + // column2.relations + // .filter( + // relation => + // relation.relatedTable === entity.tscName && + // relation.ownerColumn === column.tscName + // ) + // .forEach(v => { + // v.ownerColumn = newName; + // }); + // }); + // }); - column.tsName = newName; + column.tscName = newName; }); }); return model; } - function changeEntityNames(entities: EntityInfo[]) { + function changeEntityNames(entities: Entity[]) { entities.forEach(entity => { - const newName = namingStrategy.entityName( - entity.tsEntityName, - entity - ); + const newName = namingStrategy.entityName(entity.tscName, entity); entities.forEach(entity2 => { - entity2.Columns.forEach(column => { - column.relations.forEach(relation => { - if (relation.ownerTable === entity.tsEntityName) { - relation.ownerTable = newName; - } - if (relation.relatedTable === entity.tsEntityName) { - relation.relatedTable = newName; - } - }); + entity2.relations.forEach(relation => { + if (relation.relatedTable === entity.tscName) { + relation.relatedTable = newName; + } }); }); - entity.tsEntityName = newName; + entity.tscName = newName; }); return entities; } diff --git a/src/NamingStrategy.ts b/src/NamingStrategy.ts index 9b3593a..ae089cb 100644 --- a/src/NamingStrategy.ts +++ b/src/NamingStrategy.ts @@ -1,20 +1,16 @@ import AbstractNamingStrategy from "./AbstractNamingStrategy"; -import RelationInfo from "./oldModels/RelationInfo"; -import EntityInfo from "./oldModels/EntityInfo"; +import { Relation } from "./models/Relation"; +import { Entity } from "./models/Entity"; import changeCase = require("change-case"); /* eslint-disable class-methods-use-this */ export default class NamingStrategy extends AbstractNamingStrategy { - public relationName( - columnOldName: string, - relation: RelationInfo, - dbModel: EntityInfo[] - ): string { - const isRelationToMany = relation.isOneToMany || relation.isManyToMany; - const ownerEntity = dbModel.find( - v => v.tsEntityName === relation.ownerTable - )!; + public relationName(relation: Relation, owner: Entity): string { + const columnOldName = relation.fieldName; + const isRelationToMany = + relation.relationType === "OneToMany" || + relation.relationType === "ManyToMany"; let columnName = changeCase.camelCase(columnOldName); if ( @@ -38,18 +34,18 @@ export default class NamingStrategy extends AbstractNamingStrategy { relation.relationType !== "ManyToMany" && columnOldName !== columnName ) { - if (ownerEntity.Columns.some(v => v.tsName === columnName)) { + if (owner.columns.some(v => v.tscName === columnName)) { columnName += "_"; - for (let i = 2; i <= ownerEntity.Columns.length; i++) { + for (let i = 2; i <= owner.columns.length; i++) { columnName = columnName.substring( 0, columnName.length - i.toString().length ) + i.toString(); if ( - ownerEntity.Columns.every( + owner.columns.every( v => - v.tsName !== columnName || + v.tscName !== columnName || columnName === columnOldName ) ) { diff --git a/src/drivers/AbstractDriver.ts b/src/drivers/AbstractDriver.ts index 273cc35..5db904d 100644 --- a/src/drivers/AbstractDriver.ts +++ b/src/drivers/AbstractDriver.ts @@ -348,6 +348,14 @@ export default abstract class AbstractDriver { } const ownerRelation: Relation = { fieldName, + relatedField: AbstractDriver.findNameForNewField( + relationTmp.ownerTable.tscName, + relationTmp.relatedTable + ), + relationOptions: { + onDelete: relationTmp.onDelete, + onUpdate: relationTmp.onUpdate + }, joinColumnOptions: relationTmp.ownerColumns.map( (v, idx) => { const retVal: JoinColumnOptions = { @@ -358,23 +366,15 @@ export default abstract class AbstractDriver { return retVal; } ), - relatedField: AbstractDriver.findNameForNewField( - relationTmp.ownerTable.tscName, - relationTmp.relatedTable - ), relatedTable: relationTmp.relatedTable.tscName, - relationOptions: { - onDelete: relationTmp.onDelete, - onUpdate: relationTmp.onUpdate - }, - relationType: isOneToMany ? "OneToMany" : "OneToOne" + relationType: isOneToMany ? "ManyToOne" : "OneToOne" }; const relatedRelation: Relation = { fieldName: ownerRelation.relatedField, relatedField: ownerRelation.fieldName, relatedTable: relationTmp.ownerTable.tscName, // relationOptions: ownerRelation.relationOptions, - relationType: isOneToMany ? "ManyToOne" : "OneToOne" + relationType: isOneToMany ? "OneToMany" : "OneToOne" }; ownerEntity.relations.push(ownerRelation); diff --git a/src/entity.mst b/src/entity.mst index 2ad37df..4002e9b 100644 --- a/src/entity.mst +++ b/src/entity.mst @@ -13,7 +13,7 @@ import { {{toEntityName .}} } from './{{toFileName .}}' @{{relationType}}(()=>{{toEntityName relatedTable}},{{toEntityName relatedTable}}=>{{toEntityName relatedTable}}.{{toPropertyName relatedField}}{{#if (or joinColumnOptions joinTableOptions)}},{ {{json relationOptions}} }{{/if}}) {{#if joinColumnOptions}}@JoinColumn({{json joinColumnOptions}}){{/if}} {{#if joinTableOptions}}@JoinTable{{json joinTableOptions}}){{/if}} -{{toPropertyName fieldName}}:{{toEntityName relatedTable}}; +{{toPropertyName fieldName}}:{{toEntityName relatedTable}}{{#contains "ToMany" relationType}}[]{{/contains}}; {{/inline}} {{#*inline "Entity"}} From 577266a03bf231bbd0cfe969a345e35450643bd5 Mon Sep 17 00:00:00 2001 From: Kononnable Date: Mon, 7 Oct 2019 13:51:39 +0200 Subject: [PATCH 10/84] removed unnecessary nullable:false - default behavior --- .../github-issues/135/entity/Post.ts | 24 +++++-- .../github-issues/135/entity/PostAuthor.ts | 32 +++++---- .../github-issues/135/entity/PostCategory.ts | 32 +++++---- .../github-issues/39/entity/Post.ts | 48 +++++++------- .../github-issues/39/entity/User.ts | 1 - .../github-issues/57/entity/Post.ts | 31 +++++---- .../github-issues/58/entity/feedextrainfo.ts | 65 ++++++++++--------- .../github-issues/58/entity/quests.ts | 35 +++++----- .../github-issues/58/entity/users.ts | 41 ++++++------ .../github-issues/65/entity/Post.ts | 29 +++++---- .../github-issues/65/entity/PostAuthor.ts | 31 +++++---- .../github-issues/65/entity/PostReader.ts | 29 ++++++--- .../github-issues/71/entity/PostAuthor.ts | 36 +++++----- .../github-issues/71/entity/PostCategory.ts | 41 +++++++----- .../github-issues/71/entity/PostDetails.ts | 39 ++++++----- .../github-issues/71/entity/PostReader.ts | 30 +++++---- 16 files changed, 317 insertions(+), 227 deletions(-) diff --git a/test/integration/github-issues/135/entity/Post.ts b/test/integration/github-issues/135/entity/Post.ts index cdce663..16e94c3 100644 --- a/test/integration/github-issues/135/entity/Post.ts +++ b/test/integration/github-issues/135/entity/Post.ts @@ -1,14 +1,26 @@ -import { Index, Entity, PrimaryColumn, Column, OneToOne, OneToMany, ManyToOne, ManyToMany, JoinColumn, JoinTable } from "typeorm"; +import { + Index, + Entity, + PrimaryColumn, + Column, + OneToOne, + OneToMany, + ManyToOne, + ManyToMany, + JoinColumn, + JoinTable +} from "typeorm"; import { PostAuthor } from "./PostAuthor"; import { PostCategory } from "./PostCategory"; - -@Index("travel_travelplanextra_travel_plan_id_extra_id_f825ca51_uniq",["postAuthor","postCategory",],{unique:true}) +@Index( + "travel_travelplanextra_travel_plan_id_extra_id_f825ca51_uniq", + ["postAuthor", "postCategory"], + { unique: true } +) @Entity("Post") export class Post { - @Column("int", { - nullable: false, primary: true, name: "Id" }) @@ -18,9 +30,7 @@ export class Post { @JoinColumn() postAuthor: PostAuthor; - @ManyToOne(type => PostCategory, PostCategory => PostCategory.Id) @JoinColumn() postCategory: PostCategory; - } diff --git a/test/integration/github-issues/135/entity/PostAuthor.ts b/test/integration/github-issues/135/entity/PostAuthor.ts index db8ca99..5b8998f 100644 --- a/test/integration/github-issues/135/entity/PostAuthor.ts +++ b/test/integration/github-issues/135/entity/PostAuthor.ts @@ -1,20 +1,26 @@ -import {Index,Entity, PrimaryColumn, Column, OneToOne, OneToMany, ManyToOne, ManyToMany, JoinColumn, JoinTable, RelationId} from "typeorm"; +import { + Index, + Entity, + PrimaryColumn, + Column, + OneToOne, + OneToMany, + ManyToOne, + ManyToMany, + JoinColumn, + JoinTable, + RelationId +} from "typeorm"; import { Post } from "./Post"; - @Entity("PostAuthor") export class PostAuthor { - - @Column("int",{ - nullable:false, - primary:true, - name:"Id" - }) - Id:number; - - + @Column("int", { + primary: true, + name: "Id" + }) + Id: number; @OneToMany(type => Post, Post => Post.Id) - posts:Post[]; - + posts: Post[]; } diff --git a/test/integration/github-issues/135/entity/PostCategory.ts b/test/integration/github-issues/135/entity/PostCategory.ts index 5804e3f..7d61e7e 100644 --- a/test/integration/github-issues/135/entity/PostCategory.ts +++ b/test/integration/github-issues/135/entity/PostCategory.ts @@ -1,20 +1,26 @@ -import {Index,Entity, PrimaryColumn, Column, OneToOne, OneToMany, ManyToOne, ManyToMany, JoinColumn, JoinTable, RelationId} from "typeorm"; +import { + Index, + Entity, + PrimaryColumn, + Column, + OneToOne, + OneToMany, + ManyToOne, + ManyToMany, + JoinColumn, + JoinTable, + RelationId +} from "typeorm"; import { Post } from "./Post"; - @Entity("PostCategory") export class PostCategory { - - @Column("int",{ - nullable:false, - primary:true, - name:"Id" - }) - Id:number; - - + @Column("int", { + primary: true, + name: "Id" + }) + Id: number; @OneToMany(type => Post, Post => Post.Id) - posts:Post[]; - + posts: Post[]; } diff --git a/test/integration/github-issues/39/entity/Post.ts b/test/integration/github-issues/39/entity/Post.ts index 378587a..f5ad32b 100644 --- a/test/integration/github-issues/39/entity/Post.ts +++ b/test/integration/github-issues/39/entity/Post.ts @@ -1,28 +1,30 @@ -import {Index,Entity, PrimaryColumn, Column, OneToOne, OneToMany, ManyToOne, JoinColumn} from "typeorm"; -import {User} from "./User"; +import { + Index, + Entity, + PrimaryColumn, + Column, + OneToOne, + OneToMany, + ManyToOne, + JoinColumn +} from "typeorm"; +import { User } from "./User"; - -@Entity("Post",{schema:"sch1"}) +@Entity("Post", { schema: "sch1" }) export class Post { + @Column("integer", { + primary: true, + name: "id" + }) + id: number; - @Column("integer",{ - nullable:false, - primary:true, - name:"id" - }) - id:number; - - - - @ManyToOne(type=>User, userId=>userId.posts) - @JoinColumn({ name:"userId"}) - userId:User; - - - @Column("text",{ - nullable:true, - name:"body" - }) - body:string; + @ManyToOne(type => User, userId => userId.posts) + @JoinColumn({ name: "userId" }) + userId: User; + @Column("text", { + nullable: true, + name: "body" + }) + body: string; } diff --git a/test/integration/github-issues/39/entity/User.ts b/test/integration/github-issues/39/entity/User.ts index a709565..6736995 100644 --- a/test/integration/github-issues/39/entity/User.ts +++ b/test/integration/github-issues/39/entity/User.ts @@ -6,7 +6,6 @@ import {Post} from "./Post"; export class User { @Column("integer",{ - nullable:false, primary:true, name:"id" }) diff --git a/test/integration/github-issues/57/entity/Post.ts b/test/integration/github-issues/57/entity/Post.ts index b7fdf4e..69eee28 100644 --- a/test/integration/github-issues/57/entity/Post.ts +++ b/test/integration/github-issues/57/entity/Post.ts @@ -1,20 +1,25 @@ -import {Index,Entity, PrimaryColumn, Column, OneToOne, OneToMany, ManyToOne, JoinColumn} from "typeorm"; - +import { + Index, + Entity, + PrimaryColumn, + Column, + OneToOne, + OneToMany, + ManyToOne, + JoinColumn +} from "typeorm"; @Entity("Post") export class Post { + @Column("integer", { + primary: true, + name: "id" + }) + id: number; - @Column("integer",{ - nullable:false, - primary:true, - name:"id" - }) - id:number; + @Column({ unique: true }) + body: string; - @Column({unique:true}) - body:string; - @Column() - body2:string; - + body2: string; } diff --git a/test/integration/github-issues/58/entity/feedextrainfo.ts b/test/integration/github-issues/58/entity/feedextrainfo.ts index 2721cb9..02f141c 100644 --- a/test/integration/github-issues/58/entity/feedextrainfo.ts +++ b/test/integration/github-issues/58/entity/feedextrainfo.ts @@ -1,36 +1,43 @@ -import {Index,Entity, PrimaryColumn, Column, OneToOne, OneToMany, ManyToOne, ManyToMany, JoinColumn, JoinTable} from "typeorm"; -import {users} from "./users"; -import {quests} from "./quests"; - +import { + Index, + Entity, + PrimaryColumn, + Column, + OneToOne, + OneToMany, + ManyToOne, + ManyToMany, + JoinColumn, + JoinTable +} from "typeorm"; +import { users } from "./users"; +import { quests } from "./quests"; @Entity("feedextrainfo") -@Index("feedExtraInfo_FeedOwnerId_idx",["feedOwnerId",],{unique:true}) -@Index("feedExtraInfo_ReaderId_idx",["readerId",],{unique:true}) -@Index("feedExtraInfo_QuestId_idx",["questId",],{unique:true}) +@Index("feedExtraInfo_FeedOwnerId_idx", ["feedOwnerId"], { unique: true }) +@Index("feedExtraInfo_ReaderId_idx", ["readerId"], { unique: true }) +@Index("feedExtraInfo_QuestId_idx", ["questId"], { unique: true }) export class feedextrainfo { + @OneToOne(type => users, FeedOwnerId => FeedOwnerId.feedextrainfo, { + primary: true + }) + @JoinColumn({ name: "FeedOwnerId" }) + feedOwnerId: users; + @OneToOne(type => quests, QuestId => QuestId.feedextrainfo, { + primary: true + }) + @JoinColumn({ name: "QuestId" }) + questId: quests; - @OneToOne(type=>users, FeedOwnerId=>FeedOwnerId.feedextrainfo,{primary:true, nullable:false, }) - @JoinColumn({ name:'FeedOwnerId'}) - feedOwnerId:users; - - - - @OneToOne(type=>quests, QuestId=>QuestId.feedextrainfo,{primary:true, nullable:false, }) - @JoinColumn({ name:'QuestId'}) - questId:quests; - - - - @OneToOne(type=>users, ReaderId=>ReaderId.feedextrainfo2,{primary:true, nullable:false, }) - @JoinColumn({ name:'ReaderId'}) - readerId:users; - - - @Column("int",{ - nullable:false, - name:"MostUpdatedFeedEntryIdUserRead" - }) - MostUpdatedFeedEntryIdUserRead:number; + @OneToOne(type => users, ReaderId => ReaderId.feedextrainfo2, { + primary: true + }) + @JoinColumn({ name: "ReaderId" }) + readerId: users; + @Column("int", { + name: "MostUpdatedFeedEntryIdUserRead" + }) + MostUpdatedFeedEntryIdUserRead: number; } diff --git a/test/integration/github-issues/58/entity/quests.ts b/test/integration/github-issues/58/entity/quests.ts index acdc56d..6c8e0bc 100644 --- a/test/integration/github-issues/58/entity/quests.ts +++ b/test/integration/github-issues/58/entity/quests.ts @@ -1,20 +1,25 @@ -import {Index,Entity, PrimaryColumn, Column, OneToOne, OneToMany, ManyToOne, ManyToMany, JoinColumn, JoinTable} from "typeorm"; -import {feedextrainfo} from "./feedextrainfo"; - +import { + Index, + Entity, + PrimaryColumn, + Column, + OneToOne, + OneToMany, + ManyToOne, + ManyToMany, + JoinColumn, + JoinTable +} from "typeorm"; +import { feedextrainfo } from "./feedextrainfo"; @Entity("quests") export class quests { + @Column("int", { + primary: true, + name: "QuestId" + }) + QuestId: number; - @Column("int",{ - nullable:false, - primary:true, - name:"QuestId" - }) - QuestId:number; - - - - @OneToOne(type=>feedextrainfo, feedextrainfo=>feedextrainfo.questId) - feedextrainfo:feedextrainfo; - + @OneToOne(type => feedextrainfo, feedextrainfo => feedextrainfo.questId) + feedextrainfo: feedextrainfo; } diff --git a/test/integration/github-issues/58/entity/users.ts b/test/integration/github-issues/58/entity/users.ts index 754e1e1..fe57631 100644 --- a/test/integration/github-issues/58/entity/users.ts +++ b/test/integration/github-issues/58/entity/users.ts @@ -1,25 +1,28 @@ -import {Index,Entity, PrimaryColumn, Column, OneToOne, OneToMany, ManyToOne, ManyToMany, JoinColumn, JoinTable} from "typeorm"; -import {feedextrainfo} from "./feedextrainfo"; - +import { + Index, + Entity, + PrimaryColumn, + Column, + OneToOne, + OneToMany, + ManyToOne, + ManyToMany, + JoinColumn, + JoinTable +} from "typeorm"; +import { feedextrainfo } from "./feedextrainfo"; @Entity("users") export class users { + @Column("int", { + primary: true, + name: "UserId" + }) + UserId: number; - @Column("int",{ - nullable:false, - primary:true, - name:"UserId" - }) - UserId:number; - - - - @OneToOne(type=>feedextrainfo, feedextrainfo=>feedextrainfo.feedOwnerId) - feedextrainfo:feedextrainfo; - - - - @OneToOne(type=>feedextrainfo, feedextrainfo2=>feedextrainfo2.readerId) - feedextrainfo2:feedextrainfo; + @OneToOne(type => feedextrainfo, feedextrainfo => feedextrainfo.feedOwnerId) + feedextrainfo: feedextrainfo; + @OneToOne(type => feedextrainfo, feedextrainfo2 => feedextrainfo2.readerId) + feedextrainfo2: feedextrainfo; } diff --git a/test/integration/github-issues/65/entity/Post.ts b/test/integration/github-issues/65/entity/Post.ts index abe57e9..2596c9e 100644 --- a/test/integration/github-issues/65/entity/Post.ts +++ b/test/integration/github-issues/65/entity/Post.ts @@ -1,24 +1,29 @@ -import {Index,Entity, PrimaryColumn, Column, OneToOne, OneToMany, ManyToOne, ManyToMany, JoinColumn, JoinTable} from "typeorm"; +import { + Index, + Entity, + PrimaryColumn, + Column, + OneToOne, + OneToMany, + ManyToOne, + ManyToMany, + JoinColumn, + JoinTable +} from "typeorm"; import { PostAuthor } from "./PostAuthor"; import { PostReader } from "./PostReader"; - @Entity("Post") export class Post { - - @Column("int",{ - nullable:false, - primary:true, - name:"Id" - }) - Id:number; - - + @Column("int", { + primary: true, + name: "Id" + }) + Id: number; @OneToOne(type => PostAuthor, PostAuthor => PostAuthor.Id) postAuthor: PostAuthor; @OneToMany(type => PostReader, PostReader => PostReader.Id) postReaders: PostReader[]; - } diff --git a/test/integration/github-issues/65/entity/PostAuthor.ts b/test/integration/github-issues/65/entity/PostAuthor.ts index 8ff3809..ab27fd7 100644 --- a/test/integration/github-issues/65/entity/PostAuthor.ts +++ b/test/integration/github-issues/65/entity/PostAuthor.ts @@ -1,22 +1,29 @@ -import {Index,Entity, PrimaryColumn, Column, OneToOne, OneToMany, ManyToOne, ManyToMany, JoinColumn, JoinTable, RelationId} from "typeorm"; +import { + Index, + Entity, + PrimaryColumn, + Column, + OneToOne, + OneToMany, + ManyToOne, + ManyToMany, + JoinColumn, + JoinTable, + RelationId +} from "typeorm"; import { Post } from "./Post"; - @Entity("PostAuthor") export class PostAuthor { - - @Column("int",{ - nullable:false, - primary:true, - name:"Id" - }) - Id:number; - - + @Column("int", { + primary: true, + name: "Id" + }) + Id: number; @OneToOne(type => Post, Post => Post.Id) @JoinColumn() - post:Post; + post: Post; @RelationId((postAuthor: PostAuthor) => postAuthor.post) postId: number; diff --git a/test/integration/github-issues/65/entity/PostReader.ts b/test/integration/github-issues/65/entity/PostReader.ts index 1fcc60e..864a73b 100644 --- a/test/integration/github-issues/65/entity/PostReader.ts +++ b/test/integration/github-issues/65/entity/PostReader.ts @@ -1,20 +1,29 @@ -import {Index,Entity, PrimaryColumn, Column, OneToOne, OneToMany, ManyToOne, ManyToMany, JoinColumn, JoinTable, RelationId} from "typeorm"; +import { + Index, + Entity, + PrimaryColumn, + Column, + OneToOne, + OneToMany, + ManyToOne, + ManyToMany, + JoinColumn, + JoinTable, + RelationId +} from "typeorm"; import { Post } from "./Post"; - @Entity("PostReader") export class PostReader { - - @Column("int",{ - nullable:false, - primary:true, - name:"Id" - }) - Id:number; + @Column("int", { + primary: true, + name: "Id" + }) + Id: number; @ManyToOne(type => Post, Post => Post.Id) @JoinColumn() - post:Post; + post: Post; @RelationId((postReader: PostReader) => postReader.post) postId: number[]; diff --git a/test/integration/github-issues/71/entity/PostAuthor.ts b/test/integration/github-issues/71/entity/PostAuthor.ts index 70fcfc7..18a2431 100644 --- a/test/integration/github-issues/71/entity/PostAuthor.ts +++ b/test/integration/github-issues/71/entity/PostAuthor.ts @@ -1,24 +1,30 @@ -import {Index,Entity, PrimaryColumn, Column, OneToOne, OneToMany, ManyToOne, ManyToMany, JoinColumn, JoinTable, RelationId} from "typeorm"; +import { + Index, + Entity, + PrimaryColumn, + Column, + OneToOne, + OneToMany, + ManyToOne, + ManyToMany, + JoinColumn, + JoinTable, + RelationId +} from "typeorm"; import { Post } from "./Post"; - @Entity("PostAuthor") export class PostAuthor { + @Column("int", { + primary: true, + name: "Id" + }) + Id: number; - @Column("int",{ - nullable:false, - primary:true, - name:"Id" - }) - Id:number; - - - - @OneToOne(type => Post, Post => Post.Id,{ - onDelete: "CASCADE", + @OneToOne(type => Post, Post => Post.Id, { + onDelete: "CASCADE" // onUpdate: "CASCADE" }) @JoinColumn() - post:Post; - + post: Post; } diff --git a/test/integration/github-issues/71/entity/PostCategory.ts b/test/integration/github-issues/71/entity/PostCategory.ts index 688d343..25f36fb 100644 --- a/test/integration/github-issues/71/entity/PostCategory.ts +++ b/test/integration/github-issues/71/entity/PostCategory.ts @@ -1,25 +1,30 @@ -import {Index,Entity, PrimaryColumn, Column, OneToOne, OneToMany, ManyToOne, ManyToMany, JoinColumn, JoinTable, RelationId} from "typeorm"; +import { + Index, + Entity, + PrimaryColumn, + Column, + OneToOne, + OneToMany, + ManyToOne, + ManyToMany, + JoinColumn, + JoinTable, + RelationId +} from "typeorm"; import { Post } from "./Post"; - @Entity("PostCategory") export class PostCategory { + @Column("int", { + primary: true, + name: "Id" + }) + Id: number; - @Column("int",{ - nullable:false, - primary:true, - name:"Id" - }) - Id:number; - - - - @OneToOne(type => Post, Post => Post.Id, - { - // onDelete: "RESTRICT", - // onUpdate: "RESTRICT" - }) + @OneToOne(type => Post, Post => Post.Id, { + // onDelete: "RESTRICT", + // onUpdate: "RESTRICT" + }) @JoinColumn() - post:Post; - + post: Post; } diff --git a/test/integration/github-issues/71/entity/PostDetails.ts b/test/integration/github-issues/71/entity/PostDetails.ts index 7935433..dc9d754 100644 --- a/test/integration/github-issues/71/entity/PostDetails.ts +++ b/test/integration/github-issues/71/entity/PostDetails.ts @@ -1,23 +1,30 @@ -import {Index,Entity, PrimaryColumn, Column, OneToOne, OneToMany, ManyToOne, ManyToMany, JoinColumn, JoinTable, RelationId} from "typeorm"; +import { + Index, + Entity, + PrimaryColumn, + Column, + OneToOne, + OneToMany, + ManyToOne, + ManyToMany, + JoinColumn, + JoinTable, + RelationId +} from "typeorm"; import { Post } from "./Post"; - @Entity("PostDetails") export class PostDetails { + @Column("int", { + primary: true, + name: "Id" + }) + Id: number; - @Column("int",{ - nullable:false, - primary:true, - name:"Id" - }) - Id:number; - - @OneToOne(type => Post, Post => Post.Id, - { - onDelete: "SET NULL", - // onUpdate: "SET NULL" - }) + @OneToOne(type => Post, Post => Post.Id, { + onDelete: "SET NULL" + // onUpdate: "SET NULL" + }) @JoinColumn() - post:Post; - + post: Post; } diff --git a/test/integration/github-issues/71/entity/PostReader.ts b/test/integration/github-issues/71/entity/PostReader.ts index 9e91689..ef232be 100644 --- a/test/integration/github-issues/71/entity/PostReader.ts +++ b/test/integration/github-issues/71/entity/PostReader.ts @@ -1,19 +1,27 @@ -import {Index,Entity, PrimaryColumn, Column, OneToOne, OneToMany, ManyToOne, ManyToMany, JoinColumn, JoinTable, RelationId} from "typeorm"; +import { + Index, + Entity, + PrimaryColumn, + Column, + OneToOne, + OneToMany, + ManyToOne, + ManyToMany, + JoinColumn, + JoinTable, + RelationId +} from "typeorm"; import { Post } from "./Post"; - @Entity("PostReader") export class PostReader { - - @Column("int",{ - nullable:false, - primary:true, - name:"Id" - }) - Id:number; + @Column("int", { + primary: true, + name: "Id" + }) + Id: number; @OneToOne(type => Post, Post => Post.Id) @JoinColumn() - post:Post; - + post: Post; } From 4f45dc996157caf3aff0abf6a75a3d3c43b17ceb Mon Sep 17 00:00:00 2001 From: Kononnable Date: Mon, 7 Oct 2019 18:59:03 +0200 Subject: [PATCH 11/84] more tests passing --- src/drivers/AbstractDriver.ts | 161 +++++++++++++++++---------------- src/entity.mst | 4 +- test/utils/EntityFileToJson.ts | 4 +- 3 files changed, 86 insertions(+), 83 deletions(-) diff --git a/src/drivers/AbstractDriver.ts b/src/drivers/AbstractDriver.ts index 5db904d..bfeba3d 100644 --- a/src/drivers/AbstractDriver.ts +++ b/src/drivers/AbstractDriver.ts @@ -79,84 +79,86 @@ export default abstract class AbstractDriver { }[] >; - public static FindManyToManyRelations(dbModel: EntityInfo[]) { - let retval = dbModel; - const manyToManyEntities = retval.filter( + public static FindManyToManyRelations(dbModel: Entity[]) { + let retVal = dbModel; + const manyToManyEntities = retVal.filter( entity => - entity.Columns.filter(column => { - return ( - column.relations.length === 1 && - !column.relations[0].isOneToMany && - column.relations[0].isOwner - ); - }).length === entity.Columns.length + entity.columns.length === + entity.columns.filter(c => c.primary).length && + entity.relations.length === 2 && + entity.relations.every( + v => v.relationOptions && v.relationType !== "ManyToMany" + ) ); - manyToManyEntities.forEach(entity => { - let relations: RelationInfo[] = []; - relations = entity.Columns.reduce( - (prev: RelationInfo[], curr) => prev.concat(curr.relations), - relations + manyToManyEntities.forEach(junctionEntity => { + const firstEntity = dbModel.find( + v => v.tscName === junctionEntity.relations[0].relatedTable + )!; + const secondEntity = dbModel.find( + v => v.tscName === junctionEntity.relations[1].relatedTable + )!; + + const firstRelation = firstEntity.relations.find( + v => v.relatedTable === junctionEntity.tscName + )!; + const secondRelation = secondEntity.relations.find( + v => v.relatedTable === junctionEntity.tscName + )!; + + firstRelation.relationType = "ManyToMany"; + secondRelation.relationType = "ManyToMany"; + firstRelation.relatedTable = secondEntity.tscName; + secondRelation.relatedTable = firstEntity.tscName; + + firstRelation.fieldName = this.findNameForNewField( + secondEntity.tscName, + firstEntity ); - const namesOfRelatedTables = relations - .map(v => v.relatedTable) - .filter((v, i, s) => s.indexOf(v) === i); - const [ - firstRelatedTable, - secondRelatedTable - ] = namesOfRelatedTables; + secondRelation.fieldName = this.findNameForNewField( + firstEntity.tscName, + secondEntity + ); + firstRelation.relatedField = secondRelation.fieldName; + secondRelation.relatedField = firstRelation.fieldName; - if (namesOfRelatedTables.length === 2) { - const relatedTable1 = retval.find( - v => v.tsEntityName === firstRelatedTable - )!; - relatedTable1.Columns = relatedTable1.Columns.filter( - v => - !v.tsName - .toLowerCase() - .startsWith(entity.tsEntityName.toLowerCase()) - ); - const relatedTable2 = retval.find( - v => v.tsEntityName === namesOfRelatedTables[1] - )!; - relatedTable2.Columns = relatedTable2.Columns.filter( - v => - !v.tsName - .toLowerCase() - .startsWith(entity.tsEntityName.toLowerCase()) - ); - retval = retval.filter(ent => { - return ent.tsEntityName !== entity.tsEntityName; - }); - - const column1 = new ColumnInfo(); - column1.tsName = secondRelatedTable; - column1.options.name = entity.sqlEntityName; - - const col1Rel = new RelationInfo(); - col1Rel.relatedTable = secondRelatedTable; - col1Rel.relatedColumn = secondRelatedTable; - - col1Rel.relationType = "ManyToMany"; - col1Rel.isOwner = true; - col1Rel.ownerColumn = firstRelatedTable; - - column1.relations.push(col1Rel); - relatedTable1.Columns.push(column1); - - const column2 = new ColumnInfo(); - column2.tsName = firstRelatedTable; - - const col2Rel = new RelationInfo(); - col2Rel.relatedTable = firstRelatedTable; - col2Rel.relatedColumn = secondRelatedTable; - - col2Rel.relationType = "ManyToMany"; - col2Rel.isOwner = false; - column2.relations.push(col2Rel); - relatedTable2.Columns.push(column2); + firstRelation.joinTableOptions = { + name: junctionEntity.sqlName, + joinColumns: junctionEntity.relations[0].joinColumnOptions!.map( + (v, i) => { + return { + name: v.referencedColumnName, + referencedColumnName: junctionEntity.relations[1] + .joinColumnOptions![i].referencedColumnName + }; + } + ), + inverseJoinColumns: junctionEntity.relations[1].joinColumnOptions!.map( + (v, i) => { + return { + name: v.referencedColumnName, + referencedColumnName: junctionEntity.relations[0] + .joinColumnOptions![i].referencedColumnName + }; + } + ) + }; + if (junctionEntity.database) { + firstRelation.joinTableOptions.database = + junctionEntity.database; } + if (junctionEntity.schema) { + firstRelation.joinTableOptions.schema = junctionEntity.schema; + } + + firstRelation.relationOptions = undefined; + secondRelation.relationOptions = undefined; + firstRelation.joinColumnOptions = undefined; + secondRelation.joinColumnOptions = undefined; + retVal = retVal.filter(ent => { + return ent.tscName !== junctionEntity.tscName; + }); }); - return retval; + return retVal; } public async GetDataFromServer( @@ -188,7 +190,7 @@ export default abstract class AbstractDriver { connectionOptions.databaseName ); await this.DisconnectFromServer(); - // dbModel = AbstractDriver.FindManyToManyRelations(dbModel); + dbModel = AbstractDriver.FindManyToManyRelations(dbModel); dbModel = AbstractDriver.FindFileImports(dbModel); return dbModel; } @@ -282,6 +284,9 @@ export default abstract class AbstractDriver { ); return; } + + let ownerRelation: Relation | undefined; + let relatedRelation: Relation | undefined; for ( let relationColumnIndex = 0; relationColumnIndex < relationTmp.ownerColumns.length; @@ -346,7 +351,7 @@ export default abstract class AbstractDriver { ownerEntity ); } - const ownerRelation: Relation = { + ownerRelation = { fieldName, relatedField: AbstractDriver.findNameForNewField( relationTmp.ownerTable.tscName, @@ -369,17 +374,17 @@ export default abstract class AbstractDriver { relatedTable: relationTmp.relatedTable.tscName, relationType: isOneToMany ? "ManyToOne" : "OneToOne" }; - const relatedRelation: Relation = { + relatedRelation = { fieldName: ownerRelation.relatedField, relatedField: ownerRelation.fieldName, relatedTable: relationTmp.ownerTable.tscName, // relationOptions: ownerRelation.relationOptions, relationType: isOneToMany ? "OneToMany" : "OneToOne" }; - - ownerEntity.relations.push(ownerRelation); - relationTmp.relatedTable.relations.push(relatedRelation); } + if (ownerRelation) ownerEntity.relations.push(ownerRelation); + if (relatedRelation) + relationTmp.relatedTable.relations.push(relatedRelation); }); return entities; } diff --git a/src/entity.mst b/src/entity.mst index 4002e9b..8efda4e 100644 --- a/src/entity.mst +++ b/src/entity.mst @@ -10,9 +10,9 @@ import { {{toEntityName .}} } from './{{toFileName .}}' {{/inline}} {{#*inline "Relation"}} -@{{relationType}}(()=>{{toEntityName relatedTable}},{{toEntityName relatedTable}}=>{{toEntityName relatedTable}}.{{toPropertyName relatedField}}{{#if (or joinColumnOptions joinTableOptions)}},{ {{json relationOptions}} }{{/if}}) +@{{relationType}}(()=>{{toEntityName relatedTable}},{{toEntityName relatedTable}}=>{{toEntityName relatedTable}}.{{toPropertyName relatedField}}{{#if joinColumnOptions}},{ {{json relationOptions}} }{{/if}}) {{#if joinColumnOptions}}@JoinColumn({{json joinColumnOptions}}){{/if}} -{{#if joinTableOptions}}@JoinTable{{json joinTableOptions}}){{/if}} +{{#if joinTableOptions}}@JoinTable({ {{json joinTableOptions}} }){{/if}} {{toPropertyName fieldName}}:{{toEntityName relatedTable}}{{#contains "ToMany" relationType}}[]{{/contains}}; {{/inline}} diff --git a/test/utils/EntityFileToJson.ts b/test/utils/EntityFileToJson.ts index 902e595..80b1e38 100644 --- a/test/utils/EntityFileToJson.ts +++ b/test/utils/EntityFileToJson.ts @@ -414,9 +414,7 @@ export default class EntityFileToJson { priorPartOfMultilineStatement = trimmedLine; } else { isMultilineStatement = false; - retVal.columns[ - retVal.columns.length - 1 - ].isOwnerOfRelation = true; + // it doesn't matter which side of ManyToMany relation is marked as owner } return; } From 681ef1a3633f03a1b39fe500c5549aef94ad8168 Mon Sep 17 00:00:00 2001 From: Kononnable Date: Mon, 7 Oct 2019 22:29:09 +0200 Subject: [PATCH 12/84] more tests passing --- src/Engine.ts | 41 ++++++++++------- src/entity.mst | 4 +- .../sample18-lazy-relations/entity/Author.ts | 13 ++++-- .../entity/Category.ts | 17 ++++--- .../sample18-lazy-relations/entity/Post.ts | 14 ++++-- .../sample3-many-to-one/entity/Post.ts | 26 ++++++----- .../sample4-many-to-many/entity/Post.ts | 34 ++++++++------ .../github-issues/71/entity/Post.ts | 44 +++++++++++-------- test/utils/EntityFileToJson.ts | 5 ++- 9 files changed, 125 insertions(+), 73 deletions(-) diff --git a/src/Engine.ts b/src/Engine.ts index e79e5d8..353e337 100644 --- a/src/Engine.ts +++ b/src/Engine.ts @@ -15,6 +15,7 @@ import SqliteDriver from "./drivers/SqliteDriver"; import NamingStrategy from "./NamingStrategy"; import AbstractNamingStrategy from "./AbstractNamingStrategy"; import { Entity } from "./models/Entity"; +import { Relation } from "./models/Relation"; import changeCase = require("change-case"); import fs = require("fs"); @@ -146,7 +147,7 @@ export function modelCustomizationPhase( let retVal = setRelationId(generationOptions, dbModel); // TODO: retVal = applyNamingStrategy(namingStrategy, retVal); - // retVal = addImportsAndGenerationOptions(retVal, generationOptions); + retVal = addImportsAndGenerationOptions(retVal, generationOptions); // retVal = removeColumnDefaultProperties(retVal, defaultValues); return retVal; } @@ -192,26 +193,21 @@ function removeColumnDefaultProperties( return dbModel; } function addImportsAndGenerationOptions( - dbModel: EntityInfo[], + dbModel: Entity[], generationOptions: IGenerationOptions ) { - dbModel.forEach(element => { - element.Imports = []; - element.Columns.forEach(column => { - column.relations.forEach(relation => { - if (element.tsEntityName !== relation.relatedTable) { - element.Imports.push(relation.relatedTable); + dbModel.forEach(entity => { + entity.relations.forEach(relation => { + if (generationOptions.lazy) { + if (!relation.relationOptions) { + relation.relationOptions = {}; } - }); - }); - element.GenerateConstructor = generationOptions.generateConstructor; - element.IsActiveRecord = generationOptions.activeRecord; - element.Imports.filter((elem, index, self) => { - return index === self.indexOf(elem); + relation.relationOptions.lazy = true; + } }); if (generationOptions.skipSchema) { - element.Schema = undefined; - element.Database = undefined; + entity.schema = undefined; + entity.database = undefined; } }); return dbModel; @@ -368,6 +364,19 @@ function createHandlebarsHelpers(generationOptions: IGenerationOptions) { return retStr; }); Handlebars.registerHelper("toLowerCase", str => str.toLowerCase()); + Handlebars.registerHelper( + "toRelation", + (entityType: string, relationType: Relation["relationType"]) => { + let retVal = entityType; + if (relationType === "ManyToMany" || relationType === "OneToMany") { + retVal = `${retVal}[]`; + } + if (generationOptions.lazy) { + retVal = `Promise<${retVal}>`; + } + return retVal; + } + ); Handlebars.registerHelper("tolowerCaseFirst", str => changeCase.lowerCaseFirst(str) ); diff --git a/src/entity.mst b/src/entity.mst index 8efda4e..b196fea 100644 --- a/src/entity.mst +++ b/src/entity.mst @@ -10,10 +10,10 @@ import { {{toEntityName .}} } from './{{toFileName .}}' {{/inline}} {{#*inline "Relation"}} -@{{relationType}}(()=>{{toEntityName relatedTable}},{{toEntityName relatedTable}}=>{{toEntityName relatedTable}}.{{toPropertyName relatedField}}{{#if joinColumnOptions}},{ {{json relationOptions}} }{{/if}}) +@{{relationType}}(()=>{{toEntityName relatedTable}},{{toEntityName relatedTable}}=>{{toEntityName relatedTable}}.{{toPropertyName relatedField}}{{#if relationOptions}},{ {{json relationOptions}} }{{/if}}) {{#if joinColumnOptions}}@JoinColumn({{json joinColumnOptions}}){{/if}} {{#if joinTableOptions}}@JoinTable({ {{json joinTableOptions}} }){{/if}} -{{toPropertyName fieldName}}:{{toEntityName relatedTable}}{{#contains "ToMany" relationType}}[]{{/contains}}; +{{toPropertyName fieldName}}:{{toRelation (toEntityName relatedTable) relationType}}; {{/inline}} {{#*inline "Entity"}} diff --git a/test/integration/examples/sample18-lazy-relations/entity/Author.ts b/test/integration/examples/sample18-lazy-relations/entity/Author.ts index 0d3d178..7a2bd65 100644 --- a/test/integration/examples/sample18-lazy-relations/entity/Author.ts +++ b/test/integration/examples/sample18-lazy-relations/entity/Author.ts @@ -1,9 +1,14 @@ -import { Column, Entity, Index, PrimaryGeneratedColumn, OneToMany } from "typeorm" -import {Post} from "./Post"; +import { + Column, + Entity, + Index, + PrimaryGeneratedColumn, + OneToMany +} from "typeorm"; +import { Post } from "./Post"; @Entity("Author") export class Author { - @PrimaryGeneratedColumn() id: number; @@ -12,6 +17,7 @@ export class Author { @OneToMany(type => Post, post => post.author, { // cascade: true + lazy: true }) posts: Promise; @@ -21,5 +27,4 @@ export class Author { // asPromise() { // return Promise.resolve(this); // } - } diff --git a/test/integration/examples/sample18-lazy-relations/entity/Category.ts b/test/integration/examples/sample18-lazy-relations/entity/Category.ts index 410df9b..1f90c4f 100644 --- a/test/integration/examples/sample18-lazy-relations/entity/Category.ts +++ b/test/integration/examples/sample18-lazy-relations/entity/Category.ts @@ -1,16 +1,23 @@ -import { Column, Entity, Index, PrimaryGeneratedColumn, VersionColumn, ManyToMany } from "typeorm" -import {Post} from "./Post"; +import { + Column, + Entity, + Index, + PrimaryGeneratedColumn, + VersionColumn, + ManyToMany +} from "typeorm"; +import { Post } from "./Post"; @Entity("Category") export class Category { - @PrimaryGeneratedColumn() id: number; @Column() name: string; - @ManyToMany(type => Post, post => post.categorys) + @ManyToMany(type => Post, post => post.categorys, { + lazy: true + }) posts: Promise; - } diff --git a/test/integration/examples/sample18-lazy-relations/entity/Post.ts b/test/integration/examples/sample18-lazy-relations/entity/Post.ts index 6d74a76..2283783 100644 --- a/test/integration/examples/sample18-lazy-relations/entity/Post.ts +++ b/test/integration/examples/sample18-lazy-relations/entity/Post.ts @@ -1,10 +1,17 @@ -import { Column, Entity, Index, PrimaryGeneratedColumn, ManyToOne, ManyToMany, JoinTable } from "typeorm" +import { + Column, + Entity, + Index, + PrimaryGeneratedColumn, + ManyToOne, + ManyToMany, + JoinTable +} from "typeorm"; import { Author } from "./Author"; import { Category } from "./Category"; @Entity("Post") export class Post { - @PrimaryGeneratedColumn() id: number; @@ -15,6 +22,7 @@ export class Post { text: string; @ManyToOne(type => Author, author => author.posts, { + lazy: true, // cascade: ["insert"], onDelete: "SET NULL", onUpdate: "CASCADE" @@ -22,9 +30,9 @@ export class Post { author: Promise; @ManyToMany(type => Category, category => category.posts, { + lazy: true // cascade: true }) @JoinTable() categorys: Promise; - } diff --git a/test/integration/examples/sample3-many-to-one/entity/Post.ts b/test/integration/examples/sample3-many-to-one/entity/Post.ts index 4505194..01a5140 100644 --- a/test/integration/examples/sample3-many-to-one/entity/Post.ts +++ b/test/integration/examples/sample3-many-to-one/entity/Post.ts @@ -1,4 +1,12 @@ -import { PrimaryGeneratedColumn, Column, Entity, OneToOne, OneToMany, ManyToOne, JoinColumn } from "typeorm"; +import { + PrimaryGeneratedColumn, + Column, + Entity, + OneToOne, + OneToMany, + ManyToOne, + JoinColumn +} from "typeorm"; import { PostDetails } from "./PostDetails"; import { PostCategory } from "./PostCategory"; import { PostAuthor } from "./PostAuthor"; @@ -8,7 +16,6 @@ import { PostMetadata } from "./PostMetadata"; @Entity("Post") export class Post { - @PrimaryGeneratedColumn() id: number; @@ -20,41 +27,40 @@ export class Post { // post has relation with category, however inverse relation is not set (category does not have relation with post set) @ManyToOne(type => PostCategory, { - cascade: true, - onDelete: 'CASCADE' + // cascade: true, + onDelete: "CASCADE" }) category: PostCategory; // post has relation with details. cascade inserts here means if new PostDetails instance will be set to this // relation it will be inserted automatically to the db when you save this Post entity @ManyToOne(type => PostDetails, details => details.posts, { - cascade: true, + // cascade: true, }) details: PostDetails; // post has relation with details. cascade update here means if new PostDetail instance will be set to this relation // it will be inserted automatically to the db when you save this Post entity @ManyToOne(type => PostImage, image => image.posts, { - cascade: true, + // cascade: true, }) image: PostImage; // post has relation with details. cascade update here means if new PostDetail instance will be set to this relation // it will be inserted automatically to the db when you save this Post entity @ManyToOne(type => PostMetadata, metadata => metadata.posts, { - cascade: true, + // cascade: true, }) metadata: PostMetadata | null; // post has relation with details. full cascades here @ManyToOne(type => PostInformation, information => information.posts, { - cascade: true, - onDelete: 'CASCADE' + // cascade: true, + onDelete: "CASCADE" }) information: PostInformation; // post has relation with details. not cascades here. means cannot be persisted, updated or removed @ManyToOne(type => PostAuthor, author => author.posts) author: PostAuthor; - } diff --git a/test/integration/examples/sample4-many-to-many/entity/Post.ts b/test/integration/examples/sample4-many-to-many/entity/Post.ts index 83b80c0..5c2a680 100644 --- a/test/integration/examples/sample4-many-to-many/entity/Post.ts +++ b/test/integration/examples/sample4-many-to-many/entity/Post.ts @@ -1,14 +1,23 @@ -import { PrimaryGeneratedColumn, Column, Entity, OneToOne, OneToMany, ManyToOne, ManyToMany, JoinColumn, JoinTable } from "typeorm"; -import {PostDetail} from "./PostDetail"; -import {PostCategory} from "./PostCategory"; -import {PostAuthor} from "./PostAuthor"; -import {PostInformation} from "./PostInformation"; -import {PostImage} from "./PostImage"; -import {PostMetadata} from "./PostMetadata"; +import { + PrimaryGeneratedColumn, + Column, + Entity, + OneToOne, + OneToMany, + ManyToOne, + ManyToMany, + JoinColumn, + JoinTable +} from "typeorm"; +import { PostDetail } from "./PostDetail"; +import { PostCategory } from "./PostCategory"; +import { PostAuthor } from "./PostAuthor"; +import { PostInformation } from "./PostInformation"; +import { PostImage } from "./PostImage"; +import { PostMetadata } from "./PostMetadata"; @Entity("Post") export class Post { - @PrimaryGeneratedColumn() id: number; @@ -20,7 +29,7 @@ export class Post { // post has relation with category, however inverse relation is not set (category does not have relation with post set) @ManyToMany(type => PostCategory, { - cascade: true + // cascade: true }) @JoinTable() postCategorys: PostCategory[]; @@ -28,7 +37,7 @@ export class Post { // post has relation with details. cascade inserts here means if new PostDetails instance will be set to this // relation it will be inserted automatically to the db when you save this Post entity @ManyToMany(type => PostDetail, details => details.posts, { - cascade: true + // cascade: true }) @JoinTable() postDetails: PostDetail[]; @@ -36,7 +45,7 @@ export class Post { // post has relation with details. cascade update here means if new PostDetail instance will be set to this relation // it will be inserted automatically to the db when you save this Post entity @ManyToMany(type => PostImage, image => image.posts, { - cascade: true + // cascade: true }) @JoinTable() postImages: PostImage[]; @@ -49,7 +58,7 @@ export class Post { // post has relation with details. full cascades here @ManyToMany(type => PostInformation, information => information.posts, { - cascade: true + // cascade: true }) @JoinTable() postInformations: PostInformation[]; @@ -58,5 +67,4 @@ export class Post { @ManyToMany(type => PostAuthor, author => author.posts) @JoinTable() postAuthors: PostAuthor[]; - } diff --git a/test/integration/github-issues/71/entity/Post.ts b/test/integration/github-issues/71/entity/Post.ts index c9b85b6..92b7eba 100644 --- a/test/integration/github-issues/71/entity/Post.ts +++ b/test/integration/github-issues/71/entity/Post.ts @@ -1,41 +1,47 @@ -import { Index, Entity, PrimaryColumn, Column, OneToOne, OneToMany, ManyToOne, ManyToMany, JoinColumn, JoinTable } from "typeorm"; +import { + Index, + Entity, + PrimaryColumn, + Column, + OneToOne, + OneToMany, + ManyToOne, + ManyToMany, + JoinColumn, + JoinTable +} from "typeorm"; import { PostReader } from "./PostReader"; import { PostAuthor } from "./PostAuthor"; import { PostCategory } from "./PostCategory"; import { PostDetails } from "./PostDetails"; - @Entity("Post") export class Post { - @Column("int", { - nullable: false, + // nullable: false, primary: true, name: "Id" }) Id: number; - @OneToOne(type => PostAuthor, PostAuthor => PostAuthor.Id, - { - // onDelete: "CASCADE", - // onUpdate: "CASCADE" - }) + @OneToOne(type => PostAuthor, PostAuthor => PostAuthor.Id, { + // onDelete: "CASCADE", + // onUpdate: "CASCADE" + }) postAuthor: PostAuthor; @OneToOne(type => PostReader, PostReader => PostReader.Id) postReader: PostReader; - @OneToOne(type => PostCategory, PostCategory => PostCategory.Id, - { - // onDelete: "RESTRICT", - // onUpdate: "RESTRICT" - }) + @OneToOne(type => PostCategory, PostCategory => PostCategory.Id, { + // onDelete: "RESTRICT", + // onUpdate: "RESTRICT" + }) postCategory: PostCategory; - @OneToOne(type => PostDetails, PostDetails => PostDetails.Id, - { - // onDelete: "SET NULL", - // onUpdate: "SET NULL" - }) + @OneToOne(type => PostDetails, PostDetails => PostDetails.Id, { + // onDelete: "SET NULL", + // onUpdate: "SET NULL" + }) postDetails: PostDetails; } diff --git a/test/utils/EntityFileToJson.ts b/test/utils/EntityFileToJson.ts index 80b1e38..a6f9229 100644 --- a/test/utils/EntityFileToJson.ts +++ b/test/utils/EntityFileToJson.ts @@ -356,6 +356,7 @@ export default class EntityFileToJson { retVal.columns.push(column); column.relationType = "ManyToOne"; column.isOwnerOfRelation = true; + EntityFileToJson.getRelationOptions(trimmedLine, column); } return; } @@ -368,6 +369,7 @@ export default class EntityFileToJson { const column = new EntityColumn(); retVal.columns.push(column); column.relationType = "OneToMany"; + EntityFileToJson.getRelationOptions(trimmedLine, column); } return; } @@ -380,6 +382,7 @@ export default class EntityFileToJson { const column = new EntityColumn(); retVal.columns.push(column); column.relationType = "ManyToMany"; + EntityFileToJson.getRelationOptions(trimmedLine, column); } return; } @@ -452,7 +455,7 @@ export default class EntityFileToJson { colTypes = colTypes.substring(8, colTypes.length - 1); retVal.columns[ retVal.columns.length - 1 - ].columnOptions.isLazy = true; + ].columnOptions.isTypeLazy = true; } retVal.columns[ retVal.columns.length - 1 From 886147e4c0b4cf940e8820a14f253c682e4aa0ef Mon Sep 17 00:00:00 2001 From: Kononnable Date: Mon, 7 Oct 2019 23:06:55 +0200 Subject: [PATCH 13/84] fix test utility --- test/integration/github-issues/135/entity/Post.ts | 8 ++++---- .../github-issues/135/entity/PostAuthor.ts | 6 +++--- .../github-issues/135/entity/PostCategory.ts | 6 +++--- test/integration/github-issues/65/entity/Post.ts | 8 ++++---- .../github-issues/65/entity/PostAuthor.ts | 6 +++--- .../github-issues/65/entity/PostReader.ts | 6 +++--- test/integration/github-issues/71/entity/Post.ts | 12 ++++++------ .../github-issues/71/entity/PostAuthor.ts | 6 +++--- .../github-issues/71/entity/PostCategory.ts | 6 +++--- .../github-issues/71/entity/PostDetails.ts | 6 +++--- .../github-issues/71/entity/PostReader.ts | 6 +++--- test/utils/EntityFileToJson.ts | 9 --------- 12 files changed, 38 insertions(+), 47 deletions(-) diff --git a/test/integration/github-issues/135/entity/Post.ts b/test/integration/github-issues/135/entity/Post.ts index 16e94c3..b637582 100644 --- a/test/integration/github-issues/135/entity/Post.ts +++ b/test/integration/github-issues/135/entity/Post.ts @@ -22,15 +22,15 @@ import { PostCategory } from "./PostCategory"; export class Post { @Column("int", { primary: true, - name: "Id" + name: "id" }) - Id: number; + id: number; - @ManyToOne(type => PostAuthor, PostAuthor => PostAuthor.Id) + @ManyToOne(type => PostAuthor, PostAuthor => PostAuthor.id) @JoinColumn() postAuthor: PostAuthor; - @ManyToOne(type => PostCategory, PostCategory => PostCategory.Id) + @ManyToOne(type => PostCategory, PostCategory => PostCategory.id) @JoinColumn() postCategory: PostCategory; } diff --git a/test/integration/github-issues/135/entity/PostAuthor.ts b/test/integration/github-issues/135/entity/PostAuthor.ts index 5b8998f..0a649ae 100644 --- a/test/integration/github-issues/135/entity/PostAuthor.ts +++ b/test/integration/github-issues/135/entity/PostAuthor.ts @@ -17,10 +17,10 @@ import { Post } from "./Post"; export class PostAuthor { @Column("int", { primary: true, - name: "Id" + name: "id" }) - Id: number; + id: number; - @OneToMany(type => Post, Post => Post.Id) + @OneToMany(type => Post, Post => Post.id) posts: Post[]; } diff --git a/test/integration/github-issues/135/entity/PostCategory.ts b/test/integration/github-issues/135/entity/PostCategory.ts index 7d61e7e..675f571 100644 --- a/test/integration/github-issues/135/entity/PostCategory.ts +++ b/test/integration/github-issues/135/entity/PostCategory.ts @@ -17,10 +17,10 @@ import { Post } from "./Post"; export class PostCategory { @Column("int", { primary: true, - name: "Id" + name: "id" }) - Id: number; + id: number; - @OneToMany(type => Post, Post => Post.Id) + @OneToMany(type => Post, Post => Post.id) posts: Post[]; } diff --git a/test/integration/github-issues/65/entity/Post.ts b/test/integration/github-issues/65/entity/Post.ts index 2596c9e..af629a0 100644 --- a/test/integration/github-issues/65/entity/Post.ts +++ b/test/integration/github-issues/65/entity/Post.ts @@ -17,13 +17,13 @@ import { PostReader } from "./PostReader"; export class Post { @Column("int", { primary: true, - name: "Id" + name: "id" }) - Id: number; + id: number; - @OneToOne(type => PostAuthor, PostAuthor => PostAuthor.Id) + @OneToOne(type => PostAuthor, PostAuthor => PostAuthor.id) postAuthor: PostAuthor; - @OneToMany(type => PostReader, PostReader => PostReader.Id) + @OneToMany(type => PostReader, PostReader => PostReader.id) postReaders: PostReader[]; } diff --git a/test/integration/github-issues/65/entity/PostAuthor.ts b/test/integration/github-issues/65/entity/PostAuthor.ts index ab27fd7..fd16930 100644 --- a/test/integration/github-issues/65/entity/PostAuthor.ts +++ b/test/integration/github-issues/65/entity/PostAuthor.ts @@ -17,11 +17,11 @@ import { Post } from "./Post"; export class PostAuthor { @Column("int", { primary: true, - name: "Id" + name: "id" }) - Id: number; + id: number; - @OneToOne(type => Post, Post => Post.Id) + @OneToOne(type => Post, Post => Post.id) @JoinColumn() post: Post; diff --git a/test/integration/github-issues/65/entity/PostReader.ts b/test/integration/github-issues/65/entity/PostReader.ts index 864a73b..37a0462 100644 --- a/test/integration/github-issues/65/entity/PostReader.ts +++ b/test/integration/github-issues/65/entity/PostReader.ts @@ -17,11 +17,11 @@ import { Post } from "./Post"; export class PostReader { @Column("int", { primary: true, - name: "Id" + name: "id" }) - Id: number; + id: number; - @ManyToOne(type => Post, Post => Post.Id) + @ManyToOne(type => Post, Post => Post.id) @JoinColumn() post: Post; diff --git a/test/integration/github-issues/71/entity/Post.ts b/test/integration/github-issues/71/entity/Post.ts index 92b7eba..8c96706 100644 --- a/test/integration/github-issues/71/entity/Post.ts +++ b/test/integration/github-issues/71/entity/Post.ts @@ -20,26 +20,26 @@ export class Post { @Column("int", { // nullable: false, primary: true, - name: "Id" + name: "id" }) - Id: number; + id: number; - @OneToOne(type => PostAuthor, PostAuthor => PostAuthor.Id, { + @OneToOne(type => PostAuthor, PostAuthor => PostAuthor.id, { // onDelete: "CASCADE", // onUpdate: "CASCADE" }) postAuthor: PostAuthor; - @OneToOne(type => PostReader, PostReader => PostReader.Id) + @OneToOne(type => PostReader, PostReader => PostReader.id) postReader: PostReader; - @OneToOne(type => PostCategory, PostCategory => PostCategory.Id, { + @OneToOne(type => PostCategory, PostCategory => PostCategory.id, { // onDelete: "RESTRICT", // onUpdate: "RESTRICT" }) postCategory: PostCategory; - @OneToOne(type => PostDetails, PostDetails => PostDetails.Id, { + @OneToOne(type => PostDetails, PostDetails => PostDetails.id, { // onDelete: "SET NULL", // onUpdate: "SET NULL" }) diff --git a/test/integration/github-issues/71/entity/PostAuthor.ts b/test/integration/github-issues/71/entity/PostAuthor.ts index 18a2431..b9b01df 100644 --- a/test/integration/github-issues/71/entity/PostAuthor.ts +++ b/test/integration/github-issues/71/entity/PostAuthor.ts @@ -17,11 +17,11 @@ import { Post } from "./Post"; export class PostAuthor { @Column("int", { primary: true, - name: "Id" + name: "id" }) - Id: number; + id: number; - @OneToOne(type => Post, Post => Post.Id, { + @OneToOne(type => Post, Post => Post.id, { onDelete: "CASCADE" // onUpdate: "CASCADE" }) diff --git a/test/integration/github-issues/71/entity/PostCategory.ts b/test/integration/github-issues/71/entity/PostCategory.ts index 25f36fb..5aef2f3 100644 --- a/test/integration/github-issues/71/entity/PostCategory.ts +++ b/test/integration/github-issues/71/entity/PostCategory.ts @@ -17,11 +17,11 @@ import { Post } from "./Post"; export class PostCategory { @Column("int", { primary: true, - name: "Id" + name: "id" }) - Id: number; + id: number; - @OneToOne(type => Post, Post => Post.Id, { + @OneToOne(type => Post, Post => Post.id, { // onDelete: "RESTRICT", // onUpdate: "RESTRICT" }) diff --git a/test/integration/github-issues/71/entity/PostDetails.ts b/test/integration/github-issues/71/entity/PostDetails.ts index dc9d754..3feb93f 100644 --- a/test/integration/github-issues/71/entity/PostDetails.ts +++ b/test/integration/github-issues/71/entity/PostDetails.ts @@ -17,11 +17,11 @@ import { Post } from "./Post"; export class PostDetails { @Column("int", { primary: true, - name: "Id" + name: "id" }) - Id: number; + id: number; - @OneToOne(type => Post, Post => Post.Id, { + @OneToOne(type => Post, Post => Post.id, { onDelete: "SET NULL" // onUpdate: "SET NULL" }) diff --git a/test/integration/github-issues/71/entity/PostReader.ts b/test/integration/github-issues/71/entity/PostReader.ts index ef232be..86b1566 100644 --- a/test/integration/github-issues/71/entity/PostReader.ts +++ b/test/integration/github-issues/71/entity/PostReader.ts @@ -17,11 +17,11 @@ import { Post } from "./Post"; export class PostReader { @Column("int", { primary: true, - name: "Id" + name: "id" }) - Id: number; + id: number; - @OneToOne(type => Post, Post => Post.Id) + @OneToOne(type => Post, Post => Post.id) @JoinColumn() post: Post; } diff --git a/test/utils/EntityFileToJson.ts b/test/utils/EntityFileToJson.ts index a6f9229..b73df1f 100644 --- a/test/utils/EntityFileToJson.ts +++ b/test/utils/EntityFileToJson.ts @@ -499,15 +499,6 @@ export default class EntityFileToJson { console.log(`${trimmedLine}`); }); - retVal.columns = retVal.columns.map(col => { - 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")) { From 74ace5f7a673644e5752cf7681e3d7bfef58dfda Mon Sep 17 00:00:00 2001 From: Kononnable Date: Tue, 8 Oct 2019 00:47:53 +0200 Subject: [PATCH 14/84] one more test passing --- src/Engine.ts | 39 +++++++++++------------------------ src/Utils.ts | 28 +++++++++++++++++++++++++ src/drivers/AbstractDriver.ts | 39 +++++++---------------------------- 3 files changed, 48 insertions(+), 58 deletions(-) diff --git a/src/Engine.ts b/src/Engine.ts index 353e337..e1cff5c 100644 --- a/src/Engine.ts +++ b/src/Engine.ts @@ -477,7 +477,12 @@ function applyNamingStrategy( model.forEach(entity => { entity.relations.forEach(relation => { const oldName = relation.fieldName; - const newName = namingStrategy.relationName(relation, entity); + let newName = namingStrategy.relationName(relation, entity); + newName = TomgUtils.findNameForNewField( + newName, + entity, + oldName + ); const relatedEntity = model.find( v => v.tscName === relation.relatedTable @@ -504,38 +509,18 @@ function applyNamingStrategy( function changeColumnNames(model: Entity[]) { model.forEach(entity => { entity.columns.forEach(column => { - const newName = namingStrategy.columnName( - column.tscName, - column + const oldName = column.tscName; + let newName = namingStrategy.columnName(column.tscName, column); + newName = TomgUtils.findNameForNewField( + newName, + entity, + oldName ); entity.indices.forEach(index => { index.columns.map(column2 => column2 === column.tscName ? newName : column2 ); }); - // TODO: Should relational columns be changed by both changeRelationNames and changeColumnNames? - // model.forEach(entity2 => { - // entity2.columns.forEach(column2 => { - // column2.relations - // .filter( - // relation => - // relation.relatedTable === entity.tscName && - // relation.relatedColumn === column.tscName - // ) - // .forEach(v => { - // v.relatedColumn = newName; - // }); - // column2.relations - // .filter( - // relation => - // relation.relatedTable === entity.tscName && - // relation.ownerColumn === column.tscName - // ) - // .forEach(v => { - // v.ownerColumn = newName; - // }); - // }); - // }); column.tscName = newName; }); diff --git a/src/Utils.ts b/src/Utils.ts index aebf54d..525f287 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -1,4 +1,5 @@ import * as packagejson from "../package.json"; +import { Entity } from "./models/Entity"; export function LogError( errText: string, @@ -24,3 +25,30 @@ export function LogError( export function packageVersion() { return `${(packagejson as any).name}@${(packagejson as any).version}`; } +export function findNameForNewField( + _fieldName: string, + entity: Entity, + columnOldName = "" +) { + let fieldName = _fieldName; + const validNameCondition = () => + (entity.columns.every(v => v.tscName !== fieldName) && + entity.relations.every(v => v.fieldName !== fieldName)) || + (columnOldName && columnOldName === fieldName); + if (!validNameCondition()) { + fieldName += "_"; + for ( + let i = 2; + i <= entity.columns.length + entity.relations.length; + i++ + ) { + fieldName = + fieldName.substring(0, fieldName.length - i.toString().length) + + i.toString(); + if (validNameCondition()) { + break; + } + } + } + return fieldName; +} diff --git a/src/drivers/AbstractDriver.ts b/src/drivers/AbstractDriver.ts index bfeba3d..0dd9f2f 100644 --- a/src/drivers/AbstractDriver.ts +++ b/src/drivers/AbstractDriver.ts @@ -88,7 +88,9 @@ export default abstract class AbstractDriver { entity.relations.length === 2 && entity.relations.every( v => v.relationOptions && v.relationType !== "ManyToMany" - ) + ) && + entity.relations[0].relatedTable !== + entity.relations[1].relatedTable ); manyToManyEntities.forEach(junctionEntity => { const firstEntity = dbModel.find( @@ -110,11 +112,11 @@ export default abstract class AbstractDriver { firstRelation.relatedTable = secondEntity.tscName; secondRelation.relatedTable = firstEntity.tscName; - firstRelation.fieldName = this.findNameForNewField( + firstRelation.fieldName = TomgUtils.findNameForNewField( secondEntity.tscName, firstEntity ); - secondRelation.fieldName = this.findNameForNewField( + secondRelation.fieldName = TomgUtils.findNameForNewField( firstEntity.tscName, secondEntity ); @@ -341,19 +343,19 @@ export default abstract class AbstractDriver { } let fieldName = ""; if (relationTmp.ownerColumns.length === 1) { - fieldName = AbstractDriver.findNameForNewField( + fieldName = TomgUtils.findNameForNewField( ownerColumn.tscName, ownerEntity ); } else { - fieldName = AbstractDriver.findNameForNewField( + fieldName = TomgUtils.findNameForNewField( relationTmp.relatedTable.tscName, ownerEntity ); } ownerRelation = { fieldName, - relatedField: AbstractDriver.findNameForNewField( + relatedField: TomgUtils.findNameForNewField( relationTmp.ownerTable.tscName, relationTmp.relatedTable ), @@ -389,31 +391,6 @@ export default abstract class AbstractDriver { return entities; } - private static findNameForNewField(_fieldName: string, entity: Entity) { - let fieldName = _fieldName; - const validNameCondition = - entity.columns.every(v => v.tscName !== fieldName) && - entity.relations.every(v => v.fieldName !== fieldName); - if (!validNameCondition) { - fieldName += "_"; - for ( - let i = 2; - i <= entity.columns.length + entity.relations.length; - i++ - ) { - fieldName = - fieldName.substring( - 0, - fieldName.length - i.toString().length - ) + i.toString(); - if (validNameCondition) { - break; - } - } - } - return fieldName; - } - public abstract async GetCoulmnsFromEntity( entities: Entity[], schema: string, From 24fe4cf48c879c84d17b154c389dde86e54c0e57 Mon Sep 17 00:00:00 2001 From: Kononnable Date: Tue, 8 Oct 2019 01:41:59 +0200 Subject: [PATCH 15/84] make one more test pass --- src/Engine.ts | 9 ++++----- src/drivers/AbstractDriver.ts | 19 +++++++++++++++---- .../entity/EverythingEntity.ts | 11 ++++++++--- test/integration/runTestsFromPath.test.ts | 3 +-- 4 files changed, 28 insertions(+), 14 deletions(-) diff --git a/src/Engine.ts b/src/Engine.ts index e1cff5c..6bcc3fa 100644 --- a/src/Engine.ts +++ b/src/Engine.ts @@ -145,22 +145,21 @@ export function modelCustomizationPhase( namingStrategy = new NamingStrategy(); } let retVal = setRelationId(generationOptions, dbModel); - // TODO: retVal = applyNamingStrategy(namingStrategy, retVal); retVal = addImportsAndGenerationOptions(retVal, generationOptions); - // retVal = removeColumnDefaultProperties(retVal, defaultValues); + retVal = removeColumnDefaultProperties(retVal, defaultValues); return retVal; } function removeColumnDefaultProperties( - dbModel: EntityInfo[], + dbModel: Entity[], defaultValues: DataTypeDefaults ) { if (!defaultValues) { return dbModel; } dbModel.forEach(entity => { - entity.Columns.forEach(column => { - const defVal = defaultValues[column.options.type as any]; + entity.columns.forEach(column => { + const defVal = defaultValues[column.tscType as any]; if (defVal) { if ( column.options.length && diff --git a/src/drivers/AbstractDriver.ts b/src/drivers/AbstractDriver.ts index 0dd9f2f..ad50998 100644 --- a/src/drivers/AbstractDriver.ts +++ b/src/drivers/AbstractDriver.ts @@ -83,14 +83,25 @@ export default abstract class AbstractDriver { let retVal = dbModel; const manyToManyEntities = retVal.filter( entity => - entity.columns.length === - entity.columns.filter(c => c.primary).length && entity.relations.length === 2 && entity.relations.every( - v => v.relationOptions && v.relationType !== "ManyToMany" + v => v.joinColumnOptions && v.relationType !== "ManyToMany" ) && entity.relations[0].relatedTable !== - entity.relations[1].relatedTable + entity.relations[1].relatedTable && + entity.columns.length === + entity.columns.filter(c => c.primary).length && + entity.columns + .map(v => v.tscName) + .filter( + v => + !entity.relations[0] + .joinColumnOptions!.map(x => x.name) + .some(jc => jc === v) && + !entity.relations[1] + .joinColumnOptions!.map(x => x.name) + .some(jc => jc === v) + ).length === 0 ); manyToManyEntities.forEach(junctionEntity => { const firstEntity = dbModel.find( diff --git a/test/integration/examples/sample11-all-types-entity/entity/EverythingEntity.ts b/test/integration/examples/sample11-all-types-entity/entity/EverythingEntity.ts index a0f1a1e..c6012f4 100644 --- a/test/integration/examples/sample11-all-types-entity/entity/EverythingEntity.ts +++ b/test/integration/examples/sample11-all-types-entity/entity/EverythingEntity.ts @@ -1,8 +1,14 @@ -import { PrimaryGeneratedColumn, Column, Entity, OneToOne, JoinColumn, Index } from "typeorm"; +import { + PrimaryGeneratedColumn, + Column, + Entity, + OneToOne, + JoinColumn, + Index +} from "typeorm"; @Entity("EverythingEntity") export class EverythingEntity { - //TODO: change to check column types per database engine @PrimaryGeneratedColumn() id: number; @@ -68,5 +74,4 @@ export class EverythingEntity { // @UpdateDateColumn() // updatedDate: Date; - } diff --git a/test/integration/runTestsFromPath.test.ts b/test/integration/runTestsFromPath.test.ts index 2b37def..96cbba8 100644 --- a/test/integration/runTestsFromPath.test.ts +++ b/test/integration/runTestsFromPath.test.ts @@ -9,7 +9,7 @@ import { modelGenerationPhase } from "../../src/Engine"; import * as GTU from "../utils/GeneralTestUtils"; -import EntityInfo from "../../src/oldModels/EntityInfo"; +import { Entity } from "../../src/models/Entity"; import IConnectionOptions from "../../src/IConnectionOptions"; import fs = require("fs-extra"); @@ -17,7 +17,6 @@ import path = require("path"); import chaiSubset = require("chai-subset"); import chai = require("chai"); import yn = require("yn"); -import { Entity } from "../../src/models/Entity"; require("dotenv").config(); From 102ff614f69ecd1e9075353f7c9a497d0563000d Mon Sep 17 00:00:00 2001 From: Kononnable Date: Tue, 8 Oct 2019 20:35:07 +0200 Subject: [PATCH 16/84] one more test --- src/Engine.ts | 4 +-- src/NamingStrategy.ts | 26 ++++------------- src/Utils.ts | 11 +++++-- src/entity.mst | 2 +- .../github-issues/58/entity/feedextrainfo.ts | 29 ++++++++++--------- .../github-issues/58/entity/quests.ts | 4 +-- .../github-issues/58/entity/users.ts | 6 ++-- 7 files changed, 38 insertions(+), 44 deletions(-) diff --git a/src/Engine.ts b/src/Engine.ts index 6bcc3fa..98f25be 100644 --- a/src/Engine.ts +++ b/src/Engine.ts @@ -516,8 +516,8 @@ function applyNamingStrategy( oldName ); entity.indices.forEach(index => { - index.columns.map(column2 => - column2 === column.tscName ? newName : column2 + index.columns = index.columns.map(column2 => + column2 === oldName ? newName : column2 ); }); diff --git a/src/NamingStrategy.ts b/src/NamingStrategy.ts index ae089cb..13678ec 100644 --- a/src/NamingStrategy.ts +++ b/src/NamingStrategy.ts @@ -1,6 +1,7 @@ import AbstractNamingStrategy from "./AbstractNamingStrategy"; import { Relation } from "./models/Relation"; import { Entity } from "./models/Entity"; +import { findNameForNewField } from "./Utils"; import changeCase = require("change-case"); @@ -8,10 +9,13 @@ import changeCase = require("change-case"); export default class NamingStrategy extends AbstractNamingStrategy { public relationName(relation: Relation, owner: Entity): string { const columnOldName = relation.fieldName; + const isRelationToMany = relation.relationType === "OneToMany" || relation.relationType === "ManyToMany"; - let columnName = changeCase.camelCase(columnOldName); + let columnName = changeCase.camelCase( + columnOldName.replace(/[0-9]$/, "") + ); if ( columnName.toLowerCase().endsWith("id") && @@ -34,25 +38,7 @@ export default class NamingStrategy extends AbstractNamingStrategy { relation.relationType !== "ManyToMany" && columnOldName !== columnName ) { - if (owner.columns.some(v => v.tscName === columnName)) { - columnName += "_"; - for (let i = 2; i <= owner.columns.length; i++) { - columnName = - columnName.substring( - 0, - columnName.length - i.toString().length - ) + i.toString(); - if ( - owner.columns.every( - v => - v.tscName !== columnName || - columnName === columnOldName - ) - ) { - break; - } - } - } + columnName = findNameForNewField(columnName, owner, columnOldName); } return columnName; diff --git a/src/Utils.ts b/src/Utils.ts index 525f287..eae30f5 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -32,9 +32,14 @@ export function findNameForNewField( ) { let fieldName = _fieldName; const validNameCondition = () => - (entity.columns.every(v => v.tscName !== fieldName) && - entity.relations.every(v => v.fieldName !== fieldName)) || - (columnOldName && columnOldName === fieldName); + (entity.columns.every( + v => v.tscName.toLowerCase() !== fieldName.toLowerCase() + ) && + entity.relations.every( + v => v.fieldName.toLowerCase() !== fieldName.toLowerCase() + )) || + (columnOldName && + columnOldName.toLowerCase() === fieldName.toLowerCase()); if (!validNameCondition()) { fieldName += "_"; for ( diff --git a/src/entity.mst b/src/entity.mst index b196fea..8114e10 100644 --- a/src/entity.mst +++ b/src/entity.mst @@ -1,5 +1,5 @@ {{#*inline "Index"}} -@Index("{{name}}",[{{#columns}}"{{.}}",{{/columns~}}],{ {{json options}} }) +@Index("{{name}}",[{{#columns}}"{{toPropertyName .}}",{{/columns~}}],{ {{json options}} }) {{/inline}} {{#*inline "Import"}} import { {{toEntityName .}} } from './{{toFileName .}}' diff --git a/test/integration/github-issues/58/entity/feedextrainfo.ts b/test/integration/github-issues/58/entity/feedextrainfo.ts index 02f141c..2f822dd 100644 --- a/test/integration/github-issues/58/entity/feedextrainfo.ts +++ b/test/integration/github-issues/58/entity/feedextrainfo.ts @@ -18,26 +18,29 @@ import { quests } from "./quests"; @Index("feedExtraInfo_ReaderId_idx", ["readerId"], { unique: true }) @Index("feedExtraInfo_QuestId_idx", ["questId"], { unique: true }) export class feedextrainfo { - @OneToOne(type => users, FeedOwnerId => FeedOwnerId.feedextrainfo, { - primary: true - }) + @PrimaryColumn({ name: "FeedOwnerId" }) + feedOwnerId: number; + + @PrimaryColumn({ name: "QuestId" }) + questId: number; + + @PrimaryColumn({ name: "ReaderId" }) + readerId: number; + + @OneToOne(type => users, FeedOwnerId => FeedOwnerId.feedextrainfo) @JoinColumn({ name: "FeedOwnerId" }) - feedOwnerId: users; + feedOwner: users; - @OneToOne(type => quests, QuestId => QuestId.feedextrainfo, { - primary: true - }) + @OneToOne(type => quests, QuestId => QuestId.feedextrainfo) @JoinColumn({ name: "QuestId" }) - questId: quests; + quest: quests; - @OneToOne(type => users, ReaderId => ReaderId.feedextrainfo2, { - primary: true - }) + @OneToOne(type => users, ReaderId => ReaderId.feedextrainfo2) @JoinColumn({ name: "ReaderId" }) - readerId: users; + reader: users; @Column("int", { name: "MostUpdatedFeedEntryIdUserRead" }) - MostUpdatedFeedEntryIdUserRead: number; + mostUpdatedFeedEntryIdUserRead: number; } diff --git a/test/integration/github-issues/58/entity/quests.ts b/test/integration/github-issues/58/entity/quests.ts index 6c8e0bc..681c603 100644 --- a/test/integration/github-issues/58/entity/quests.ts +++ b/test/integration/github-issues/58/entity/quests.ts @@ -18,8 +18,8 @@ export class quests { primary: true, name: "QuestId" }) - QuestId: number; + questId: number; - @OneToOne(type => feedextrainfo, feedextrainfo => feedextrainfo.questId) + @OneToOne(type => feedextrainfo, feedextrainfo => feedextrainfo.quest) feedextrainfo: feedextrainfo; } diff --git a/test/integration/github-issues/58/entity/users.ts b/test/integration/github-issues/58/entity/users.ts index fe57631..6ae9e82 100644 --- a/test/integration/github-issues/58/entity/users.ts +++ b/test/integration/github-issues/58/entity/users.ts @@ -18,11 +18,11 @@ export class users { primary: true, name: "UserId" }) - UserId: number; + userId: number; - @OneToOne(type => feedextrainfo, feedextrainfo => feedextrainfo.feedOwnerId) + @OneToOne(type => feedextrainfo, feedextrainfo => feedextrainfo.feedOwner) feedextrainfo: feedextrainfo; - @OneToOne(type => feedextrainfo, feedextrainfo2 => feedextrainfo2.readerId) + @OneToOne(type => feedextrainfo, feedextrainfo2 => feedextrainfo2.reader) feedextrainfo2: feedextrainfo; } From 0936f81e3c54ea930f042a938ca4af06cf03e25c Mon Sep 17 00:00:00 2001 From: Kononnable Date: Wed, 9 Oct 2019 23:08:25 +0200 Subject: [PATCH 17/84] partial RelationId implementation --- src/Engine.ts | 11 +- src/Utils.ts | 3 + src/drivers/AbstractDriver.ts | 173 ++++++++++++---------- src/drivers/MysqlDriver.ts | 7 +- src/drivers/SqliteDriver.ts | 1 + src/entity.mst | 6 + src/models/Entity.ts | 2 + src/models/RelationId.ts | 5 + test/integration/runTestsFromPath.test.ts | 12 +- 9 files changed, 136 insertions(+), 84 deletions(-) create mode 100644 src/models/RelationId.ts diff --git a/src/Engine.ts b/src/Engine.ts index 98f25be..c1d5910 100644 --- a/src/Engine.ts +++ b/src/Engine.ts @@ -46,7 +46,11 @@ export async function createModelFromDatabase( connectionOptions: IConnectionOptions, generationOptions: IGenerationOptions ) { - let dbModel = await dataCollectionPhase(driver, connectionOptions); + let dbModel = await dataCollectionPhase( + driver, + connectionOptions, + generationOptions + ); if (dbModel.length === 0) { TomgUtils.LogError( "Tables not found in selected database. Skipping creation of typeorm model.", @@ -123,9 +127,10 @@ export async function createModelFromDatabase( } export async function dataCollectionPhase( driver: AbstractDriver, - connectionOptions: IConnectionOptions + connectionOptions: IConnectionOptions, + generationOptions: IGenerationOptions ) { - return driver.GetDataFromServer(connectionOptions); + return driver.GetDataFromServer(connectionOptions, generationOptions); } export function modelCustomizationPhase( diff --git a/src/Utils.ts b/src/Utils.ts index eae30f5..38fdb98 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -37,6 +37,9 @@ export function findNameForNewField( ) && entity.relations.every( v => v.fieldName.toLowerCase() !== fieldName.toLowerCase() + ) && + entity.relationIds.every( + v => v.fieldName.toLowerCase() !== fieldName.toLowerCase() )) || (columnOldName && columnOldName.toLowerCase() === fieldName.toLowerCase()); diff --git a/src/drivers/AbstractDriver.ts b/src/drivers/AbstractDriver.ts index ad50998..7963e01 100644 --- a/src/drivers/AbstractDriver.ts +++ b/src/drivers/AbstractDriver.ts @@ -13,6 +13,8 @@ import IConnectionOptions from "../IConnectionOptions"; import { Entity } from "../models/Entity"; import { RelationInternal } from "../models/RelationInternal"; import { Relation } from "../models/Relation"; +import IGenerationOptions from "../IGenerationOptions"; +import { Column } from "../models/Column"; export default abstract class AbstractDriver { public abstract standardPort: number; @@ -175,7 +177,8 @@ export default abstract class AbstractDriver { } public async GetDataFromServer( - connectionOptions: IConnectionOptions + connectionOptions: IConnectionOptions, + generationOptions: IGenerationOptions ): Promise { let dbModel = [] as Entity[]; await this.ConnectToServer(connectionOptions); @@ -200,7 +203,8 @@ export default abstract class AbstractDriver { dbModel = await this.GetRelations( dbModel, sqlEscapedSchema, - connectionOptions.databaseName + connectionOptions.databaseName, + generationOptions ); await this.DisconnectFromServer(); dbModel = AbstractDriver.FindManyToManyRelations(dbModel); @@ -234,6 +238,7 @@ export default abstract class AbstractDriver { columns: [], indices: [], relations: [], + relationIds: [], sqlName: val.TABLE_NAME, tscName: val.TABLE_NAME, database: dbNames.includes(",") ? val.DB_NAME : "", @@ -246,7 +251,8 @@ export default abstract class AbstractDriver { public static GetRelationsFromRelationTempInfo( relationsTemp: RelationInternal[], - entities: Entity[] + entities: Entity[], + generationOptions: IGenerationOptions ) { relationsTemp.forEach(relationTmp => { if (relationTmp.ownerColumns.length > 1) { @@ -298,8 +304,8 @@ export default abstract class AbstractDriver { return; } - let ownerRelation: Relation | undefined; - let relatedRelation: Relation | undefined; + const ownerColumns: Column[] = []; + const relatedColumns: Column[] = []; for ( let relationColumnIndex = 0; relationColumnIndex < relationTmp.ownerColumns.length; @@ -327,77 +333,91 @@ export default abstract class AbstractDriver { ); return; } - let isOneToMany: boolean; - isOneToMany = false; - const index = ownerEntity.indices.find( - ind => - ind.options.unique && - ind.columns.length === 1 && - ind.columns[0] === ownerColumn!.tscName - ); - isOneToMany = !index; - - if (true) { - // TODO: RelationId - ownerEntity.columns = ownerEntity.columns.filter( - v => - !relationTmp.ownerColumns.some( - u => u === v.tscName - ) || v.primary - ); - relationTmp.relatedTable.columns = relationTmp.relatedTable.columns.filter( - v => - !relationTmp.relatedColumns.some( - u => u === v.tscName - ) || v.primary - ); - } - let fieldName = ""; - if (relationTmp.ownerColumns.length === 1) { - fieldName = TomgUtils.findNameForNewField( - ownerColumn.tscName, - ownerEntity - ); - } else { - fieldName = TomgUtils.findNameForNewField( - relationTmp.relatedTable.tscName, - ownerEntity - ); - } - ownerRelation = { - fieldName, - relatedField: TomgUtils.findNameForNewField( - relationTmp.ownerTable.tscName, - relationTmp.relatedTable - ), - relationOptions: { - onDelete: relationTmp.onDelete, - onUpdate: relationTmp.onUpdate - }, - joinColumnOptions: relationTmp.ownerColumns.map( - (v, idx) => { - const retVal: JoinColumnOptions = { - name: v, - referencedColumnName: - relationTmp.relatedColumns[idx] - }; - return retVal; - } - ), - relatedTable: relationTmp.relatedTable.tscName, - relationType: isOneToMany ? "ManyToOne" : "OneToOne" - }; - relatedRelation = { - fieldName: ownerRelation.relatedField, - relatedField: ownerRelation.fieldName, - relatedTable: relationTmp.ownerTable.tscName, - // relationOptions: ownerRelation.relationOptions, - relationType: isOneToMany ? "OneToMany" : "OneToOne" - }; + ownerColumns.push(ownerColumn); + relatedColumns.push(relatedColumn); + } + let isOneToMany: boolean; + isOneToMany = false; + const index = ownerEntity.indices.find( + ind => + ind.options.unique && + ind.columns.length === ownerColumns.length && + ownerColumns.every(ownerColumn => + ind.columns.some(col => col === ownerColumn.tscName) + ) + ); + isOneToMany = !index; + + // TODO: RelationId + ownerEntity.columns = ownerEntity.columns.filter( + v => + !relationTmp.ownerColumns.some(u => u === v.tscName) || + v.primary + ); + relationTmp.relatedTable.columns = relationTmp.relatedTable.columns.filter( + v => + !relationTmp.relatedColumns.some(u => u === v.tscName) || + v.primary + ); + let fieldName = ""; + if (ownerColumns.length === 1) { + fieldName = TomgUtils.findNameForNewField( + ownerColumns[0].tscName, + ownerEntity + ); + } else { + fieldName = TomgUtils.findNameForNewField( + relationTmp.relatedTable.tscName, + ownerEntity + ); + } + + const ownerRelation: Relation = { + fieldName, + relatedField: TomgUtils.findNameForNewField( + relationTmp.ownerTable.tscName, + relationTmp.relatedTable + ), + relationOptions: { + onDelete: relationTmp.onDelete, + onUpdate: relationTmp.onUpdate + }, + joinColumnOptions: relationTmp.ownerColumns.map((v, idx) => { + const retVal: JoinColumnOptions = { + name: v, + referencedColumnName: relationTmp.relatedColumns[idx] + }; + return retVal; + }), + relatedTable: relationTmp.relatedTable.tscName, + relationType: isOneToMany ? "ManyToOne" : "OneToOne" + }; + const relatedRelation: Relation = { + fieldName: ownerRelation.relatedField, + relatedField: ownerRelation.fieldName, + relatedTable: relationTmp.ownerTable.tscName, + // relationOptions: ownerRelation.relationOptions, + relationType: isOneToMany ? "OneToMany" : "OneToOne" + }; + + ownerEntity.relations.push(ownerRelation); + relationTmp.relatedTable.relations.push(relatedRelation); + + if (generationOptions.relationIds && ownerColumns.length === 1) { + let relationIdFieldName = ""; + relationIdFieldName = TomgUtils.findNameForNewField( + ownerColumns[0].tscName, + ownerEntity + ); + ownerEntity.relationIds.push({ + fieldName: relationIdFieldName, // TODO: generate name without number(naming strategy) + fieldType: isOneToMany + ? `${ownerColumns[0].tscType}[]` + : ownerColumns[0].tscType, + relationField: ownerRelation.fieldName // TODO: naming strategy + }); + // TODO: RelationId on ManyToMany } - if (ownerRelation) ownerEntity.relations.push(ownerRelation); - if (relatedRelation) - relationTmp.relatedTable.relations.push(relatedRelation); }); return entities; } @@ -417,7 +437,8 @@ export default abstract class AbstractDriver { public abstract async GetRelations( entities: Entity[], schema: string, - dbNames: string + dbNames: string, + generationOptions: IGenerationOptions ): Promise; public static FindPrimaryColumnsFromIndexes(dbModel: Entity[]) { diff --git a/src/drivers/MysqlDriver.ts b/src/drivers/MysqlDriver.ts index 8531daf..96561fe 100644 --- a/src/drivers/MysqlDriver.ts +++ b/src/drivers/MysqlDriver.ts @@ -14,6 +14,7 @@ import { Entity } from "../models/Entity"; import { Column } from "../models/Column"; import { Index } from "../models/Index"; import { RelationInternal } from "../models/RelationInternal"; +import IGenerationOptions from "../IGenerationOptions"; export default class MysqlDriver extends AbstractDriver { public defaultValues: DataTypeDefaults = new TypeormDriver.MysqlDriver({ @@ -316,7 +317,8 @@ export default class MysqlDriver extends AbstractDriver { public async GetRelations( entities: Entity[], schema: string, - dbNames: string + dbNames: string, + generationOptions: IGenerationOptions ): Promise { const response = await this.ExecQuery<{ TableWithForeignKey: string; @@ -385,7 +387,8 @@ export default class MysqlDriver extends AbstractDriver { const retVal = MysqlDriver.GetRelationsFromRelationTempInfo( relationsTemp, - entities + entities, + generationOptions ); return retVal; } diff --git a/src/drivers/SqliteDriver.ts b/src/drivers/SqliteDriver.ts index 7a84e5d..8904902 100644 --- a/src/drivers/SqliteDriver.ts +++ b/src/drivers/SqliteDriver.ts @@ -44,6 +44,7 @@ export default class SqliteDriver extends AbstractDriver { columns: [], indices: [], relations: [], + relationIds: [], sqlName: val.tbl_name, tscName: val.tbl_name, fileImports: [] diff --git a/src/entity.mst b/src/entity.mst index 8114e10..0c7f940 100644 --- a/src/entity.mst +++ b/src/entity.mst @@ -15,6 +15,11 @@ import { {{toEntityName .}} } from './{{toFileName .}}' {{#if joinTableOptions}}@JoinTable({ {{json joinTableOptions}} }){{/if}} {{toPropertyName fieldName}}:{{toRelation (toEntityName relatedTable) relationType}}; +{{/inline}} +{{#*inline "RelationId"}} +@RelationId(({{toPropertyName entityName}}:{{toEntityName entityName}})=>{{toPropertyName entityName}}.{{toPropertyName relationField}}) +{{toPropertyName fieldName}}:{{fieldType}}; + {{/inline}} {{#*inline "Entity"}} {{#indices}}{{> Index}}{{/indices~}} @@ -23,6 +28,7 @@ export class {{toEntityName tscName}} { {{#columns}}{{> Column}}{{/columns~}} {{#relations}}{{> Relation}}{{/relations~}} +{{#relationIds}}{{> RelationId entityName=../tscName}}{{/relationIds~}} } {{/inline}} diff --git a/src/models/Entity.ts b/src/models/Entity.ts index 9a2c566..019aa20 100644 --- a/src/models/Entity.ts +++ b/src/models/Entity.ts @@ -1,6 +1,7 @@ import { Column } from "./Column"; import { Relation } from "./Relation"; import { Index } from "./Index"; +import { RelationId } from "./RelationId"; export type Entity = { sqlName: string; @@ -10,6 +11,7 @@ export type Entity = { schema?: string; columns: Column[]; + relationIds: RelationId[]; relations: Relation[]; indices: Index[]; fileImports: string[]; diff --git a/src/models/RelationId.ts b/src/models/RelationId.ts new file mode 100644 index 0000000..bef6676 --- /dev/null +++ b/src/models/RelationId.ts @@ -0,0 +1,5 @@ +export type RelationId = { + fieldName: string; + fieldType: string; + relationField: string; +}; diff --git a/test/integration/runTestsFromPath.test.ts b/test/integration/runTestsFromPath.test.ts index 96cbba8..c957d2b 100644 --- a/test/integration/runTestsFromPath.test.ts +++ b/test/integration/runTestsFromPath.test.ts @@ -94,14 +94,16 @@ function runTestForMultipleDrivers( driver, Object.assign(connectionOptions, { databaseName: "db1,db2" - }) + }), + generationOptions ); break; default: dbModel = await dataCollectionPhase( driver, - connectionOptions + connectionOptions, + generationOptions ); break; } @@ -160,7 +162,11 @@ async function runTest( resultsPath, filesOrgPathTS } = await prepareTestRuns(testPartialPath, dbDriver, dbDriver); - let dbModel = await dataCollectionPhase(driver, connectionOptions); + let dbModel = await dataCollectionPhase( + driver, + connectionOptions, + generationOptions + ); dbModel = modelCustomizationPhase( dbModel, generationOptions, From ad8e1f528f9ab0413537dc936146a9880f3a3f26 Mon Sep 17 00:00:00 2001 From: Kononnable Date: Thu, 10 Oct 2019 15:40:08 +0200 Subject: [PATCH 18/84] RelationIds for OneToOne, OneToMany --- src/AbstractNamingStrategy.ts | 7 +++++++ src/Engine.ts | 35 +++++++++++++++++++++++++++++++++++ src/NamingStrategy.ts | 34 ++++++++++++++++++++++++++-------- src/drivers/AbstractDriver.ts | 4 ++-- 4 files changed, 70 insertions(+), 10 deletions(-) diff --git a/src/AbstractNamingStrategy.ts b/src/AbstractNamingStrategy.ts index 007562d..547367f 100644 --- a/src/AbstractNamingStrategy.ts +++ b/src/AbstractNamingStrategy.ts @@ -1,8 +1,15 @@ import { Relation } from "./models/Relation"; import { Entity } from "./models/Entity"; import { Column } from "./models/Column"; +import { RelationId } from "./models/RelationId"; export default abstract class AbstractNamingStrategy { + public abstract relationIdName( + relationId: RelationId, + relation: Relation, + owner: Entity + ): string; + public abstract relationName(relation: Relation, owner: Entity): string; public abstract entityName(entityName: string, entity?: Entity): string; diff --git a/src/Engine.ts b/src/Engine.ts index c1d5910..7011ecc 100644 --- a/src/Engine.ts +++ b/src/Engine.ts @@ -473,10 +473,41 @@ function applyNamingStrategy( dbModel: Entity[] ) { let retval = changeRelationNames(dbModel); + retval = changeRelationIdNames(retval); retval = changeEntityNames(retval); retval = changeColumnNames(retval); return retval; + function changeRelationIdNames(model: Entity[]) { + // TODO: + model.forEach(entity => { + entity.relationIds.forEach(relationId => { + const oldName = relationId.fieldName; + const relation = entity.relations.find( + v => v.fieldName === relationId.relationField + )!; + let newName = namingStrategy.relationIdName( + relationId, + relation, + entity + ); + newName = TomgUtils.findNameForNewField( + newName, + entity, + oldName + ); + entity.indices.forEach(index => { + index.columns = index.columns.map(column2 => + column2 === oldName ? newName : column2 + ); + }); + + relationId.fieldName = newName; + }); + }); + return dbModel; + } + function changeRelationNames(model: Entity[]) { model.forEach(entity => { entity.relations.forEach(relation => { @@ -495,6 +526,10 @@ function applyNamingStrategy( v => v.fieldName === relation.relatedField )!; + entity.relationIds + .filter(v => v.relationField === oldName) + .forEach(v => (v.relationField = newName)); + relation.fieldName = newName; relation2.relatedField = newName; diff --git a/src/NamingStrategy.ts b/src/NamingStrategy.ts index 13678ec..399ea44 100644 --- a/src/NamingStrategy.ts +++ b/src/NamingStrategy.ts @@ -1,12 +1,37 @@ import AbstractNamingStrategy from "./AbstractNamingStrategy"; import { Relation } from "./models/Relation"; import { Entity } from "./models/Entity"; -import { findNameForNewField } from "./Utils"; +import { RelationId } from "./models/RelationId"; import changeCase = require("change-case"); /* eslint-disable class-methods-use-this */ export default class NamingStrategy extends AbstractNamingStrategy { + public relationIdName( + relationId: RelationId, + relation: Relation, + owner: Entity + ): string { + const columnOldName = relationId.fieldName; + + const isRelationToMany = + relation.relationType === "OneToMany" || + relation.relationType === "ManyToMany"; + let columnName = changeCase.camelCase( + columnOldName.replace(/[0-9]$/, "") + ); + + if (!Number.isNaN(parseInt(columnName[columnName.length - 1], 10))) { + columnName = columnName.substring(0, columnName.length - 1); + } + if (!Number.isNaN(parseInt(columnName[columnName.length - 1], 10))) { + columnName = columnName.substring(0, columnName.length - 1); + } + columnName += isRelationToMany ? "s" : ""; + + return columnName; + } + public relationName(relation: Relation, owner: Entity): string { const columnOldName = relation.fieldName; @@ -34,13 +59,6 @@ export default class NamingStrategy extends AbstractNamingStrategy { } columnName += isRelationToMany ? "s" : ""; - if ( - relation.relationType !== "ManyToMany" && - columnOldName !== columnName - ) { - columnName = findNameForNewField(columnName, owner, columnOldName); - } - return columnName; } diff --git a/src/drivers/AbstractDriver.ts b/src/drivers/AbstractDriver.ts index 7963e01..7904c24 100644 --- a/src/drivers/AbstractDriver.ts +++ b/src/drivers/AbstractDriver.ts @@ -410,11 +410,11 @@ export default abstract class AbstractDriver { ownerEntity ); ownerEntity.relationIds.push({ - fieldName: relationIdFieldName, // TODO: generate name without number(naming strategy) + fieldName: relationIdFieldName, fieldType: isOneToMany ? `${ownerColumns[0].tscType}[]` : ownerColumns[0].tscType, - relationField: ownerRelation.fieldName // TODO: naming strategy + relationField: ownerRelation.fieldName }); // TODO: RelationId on ManyToMany } From 2551a5629afee861199b260adc0a31c907049d27 Mon Sep 17 00:00:00 2001 From: Kononnable Date: Thu, 10 Oct 2019 21:05:06 +0200 Subject: [PATCH 19/84] Mssql implementation --- src/Engine.ts | 4 +- src/drivers/AbstractDriver.ts | 14 +- src/drivers/MssqlDriver.ts | 719 +++++++++--------- .../entityTypes/mssql/entity/Post.ts | 4 +- .../github-issues/39/entity/Post.ts | 4 +- .../github-issues/39/entity/User.ts | 45 +- 6 files changed, 406 insertions(+), 384 deletions(-) diff --git a/src/Engine.ts b/src/Engine.ts index 7011ecc..93e26fd 100644 --- a/src/Engine.ts +++ b/src/Engine.ts @@ -528,7 +528,9 @@ function applyNamingStrategy( entity.relationIds .filter(v => v.relationField === oldName) - .forEach(v => (v.relationField = newName)); + .forEach(v => { + v.relationField = newName; + }); relation.fieldName = newName; relation2.relatedField = newName; diff --git a/src/drivers/AbstractDriver.ts b/src/drivers/AbstractDriver.ts index 7904c24..fb577ee 100644 --- a/src/drivers/AbstractDriver.ts +++ b/src/drivers/AbstractDriver.ts @@ -3,7 +3,7 @@ import { WithPrecisionColumnType, WithWidthColumnType } from "typeorm/driver/types/ColumnTypes"; -import { JoinColumnOptions } from "typeorm"; +import { JoinColumnOptions, RelationOptions } from "typeorm"; import { DataTypeDefaults } from "typeorm/driver/types/DataTypeDefaults"; import * as TomgUtils from "../Utils"; import EntityInfo from "../oldModels/EntityInfo"; @@ -372,16 +372,17 @@ export default abstract class AbstractDriver { ); } + const relationOptions: RelationOptions = { + onDelete: relationTmp.onDelete, + onUpdate: relationTmp.onUpdate + }; + const ownerRelation: Relation = { fieldName, relatedField: TomgUtils.findNameForNewField( relationTmp.ownerTable.tscName, relationTmp.relatedTable ), - relationOptions: { - onDelete: relationTmp.onDelete, - onUpdate: relationTmp.onUpdate - }, joinColumnOptions: relationTmp.ownerColumns.map((v, idx) => { const retVal: JoinColumnOptions = { name: v, @@ -392,6 +393,9 @@ export default abstract class AbstractDriver { relatedTable: relationTmp.relatedTable.tscName, relationType: isOneToMany ? "ManyToOne" : "OneToOne" }; + if (JSON.stringify(relationOptions) !== "{}") { + ownerRelation.relationOptions = relationOptions; + } const relatedRelation: Relation = { fieldName: ownerRelation.relatedField, relatedField: ownerRelation.fieldName, diff --git a/src/drivers/MssqlDriver.ts b/src/drivers/MssqlDriver.ts index 057357b..1331107 100644 --- a/src/drivers/MssqlDriver.ts +++ b/src/drivers/MssqlDriver.ts @@ -4,13 +4,12 @@ import * as TypeormDriver from "typeorm/driver/sqlserver/SqlServerDriver"; import { DataTypeDefaults } from "typeorm/driver/types/DataTypeDefaults"; import * as TomgUtils from "../Utils"; import AbstractDriver from "./AbstractDriver"; -import EntityInfo from "../oldModels/EntityInfo"; -import ColumnInfo from "../oldModels/ColumnInfo"; -import IndexInfo from "../oldModels/IndexInfo"; -import IndexColumnInfo from "../oldModels/IndexColumnInfo"; -import RelationTempInfo from "../oldModels/RelationTempInfo"; import IConnectionOptions from "../IConnectionOptions"; import { Entity } from "../models/Entity"; +import { Column } from "../models/Column"; +import { Index } from "../models/Index"; +import IGenerationOptions from "../IGenerationOptions"; +import { RelationInternal } from "../models/RelationInternal"; export default class MssqlDriver extends AbstractDriver { public defaultValues: DataTypeDefaults = new TypeormDriver.SqlServerDriver({ @@ -45,185 +44,193 @@ WHERE TABLE_TYPE='BASE TABLE' and TABLE_SCHEMA in (${schema}) AND TABLE_CATALOG schema: string, dbNames: string ): Promise { - throw new Error(); - // TODO: Remove - // const request = new MSSQL.Request(this.Connection); - // const response: { - // TABLE_NAME: string; - // COLUMN_NAME: string; - // COLUMN_DEFAULT: string; - // IS_NULLABLE: string; - // DATA_TYPE: string; - // CHARACTER_MAXIMUM_LENGTH: number; - // NUMERIC_PRECISION: number; - // NUMERIC_SCALE: number; - // IsIdentity: number; - // IsUnique: number; - // }[] = (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(*) - // FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS tc - // inner join INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE cu - // on cu.CONSTRAINT_NAME = tc.CONSTRAINT_NAME - // where - // tc.CONSTRAINT_TYPE = 'UNIQUE' - // and tc.TABLE_NAME = c.TABLE_NAME - // and cu.COLUMN_NAME = c.COLUMN_NAME - // and tc.TABLE_SCHEMA=c.TABLE_SCHEMA) IsUnique - // FROM INFORMATION_SCHEMA.COLUMNS c - // where TABLE_SCHEMA in (${schema}) AND TABLE_CATALOG in (${MssqlDriver.escapeCommaSeparatedList( - // dbNames - // )}) - // order by ordinal_position`)).recordset; - // entities.forEach(ent => { - // response - // .filter(filterVal => { - // return filterVal.TABLE_NAME === ent.tsEntityName; - // }) - // .forEach(resp => { - // const colInfo: ColumnInfo = new ColumnInfo(); - // colInfo.tsName = resp.COLUMN_NAME; - // colInfo.options.name = resp.COLUMN_NAME; - // colInfo.options.nullable = resp.IS_NULLABLE === "YES"; - // colInfo.options.generated = resp.IsIdentity === 1; - // colInfo.options.unique = resp.IsUnique === 1; - // colInfo.options.default = MssqlDriver.ReturnDefaultValueFunction( - // resp.COLUMN_DEFAULT - // ); - // colInfo.options.type = resp.DATA_TYPE as any; - // switch (resp.DATA_TYPE) { - // case "bigint": - // colInfo.tsType = "string"; - // break; - // case "bit": - // colInfo.tsType = "boolean"; - // break; - // case "decimal": - // colInfo.tsType = "number"; - // break; - // case "int": - // colInfo.tsType = "number"; - // break; - // case "money": - // colInfo.tsType = "number"; - // break; - // case "numeric": - // colInfo.tsType = "number"; - // break; - // case "smallint": - // colInfo.tsType = "number"; - // break; - // case "smallmoney": - // colInfo.tsType = "number"; - // break; - // case "tinyint": - // colInfo.tsType = "number"; - // break; - // case "float": - // colInfo.tsType = "number"; - // break; - // case "real": - // colInfo.tsType = "number"; - // break; - // case "date": - // colInfo.tsType = "Date"; - // break; - // case "datetime2": - // colInfo.tsType = "Date"; - // break; - // case "datetime": - // colInfo.tsType = "Date"; - // break; - // case "datetimeoffset": - // colInfo.tsType = "Date"; - // break; - // case "smalldatetime": - // colInfo.tsType = "Date"; - // break; - // case "time": - // colInfo.tsType = "Date"; - // break; - // case "char": - // colInfo.tsType = "string"; - // break; - // case "text": - // colInfo.tsType = "string"; - // break; - // case "varchar": - // colInfo.tsType = "string"; - // break; - // case "nchar": - // colInfo.tsType = "string"; - // break; - // case "ntext": - // colInfo.tsType = "string"; - // break; - // case "nvarchar": - // colInfo.tsType = "string"; - // break; - // case "binary": - // colInfo.tsType = "Buffer"; - // break; - // case "image": - // colInfo.tsType = "Buffer"; - // break; - // case "varbinary": - // colInfo.tsType = "Buffer"; - // break; - // case "hierarchyid": - // colInfo.tsType = "string"; - // break; - // case "sql_variant": - // colInfo.tsType = "string"; - // break; - // case "timestamp": - // colInfo.tsType = "Date"; - // break; - // case "uniqueidentifier": - // colInfo.tsType = "string"; - // break; - // case "xml": - // colInfo.tsType = "string"; - // break; - // case "geometry": - // colInfo.tsType = "string"; - // break; - // case "geography": - // colInfo.tsType = "string"; - // break; - // default: - // TomgUtils.LogError( - // `Unknown column type: ${resp.DATA_TYPE} table name: ${resp.TABLE_NAME} column name: ${resp.COLUMN_NAME}` - // ); - // break; - // } + const request = new MSSQL.Request(this.Connection); + const response: { + TABLE_NAME: string; + COLUMN_NAME: string; + COLUMN_DEFAULT: string; + IS_NULLABLE: string; + DATA_TYPE: string; + CHARACTER_MAXIMUM_LENGTH: number; + NUMERIC_PRECISION: number; + NUMERIC_SCALE: number; + IsIdentity: number; + IsUnique: number; + }[] = (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(*) + FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS tc + inner join INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE cu + on cu.CONSTRAINT_NAME = tc.CONSTRAINT_NAME + where + tc.CONSTRAINT_TYPE = 'UNIQUE' + and tc.TABLE_NAME = c.TABLE_NAME + and cu.COLUMN_NAME = c.COLUMN_NAME + and tc.TABLE_SCHEMA=c.TABLE_SCHEMA) IsUnique + FROM INFORMATION_SCHEMA.COLUMNS c + where TABLE_SCHEMA in (${schema}) AND TABLE_CATALOG in (${MssqlDriver.escapeCommaSeparatedList( + dbNames + )}) + order by ordinal_position`)).recordset; + entities.forEach(ent => { + response + .filter(filterVal => { + return filterVal.TABLE_NAME === ent.tscName; + }) + .forEach(resp => { + const tscName = resp.COLUMN_NAME; + const options: Partial = {}; + options.name = resp.COLUMN_NAME; + if (resp.IS_NULLABLE === "YES") options.nullable = true; + if (resp.IsUnique === 1) options.unique = true; + const generated = resp.IsIdentity === 1 ? true : undefined; + const defaultValue = MssqlDriver.ReturnDefaultValueFunction( + resp.COLUMN_DEFAULT + ); + const columnType = resp.DATA_TYPE as any; + let tscType = ""; + switch (resp.DATA_TYPE) { + case "bigint": + tscType = "string"; + break; + case "bit": + tscType = "boolean"; + break; + case "decimal": + tscType = "number"; + break; + case "int": + tscType = "number"; + break; + case "money": + tscType = "number"; + break; + case "numeric": + tscType = "number"; + break; + case "smallint": + tscType = "number"; + break; + case "smallmoney": + tscType = "number"; + break; + case "tinyint": + tscType = "number"; + break; + case "float": + tscType = "number"; + break; + case "real": + tscType = "number"; + break; + case "date": + tscType = "Date"; + break; + case "datetime2": + tscType = "Date"; + break; + case "datetime": + tscType = "Date"; + break; + case "datetimeoffset": + tscType = "Date"; + break; + case "smalldatetime": + tscType = "Date"; + break; + case "time": + tscType = "Date"; + break; + case "char": + tscType = "string"; + break; + case "text": + tscType = "string"; + break; + case "varchar": + tscType = "string"; + break; + case "nchar": + tscType = "string"; + break; + case "ntext": + tscType = "string"; + break; + case "nvarchar": + tscType = "string"; + break; + case "binary": + tscType = "Buffer"; + break; + case "image": + tscType = "Buffer"; + break; + case "varbinary": + tscType = "Buffer"; + break; + case "hierarchyid": + tscType = "string"; + break; + case "sql_variant": + tscType = "string"; + break; + case "timestamp": + tscType = "Date"; + break; + case "uniqueidentifier": + tscType = "string"; + break; + case "xml": + tscType = "string"; + break; + case "geometry": + tscType = "string"; + break; + case "geography": + tscType = "string"; + break; + default: + TomgUtils.LogError( + `Unknown column type: ${resp.DATA_TYPE} table name: ${resp.TABLE_NAME} column name: ${resp.COLUMN_NAME}` + ); + break; + } - // if ( - // this.ColumnTypesWithPrecision.some( - // v => v === colInfo.options.type - // ) - // ) { - // colInfo.options.precision = resp.NUMERIC_PRECISION; - // colInfo.options.scale = resp.NUMERIC_SCALE; - // } - // if ( - // this.ColumnTypesWithLength.some( - // v => v === colInfo.options.type - // ) - // ) { - // colInfo.options.length = - // resp.CHARACTER_MAXIMUM_LENGTH > 0 - // ? resp.CHARACTER_MAXIMUM_LENGTH - // : undefined; - // } + if ( + this.ColumnTypesWithPrecision.some( + v => v === columnType + ) + ) { + if (resp.NUMERIC_PRECISION !== null) { + options.precision = resp.NUMERIC_PRECISION; + } + if (resp.NUMERIC_SCALE !== null) { + options.scale = resp.NUMERIC_SCALE; + } + } + if ( + this.ColumnTypesWithLength.some(v => v === columnType) + ) { + options.length = + resp.CHARACTER_MAXIMUM_LENGTH > 0 + ? resp.CHARACTER_MAXIMUM_LENGTH + : undefined; + } - // if (colInfo.options.type) { - // ent.Columns.push(colInfo); - // } - // }); - // }); - // return entities; + if (columnType) { + ent.columns.push({ + generated, + type: columnType, + default: defaultValue, + options: { name: "", ...options }, // TODO: Change + tscName, + tscType + }); + } + }); + }); + return entities; } public async GetIndexesFromEntity( @@ -231,181 +238,189 @@ WHERE TABLE_TYPE='BASE TABLE' and TABLE_SCHEMA in (${schema}) AND TABLE_CATALOG schema: string, dbNames: string ): Promise { - throw new Error(); - // TODO: Remove - // const request = new MSSQL.Request(this.Connection); - // const response: { - // TableName: string; - // IndexName: string; - // ColumnName: string; - // is_unique: boolean; - // is_primary_key: boolean; - // }[] = []; - // await Promise.all( - // dbNames.split(",").map(async dbName => { - // await this.UseDB(dbName); - // const resp: { - // TableName: string; - // IndexName: string; - // ColumnName: string; - // is_unique: boolean; - // is_primary_key: boolean; - // }[] = (await request.query(`SELECT - // TableName = t.name, - // IndexName = ind.name, - // ColumnName = col.name, - // ind.is_unique, - // ind.is_primary_key - // FROM - // sys.indexes ind - // INNER JOIN - // sys.index_columns ic ON ind.object_id = ic.object_id and ind.index_id = ic.index_id - // INNER JOIN - // sys.columns col ON ic.object_id = col.object_id and ic.column_id = col.column_id - // INNER JOIN - // sys.tables t ON ind.object_id = t.object_id - // INNER JOIN - // sys.schemas s on s.schema_id=t.schema_id - // WHERE - // t.is_ms_shipped = 0 and s.name in (${schema}) - // ORDER BY - // t.name, ind.name, ind.index_id, ic.key_ordinal;`)).recordset; - // response.push(...resp); - // }) - // ); - // entities.forEach(ent => { - // response - // .filter(filterVal => filterVal.TableName === ent.tsEntityName) - // .forEach(resp => { - // let indexInfo: IndexInfo = {} as IndexInfo; - // const indexColumnInfo: IndexColumnInfo = {} as IndexColumnInfo; - // if ( - // ent.Indexes.filter(filterVal => { - // return filterVal.name === resp.IndexName; - // }).length > 0 - // ) { - // [indexInfo] = ent.Indexes.filter(filterVal => { - // return filterVal.name === resp.IndexName; - // }); - // } else { - // indexInfo.columns = [] as IndexColumnInfo[]; - // indexInfo.name = resp.IndexName; - // indexInfo.isUnique = resp.is_unique; - // indexInfo.isPrimaryKey = resp.is_primary_key; - // ent.Indexes.push(indexInfo); - // } - // indexColumnInfo.name = resp.ColumnName; - // indexInfo.columns.push(indexColumnInfo); - // }); - // }); + const request = new MSSQL.Request(this.Connection); + const response: { + TableName: string; + IndexName: string; + ColumnName: string; + is_unique: boolean; + is_primary_key: boolean; + }[] = []; + await Promise.all( + dbNames.split(",").map(async dbName => { + await this.UseDB(dbName); + const resp: { + TableName: string; + IndexName: string; + ColumnName: string; + is_unique: boolean; + is_primary_key: boolean; + }[] = (await request.query(`SELECT + TableName = t.name, + IndexName = ind.name, + ColumnName = col.name, + ind.is_unique, + ind.is_primary_key + FROM + sys.indexes ind + INNER JOIN + sys.index_columns ic ON ind.object_id = ic.object_id and ind.index_id = ic.index_id + INNER JOIN + sys.columns col ON ic.object_id = col.object_id and ic.column_id = col.column_id + INNER JOIN + sys.tables t ON ind.object_id = t.object_id + INNER JOIN + sys.schemas s on s.schema_id=t.schema_id + WHERE + t.is_ms_shipped = 0 and s.name in (${schema}) + ORDER BY + t.name, ind.name, ind.index_id, ic.key_ordinal;`)).recordset; + response.push(...resp); + }) + ); - // return entities; + entities.forEach(ent => { + const entityIndices = response.filter( + filterVal => filterVal.TableName === ent.tscName + ); + const indexNames = new Set(entityIndices.map(v => v.IndexName)); + indexNames.forEach(indexName => { + const records = entityIndices.filter( + v => v.IndexName === indexName + ); + const indexInfo: Index = { + columns: [], + options: {}, + name: records[0].IndexName + }; + if (records[0].is_primary_key) indexInfo.primary = true; + if (records[0].is_unique) indexInfo.options.unique = true; + records.forEach(record => { + indexInfo.columns.push(record.ColumnName); + }); + ent.indices.push(indexInfo); + }); + }); + + return entities; } public async GetRelations( entities: Entity[], schema: string, - dbNames: string + dbNames: string, + generationOptions: IGenerationOptions ): Promise { - throw new Error(); - // TODO: Remove - // const request = new MSSQL.Request(this.Connection); - // const response: { - // TableWithForeignKey: string; - // FK_PartNo: number; - // ForeignKeyColumn: string; - // TableReferenced: string; - // ForeignKeyColumnReferenced: string; - // onDelete: "RESTRICT" | "CASCADE" | "SET_NULL" | "NO_ACTION"; - // onUpdate: "RESTRICT" | "CASCADE" | "SET_NULL" | "NO_ACTION"; - // objectId: number; - // }[] = []; - // await Promise.all( - // dbNames.split(",").map(async dbName => { - // await this.UseDB(dbName); - // const resp: { - // TableWithForeignKey: string; - // FK_PartNo: number; - // ForeignKeyColumn: string; - // TableReferenced: string; - // ForeignKeyColumnReferenced: string; - // onDelete: "RESTRICT" | "CASCADE" | "SET_NULL" | "NO_ACTION"; - // onUpdate: "RESTRICT" | "CASCADE" | "SET_NULL" | "NO_ACTION"; - // objectId: number; - // }[] = (await request.query(`select - // parentTable.name as TableWithForeignKey, - // fkc.constraint_column_id as FK_PartNo, - // parentColumn.name as ForeignKeyColumn, - // referencedTable.name as TableReferenced, - // referencedColumn.name as ForeignKeyColumnReferenced, - // fk.delete_referential_action_desc as onDelete, - // fk.update_referential_action_desc as onUpdate, - // fk.object_id as objectId - // from - // sys.foreign_keys fk - // inner join - // sys.foreign_key_columns as fkc on fkc.constraint_object_id=fk.object_id - // inner join - // sys.tables as parentTable on fkc.parent_object_id = parentTable.object_id - // inner join - // sys.columns as parentColumn on fkc.parent_object_id = parentColumn.object_id and fkc.parent_column_id = parentColumn.column_id - // inner join - // sys.tables as referencedTable on fkc.referenced_object_id = referencedTable.object_id - // inner join - // sys.columns as referencedColumn on fkc.referenced_object_id = referencedColumn.object_id and fkc.referenced_column_id = referencedColumn.column_id - // inner join - // sys.schemas as parentSchema on parentSchema.schema_id=parentTable.schema_id - // where - // fk.is_disabled=0 and fk.is_ms_shipped=0 and parentSchema.name in (${schema}) - // order by - // TableWithForeignKey, FK_PartNo`)).recordset; - // response.push(...resp); - // }) - // ); - // const relationsTemp: RelationTempInfo[] = [] as RelationTempInfo[]; - // response.forEach(resp => { - // let rels = relationsTemp.find( - // val => val.objectId === resp.objectId - // ); - // if (rels === undefined) { - // rels = {} as RelationTempInfo; - // rels.ownerColumnsNames = []; - // rels.referencedColumnsNames = []; - // switch (resp.onDelete) { - // case "NO_ACTION": - // rels.actionOnDelete = null; - // break; - // case "SET_NULL": - // rels.actionOnDelete = "SET NULL"; - // break; - // default: - // rels.actionOnDelete = resp.onDelete; - // break; - // } - // switch (resp.onUpdate) { - // case "NO_ACTION": - // rels.actionOnUpdate = null; - // break; - // case "SET_NULL": - // rels.actionOnUpdate = "SET NULL"; - // break; - // default: - // rels.actionOnUpdate = resp.onUpdate; - // break; - // } - // rels.objectId = resp.objectId; - // rels.ownerTable = resp.TableWithForeignKey; - // rels.referencedTable = resp.TableReferenced; - // relationsTemp.push(rels); - // } - // rels.ownerColumnsNames.push(resp.ForeignKeyColumn); - // rels.referencedColumnsNames.push(resp.ForeignKeyColumnReferenced); - // }); - // const retVal = MssqlDriver.GetRelationsFromRelationTempInfo( - // relationsTemp, - // entities - // ); - // return retVal; + const request = new MSSQL.Request(this.Connection); + const response: { + TableWithForeignKey: string; + FK_PartNo: number; + ForeignKeyColumn: string; + TableReferenced: string; + ForeignKeyColumnReferenced: string; + onDelete: "RESTRICT" | "CASCADE" | "SET_NULL" | "NO_ACTION"; + onUpdate: "RESTRICT" | "CASCADE" | "SET_NULL" | "NO_ACTION"; + objectId: number; + }[] = []; + await Promise.all( + dbNames.split(",").map(async dbName => { + await this.UseDB(dbName); + const resp: { + TableWithForeignKey: string; + FK_PartNo: number; + ForeignKeyColumn: string; + TableReferenced: string; + ForeignKeyColumnReferenced: string; + onDelete: "RESTRICT" | "CASCADE" | "SET_NULL" | "NO_ACTION"; + onUpdate: "RESTRICT" | "CASCADE" | "SET_NULL" | "NO_ACTION"; + objectId: number; + }[] = (await request.query(`select + parentTable.name as TableWithForeignKey, + fkc.constraint_column_id as FK_PartNo, + parentColumn.name as ForeignKeyColumn, + referencedTable.name as TableReferenced, + referencedColumn.name as ForeignKeyColumnReferenced, + fk.delete_referential_action_desc as onDelete, + fk.update_referential_action_desc as onUpdate, + fk.object_id as objectId + from + sys.foreign_keys fk + inner join + sys.foreign_key_columns as fkc on fkc.constraint_object_id=fk.object_id + inner join + sys.tables as parentTable on fkc.parent_object_id = parentTable.object_id + inner join + sys.columns as parentColumn on fkc.parent_object_id = parentColumn.object_id and fkc.parent_column_id = parentColumn.column_id + inner join + sys.tables as referencedTable on fkc.referenced_object_id = referencedTable.object_id + inner join + sys.columns as referencedColumn on fkc.referenced_object_id = referencedColumn.object_id and fkc.referenced_column_id = referencedColumn.column_id + inner join + sys.schemas as parentSchema on parentSchema.schema_id=parentTable.schema_id + where + fk.is_disabled=0 and fk.is_ms_shipped=0 and parentSchema.name in (${schema}) + order by + TableWithForeignKey, FK_PartNo`)).recordset; + response.push(...resp); + }) + ); + const relationsTemp: RelationInternal[] = [] as RelationInternal[]; + const relationKeys = new Set(response.map(v => v.objectId)); + + relationKeys.forEach(relationId => { + const rows = response.filter(v => v.objectId === relationId); + const ownerTable = entities.find( + v => v.sqlName === rows[0].TableWithForeignKey + ); + const relatedTable = entities.find( + v => v.sqlName === rows[0].TableReferenced + ); + if (!ownerTable || !relatedTable) { + TomgUtils.LogError( + `Relation between tables ${rows[0].TableWithForeignKey} and ${rows[0].TableReferenced} wasn't found in entity model.`, + true + ); + return; + } + const internal: RelationInternal = { + ownerColumns: [], + relatedColumns: [], + ownerTable, + relatedTable + }; + switch (rows[0].onDelete) { + case "NO_ACTION": + break; + case "SET_NULL": + internal.onDelete = "SET NULL"; + break; + default: + internal.onDelete = rows[0].onDelete; + break; + } + switch (rows[0].onUpdate) { + case "NO_ACTION": + break; + case "SET_NULL": + internal.onUpdate = "SET NULL"; + break; + default: + internal.onUpdate = rows[0].onUpdate; + break; + } + rows.forEach(row => { + internal.ownerColumns.push(row.ForeignKeyColumn); + internal.relatedColumns.push(row.ForeignKeyColumnReferenced); + }); + relationsTemp.push(internal); + }); + + const retVal = MssqlDriver.GetRelationsFromRelationTempInfo( + relationsTemp, + entities, + generationOptions + ); + return retVal; } public async DisconnectFromServer() { @@ -472,10 +487,10 @@ WHERE TABLE_TYPE='BASE TABLE' and TABLE_SCHEMA in (${schema}) AND TABLE_CATALOG private static ReturnDefaultValueFunction( defVal: string | null - ): string | null { + ): string | undefined { let defaultValue = defVal; if (!defaultValue) { - return null; + return undefined; } if (defaultValue.startsWith("(") && defaultValue.endsWith(")")) { defaultValue = defaultValue.slice(1, -1); diff --git a/test/integration/entityTypes/mssql/entity/Post.ts b/test/integration/entityTypes/mssql/entity/Post.ts index dc00e73..3f15287 100644 --- a/test/integration/entityTypes/mssql/entity/Post.ts +++ b/test/integration/entityTypes/mssql/entity/Post.ts @@ -2,7 +2,6 @@ import { Entity, PrimaryColumn, Column } from "typeorm"; @Entity("Post") export class Post { - @PrimaryColumn() id: number; @@ -91,7 +90,7 @@ export class Post { hierarchyid: string; @Column("sql_variant") - sql_variant: string; + sqlVariant: string; @Column("timestamp") timestamp: Date; @@ -107,5 +106,4 @@ export class Post { @Column("geography") geography: string; - } diff --git a/test/integration/github-issues/39/entity/Post.ts b/test/integration/github-issues/39/entity/Post.ts index f5ad32b..52b18d8 100644 --- a/test/integration/github-issues/39/entity/Post.ts +++ b/test/integration/github-issues/39/entity/Post.ts @@ -18,9 +18,9 @@ export class Post { }) id: number; - @ManyToOne(type => User, userId => userId.posts) + @ManyToOne(type => User, user => user.posts) @JoinColumn({ name: "userId" }) - userId: User; + user: User; @Column("text", { nullable: true, diff --git a/test/integration/github-issues/39/entity/User.ts b/test/integration/github-issues/39/entity/User.ts index 6736995..8370780 100644 --- a/test/integration/github-issues/39/entity/User.ts +++ b/test/integration/github-issues/39/entity/User.ts @@ -1,26 +1,29 @@ -import {Index,Entity, PrimaryColumn, Column, OneToOne, OneToMany, ManyToOne, JoinColumn} from "typeorm"; -import {Post} from "./Post"; +import { + Index, + Entity, + PrimaryColumn, + Column, + OneToOne, + OneToMany, + ManyToOne, + JoinColumn +} from "typeorm"; +import { Post } from "./Post"; - -@Entity("User",{schema:"sch2"}) +@Entity("User", { schema: "sch2" }) export class User { + @Column("integer", { + primary: true, + name: "id" + }) + id: number; - @Column("integer",{ - primary:true, - name:"id" - }) - id:number; - - - @Column("text",{ - nullable:true, - name:"name" - }) - name:string; - - - - @OneToMany(type=>Post, posts=>posts.userId) - posts:Post[]; + @Column("text", { + nullable: true, + name: "name" + }) + name: string; + @OneToMany(type => Post, posts => posts.user) + posts: Post[]; } From d1407ab5d946d12419fba615a7b92b272ad124e3 Mon Sep 17 00:00:00 2001 From: Kononnable Date: Thu, 10 Oct 2019 22:18:22 +0200 Subject: [PATCH 20/84] oracledb implementation --- src/drivers/OracleDriver.ts | 519 +++++++++--------- .../entityTypes/oracle/entity/Post.ts | 12 +- .../sample18-lazy-relations/entity/Post.ts | 4 +- 3 files changed, 278 insertions(+), 257 deletions(-) diff --git a/src/drivers/OracleDriver.ts b/src/drivers/OracleDriver.ts index d58eeba..971044a 100644 --- a/src/drivers/OracleDriver.ts +++ b/src/drivers/OracleDriver.ts @@ -2,13 +2,12 @@ import * as TypeormDriver from "typeorm/driver/oracle/OracleDriver"; import { DataTypeDefaults } from "typeorm/driver/types/DataTypeDefaults"; import * as TomgUtils from "../Utils"; import AbstractDriver from "./AbstractDriver"; -import EntityInfo from "../oldModels/EntityInfo"; -import ColumnInfo from "../oldModels/ColumnInfo"; -import IndexInfo from "../oldModels/IndexInfo"; -import IndexColumnInfo from "../oldModels/IndexColumnInfo"; -import RelationTempInfo from "../oldModels/RelationTempInfo"; import IConnectionOptions from "../IConnectionOptions"; import { Entity } from "../models/Entity"; +import { Column } from "../models/Column"; +import { Index } from "../models/Index"; +import IGenerationOptions from "../IGenerationOptions"; +import { RelationInternal } from "../models/RelationInternal"; export default class OracleDriver extends AbstractDriver { public defaultValues: DataTypeDefaults = new TypeormDriver.OracleDriver({ @@ -49,257 +48,281 @@ export default class OracleDriver extends AbstractDriver { }; public async GetCoulmnsFromEntity(entities: Entity[]): Promise { - throw new Error(); - // TODO: Remove - // const response: { - // TABLE_NAME: string; - // COLUMN_NAME: string; - // DATA_DEFAULT: string; - // NULLABLE: string; - // DATA_TYPE: string; - // DATA_LENGTH: number; - // DATA_PRECISION: number; - // DATA_SCALE: number; - // IDENTITY_COLUMN: string; - // 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 - // JOIN USER_CONSTRAINTS uc ON uc.CONSTRAINT_NAME = ucc.CONSTRAINT_NAME and uc.CONSTRAINT_TYPE='U' - // where ucc.column_name = utc.COLUMN_NAME AND ucc.table_name = utc.TABLE_NAME) IS_UNIQUE - // FROM USER_TAB_COLUMNS utc`)).rows!; + const response: { + TABLE_NAME: string; + COLUMN_NAME: string; + DATA_DEFAULT: string; + NULLABLE: string; + DATA_TYPE: string; + DATA_LENGTH: number; + DATA_PRECISION: number; + DATA_SCALE: number; + IDENTITY_COLUMN: string; + 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 + JOIN USER_CONSTRAINTS uc ON uc.CONSTRAINT_NAME = ucc.CONSTRAINT_NAME and uc.CONSTRAINT_TYPE='U' + where ucc.column_name = utc.COLUMN_NAME AND ucc.table_name = utc.TABLE_NAME) IS_UNIQUE + FROM USER_TAB_COLUMNS utc`)).rows!; - // entities.forEach(ent => { - // response - // .filter(filterVal => filterVal.TABLE_NAME === ent.tsEntityName) - // .forEach(resp => { - // const colInfo: ColumnInfo = new ColumnInfo(); - // colInfo.tsName = resp.COLUMN_NAME; - // colInfo.options.name = resp.COLUMN_NAME; - // colInfo.options.nullable = resp.NULLABLE === "Y"; - // colInfo.options.generated = resp.IDENTITY_COLUMN === "YES"; - // colInfo.options.default = - // !resp.DATA_DEFAULT || resp.DATA_DEFAULT.includes('"') - // ? null - // : OracleDriver.ReturnDefaultValueFunction( - // resp.DATA_DEFAULT - // ); - // colInfo.options.unique = resp.IS_UNIQUE > 0; - // const DATA_TYPE = resp.DATA_TYPE.replace(/\([0-9]+\)/g, ""); - // colInfo.options.type = DATA_TYPE.toLowerCase() as any; - // switch (DATA_TYPE.toLowerCase()) { - // case "char": - // colInfo.tsType = "string"; - // break; - // case "nchar": - // colInfo.tsType = "string"; - // break; - // case "nvarchar2": - // colInfo.tsType = "string"; - // break; - // case "varchar2": - // colInfo.tsType = "string"; - // break; - // case "long": - // colInfo.tsType = "string"; - // break; - // case "raw": - // colInfo.tsType = "Buffer"; - // break; - // case "long raw": - // colInfo.tsType = "Buffer"; - // break; - // case "number": - // colInfo.tsType = "number"; - // break; - // case "numeric": - // colInfo.tsType = "number"; - // break; - // case "float": - // colInfo.tsType = "number"; - // break; - // case "dec": - // colInfo.tsType = "number"; - // break; - // case "decimal": - // colInfo.tsType = "number"; - // break; - // case "integer": - // colInfo.tsType = "number"; - // break; - // case "int": - // colInfo.tsType = "number"; - // break; - // case "smallint": - // colInfo.tsType = "number"; - // break; - // case "real": - // colInfo.tsType = "number"; - // break; - // case "double precision": - // colInfo.tsType = "number"; - // break; - // case "date": - // colInfo.tsType = "Date"; - // break; - // case "timestamp": - // colInfo.tsType = "Date"; - // break; - // case "timestamp with time zone": - // colInfo.tsType = "Date"; - // break; - // case "timestamp with local time zone": - // colInfo.tsType = "Date"; - // break; - // case "interval year to month": - // colInfo.tsType = "string"; - // break; - // case "interval day to second": - // colInfo.tsType = "string"; - // break; - // case "bfile": - // colInfo.tsType = "Buffer"; - // break; - // case "blob": - // colInfo.tsType = "Buffer"; - // break; - // case "clob": - // colInfo.tsType = "string"; - // break; - // case "nclob": - // colInfo.tsType = "string"; - // break; - // case "rowid": - // colInfo.tsType = "number"; - // break; - // case "urowid": - // colInfo.tsType = "number"; - // break; - // default: - // TomgUtils.LogError( - // `Unknown column type:${DATA_TYPE}` - // ); - // break; - // } - // if ( - // this.ColumnTypesWithPrecision.some( - // v => v === colInfo.options.type - // ) - // ) { - // colInfo.options.precision = resp.DATA_PRECISION; - // colInfo.options.scale = resp.DATA_SCALE; - // } - // if ( - // this.ColumnTypesWithLength.some( - // v => v === colInfo.options.type - // ) - // ) { - // colInfo.options.length = - // resp.DATA_LENGTH > 0 ? resp.DATA_LENGTH : undefined; - // } + entities.forEach(ent => { + response + .filter(filterVal => filterVal.TABLE_NAME === ent.tscName) + .forEach(resp => { + const tscName = resp.COLUMN_NAME; + const options: Partial = {}; + options.name = resp.COLUMN_NAME; + if (resp.NULLABLE === "Y") options.nullable = true; + if (resp.IS_UNIQUE > 0) options.unique = true; + const generated = + resp.IDENTITY_COLUMN === "YES" ? true : undefined; + const defaultValue = + !resp.DATA_DEFAULT || resp.DATA_DEFAULT.includes('"') + ? undefined + : OracleDriver.ReturnDefaultValueFunction( + resp.DATA_DEFAULT + ); + const DATA_TYPE = resp.DATA_TYPE.replace(/\([0-9]+\)/g, ""); + const columnType = DATA_TYPE.toLowerCase() as any; + let tscType = ""; + switch (DATA_TYPE.toLowerCase()) { + case "char": + tscType = "string"; + break; + case "nchar": + tscType = "string"; + break; + case "nvarchar2": + tscType = "string"; + break; + case "varchar2": + tscType = "string"; + break; + case "long": + tscType = "string"; + break; + case "raw": + tscType = "Buffer"; + break; + case "long raw": + tscType = "Buffer"; + break; + case "number": + tscType = "number"; + break; + case "numeric": + tscType = "number"; + break; + case "float": + tscType = "number"; + break; + case "dec": + tscType = "number"; + break; + case "decimal": + tscType = "number"; + break; + case "integer": + tscType = "number"; + break; + case "int": + tscType = "number"; + break; + case "smallint": + tscType = "number"; + break; + case "real": + tscType = "number"; + break; + case "double precision": + tscType = "number"; + break; + case "date": + tscType = "Date"; + break; + case "timestamp": + tscType = "Date"; + break; + case "timestamp with time zone": + tscType = "Date"; + break; + case "timestamp with local time zone": + tscType = "Date"; + break; + case "interval year to month": + tscType = "string"; + break; + case "interval day to second": + tscType = "string"; + break; + case "bfile": + tscType = "Buffer"; + break; + case "blob": + tscType = "Buffer"; + break; + case "clob": + tscType = "string"; + break; + case "nclob": + tscType = "string"; + break; + case "rowid": + tscType = "number"; + break; + case "urowid": + tscType = "number"; + break; + default: + TomgUtils.LogError( + `Unknown column type:${DATA_TYPE}` + ); + break; + } + if ( + this.ColumnTypesWithPrecision.some( + v => v === columnType + ) + ) { + if (resp.DATA_PRECISION !== null) { + options.precision = resp.DATA_PRECISION; + } + if (resp.DATA_SCALE !== null) { + options.scale = resp.DATA_SCALE; + } + } + if ( + this.ColumnTypesWithLength.some(v => v === columnType) + ) { + options.length = + resp.DATA_LENGTH > 0 ? resp.DATA_LENGTH : undefined; + } - // if (colInfo.options.type) { - // ent.Columns.push(colInfo); - // } - // }); - // }); - // return entities; + if (columnType) { + ent.columns.push({ + generated, + type: columnType, + default: defaultValue, + options: { name: "", ...options }, // TODO: Change + tscName, + tscType + }); + } + }); + }); + return entities; } public async GetIndexesFromEntity(entities: Entity[]): Promise { - throw new Error(); - // TODO: Remove - // const response: { - // COLUMN_NAME: string; - // TABLE_NAME: string; - // INDEX_NAME: string; - // UNIQUENESS: string; - // ISPRIMARYKEY: number; - // }[] = (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 - // LEFT JOIN USER_CONSTRAINTS uc ON uc.INDEX_NAME = ind.INDEX_NAME - // ORDER BY col.INDEX_NAME ASC ,col.COLUMN_POSITION ASC`)).rows!; + const response: { + COLUMN_NAME: string; + TABLE_NAME: string; + INDEX_NAME: string; + UNIQUENESS: string; + ISPRIMARYKEY: number; + }[] = (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 + LEFT JOIN USER_CONSTRAINTS uc ON uc.INDEX_NAME = ind.INDEX_NAME + ORDER BY col.INDEX_NAME ASC ,col.COLUMN_POSITION ASC`)).rows!; - // entities.forEach(ent => { - // response - // .filter(filterVal => filterVal.TABLE_NAME === ent.tsEntityName) - // .forEach(resp => { - // let indexInfo: IndexInfo = {} as IndexInfo; - // const indexColumnInfo: IndexColumnInfo = {} as IndexColumnInfo; - // if ( - // ent.Indexes.filter( - // filterVal => filterVal.name === resp.INDEX_NAME - // ).length > 0 - // ) { - // indexInfo = ent.Indexes.find( - // filterVal => filterVal.name === resp.INDEX_NAME - // )!; - // } else { - // indexInfo.columns = [] as IndexColumnInfo[]; - // indexInfo.name = resp.INDEX_NAME; - // indexInfo.isUnique = resp.UNIQUENESS === "UNIQUE"; - // indexInfo.isPrimaryKey = resp.ISPRIMARYKEY === 1; - // ent.Indexes.push(indexInfo); - // } - // indexColumnInfo.name = resp.COLUMN_NAME; - // indexInfo.columns.push(indexColumnInfo); - // }); - // }); + entities.forEach(ent => { + const entityIndices = response.filter( + filterVal => filterVal.TABLE_NAME === ent.tscName + ); + const indexNames = new Set(entityIndices.map(v => v.INDEX_NAME)); + indexNames.forEach(indexName => { + const records = entityIndices.filter( + v => v.INDEX_NAME === indexName + ); + const indexInfo: Index = { + columns: [], + options: {}, + name: records[0].INDEX_NAME + }; + if (records[0].ISPRIMARYKEY === 1) indexInfo.primary = true; + if (records[0].UNIQUENESS === "UNIQUE") + indexInfo.options.unique = true; + records.forEach(record => { + indexInfo.columns.push(record.COLUMN_NAME); + }); + ent.indices.push(indexInfo); + }); + }); - // return entities; + return entities; } - public async GetRelations(entities: Entity[]): Promise { - throw new Error(); - // TODO: Remove - // const response: { - // OWNER_TABLE_NAME: string; - // OWNER_POSITION: string; - // OWNER_COLUMN_NAME: string; - // CHILD_TABLE_NAME: string; - // CHILD_COLUMN_NAME: string; - // DELETE_RULE: "RESTRICT" | "CASCADE" | "SET NULL" | "NO ACTION"; - // CONSTRAINT_NAME: string; - // }[] = (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, - // owner.CONSTRAINT_NAME - // from user_constraints owner - // join user_constraints child on owner.r_constraint_name=child.CONSTRAINT_NAME and child.constraint_type in ('P','U') - // JOIN USER_CONS_COLUMNS ownCol ON owner.CONSTRAINT_NAME = ownCol.CONSTRAINT_NAME - // JOIN USER_CONS_COLUMNS childCol ON child.CONSTRAINT_NAME = childCol.CONSTRAINT_NAME AND ownCol.POSITION=childCol.POSITION - // ORDER BY OWNER_TABLE_NAME ASC, owner.CONSTRAINT_NAME ASC, OWNER_POSITION ASC`)) - // .rows!; + public async GetRelations( + entities: Entity[], + schema: string, + dbNames: string, + generationOptions: IGenerationOptions + ): Promise { + const response: { + OWNER_TABLE_NAME: string; + OWNER_POSITION: string; + OWNER_COLUMN_NAME: string; + CHILD_TABLE_NAME: string; + CHILD_COLUMN_NAME: string; + DELETE_RULE: "RESTRICT" | "CASCADE" | "SET NULL" | "NO ACTION"; + CONSTRAINT_NAME: string; + }[] = (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, + owner.CONSTRAINT_NAME + from user_constraints owner + join user_constraints child on owner.r_constraint_name=child.CONSTRAINT_NAME and child.constraint_type in ('P','U') + JOIN USER_CONS_COLUMNS ownCol ON owner.CONSTRAINT_NAME = ownCol.CONSTRAINT_NAME + JOIN USER_CONS_COLUMNS childCol ON child.CONSTRAINT_NAME = childCol.CONSTRAINT_NAME AND ownCol.POSITION=childCol.POSITION + ORDER BY OWNER_TABLE_NAME ASC, owner.CONSTRAINT_NAME ASC, OWNER_POSITION ASC`)) + .rows!; - // const relationsTemp: RelationTempInfo[] = [] as RelationTempInfo[]; - // response.forEach(resp => { - // let rels = relationsTemp.find( - // val => val.objectId === resp.CONSTRAINT_NAME - // ); - // if (rels === undefined) { - // rels = {} as RelationTempInfo; - // rels.ownerColumnsNames = []; - // rels.referencedColumnsNames = []; - // rels.actionOnDelete = - // resp.DELETE_RULE === "NO ACTION" ? null : resp.DELETE_RULE; - // rels.actionOnUpdate = null; - // rels.objectId = resp.CONSTRAINT_NAME; - // rels.ownerTable = resp.OWNER_TABLE_NAME; - // rels.referencedTable = resp.CHILD_TABLE_NAME; - // relationsTemp.push(rels); - // } - // rels.ownerColumnsNames.push(resp.OWNER_COLUMN_NAME); - // rels.referencedColumnsNames.push(resp.CHILD_COLUMN_NAME); - // }); - // const retVal = OracleDriver.GetRelationsFromRelationTempInfo( - // relationsTemp, - // entities - // ); - // return retVal; + const relationsTemp: RelationInternal[] = [] as RelationInternal[]; + const relationKeys = new Set(response.map(v => v.CONSTRAINT_NAME)); + + relationKeys.forEach(relationId => { + const rows = response.filter(v => v.CONSTRAINT_NAME === relationId); + const ownerTable = entities.find( + v => v.sqlName === rows[0].OWNER_TABLE_NAME + ); + const relatedTable = entities.find( + v => v.sqlName === rows[0].CHILD_TABLE_NAME + ); + + if (!ownerTable || !relatedTable) { + TomgUtils.LogError( + `Relation between tables ${rows[0].OWNER_TABLE_NAME} and ${rows[0].CHILD_TABLE_NAME} wasn't found in entity model.`, + true + ); + return; + } + const internal: RelationInternal = { + ownerColumns: [], + relatedColumns: [], + ownerTable, + relatedTable + }; + if (rows[0].DELETE_RULE !== "NO ACTION") { + internal.onDelete = rows[0].DELETE_RULE; + } + rows.forEach(row => { + internal.ownerColumns.push(row.OWNER_COLUMN_NAME); + internal.relatedColumns.push(row.CHILD_COLUMN_NAME); + }); + relationsTemp.push(internal); + }); + + const retVal = OracleDriver.GetRelationsFromRelationTempInfo( + relationsTemp, + entities, + generationOptions + ); + return retVal; } public async DisconnectFromServer() { @@ -373,10 +396,10 @@ export default class OracleDriver extends AbstractDriver { private static ReturnDefaultValueFunction( defVal: string | null - ): string | null { + ): string | undefined { let defaultVal = defVal; if (!defaultVal) { - return null; + return undefined; } if (defaultVal.endsWith(" ")) { defaultVal = defaultVal.slice(0, -1); diff --git a/test/integration/entityTypes/oracle/entity/Post.ts b/test/integration/entityTypes/oracle/entity/Post.ts index ea69e96..ced4844 100644 --- a/test/integration/entityTypes/oracle/entity/Post.ts +++ b/test/integration/entityTypes/oracle/entity/Post.ts @@ -2,7 +2,6 @@ import { Entity, PrimaryColumn, Column } from "typeorm"; @Entity("Post") export class Post { - @PrimaryColumn() id: number; @@ -58,7 +57,7 @@ export class Post { real: number; @Column("double precision") - double_precision: number; + doublePrecision: number; @Column("date") date: Date; @@ -67,16 +66,16 @@ export class Post { timestamp: Date; @Column("timestamp with time zone") - timestamp_with_time_zone: Date; + timestampWithTimeZone: Date; @Column("timestamp with local time zone") - timestamp_with_local_time_zone: Date; + timestampWithLocalTimeZone: Date; @Column("interval year to month") - interval_year_to_month: string; + intervalYearToMonth: string; @Column("interval day to second") - interval_day_to_second: string; + intervalDayToSecond: string; @Column("bfile") bfile: Buffer; @@ -95,5 +94,4 @@ export class Post { @Column("urowid") urowid: number; - } diff --git a/test/integration/examples/sample18-lazy-relations/entity/Post.ts b/test/integration/examples/sample18-lazy-relations/entity/Post.ts index 2283783..e5418d6 100644 --- a/test/integration/examples/sample18-lazy-relations/entity/Post.ts +++ b/test/integration/examples/sample18-lazy-relations/entity/Post.ts @@ -24,8 +24,8 @@ export class Post { @ManyToOne(type => Author, author => author.posts, { lazy: true, // cascade: ["insert"], - onDelete: "SET NULL", - onUpdate: "CASCADE" + onDelete: "SET NULL" + // onUpdate: "CASCADE" - onUpdate not supported on oracledb }) author: Promise; From 9c546dfdef5b1177c83f18c7bd79396923d586e3 Mon Sep 17 00:00:00 2001 From: Kononnable Date: Thu, 10 Oct 2019 22:45:04 +0200 Subject: [PATCH 21/84] complex relationships support --- src/drivers/AbstractDriver.ts | 34 +++++++++---------- src/entity.mst | 2 +- .../github-issues/117/entity/Post.ts | 29 ++++++++++++++++ .../github-issues/117/entity/Section.ts | 32 +++++++++++++++++ test/utils/EntityFileToJson.ts | 2 ++ 5 files changed, 81 insertions(+), 18 deletions(-) create mode 100644 test/integration/github-issues/117/entity/Post.ts create mode 100644 test/integration/github-issues/117/entity/Section.ts diff --git a/src/drivers/AbstractDriver.ts b/src/drivers/AbstractDriver.ts index fb577ee..889f291 100644 --- a/src/drivers/AbstractDriver.ts +++ b/src/drivers/AbstractDriver.ts @@ -259,16 +259,16 @@ export default abstract class AbstractDriver { const relatedTable = entities.find( entity => entity.tscName === relationTmp.ownerTable.tscName )!; - if ( - relatedTable.columns.length !== - relationTmp.ownerColumns.length * 2 - ) { - TomgUtils.LogError( - `Relation between tables ${relationTmp.ownerTable.sqlName} and ${relationTmp.relatedTable.sqlName} wasn't generated correctly - complex relationships aren't supported yet.`, - false - ); - return; - } + // if ( + // relatedTable.columns.length !== + // relationTmp.ownerColumns.length * 2 + // ) { + // TomgUtils.LogError( + // `Relation between tables ${relationTmp.ownerTable.sqlName} and ${relationTmp.relatedTable.sqlName} wasn't generated correctly - complex relationships aren't supported yet.`, + // false + // ); + // return; + // } const secondRelation = relationsTemp.find( relation => @@ -276,13 +276,13 @@ export default abstract class AbstractDriver { relation.relatedTable.tscName !== relationTmp.relatedTable.tscName )!; - if (!secondRelation) { - TomgUtils.LogError( - `Relation between tables ${relationTmp.ownerTable.sqlName} and ${relationTmp.relatedTable.sqlName} wasn't generated correctly - complex relationships aren't supported yet.`, - false - ); - return; - } + // if (!secondRelation) { + // TomgUtils.LogError( + // `Relation between tables ${relationTmp.ownerTable.sqlName} and ${relationTmp.relatedTable.sqlName} wasn't generated correctly - complex relationships aren't supported yet.`, + // false + // ); + // return; + // } } const ownerEntity = entities.find( diff --git a/src/entity.mst b/src/entity.mst index 0c7f940..cb9fcac 100644 --- a/src/entity.mst +++ b/src/entity.mst @@ -11,7 +11,7 @@ import { {{toEntityName .}} } from './{{toFileName .}}' {{/inline}} {{#*inline "Relation"}} @{{relationType}}(()=>{{toEntityName relatedTable}},{{toEntityName relatedTable}}=>{{toEntityName relatedTable}}.{{toPropertyName relatedField}}{{#if relationOptions}},{ {{json relationOptions}} }{{/if}}) -{{#if joinColumnOptions}}@JoinColumn({{json joinColumnOptions}}){{/if}} +{{#if joinColumnOptions}}@JoinColumn([{{json joinColumnOptions}}]){{/if}} {{#if joinTableOptions}}@JoinTable({ {{json joinTableOptions}} }){{/if}} {{toPropertyName fieldName}}:{{toRelation (toEntityName relatedTable) relationType}}; diff --git a/test/integration/github-issues/117/entity/Post.ts b/test/integration/github-issues/117/entity/Post.ts new file mode 100644 index 0000000..b408da2 --- /dev/null +++ b/test/integration/github-issues/117/entity/Post.ts @@ -0,0 +1,29 @@ +import { + Index, + Entity, + PrimaryColumn, + Column, + OneToOne, + OneToMany, + ManyToOne, + ManyToMany, + JoinColumn, + JoinTable +} from "typeorm"; +import { Section } from "./Section"; + +@Entity("Post") +export class Post { + @Column("int", { + primary: true, + name: "Id" + }) + id: number; + + @OneToOne(type => Section, section => section.post) + @JoinColumn([ + { name: "work", referencedColumnName: "work" }, + { name: "section", referencedColumnName: "section" } + ]) + section: Section; +} diff --git a/test/integration/github-issues/117/entity/Section.ts b/test/integration/github-issues/117/entity/Section.ts new file mode 100644 index 0000000..b67b276 --- /dev/null +++ b/test/integration/github-issues/117/entity/Section.ts @@ -0,0 +1,32 @@ +import { + Index, + Entity, + PrimaryColumn, + Column, + OneToOne, + OneToMany, + ManyToOne, + ManyToMany, + JoinColumn, + JoinTable, + RelationId +} from "typeorm"; +import { Post } from "./Post"; + +@Entity("Section") +export class Section { + @Column("int", { + primary: true, + name: "work" + }) + work: number; + + @Column("int", { + primary: true, + name: "section" + }) + section: number; + + @OneToOne(type => Post, Post => Post.id) + post: Post; +} diff --git a/test/utils/EntityFileToJson.ts b/test/utils/EntityFileToJson.ts index b73df1f..afb861a 100644 --- a/test/utils/EntityFileToJson.ts +++ b/test/utils/EntityFileToJson.ts @@ -405,6 +405,7 @@ export default class EntityFileToJson { priorPartOfMultilineStatement = trimmedLine; } else { isMultilineStatement = false; + // TODO: get joinColumnOptions options retVal.columns[ retVal.columns.length - 1 ].isOwnerOfRelation = true; @@ -417,6 +418,7 @@ export default class EntityFileToJson { priorPartOfMultilineStatement = trimmedLine; } else { isMultilineStatement = false; + // TODO: get joinTableOptions options - is it possible while JoinTable can be on either side of the relationship? // it doesn't matter which side of ManyToMany relation is marked as owner } return; From 6d4a97d39a46b95c5d68c2a857c9bb191ea1a3b7 Mon Sep 17 00:00:00 2001 From: Kononnable Date: Fri, 11 Oct 2019 10:05:21 +0200 Subject: [PATCH 22/84] postgres implementation --- src/drivers/PostgresDriver.ts | 544 +++++++++--------- .../entityTypes/postgres/entity/Post.ts | 10 +- .../entityTypes/postgres/entity/PostArrays.ts | 10 +- 3 files changed, 290 insertions(+), 274 deletions(-) diff --git a/src/drivers/PostgresDriver.ts b/src/drivers/PostgresDriver.ts index 02c5615..7571591 100644 --- a/src/drivers/PostgresDriver.ts +++ b/src/drivers/PostgresDriver.ts @@ -11,6 +11,10 @@ import IndexColumnInfo from "../oldModels/IndexColumnInfo"; import RelationTempInfo from "../oldModels/RelationTempInfo"; import IConnectionOptions from "../IConnectionOptions"; import { Entity } from "../models/Entity"; +import { Column } from "../models/Column"; +import { Index } from "../models/Index"; +import IGenerationOptions from "../IGenerationOptions"; +import { RelationInternal } from "../models/RelationInternal"; export default class PostgresDriver extends AbstractDriver { public defaultValues: DataTypeDefaults = new TypeormDriver.PostgresDriver({ @@ -40,125 +44,131 @@ export default class PostgresDriver extends AbstractDriver { entities: Entity[], schema: string ): Promise { - throw new Error(); - // TODO: Remove - // const response: { - // table_name: string; - // column_name: string; - // udt_name: string; - // column_default: string; - // is_nullable: string; - // data_type: string; - // character_maximum_length: number; - // numeric_precision: number; - // numeric_scale: number; - // isidentity: string; - // isunique: string; - // enumvalues: string | null; - // }[] = (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, - // (SELECT count(*) - // FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS tc - // inner join INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE cu - // on cu.CONSTRAINT_NAME = tc.CONSTRAINT_NAME - // where - // tc.CONSTRAINT_TYPE = 'UNIQUE' - // and tc.TABLE_NAME = c.TABLE_NAME - // and cu.COLUMN_NAME = c.COLUMN_NAME - // and tc.TABLE_SCHEMA=c.TABLE_SCHEMA) IsUnique, - // (SELECT - // string_agg(enumlabel, ',') - // FROM "pg_enum" "e" - // INNER JOIN "pg_type" "t" ON "t"."oid" = "e"."enumtypid" - // INNER JOIN "pg_namespace" "n" ON "n"."oid" = "t"."typnamespace" - // WHERE "n"."nspname" = table_schema AND "t"."typname"=udt_name - // ) enumValues - // FROM INFORMATION_SCHEMA.COLUMNS c - // where table_schema in (${schema}) - // order by ordinal_position`)).rows; - // entities.forEach(ent => { - // response - // .filter(filterVal => filterVal.table_name === ent.tsEntityName) - // .forEach(resp => { - // const colInfo: ColumnInfo = new ColumnInfo(); - // colInfo.tsName = resp.column_name; - // colInfo.options.name = resp.column_name; - // colInfo.options.nullable = resp.is_nullable === "YES"; - // colInfo.options.generated = resp.isidentity === "YES"; - // colInfo.options.unique = resp.isunique === "1"; - // colInfo.options.default = colInfo.options.generated - // ? null - // : PostgresDriver.ReturnDefaultValueFunction( - // resp.column_default - // ); + const response: { + table_name: string; + column_name: string; + udt_name: string; + column_default: string; + is_nullable: string; + data_type: string; + character_maximum_length: number; + numeric_precision: number; + numeric_scale: number; + isidentity: string; + isunique: string; + enumvalues: string | null; + }[] = (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, + (SELECT count(*) + FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS tc + inner join INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE cu + on cu.CONSTRAINT_NAME = tc.CONSTRAINT_NAME + where + tc.CONSTRAINT_TYPE = 'UNIQUE' + and tc.TABLE_NAME = c.TABLE_NAME + and cu.COLUMN_NAME = c.COLUMN_NAME + and tc.TABLE_SCHEMA=c.TABLE_SCHEMA) IsUnique, + (SELECT + string_agg(enumlabel, ',') + FROM "pg_enum" "e" + INNER JOIN "pg_type" "t" ON "t"."oid" = "e"."enumtypid" + INNER JOIN "pg_namespace" "n" ON "n"."oid" = "t"."typnamespace" + WHERE "n"."nspname" = table_schema AND "t"."typname"=udt_name + ) enumValues + FROM INFORMATION_SCHEMA.COLUMNS c + where table_schema in (${schema}) + order by ordinal_position`)).rows; + entities.forEach(ent => { + response + .filter(filterVal => filterVal.table_name === ent.tscName) + .forEach(resp => { + const tscName = resp.column_name; + const options: Partial = {}; + options.name = resp.column_name; + if (resp.is_nullable === "YES") options.nullable = true; + if (resp.isunique === "1") options.unique = true; - // const columnTypes = this.MatchColumnTypes( - // resp.data_type, - // resp.udt_name, - // resp.enumvalues - // ); - // if (!columnTypes.sqlType || !columnTypes.tsType) { - // if ( - // resp.data_type === "USER-DEFINED" || - // resp.data_type === "ARRAY" - // ) { - // TomgUtils.LogError( - // `Unknown ${resp.data_type} column type: ${resp.udt_name} table name: ${resp.table_name} column name: ${resp.column_name}` - // ); - // } else { - // TomgUtils.LogError( - // `Unknown column type: ${resp.data_type} table name: ${resp.table_name} column name: ${resp.column_name}` - // ); - // } - // return; - // } - // colInfo.options.type = columnTypes.sqlType as any; - // colInfo.tsType = columnTypes.tsType; - // colInfo.options.array = columnTypes.isArray; - // colInfo.options.enum = columnTypes.enumValues; - // if (colInfo.options.array) { - // colInfo.tsType = colInfo.tsType - // .split("|") - // .map(x => `${x.replace("|", "").trim()}[]`) - // .join(" | ") as any; - // } + const generated = + resp.isidentity === "YES" ? true : undefined; + const defaultValue = generated + ? undefined + : PostgresDriver.ReturnDefaultValueFunction( + resp.column_default + ); - // if ( - // this.ColumnTypesWithPrecision.some( - // v => v === colInfo.options.type - // ) - // ) { - // colInfo.options.precision = resp.numeric_precision; - // colInfo.options.scale = resp.numeric_scale; - // } - // if ( - // this.ColumnTypesWithLength.some( - // v => v === colInfo.options.type - // ) - // ) { - // colInfo.options.length = - // resp.character_maximum_length > 0 - // ? resp.character_maximum_length - // : undefined; - // } - // if ( - // this.ColumnTypesWithWidth.some( - // v => v === colInfo.options.type - // ) - // ) { - // colInfo.options.width = - // resp.character_maximum_length > 0 - // ? resp.character_maximum_length - // : undefined; - // } - // if (colInfo.options.type && colInfo.tsType) { - // ent.Columns.push(colInfo); - // } - // }); - // }); - // return entities; + const columnTypes = this.MatchColumnTypes( + resp.data_type, + resp.udt_name, + resp.enumvalues + ); + if (!columnTypes.sqlType || !columnTypes.tsType) { + if ( + resp.data_type === "USER-DEFINED" || + resp.data_type === "ARRAY" + ) { + TomgUtils.LogError( + `Unknown ${resp.data_type} column type: ${resp.udt_name} table name: ${resp.table_name} column name: ${resp.column_name}` + ); + } else { + TomgUtils.LogError( + `Unknown column type: ${resp.data_type} table name: ${resp.table_name} column name: ${resp.column_name}` + ); + } + return; + } + const columnType = columnTypes.sqlType as any; + let tscType = columnTypes.tsType; + if (columnTypes.isArray) options.array = true; + if (columnTypes.enumValues.length > 0) + options.enum = columnTypes.enumValues; + if (options.array) { + tscType = tscType + .split("|") + .map(x => `${x.replace("|", "").trim()}[]`) + .join(" | ") as any; + } + + if ( + this.ColumnTypesWithPrecision.some( + v => v === columnType + ) + ) { + if (resp.numeric_precision !== null) { + options.precision = resp.numeric_precision; + } + if (resp.numeric_scale !== null) { + options.scale = resp.numeric_scale; + } + } + if ( + this.ColumnTypesWithLength.some(v => v === columnType) + ) { + options.length = + resp.character_maximum_length > 0 + ? resp.character_maximum_length + : undefined; + } + if (this.ColumnTypesWithWidth.some(v => v === columnType)) { + options.width = + resp.character_maximum_length > 0 + ? resp.character_maximum_length + : undefined; + } + if (columnType && tscType) { + ent.columns.push({ + generated, + type: columnType, + default: defaultValue, + options: { name: "", ...options }, // TODO: Change + tscName, + tscType + }); + } + }); + }); + return entities; } public MatchColumnTypes( @@ -167,7 +177,7 @@ export default class PostgresDriver extends AbstractDriver { enumValues: string | null ) { let ret: { - tsType?: ColumnInfo["tsType"]; + tsType?: Column["tscType"]; sqlType: string | null; isArray: boolean; enumValues: string[]; @@ -382,9 +392,7 @@ export default class PostgresDriver extends AbstractDriver { .split(",") .join('" | "')}"` as never) as string; ret.sqlType = "enum"; - ret.enumValues = (`"${enumValues - .split(",") - .join('","')}"` as never) as string[]; + ret.enumValues = enumValues.split(","); } else { ret.tsType = undefined; ret.sqlType = null; @@ -404,152 +412,162 @@ export default class PostgresDriver extends AbstractDriver { entities: Entity[], schema: string ): Promise { - throw new Error(); - // TODO: Remove - // const response: { - // tablename: string; - // indexname: string; - // columnname: string; - // is_unique: number; - // is_primary_key: number; - // }[] = (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 - // END AS is_unique, - // CASE - // 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 - // JOIN pg_type t ON t.oid = f.atttypid - // LEFT JOIN pg_attrdef d ON d.adrelid = c.oid AND d.adnum = f.attnum - // LEFT JOIN pg_namespace n ON n.oid = c.relnamespace - // LEFT JOIN pg_index AS ix ON f.attnum = ANY(ix.indkey) and c.oid = f.attrelid and c.oid = ix.indrelid - // LEFT JOIN pg_class AS i ON ix.indexrelid = i.oid - // WHERE c.relkind = 'r'::char - // AND n.nspname in (${schema}) - // AND f.attnum > 0 - // AND i.oid<>0 - // ORDER BY c.relname,f.attname;`)).rows; - // entities.forEach(ent => { - // response - // .filter(filterVal => filterVal.tablename === ent.tsEntityName) - // .forEach(resp => { - // let indexInfo: IndexInfo = {} as IndexInfo; - // const indexColumnInfo: IndexColumnInfo = {} as IndexColumnInfo; - // if ( - // ent.Indexes.filter( - // filterVal => filterVal.name === resp.indexname - // ).length > 0 - // ) { - // indexInfo = ent.Indexes.find( - // filterVal => filterVal.name === resp.indexname - // )!; - // } else { - // indexInfo.columns = [] as IndexColumnInfo[]; - // indexInfo.name = resp.indexname; - // 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) { - // indexInfo.isPrimaryKey = false; - // } - // indexInfo.columns.push(indexColumnInfo); - // }); - // }); + const response: { + tablename: string; + indexname: string; + columnname: string; + is_unique: number; + is_primary_key: number; + }[] = (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 + END AS is_unique, + CASE + 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 + JOIN pg_type t ON t.oid = f.atttypid + LEFT JOIN pg_attrdef d ON d.adrelid = c.oid AND d.adnum = f.attnum + LEFT JOIN pg_namespace n ON n.oid = c.relnamespace + LEFT JOIN pg_index AS ix ON f.attnum = ANY(ix.indkey) and c.oid = f.attrelid and c.oid = ix.indrelid + LEFT JOIN pg_class AS i ON ix.indexrelid = i.oid + WHERE c.relkind = 'r'::char + AND n.nspname in (${schema}) + AND f.attnum > 0 + AND i.oid<>0 + ORDER BY c.relname,f.attname;`)).rows; + entities.forEach(ent => { + const entityIndices = response.filter( + filterVal => filterVal.tablename === ent.tscName + ); + const indexNames = new Set(entityIndices.map(v => v.indexname)); + indexNames.forEach(indexName => { + const records = entityIndices.filter( + v => v.indexname === indexName + ); + const indexInfo: Index = { + columns: [], + options: {}, + name: records[0].indexname + }; + if (records[0].is_primary_key === 1) indexInfo.primary = true; + if (records[0].is_unique === 1) indexInfo.options.unique = true; + records.forEach(record => { + indexInfo.columns.push(record.columnname); + }); + ent.indices.push(indexInfo); + }); + }); - // return entities; + return entities; } public async GetRelations( entities: Entity[], - schema: string + schema: string, + dbNames: string, + generationOptions: IGenerationOptions ): Promise { - throw new Error(); - // TODO: Remove - // const response: { - // tablewithforeignkey: string; - // fk_partno: number; - // foreignkeycolumn: string; - // tablereferenced: string; - // foreignkeycolumnreferenced: string; - // ondelete: "RESTRICT" | "CASCADE" | "SET NULL" | "NO ACTION"; - // onupdate: "RESTRICT" | "CASCADE" | "SET NULL" | "NO ACTION"; - // object_id: string; - // // Distinct because of note in https://www.postgresql.org/docs/9.1/information-schema.html - // }[] = (await this.Connection.query(`SELECT DISTINCT - // con.relname AS tablewithforeignkey, - // att.attnum as fk_partno, - // att2.attname AS foreignkeycolumn, - // cl.relname AS tablereferenced, - // att.attname AS foreignkeycolumnreferenced, - // delete_rule as ondelete, - // update_rule as onupdate, - // concat(con.conname,con.conrelid,con.confrelid) as object_id - // FROM ( - // SELECT - // unnest(con1.conkey) AS parent, - // unnest(con1.confkey) AS child, - // con1.confrelid, - // con1.conrelid, - // cl_1.relname, - // con1.conname, - // nspname - // FROM - // pg_class cl_1, - // pg_namespace ns, - // pg_constraint con1 - // WHERE - // con1.contype = 'f'::"char" - // AND cl_1.relnamespace = ns.oid - // AND con1.conrelid = cl_1.oid - // and nspname in (${schema}) - // ) con, - // pg_attribute att, - // pg_class cl, - // pg_attribute att2, - // information_schema.referential_constraints rc - // WHERE - // att.attrelid = con.confrelid - // AND att.attnum = con.child - // AND cl.oid = con.confrelid - // AND att2.attrelid = con.conrelid - // AND att2.attnum = con.parent - // AND rc.constraint_name= con.conname AND constraint_catalog=current_database() AND rc.constraint_schema=nspname - // `)).rows; - // const relationsTemp: RelationTempInfo[] = [] as RelationTempInfo[]; - // response.forEach(resp => { - // let rels = relationsTemp.find( - // val => val.objectId === resp.object_id - // ); - // if (rels === undefined) { - // rels = {} as RelationTempInfo; - // rels.ownerColumnsNames = []; - // rels.referencedColumnsNames = []; - // rels.actionOnDelete = - // resp.ondelete === "NO ACTION" ? null : resp.ondelete; - // rels.actionOnUpdate = - // resp.onupdate === "NO ACTION" ? null : resp.onupdate; - // rels.objectId = resp.object_id; - // rels.ownerTable = resp.tablewithforeignkey; - // rels.referencedTable = resp.tablereferenced; - // relationsTemp.push(rels); - // } - // rels.ownerColumnsNames.push(resp.foreignkeycolumn); - // rels.referencedColumnsNames.push(resp.foreignkeycolumnreferenced); - // }); - // const retVal = PostgresDriver.GetRelationsFromRelationTempInfo( - // relationsTemp, - // entities - // ); - // return retVal; + const response: { + tablewithforeignkey: string; + fk_partno: number; + foreignkeycolumn: string; + tablereferenced: string; + foreignkeycolumnreferenced: string; + ondelete: "RESTRICT" | "CASCADE" | "SET NULL" | "NO ACTION"; + onupdate: "RESTRICT" | "CASCADE" | "SET NULL" | "NO ACTION"; + object_id: string; + // Distinct because of note in https://www.postgresql.org/docs/9.1/information-schema.html + }[] = (await this.Connection.query(`SELECT DISTINCT + con.relname AS tablewithforeignkey, + att.attnum as fk_partno, + att2.attname AS foreignkeycolumn, + cl.relname AS tablereferenced, + att.attname AS foreignkeycolumnreferenced, + delete_rule as ondelete, + update_rule as onupdate, + concat(con.conname,con.conrelid,con.confrelid) as object_id + FROM ( + SELECT + unnest(con1.conkey) AS parent, + unnest(con1.confkey) AS child, + con1.confrelid, + con1.conrelid, + cl_1.relname, + con1.conname, + nspname + FROM + pg_class cl_1, + pg_namespace ns, + pg_constraint con1 + WHERE + con1.contype = 'f'::"char" + AND cl_1.relnamespace = ns.oid + AND con1.conrelid = cl_1.oid + and nspname in (${schema}) + ) con, + pg_attribute att, + pg_class cl, + pg_attribute att2, + information_schema.referential_constraints rc + WHERE + att.attrelid = con.confrelid + AND att.attnum = con.child + AND cl.oid = con.confrelid + AND att2.attrelid = con.conrelid + AND att2.attnum = con.parent + AND rc.constraint_name= con.conname AND constraint_catalog=current_database() AND rc.constraint_schema=nspname + `)).rows; + + const relationsTemp: RelationInternal[] = [] as RelationInternal[]; + const relationKeys = new Set(response.map(v => v.object_id)); + + relationKeys.forEach(relationId => { + const rows = response.filter(v => v.object_id === relationId); + const ownerTable = entities.find( + v => v.sqlName === rows[0].tablewithforeignkey + ); + const relatedTable = entities.find( + v => v.sqlName === rows[0].tablereferenced + ); + if (!ownerTable || !relatedTable) { + TomgUtils.LogError( + `Relation between tables ${rows[0].tablewithforeignkey} and ${rows[0].tablereferenced} wasn't found in entity model.`, + true + ); + return; + } + const internal: RelationInternal = { + ownerColumns: [], + relatedColumns: [], + ownerTable, + relatedTable + }; + if (rows[0].ondelete !== "NO ACTION") { + internal.onDelete = rows[0].ondelete; + } + if (rows[0].onupdate !== "NO ACTION") { + internal.onUpdate = rows[0].onupdate; + } + rows.forEach(row => { + internal.ownerColumns.push(row.foreignkeycolumn); + internal.relatedColumns.push(row.foreignkeycolumnreferenced); + }); + relationsTemp.push(internal); + }); + + const retVal = PostgresDriver.GetRelationsFromRelationTempInfo( + relationsTemp, + entities, + generationOptions + ); + return retVal; } public async DisconnectFromServer() { @@ -623,10 +641,10 @@ export default class PostgresDriver extends AbstractDriver { private static ReturnDefaultValueFunction( defVal: string | null - ): string | null { + ): string | undefined { let defaultValue = defVal; if (!defaultValue) { - return null; + return undefined; } defaultValue = defaultValue.replace(/'::[\w ]*/, "'"); if (defaultValue.startsWith(`'`)) { diff --git a/test/integration/entityTypes/postgres/entity/Post.ts b/test/integration/entityTypes/postgres/entity/Post.ts index 1f1cc56..77012f0 100644 --- a/test/integration/entityTypes/postgres/entity/Post.ts +++ b/test/integration/entityTypes/postgres/entity/Post.ts @@ -81,7 +81,7 @@ export class Post { varbit: string; @Column("bit varying") - bit_varying: string; + bitVarying: string; @Column("timetz") timetz: string; @@ -93,10 +93,10 @@ export class Post { timestamp: Date; @Column("timestamp without time zone") - timestamp_without_time_zone: Date; + timestampWithoutTimeZone: Date; @Column("timestamp with time zone") - timestamp_with_time_zone: Date; + timestampWithTimeZone: Date; @Column("date") date: string; @@ -104,10 +104,10 @@ export class Post { @Column("time") time: string; @Column("time without time zone") - time_without_time_zone: string; + timeWithoutTimeZone: string; @Column("time with time zone") - time_with_time_zone: string; + timeWithTimeZone: string; @Column("interval") interval: any; diff --git a/test/integration/entityTypes/postgres/entity/PostArrays.ts b/test/integration/entityTypes/postgres/entity/PostArrays.ts index fde1012..5b7a6ad 100644 --- a/test/integration/entityTypes/postgres/entity/PostArrays.ts +++ b/test/integration/entityTypes/postgres/entity/PostArrays.ts @@ -2,7 +2,6 @@ import { Entity, PrimaryColumn, Column } from "typeorm"; @Entity("PostArrays") export class PostArrays { - @PrimaryColumn() id: number; @@ -82,7 +81,7 @@ export class PostArrays { varbit: string[]; @Column("bit varying", { array: true }) - bit_varying: string[]; + bitVarying: string[]; @Column("timetz", { array: true }) timetz: string[]; @@ -97,7 +96,7 @@ export class PostArrays { // timestamp_without_time_zone: Date[]; @Column("timestamp with time zone", { array: true }) - timestamp_with_time_zone: Date[]; + timestampWithTimeZone: Date[]; @Column("date", { array: true }) date: string[]; @@ -105,10 +104,10 @@ export class PostArrays { @Column("time", { array: true }) time: string[]; @Column("time without time zone", { array: true }) - time_without_time_zone: string[]; + timeWithoutTimeZone: string[]; @Column("time with time zone", { array: true }) - time_with_time_zone: string[]; + timeWithTimeZone: string[]; @Column("interval", { array: true }) interval: any[]; @@ -187,5 +186,4 @@ export class PostArrays { @Column("daterange", { array: true }) daterange: string[]; - } From 95e0cc58541a3b7eb71258885e2488726572bdba Mon Sep 17 00:00:00 2001 From: Kononnable Date: Fri, 11 Oct 2019 12:01:35 +0200 Subject: [PATCH 23/84] sqlite implementation --- src/drivers/SqliteDriver.ts | 592 ++++++++++-------- .../entityTypes/sqlite/entity/Post.ts | 8 +- 2 files changed, 330 insertions(+), 270 deletions(-) diff --git a/src/drivers/SqliteDriver.ts b/src/drivers/SqliteDriver.ts index 8904902..c6fe377 100644 --- a/src/drivers/SqliteDriver.ts +++ b/src/drivers/SqliteDriver.ts @@ -11,6 +11,10 @@ import IndexColumnInfo from "../oldModels/IndexColumnInfo"; import RelationTempInfo from "../oldModels/RelationTempInfo"; import IConnectionOptions from "../IConnectionOptions"; import { Entity } from "../models/Entity"; +import { Column } from "../models/Column"; +import { Index } from "../models/Index"; +import IGenerationOptions from "../IGenerationOptions"; +import { RelationInternal } from "../models/RelationInternal"; export default class SqliteDriver extends AbstractDriver { public defaultValues: DataTypeDefaults = new TypeormDriver.SqliteDriver({ @@ -54,277 +58,335 @@ export default class SqliteDriver extends AbstractDriver { } public async GetCoulmnsFromEntity(entities: Entity[]): Promise { - throw new Error(); - // TODO: Remove - // await Promise.all( - // entities.map(async ent => { - // const response = await this.ExecQuery<{ - // cid: number; - // name: string; - // type: string; - // notnull: number; - // dflt_value: string; - // pk: number; - // }>(`PRAGMA table_info('${ent.tsEntityName}');`); - // response.forEach(resp => { - // const colInfo: ColumnInfo = new ColumnInfo(); - // colInfo.tsName = resp.name; - // colInfo.options.name = resp.name; - // colInfo.options.nullable = resp.notnull === 0; - // colInfo.options.primary = resp.pk > 0; - // colInfo.options.default = SqliteDriver.ReturnDefaultValueFunction( - // resp.dflt_value - // ); - // colInfo.options.type = resp.type - // .replace(/\([0-9 ,]+\)/g, "") - // .toLowerCase() - // .trim() as any; - // colInfo.options.generated = - // colInfo.options.primary && - // this.tablesWithGeneratedPrimaryKey.includes( - // ent.tsEntityName - // ); - // switch (colInfo.options.type) { - // case "int": - // colInfo.tsType = "number"; - // break; - // case "integer": - // colInfo.tsType = "number"; - // break; - // case "int2": - // colInfo.tsType = "number"; - // break; - // case "int8": - // colInfo.tsType = "number"; - // break; - // case "tinyint": - // colInfo.tsType = "number"; - // break; - // case "smallint": - // colInfo.tsType = "number"; - // break; - // case "mediumint": - // colInfo.tsType = "number"; - // break; - // case "bigint": - // colInfo.tsType = "string"; - // break; - // case "unsigned big int": - // colInfo.tsType = "string"; - // break; - // case "character": - // colInfo.tsType = "string"; - // break; - // case "varchar": - // colInfo.tsType = "string"; - // break; - // case "varying character": - // colInfo.tsType = "string"; - // break; - // case "nchar": - // colInfo.tsType = "string"; - // break; - // case "native character": - // colInfo.tsType = "string"; - // break; - // case "nvarchar": - // colInfo.tsType = "string"; - // break; - // case "text": - // colInfo.tsType = "string"; - // break; - // case "blob": - // colInfo.tsType = "Buffer"; - // break; - // case "clob": - // colInfo.tsType = "string"; - // break; - // case "real": - // colInfo.tsType = "number"; - // break; - // case "double": - // colInfo.tsType = "number"; - // break; - // case "double precision": - // colInfo.tsType = "number"; - // break; - // case "float": - // colInfo.tsType = "number"; - // break; - // case "numeric": - // colInfo.tsType = "number"; - // break; - // case "decimal": - // colInfo.tsType = "number"; - // break; - // case "boolean": - // colInfo.tsType = "boolean"; - // break; - // case "date": - // colInfo.tsType = "string"; - // break; - // case "datetime": - // colInfo.tsType = "Date"; - // break; - // default: - // TomgUtils.LogError( - // `Unknown column type: ${colInfo.options.type} table name: ${ent.tsEntityName} column name: ${resp.name}` - // ); - // break; - // } - // const options = resp.type.match(/\([0-9 ,]+\)/g); - // if ( - // this.ColumnTypesWithPrecision.some( - // v => v === colInfo.options.type - // ) && - // options - // ) { - // colInfo.options.precision = options[0] - // .substring(1, options[0].length - 1) - // .split(",")[0] as any; - // colInfo.options.scale = options[0] - // .substring(1, options[0].length - 1) - // .split(",")[1] as any; - // } - // if ( - // this.ColumnTypesWithLength.some( - // v => v === colInfo.options.type - // ) && - // options - // ) { - // colInfo.options.length = options[0].substring( - // 1, - // options[0].length - 1 - // ) as any; - // } - // if ( - // this.ColumnTypesWithWidth.some( - // v => - // v === colInfo.options.type && - // colInfo.tsType !== "boolean" - // ) && - // options - // ) { - // colInfo.options.width = options[0].substring( - // 1, - // options[0].length - 1 - // ) as any; - // } + await Promise.all( + entities.map(async ent => { + const response = await this.ExecQuery<{ + cid: number; + name: string; + type: string; + notnull: number; + dflt_value: string; + pk: number; + }>(`PRAGMA table_info('${ent.tscName}');`); + response.forEach(resp => { + const tscName = resp.name; + let tscType = ""; + const options: Partial = {}; + options.name = resp.name; + if (resp.notnull === 0) options.nullable = true; + const isPrimary = resp.pk > 0 ? true : undefined; + const defaultValue = SqliteDriver.ReturnDefaultValueFunction( + resp.dflt_value + ); + let columnType = resp.type + .replace(/\([0-9 ,]+\)/g, "") + .toLowerCase() + .trim(); + const generated = + isPrimary && + this.tablesWithGeneratedPrimaryKey.includes(ent.tscName) + ? true + : undefined; + switch (columnType) { + case "int": + tscType = "number"; + break; + case "integer": + tscType = "number"; + break; + case "int2": + tscType = "number"; + break; + case "int8": + tscType = "number"; + break; + case "tinyint": + tscType = "number"; + break; + case "smallint": + tscType = "number"; + break; + case "mediumint": + tscType = "number"; + break; + case "bigint": + tscType = "string"; + break; + case "unsigned big int": + tscType = "string"; + break; + case "character": + tscType = "string"; + break; + case "varchar": + tscType = "string"; + break; + case "varying character": + tscType = "string"; + break; + case "nchar": + tscType = "string"; + break; + case "native character": + tscType = "string"; + break; + case "nvarchar": + tscType = "string"; + break; + case "text": + tscType = "string"; + break; + case "blob": + tscType = "Buffer"; + break; + case "clob": + tscType = "string"; + break; + case "real": + tscType = "number"; + break; + case "double": + tscType = "number"; + break; + case "double precision": + tscType = "number"; + break; + case "float": + tscType = "number"; + break; + case "numeric": + tscType = "number"; + break; + case "decimal": + tscType = "number"; + break; + case "boolean": + tscType = "boolean"; + break; + case "date": + tscType = "string"; + break; + case "datetime": + tscType = "Date"; + break; + default: + TomgUtils.LogError( + `Unknown column type: ${columnType} table name: ${ent.tscName} column name: ${resp.name}` + ); + break; + } + const sqlOptions = resp.type.match(/\([0-9 ,]+\)/g); + if ( + this.ColumnTypesWithPrecision.some( + v => v === columnType + ) && + sqlOptions + ) { + options.precision = sqlOptions[0] + .substring(1, sqlOptions[0].length - 1) + .split(",")[0] as any; + options.scale = sqlOptions[0] + .substring(1, sqlOptions[0].length - 1) + .split(",")[1] as any; + } + if ( + this.ColumnTypesWithLength.some( + v => v === columnType + ) && + sqlOptions + ) { + options.length = Number.parseInt( + sqlOptions[0].substring( + 1, + sqlOptions[0].length - 1 + ), + 10 + ); + } + if ( + this.ColumnTypesWithWidth.some( + v => v === columnType && tscType !== "boolean" + ) && + sqlOptions + ) { + options.width = sqlOptions[0].substring( + 1, + sqlOptions[0].length - 1 + ) as any; + } - // if (colInfo.options.type) { - // ent.Columns.push(colInfo); - // } - // }); - // }) - // ); + if (columnType) { + ent.columns.push({ + generated, + primary: isPrimary, + type: columnType, + default: defaultValue, + options: { name: "", ...options }, // TODO: Change + tscName, + tscType + }); + } + }); + }) + ); - // return entities; + return entities; } public async GetIndexesFromEntity(entities: Entity[]): Promise { - throw new Error(); - // TODO: Remove - // await Promise.all( - // entities.map(async ent => { - // const response = await this.ExecQuery<{ - // seq: number; - // name: string; - // unique: number; - // origin: string; - // partial: number; - // }>(`PRAGMA index_list('${ent.tsEntityName}');`); - // await Promise.all( - // response.map(async resp => { - // const indexColumnsResponse = await this.ExecQuery<{ - // seqno: number; - // cid: number; - // name: string; - // }>(`PRAGMA index_info('${resp.name}');`); - // indexColumnsResponse.forEach(element => { - // let indexInfo: IndexInfo = {} as IndexInfo; - // const indexColumnInfo: IndexColumnInfo = {} as IndexColumnInfo; - // if ( - // ent.Indexes.filter(filterVal => { - // return filterVal.name === resp.name; - // }).length > 0 - // ) { - // indexInfo = ent.Indexes.find( - // filterVal => filterVal.name === resp.name - // )!; - // } else { - // indexInfo.columns = [] as IndexColumnInfo[]; - // indexInfo.name = resp.name; - // indexInfo.isUnique = resp.unique === 1; - // ent.Indexes.push(indexInfo); - // } - // indexColumnInfo.name = element.name; - // if ( - // indexColumnsResponse.length === 1 && - // indexInfo.isUnique - // ) { - // ent.Columns.filter( - // v => v.tsName === indexColumnInfo.name - // ).forEach(v => { - // // eslint-disable-next-line no-param-reassign - // v.options.unique = true; - // }); - // } - // indexInfo.columns.push(indexColumnInfo); - // }); - // }) - // ); - // }) - // ); + await Promise.all( + entities.map(async ent => { + const response = await this.ExecQuery<{ + seq: number; + name: string; + unique: number; + origin: string; + partial: number; + }>(`PRAGMA index_list('${ent.tscName}');`); + await Promise.all( + response.map(async resp => { + const indexColumnsResponse = await this.ExecQuery<{ + seqno: number; + cid: number; + name: string; + }>(`PRAGMA index_info('${resp.name}');`); - // return entities; + const indexInfo: Index = { + name: resp.name, + columns: [], + options: {} + }; + if (resp.unique === 1) indexInfo.options.unique = true; + + indexColumnsResponse.forEach(record => { + indexInfo.columns.push(record.name); + }); + if ( + indexColumnsResponse.length === 1 && + indexInfo.options.unique + ) { + ent.columns + .filter(v => v.tscName === indexInfo.columns[0]) + .forEach(v => { + // eslint-disable-next-line no-param-reassign + v.options.unique = true; + }); + } + ent.indices.push(indexInfo); + + // indexColumnsResponse.forEach(element => { + // const indexColumnInfo: IndexColumnInfo = {} as IndexColumnInfo; + // if ( + // ent.indices.filter(filterVal => { + // return filterVal.name === resp.name; + // }).length > 0 + // ) { + // indexInfo = ent.indices.find( + // filterVal => filterVal.name === resp.name + // )!; + // } else { + // indexInfo.columns = [] as IndexColumnInfo[]; + // indexInfo.name = resp.name; + // indexInfo.isUnique = resp.unique === 1; + // ent.indices.push(indexInfo); + // } + // indexColumnInfo.name = element.name; + // if ( + // indexColumnsResponse.length === 1 && + // indexInfo.isUnique + // ) { + // ent.columns + // .filter( + // v => v.tscName === indexColumnInfo.name + // ) + // .forEach(v => { + // // eslint-disable-next-line no-param-reassign + // v.options.unique = true; + // }); + // } + // indexInfo.columns.push(indexColumnInfo); + // }); + }) + ); + }) + ); + + return entities; } - public async GetRelations(entities: Entity[]): Promise { - throw new Error(); - // TODO: Remove - // let retVal = entities; - // await Promise.all( - // retVal.map(async entity => { - // const response = await this.ExecQuery<{ - // id: number; - // seq: number; - // table: string; - // from: string; - // to: string; - // on_update: - // | "RESTRICT" - // | "CASCADE" - // | "SET NULL" - // | "NO ACTION"; - // on_delete: - // | "RESTRICT" - // | "CASCADE" - // | "SET NULL" - // | "NO ACTION"; - // match: string; - // }>(`PRAGMA foreign_key_list('${entity.tsEntityName}');`); - // const relationsTemp: RelationTempInfo[] = [] as RelationTempInfo[]; - // response.forEach(resp => { - // const rels = {} as RelationTempInfo; - // rels.ownerColumnsNames = []; - // rels.referencedColumnsNames = []; - // rels.actionOnDelete = - // resp.on_delete === "NO ACTION" ? null : resp.on_delete; - // rels.actionOnUpdate = - // resp.on_update === "NO ACTION" ? null : resp.on_update; - // rels.ownerTable = entity.tsEntityName; - // rels.referencedTable = resp.table; - // relationsTemp.push(rels); - // rels.ownerColumnsNames.push(resp.from); - // rels.referencedColumnsNames.push(resp.to); - // }); - // retVal = SqliteDriver.GetRelationsFromRelationTempInfo( - // relationsTemp, - // retVal - // ); - // }) - // ); - // return retVal; + public async GetRelations( + entities: Entity[], + schema: string, + dbNames: string, + generationOptions: IGenerationOptions + ): Promise { + let retVal = entities; + await Promise.all( + retVal.map(async entity => { + const response = await this.ExecQuery<{ + id: number; + seq: number; + table: string; + from: string; + to: string; + on_update: + | "RESTRICT" + | "CASCADE" + | "SET NULL" + | "NO ACTION"; + on_delete: + | "RESTRICT" + | "CASCADE" + | "SET NULL" + | "NO ACTION"; + match: string; + }>(`PRAGMA foreign_key_list('${entity.tscName}');`); + + const relationsTemp: RelationInternal[] = [] as RelationInternal[]; + const relationKeys = new Set(response.map(v => v.id)); + + relationKeys.forEach(relationId => { + const rows = response.filter(v => v.id === relationId); + const ownerTable = entities.find( + v => v.sqlName === entity.tscName + ); + const relatedTable = entities.find( + v => v.sqlName === rows[0].table + ); + if (!ownerTable || !relatedTable) { + TomgUtils.LogError( + `Relation between tables ${entity.tscName} and ${rows[0].table} wasn't found in entity model.`, + true + ); + return; + } + const internal: RelationInternal = { + ownerColumns: [], + relatedColumns: [], + ownerTable, + relatedTable + }; + if (rows[0].on_delete !== "NO ACTION") { + internal.onDelete = rows[0].on_delete; + } + if (rows[0].on_update !== "NO ACTION") { + internal.onUpdate = rows[0].on_update; + } + rows.forEach(row => { + internal.ownerColumns.push(row.from); + internal.relatedColumns.push(row.to); + }); + relationsTemp.push(internal); + }); + + retVal = SqliteDriver.GetRelationsFromRelationTempInfo( + relationsTemp, + retVal, + generationOptions + ); + }) + ); + return retVal; } public async DisconnectFromServer() { @@ -393,9 +455,9 @@ export default class SqliteDriver extends AbstractDriver { private static ReturnDefaultValueFunction( defVal: string | null - ): string | null { + ): string | undefined { if (!defVal) { - return null; + return undefined; } if (defVal.startsWith(`'`)) { return `() => "${defVal}"`; diff --git a/test/integration/entityTypes/sqlite/entity/Post.ts b/test/integration/entityTypes/sqlite/entity/Post.ts index 73326e4..24d4aae 100644 --- a/test/integration/entityTypes/sqlite/entity/Post.ts +++ b/test/integration/entityTypes/sqlite/entity/Post.ts @@ -2,7 +2,6 @@ import { Entity, PrimaryColumn, Column } from "typeorm"; @Entity("Post") export class Post { - @PrimaryColumn() id: number; @@ -34,7 +33,7 @@ export class Post { bigint: string; @Column("unsigned big int") - unsigned_big_int: string; + unsignedBigInt: string; @Column("character") character: string; @@ -43,13 +42,13 @@ export class Post { varchar: string; @Column("varying character") - varying_character: string; + varyingCharacter: string; @Column("nchar") nchar: string; @Column("native character") - native_character: string; + nativeCharacter: string; @Column("nvarchar") nvarchar: string; @@ -88,5 +87,4 @@ export class Post { @Column("datetime") datetime: Date; - } From bd8a79040c4c2c63a44201bf0ded80f7fc0d39ef Mon Sep 17 00:00:00 2001 From: Kononnable Date: Fri, 11 Oct 2019 12:41:33 +0200 Subject: [PATCH 24/84] code linting --- src/Engine.ts | 1 - src/NamingStrategy.ts | 9 ++------- src/drivers/AbstractDriver.ts | 33 --------------------------------- src/drivers/MysqlDriver.ts | 5 ----- src/drivers/PostgresDriver.ts | 5 ----- src/drivers/SqliteDriver.ts | 7 +------ test/utils/EntityFileToJson.ts | 13 +++---------- 7 files changed, 6 insertions(+), 67 deletions(-) diff --git a/src/Engine.ts b/src/Engine.ts index 93e26fd..1dba8e0 100644 --- a/src/Engine.ts +++ b/src/Engine.ts @@ -7,7 +7,6 @@ import MssqlDriver from "./drivers/MssqlDriver"; import MariaDbDriver from "./drivers/MariaDbDriver"; import IConnectionOptions from "./IConnectionOptions"; import IGenerationOptions from "./IGenerationOptions"; -import EntityInfo from "./oldModels/EntityInfo"; import PostgresDriver from "./drivers/PostgresDriver"; import MysqlDriver from "./drivers/MysqlDriver"; import OracleDriver from "./drivers/OracleDriver"; diff --git a/src/NamingStrategy.ts b/src/NamingStrategy.ts index 399ea44..42bd127 100644 --- a/src/NamingStrategy.ts +++ b/src/NamingStrategy.ts @@ -1,17 +1,12 @@ import AbstractNamingStrategy from "./AbstractNamingStrategy"; import { Relation } from "./models/Relation"; -import { Entity } from "./models/Entity"; import { RelationId } from "./models/RelationId"; import changeCase = require("change-case"); /* eslint-disable class-methods-use-this */ export default class NamingStrategy extends AbstractNamingStrategy { - public relationIdName( - relationId: RelationId, - relation: Relation, - owner: Entity - ): string { + public relationIdName(relationId: RelationId, relation: Relation): string { const columnOldName = relationId.fieldName; const isRelationToMany = @@ -32,7 +27,7 @@ export default class NamingStrategy extends AbstractNamingStrategy { return columnName; } - public relationName(relation: Relation, owner: Entity): string { + public relationName(relation: Relation): string { const columnOldName = relation.fieldName; const isRelationToMany = diff --git a/src/drivers/AbstractDriver.ts b/src/drivers/AbstractDriver.ts index 889f291..7ea68ed 100644 --- a/src/drivers/AbstractDriver.ts +++ b/src/drivers/AbstractDriver.ts @@ -6,9 +6,6 @@ import { import { JoinColumnOptions, RelationOptions } from "typeorm"; import { DataTypeDefaults } from "typeorm/driver/types/DataTypeDefaults"; import * as TomgUtils from "../Utils"; -import EntityInfo from "../oldModels/EntityInfo"; -import RelationInfo from "../oldModels/RelationInfo"; -import ColumnInfo from "../oldModels/ColumnInfo"; import IConnectionOptions from "../IConnectionOptions"; import { Entity } from "../models/Entity"; import { RelationInternal } from "../models/RelationInternal"; @@ -255,36 +252,6 @@ export default abstract class AbstractDriver { generationOptions: IGenerationOptions ) { relationsTemp.forEach(relationTmp => { - if (relationTmp.ownerColumns.length > 1) { - const relatedTable = entities.find( - entity => entity.tscName === relationTmp.ownerTable.tscName - )!; - // if ( - // relatedTable.columns.length !== - // relationTmp.ownerColumns.length * 2 - // ) { - // TomgUtils.LogError( - // `Relation between tables ${relationTmp.ownerTable.sqlName} and ${relationTmp.relatedTable.sqlName} wasn't generated correctly - complex relationships aren't supported yet.`, - // false - // ); - // return; - // } - - const secondRelation = relationsTemp.find( - relation => - relation.ownerTable.tscName === relatedTable.tscName && - relation.relatedTable.tscName !== - relationTmp.relatedTable.tscName - )!; - // if (!secondRelation) { - // TomgUtils.LogError( - // `Relation between tables ${relationTmp.ownerTable.sqlName} and ${relationTmp.relatedTable.sqlName} wasn't generated correctly - complex relationships aren't supported yet.`, - // false - // ); - // return; - // } - } - const ownerEntity = entities.find( entity => entity.tscName === relationTmp.ownerTable.tscName ); diff --git a/src/drivers/MysqlDriver.ts b/src/drivers/MysqlDriver.ts index 96561fe..f6cc0eb 100644 --- a/src/drivers/MysqlDriver.ts +++ b/src/drivers/MysqlDriver.ts @@ -4,11 +4,6 @@ import * as TypeormDriver from "typeorm/driver/mysql/MysqlDriver"; import { DataTypeDefaults } from "typeorm/driver/types/DataTypeDefaults"; import * as TomgUtils from "../Utils"; import AbstractDriver from "./AbstractDriver"; -import EntityInfo from "../oldModels/EntityInfo"; -import ColumnInfo from "../oldModels/ColumnInfo"; -import IndexInfo from "../oldModels/IndexInfo"; -import IndexColumnInfo from "../oldModels/IndexColumnInfo"; -import RelationTempInfo from "../oldModels/RelationTempInfo"; import IConnectionOptions from "../IConnectionOptions"; import { Entity } from "../models/Entity"; import { Column } from "../models/Column"; diff --git a/src/drivers/PostgresDriver.ts b/src/drivers/PostgresDriver.ts index 7571591..50bfb0c 100644 --- a/src/drivers/PostgresDriver.ts +++ b/src/drivers/PostgresDriver.ts @@ -4,11 +4,6 @@ import * as TypeormDriver from "typeorm/driver/postgres/PostgresDriver"; import { DataTypeDefaults } from "typeorm/driver/types/DataTypeDefaults"; import * as TomgUtils from "../Utils"; import AbstractDriver from "./AbstractDriver"; -import EntityInfo from "../oldModels/EntityInfo"; -import ColumnInfo from "../oldModels/ColumnInfo"; -import IndexInfo from "../oldModels/IndexInfo"; -import IndexColumnInfo from "../oldModels/IndexColumnInfo"; -import RelationTempInfo from "../oldModels/RelationTempInfo"; import IConnectionOptions from "../IConnectionOptions"; import { Entity } from "../models/Entity"; import { Column } from "../models/Column"; diff --git a/src/drivers/SqliteDriver.ts b/src/drivers/SqliteDriver.ts index c6fe377..60ce45a 100644 --- a/src/drivers/SqliteDriver.ts +++ b/src/drivers/SqliteDriver.ts @@ -4,11 +4,6 @@ import { DataTypeDefaults } from "typeorm/driver/types/DataTypeDefaults"; import * as sqliteLib from "sqlite3"; import * as TomgUtils from "../Utils"; import AbstractDriver from "./AbstractDriver"; -import EntityInfo from "../oldModels/EntityInfo"; -import ColumnInfo from "../oldModels/ColumnInfo"; -import IndexInfo from "../oldModels/IndexInfo"; -import IndexColumnInfo from "../oldModels/IndexColumnInfo"; -import RelationTempInfo from "../oldModels/RelationTempInfo"; import IConnectionOptions from "../IConnectionOptions"; import { Entity } from "../models/Entity"; import { Column } from "../models/Column"; @@ -78,7 +73,7 @@ export default class SqliteDriver extends AbstractDriver { const defaultValue = SqliteDriver.ReturnDefaultValueFunction( resp.dflt_value ); - let columnType = resp.type + const columnType = resp.type .replace(/\([0-9 ,]+\)/g, "") .toLowerCase() .trim(); diff --git a/test/utils/EntityFileToJson.ts b/test/utils/EntityFileToJson.ts index afb861a..d091b89 100644 --- a/test/utils/EntityFileToJson.ts +++ b/test/utils/EntityFileToJson.ts @@ -92,16 +92,9 @@ export default class EntityFileToJson { /default: \(\) => (.*)/, `default: $1` ); - try { - col.columnOptions = JSON.parse( - badJSON.replace( - /(['"])?([a-z0-9A-Z_]+)(['"])?:/g, - '"$2": ' - ) - ); - } catch (error) { - debugger; - } + col.columnOptions = JSON.parse( + badJSON.replace(/(['"])?([a-z0-9A-Z_]+)(['"])?:/g, '"$2": ') + ); } else if ( decoratorParameters[0] === '"' && decoratorParameters.endsWith('"') From 15b62916065b030e81dc698e4eeae14eab330ce0 Mon Sep 17 00:00:00 2001 From: Kononnable Date: Sat, 12 Oct 2019 10:24:43 +0200 Subject: [PATCH 25/84] code cleanup --- src/Engine.ts | 17 +--- src/drivers/AbstractDriver.ts | 2 - src/oldModels/ColumnInfo.ts | 22 ------ src/oldModels/EntityInfo.ts | 38 --------- src/oldModels/IndexColumnInfo.ts | 3 - src/oldModels/IndexInfo.ts | 8 -- src/oldModels/RelationInfo.ts | 46 ----------- src/oldModels/RelationTempInfo.ts | 15 ---- test/drivers/MssqlDriver.test.ts | 78 ++++++++++--------- .../{feedextrainfo.ts => Feedextrainfo.ts} | 18 ++--- .../58/entity/{quests.ts => Quests.ts} | 8 +- .../58/entity/{users.ts => Users.ts} | 12 +-- test/utils/GeneralTestUtils.ts | 4 +- 13 files changed, 62 insertions(+), 209 deletions(-) delete mode 100644 src/oldModels/ColumnInfo.ts delete mode 100644 src/oldModels/EntityInfo.ts delete mode 100644 src/oldModels/IndexColumnInfo.ts delete mode 100644 src/oldModels/IndexInfo.ts delete mode 100644 src/oldModels/RelationInfo.ts delete mode 100644 src/oldModels/RelationTempInfo.ts rename test/integration/github-issues/58/entity/{feedextrainfo.ts => Feedextrainfo.ts} (70%) rename test/integration/github-issues/58/entity/{quests.ts => Quests.ts} (63%) rename test/integration/github-issues/58/entity/{users.ts => Users.ts} (54%) diff --git a/src/Engine.ts b/src/Engine.ts index 1dba8e0..04e749b 100644 --- a/src/Engine.ts +++ b/src/Engine.ts @@ -148,8 +148,7 @@ export function modelCustomizationPhase( } else { namingStrategy = new NamingStrategy(); } - let retVal = setRelationId(generationOptions, dbModel); - retVal = applyNamingStrategy(namingStrategy, retVal); + let retVal = applyNamingStrategy(namingStrategy, dbModel); retVal = addImportsAndGenerationOptions(retVal, generationOptions); retVal = removeColumnDefaultProperties(retVal, defaultValues); return retVal; @@ -216,19 +215,6 @@ function addImportsAndGenerationOptions( return dbModel; } -function setRelationId(generationOptions: IGenerationOptions, model: Entity[]) { - // TODO: - // if (generationOptions.relationIds) { - // model.forEach(ent => { - // ent.columns.forEach(col => { - // col.relations.forEach(rel => { - // rel.relationIdField = rel.isOwner; - // }); - // }); - // }); - // } - return model; -} export function modelGenerationPhase( connectionOptions: IConnectionOptions, generationOptions: IGenerationOptions, @@ -478,7 +464,6 @@ function applyNamingStrategy( return retval; function changeRelationIdNames(model: Entity[]) { - // TODO: model.forEach(entity => { entity.relationIds.forEach(relationId => { const oldName = relationId.fieldName; diff --git a/src/drivers/AbstractDriver.ts b/src/drivers/AbstractDriver.ts index 7ea68ed..501de28 100644 --- a/src/drivers/AbstractDriver.ts +++ b/src/drivers/AbstractDriver.ts @@ -315,7 +315,6 @@ export default abstract class AbstractDriver { ); isOneToMany = !index; - // TODO: RelationId ownerEntity.columns = ownerEntity.columns.filter( v => !relationTmp.ownerColumns.some(u => u === v.tscName) || @@ -367,7 +366,6 @@ export default abstract class AbstractDriver { fieldName: ownerRelation.relatedField, relatedField: ownerRelation.fieldName, relatedTable: relationTmp.ownerTable.tscName, - // relationOptions: ownerRelation.relationOptions, relationType: isOneToMany ? "OneToMany" : "OneToOne" }; diff --git a/src/oldModels/ColumnInfo.ts b/src/oldModels/ColumnInfo.ts deleted file mode 100644 index b373c99..0000000 --- a/src/oldModels/ColumnInfo.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { ColumnOptions } from "typeorm"; -import RelationInfo from "./RelationInfo"; - -export default class ColumnInfo { - public options: ColumnOptions = {}; - - public tsName: string = ""; - - public tsType: - | "number" - | "string" - | "boolean" - | "Date" - | "Buffer" - | "object" - | "string | object" - | "string | string[]" - | "any" - | string; - - public relations: RelationInfo[] = []; -} diff --git a/src/oldModels/EntityInfo.ts b/src/oldModels/EntityInfo.ts deleted file mode 100644 index b1cf4a7..0000000 --- a/src/oldModels/EntityInfo.ts +++ /dev/null @@ -1,38 +0,0 @@ -import ColumnInfo from "./ColumnInfo"; -import IndexInfo from "./IndexInfo"; - -export default class EntityInfo { - public tsEntityName: string; - - public sqlEntityName: string; - - public Columns: ColumnInfo[]; - - public Imports: string[]; - - public UniqueImports: string[]; - - public Indexes: IndexInfo[]; - - public Schema?: string; - - public GenerateConstructor: boolean; - - public IsActiveRecord: boolean; - - public Database?: string; - - public relationImports() { - const imports: string[] = []; - this.Columns.forEach(column => { - column.relations.forEach(relation => { - if (this.tsEntityName !== relation.relatedTable) { - imports.push(relation.relatedTable); - } - }); - }); - this.UniqueImports = imports.filter( - (elem, index, self) => index === self.indexOf(elem) - ); - } -} diff --git a/src/oldModels/IndexColumnInfo.ts b/src/oldModels/IndexColumnInfo.ts deleted file mode 100644 index f4fa605..0000000 --- a/src/oldModels/IndexColumnInfo.ts +++ /dev/null @@ -1,3 +0,0 @@ -export default interface IndexColumnInfo { - name: string; -} diff --git a/src/oldModels/IndexInfo.ts b/src/oldModels/IndexInfo.ts deleted file mode 100644 index ac94f15..0000000 --- a/src/oldModels/IndexInfo.ts +++ /dev/null @@ -1,8 +0,0 @@ -import IndexColumnInfo from "./IndexColumnInfo"; - -export default interface IndexInfo { - name: string; - columns: IndexColumnInfo[]; - isUnique: boolean; - isPrimaryKey: boolean; -} diff --git a/src/oldModels/RelationInfo.ts b/src/oldModels/RelationInfo.ts deleted file mode 100644 index efaa10e..0000000 --- a/src/oldModels/RelationInfo.ts +++ /dev/null @@ -1,46 +0,0 @@ -export default class RelationInfo { - 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; - - public actionOnUpdate: - | "RESTRICT" - | "CASCADE" - | "SET NULL" - | "DEFAULT" - | null; - - public relationIdField: boolean = false; - - public get isOneToMany(): boolean { - return this.relationType === "OneToMany"; - } - - public get isManyToMany(): boolean { - return this.relationType === "ManyToMany"; - } - - public get isOneToOne(): boolean { - return this.relationType === "OneToOne"; - } - - public get isManyToOne(): boolean { - return this.relationType === "ManyToOne"; - } -} diff --git a/src/oldModels/RelationTempInfo.ts b/src/oldModels/RelationTempInfo.ts deleted file mode 100644 index f6914f8..0000000 --- a/src/oldModels/RelationTempInfo.ts +++ /dev/null @@ -1,15 +0,0 @@ -export default interface RelationTempInfo { - ownerTable: string; - ownerColumnsNames: string[]; - referencedTable: string; - referencedColumnsNames: string[]; - actionOnDelete: - | "RESTRICT" - | "CASCADE" - | "SET NULL" - | "DEFAULT" - | "NO ACTION" - | null; - actionOnUpdate: "RESTRICT" | "CASCADE" | "SET NULL" | "DEFAULT" | null; - objectId: number | string; -} diff --git a/test/drivers/MssqlDriver.test.ts b/test/drivers/MssqlDriver.test.ts index 5c815b9..b3a6380 100644 --- a/test/drivers/MssqlDriver.test.ts +++ b/test/drivers/MssqlDriver.test.ts @@ -2,10 +2,7 @@ import { expect } from "chai"; import * as MSSQL from "mssql"; import * as Sinon from "sinon"; import MssqlDriver from "../../src/drivers/MssqlDriver"; -import EntityInfo from "../../src/oldModels/EntityInfo"; -import ColumnInfo from "../../src/oldModels/ColumnInfo"; -import IndexInfo from "../../src/oldModels/IndexInfo"; -import RelationInfo from "../../src/oldModels/RelationInfo"; +import { Entity } from "../../src/models/Entity"; interface FakeResponse extends MSSQL.IResult { recordsets: MSSQL.IRecordSet[]; @@ -26,8 +23,7 @@ class FakeRecordset extends Array implements MSSQL.IRecordSet { } } -// TODO: Remove -describe.skip("MssqlDriver", function() { +describe("MssqlDriver", function() { let driver: MssqlDriver; const sandbox = Sinon.sandbox.create(); @@ -52,14 +48,18 @@ describe.skip("MssqlDriver", function() { } }); const result = await driver.GetAllTables("schema", "db"); - const expectedResult = [] as EntityInfo[]; - const y = new EntityInfo(); - y.tsEntityName = "name"; - y.sqlEntityName = "name"; - y.Schema = "schema"; - y.Columns = [] as ColumnInfo[]; - y.Indexes = [] as IndexInfo[]; - y.Database = ""; + const expectedResult = [] as Entity[]; + const y: Entity = { + columns: [], + indices: [], + relationIds: [], + relations: [], + sqlName: "name", + tscName: "name", + schema: "schema", + database: "", + fileImports: [] + }; expectedResult.push(y); expect(result).to.be.deep.equal(expectedResult); }); @@ -83,36 +83,38 @@ describe.skip("MssqlDriver", function() { } }); - const entities = [] as EntityInfo[]; - const y = new EntityInfo(); - y.tsEntityName = "name"; - y.Columns = [] as ColumnInfo[]; - y.Indexes = [] as IndexInfo[]; - y.Database = ""; + const entities = [] as Entity[]; + const y: Entity = { + columns: [], + indices: [], + relationIds: [], + relations: [], + sqlName: "name", + tscName: "name", + schema: "schema", + database: "", + fileImports: [] + }; entities.push(y); - const expected: EntityInfo[] = JSON.parse(JSON.stringify(entities)); - expected[0].Columns.push({ + const expected: Entity[] = JSON.parse(JSON.stringify(entities)); + expected[0].columns.push({ options: { - default: `() => "'a'"`, nullable: true, - generated: true, - name: "name", - unique: false, - type: "int" + name: "name" }, - tsName: "name", - tsType: "number", - relations: [] as RelationInfo[] + type: "int", + generated: true, + default: `() => "'a'"`, + tscName: "name", + tscType: "number" }); - throw new Error(); - // TODO: Remove - // const result = await driver.GetCoulmnsFromEntity( - // entities, - // "schema", - // "db" - // ); - // expect(result).to.be.deep.equal(expected); + const result = await driver.GetCoulmnsFromEntity( + entities, + "schema", + "db" + ); + expect(result).to.be.deep.equal(expected); }); it("should find primary indexes"); it("should get indexes info"); diff --git a/test/integration/github-issues/58/entity/feedextrainfo.ts b/test/integration/github-issues/58/entity/Feedextrainfo.ts similarity index 70% rename from test/integration/github-issues/58/entity/feedextrainfo.ts rename to test/integration/github-issues/58/entity/Feedextrainfo.ts index 2f822dd..bdd1a4d 100644 --- a/test/integration/github-issues/58/entity/feedextrainfo.ts +++ b/test/integration/github-issues/58/entity/Feedextrainfo.ts @@ -10,14 +10,14 @@ import { JoinColumn, JoinTable } from "typeorm"; -import { users } from "./users"; -import { quests } from "./quests"; +import { Users } from "./Users"; +import { Quests } from "./Quests"; @Entity("feedextrainfo") @Index("feedExtraInfo_FeedOwnerId_idx", ["feedOwnerId"], { unique: true }) @Index("feedExtraInfo_ReaderId_idx", ["readerId"], { unique: true }) @Index("feedExtraInfo_QuestId_idx", ["questId"], { unique: true }) -export class feedextrainfo { +export class Feedextrainfo { @PrimaryColumn({ name: "FeedOwnerId" }) feedOwnerId: number; @@ -27,17 +27,17 @@ export class feedextrainfo { @PrimaryColumn({ name: "ReaderId" }) readerId: number; - @OneToOne(type => users, FeedOwnerId => FeedOwnerId.feedextrainfo) + @OneToOne(type => Users, FeedOwnerId => FeedOwnerId.feedextrainfo) @JoinColumn({ name: "FeedOwnerId" }) - feedOwner: users; + feedOwner: Users; - @OneToOne(type => quests, QuestId => QuestId.feedextrainfo) + @OneToOne(type => Quests, QuestId => QuestId.feedextrainfo) @JoinColumn({ name: "QuestId" }) - quest: quests; + quest: Quests; - @OneToOne(type => users, ReaderId => ReaderId.feedextrainfo2) + @OneToOne(type => Users, ReaderId => ReaderId.feedextrainfo2) @JoinColumn({ name: "ReaderId" }) - reader: users; + reader: Users; @Column("int", { name: "MostUpdatedFeedEntryIdUserRead" diff --git a/test/integration/github-issues/58/entity/quests.ts b/test/integration/github-issues/58/entity/Quests.ts similarity index 63% rename from test/integration/github-issues/58/entity/quests.ts rename to test/integration/github-issues/58/entity/Quests.ts index 681c603..a4b2362 100644 --- a/test/integration/github-issues/58/entity/quests.ts +++ b/test/integration/github-issues/58/entity/Quests.ts @@ -10,16 +10,16 @@ import { JoinColumn, JoinTable } from "typeorm"; -import { feedextrainfo } from "./feedextrainfo"; +import { Feedextrainfo } from "./Feedextrainfo"; @Entity("quests") -export class quests { +export class Quests { @Column("int", { primary: true, name: "QuestId" }) questId: number; - @OneToOne(type => feedextrainfo, feedextrainfo => feedextrainfo.quest) - feedextrainfo: feedextrainfo; + @OneToOne(type => Feedextrainfo, feedextrainfo => feedextrainfo.quest) + feedextrainfo: Feedextrainfo; } diff --git a/test/integration/github-issues/58/entity/users.ts b/test/integration/github-issues/58/entity/Users.ts similarity index 54% rename from test/integration/github-issues/58/entity/users.ts rename to test/integration/github-issues/58/entity/Users.ts index 6ae9e82..06d1560 100644 --- a/test/integration/github-issues/58/entity/users.ts +++ b/test/integration/github-issues/58/entity/Users.ts @@ -10,19 +10,19 @@ import { JoinColumn, JoinTable } from "typeorm"; -import { feedextrainfo } from "./feedextrainfo"; +import { Feedextrainfo } from "./Feedextrainfo"; @Entity("users") -export class users { +export class Users { @Column("int", { primary: true, name: "UserId" }) userId: number; - @OneToOne(type => feedextrainfo, feedextrainfo => feedextrainfo.feedOwner) - feedextrainfo: feedextrainfo; + @OneToOne(type => Feedextrainfo, feedextrainfo => feedextrainfo.feedOwner) + feedextrainfo: Feedextrainfo; - @OneToOne(type => feedextrainfo, feedextrainfo2 => feedextrainfo2.reader) - feedextrainfo2: feedextrainfo; + @OneToOne(type => Feedextrainfo, feedextrainfo2 => feedextrainfo2.reader) + feedextrainfo2: Feedextrainfo; } diff --git a/test/utils/GeneralTestUtils.ts b/test/utils/GeneralTestUtils.ts index 00b7e23..acccab7 100644 --- a/test/utils/GeneralTestUtils.ts +++ b/test/utils/GeneralTestUtils.ts @@ -15,8 +15,8 @@ export function getGenerationOptions(resultsPath: string): IGenerationOptions { return { resultsPath, noConfigs: false, - convertCaseEntity: "none", // TODO: Change to lib defaults - convertCaseFile: "none", + convertCaseEntity: "pascal", + convertCaseFile: "pascal", convertCaseProperty: "camel", propertyVisibility: "none", lazy: false, From 097ce29951bb7a9300230875f0d1cba33a0d13d5 Mon Sep 17 00:00:00 2001 From: Kononnable Date: Sat, 12 Oct 2019 11:02:46 +0200 Subject: [PATCH 26/84] code cleanup --- src/Engine.ts | 32 ++--------------------- src/drivers/MssqlDriver.ts | 7 ++--- src/drivers/MysqlDriver.ts | 7 ++--- src/drivers/OracleDriver.ts | 7 ++--- src/drivers/PostgresDriver.ts | 7 ++--- src/drivers/SqliteDriver.ts | 5 ++-- src/entity.mst | 49 ----------------------------------- 7 files changed, 20 insertions(+), 94 deletions(-) diff --git a/src/Engine.ts b/src/Engine.ts index 04e749b..c6e4577 100644 --- a/src/Engine.ts +++ b/src/Engine.ts @@ -273,7 +273,6 @@ function createHandlebarsHelpers(generationOptions: IGenerationOptions) { const withoutQuotes = json.replace(/"([^(")"]+)":/g, "$1:"); return withoutQuotes.slice(1, withoutQuotes.length - 1); }); - Handlebars.registerHelper("curly", open => (open ? "{" : "}")); Handlebars.registerHelper("toEntityName", str => { let retStr = ""; switch (generationOptions.convertCaseEntity) { @@ -291,25 +290,6 @@ function createHandlebarsHelpers(generationOptions: IGenerationOptions) { } return retStr; }); - Handlebars.registerHelper("concat", (stra: string, strb: string) => { - return stra + strb; - }); - Handlebars.registerHelper("contains", function contains( - searchTerm: string, - target: string, - options - ) { - return target.indexOf(searchTerm) > -1 - ? options.fn(this) - : options.inverse(this); - }); - Handlebars.registerHelper("toFileImports", (set: Set) => { - return [...set].reduce( - (pv, cv) => - `${pv}import { {{toEntityName ${cv}}} } from './{{toFileName ${cv}}};`, - "" - ); - }); Handlebars.registerHelper("toFileName", str => { let retStr = ""; switch (generationOptions.convertCaseFile) { @@ -331,6 +311,7 @@ function createHandlebarsHelpers(generationOptions: IGenerationOptions) { return retStr; }); Handlebars.registerHelper("printPropertyVisibility", () => + // TODO: generationOptions.propertyVisibility !== "none" ? `${generationOptions.propertyVisibility} ` : "" @@ -352,7 +333,6 @@ function createHandlebarsHelpers(generationOptions: IGenerationOptions) { } return retStr; }); - Handlebars.registerHelper("toLowerCase", str => str.toLowerCase()); Handlebars.registerHelper( "toRelation", (entityType: string, relationType: Relation["relationType"]) => { @@ -366,18 +346,10 @@ function createHandlebarsHelpers(generationOptions: IGenerationOptions) { return retVal; } ); - Handlebars.registerHelper("tolowerCaseFirst", str => - changeCase.lowerCaseFirst(str) - ); Handlebars.registerHelper("strictMode", () => + // TODO: generationOptions.strictMode ? generationOptions.strictMode : "" ); - Handlebars.registerHelper("toLazy", str => { - if (generationOptions.lazy) { - return `Promise<${str}>`; - } - return str; - }); Handlebars.registerHelper({ and: (v1, v2) => v1 && v2, eq: (v1, v2) => v1 === v2, diff --git a/src/drivers/MssqlDriver.ts b/src/drivers/MssqlDriver.ts index 1331107..40ab741 100644 --- a/src/drivers/MssqlDriver.ts +++ b/src/drivers/MssqlDriver.ts @@ -80,8 +80,9 @@ WHERE TABLE_TYPE='BASE TABLE' and TABLE_SCHEMA in (${schema}) AND TABLE_CATALOG }) .forEach(resp => { const tscName = resp.COLUMN_NAME; - const options: Partial = {}; - options.name = resp.COLUMN_NAME; + const options: Column["options"] = { + name: resp.COLUMN_NAME + }; if (resp.IS_NULLABLE === "YES") options.nullable = true; if (resp.IsUnique === 1) options.unique = true; const generated = resp.IsIdentity === 1 ? true : undefined; @@ -223,7 +224,7 @@ WHERE TABLE_TYPE='BASE TABLE' and TABLE_SCHEMA in (${schema}) AND TABLE_CATALOG generated, type: columnType, default: defaultValue, - options: { name: "", ...options }, // TODO: Change + options, tscName, tscType }); diff --git a/src/drivers/MysqlDriver.ts b/src/drivers/MysqlDriver.ts index f6cc0eb..0038e23 100644 --- a/src/drivers/MysqlDriver.ts +++ b/src/drivers/MysqlDriver.ts @@ -70,8 +70,9 @@ export default class MysqlDriver extends AbstractDriver { .forEach(resp => { const tscName = resp.COLUMN_NAME; let tscType = ""; - const options: Partial = {}; - options.name = resp.COLUMN_NAME; + const options: Column["options"] = { + name: resp.COLUMN_NAME + }; const generated = resp.IsIdentity === 1 ? true : undefined; const defaultValue = MysqlDriver.ReturnDefaultValueFunction( resp.COLUMN_DEFAULT @@ -254,7 +255,7 @@ export default class MysqlDriver extends AbstractDriver { generated, type: columnType, default: defaultValue, - options: { name: "", ...options }, // TODO: Change + options, tscName, tscType }); diff --git a/src/drivers/OracleDriver.ts b/src/drivers/OracleDriver.ts index 971044a..618cc8c 100644 --- a/src/drivers/OracleDriver.ts +++ b/src/drivers/OracleDriver.ts @@ -72,8 +72,9 @@ export default class OracleDriver extends AbstractDriver { .filter(filterVal => filterVal.TABLE_NAME === ent.tscName) .forEach(resp => { const tscName = resp.COLUMN_NAME; - const options: Partial = {}; - options.name = resp.COLUMN_NAME; + const options: Column["options"] = { + name: resp.COLUMN_NAME + }; if (resp.NULLABLE === "Y") options.nullable = true; if (resp.IS_UNIQUE > 0) options.unique = true; const generated = @@ -205,7 +206,7 @@ export default class OracleDriver extends AbstractDriver { generated, type: columnType, default: defaultValue, - options: { name: "", ...options }, // TODO: Change + options, tscName, tscType }); diff --git a/src/drivers/PostgresDriver.ts b/src/drivers/PostgresDriver.ts index 50bfb0c..4ad3e96 100644 --- a/src/drivers/PostgresDriver.ts +++ b/src/drivers/PostgresDriver.ts @@ -80,8 +80,9 @@ export default class PostgresDriver extends AbstractDriver { .filter(filterVal => filterVal.table_name === ent.tscName) .forEach(resp => { const tscName = resp.column_name; - const options: Partial = {}; - options.name = resp.column_name; + const options: Column["options"] = { + name: resp.column_name + }; if (resp.is_nullable === "YES") options.nullable = true; if (resp.isunique === "1") options.unique = true; @@ -156,7 +157,7 @@ export default class PostgresDriver extends AbstractDriver { generated, type: columnType, default: defaultValue, - options: { name: "", ...options }, // TODO: Change + options, tscName, tscType }); diff --git a/src/drivers/SqliteDriver.ts b/src/drivers/SqliteDriver.ts index 60ce45a..028542f 100644 --- a/src/drivers/SqliteDriver.ts +++ b/src/drivers/SqliteDriver.ts @@ -66,8 +66,7 @@ export default class SqliteDriver extends AbstractDriver { response.forEach(resp => { const tscName = resp.name; let tscType = ""; - const options: Partial = {}; - options.name = resp.name; + const options: Column["options"] = { name: resp.name }; if (resp.notnull === 0) options.nullable = true; const isPrimary = resp.pk > 0 ? true : undefined; const defaultValue = SqliteDriver.ReturnDefaultValueFunction( @@ -216,7 +215,7 @@ export default class SqliteDriver extends AbstractDriver { primary: isPrimary, type: columnType, default: defaultValue, - options: { name: "", ...options }, // TODO: Change + options, tscName, tscType }); diff --git a/src/entity.mst b/src/entity.mst index cb9fcac..3a6aea7 100644 --- a/src/entity.mst +++ b/src/entity.mst @@ -36,52 +36,3 @@ import {BaseEntity,Column,Entity,Index,JoinColumn,JoinTable,ManyToMany,ManyToOne {{#fileImports}}{{> Import}}{{/fileImports~}} {{~> Entity}} - - -{{!-- -{{relationImports}}{{#each UniqueImports}}import {{curly true}}{{toEntityName this}}{{curly false}} from "./{{toFileName this}}"; -{{/each}} - - -@Entity("{{sqlEntityName}}"{{#Schema}} ,{schema:"{{.}}"{{#if ../Database}}, database:"{{../Database}}"{{/if}} } {{/Schema}}) -{{#Indexes}}{{^isPrimaryKey}}@Index("{{name}}",[{{#columns}}"{{toPropertyName name}}",{{/columns}}]{{#isUnique}},{unique:true}{{/isUnique}}) -{{/isPrimaryKey}}{{/Indexes}}export class {{toEntityName tsEntityName}}{{#IsActiveRecord}} extends BaseEntity{{/IsActiveRecord}} { -{{#Columns}} - - {{^relations}}{{#options}}{{#generated}} @PrimaryGeneratedColumn({ - type:"{{type}}", {{/generated}}{{^generated}} @Column("{{type}}",{ {{#nullable}} - nullable:true,{{/nullable}}{{^nullable}} - nullable:false,{{/nullable}}{{#primary}} - primary:{{primary}},{{/primary}}{{/generated}}{{#unique}} - unique: true,{{/unique}}{{#length}} - length:{{.}},{{/length}}{{#width}} - width:{{.}},{{/width}}{{#unsigned}} - unsigned: true,{{/unsigned}}{{#default}} - default: {{.}},{{/default}}{{#precision}} - precision:{{.}},{{/precision}}{{#scale}} - scale:{{.}},{{/scale}}{{#enum}} - enum:[{{.}}],{{/enum}}{{#array}} - array:{{array}},{{/array}} - name:"{{name}}" - }){{/options}} - {{printPropertyVisibility}}{{toPropertyName tsName}}{{strictMode}}:{{tsType}}{{#options/nullable}} | null{{/options/nullable}}; - {{/relations}}{{#relations}} - @{{relationType}}(()=>{{toEntityName relatedTable}}, ({{toPropertyName relatedTable}}: {{toEntityName relatedTable}})=>{{toPropertyName relatedTable}}.{{#if isOwner}}{{toPropertyName ownerColumn}},{ {{#../options/primary}}primary:true,{{/../options/primary}}{{^../options/nullable}} nullable:false,{{/../options/nullable}}{{#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({ name:'{{ ../options/name}}'}){{else}}@JoinColumn({ name:'{{ ../options/name}}'}){{/if}}{{/isOwner}} - {{#if (or isOneToMany isManyToMany)}}{{printPropertyVisibility}}{{toPropertyName ../tsName}}{{strictMode}}:{{toLazy (concat (toEntityName relatedTable) "[]")}}; - {{else}}{{printPropertyVisibility}}{{toPropertyName ../tsName}}{{strictMode}}:{{toLazy (concat (toEntityName relatedTable) ' | null')}}; - {{/if}} - {{#if relationIdField }} - - @RelationId(({{toPropertyName ../../tsEntityName}}: {{toEntityName ../../tsEntityName}}) => {{toPropertyName ../../tsEntityName}}.{{toPropertyName ../tsName}}) - {{printPropertyVisibility}}{{toPropertyName ../tsName}}Id{{strictMode}}: {{#if isOneToOne}}{{toLazy ../tsType}}{{else}}{{toLazy (concat ../tsType "[]")}}{{/if}};{{/if}}{{/relations}} - {{/Columns}} - {{#if GenerateConstructor}} - - {{printPropertyVisibility}}constructor(init?: Partial<{{toEntityName tsEntityName}}>) { - {{#IsActiveRecord}}super(); - {{/IsActiveRecord}}Object.assign(this, init); - } - {{/if}} -} ---}} \ No newline at end of file From 234939134057f6469a41b872969728ff9b26cc1c Mon Sep 17 00:00:00 2001 From: Kononnable Date: Sat, 12 Oct 2019 11:07:11 +0200 Subject: [PATCH 27/84] longer wait times on travis CI --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 256e399..7cad05a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -41,6 +41,7 @@ before_script: - if [ -n "$DOCKER_USERNAME" ]; then mkdir /opt/oracle; npm i oracledb --no-save; docker cp typeorm-mg-oracle-client:/usr/lib/oracle/12.2/client64/lib /opt/oracle/instantclient_12_2; fi - export LD_LIBRARY_PATH=/opt/oracle/instantclient_12_2:$LD_LIBRARY_PATH script: +- sleep 60 - travis_retry sh -c 'sleep 60 && npm t -- --colors' after_success: - codecov From 12c9fbae9b7fc89a31792b60229f13016832b59f Mon Sep 17 00:00:00 2001 From: Kononnable Date: Sat, 12 Oct 2019 12:30:42 +0200 Subject: [PATCH 28/84] code linting --- .eslintrc.js | 11 +--- .travis.yml | 4 +- package.json | 2 +- src/Engine.ts | 2 +- src/Utils.ts | 8 ++- src/drivers/MssqlDriver.ts | 2 +- src/drivers/MysqlDriver.ts | 12 ++--- src/drivers/OracleDriver.ts | 22 ++++---- src/drivers/PostgresDriver.ts | 4 +- src/drivers/SqliteDriver.ts | 66 ++++++++--------------- src/index.ts | 54 +++++++++---------- src/models/Column.ts | 2 +- test/drivers/MssqlDriver.test.ts | 2 +- test/integration/runTestsFromPath.test.ts | 28 ++++------ test/mocha.opts | 3 ++ test/utils/EntityFileToJson.ts | 23 +++----- test/utils/GeneralTestUtils.ts | 6 +-- 17 files changed, 102 insertions(+), 149 deletions(-) create mode 100644 test/mocha.opts diff --git a/.eslintrc.js b/.eslintrc.js index b2ae4ed..587e3f8 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -40,14 +40,5 @@ module.exports = { extensions: [".js", ".jsx", ".ts", ".tsx"] } } - }, - overrides: [ - { - files: ["**/*.test.ts"], - rules: { - "no-unused-expressions": "off", - "func-names": "off" - } - } - ] + } }; diff --git a/.travis.yml b/.travis.yml index 7cad05a..2331e31 100644 --- a/.travis.yml +++ b/.travis.yml @@ -41,8 +41,8 @@ before_script: - if [ -n "$DOCKER_USERNAME" ]; then mkdir /opt/oracle; npm i oracledb --no-save; docker cp typeorm-mg-oracle-client:/usr/lib/oracle/12.2/client64/lib /opt/oracle/instantclient_12_2; fi - export LD_LIBRARY_PATH=/opt/oracle/instantclient_12_2:$LD_LIBRARY_PATH script: -- sleep 60 -- travis_retry sh -c 'sleep 60 && npm t -- --colors' +- docker ps +- travis_retry sh -c 'sleep 60 && docker ps && npm t -- --colors' after_success: - codecov dd: diff --git a/package.json b/package.json index f4af5e7..40e1ba1 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "build": "npm run clean && tsc && ncp src/entity.mst dist/src/entity.mst", "prepare": "npm run build", "pretest": "tsc --noEmit", - "test": "nyc --reporter=lcov ts-node ./node_modules/mocha/bin/_mocha test/**/*.test.ts -- -R spec --bail", + "test": "nyc --reporter=lcov ts-node ./node_modules/mocha/bin/_mocha test/**/*.test.ts -- --bail", "posttest": "eslint ./**/*.ts ./src/**/*.ts ./test/**/*.ts", "clean": "rimraf coverage output dist", "prettier": "prettier --write ./src/*.ts ./src/**/*.ts" diff --git a/src/Engine.ts b/src/Engine.ts index c6e4577..2ef0e90 100644 --- a/src/Engine.ts +++ b/src/Engine.ts @@ -162,7 +162,7 @@ function removeColumnDefaultProperties( } dbModel.forEach(entity => { entity.columns.forEach(column => { - const defVal = defaultValues[column.tscType as any]; + const defVal = defaultValues[column.tscType]; if (defVal) { if ( column.options.length && diff --git a/src/Utils.ts b/src/Utils.ts index 38fdb98..bd10f3b 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -4,16 +4,14 @@ import { Entity } from "./models/Entity"; export function LogError( errText: string, isABug: boolean = true, - passedError?: any + passedError?: string | ErrorConstructor ) { let errObject = passedError; console.error(errText); console.error(`Error occured in typeorm-model-generator.`); console.error(`${packageVersion()} node@${process.version}`); console.error( - `If you think this is a bug please open an issue including this log on ${ - (packagejson as any).bugs.url - }` + `If you think this is a bug please open an issue including this log on ${packagejson.bugs.url}` ); if (isABug && !passedError) { errObject = new Error().stack; @@ -23,7 +21,7 @@ export function LogError( } } export function packageVersion() { - return `${(packagejson as any).name}@${(packagejson as any).version}`; + return `${packagejson.name}@${packagejson.version}`; } export function findNameForNewField( _fieldName: string, diff --git a/src/drivers/MssqlDriver.ts b/src/drivers/MssqlDriver.ts index 40ab741..4b639fa 100644 --- a/src/drivers/MssqlDriver.ts +++ b/src/drivers/MssqlDriver.ts @@ -89,7 +89,7 @@ WHERE TABLE_TYPE='BASE TABLE' and TABLE_SCHEMA in (${schema}) AND TABLE_CATALOG const defaultValue = MssqlDriver.ReturnDefaultValueFunction( resp.COLUMN_DEFAULT ); - const columnType = resp.DATA_TYPE as any; + const columnType = resp.DATA_TYPE; let tscType = ""; switch (resp.DATA_TYPE) { case "bigint": diff --git a/src/drivers/MysqlDriver.ts b/src/drivers/MysqlDriver.ts index 0038e23..75aab4a 100644 --- a/src/drivers/MysqlDriver.ts +++ b/src/drivers/MysqlDriver.ts @@ -456,21 +456,19 @@ export default class MysqlDriver extends AbstractDriver { } public async CreateDB(dbName: string) { - await this.ExecQuery(`CREATE DATABASE ${dbName}; `); + await this.ExecQuery(`CREATE DATABASE ${dbName}; `); } public async UseDB(dbName: string) { - await this.ExecQuery(`USE ${dbName}; `); + await this.ExecQuery(`USE ${dbName}; `); } public async DropDB(dbName: string) { - await this.ExecQuery(`DROP DATABASE ${dbName}; `); + await this.ExecQuery(`DROP DATABASE ${dbName}; `); } public async CheckIfDBExists(dbName: string): Promise { - const resp = await this.ExecQuery( - `SHOW DATABASES LIKE '${dbName}' ` - ); + const resp = await this.ExecQuery(`SHOW DATABASES LIKE '${dbName}' `); return resp.length > 0; } @@ -480,7 +478,7 @@ export default class MysqlDriver extends AbstractDriver { const stream = query.stream({}); const promise = new Promise((resolve, reject) => { stream.on("data", chunk => { - ret.push((chunk as any) as T); + ret.push((chunk as unknown) 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 618cc8c..88f99e9 100644 --- a/src/drivers/OracleDriver.ts +++ b/src/drivers/OracleDriver.ts @@ -86,7 +86,7 @@ export default class OracleDriver extends AbstractDriver { resp.DATA_DEFAULT ); const DATA_TYPE = resp.DATA_TYPE.replace(/\([0-9]+\)/g, ""); - const columnType = DATA_TYPE.toLowerCase() as any; + const columnType = DATA_TYPE.toLowerCase(); let tscType = ""; switch (DATA_TYPE.toLowerCase()) { case "char": @@ -332,22 +332,22 @@ export default class OracleDriver extends AbstractDriver { } } - public async ConnectToServer(connectionOptons: IConnectionOptions) { + public async ConnectToServer(connectionOptions: IConnectionOptions) { let config: any; - if (connectionOptons.user === String(process.env.ORACLE_UsernameSys)) { + if (connectionOptions.user === String(process.env.ORACLE_UsernameSys)) { config /* Oracle.IConnectionAttributes */ = { - connectString: `${connectionOptons.host}:${connectionOptons.port}/${connectionOptons.databaseName}`, - externalAuth: connectionOptons.ssl, - password: connectionOptons.password, + connectString: `${connectionOptions.host}:${connectionOptions.port}/${connectionOptions.databaseName}`, + externalAuth: connectionOptions.ssl, + password: connectionOptions.password, privilege: this.Oracle.SYSDBA, - user: connectionOptons.user + user: connectionOptions.user }; } else { config /* Oracle.IConnectionAttributes */ = { - connectString: `${connectionOptons.host}:${connectionOptons.port}/${connectionOptons.databaseName}`, - externalAuth: connectionOptons.ssl, - password: connectionOptons.password, - user: connectionOptons.user + connectString: `${connectionOptions.host}:${connectionOptions.port}/${connectionOptions.databaseName}`, + externalAuth: connectionOptions.ssl, + password: connectionOptions.password, + user: connectionOptions.user }; } const that = this; diff --git a/src/drivers/PostgresDriver.ts b/src/drivers/PostgresDriver.ts index 4ad3e96..c34402f 100644 --- a/src/drivers/PostgresDriver.ts +++ b/src/drivers/PostgresDriver.ts @@ -114,7 +114,7 @@ export default class PostgresDriver extends AbstractDriver { } return; } - const columnType = columnTypes.sqlType as any; + const columnType = columnTypes.sqlType; let tscType = columnTypes.tsType; if (columnTypes.isArray) options.array = true; if (columnTypes.enumValues.length > 0) @@ -123,7 +123,7 @@ export default class PostgresDriver extends AbstractDriver { tscType = tscType .split("|") .map(x => `${x.replace("|", "").trim()}[]`) - .join(" | ") as any; + .join(" | "); } if ( diff --git a/src/drivers/SqliteDriver.ts b/src/drivers/SqliteDriver.ts index 028542f..64ce684 100644 --- a/src/drivers/SqliteDriver.ts +++ b/src/drivers/SqliteDriver.ts @@ -24,7 +24,7 @@ export default class SqliteDriver extends AbstractDriver { public sqlite = sqliteLib.verbose(); - public db: any; + public db: sqliteLib.Database; public tablesWithGeneratedPrimaryKey: string[] = new Array(); @@ -176,12 +176,18 @@ export default class SqliteDriver extends AbstractDriver { ) && sqlOptions ) { - options.precision = sqlOptions[0] - .substring(1, sqlOptions[0].length - 1) - .split(",")[0] as any; - options.scale = sqlOptions[0] - .substring(1, sqlOptions[0].length - 1) - .split(",")[1] as any; + options.precision = Number.parseInt( + sqlOptions[0] + .substring(1, sqlOptions[0].length - 1) + .split(",")[0], + 10 + ); + options.scale = Number.parseInt( + sqlOptions[0] + .substring(1, sqlOptions[0].length - 1) + .split(",")[1], + 10 + ); } if ( this.ColumnTypesWithLength.some( @@ -203,10 +209,13 @@ export default class SqliteDriver extends AbstractDriver { ) && sqlOptions ) { - options.width = sqlOptions[0].substring( - 1, - sqlOptions[0].length - 1 - ) as any; + options.width = Number.parseInt( + sqlOptions[0].substring( + 1, + sqlOptions[0].length - 1 + ), + 10 + ); } if (columnType) { @@ -267,39 +276,6 @@ export default class SqliteDriver extends AbstractDriver { }); } ent.indices.push(indexInfo); - - // indexColumnsResponse.forEach(element => { - // const indexColumnInfo: IndexColumnInfo = {} as IndexColumnInfo; - // if ( - // ent.indices.filter(filterVal => { - // return filterVal.name === resp.name; - // }).length > 0 - // ) { - // indexInfo = ent.indices.find( - // filterVal => filterVal.name === resp.name - // )!; - // } else { - // indexInfo.columns = [] as IndexColumnInfo[]; - // indexInfo.name = resp.name; - // indexInfo.isUnique = resp.unique === 1; - // ent.indices.push(indexInfo); - // } - // indexColumnInfo.name = element.name; - // if ( - // indexColumnsResponse.length === 1 && - // indexInfo.isUnique - // ) { - // ent.columns - // .filter( - // v => v.tscName === indexColumnInfo.name - // ) - // .forEach(v => { - // // eslint-disable-next-line no-param-reassign - // v.options.unique = true; - // }); - // } - // indexInfo.columns.push(indexColumnInfo); - // }); }) ); }) @@ -425,7 +401,7 @@ export default class SqliteDriver extends AbstractDriver { } public async ExecQuery(sql: string): Promise { - let ret: any; + let ret: T[] = []; const promise = new Promise((resolve, reject) => { this.db.serialize(() => { this.db.all(sql, [], (err, row) => { diff --git a/src/index.ts b/src/index.ts index 4e9df15..c3a37aa 100644 --- a/src/index.ts +++ b/src/index.ts @@ -216,7 +216,7 @@ async function GetUtilParametersByInquirer() { const connectionOptions: IConnectionOptions = new IConnectionOptions(); const generationOptions: IGenerationOptions = new IGenerationOptions(); - connectionOptions.databaseType = ((await inquirer.prompt([ + connectionOptions.databaseType = (await inquirer.prompt([ { choices: [ "mssql", @@ -230,10 +230,10 @@ async function GetUtilParametersByInquirer() { name: "engine", type: "list" } - ])) as any).engine; + ])).engine; const driver = createDriver(connectionOptions.databaseType); if (connectionOptions.databaseType !== "sqlite") { - const answ: any = await inquirer.prompt([ + const answ = await inquirer.prompt([ { default: "localhost", message: "Database address:", @@ -283,7 +283,7 @@ async function GetUtilParametersByInquirer() { connectionOptions.databaseType === "mssql" || connectionOptions.databaseType === "postgres" ) { - connectionOptions.schemaName = ((await inquirer.prompt([ + connectionOptions.schemaName = (await inquirer.prompt([ { default: driver.standardSchema, message: @@ -291,7 +291,7 @@ async function GetUtilParametersByInquirer() { name: "schema", type: "input" } - ])) as any).schema; + ])).schema; } connectionOptions.port = answ.port; connectionOptions.host = answ.host; @@ -300,38 +300,38 @@ async function GetUtilParametersByInquirer() { connectionOptions.databaseName = answ.dbName; connectionOptions.ssl = answ.ssl; } else { - connectionOptions.databaseName = ((await inquirer.prompt([ + connectionOptions.databaseName = (await inquirer.prompt([ { default: "", message: "Path to database file:", name: "dbName", type: "input" } - ])) as any).dbName; + ])).dbName; } - generationOptions.resultsPath = ((await inquirer.prompt([ + generationOptions.resultsPath = (await inquirer.prompt([ { default: path.resolve(process.cwd(), "output"), message: "Path where generated models should be stored:", name: "output", type: "input" } - ])) as any).output; + ])).output; if ( connectionOptions.databaseType === "mssql" || connectionOptions.databaseType === "postgres" ) { - const { changeRequestTimeout } = (await inquirer.prompt([ + const { changeRequestTimeout } = await inquirer.prompt([ { default: false, message: "Do you want to change default sql query timeout?", name: "changeRequestTimeout", type: "confirm" } - ])) as any; + ]); if (changeRequestTimeout) { - const { timeout } = (await inquirer.prompt({ + const { timeout } = await inquirer.prompt({ message: "Query timeout(ms):", name: "timeout", type: "input", @@ -339,20 +339,20 @@ async function GetUtilParametersByInquirer() { const valid = !Number.isNaN(parseInt(value, 10)); return valid || "Please enter a valid number"; } - })) as any; + }); connectionOptions.timeout = timeout; } } - const { customizeGeneration } = (await inquirer.prompt([ + const { customizeGeneration } = await inquirer.prompt([ { default: false, message: "Do you want to customize generated model?", name: "customizeGeneration", type: "confirm" } - ])) as any; + ]); if (customizeGeneration) { - const customizations: string[] = ((await inquirer.prompt([ + const customizations: string[] = (await inquirer.prompt([ { choices: [ { @@ -394,9 +394,9 @@ async function GetUtilParametersByInquirer() { name: "selected", type: "checkbox" } - ])) as any).selected; + ])).selected; - generationOptions.propertyVisibility = ((await inquirer.prompt([ + generationOptions.propertyVisibility = (await inquirer.prompt([ { choices: ["public", "protected", "private", "none"], message: @@ -405,9 +405,9 @@ async function GetUtilParametersByInquirer() { default: "none", type: "list" } - ])) as any).propertyVisibility; + ])).propertyVisibility; - const { strictModeRaw } = (await inquirer.prompt([ + const { strictModeRaw } = await inquirer.prompt([ { choices: ["none", "?", "!"], message: "Mark fields as optional(?) or non-null(!)", @@ -415,7 +415,7 @@ async function GetUtilParametersByInquirer() { default: "none", type: "list" } - ])) as any; + ]); generationOptions.strictMode = strictModeRaw === "none" ? false : strictModeRaw; @@ -431,7 +431,7 @@ async function GetUtilParametersByInquirer() { ); if (customizations.includes("namingStrategy")) { - const namingStrategyPath = ((await inquirer.prompt([ + const namingStrategyPath = (await inquirer.prompt([ { default: path.resolve(process.cwd()), message: "Path to custom naming strategy file:", @@ -445,7 +445,7 @@ async function GetUtilParametersByInquirer() { ); } } - ])) as any).namingStrategy; + ])).namingStrategy; if (namingStrategyPath && namingStrategyPath !== "") { generationOptions.customNamingStrategyPath = namingStrategyPath; @@ -454,7 +454,7 @@ async function GetUtilParametersByInquirer() { } } if (customizations.includes("namingConvention")) { - const namingConventions = (await inquirer.prompt([ + const namingConventions = await inquirer.prompt([ { choices: ["pascal", "param", "camel", "none"], default: "pascal", @@ -476,21 +476,21 @@ async function GetUtilParametersByInquirer() { name: "propertyCase", type: "list" } - ])) as any; + ]); generationOptions.convertCaseFile = namingConventions.fileCase; generationOptions.convertCaseProperty = namingConventions.propertyCase; generationOptions.convertCaseEntity = namingConventions.entityCase; } } - const { saveConfig } = (await inquirer.prompt([ + const { saveConfig } = await inquirer.prompt([ { default: false, message: "Save configuration to config file?", name: "saveConfig", type: "confirm" } - ])) as any; + ]); if (saveConfig) { await fs.writeJson( path.resolve(process.cwd(), ".tomg-config"), diff --git a/src/models/Column.ts b/src/models/Column.ts index f62b867..bde92ce 100644 --- a/src/models/Column.ts +++ b/src/models/Column.ts @@ -1,7 +1,7 @@ import { ColumnType } from "typeorm"; export type Column = { - tscType: any; + tscType: string; tscName: string; type: ColumnType | string; // todo: remove ? diff --git a/test/drivers/MssqlDriver.test.ts b/test/drivers/MssqlDriver.test.ts index b3a6380..bfa577f 100644 --- a/test/drivers/MssqlDriver.test.ts +++ b/test/drivers/MssqlDriver.test.ts @@ -23,7 +23,7 @@ class FakeRecordset extends Array implements MSSQL.IRecordSet { } } -describe("MssqlDriver", function() { +describe("MssqlDriver", () => { let driver: MssqlDriver; const sandbox = Sinon.sandbox.create(); diff --git a/test/integration/runTestsFromPath.test.ts b/test/integration/runTestsFromPath.test.ts index c957d2b..240844d 100644 --- a/test/integration/runTestsFromPath.test.ts +++ b/test/integration/runTestsFromPath.test.ts @@ -22,27 +22,19 @@ require("dotenv").config(); chai.use(chaiSubset); -it("Column default values", async function() { +it("Column default values", async () => { const testPartialPath = "test/integration/defaultValues"; - this.timeout(60000); - this.slow(10000); // compiling created models takes time await runTestsFromPath(testPartialPath, true); -}); -it("Platform specyfic types", async function() { - this.timeout(60000); - this.slow(10000); // compiling created models takes time +}).timeout(); +it("Platform specyfic types", async () => { const testPartialPath = "test/integration/entityTypes"; await runTestsFromPath(testPartialPath, true); }); -describe("GitHub issues", async function() { - this.timeout(60000); - this.slow(10000); // compiling created models takes time +describe("GitHub issues", async () => { const testPartialPath = "test/integration/github-issues"; await runTestsFromPath(testPartialPath, false); }); -describe("TypeOrm examples", async function() { - this.timeout(60000); - this.slow(10000); // compiling created models takes time +describe("TypeOrm examples", async () => { const testPartialPath = "test/integration/examples"; await runTestsFromPath(testPartialPath, false); }); @@ -77,7 +69,7 @@ function runTestForMultipleDrivers( dbDrivers: string[], testPartialPath: string ) { - it(testName, async function() { + it(testName, async () => { const driversToRun = selectDriversForSpecyficTest(); const modelGenerationPromises = driversToRun.map(async dbDriver => { const { @@ -228,7 +220,7 @@ function compileGeneratedModel(filesGenPath: string, drivers: string[]) { ); } }); - const compileErrors = GTU.compileTsFiles(currentDirectoryFiles, { + const compiledWithoutErrors = GTU.compileTsFiles(currentDirectoryFiles, { experimentalDecorators: true, sourceMap: false, emitDecoratorMetadata: true, @@ -236,8 +228,10 @@ function compileGeneratedModel(filesGenPath: string, drivers: string[]) { moduleResolution: ts.ModuleResolutionKind.NodeJs, module: ts.ModuleKind.CommonJS }); - expect(compileErrors, "Errors detected while compiling generated model").to - .be.false; + expect( + compiledWithoutErrors, + "Errors detected while compiling generated model" + ).to.equal(true); } async function prepareTestRuns( diff --git a/test/mocha.opts b/test/mocha.opts new file mode 100644 index 0000000..05132a0 --- /dev/null +++ b/test/mocha.opts @@ -0,0 +1,3 @@ +--timeout 60000 +--slow 20000 +-R spec \ No newline at end of file diff --git a/test/utils/EntityFileToJson.ts b/test/utils/EntityFileToJson.ts index d091b89..ba6823b 100644 --- a/test/utils/EntityFileToJson.ts +++ b/test/utils/EntityFileToJson.ts @@ -6,7 +6,7 @@ class EntityJson { public columns: EntityColumn[] = [] as EntityColumn[]; - public indicies: EntityIndex[] = [] as EntityIndex[]; + public indices: EntityIndex[] = [] as EntityIndex[]; } class EntityColumn { public columnName: string; @@ -15,12 +15,7 @@ class EntityColumn { public columnOptions: any = {}; - public relationType: - | "OneToOne" - | "OneToMany" - | "ManyToOne" - | "ManyToMany" - | "None" = "None"; + public relationType: "OneToOne" | "OneToMany" | "ManyToOne" | "ManyToMany"; public isOwnerOfRelation: boolean = false; } @@ -283,7 +278,7 @@ export default class EntityFileToJson { isMultilineStatement = false; const ind = new EntityIndex(); EntityFileToJson.getIndexOptions(trimmedLine, ind); - retVal.indicies.push(ind); + retVal.indices.push(ind); } return; } @@ -424,7 +419,7 @@ export default class EntityFileToJson { isMultilineStatement = false; const ind = new EntityIndex(); EntityFileToJson.getIndexOptions(trimmedLine, ind); - retVal.indicies.push(ind); + retVal.indices.push(ind); } return; } @@ -472,13 +467,11 @@ export default class EntityFileToJson { ); } if ( - retVal.indicies.length > 0 && - retVal.indicies[retVal.indicies.length - 1].columnNames + retVal.indices.length > 0 && + retVal.indices[retVal.indices.length - 1].columnNames .length === 0 ) { - retVal.indicies[ - retVal.indicies.length - 1 - ].columnNames.push( + retVal.indices[retVal.indices.length - 1].columnNames.push( retVal.columns[retVal.columns.length - 1].columnName ); } @@ -494,7 +487,7 @@ export default class EntityFileToJson { console.log(`${trimmedLine}`); }); - retVal.indicies = retVal.indicies.map(ind => { + retVal.indices = retVal.indices.map(ind => { ind.columnNames = ind.columnNames.map(colName => { if (colName.endsWith("Id")) { colName = colName.substr(0, colName.length - 2); diff --git a/test/utils/GeneralTestUtils.ts b/test/utils/GeneralTestUtils.ts index acccab7..d3d2d1d 100644 --- a/test/utils/GeneralTestUtils.ts +++ b/test/utils/GeneralTestUtils.ts @@ -301,7 +301,7 @@ export function compileTsFiles( ): boolean { const program = ts.createProgram(fileNames, options); const emitResult = program.emit(); - let compileErrors = false; + let compiledWithoutErrors = true; const preDiagnostics = ts.getPreEmitDiagnostics(program); const allDiagnostics = [...preDiagnostics, ...emitResult.diagnostics]; @@ -318,10 +318,10 @@ export function compileTsFiles( `${diagnostic.file!.fileName} (${lineAndCharacter.line + 1},${lineAndCharacter.character + 1}): ${message}` ); - compileErrors = true; + compiledWithoutErrors = false; }); - return compileErrors; + return compiledWithoutErrors; } export function getEnabledDbDrivers() { From 8f719f67bb7e8972fb0e63d2bc9ae6ba71cb1016 Mon Sep 17 00:00:00 2001 From: Kononnable Date: Sat, 12 Oct 2019 17:45:18 +0200 Subject: [PATCH 29/84] proper column names pluralization --- package-lock.json | 11 +++++++++++ package.json | 2 ++ src/NamingStrategy.ts | 10 +++++++--- .../sample18-lazy-relations/entity/Category.ts | 2 +- .../sample18-lazy-relations/entity/Post.ts | 2 +- .../sample4-many-to-many/entity/Post.ts | 4 ++-- .../entity/PostMetadata.ts | 18 +++++++++++++----- 7 files changed, 37 insertions(+), 12 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8afdab2..1c9d8b4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -352,6 +352,12 @@ "moment": ">=2.14.0" } }, + "@types/pluralize": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/pluralize/-/pluralize-0.0.29.tgz", + "integrity": "sha512-BYOID+l2Aco2nBik+iYS4SZX0Lf20KPILP5RGmM1IgzdwNdTs0eebiFriOPcej1sX9mLnSoiNte5zcFxssgpGA==", + "dev": true + }, "@types/prettier": { "version": "1.18.3", "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-1.18.3.tgz", @@ -4217,6 +4223,11 @@ "semver-compare": "^1.0.0" } }, + "pluralize": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", + "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==" + }, "postgres-array": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", diff --git a/package.json b/package.json index 40e1ba1..718351f 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "mssql": "^5.1.0", "mysql": "^2.17.1", "pg": "^7.12.0", + "pluralize": "^8.0.0", "prettier": "^1.18.2", "reflect-metadata": "^0.1.13", "sqlite3": "^4.0.9", @@ -52,6 +53,7 @@ "@types/node": "^12.6.9", "@types/oracledb": "^3.1.3", "@types/pg": "^7.4.14", + "@types/pluralize": "0.0.29", "@types/prettier": "^1.18.3", "@types/sinon": "^7.0.13", "@types/sqlite3": "^3.1.5", diff --git a/src/NamingStrategy.ts b/src/NamingStrategy.ts index 42bd127..38423a7 100644 --- a/src/NamingStrategy.ts +++ b/src/NamingStrategy.ts @@ -1,3 +1,4 @@ +import { plural } from "pluralize"; import AbstractNamingStrategy from "./AbstractNamingStrategy"; import { Relation } from "./models/Relation"; import { RelationId } from "./models/RelationId"; @@ -22,7 +23,9 @@ export default class NamingStrategy extends AbstractNamingStrategy { if (!Number.isNaN(parseInt(columnName[columnName.length - 1], 10))) { columnName = columnName.substring(0, columnName.length - 1); } - columnName += isRelationToMany ? "s" : ""; + if (isRelationToMany) { + columnName = plural(columnName); + } return columnName; } @@ -52,8 +55,9 @@ export default class NamingStrategy extends AbstractNamingStrategy { if (!Number.isNaN(parseInt(columnName[columnName.length - 1], 10))) { columnName = columnName.substring(0, columnName.length - 1); } - columnName += isRelationToMany ? "s" : ""; - + if (isRelationToMany) { + columnName = plural(columnName); + } return columnName; } diff --git a/test/integration/examples/sample18-lazy-relations/entity/Category.ts b/test/integration/examples/sample18-lazy-relations/entity/Category.ts index 1f90c4f..4b7632f 100644 --- a/test/integration/examples/sample18-lazy-relations/entity/Category.ts +++ b/test/integration/examples/sample18-lazy-relations/entity/Category.ts @@ -16,7 +16,7 @@ export class Category { @Column() name: string; - @ManyToMany(type => Post, post => post.categorys, { + @ManyToMany(type => Post, post => post.categories, { lazy: true }) posts: Promise; diff --git a/test/integration/examples/sample18-lazy-relations/entity/Post.ts b/test/integration/examples/sample18-lazy-relations/entity/Post.ts index e5418d6..0209d7e 100644 --- a/test/integration/examples/sample18-lazy-relations/entity/Post.ts +++ b/test/integration/examples/sample18-lazy-relations/entity/Post.ts @@ -34,5 +34,5 @@ export class Post { // cascade: true }) @JoinTable() - categorys: Promise; + categories: Promise; } diff --git a/test/integration/examples/sample4-many-to-many/entity/Post.ts b/test/integration/examples/sample4-many-to-many/entity/Post.ts index 5c2a680..a3e219c 100644 --- a/test/integration/examples/sample4-many-to-many/entity/Post.ts +++ b/test/integration/examples/sample4-many-to-many/entity/Post.ts @@ -32,7 +32,7 @@ export class Post { // cascade: true }) @JoinTable() - postCategorys: PostCategory[]; + postCategories: PostCategory[]; // post has relation with details. cascade inserts here means if new PostDetails instance will be set to this // relation it will be inserted automatically to the db when you save this Post entity @@ -54,7 +54,7 @@ export class Post { // it will be inserted automatically to the db when you save this Post entity @ManyToMany(type => PostMetadata, metadata => metadata.posts) @JoinTable() - postMetadatas: PostMetadata[]; + postMetadata: PostMetadata[]; // post has relation with details. full cascades here @ManyToMany(type => PostInformation, information => information.posts, { diff --git a/test/integration/examples/sample4-many-to-many/entity/PostMetadata.ts b/test/integration/examples/sample4-many-to-many/entity/PostMetadata.ts index 9bb0f38..280ff53 100644 --- a/test/integration/examples/sample4-many-to-many/entity/PostMetadata.ts +++ b/test/integration/examples/sample4-many-to-many/entity/PostMetadata.ts @@ -1,16 +1,24 @@ -import { PrimaryGeneratedColumn, Column, Entity, OneToOne, OneToMany, ManyToOne, ManyToMany, JoinColumn, JoinTable } from "typeorm"; -import {Post} from "./Post"; +import { + PrimaryGeneratedColumn, + Column, + Entity, + OneToOne, + OneToMany, + ManyToOne, + ManyToMany, + JoinColumn, + JoinTable +} from "typeorm"; +import { Post } from "./Post"; @Entity("PostMetadata") export class PostMetadata { - @PrimaryGeneratedColumn() id: number; @Column() description: string; - @ManyToMany(type => Post, post => post.postMetadatas) + @ManyToMany(type => Post, post => post.postMetadata) posts: Post[]; - } From 30c2da8446b28bbb94032b57543032feff2f9a65 Mon Sep 17 00:00:00 2001 From: Kononnable Date: Sat, 12 Oct 2019 18:50:23 +0200 Subject: [PATCH 30/84] test why mariadb travis build failed --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 2331e31..3495f23 100644 --- a/.travis.yml +++ b/.travis.yml @@ -42,6 +42,7 @@ before_script: - export LD_LIBRARY_PATH=/opt/oracle/instantclient_12_2:$LD_LIBRARY_PATH script: - docker ps +- docker logs typeorm-mariadb - travis_retry sh -c 'sleep 60 && docker ps && npm t -- --colors' after_success: - codecov From 6ac8460d416d0b5fa021505143ffbd84ae8b6a06 Mon Sep 17 00:00:00 2001 From: Kononnable Date: Sat, 12 Oct 2019 20:08:10 +0200 Subject: [PATCH 31/84] dependencies version upgrade trying to debug failing CI build --- .travis.yml | 3 +- package-lock.json | 1596 +++++++++++++++++++++++++++------------------ package.json | 56 +- 3 files changed, 982 insertions(+), 673 deletions(-) diff --git a/.travis.yml b/.travis.yml index 3495f23..c746455 100644 --- a/.travis.yml +++ b/.travis.yml @@ -42,8 +42,7 @@ before_script: - export LD_LIBRARY_PATH=/opt/oracle/instantclient_12_2:$LD_LIBRARY_PATH script: - docker ps -- docker logs typeorm-mariadb -- travis_retry sh -c 'sleep 60 && docker ps && npm t -- --colors' +- travis_retry sh -c 'sleep 60 && docker ps && docker logs typeorm-mg-mariadb && docker logs typeorm-mg-mysql && npm t -- --colors' after_success: - codecov dd: diff --git a/package-lock.json b/package-lock.json index 1c9d8b4..379644d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -131,28 +131,28 @@ } }, "@nodelib/fs.scandir": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.1.tgz", - "integrity": "sha512-NT/skIZjgotDSiXs0WqYhgcuBKhUMgfekCmCGtkUAiLqZdOnrdjmZr9wRl3ll64J9NF79uZ4fk16Dx0yMc/Xbg==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz", + "integrity": "sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw==", "dev": true, "requires": { - "@nodelib/fs.stat": "2.0.1", + "@nodelib/fs.stat": "2.0.3", "run-parallel": "^1.1.9" } }, "@nodelib/fs.stat": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.1.tgz", - "integrity": "sha512-+RqhBlLn6YRBGOIoVYthsG0J9dfpO79eJyN7BYBkZJtfqrBwf2KK+rD/M/yjZR6WBmIhAgOV7S60eCgaSWtbFw==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz", + "integrity": "sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA==", "dev": true }, "@nodelib/fs.walk": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.2.tgz", - "integrity": "sha512-J/DR3+W12uCzAJkw7niXDcqcKBg6+5G5Q/ZpThpGNzAUz70eOR6RV4XnnSN01qHZiVl0eavoxJsBypQoKsV2QQ==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz", + "integrity": "sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ==", "dev": true, "requires": { - "@nodelib/fs.scandir": "2.1.1", + "@nodelib/fs.scandir": "2.1.3", "fastq": "^1.6.0" } }, @@ -166,18 +166,18 @@ } }, "@sinonjs/commons": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.4.0.tgz", - "integrity": "sha512-9jHK3YF/8HtJ9wCAbG+j8cD0i0+ATS9A7gXFqS36TblLPNy6rEEc+SB0imo91eCboGaBYGV/MT1/br/J+EE7Tw==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.6.0.tgz", + "integrity": "sha512-w4/WHG7C4WWFyE5geCieFJF6MZkbW4VAriol5KlmQXpAQdxvV0p26sqNZOW6Qyw6Y0l9K4g+cHvvczR2sEEpqg==", "dev": true, "requires": { "type-detect": "4.0.8" } }, "@sinonjs/formatio": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-3.2.1.tgz", - "integrity": "sha512-tsHvOB24rvyvV2+zKMmPkZ7dXX6LSLKZ7aOtXY6Edklp0uRcgGpOsQTTGTcWViFyx4uhWc6GV8QdnALbIbIdeQ==", + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-3.2.2.tgz", + "integrity": "sha512-B8SEsgd8gArBLMD6zpRw3juQ2FVSsmdd7qlevyDqzS9WTCtvF55/gAL+h6gue8ZvPYcdiPdvueM/qm//9XzyTQ==", "dev": true, "requires": { "@sinonjs/commons": "^1", @@ -185,14 +185,22 @@ } }, "@sinonjs/samsam": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-3.3.1.tgz", - "integrity": "sha512-wRSfmyd81swH0hA1bxJZJ57xr22kC07a1N4zuIL47yTS04bDk6AoCkczcqHEjcRPmJ+FruGJ9WBQiJwMtIElFw==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-3.3.3.tgz", + "integrity": "sha512-bKCMKZvWIjYD0BLGnNrxVuw4dkWCYsLqFOUWw8VgKF/+5Y+mE7LfHWPIYoDXowH+3a9LsWDMo0uAP8YDosPvHQ==", "dev": true, "requires": { - "@sinonjs/commons": "^1.0.2", + "@sinonjs/commons": "^1.3.0", "array-from": "^2.1.1", - "lodash": "^4.17.11" + "lodash": "^4.17.15" + }, + "dependencies": { + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "dev": true + } } }, "@sinonjs/text-encoding": { @@ -202,24 +210,24 @@ "dev": true }, "@types/chai": { - "version": "4.1.7", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.1.7.tgz", - "integrity": "sha512-2Y8uPt0/jwjhQ6EiluT0XCri1Dbplr0ZxfFXUz+ye13gaqE8u5gL5ppao1JrUYr9cIip5S6MvQzBS7Kke7U9VA==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.2.3.tgz", + "integrity": "sha512-VRw2xEGbll3ZiTQ4J02/hUjNqZoue1bMhoo2dgM2LXjDdyaq4q80HgBDHwpI0/VKlo4Eg+BavyQMv/NYgTetzA==", "dev": true }, "@types/chai-as-promised": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/@types/chai-as-promised/-/chai-as-promised-7.1.1.tgz", - "integrity": "sha512-dberBxQW/XWv6BMj0su1lV9/C9AUx5Hqu2pisuS6S4YK/Qt6vurcj/BmcbEsobIWWCQzhesNY8k73kIxx4X7Mg==", + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/@types/chai-as-promised/-/chai-as-promised-7.1.2.tgz", + "integrity": "sha512-PO2gcfR3Oxa+u0QvECLe1xKXOqYTzCmWf0FhLhjREoW3fPAVamjihL7v1MOVLJLsnAMdLcjkfrs01yvDMwVK4Q==", "dev": true, "requires": { "@types/chai": "*" } }, "@types/chai-subset": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@types/chai-subset/-/chai-subset-1.3.2.tgz", - "integrity": "sha512-VMA1aOXwPEJADlj5ykmYv77YKmbEuAxiLz/+lT6vFIWQ1EA06jF01TytVBAbVTNk0pjfW1Uhw5R5MaEq426N0A==", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@types/chai-subset/-/chai-subset-1.3.3.tgz", + "integrity": "sha512-frBecisrNGz+F4T6bcc+NLeolfiojh5FxW2klu669+8BARtyQv2C/GkNW6FUodVe4BroGMP/wER/YDGc7rEllw==", "dev": true, "requires": { "@types/chai": "*" @@ -295,27 +303,28 @@ "dev": true }, "@types/mssql": { - "version": "4.0.16", - "resolved": "https://registry.npmjs.org/@types/mssql/-/mssql-4.0.16.tgz", - "integrity": "sha512-bvH+9IZJ46QyQtuBciDyDf3lSqFFM/XhdVsHsCdVm0CdaZwH421wOIHJ2ajb2CG4XFqfNXA+UVNDyPqiNz6c0w==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@types/mssql/-/mssql-4.3.1.tgz", + "integrity": "sha512-LB+fDgwAbcvGfFCWN89gqZgyTIbEmnLW4RzVZeiaDSZJwL8xv8Rei2zM/5E62eW9G0UoY/4fHDXxTNRnCdlJRg==", "dev": true, "requires": { - "@types/node": "*" + "@types/node": "*", + "@types/tedious": "*" } }, "@types/mysql": { - "version": "2.15.6", - "resolved": "https://registry.npmjs.org/@types/mysql/-/mysql-2.15.6.tgz", - "integrity": "sha512-PJBY2R3jGJwGrmFgGAJ+1nj4S/PLkF6nT+HvUygniq9ZcVht0mTH1TLAjjyfIXf9FfrELs8mbqOrWa/Tn89NCA==", + "version": "2.15.7", + "resolved": "https://registry.npmjs.org/@types/mysql/-/mysql-2.15.7.tgz", + "integrity": "sha512-S7cpDl+heeTe2zd7LGeAodEsx9AnkzW1vHJ9kKwr9ype1KohW01jaUmCYhpafrQvnxzcUJAfeYdDr3fET8ufPw==", "dev": true, "requires": { "@types/node": "*" } }, "@types/node": { - "version": "12.6.9", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.6.9.tgz", - "integrity": "sha512-+YB9FtyxXGyD54p8rXwWaN1EWEyar5L58GlGWgtH2I9rGmLGBQcw63+0jw+ujqVavNuO47S1ByAjm9zdHMnskw==", + "version": "12.7.12", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.7.12.tgz", + "integrity": "sha512-KPYGmfD0/b1eXurQ59fXD1GBzhSQfz6/lKBxkaHX9dKTzjXbK68Zt7yGUxUsCS1jeTy/8aL+d9JEr+S54mpkWQ==", "dev": true }, "@types/normalize-package-data": { @@ -325,18 +334,18 @@ "dev": true }, "@types/oracledb": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/@types/oracledb/-/oracledb-3.1.3.tgz", - "integrity": "sha512-UlFv/T2A+PnvaNldjGjVQ7EBXxrAqtPman3i5J9kUQu37W+l/iFM2BPTg6CYr/Uxx6v0dAoVgHb1Po+dFfCdSg==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/oracledb/-/oracledb-4.0.4.tgz", + "integrity": "sha512-csHiM6eeV6Yzb4riR7+SHsEGZ19+mm+gbEbN3gGpA4nQa2ICLMJReesWfz+GWka6RMCjNNEflfenXgZ8HVsU5Q==", "dev": true, "requires": { "@types/node": "*" } }, "@types/pg": { - "version": "7.4.14", - "resolved": "https://registry.npmjs.org/@types/pg/-/pg-7.4.14.tgz", - "integrity": "sha512-2e4XapP9V/X42IGByC5IHzCzHqLLCNJid8iZBbkk6lkaDMvli8Rk62YE9wjGcLD5Qr5Zaw1ShkQyXy91PI8C0Q==", + "version": "7.11.2", + "resolved": "https://registry.npmjs.org/@types/pg/-/pg-7.11.2.tgz", + "integrity": "sha512-4+rj7fnidA77jFURNanuPPc1HrQv+RkhI6s+K18G9zOKbOUUpChA/rbNMqFukNuZ89LoIt/I9dAlxf329TjCNw==", "dev": true, "requires": { "@types/node": "*", @@ -365,9 +374,9 @@ "dev": true }, "@types/sinon": { - "version": "7.0.13", - "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-7.0.13.tgz", - "integrity": "sha512-d7c/C/+H/knZ3L8/cxhicHUiTDxdgap0b/aNJfsmLwFu/iOP17mdgbQsbHA3SJmrzsjD0l3UEE5SN4xxuz5ung==", + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-7.5.0.tgz", + "integrity": "sha512-NyzhuSBy97B/zE58cDw4NyGvByQbAHNP9069KVSgnXt/sc0T6MFRh0InKAeBVHJWdSXG1S3+PxgVIgKo9mTHbw==", "dev": true }, "@types/sqlite3": { @@ -379,6 +388,15 @@ "@types/node": "*" } }, + "@types/tedious": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/tedious/-/tedious-4.0.0.tgz", + "integrity": "sha512-uu/7XzkXSoU/AngLDdGURUFw98vZFgzQOuOIIUbSPiUfkaU7O1z29bDN4VejtmM5NS21fCHVJdd+cM96h+L78w==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/through": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/through/-/through-0.0.29.tgz", @@ -425,30 +443,18 @@ "@types/json-schema": "^7.0.3", "@typescript-eslint/typescript-estree": "1.13.0", "eslint-scope": "^4.0.0" - } - }, - "@typescript-eslint/parser": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-1.13.0.tgz", - "integrity": "sha512-ITMBs52PCPgLb2nGPoeT4iU3HdQZHcPaZVw+7CsFagRJHUhyeTgorEwHXhFf3e7Evzi8oujKNpHc8TONth8AdQ==", - "dev": true, - "requires": { - "@types/eslint-visitor-keys": "^1.0.0", - "@typescript-eslint/experimental-utils": "1.13.0", - "@typescript-eslint/typescript-estree": "1.13.0", - "eslint-visitor-keys": "^1.0.0" - } - }, - "@typescript-eslint/typescript-estree": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-1.13.0.tgz", - "integrity": "sha512-b5rCmd2e6DCC6tCTN9GSUAuxdYwCM/k/2wdjHGrIRGPSJotWMCe/dGpi66u42bhuh8q3QBzqM4TMA1GUUCJvdw==", - "dev": true, - "requires": { - "lodash.unescape": "4.0.1", - "semver": "5.5.0" }, "dependencies": { + "@typescript-eslint/typescript-estree": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-1.13.0.tgz", + "integrity": "sha512-b5rCmd2e6DCC6tCTN9GSUAuxdYwCM/k/2wdjHGrIRGPSJotWMCe/dGpi66u42bhuh8q3QBzqM4TMA1GUUCJvdw==", + "dev": true, + "requires": { + "lodash.unescape": "4.0.1", + "semver": "5.5.0" + } + }, "semver": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", @@ -457,21 +463,100 @@ } } }, + "@typescript-eslint/parser": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-2.3.3.tgz", + "integrity": "sha512-+cV53HuYFeeyrNW8x/rgPmbVrzzp/rpRmwbJnNtwn4K8mroL1BdjxwQh7X9cUHp9rm4BBiEWmD3cSBjKG7d5mw==", + "dev": true, + "requires": { + "@types/eslint-visitor-keys": "^1.0.0", + "@typescript-eslint/experimental-utils": "2.3.3", + "@typescript-eslint/typescript-estree": "2.3.3", + "eslint-visitor-keys": "^1.1.0" + }, + "dependencies": { + "@typescript-eslint/experimental-utils": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-2.3.3.tgz", + "integrity": "sha512-MQ4jKPMTU1ty4TigJCRKFPye2qyQdH8jzIIkceaHgecKFmkNS1hXPqKiZ+mOehkz6+HcN5Nuvwm+frmWZR9tdg==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.3", + "@typescript-eslint/typescript-estree": "2.3.3", + "eslint-scope": "^5.0.0" + } + }, + "@typescript-eslint/typescript-estree": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-2.3.3.tgz", + "integrity": "sha512-GkACs12Xp8d/STunNv/iSMYJFQrkrax9vuPZySlgSzoJJtw1cp6tbEw4qsLskQv6vloLrkFJHcTJ0a/yCB5cIA==", + "dev": true, + "requires": { + "glob": "^7.1.4", + "is-glob": "^4.0.1", + "lodash.unescape": "4.0.1", + "semver": "^6.3.0" + } + }, + "eslint-scope": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.0.0.tgz", + "integrity": "sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw==", + "dev": true, + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "eslint-visitor-keys": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz", + "integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==", + "dev": true + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "@typescript-eslint/typescript-estree": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-2.3.3.tgz", + "integrity": "sha512-GkACs12Xp8d/STunNv/iSMYJFQrkrax9vuPZySlgSzoJJtw1cp6tbEw4qsLskQv6vloLrkFJHcTJ0a/yCB5cIA==", + "dev": true, + "requires": { + "glob": "^7.1.4", + "is-glob": "^4.0.1", + "lodash.unescape": "4.0.1", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, "abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" }, "acorn": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.2.1.tgz", - "integrity": "sha512-JD0xT5FCRDNyjDda3Lrg/IxFscp9q4tiYtxE1/nOzlKCk7hIRuYjhq1kCNkbPjMRMZuFq20HNQn1I9k8Oj0E+Q==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.1.0.tgz", + "integrity": "sha512-kL5CuoXA/dgxlBbVrflsflzQ3PAas7RYZB52NOm/6839iVYJgKMJ3cQJD+t2i5+qFa8h3MDpEOJiS64E8JLnSQ==", "dev": true }, "acorn-jsx": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.0.1.tgz", - "integrity": "sha512-HJ7CfNHrfJLlNTzIEUTj43LNWGkqpRLxm3YjAlcD0ACydk9XynzYsCBHxut+iqt+1aBXkx9UP/w/ZqMr13XIzg==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.0.2.tgz", + "integrity": "sha512-tiNTrP1MP0QrChmD2DdupCr6HWSFeKVw5d/dHTu4Y7rkAkRhU/Dt7dphAfIUyxtHpl/eBVip5uTNSpQJHylpAw==", "dev": true }, "adal-node": { @@ -498,14 +583,24 @@ } }, "agent-base": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.2.1.tgz", - "integrity": "sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", + "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", "dev": true, "requires": { "es6-promisify": "^5.0.0" } }, + "aggregate-error": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.0.1.tgz", + "integrity": "sha512-quoaXsZ9/BLNae5yiNoUz+Nhkwz83GhWwtYFglcjEQB2NDHCIpApbqXxIFnm4Pq/Nvhrsq5sYJFyohrrxnTGAA==", + "dev": true, + "requires": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + } + }, "ajv": { "version": "6.10.0", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.0.tgz", @@ -526,7 +621,8 @@ "ansi-escapes": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", - "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==" + "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", + "dev": true }, "ansi-regex": { "version": "3.0.0", @@ -679,9 +775,9 @@ "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" }, "base64-js": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz", - "integrity": "sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw==" + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", + "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==" }, "bcrypt-pbkdf": { "version": "1.0.2", @@ -735,9 +831,9 @@ "dev": true }, "buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.2.1.tgz", - "integrity": "sha512-c+Ko0loDaFfuPWiL02ls9Xd3GO3cPVmUobQ6t3rXNUk304u6hGq+8N/kFi+QEIKhzK3uwolVhLzszmfLmMLnqg==", + "version": "5.4.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.4.3.tgz", + "integrity": "sha512-zvj65TkFeIt3i6aj5bIvJDzjjQQGs4o/sNoezg1F1kYap9Nu2jcUdpwzRSJTHMMzG0H7bZkn4rNQpImhuxWX2A==", "requires": { "base64-js": "^1.0.2", "ieee754": "^1.1.4" @@ -778,6 +874,14 @@ "dev": true, "requires": { "callsites": "^2.0.0" + }, + "dependencies": { + "callsites": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", + "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=", + "dev": true + } } }, "caller-path": { @@ -790,9 +894,9 @@ } }, "callsites": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", - "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true }, "camel-case": { @@ -890,9 +994,9 @@ "dev": true }, "chownr": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.2.tgz", - "integrity": "sha512-GkfeAQh+QNy3wquu9oIZr6SS5x7wGdSgNQvD10X3r+AZr1Oys22HW8kAmDMvNg2+Dm0TeGaEuO8gFwdBXxwO8A==" + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.3.tgz", + "integrity": "sha512-i70fVHhmV3DtTl6nqvZOnIjbY0Pe4kAUjwHj8z0zAdgBtYrJyYwLKCCuRBQ5ppkyL0AkN7HKRnETdmdp1zqNXw==" }, "ci-info": { "version": "2.0.0", @@ -900,10 +1004,17 @@ "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", "dev": true }, + "clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true + }, "cli-cursor": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", + "dev": true, "requires": { "restore-cursor": "^2.0.0" } @@ -918,6 +1029,44 @@ "mz": "^2.4.0", "parse5": "^4.0.0", "yargs": "^13.0.0" + }, + "dependencies": { + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "yargs": { + "version": "13.3.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.0.tgz", + "integrity": "sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA==", + "requires": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.1" + } + }, + "yargs-parser": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz", + "integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==", + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } } }, "cli-truncate": { @@ -945,6 +1094,12 @@ "number-is-nan": "^1.0.0" } }, + "slice-ansi": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz", + "integrity": "sha1-7b+JA/ZvfOL46v1s7tZeJkyDGzU=", + "dev": true + }, "string-width": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", @@ -973,70 +1128,33 @@ "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=" }, "cliui": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", - "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", - "dev": true, + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", "requires": { - "string-width": "^2.1.1", - "strip-ansi": "^4.0.0", - "wrap-ansi": "^2.0.0" + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" }, "dependencies": { - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "dev": true, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", "requires": { - "number-is-nan": "^1.0.0" - } - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" } }, "wrap-ansi": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", - "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", - "dev": true, + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", "requires": { - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1" - }, - "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 - }, - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dev": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - } + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" } } } @@ -1047,9 +1165,9 @@ "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" }, "codecov": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/codecov/-/codecov-3.5.0.tgz", - "integrity": "sha512-/OsWOfIHaQIr7aeZ4pY0UC1PZT6kimoKFOFYFNb6wxo3iw12nRrh+mNGH72rnXxNsq6SGfesVPizm/6Q3XqcFQ==", + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/codecov/-/codecov-3.6.1.tgz", + "integrity": "sha512-IUJB6WG47nWK7o50etF8jBadxdMw7DmoQg05yIljstXFBGB6clOZsIj6iD4P82T2YaIU3qq+FFu8K9pxgkCJDQ==", "dev": true, "requires": { "argv": "^0.0.2", @@ -1057,18 +1175,6 @@ "js-yaml": "^3.13.1", "teeny-request": "^3.11.3", "urlgrey": "^0.4.4" - }, - "dependencies": { - "js-yaml": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", - "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - } } }, "color-convert": { @@ -1158,6 +1264,24 @@ "is-directory": "^0.3.1", "js-yaml": "^3.13.1", "parse-json": "^4.0.0" + }, + "dependencies": { + "import-fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", + "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=", + "dev": true, + "requires": { + "caller-path": "^2.0.0", + "resolve-from": "^3.0.0" + } + }, + "resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", + "dev": true + } } }, "cp-file": { @@ -1195,9 +1319,9 @@ }, "dependencies": { "semver": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", - "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", "dev": true } } @@ -1273,22 +1397,41 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "dev": true, "requires": { "object-keys": "^1.0.12" } }, "del": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/del/-/del-5.0.0.tgz", - "integrity": "sha512-TfU3nUY0WDIhN18eq+pgpbLY9AfL5RfiE9czKaTSolc6aK7qASXfDErvYgjV1UqCR4sNXDoxO0/idPmhDUt2Sg==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/del/-/del-5.1.0.tgz", + "integrity": "sha512-wH9xOVHnczo9jN2IW68BabcecVPxacIA3g/7z6vhSU/4stOKQzeCRK0yD0A24WiAAUJmmVpWqrERcTxnLo3AnA==", "dev": true, "requires": { - "globby": "^10.0.0", - "is-path-cwd": "^2.0.0", - "is-path-in-cwd": "^2.0.0", - "p-map": "^2.0.0", - "rimraf": "^2.6.3" + "globby": "^10.0.1", + "graceful-fs": "^4.2.2", + "is-glob": "^4.0.1", + "is-path-cwd": "^2.2.0", + "is-path-inside": "^3.0.1", + "p-map": "^3.0.0", + "rimraf": "^3.0.0", + "slash": "^3.0.0" + }, + "dependencies": { + "graceful-fs": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.2.tgz", + "integrity": "sha512-IItsdsea19BoLC7ELy13q1iJFNmd7ofZH5+X/pJr90/nRoPEX0DJo1dHDbgtYWOhJhcCgMDTOw84RZ72q6lB+Q==", + "dev": true + }, + "rimraf": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.0.tgz", + "integrity": "sha512-NDGVxTsjqfunkds7CqsOiEnxln4Bo7Nddl3XhS4pXg5OzwkLqJ971ZVAAnB+DDLnF76N+VnDEiBHaVV8I06SUg==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + } } }, "delayed-stream": { @@ -1352,9 +1495,9 @@ } }, "dotenv": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.0.0.tgz", - "integrity": "sha512-30xVGqjLjiUOArT4+M5q9sYdvuR4riM6yK9wMcas9Vbp6zZa+ocC9dp6QoftuhTPhFAiLK/0C5Ni2nou/Bk8lg==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.1.0.tgz", + "integrity": "sha512-GUE3gqcDCaMltj2++g6bRQ5rBJWtkWTmqmD0fo1RnnMuUqHNCt2oTPeDnS9n6fKYvlhn7AeBkb38lymBtWBQdA==", "dev": true }, "ecc-jsbn": { @@ -1386,9 +1529,9 @@ "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" }, "end-of-stream": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", - "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", "dev": true, "requires": { "once": "^1.4.0" @@ -1407,7 +1550,6 @@ "version": "1.13.0", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.13.0.tgz", "integrity": "sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg==", - "dev": true, "requires": { "es-to-primitive": "^1.2.0", "function-bind": "^1.1.1", @@ -1421,7 +1563,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", - "dev": true, "requires": { "is-callable": "^1.1.4", "is-date-object": "^1.0.1", @@ -1435,9 +1576,9 @@ "dev": true }, "es6-promise": { - "version": "4.2.6", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.6.tgz", - "integrity": "sha512-aRVgGdnmW2OiySVPUC9e6m+plolMAJKjZnQlCwNSuK5yQ0JN61DZSO1X1Ufd1foqWRAlig0rhduTCHe7sVtK5Q==", + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", "dev": true }, "es6-promisify": { @@ -1455,9 +1596,9 @@ "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" }, "eslint": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.1.0.tgz", - "integrity": "sha512-QhrbdRD7ofuV09IuE2ySWBz0FyXCq0rriLTZXZqaWSI79CVtHVRdkFuFTViiqzZhkCgfOh9USpriuGN2gIpZDQ==", + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.5.1.tgz", + "integrity": "sha512-32h99BoLYStT1iq1v2P9uwpyznQ4M2jRiFB6acitKz52Gqn+vPaMDUTB1bYi1WN4Nquj2w+t+bimYUG83DC55A==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", @@ -1467,9 +1608,9 @@ "debug": "^4.0.1", "doctrine": "^3.0.0", "eslint-scope": "^5.0.0", - "eslint-utils": "^1.3.1", - "eslint-visitor-keys": "^1.0.0", - "espree": "^6.0.0", + "eslint-utils": "^1.4.2", + "eslint-visitor-keys": "^1.1.0", + "espree": "^6.1.1", "esquery": "^1.0.1", "esutils": "^2.0.2", "file-entry-cache": "^5.0.1", @@ -1518,26 +1659,37 @@ "estraverse": "^4.1.1" } }, - "ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "eslint-visitor-keys": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz", + "integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==", "dev": true }, - "import-fresh": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.1.0.tgz", - "integrity": "sha512-PpuksHKGt8rXfWEr9m9EHIpgyyaltBy8+eF6GJM0QCAxMgxCfucMF3mjecK2QsJr0amJW7gTqh5/wht0z2UhEQ==", + "inquirer": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.5.2.tgz", + "integrity": "sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ==", "dev": true, "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" + "ansi-escapes": "^3.2.0", + "chalk": "^2.4.2", + "cli-cursor": "^2.1.0", + "cli-width": "^2.0.0", + "external-editor": "^3.0.3", + "figures": "^2.0.0", + "lodash": "^4.17.12", + "mute-stream": "0.0.7", + "run-async": "^2.2.0", + "rxjs": "^6.4.0", + "string-width": "^2.1.0", + "strip-ansi": "^5.1.0", + "through": "^2.3.6" } }, - "resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "mute-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", + "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", "dev": true }, "semver": { @@ -1545,12 +1697,6 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true - }, - "strip-json-comments": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.0.1.tgz", - "integrity": "sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw==", - "dev": true } } }, @@ -1566,20 +1712,12 @@ } }, "eslint-config-prettier": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-6.0.0.tgz", - "integrity": "sha512-vDrcCFE3+2ixNT5H83g28bO/uYAwibJxerXPj+E7op4qzBCsAV36QfvdAyVOoNxKAH2Os/e01T/2x++V0LPukA==", + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-6.4.0.tgz", + "integrity": "sha512-YrKucoFdc7SEko5Sxe4r6ixqXPDP1tunGw91POeZTTRKItf/AMFYt/YLEQtZMkR2LVpAVhcAcZgcWpm1oGPW7w==", "dev": true, "requires": { "get-stdin": "^6.0.0" - }, - "dependencies": { - "get-stdin": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz", - "integrity": "sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==", - "dev": true - } } }, "eslint-import-resolver-node": { @@ -1860,14 +1998,22 @@ "dev": true }, "espree": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-6.0.0.tgz", - "integrity": "sha512-lJvCS6YbCn3ImT3yKkPe0+tJ+mH6ljhGNjHQH9mRtiO6gjhVAOhVXW1yjnwqGwTkK3bGbye+hb00nFNmu0l/1Q==", + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-6.1.1.tgz", + "integrity": "sha512-EYbr8XZUhWbYCqQRW0duU5LxzL5bETN6AjKBGy1302qqzPaCH10QbRg3Wvco79Z8x9WbiE8HYB4e75xl6qUYvQ==", "dev": true, "requires": { - "acorn": "^6.0.7", - "acorn-jsx": "^5.0.0", - "eslint-visitor-keys": "^1.0.0" + "acorn": "^7.0.0", + "acorn-jsx": "^5.0.2", + "eslint-visitor-keys": "^1.1.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz", + "integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==", + "dev": true + } } }, "esprima": { @@ -1946,16 +2092,15 @@ "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=" }, "fast-glob": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.0.4.tgz", - "integrity": "sha512-wkIbV6qg37xTJwqSsdnIphL1e+LaGz4AIQqr00mIubMaEhv1/HEmJ0uuCGZRNRUkZZmOB5mJKO0ZUTVq+SxMQg==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.1.0.tgz", + "integrity": "sha512-TrUz3THiq2Vy3bjfQUB2wNyPdGBeGmdjbzzBLhfHN4YFurYptCKwGq/TfiRavbGywFRzY6U2CdmQ1zmsY5yYaw==", "dev": true, "requires": { - "@nodelib/fs.stat": "^2.0.1", - "@nodelib/fs.walk": "^1.2.1", - "glob-parent": "^5.0.0", - "is-glob": "^4.0.1", - "merge2": "^1.2.3", + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.0", + "merge2": "^1.3.0", "micromatch": "^4.0.2" } }, @@ -1980,14 +2125,15 @@ } }, "figlet": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/figlet/-/figlet-1.2.3.tgz", - "integrity": "sha512-+F5zdvZ66j77b8x2KCPvWUHC0UCKUMWrewxmewgPlagp3wmDpcrHMbyv/ygq/6xoxBPGQA+UJU3SMoBzKoROQQ==" + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/figlet/-/figlet-1.2.4.tgz", + "integrity": "sha512-mv8YA9RruB4C5QawPaD29rEVx3N97ZTyNrE4DAfbhuo6tpcMdKnPVo8MlyT3RP5uPcg5M14bEJBq7kjFf4kAWg==" }, "figures": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", + "dev": true, "requires": { "escape-string-regexp": "^1.0.5" } @@ -2047,14 +2193,6 @@ "dev": true, "requires": { "is-buffer": "~2.0.3" - }, - "dependencies": { - "is-buffer": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.3.tgz", - "integrity": "sha512-U15Q7MXTuZlrbymiz95PJpZxu8IlipAp4dtS3wOdgPXx3mqBnslrWU14kxfHB+Py/+2PVKSr37dMAgM2A4uArw==", - "dev": true - } } }, "flat-cache": { @@ -2066,6 +2204,17 @@ "flatted": "^2.0.0", "rimraf": "2.6.3", "write": "1.0.3" + }, + "dependencies": { + "rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + } } }, "flatted": { @@ -2129,11 +2278,11 @@ } }, "fs-minipass": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.6.tgz", - "integrity": "sha512-crhvyXcMejjv3Z5d2Fa9sf5xLYVCF5O1c71QxbVnbLsmYMBEvDAftewesN/HhY03YRoA7zOMxjNGrF5svGaaeQ==", + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz", + "integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==", "requires": { - "minipass": "^2.2.1" + "minipass": "^2.6.0" } }, "fs.realpath": { @@ -2144,8 +2293,7 @@ "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, "functional-red-black-tree": { "version": "1.0.1", @@ -2218,15 +2366,15 @@ "dev": true }, "get-own-enumerable-property-symbols": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.0.tgz", - "integrity": "sha512-CIJYJC4GGF06TakLg8z4GQKvDsx9EMspVxOYih7LerEL/WosUnFIww45CGfxfeKHqlg3twgUrYRT1O3WQqjGCg==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.1.tgz", + "integrity": "sha512-09/VS4iek66Dh2bctjRkowueRJbY1JDGR1L/zRxO1Qk8Uxs6PnqaNSqalpizPT+CDjre3hnEsuzvhgomz9qYrA==", "dev": true }, "get-stdin": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-7.0.0.tgz", - "integrity": "sha512-zRKcywvrXlXsA0v0i9Io4KDRaAw7+a1ZpjRwl9Wox8PFlVCCHra7E9c4kqXCoCM9nR5tBkaTTZRBoCm60bFqTQ==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz", + "integrity": "sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==", "dev": true }, "get-stream": { @@ -2260,9 +2408,9 @@ } }, "glob-parent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.0.0.tgz", - "integrity": "sha512-Z2RwiujPRGluePM6j699ktJYxmPpJKCfpGA13jz2hmFZC7gKetzrWvg5KN3+OsIFmydGyZ1AVwERCq1w/ZZwRg==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.0.tgz", + "integrity": "sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw==", "dev": true, "requires": { "is-glob": "^4.0.1" @@ -2288,6 +2436,14 @@ "ignore": "^5.1.1", "merge2": "^1.2.3", "slash": "^3.0.0" + }, + "dependencies": { + "ignore": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.4.tgz", + "integrity": "sha512-MzbUSahkTW1u7JpKKjY7LCARd1fU5W2rLdxlM4kdkayuCwZImjkpluF9CM1aLewYJguPDqewLam18Y6AU69A8A==", + "dev": true + } } }, "graceful-fs": { @@ -2302,9 +2458,9 @@ "dev": true }, "handlebars": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.1.2.tgz", - "integrity": "sha512-nvfrjqvt9xQ8Z/w0ijewdD/vvWDTOweBUm96NTr66Wfvo1mJenBLwcYmPs3TIBP5ruzYGD7Hx/DaM9RmhroGPw==", + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.4.3.tgz", + "integrity": "sha512-B0W4A2U1ww3q7VVthTKfh+epHx+q4mCt6iK+zEAzbMBpWQAwxCeKxEGpj/1oQTpzPXDNSOG7hmG14TsISH50yw==", "requires": { "neo-async": "^2.6.0", "optimist": "^0.6.1", @@ -2330,7 +2486,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, "requires": { "function-bind": "^1.1.1" } @@ -2358,8 +2513,7 @@ "has-symbols": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", - "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=", - "dev": true + "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=" }, "has-unicode": { "version": "2.0.1", @@ -2391,9 +2545,9 @@ } }, "highlight.js": { - "version": "9.15.8", - "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.15.8.tgz", - "integrity": "sha512-RrapkKQWwE+wKdF73VsOa2RQdIoO3mxwJ4P8mhbI6KYJUraUHRKM5w5zQQKXNk0xNL4UVRdulV9SBJcmzJNzVA==" + "version": "9.15.10", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.15.10.tgz", + "integrity": "sha512-RoV7OkQm0T3os3Dd2VHLNMoaoDVx77Wygln3n9l5YV172XonWG6rgQD3XnF/BuFFZw9A0TJgmMSO8FEWQgvcXw==" }, "hosted-git-info": { "version": "2.7.1", @@ -2412,19 +2566,19 @@ } }, "https-proxy-agent": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz", - "integrity": "sha512-HPCTS1LW51bcyMYbxUIOO4HEOlQ1/1qRaFWcyxvwaqUS9TY88aoEuHUY33kuAh1YhVVaDQhLZsnPd+XNARWZlQ==", + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.2.tgz", + "integrity": "sha512-c8Ndjc9Bkpfx/vCJueCPy0jlP4ccCCSNDp8xwCZzPjKJUm+B+u9WX2x98Qx4n1PiMNTWo3D7KK5ifNV/yJyRzg==", "dev": true, "requires": { - "agent-base": "^4.1.0", + "agent-base": "^4.3.0", "debug": "^3.1.0" } }, "husky": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/husky/-/husky-3.0.2.tgz", - "integrity": "sha512-WXCtaME2x0o4PJlKY4ap8BzLA+D0zlvefqAvLCPriOOu+x0dpO5uc5tlB7CY6/0SE2EESmoZsj4jW5D09KrJoA==", + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/husky/-/husky-3.0.8.tgz", + "integrity": "sha512-HFOsgcyrX3qe/rBuqyTt+P4Gxn5P0seJmr215LAZ/vnwK3jWB3r0ck7swbzGRUbufCf9w/lgHPVbF/YXQALgfQ==", "dev": true, "requires": { "chalk": "^2.4.2", @@ -2434,10 +2588,18 @@ "is-ci": "^2.0.0", "opencollective-postinstall": "^2.0.2", "pkg-dir": "^4.2.0", - "please-upgrade-node": "^3.1.1", + "please-upgrade-node": "^3.2.0", "read-pkg": "^5.1.1", "run-node": "^1.0.0", "slash": "^3.0.0" + }, + "dependencies": { + "get-stdin": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-7.0.0.tgz", + "integrity": "sha512-zRKcywvrXlXsA0v0i9Io4KDRaAw7+a1ZpjRwl9Wox8PFlVCCHra7E9c4kqXCoCM9nR5tBkaTTZRBoCm60bFqTQ==", + "dev": true + } } }, "iconv-lite": { @@ -2454,27 +2616,27 @@ "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" }, "ignore": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.2.tgz", - "integrity": "sha512-vdqWBp7MyzdmHkkRWV5nY+PfGRbYbahfuvsBCh277tq+w9zyNi7h5CYJCK0kmzti9kU+O/cB7sE8HvKv6aXAKQ==", + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", "dev": true }, "ignore-walk": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.1.tgz", - "integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.3.tgz", + "integrity": "sha512-m7o6xuOaT1aqheYHKf8W6J5pYH85ZI9w077erOzLje3JsB1gkafkAhHHY19dqjulgIZHFm32Cp5uNZgcQqdJKw==", "requires": { "minimatch": "^3.0.4" } }, "import-fresh": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", - "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.1.0.tgz", + "integrity": "sha512-PpuksHKGt8rXfWEr9m9EHIpgyyaltBy8+eF6GJM0QCAxMgxCfucMF3mjecK2QsJr0amJW7gTqh5/wht0z2UhEQ==", "dev": true, "requires": { - "caller-path": "^2.0.0", - "resolve-from": "^3.0.0" + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" } }, "imurmurhash": { @@ -2484,9 +2646,9 @@ "dev": true }, "indent-string": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", - "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", "dev": true }, "inflight": { @@ -2509,42 +2671,119 @@ "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" }, "inquirer": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.5.0.tgz", - "integrity": "sha512-scfHejeG/lVZSpvCXpsB4j/wQNPM5JC8kiElOI0OUTwmc1RTpXr4H32/HOlQHcZiYl2z2VElwuCVDRG8vFmbnA==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.0.0.tgz", + "integrity": "sha512-rSdC7zelHdRQFkWnhsMu2+2SO41mpv2oF2zy4tMhmiLWkcKbOAs87fWAJhVXttKVwhdZvymvnuM95EyEXg2/tQ==", "requires": { - "ansi-escapes": "^3.2.0", + "ansi-escapes": "^4.2.1", "chalk": "^2.4.2", - "cli-cursor": "^2.1.0", + "cli-cursor": "^3.1.0", "cli-width": "^2.0.0", "external-editor": "^3.0.3", - "figures": "^2.0.0", - "lodash": "^4.17.12", - "mute-stream": "0.0.7", + "figures": "^3.0.0", + "lodash": "^4.17.15", + "mute-stream": "0.0.8", "run-async": "^2.2.0", "rxjs": "^6.4.0", - "string-width": "^2.1.0", + "string-width": "^4.1.0", "strip-ansi": "^5.1.0", "through": "^2.3.6" + }, + "dependencies": { + "ansi-escapes": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.2.1.tgz", + "integrity": "sha512-Cg3ymMAdN10wOk/VYfLV7KCQyv7EDirJ64500sU7n9UlmioEtDuU5Gd+hj73hXSU/ex7tHJSssmyftDdkMLO8Q==", + "requires": { + "type-fest": "^0.5.2" + } + }, + "cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "requires": { + "restore-cursor": "^3.1.0" + } + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "figures": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.0.0.tgz", + "integrity": "sha512-HKri+WoWoUgr83pehn/SIgLOMZ9nAWC6dcGj26RY2R4F50u4+RTUz0RCrUlOV3nKRAICW1UGzyb+kcX2qK1S/g==", + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + }, + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" + }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==" + }, + "onetime": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.0.tgz", + "integrity": "sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==", + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "requires": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + } + }, + "string-width": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.1.0.tgz", + "integrity": "sha512-NrX+1dVVh+6Y9dnQ19pR0pP4FiEIlUvdTGn8pw6CKTNq5sgib2nIhmUNT5TAmhWmvKr3WcxBcP3E8nWezuipuQ==", + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^5.2.0" + } + }, + "type-fest": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.5.2.tgz", + "integrity": "sha512-DWkS49EQKVX//Tbupb9TFa19c7+MK1XmzkrZUR8TAktmE/DizXoaoJV6TZ/tSIPXipqNiRI6CyAe7x69Jb6RSw==" + } } }, - "invert-kv": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", - "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==", - "dev": true - }, "is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", "dev": true }, + "is-buffer": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz", + "integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==", + "dev": true + }, "is-callable": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", - "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==", - "dev": true + "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==" }, "is-ci": { "version": "2.0.0", @@ -2558,8 +2797,7 @@ "is-date-object": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", - "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", - "dev": true + "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=" }, "is-directory": { "version": "0.3.1", @@ -2622,23 +2860,11 @@ "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", "dev": true }, - "is-path-in-cwd": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-2.1.0.tgz", - "integrity": "sha512-rNocXHgipO+rvnP6dk3zI20RpOtrAM/kzbB258Uw5BWr3TpXi861yzjo16Dn4hUox07iw5AyeMLHWsujkjzvRQ==", - "dev": true, - "requires": { - "is-path-inside": "^2.1.0" - } - }, "is-path-inside": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-2.1.0.tgz", - "integrity": "sha512-wiyhTzfDWsvwAW53OBWF5zuvaOGlZ6PwYxAbPVDhpm+gM09xKQGjBq/8uYN12aDvMxnAnq3dxTyoSoRNmg5YFg==", - "dev": true, - "requires": { - "path-is-inside": "^1.0.2" - } + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.2.tgz", + "integrity": "sha512-/2UGPSgmtqwo1ktx8NDHjuPwZWmHhO+gj0f93EkhLB5RgW9RZevWYYlIkS6zePc6U2WpOdQYIwHe9YC4DWEBVg==", + "dev": true }, "is-promise": { "version": "2.1.0", @@ -2649,7 +2875,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", - "dev": true, "requires": { "has": "^1.0.1" } @@ -2670,7 +2895,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", - "dev": true, "requires": { "has-symbols": "^1.0.0" } @@ -2785,6 +3009,15 @@ "requires": { "ms": "^2.1.1" } + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } } } }, @@ -2807,7 +3040,6 @@ "version": "3.13.1", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", - "dev": true, "requires": { "argparse": "^1.0.7", "esprima": "^4.0.0" @@ -2895,15 +3127,6 @@ "safe-buffer": "^5.0.1" } }, - "lcid": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", - "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", - "dev": true, - "requires": { - "invert-kv": "^2.0.0" - } - }, "levn": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", @@ -2921,9 +3144,9 @@ "dev": true }, "lint-staged": { - "version": "9.2.1", - "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-9.2.1.tgz", - "integrity": "sha512-3lGgJfBddCy/WndKdNko+uJbwyYjBD1k+V+SA+phBYWzH265S95KQya/Wln/UL+hOjc7NcjtFYVCUWuAcqYHhg==", + "version": "9.4.2", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-9.4.2.tgz", + "integrity": "sha512-OFyGokJSWTn2M6vngnlLXjaHhi8n83VIZZ5/1Z26SULRUWgR3ITWpAEQC9Pnm3MC/EpCxlwts/mQWDHNji2+zA==", "dev": true, "requires": { "chalk": "^2.4.2", @@ -2936,11 +3159,23 @@ "listr": "^0.14.3", "log-symbols": "^3.0.0", "micromatch": "^4.0.2", + "normalize-path": "^3.0.0", "please-upgrade-node": "^3.1.1", "string-argv": "^0.3.0", "stringify-object": "^3.3.0" }, "dependencies": { + "cross-spawn": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.1.tgz", + "integrity": "sha512-u7v4o84SwFpD32Z8IIcPZ6z1/ie24O6RU3RbtL5Y316l3KuHVPx9ItBgWQ6VlfAFnRnTtMUrsQ9MUUTuEZjogg==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, "debug": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", @@ -2951,12 +3186,12 @@ } }, "execa": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/execa/-/execa-2.0.3.tgz", - "integrity": "sha512-iM124nlyGSrXmuyZF1EMe83ESY2chIYVyDRZKgmcDynid2Q2v/+GuE7gNMl6Sy9Niwf4MC0DDxagOxeMPjuLsw==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-2.1.0.tgz", + "integrity": "sha512-Y/URAVapfbYy2Xp/gb6A0E7iR8xeqOCXsuuaoMn7A5PzrXUK84E1gyiEfq0wQd/GHA6GsoHWwhNq8anb0mleIw==", "dev": true, "requires": { - "cross-spawn": "^6.0.5", + "cross-spawn": "^7.0.0", "get-stream": "^5.0.0", "is-stream": "^2.0.0", "merge-stream": "^2.0.0", @@ -2982,15 +3217,6 @@ "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", "dev": true }, - "log-symbols": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz", - "integrity": "sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==", - "dev": true, - "requires": { - "chalk": "^2.4.2" - } - }, "mimic-fn": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", @@ -3026,6 +3252,30 @@ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.0.tgz", "integrity": "sha512-8cChqz0RP6SHJkMt48FW0A7+qUOn+OsnOsVtzI59tZ8m+5bCSk7hzwET0pulwOM2YMn9J1efb07KB9l9f30SGg==", "dev": true + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "which": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.1.tgz", + "integrity": "sha512-N7GBZOTswtB9lkQBZA4+zAXrjEIWAUOB93AvzUiudRzRxhUdLURQ7D/gAIMY1gatT/LTbmbcv8SiYazy3eYB7w==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } } } }, @@ -3044,6 +3294,14 @@ "listr-verbose-renderer": "^0.5.0", "p-map": "^2.0.0", "rxjs": "^6.3.3" + }, + "dependencies": { + "p-map": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", + "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==", + "dev": true + } } }, "listr-silent-renderer": { @@ -3103,6 +3361,12 @@ "object-assign": "^4.1.0" } }, + "indent-string": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", + "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=", + "dev": true + }, "log-symbols": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-1.0.2.tgz", @@ -3165,7 +3429,8 @@ "lodash": { "version": "4.17.14", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.14.tgz", - "integrity": "sha512-mmKYbW3GLuJeX+iGP+Y7Gp1AiGHGbXHCOh/jZmrawMmsE7MS4znI3RL2FsjbqOyMayHInjOeykW7PEajUk1/xw==" + "integrity": "sha512-mmKYbW3GLuJeX+iGP+Y7Gp1AiGHGbXHCOh/jZmrawMmsE7MS4znI3RL2FsjbqOyMayHInjOeykW7PEajUk1/xw==", + "dev": true }, "lodash.flattendeep": { "version": "4.4.0", @@ -3180,12 +3445,12 @@ "dev": true }, "log-symbols": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", - "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz", + "integrity": "sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==", "dev": true, "requires": { - "chalk": "^2.0.1" + "chalk": "^2.4.2" } }, "log-update": { @@ -3200,9 +3465,9 @@ } }, "lolex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/lolex/-/lolex-4.1.0.tgz", - "integrity": "sha512-BYxIEXiVq5lGIXeVHnsFzqa1TxN5acnKnPCdlZSpzm8viNEOhiigupA4vTQ9HEFQ6nLTQ9wQOgBknJgzUYQ9Aw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lolex/-/lolex-4.2.0.tgz", + "integrity": "sha512-gKO5uExCXvSm6zbF562EvM+rd1kQDnB9AZBbiQVzf1ZmdDpxUSvpnAaVOP83N/31mRK8Ml8/VE8DMvsAZQ+7wg==", "dev": true }, "lower-case": { @@ -3266,34 +3531,6 @@ "integrity": "sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g==", "dev": true }, - "map-age-cleaner": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", - "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==", - "dev": true, - "requires": { - "p-defer": "^1.0.0" - } - }, - "mem": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz", - "integrity": "sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==", - "dev": true, - "requires": { - "map-age-cleaner": "^0.1.1", - "mimic-fn": "^2.0.0", - "p-is-promise": "^2.0.0" - }, - "dependencies": { - "mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true - } - } - }, "merge-source-map": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/merge-source-map/-/merge-source-map-1.1.0.tgz", @@ -3310,9 +3547,9 @@ "dev": true }, "merge2": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.2.4.tgz", - "integrity": "sha512-FYE8xI+6pjFOhokZu0We3S5NKCirLbCzSh2Usf3qEyr4X8U+0jNg9P8RZ4qz+V2UoECLVwSyzU3LxXBaLGtD3A==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.3.0.tgz", + "integrity": "sha512-2j4DAdlBOkiSZIsaXk4mTE3sRS02yBHAtfy127xRV3bQUFqXkjHCHLW6Scv7DwNRbIWNHH8zpnz9zMaKXIdvYw==", "dev": true }, "micromatch": { @@ -3341,7 +3578,8 @@ "mimic-fn": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", - "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==" + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", + "dev": true }, "minimatch": { "version": "3.0.4", @@ -3357,9 +3595,9 @@ "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=" }, "minipass": { - "version": "2.3.5", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.3.5.tgz", - "integrity": "sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==", + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", + "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -3373,11 +3611,11 @@ } }, "minizlib": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.2.1.tgz", - "integrity": "sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA==", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz", + "integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==", "requires": { - "minipass": "^2.2.1" + "minipass": "^2.9.0" } }, "mkdirp": { @@ -3396,9 +3634,9 @@ } }, "mocha": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-6.2.0.tgz", - "integrity": "sha512-qwfFgY+7EKAAUAdv7VYMZQknI7YJSGesxHyhn6qD52DV8UcSZs5XwCifcZGMVIE4a5fbmhvbotxC0DLQ0oKohQ==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-6.2.1.tgz", + "integrity": "sha512-VCcWkLHwk79NYQc8cxhkmI8IigTIhsCwZ6RTxQsqK6go4UvEhzJkYuHm8B2YtlSxcYq2fY+ucr4JBwoD6ci80A==", "dev": true, "requires": { "ansi-colors": "3.2.3", @@ -3421,9 +3659,9 @@ "supports-color": "6.0.0", "which": "1.3.1", "wide-align": "1.1.3", - "yargs": "13.2.2", - "yargs-parser": "13.0.0", - "yargs-unparser": "1.5.0" + "yargs": "13.3.0", + "yargs-parser": "13.1.1", + "yargs-unparser": "1.6.0" }, "dependencies": { "glob": { @@ -3440,6 +3678,15 @@ "path-is-absolute": "^1.0.0" } }, + "log-symbols": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", + "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", + "dev": true, + "requires": { + "chalk": "^2.0.1" + } + }, "string-width": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", @@ -3451,6 +3698,12 @@ "strip-ansi": "^5.1.0" } }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true + }, "supports-color": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", @@ -3470,22 +3723,31 @@ } }, "yargs": { - "version": "13.2.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.2.2.tgz", - "integrity": "sha512-WyEoxgyTD3w5XRpAQNYUB9ycVH/PQrToaTXdYXRdOXvEy1l19br+VJsc0vcO8PTGg5ro/l/GY7F/JMEBmI0BxA==", + "version": "13.3.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.0.tgz", + "integrity": "sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA==", "dev": true, "requires": { - "cliui": "^4.0.0", + "cliui": "^5.0.0", "find-up": "^3.0.0", "get-caller-file": "^2.0.1", - "os-locale": "^3.1.0", "require-directory": "^2.1.1", "require-main-filename": "^2.0.0", "set-blocking": "^2.0.0", "string-width": "^3.0.0", "which-module": "^2.0.0", "y18n": "^4.0.0", - "yargs-parser": "^13.0.0" + "yargs-parser": "^13.1.1" + } + }, + "yargs-parser": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz", + "integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" } } } @@ -3512,9 +3774,9 @@ } }, "mute-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", - "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=" + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==" }, "mysql": { "version": "2.17.1", @@ -3594,12 +3856,12 @@ "dev": true }, "nise": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/nise/-/nise-1.5.0.tgz", - "integrity": "sha512-Z3sfYEkLFzFmL8KY6xnSJLRxwQwYBjOXi/24lb62ZnZiGA0JUzGGTI6TBIgfCSMIDl9Jlu8SRmHNACLTemDHww==", + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/nise/-/nise-1.5.2.tgz", + "integrity": "sha512-/6RhOUlicRCbE9s+94qCUsyE+pKlVJ5AhIv+jEE7ESKwnbXqulKZ1FYU+XAtHHWE9TinYvAxDUJAb912PwPoWA==", "dev": true, "requires": { - "@sinonjs/formatio": "^3.1.0", + "@sinonjs/formatio": "^3.2.1", "@sinonjs/text-encoding": "^0.7.1", "just-extend": "^4.0.2", "lolex": "^4.1.0", @@ -3625,9 +3887,9 @@ }, "dependencies": { "semver": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", - "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", "dev": true } } @@ -3655,10 +3917,18 @@ "tar": "^4" }, "dependencies": { + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "requires": { + "glob": "^7.1.3" + } + }, "semver": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", - "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==" + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" } } }, @@ -3694,15 +3964,21 @@ } } }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, "npm-bundled": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.0.6.tgz", "integrity": "sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g==" }, "npm-packlist": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.4.tgz", - "integrity": "sha512-zTLo8UcVYtDU3gdeaFu2Xu0n0EvelfHDGuqtNIn5RO7yQj4H1TqNdBc/yZjxnWA0PVB8D3Woyp0i5B43JwQ6Vw==", + "version": "1.4.6", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.6.tgz", + "integrity": "sha512-u65uQdb+qwtGvEJh/DgQgW1Xg7sqeNbmxYyrvlNznaVTjV3E5P6F/EFjM+BVHXl7JJlsdG8A64M0XI8FI/IOlg==", "requires": { "ignore-walk": "^3.0.1", "npm-bundled": "^1.0.1" @@ -3771,6 +4047,56 @@ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "yargs": { + "version": "13.3.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.0.tgz", + "integrity": "sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA==", + "dev": true, + "requires": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.1" + }, + "dependencies": { + "yargs-parser": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz", + "integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } } } }, @@ -3787,8 +4113,7 @@ "object-keys": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" }, "object.assign": { "version": "4.1.0", @@ -3818,7 +4143,6 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz", "integrity": "sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY=", - "dev": true, "requires": { "define-properties": "^1.1.2", "es-abstract": "^1.5.1" @@ -3848,6 +4172,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "dev": true, "requires": { "mimic-fn": "^1.0.0" } @@ -3865,6 +4190,13 @@ "requires": { "minimist": "~0.0.1", "wordwrap": "~0.0.2" + }, + "dependencies": { + "wordwrap": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=" + } } }, "optionator": { @@ -3879,14 +4211,6 @@ "prelude-ls": "~1.1.2", "type-check": "~0.3.2", "wordwrap": "~1.0.0" - }, - "dependencies": { - "wordwrap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", - "dev": true - } } }, "os-homedir": { @@ -3894,17 +4218,6 @@ "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" }, - "os-locale": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", - "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", - "dev": true, - "requires": { - "execa": "^1.0.0", - "lcid": "^2.0.0", - "mem": "^4.0.0" - } - }, "os-tmpdir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", @@ -3919,24 +4232,12 @@ "os-tmpdir": "^1.0.0" } }, - "p-defer": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", - "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=", - "dev": true - }, "p-finally": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", "dev": true }, - "p-is-promise": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.1.0.tgz", - "integrity": "sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==", - "dev": true - }, "p-limit": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz", @@ -3954,10 +4255,13 @@ } }, "p-map": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", - "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==", - "dev": true + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", + "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", + "dev": true, + "requires": { + "aggregate-error": "^3.0.0" + } }, "p-try": { "version": "2.2.0", @@ -3996,14 +4300,6 @@ "dev": true, "requires": { "callsites": "^3.0.0" - }, - "dependencies": { - "callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true - } } }, "parent-require": { @@ -4053,12 +4349,6 @@ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" }, - "path-is-inside": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", - "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", - "dev": true - }, "path-key": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", @@ -4109,15 +4399,15 @@ "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" }, "pg": { - "version": "7.12.0", - "resolved": "https://registry.npmjs.org/pg/-/pg-7.12.0.tgz", - "integrity": "sha512-q54Ic0oBXfDZMwheP8ALeUX32TUXvF7SNgAlZjyhkDuFCJkQCgcLBz0Be5uOrAj3ljSok/CI9lRbYzEko0z1Zw==", + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/pg/-/pg-7.12.1.tgz", + "integrity": "sha512-l1UuyfEvoswYfcUe6k+JaxiN+5vkOgYcVSbSuw3FvdLqDbaoa2RJo1zfJKfPsSYPFVERd4GHvX3s2PjG1asSDA==", "requires": { "buffer-writer": "2.0.0", "packet-reader": "1.0.0", "pg-connection-string": "0.1.3", "pg-pool": "^2.0.4", - "pg-types": "~2.0.0", + "pg-types": "^2.1.0", "pgpass": "1.x", "semver": "4.3.2" } @@ -4138,9 +4428,9 @@ "integrity": "sha512-UiJyO5B9zZpu32GSlP0tXy8J2NsJ9EFGFfz5v6PSbdz/1hBLX1rNiiy5+mAm5iJJYwfCv4A0EBcQLGWwjbpzZw==" }, "pg-types": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.0.1.tgz", - "integrity": "sha512-b7y6QM1VF5nOeX9ukMQ0h8a9z89mojrBHXfJeSug4mhL0YpxNBm83ot2TROyoAmX/ZOX3UbwVO4EbH7i1ZZNiw==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", + "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", "requires": { "pg-int8": "1.0.1", "postgres-array": "~2.0.0", @@ -4215,9 +4505,9 @@ } }, "please-upgrade-node": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/please-upgrade-node/-/please-upgrade-node-3.1.1.tgz", - "integrity": "sha512-KY1uHnQ2NlQHqIJQpnh/i54rKkuxCEBx+voJIS/Mvb+L2iYd2NMotwduhKTMjfC1uKoX3VXOxLjIYG66dfJTVQ==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz", + "integrity": "sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg==", "dev": true, "requires": { "semver-compare": "^1.0.0" @@ -4314,6 +4604,11 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" } } }, @@ -4461,15 +4756,16 @@ } }, "resolve-from": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", - "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true }, "restore-cursor": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", + "dev": true, "requires": { "onetime": "^2.0.0", "signal-exit": "^3.0.2" @@ -4482,26 +4778,12 @@ "dev": true }, "rimraf": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", - "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.0.tgz", + "integrity": "sha512-NDGVxTsjqfunkds7CqsOiEnxln4Bo7Nddl3XhS4pXg5OzwkLqJ971ZVAAnB+DDLnF76N+VnDEiBHaVV8I06SUg==", + "dev": true, "requires": { "glob": "^7.1.3" - }, - "dependencies": { - "glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - } } }, "run-async": { @@ -4593,17 +4875,17 @@ "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" }, "sinon": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-7.3.2.tgz", - "integrity": "sha512-thErC1z64BeyGiPvF8aoSg0LEnptSaWE7YhdWWbWXgelOyThent7uKOnnEh9zBxDbKixtr5dEko+ws1sZMuFMA==", + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-7.5.0.tgz", + "integrity": "sha512-AoD0oJWerp0/rY9czP/D6hDTTUYGpObhZjMpd7Cl/A6+j0xBE+ayL/ldfggkBXUs0IkvIiM1ljM8+WkOc5k78Q==", "dev": true, "requires": { "@sinonjs/commons": "^1.4.0", "@sinonjs/formatio": "^3.2.1", - "@sinonjs/samsam": "^3.3.1", + "@sinonjs/samsam": "^3.3.3", "diff": "^3.5.0", - "lolex": "^4.0.1", - "nise": "^1.4.10", + "lolex": "^4.2.0", + "nise": "^1.5.2", "supports-color": "^5.5.0" } }, @@ -4620,10 +4902,15 @@ "dev": true }, "slice-ansi": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz", - "integrity": "sha1-7b+JA/ZvfOL46v1s7tZeJkyDGzU=", - "dev": true + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", + "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "astral-regex": "^1.0.0", + "is-fullwidth-code-point": "^2.0.0" + } }, "snake-case": { "version": "2.1.0", @@ -4660,6 +4947,17 @@ "rimraf": "^2.6.2", "signal-exit": "^3.0.2", "which": "^1.3.0" + }, + "dependencies": { + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + } } }, "spdx-correct": { @@ -4708,9 +5006,9 @@ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" }, "sqlite3": { - "version": "4.0.9", - "resolved": "https://registry.npmjs.org/sqlite3/-/sqlite3-4.0.9.tgz", - "integrity": "sha512-IkvzjmsWQl9BuBiM4xKpl5X8WCR4w0AeJHRdobCdXZ8dT/lNc1XS6WqvY35N6+YzIIgzSBeY5prdFObID9F9tA==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/sqlite3/-/sqlite3-4.1.0.tgz", + "integrity": "sha512-RvqoKxq+8pDHsJo7aXxsFR18i+dU2Wp5o12qAJOV5LNcDt+fgJsc2QKKg3sIRfXrN9ZjzY1T7SNe/DFVqAXjaw==", "requires": { "nan": "^2.12.1", "node-pre-gyp": "^0.11.0", @@ -4739,9 +5037,9 @@ } }, "string-argv": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.0.tgz", - "integrity": "sha512-NGZHq3nkSXVtGZXTBjFru3MNfoZyIzN25T7BmvdgnSC0LCJczAGLLMQLyjywSIaAoqSemgLzBRHOsnrHbt60+Q==", + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.1.tgz", + "integrity": "sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg==", "dev": true }, "string-width": { @@ -4816,9 +5114,10 @@ "dev": true }, "strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.0.1.tgz", + "integrity": "sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw==", + "dev": true }, "supports-color": { "version": "5.5.0", @@ -4844,9 +5143,9 @@ "dev": true }, "table": { - "version": "5.4.5", - "resolved": "https://registry.npmjs.org/table/-/table-5.4.5.tgz", - "integrity": "sha512-oGa2Hl7CQjfoaogtrOHEJroOcYILTx7BZWLGsJIlzoWmB2zmguhNfPJZsWPKYek/MgCxfco54gEi31d1uN2hFA==", + "version": "5.4.6", + "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", + "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", "dev": true, "requires": { "ajv": "^6.10.2", @@ -4867,17 +5166,6 @@ "uri-js": "^4.2.2" } }, - "slice-ansi": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", - "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.0", - "astral-regex": "^1.0.0", - "is-fullwidth-code-point": "^2.0.0" - } - }, "string-width": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", @@ -4892,13 +5180,13 @@ } }, "tar": { - "version": "4.4.10", - "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.10.tgz", - "integrity": "sha512-g2SVs5QIxvo6OLp0GudTqEf05maawKUxXru104iaayWA09551tFCTI8f1Asb4lPfkBr91k07iL4c11XO3/b0tA==", + "version": "4.4.13", + "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.13.tgz", + "integrity": "sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA==", "requires": { "chownr": "^1.1.1", "fs-minipass": "^1.2.5", - "minipass": "^2.3.5", + "minipass": "^2.8.6", "minizlib": "^1.2.1", "mkdirp": "^0.5.0", "safe-buffer": "^5.1.2", @@ -5050,9 +5338,9 @@ "dev": true }, "ts-node": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.3.0.tgz", - "integrity": "sha512-dyNS/RqyVTDcmNM4NIBAeDMpsAdaQ+ojdf0GOLqE6nwJOgzEkdRNzJywhDfwnuvB10oa6NLVG1rUJQCpRN7qoQ==", + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.4.1.tgz", + "integrity": "sha512-5LpRN+mTiCs7lI5EtbXmF/HfMeCjzt7DH9CZwtkr6SywStrNQC723wG+aOWFiLNn7zT3kD/RnFqi3ZUfr4l5Qw==", "dev": true, "requires": { "arg": "^4.1.0", @@ -5125,9 +5413,9 @@ "dev": true }, "typeorm": { - "version": "0.2.18", - "resolved": "https://registry.npmjs.org/typeorm/-/typeorm-0.2.18.tgz", - "integrity": "sha512-S553GwtG5ab268+VmaLCN7gKDqFPIzUw0eGMTobJ9yr0Np62Ojfx8j1Oa9bIeh5p7Pz1/kmGabAHoP1MYK05pA==", + "version": "0.2.19", + "resolved": "https://registry.npmjs.org/typeorm/-/typeorm-0.2.19.tgz", + "integrity": "sha512-xKVx/W41zckQ7v8WYcpRhSKpjXDKG/Jgjy0RWvYelR8ZnfyblNRL12jF4P8tIhwXv6l5t01s7HEc9lR+zb6Gtg==", "requires": { "app-root-path": "^2.0.1", "buffer": "^5.1.0", @@ -5158,29 +5446,56 @@ "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-6.2.0.tgz", "integrity": "sha512-HygQCKUBSFl8wKQZBSemMywRWcEDNidvNbjGVyZu3nbZ8qq9ubiPoGLMdRDpfSrpkkm9BXYFkpKxxFX38o/76w==" }, - "js-yaml": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", - "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "yargs": { + "version": "13.3.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.0.tgz", + "integrity": "sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA==", + "requires": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.1" + } + }, + "yargs-parser": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz", + "integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==", + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" } } } }, "typescript": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.5.3.tgz", - "integrity": "sha512-ACzBtm/PhXBDId6a6sDJfroT2pOWt/oOnk4/dElG5G33ZL776N3Y6/6bKZJBFpd+b05F3Ct9qDjMeJmRWtE2/g==" + "version": "3.6.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.6.4.tgz", + "integrity": "sha512-unoCll1+l+YK4i4F8f22TaNVPRHcD9PA3yCuZ8g5e0qGqlVlJ/8FSateOLLSagn+Yg5+ZwuPkL8LFUc0Jcvksg==" }, "uglify-js": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.6.0.tgz", - "integrity": "sha512-W+jrUHJr3DXKhrsS7NUVxn3zqMOFn0hL/Ei6v0anCIMoKC93TjcflTagwIHLW7SfMFfiQuktQyFVCFHGUE0+yg==", + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.6.1.tgz", + "integrity": "sha512-+dSJLJpXBb6oMHP+Yvw8hUgElz4gLTh82XuX68QiJVTXaE5ibl6buzhNkQdYhBlIhozWOC9ge16wyRmjG4TwVQ==", "optional": true, "requires": { - "commander": "~2.20.0", + "commander": "2.20.0", "source-map": "~0.6.1" } }, @@ -5226,6 +5541,15 @@ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" }, + "util.promisify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.0.tgz", + "integrity": "sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA==", + "requires": { + "define-properties": "^1.1.2", + "object.getownpropertydescriptors": "^2.0.3" + } + }, "uuid": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", @@ -5280,9 +5604,10 @@ } }, "wordwrap": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", - "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=" + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", + "dev": true }, "wrap-ansi": { "version": "3.0.1", @@ -5331,18 +5656,19 @@ } }, "xml2js": { - "version": "0.4.19", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz", - "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==", + "version": "0.4.22", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.22.tgz", + "integrity": "sha512-MWTbxAQqclRSTnehWWe5nMKzI3VmJ8ltiJEco8akcC6j3miOhjjfzKum5sId+CWhfxdOs/1xauYr8/ZDBtQiRw==", "requires": { "sax": ">=0.6.0", - "xmlbuilder": "~9.0.1" + "util.promisify": "~1.0.0", + "xmlbuilder": "~11.0.0" } }, "xmlbuilder": { - "version": "9.0.7", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", - "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=" + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==" }, "xmldom": { "version": "0.1.27", @@ -5365,9 +5691,9 @@ "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==" }, "yallist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz", - "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==" + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" }, "yargonaut": { "version": "1.1.4", @@ -5417,11 +5743,12 @@ } }, "yargs": { - "version": "13.3.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.0.tgz", - "integrity": "sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA==", + "version": "14.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-14.2.0.tgz", + "integrity": "sha512-/is78VKbKs70bVZH7w4YaZea6xcJWOAwkhbR0CFuZBmYtfTYF0xjGJF43AYd8g2Uii1yJwmS5GR2vBmrc32sbg==", "requires": { "cliui": "^5.0.0", + "decamelize": "^1.2.0", "find-up": "^3.0.0", "get-caller-file": "^2.0.1", "require-directory": "^2.1.1", @@ -5430,19 +5757,9 @@ "string-width": "^3.0.0", "which-module": "^2.0.0", "y18n": "^4.0.0", - "yargs-parser": "^13.1.1" + "yargs-parser": "^15.0.0" }, "dependencies": { - "cliui": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", - "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", - "requires": { - "string-width": "^3.1.0", - "strip-ansi": "^5.2.0", - "wrap-ansi": "^5.1.0" - } - }, "string-width": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", @@ -5453,20 +5770,10 @@ "strip-ansi": "^5.1.0" } }, - "wrap-ansi": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", - "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", - "requires": { - "ansi-styles": "^3.2.0", - "string-width": "^3.0.0", - "strip-ansi": "^5.0.0" - } - }, "yargs-parser": { - "version": "13.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz", - "integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==", + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-15.0.0.tgz", + "integrity": "sha512-xLTUnCMc4JhxrPEPUYD5IBR1mWCK/aT6+RJ/K29JY2y1vD+FhtgKK0AXRWvI262q3QSffAQuTouFIKUuHX89wQ==", "requires": { "camelcase": "^5.0.0", "decamelize": "^1.2.0" @@ -5485,52 +5792,55 @@ } }, "yargs-unparser": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.5.0.tgz", - "integrity": "sha512-HK25qidFTCVuj/D1VfNiEndpLIeJN78aqgR23nL3y4N0U/91cOAzqfHlF8n2BvoNDcZmJKin3ddNSvOxSr8flw==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.6.0.tgz", + "integrity": "sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw==", "dev": true, "requires": { "flat": "^4.1.0", - "lodash": "^4.17.11", - "yargs": "^12.0.5" + "lodash": "^4.17.15", + "yargs": "^13.3.0" }, "dependencies": { - "get-caller-file": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", - "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", "dev": true }, - "require-main-filename": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", - "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", - "dev": true - }, - "yargs": { - "version": "12.0.5", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz", - "integrity": "sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==", + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", "dev": true, "requires": { - "cliui": "^4.0.0", - "decamelize": "^1.2.0", + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "yargs": { + "version": "13.3.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.0.tgz", + "integrity": "sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA==", + "dev": true, + "requires": { + "cliui": "^5.0.0", "find-up": "^3.0.0", - "get-caller-file": "^1.0.1", - "os-locale": "^3.0.0", + "get-caller-file": "^2.0.1", "require-directory": "^2.1.1", - "require-main-filename": "^1.0.1", + "require-main-filename": "^2.0.0", "set-blocking": "^2.0.0", - "string-width": "^2.0.0", + "string-width": "^3.0.0", "which-module": "^2.0.0", - "y18n": "^3.2.1 || ^4.0.0", - "yargs-parser": "^11.1.1" + "y18n": "^4.0.0", + "yargs-parser": "^13.1.1" } }, "yargs-parser": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-11.1.1.tgz", - "integrity": "sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==", + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz", + "integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==", "dev": true, "requires": { "camelcase": "^5.0.0", diff --git a/package.json b/package.json index 718351f..81fe77c 100644 --- a/package.json +++ b/package.json @@ -26,60 +26,60 @@ "dependencies": { "change-case": "^3.1.0", "fs-extra": "^8.1.0", - "handlebars": "^4.1.2", - "inquirer": "^6.5.0", + "handlebars": "^4.4.3", + "inquirer": "^7.0.0", "mssql": "^5.1.0", "mysql": "^2.17.1", - "pg": "^7.12.0", + "pg": "^7.12.1", "pluralize": "^8.0.0", "prettier": "^1.18.2", "reflect-metadata": "^0.1.13", - "sqlite3": "^4.0.9", - "typeorm": "^0.2.18", - "typescript": "^3.5.3", - "yargs": "^13.3.0", + "sqlite3": "^4.1.0", + "typeorm": "^0.2.19", + "typescript": "^3.6.4", + "yargs": "^14.2.0", "yn": "^2.0.0" }, "devDependencies": { - "@types/chai": "^4.1.7", - "@types/chai-as-promised": "^7.1.1", - "@types/chai-subset": "^1.3.2", + "@types/chai": "^4.2.3", + "@types/chai-as-promised": "^7.1.2", + "@types/chai-subset": "^1.3.3", "@types/fs-extra": "^8.0.0", "@types/handlebars": "^4.1.0", "@types/inquirer": "^6.5.0", "@types/mocha": "^5.2.7", - "@types/mssql": "^4.0.16", - "@types/mysql": "^2.15.6", - "@types/node": "^12.6.9", - "@types/oracledb": "^3.1.3", - "@types/pg": "^7.4.14", + "@types/mssql": "^4.3.1", + "@types/mysql": "^2.15.7", + "@types/node": "^12.7.12", + "@types/oracledb": "^4.0.4", + "@types/pg": "^7.11.2", "@types/pluralize": "0.0.29", "@types/prettier": "^1.18.3", - "@types/sinon": "^7.0.13", + "@types/sinon": "^7.5.0", "@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", + "@typescript-eslint/parser": "^2.3.3", + "@typescript-eslint/typescript-estree": "^2.3.3", "chai": "^4.2.0", "chai-as-promised": "^7.1.1", "chai-subset": "^1.6.0", - "codecov": "^3.5.0", - "dotenv": "^8.0.0", - "eslint": "^6.1.0", + "codecov": "^3.6.1", + "dotenv": "^8.1.0", + "eslint": "^6.5.1", "eslint-config-airbnb-base": "^14.0.0", - "eslint-config-prettier": "^6.0.0", + "eslint-config-prettier": "^6.4.0", "eslint-plugin-import": "^2.18.2", - "husky": "^3.0.2", - "lint-staged": "^9.2.1", - "mocha": "^6.2.0", + "husky": "^3.0.8", + "lint-staged": "^9.4.2", + "mocha": "^6.2.1", "ncp": "^2.0.0", "nyc": "^14.1.1", - "rimraf": "^2.6.3", - "sinon": "^7.3.2", + "rimraf": "^3.0.0", + "sinon": "^7.5.0", "sinon-chai": "^3.3.0", - "ts-node": "^8.3.0" + "ts-node": "^8.4.1" }, "husky": { "hooks": { From e478562c6e8367aabb6e5882efc95f6fcc125722 Mon Sep 17 00:00:00 2001 From: Kononnable Date: Sat, 12 Oct 2019 22:03:54 +0200 Subject: [PATCH 32/84] generate tsconfig, ormconfig through template files --- package.json | 2 +- src/Engine.ts | 176 ++++++++------------------------- src/{ => templates}/entity.mst | 0 src/templates/ormconfig.mst | 16 +++ src/templates/tsconfig.mst | 10 ++ 5 files changed, 70 insertions(+), 134 deletions(-) rename src/{ => templates}/entity.mst (100%) create mode 100644 src/templates/ormconfig.mst create mode 100644 src/templates/tsconfig.mst diff --git a/package.json b/package.json index 81fe77c..e8f4970 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "bin": "bin/typeorm-model-generator", "scripts": { "start": "ts-node ./src/index.ts", - "build": "npm run clean && tsc && ncp src/entity.mst dist/src/entity.mst", + "build": "npm run clean && tsc && ncp src/templates/ dist/src/templates/", "prepare": "npm run build", "pretest": "tsc --noEmit", "test": "nyc --reporter=lcov ts-node ./node_modules/mocha/bin/_mocha test/**/*.test.ts -- --bail", diff --git a/src/Engine.ts b/src/Engine.ts index 2ef0e90..4f0e7dc 100644 --- a/src/Engine.ts +++ b/src/Engine.ts @@ -1,6 +1,9 @@ import * as Handlebars from "handlebars"; import * as Prettier from "prettier"; import { DataTypeDefaults } from "typeorm/driver/types/DataTypeDefaults"; +import * as changeCase from "change-case"; +import * as fs from "fs"; +import * as path from "path"; import * as TomgUtils from "./Utils"; import AbstractDriver from "./drivers/AbstractDriver"; import MssqlDriver from "./drivers/MssqlDriver"; @@ -16,10 +19,6 @@ import AbstractNamingStrategy from "./AbstractNamingStrategy"; import { Entity } from "./models/Entity"; import { Relation } from "./models/Relation"; -import changeCase = require("change-case"); -import fs = require("fs"); -import path = require("path"); - export function createDriver(driverName: string): AbstractDriver { switch (driverName) { case "mssql": @@ -62,66 +61,6 @@ export async function createModelFromDatabase( generationOptions, driver.defaultValues ); - // const dbModel: Entity = { - // sqlName: "sqlName", - // tscName: "typescriptName", - // schema: "schema", - // database: "database", - // columns: [ - // { - // tscType: "typescriptType", - // tscName: "tscName", - // options: { - // name: "sqlName", - // type: "integer", - // length: 2, - // scale: 2 - // } - // }, - // { - // tscType: "typescriptType", - // tscName: "tscName", - // options: { - // name: "sqlName", - // type: "integer", - // length: 2, - // scale: 2 - // } - // } - // ], - // indices: [ - // { - // columns: ["columns"], - // name: "name" - // }, - // { - // columns: ["columns"], - // name: "name" - // } - // ], - // relations: [ - // { - // relationType: "OneToMany", - // relatedField: "relatedField", - // fieldName: "relation", - // relatedTable: "any", - // relationOptions: { - // onUpdate: "CASCADE", - // onDelete: "NO ACTION" - // } - // }, - // { - // relationType: "OneToOne", - // relatedField: "relatedField", - // fieldName: "relation", - // relatedTable: "any", - // relationOptions: { - // onUpdate: "CASCADE", - // onDelete: "NO ACTION" - // } - // } - // ] - // }; modelGenerationPhase(connectionOptions, generationOptions, dbModel); } export async function dataCollectionPhase( @@ -221,19 +160,19 @@ export function modelGenerationPhase( databaseModel: Entity[] ) { createHandlebarsHelpers(generationOptions); - const templatePath = path.resolve(__dirname, "entity.mst"); + const templatePath = path.resolve(__dirname, "templates", "entity.mst"); const template = fs.readFileSync(templatePath, "UTF-8"); const resultPath = generationOptions.resultsPath; if (!fs.existsSync(resultPath)) { fs.mkdirSync(resultPath); } - let entitesPath = resultPath; + let entitiesPath = resultPath; if (!generationOptions.noConfigs) { createTsConfigFile(resultPath); createTypeOrmConfig(resultPath, connectionOptions); - entitesPath = path.resolve(resultPath, "./entities"); - if (!fs.existsSync(entitesPath)) { - fs.mkdirSync(entitesPath); + entitiesPath = path.resolve(resultPath, "./entities"); + if (!fs.existsSync(entitiesPath)) { + fs.mkdirSync(entitiesPath); } } const compliedTemplate = Handlebars.compile(template, { @@ -257,7 +196,10 @@ export function modelGenerationPhase( default: throw new Error("Unknown case style"); } - const resultFilePath = path.resolve(entitesPath, `${casedFileName}.ts`); + const resultFilePath = path.resolve( + entitiesPath, + `${casedFileName}.ts` + ); const rendered = compliedTemplate(element); const formatted = Prettier.format(rendered, { parser: "typescript" }); fs.writeFileSync(resultFilePath, formatted, { @@ -362,78 +304,46 @@ function createHandlebarsHelpers(generationOptions: IGenerationOptions) { }); } -// TODO:Move to mustache template file -function createTsConfigFile(resultPath) { - fs.writeFileSync( - path.resolve(resultPath, "tsconfig.json"), - `{"compilerOptions": { - "lib": ["es5", "es6"], - "target": "es6", - "module": "commonjs", - "moduleResolution": "node", - "emitDecoratorMetadata": true, - "experimentalDecorators": true, - "sourceMap": true - }}`, - { encoding: "UTF-8", flag: "w" } - ); +function createTsConfigFile(outputPath: string) { + const templatePath = path.resolve(__dirname, "templates", "tsconfig.mst"); + const template = fs.readFileSync(templatePath, "UTF-8"); + const compliedTemplate = Handlebars.compile(template, { + noEscape: true + }); + const rendered = compliedTemplate({}); + const formatted = Prettier.format(rendered, { parser: "json" }); + const resultFilePath = path.resolve(outputPath, "tsconfig.json"); + fs.writeFileSync(resultFilePath, formatted, { + encoding: "UTF-8", + flag: "w" + }); } function createTypeOrmConfig( - resultPath: string, + outputPath: string, connectionOptions: IConnectionOptions ) { - if (connectionOptions.schemaName === "") { - fs.writeFileSync( - path.resolve(resultPath, "ormconfig.json"), - `[ - { - "name": "default", - "type": "${connectionOptions.databaseType}", - "host": "${connectionOptions.host}", - "port": ${connectionOptions.port}, - "username": "${connectionOptions.user}", - "password": "${connectionOptions.password}", - "database": "${connectionOptions.databaseName}", - "synchronize": false, - "entities": [ - "entities/*.js" - ] - } -]`, - { encoding: "UTF-8", flag: "w" } - ); - } else { - fs.writeFileSync( - path.resolve(resultPath, "ormconfig.json"), - `[ - { - "name": "default", - "type": "${connectionOptions.databaseType}", - "host": "${connectionOptions.host}", - "port": ${connectionOptions.port}, - "username": "${connectionOptions.user}", - "password": "${connectionOptions.password}", - "database": "${connectionOptions.databaseName}", - "schema": "${connectionOptions.schemaName}", - "synchronize": false, - "entities": [ - "entities/*.js" - ] - } -]`, - { encoding: "UTF-8", flag: "w" } - ); - } + const templatePath = path.resolve(__dirname, "templates", "ormconfig.mst"); + const template = fs.readFileSync(templatePath, "UTF-8"); + const compliedTemplate = Handlebars.compile(template, { + noEscape: true + }); + const rendered = compliedTemplate(connectionOptions); + const formatted = Prettier.format(rendered, { parser: "json" }); + const resultFilePath = path.resolve(outputPath, "ormconfig.json"); + fs.writeFileSync(resultFilePath, formatted, { + encoding: "UTF-8", + flag: "w" + }); } function applyNamingStrategy( namingStrategy: AbstractNamingStrategy, dbModel: Entity[] ) { - let retval = changeRelationNames(dbModel); - retval = changeRelationIdNames(retval); - retval = changeEntityNames(retval); - retval = changeColumnNames(retval); - return retval; + let retVal = changeRelationNames(dbModel); + retVal = changeRelationIdNames(retVal); + retVal = changeEntityNames(retVal); + retVal = changeColumnNames(retVal); + return retVal; function changeRelationIdNames(model: Entity[]) { model.forEach(entity => { diff --git a/src/entity.mst b/src/templates/entity.mst similarity index 100% rename from src/entity.mst rename to src/templates/entity.mst diff --git a/src/templates/ormconfig.mst b/src/templates/ormconfig.mst new file mode 100644 index 0000000..800022e --- /dev/null +++ b/src/templates/ormconfig.mst @@ -0,0 +1,16 @@ +[ + { + "name": "default", + "type": "{{databaseType}}", + "host": "{{host}}", + "port": {{port}}, + "username": "{{user}}", + "password": "{{password}}", + "database": "{{databaseName}}",{{#schemaName}} + "schema": "{{.}}",{{/schemaName}} + "synchronize": false, + "entities": [ + "entities/*.js" + ] + } +] \ No newline at end of file diff --git a/src/templates/tsconfig.mst b/src/templates/tsconfig.mst new file mode 100644 index 0000000..474ae94 --- /dev/null +++ b/src/templates/tsconfig.mst @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "target": "es2017", + "module": "commonjs", + "moduleResolution": "node", + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "sourceMap": true + } +} \ No newline at end of file From bd9750bbb4fa26fa773bb20cdae17f3b49a2b005 Mon Sep 17 00:00:00 2001 From: Kononnable Date: Sun, 13 Oct 2019 11:06:11 +0200 Subject: [PATCH 33/84] code cleanup, dependencies upgrade --- package-lock.json | 72 ++-- package.json | 7 +- src/Engine.ts | 391 +--------------------- src/IConnectionOptions.ts | 16 +- src/IGenerationOptions.ts | 16 +- src/ModelCustomization.ts | 204 +++++++++++ src/ModelGeneration.ts | 191 +++++++++++ src/Utils.ts | 2 +- src/drivers/OracleDriver.ts | 3 +- src/index.ts | 126 +++---- test/integration/runTestsFromPath.test.ts | 34 +- test/utils/EntityFileToJson.ts | 4 +- test/utils/GeneralTestUtils.ts | 10 +- tsconfig.json | 2 +- 14 files changed, 535 insertions(+), 543 deletions(-) create mode 100644 src/ModelCustomization.ts create mode 100644 src/ModelGeneration.ts diff --git a/package-lock.json b/package-lock.json index 379644d..24cd216 100644 --- a/package-lock.json +++ b/package-lock.json @@ -407,60 +407,42 @@ } }, "@types/yargs": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-12.0.1.tgz", - "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==", + "version": "13.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.3.tgz", + "integrity": "sha512-K8/LfZq2duW33XW/tFwEAfnZlqIfVsoyRB3kfXdPXYhl0nfM8mmh7GS0jg7WrX2Dgq/0Ha/pR1PaR+BvmWwjiQ==", "dev": true, "requires": { - "yn": "*" + "@types/yargs-parser": "*" } }, + "@types/yargs-parser": { + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-13.1.0.tgz", + "integrity": "sha512-gCubfBUZ6KxzoibJ+SCUc/57Ms1jz5NjHe4+dI2krNmU5zCPAphyLJYyTOg06ueIyfj+SaCUqmzun7ImlxDcKg==", + "dev": true + }, "@typescript-eslint/eslint-plugin": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-1.13.0.tgz", - "integrity": "sha512-WQHCozMnuNADiqMtsNzp96FNox5sOVpU8Xt4meaT4em8lOG1SrOv92/mUbEHQVh90sldKSfcOc/I0FOb/14G1g==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.3.3.tgz", + "integrity": "sha512-12cCbwu5PbQudkq2xCIS/QhB7hCMrsNPXK+vJtqy/zFqtzVkPRGy12O5Yy0gUK086f3VHV/P4a4R4CjMW853pA==", "dev": true, "requires": { - "@typescript-eslint/experimental-utils": "1.13.0", - "eslint-utils": "^1.3.1", + "@typescript-eslint/experimental-utils": "2.3.3", + "eslint-utils": "^1.4.2", "functional-red-black-tree": "^1.0.1", "regexpp": "^2.0.1", - "tsutils": "^3.7.0" + "tsutils": "^3.17.1" } }, "@typescript-eslint/experimental-utils": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-1.13.0.tgz", - "integrity": "sha512-zmpS6SyqG4ZF64ffaJ6uah6tWWWgZ8m+c54XXgwFtUv0jNz8aJAVx8chMCvnk7yl6xwn8d+d96+tWp7fXzTuDg==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-2.3.3.tgz", + "integrity": "sha512-MQ4jKPMTU1ty4TigJCRKFPye2qyQdH8jzIIkceaHgecKFmkNS1hXPqKiZ+mOehkz6+HcN5Nuvwm+frmWZR9tdg==", "dev": true, "requires": { "@types/json-schema": "^7.0.3", - "@typescript-eslint/typescript-estree": "1.13.0", - "eslint-scope": "^4.0.0" - }, - "dependencies": { - "@typescript-eslint/typescript-estree": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-1.13.0.tgz", - "integrity": "sha512-b5rCmd2e6DCC6tCTN9GSUAuxdYwCM/k/2wdjHGrIRGPSJotWMCe/dGpi66u42bhuh8q3QBzqM4TMA1GUUCJvdw==", - "dev": true, - "requires": { - "lodash.unescape": "4.0.1", - "semver": "5.5.0" - } - }, - "semver": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", - "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", - "dev": true - } + "@typescript-eslint/typescript-estree": "2.3.3", + "eslint-scope": "^5.0.0" } }, "@typescript-eslint/parser": { @@ -1973,9 +1955,9 @@ } }, "eslint-scope": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", - "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.0.0.tgz", + "integrity": "sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw==", "dev": true, "requires": { "esrecurse": "^4.1.0", @@ -5850,9 +5832,9 @@ } }, "yn": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/yn/-/yn-2.0.0.tgz", - "integrity": "sha1-5a2ryKz0CPY4X8dklWhMiOavaJo=" + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==" } } } diff --git a/package.json b/package.json index e8f4970..f10558a 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,7 @@ "typeorm": "^0.2.19", "typescript": "^3.6.4", "yargs": "^14.2.0", - "yn": "^2.0.0" + "yn": "^3.1.1" }, "devDependencies": { "@types/chai": "^4.2.3", @@ -57,9 +57,8 @@ "@types/prettier": "^1.18.3", "@types/sinon": "^7.5.0", "@types/sqlite3": "^3.1.5", - "@types/yargs": "^12.0.1", - "@types/yn": "^3.1.0", - "@typescript-eslint/eslint-plugin": "^1.13.0", + "@types/yargs": "^13.0.3", + "@typescript-eslint/eslint-plugin": "^2.3.3", "@typescript-eslint/parser": "^2.3.3", "@typescript-eslint/typescript-estree": "^2.3.3", "chai": "^4.2.0", diff --git a/src/Engine.ts b/src/Engine.ts index 4f0e7dc..cd9289a 100644 --- a/src/Engine.ts +++ b/src/Engine.ts @@ -1,9 +1,3 @@ -import * as Handlebars from "handlebars"; -import * as Prettier from "prettier"; -import { DataTypeDefaults } from "typeorm/driver/types/DataTypeDefaults"; -import * as changeCase from "change-case"; -import * as fs from "fs"; -import * as path from "path"; import * as TomgUtils from "./Utils"; import AbstractDriver from "./drivers/AbstractDriver"; import MssqlDriver from "./drivers/MssqlDriver"; @@ -14,10 +8,8 @@ import PostgresDriver from "./drivers/PostgresDriver"; import MysqlDriver from "./drivers/MysqlDriver"; import OracleDriver from "./drivers/OracleDriver"; import SqliteDriver from "./drivers/SqliteDriver"; -import NamingStrategy from "./NamingStrategy"; -import AbstractNamingStrategy from "./AbstractNamingStrategy"; -import { Entity } from "./models/Entity"; -import { Relation } from "./models/Relation"; +import modelCustomizationPhase from "./ModelCustomization"; +import modelGenerationPhase from "./ModelGeneration"; export function createDriver(driverName: string): AbstractDriver { switch (driverName) { @@ -70,382 +62,3 @@ export async function dataCollectionPhase( ) { return driver.GetDataFromServer(connectionOptions, generationOptions); } - -export function modelCustomizationPhase( - dbModel: Entity[], - generationOptions: IGenerationOptions, - defaultValues: DataTypeDefaults -) { - let namingStrategy: AbstractNamingStrategy; - if ( - generationOptions.customNamingStrategyPath && - generationOptions.customNamingStrategyPath !== "" - ) { - // eslint-disable-next-line global-require, import/no-dynamic-require, @typescript-eslint/no-var-requires - const req = require(generationOptions.customNamingStrategyPath); - namingStrategy = new req.NamingStrategy(); - } else { - namingStrategy = new NamingStrategy(); - } - let retVal = applyNamingStrategy(namingStrategy, dbModel); - retVal = addImportsAndGenerationOptions(retVal, generationOptions); - retVal = removeColumnDefaultProperties(retVal, defaultValues); - return retVal; -} -function removeColumnDefaultProperties( - dbModel: Entity[], - defaultValues: DataTypeDefaults -) { - if (!defaultValues) { - return dbModel; - } - dbModel.forEach(entity => { - entity.columns.forEach(column => { - const defVal = defaultValues[column.tscType]; - if (defVal) { - if ( - column.options.length && - defVal.length && - column.options.length === defVal.length - ) { - column.options.length = undefined; - } - if ( - column.options.precision && - defVal.precision && - column.options.precision === defVal.precision && - column.options.scale && - defVal.scale && - column.options.scale === defVal.scale - ) { - column.options.precision = undefined; - column.options.scale = undefined; - } - if ( - column.options.width && - defVal.width && - column.options.width === defVal.width - ) { - column.options.width = undefined; - } - } - }); - }); - return dbModel; -} -function addImportsAndGenerationOptions( - dbModel: Entity[], - generationOptions: IGenerationOptions -) { - dbModel.forEach(entity => { - entity.relations.forEach(relation => { - if (generationOptions.lazy) { - if (!relation.relationOptions) { - relation.relationOptions = {}; - } - relation.relationOptions.lazy = true; - } - }); - if (generationOptions.skipSchema) { - entity.schema = undefined; - entity.database = undefined; - } - }); - return dbModel; -} - -export function modelGenerationPhase( - connectionOptions: IConnectionOptions, - generationOptions: IGenerationOptions, - databaseModel: Entity[] -) { - createHandlebarsHelpers(generationOptions); - const templatePath = path.resolve(__dirname, "templates", "entity.mst"); - const template = fs.readFileSync(templatePath, "UTF-8"); - const resultPath = generationOptions.resultsPath; - if (!fs.existsSync(resultPath)) { - fs.mkdirSync(resultPath); - } - let entitiesPath = resultPath; - if (!generationOptions.noConfigs) { - createTsConfigFile(resultPath); - createTypeOrmConfig(resultPath, connectionOptions); - entitiesPath = path.resolve(resultPath, "./entities"); - if (!fs.existsSync(entitiesPath)) { - fs.mkdirSync(entitiesPath); - } - } - const compliedTemplate = Handlebars.compile(template, { - noEscape: true - }); - databaseModel.forEach(element => { - let casedFileName = ""; - switch (generationOptions.convertCaseFile) { - case "camel": - casedFileName = changeCase.camelCase(element.tscName); - break; - case "param": - casedFileName = changeCase.paramCase(element.tscName); - break; - case "pascal": - casedFileName = changeCase.pascalCase(element.tscName); - break; - case "none": - casedFileName = element.tscName; - break; - default: - throw new Error("Unknown case style"); - } - const resultFilePath = path.resolve( - entitiesPath, - `${casedFileName}.ts` - ); - const rendered = compliedTemplate(element); - const formatted = Prettier.format(rendered, { parser: "typescript" }); - fs.writeFileSync(resultFilePath, formatted, { - encoding: "UTF-8", - flag: "w" - }); - }); -} - -function createHandlebarsHelpers(generationOptions: IGenerationOptions) { - Handlebars.registerHelper("json", context => { - const json = JSON.stringify(context); - const withoutQuotes = json.replace(/"([^(")"]+)":/g, "$1:"); - return withoutQuotes.slice(1, withoutQuotes.length - 1); - }); - Handlebars.registerHelper("toEntityName", str => { - let retStr = ""; - switch (generationOptions.convertCaseEntity) { - case "camel": - retStr = changeCase.camelCase(str); - break; - case "pascal": - retStr = changeCase.pascalCase(str); - break; - case "none": - retStr = str; - break; - default: - throw new Error("Unknown case style"); - } - return retStr; - }); - Handlebars.registerHelper("toFileName", str => { - let retStr = ""; - switch (generationOptions.convertCaseFile) { - case "camel": - retStr = changeCase.camelCase(str); - break; - case "param": - retStr = changeCase.paramCase(str); - break; - case "pascal": - retStr = changeCase.pascalCase(str); - break; - case "none": - retStr = str; - break; - default: - throw new Error("Unknown case style"); - } - return retStr; - }); - Handlebars.registerHelper("printPropertyVisibility", () => - // TODO: - generationOptions.propertyVisibility !== "none" - ? `${generationOptions.propertyVisibility} ` - : "" - ); - Handlebars.registerHelper("toPropertyName", str => { - let retStr = ""; - switch (generationOptions.convertCaseProperty) { - case "camel": - retStr = changeCase.camelCase(str); - break; - case "pascal": - retStr = changeCase.pascalCase(str); - break; - case "none": - retStr = str; - break; - default: - throw new Error("Unknown case style"); - } - return retStr; - }); - Handlebars.registerHelper( - "toRelation", - (entityType: string, relationType: Relation["relationType"]) => { - let retVal = entityType; - if (relationType === "ManyToMany" || relationType === "OneToMany") { - retVal = `${retVal}[]`; - } - if (generationOptions.lazy) { - retVal = `Promise<${retVal}>`; - } - return retVal; - } - ); - Handlebars.registerHelper("strictMode", () => - // TODO: - generationOptions.strictMode ? generationOptions.strictMode : "" - ); - Handlebars.registerHelper({ - 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 - }); -} - -function createTsConfigFile(outputPath: string) { - const templatePath = path.resolve(__dirname, "templates", "tsconfig.mst"); - const template = fs.readFileSync(templatePath, "UTF-8"); - const compliedTemplate = Handlebars.compile(template, { - noEscape: true - }); - const rendered = compliedTemplate({}); - const formatted = Prettier.format(rendered, { parser: "json" }); - const resultFilePath = path.resolve(outputPath, "tsconfig.json"); - fs.writeFileSync(resultFilePath, formatted, { - encoding: "UTF-8", - flag: "w" - }); -} -function createTypeOrmConfig( - outputPath: string, - connectionOptions: IConnectionOptions -) { - const templatePath = path.resolve(__dirname, "templates", "ormconfig.mst"); - const template = fs.readFileSync(templatePath, "UTF-8"); - const compliedTemplate = Handlebars.compile(template, { - noEscape: true - }); - const rendered = compliedTemplate(connectionOptions); - const formatted = Prettier.format(rendered, { parser: "json" }); - const resultFilePath = path.resolve(outputPath, "ormconfig.json"); - fs.writeFileSync(resultFilePath, formatted, { - encoding: "UTF-8", - flag: "w" - }); -} -function applyNamingStrategy( - namingStrategy: AbstractNamingStrategy, - dbModel: Entity[] -) { - let retVal = changeRelationNames(dbModel); - retVal = changeRelationIdNames(retVal); - retVal = changeEntityNames(retVal); - retVal = changeColumnNames(retVal); - return retVal; - - function changeRelationIdNames(model: Entity[]) { - model.forEach(entity => { - entity.relationIds.forEach(relationId => { - const oldName = relationId.fieldName; - const relation = entity.relations.find( - v => v.fieldName === relationId.relationField - )!; - let newName = namingStrategy.relationIdName( - relationId, - relation, - entity - ); - newName = TomgUtils.findNameForNewField( - newName, - entity, - oldName - ); - entity.indices.forEach(index => { - index.columns = index.columns.map(column2 => - column2 === oldName ? newName : column2 - ); - }); - - relationId.fieldName = newName; - }); - }); - return dbModel; - } - - function changeRelationNames(model: Entity[]) { - model.forEach(entity => { - entity.relations.forEach(relation => { - const oldName = relation.fieldName; - let newName = namingStrategy.relationName(relation, entity); - newName = TomgUtils.findNameForNewField( - newName, - entity, - oldName - ); - - const relatedEntity = model.find( - v => v.tscName === relation.relatedTable - )!; - const relation2 = relatedEntity.relations.find( - v => v.fieldName === relation.relatedField - )!; - - entity.relationIds - .filter(v => v.relationField === oldName) - .forEach(v => { - v.relationField = newName; - }); - - relation.fieldName = newName; - relation2.relatedField = newName; - - if (relation.relationOptions) { - entity.indices.forEach(ind => { - ind.columns.map(column2 => - column2 === oldName ? newName : column2 - ); - }); - } - }); - }); - return dbModel; - } - - function changeColumnNames(model: Entity[]) { - model.forEach(entity => { - entity.columns.forEach(column => { - const oldName = column.tscName; - let newName = namingStrategy.columnName(column.tscName, column); - newName = TomgUtils.findNameForNewField( - newName, - entity, - oldName - ); - entity.indices.forEach(index => { - index.columns = index.columns.map(column2 => - column2 === oldName ? newName : column2 - ); - }); - - column.tscName = newName; - }); - }); - return model; - } - function changeEntityNames(entities: Entity[]) { - entities.forEach(entity => { - const newName = namingStrategy.entityName(entity.tscName, entity); - entities.forEach(entity2 => { - entity2.relations.forEach(relation => { - if (relation.relatedTable === entity.tscName) { - relation.relatedTable = newName; - } - }); - }); - entity.tscName = newName; - }); - return entities; - } -} diff --git a/src/IConnectionOptions.ts b/src/IConnectionOptions.ts index 3cab302..c280478 100644 --- a/src/IConnectionOptions.ts +++ b/src/IConnectionOptions.ts @@ -1,19 +1,19 @@ export default class IConnectionOptions { - public host: string = ""; + public host = ""; - public port: number = 0; + public port = 0; - public databaseName: string = ""; + public databaseName = ""; - public user: string = ""; + public user = ""; - public password: string = ""; + public password = ""; - public databaseType: string = ""; + public databaseType = ""; - public schemaName: string = ""; + public schemaName = ""; - public ssl: boolean = false; + public ssl = false; public timeout?: number; } diff --git a/src/IGenerationOptions.ts b/src/IGenerationOptions.ts index 9b64956..23180f6 100644 --- a/src/IGenerationOptions.ts +++ b/src/IGenerationOptions.ts @@ -1,7 +1,7 @@ export default class IGenerationOptions { - public resultsPath: string = ""; + public resultsPath = ""; - public noConfigs: boolean = false; + public noConfigs = false; public convertCaseFile: "pascal" | "param" | "camel" | "none" = "none"; @@ -12,17 +12,17 @@ export default class IGenerationOptions { public propertyVisibility: "public" | "protected" | "private" | "none" = "none"; - public lazy: boolean = false; + public lazy = false; - public activeRecord: boolean = false; + public activeRecord = false; - public generateConstructor: boolean = false; + public generateConstructor = false; - public customNamingStrategyPath: string = ""; + public customNamingStrategyPath = ""; - public relationIds: boolean = false; + public relationIds = false; public strictMode: false | "?" | "!" = false; - public skipSchema: boolean = false; + public skipSchema = false; } diff --git a/src/ModelCustomization.ts b/src/ModelCustomization.ts new file mode 100644 index 0000000..1bc2bea --- /dev/null +++ b/src/ModelCustomization.ts @@ -0,0 +1,204 @@ +import { DataTypeDefaults } from "typeorm/driver/types/DataTypeDefaults"; +import { Entity } from "./models/Entity"; +import IGenerationOptions from "./IGenerationOptions"; +import AbstractNamingStrategy from "./AbstractNamingStrategy"; +import NamingStrategy from "./NamingStrategy"; +import * as TomgUtils from "./Utils"; + +export default function modelCustomizationPhase( + dbModel: Entity[], + generationOptions: IGenerationOptions, + defaultValues: DataTypeDefaults +) { + let namingStrategy: AbstractNamingStrategy; + if ( + generationOptions.customNamingStrategyPath && + generationOptions.customNamingStrategyPath !== "" + ) { + // eslint-disable-next-line global-require, import/no-dynamic-require, @typescript-eslint/no-var-requires + const req = require(generationOptions.customNamingStrategyPath); + namingStrategy = new req.NamingStrategy(); + } else { + namingStrategy = new NamingStrategy(); + } + let retVal = applyNamingStrategy(namingStrategy, dbModel); + retVal = addImportsAndGenerationOptions(retVal, generationOptions); + retVal = removeColumnDefaultProperties(retVal, defaultValues); + return retVal; +} +function removeColumnDefaultProperties( + dbModel: Entity[], + defaultValues: DataTypeDefaults +) { + if (!defaultValues) { + return dbModel; + } + dbModel.forEach(entity => { + entity.columns.forEach(column => { + const defVal = defaultValues[column.tscType]; + if (defVal) { + if ( + column.options.length && + defVal.length && + column.options.length === defVal.length + ) { + column.options.length = undefined; + } + if ( + column.options.precision && + defVal.precision && + column.options.precision === defVal.precision && + column.options.scale && + defVal.scale && + column.options.scale === defVal.scale + ) { + column.options.precision = undefined; + column.options.scale = undefined; + } + if ( + column.options.width && + defVal.width && + column.options.width === defVal.width + ) { + column.options.width = undefined; + } + } + }); + }); + return dbModel; +} +function addImportsAndGenerationOptions( + dbModel: Entity[], + generationOptions: IGenerationOptions +) { + dbModel.forEach(entity => { + entity.relations.forEach(relation => { + if (generationOptions.lazy) { + if (!relation.relationOptions) { + relation.relationOptions = {}; + } + relation.relationOptions.lazy = true; + } + }); + if (generationOptions.skipSchema) { + entity.schema = undefined; + entity.database = undefined; + } + }); + return dbModel; +} + +function applyNamingStrategy( + namingStrategy: AbstractNamingStrategy, + dbModel: Entity[] +) { + let retVal = changeRelationNames(dbModel); + retVal = changeRelationIdNames(retVal); + retVal = changeEntityNames(retVal); + retVal = changeColumnNames(retVal); + return retVal; + + function changeRelationIdNames(model: Entity[]) { + model.forEach(entity => { + entity.relationIds.forEach(relationId => { + const oldName = relationId.fieldName; + const relation = entity.relations.find( + v => v.fieldName === relationId.relationField + )!; + let newName = namingStrategy.relationIdName( + relationId, + relation, + entity + ); + newName = TomgUtils.findNameForNewField( + newName, + entity, + oldName + ); + entity.indices.forEach(index => { + index.columns = index.columns.map(column2 => + column2 === oldName ? newName : column2 + ); + }); + + relationId.fieldName = newName; + }); + }); + return dbModel; + } + + function changeRelationNames(model: Entity[]) { + model.forEach(entity => { + entity.relations.forEach(relation => { + const oldName = relation.fieldName; + let newName = namingStrategy.relationName(relation, entity); + newName = TomgUtils.findNameForNewField( + newName, + entity, + oldName + ); + + const relatedEntity = model.find( + v => v.tscName === relation.relatedTable + )!; + const relation2 = relatedEntity.relations.find( + v => v.fieldName === relation.relatedField + )!; + + entity.relationIds + .filter(v => v.relationField === oldName) + .forEach(v => { + v.relationField = newName; + }); + + relation.fieldName = newName; + relation2.relatedField = newName; + + if (relation.relationOptions) { + entity.indices.forEach(ind => { + ind.columns.map(column2 => + column2 === oldName ? newName : column2 + ); + }); + } + }); + }); + return dbModel; + } + + function changeColumnNames(model: Entity[]) { + model.forEach(entity => { + entity.columns.forEach(column => { + const oldName = column.tscName; + let newName = namingStrategy.columnName(column.tscName, column); + newName = TomgUtils.findNameForNewField( + newName, + entity, + oldName + ); + entity.indices.forEach(index => { + index.columns = index.columns.map(column2 => + column2 === oldName ? newName : column2 + ); + }); + + column.tscName = newName; + }); + }); + return model; + } + function changeEntityNames(entities: Entity[]) { + entities.forEach(entity => { + const newName = namingStrategy.entityName(entity.tscName, entity); + entities.forEach(entity2 => { + entity2.relations.forEach(relation => { + if (relation.relatedTable === entity.tscName) { + relation.relatedTable = newName; + } + }); + }); + entity.tscName = newName; + }); + return entities; + } +} diff --git a/src/ModelGeneration.ts b/src/ModelGeneration.ts new file mode 100644 index 0000000..6f0b27e --- /dev/null +++ b/src/ModelGeneration.ts @@ -0,0 +1,191 @@ +import * as Handlebars from "handlebars"; +import * as Prettier from "prettier"; +import * as changeCase from "change-case"; +import * as fs from "fs"; +import * as path from "path"; +import IConnectionOptions from "./IConnectionOptions"; +import IGenerationOptions from "./IGenerationOptions"; +import { Entity } from "./models/Entity"; +import { Relation } from "./models/Relation"; + +export default function modelGenerationPhase( + connectionOptions: IConnectionOptions, + generationOptions: IGenerationOptions, + databaseModel: Entity[] +) { + createHandlebarsHelpers(generationOptions); + const templatePath = path.resolve(__dirname, "templates", "entity.mst"); + const template = fs.readFileSync(templatePath, "UTF-8"); + const resultPath = generationOptions.resultsPath; + if (!fs.existsSync(resultPath)) { + fs.mkdirSync(resultPath); + } + let entitiesPath = resultPath; + if (!generationOptions.noConfigs) { + createTsConfigFile(resultPath); + createTypeOrmConfig(resultPath, connectionOptions); + entitiesPath = path.resolve(resultPath, "./entities"); + if (!fs.existsSync(entitiesPath)) { + fs.mkdirSync(entitiesPath); + } + } + const compliedTemplate = Handlebars.compile(template, { + noEscape: true + }); + databaseModel.forEach(element => { + let casedFileName = ""; + switch (generationOptions.convertCaseFile) { + case "camel": + casedFileName = changeCase.camelCase(element.tscName); + break; + case "param": + casedFileName = changeCase.paramCase(element.tscName); + break; + case "pascal": + casedFileName = changeCase.pascalCase(element.tscName); + break; + case "none": + casedFileName = element.tscName; + break; + default: + throw new Error("Unknown case style"); + } + const resultFilePath = path.resolve( + entitiesPath, + `${casedFileName}.ts` + ); + const rendered = compliedTemplate(element); + const formatted = Prettier.format(rendered, { parser: "typescript" }); + fs.writeFileSync(resultFilePath, formatted, { + encoding: "UTF-8", + flag: "w" + }); + }); +} + +function createHandlebarsHelpers(generationOptions: IGenerationOptions) { + Handlebars.registerHelper("json", context => { + const json = JSON.stringify(context); + const withoutQuotes = json.replace(/"([^(")"]+)":/g, "$1:"); + return withoutQuotes.slice(1, withoutQuotes.length - 1); + }); + Handlebars.registerHelper("toEntityName", str => { + let retStr = ""; + switch (generationOptions.convertCaseEntity) { + case "camel": + retStr = changeCase.camelCase(str); + break; + case "pascal": + retStr = changeCase.pascalCase(str); + break; + case "none": + retStr = str; + break; + default: + throw new Error("Unknown case style"); + } + return retStr; + }); + Handlebars.registerHelper("toFileName", str => { + let retStr = ""; + switch (generationOptions.convertCaseFile) { + case "camel": + retStr = changeCase.camelCase(str); + break; + case "param": + retStr = changeCase.paramCase(str); + break; + case "pascal": + retStr = changeCase.pascalCase(str); + break; + case "none": + retStr = str; + break; + default: + throw new Error("Unknown case style"); + } + return retStr; + }); + Handlebars.registerHelper("printPropertyVisibility", () => + // TODO: + generationOptions.propertyVisibility !== "none" + ? `${generationOptions.propertyVisibility} ` + : "" + ); + Handlebars.registerHelper("toPropertyName", str => { + let retStr = ""; + switch (generationOptions.convertCaseProperty) { + case "camel": + retStr = changeCase.camelCase(str); + break; + case "pascal": + retStr = changeCase.pascalCase(str); + break; + case "none": + retStr = str; + break; + default: + throw new Error("Unknown case style"); + } + return retStr; + }); + Handlebars.registerHelper( + "toRelation", + (entityType: string, relationType: Relation["relationType"]) => { + let retVal = entityType; + if (relationType === "ManyToMany" || relationType === "OneToMany") { + retVal = `${retVal}[]`; + } + if (generationOptions.lazy) { + retVal = `Promise<${retVal}>`; + } + return retVal; + } + ); + Handlebars.registerHelper("strictMode", () => + // TODO: + generationOptions.strictMode ? generationOptions.strictMode : "" + ); + Handlebars.registerHelper({ + 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 + }); +} + +function createTsConfigFile(outputPath: string) { + const templatePath = path.resolve(__dirname, "templates", "tsconfig.mst"); + const template = fs.readFileSync(templatePath, "UTF-8"); + const compliedTemplate = Handlebars.compile(template, { + noEscape: true + }); + const rendered = compliedTemplate({}); + const formatted = Prettier.format(rendered, { parser: "json" }); + const resultFilePath = path.resolve(outputPath, "tsconfig.json"); + fs.writeFileSync(resultFilePath, formatted, { + encoding: "UTF-8", + flag: "w" + }); +} +function createTypeOrmConfig( + outputPath: string, + connectionOptions: IConnectionOptions +) { + const templatePath = path.resolve(__dirname, "templates", "ormconfig.mst"); + const template = fs.readFileSync(templatePath, "UTF-8"); + const compliedTemplate = Handlebars.compile(template, { + noEscape: true + }); + const rendered = compliedTemplate(connectionOptions); + const formatted = Prettier.format(rendered, { parser: "json" }); + const resultFilePath = path.resolve(outputPath, "ormconfig.json"); + fs.writeFileSync(resultFilePath, formatted, { + encoding: "UTF-8", + flag: "w" + }); +} diff --git a/src/Utils.ts b/src/Utils.ts index bd10f3b..700db61 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -3,7 +3,7 @@ import { Entity } from "./models/Entity"; export function LogError( errText: string, - isABug: boolean = true, + isABug = true, passedError?: string | ErrorConstructor ) { let errObject = passedError; diff --git a/src/drivers/OracleDriver.ts b/src/drivers/OracleDriver.ts index 88f99e9..38cf79b 100644 --- a/src/drivers/OracleDriver.ts +++ b/src/drivers/OracleDriver.ts @@ -350,11 +350,10 @@ export default class OracleDriver extends AbstractDriver { user: connectionOptions.user }; } - const that = this; const promise = new Promise((resolve, reject) => { this.Oracle.getConnection(config, (err, connection) => { if (!err) { - that.Connection = connection; + this.Connection = connection; resolve(true); } else { TomgUtils.LogError( diff --git a/src/index.ts b/src/index.ts index c3a37aa..ba03a04 100644 --- a/src/index.ts +++ b/src/index.ts @@ -51,33 +51,38 @@ async function CliLogic() { function GetUtilParametersByArgs() { const { argv } = Yargs.usage( - "Usage: typeorm-model-generator -h -d -p [port] -u -x [password] -e [engine]\nYou can also run program without specyfiying any parameters." - ) - .option("h", { + "Usage: typeorm-model-generator -h -d -p [port] -u -x [password] -e [engine]\nYou can also run program without specifying any parameters." + ).options({ + h: { alias: "host", + string: true, default: "127.0.0.1", describe: "IP address/Hostname for database server" - }) - .option("d", { + }, + d: { alias: "database", + string: true, demand: true, describe: "Database name(or path for sqlite). You can pass multiple values separated by comma." - }) - .option("u", { + }, + u: { alias: "user", + string: true, describe: "Username for database server" - }) - .option("x", { + }, + x: { alias: "pass", + string: true, default: "", describe: "Password for database server" - }) - .option("p", { + }, + p: { + number: true, alias: "port", describe: "Port number for database server" - }) - .option("e", { + }, + e: { alias: "engine", choices: [ "mssql", @@ -89,94 +94,95 @@ function GetUtilParametersByArgs() { ], default: "mssql", describe: "Database engine" - }) - .option("o", { + }, + o: { alias: "output", default: path.resolve(process.cwd(), "output"), describe: "Where to place generated models" - }) - .option("s", { + }, + s: { alias: "schema", + string: true, describe: "Schema name to create model from. Only for mssql and postgres. You can pass multiple values separated by comma eg. -s scheme1,scheme2,scheme3" - }) - .option("ssl", { + }, + ssl: { boolean: true, default: false - }) - .option("noConfig", { + }, + noConfig: { boolean: true, default: false, describe: `Doesn't create tsconfig.json and ormconfig.json` - }) - .option("cf", { + }, + cf: { alias: "case-file", choices: ["pascal", "param", "camel", "none"], default: "pascal", describe: "Convert file names to specified case" - }) - .option("ce", { + }, + ce: { alias: "case-entity", choices: ["pascal", "camel", "none"], default: "pascal", describe: "Convert class names to specified case" - }) - .option("cp", { + }, + cp: { alias: "case-property", choices: ["pascal", "camel", "none"], default: "camel", describe: "Convert property names to specified case" - }) - .option("pv", { + }, + pv: { alias: "property-visibility", choices: ["public", "protected", "private", "none"], default: "none", describe: "Defines which visibility should have the generated property" - }) - .option("lazy", { + }, + lazy: { boolean: true, default: false, describe: "Generate lazy relations" - }) - .option("a", { + }, + a: { alias: "active-record", boolean: true, default: false, describe: "Use ActiveRecord syntax for generated models" - }) - .option("namingStrategy", { - describe: "Use custom naming strategy" - }) - .option("relationIds", { + }, + namingStrategy: { + describe: "Use custom naming strategy", + string: true + }, + relationIds: { boolean: true, default: false, describe: "Generate RelationId fields" - }) - .option("skipSchema", { + }, + skipSchema: { boolean: true, default: false, describe: "Omits schema identifier in generated entities" - }) - .option("generateConstructor", { + }, + generateConstructor: { boolean: true, default: false, describe: "Generate constructor allowing partial initialization" - }) - .option("strictMode", { + }, + strictMode: { choices: ["none", "?", "!"], default: "none", describe: "Mark fields as optional(?) or non-null(!)" - }) - .option("timeout", { + }, + timeout: { describe: "SQL Query timeout(ms)", number: true - }); + } + }); const driver = createDriver(argv.e); - const { standardPort } = driver; - const { standardSchema } = driver; - const standardUser = driver.standardPort; + const { standardPort, standardSchema, standardUser } = driver; let namingStrategyPath: string; if (argv.namingStrategy && argv.namingStrategy !== "") { namingStrategyPath = argv.namingStrategy; @@ -184,11 +190,11 @@ function GetUtilParametersByArgs() { namingStrategyPath = ""; } const connectionOptions: IConnectionOptions = new IConnectionOptions(); - connectionOptions.databaseName = argv.d ? argv.d.toString() : null; + connectionOptions.databaseName = argv.d; connectionOptions.databaseType = argv.e; connectionOptions.host = argv.h; - connectionOptions.password = argv.x ? argv.x.toString() : null; - connectionOptions.port = parseInt(argv.p, 10) || standardPort; + connectionOptions.password = argv.x; + connectionOptions.port = argv.p || standardPort; connectionOptions.schemaName = argv.s ? argv.s.toString() : standardSchema; connectionOptions.ssl = argv.ssl; connectionOptions.timeout = argv.timeout; @@ -196,18 +202,20 @@ function GetUtilParametersByArgs() { const generationOptions: IGenerationOptions = new IGenerationOptions(); generationOptions.activeRecord = argv.a; generationOptions.generateConstructor = argv.generateConstructor; - generationOptions.convertCaseEntity = argv.ce; - generationOptions.convertCaseFile = argv.cf; - generationOptions.convertCaseProperty = argv.cp; + generationOptions.convertCaseEntity = argv.ce as IGenerationOptions["convertCaseEntity"]; + generationOptions.convertCaseFile = argv.cf as IGenerationOptions["convertCaseFile"]; + generationOptions.convertCaseProperty = argv.cp as IGenerationOptions["convertCaseProperty"]; generationOptions.lazy = argv.lazy; generationOptions.customNamingStrategyPath = namingStrategyPath; generationOptions.noConfigs = argv.noConfig; - generationOptions.propertyVisibility = argv.pv; + generationOptions.propertyVisibility = argv.pv as IGenerationOptions["propertyVisibility"]; generationOptions.relationIds = argv.relationIds; generationOptions.skipSchema = argv.skipSchema; - generationOptions.resultsPath = argv.o ? argv.o.toString() : null; + generationOptions.resultsPath = argv.o; generationOptions.strictMode = - argv.strictMode === "none" ? false : argv.strictMode; + argv.strictMode === "none" + ? false + : (argv.strictMode as IGenerationOptions["strictMode"]); return { driver, connectionOptions, generationOptions }; } diff --git a/test/integration/runTestsFromPath.test.ts b/test/integration/runTestsFromPath.test.ts index 240844d..e86fa39 100644 --- a/test/integration/runTestsFromPath.test.ts +++ b/test/integration/runTestsFromPath.test.ts @@ -1,32 +1,28 @@ import "reflect-metadata"; -import { expect } from "chai"; +import * as chai from "chai"; import * as ts from "typescript"; +import * as fs from "fs-extra"; +import * as path from "path"; +import * as chaiSubset from "chai-subset"; +import yn from "yn"; import EntityFileToJson from "../utils/EntityFileToJson"; -import { - createDriver, - dataCollectionPhase, - modelCustomizationPhase, - modelGenerationPhase -} from "../../src/Engine"; +import { createDriver, dataCollectionPhase } from "../../src/Engine"; import * as GTU from "../utils/GeneralTestUtils"; import { Entity } from "../../src/models/Entity"; 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 modelCustomizationPhase from "../../src/ModelCustomization"; +import modelGenerationPhase from "../../src/ModelGeneration"; require("dotenv").config(); chai.use(chaiSubset); +const { expect } = chai; it("Column default values", async () => { const testPartialPath = "test/integration/defaultValues"; await runTestsFromPath(testPartialPath, true); }).timeout(); -it("Platform specyfic types", async () => { +it("Platform specific types", async () => { const testPartialPath = "test/integration/entityTypes"; await runTestsFromPath(testPartialPath, true); }); @@ -70,7 +66,7 @@ function runTestForMultipleDrivers( testPartialPath: string ) { it(testName, async () => { - const driversToRun = selectDriversForSpecyficTest(); + const driversToRun = selectDriversForSpecificTest(); const modelGenerationPromises = driversToRun.map(async dbDriver => { const { generationOptions, @@ -120,7 +116,7 @@ function runTestForMultipleDrivers( compileGeneratedModel(path.resolve(process.cwd(), `output`), dbDrivers); }); - function selectDriversForSpecyficTest() { + function selectDriversForSpecificTest() { switch (testName) { case "39": return dbDrivers.filter( @@ -187,7 +183,7 @@ function compareGeneratedFiles(filesOrgPathTS: string, filesGenPath: string) { const filesGen = fs .readdirSync(filesGenPath) .filter(val => val.toString().endsWith(".ts")); - expect(filesOrg, "Errors detected in model comparision").to.be.deep.equal( + expect(filesOrg, "Errors detected in model comparison").to.be.deep.equal( filesGen ); filesOrg.forEach(file => { @@ -275,7 +271,7 @@ async function prepareTestRuns( password: String(process.env.MYSQL_Password), databaseType: "mysql", schemaName: "ignored", - ssl: yn(process.env.MYSQL_SSL) + ssl: yn(process.env.MYSQL_SSL, { default: false }) }; break; case "mariadb": @@ -287,7 +283,7 @@ async function prepareTestRuns( password: String(process.env.MARIADB_Password), databaseType: "mariadb", schemaName: "ignored", - ssl: yn(process.env.MARIADB_SSL) + ssl: yn(process.env.MARIADB_SSL, { default: false }) }; break; diff --git a/test/utils/EntityFileToJson.ts b/test/utils/EntityFileToJson.ts index ba6823b..094a818 100644 --- a/test/utils/EntityFileToJson.ts +++ b/test/utils/EntityFileToJson.ts @@ -17,14 +17,14 @@ class EntityColumn { public relationType: "OneToOne" | "OneToMany" | "ManyToOne" | "ManyToMany"; - public isOwnerOfRelation: boolean = false; + public isOwnerOfRelation = false; } class EntityIndex { public indexName: string; public columnNames: string[] = []; - public isUnique: boolean = false; + public isUnique = false; } export default class EntityFileToJson { diff --git a/test/utils/GeneralTestUtils.ts b/test/utils/GeneralTestUtils.ts index d3d2d1d..3a3976c 100644 --- a/test/utils/GeneralTestUtils.ts +++ b/test/utils/GeneralTestUtils.ts @@ -41,7 +41,7 @@ export async function createMSSQLModels( password: String(process.env.MSSQL_Password), databaseType: "mssql", schemaName: "dbo,sch1,sch2", - ssl: yn(process.env.MSSQL_SSL) + ssl: yn(process.env.MSSQL_SSL, { default: false }) }; await driver.ConnectToServer(connectionOptions); connectionOptions.databaseName = String(process.env.MSSQL_Database); @@ -92,7 +92,7 @@ export async function createPostgresModels( password: String(process.env.POSTGRES_Password), databaseType: "postgres", schemaName: "public,sch1,sch2", - ssl: yn(process.env.POSTGRES_SSL) + ssl: yn(process.env.POSTGRES_SSL, { default: false }) }; await driver.ConnectToServer(connectionOptions); connectionOptions.databaseName = String(process.env.POSTGRES_Database); @@ -176,7 +176,7 @@ export async function createMysqlModels( password: String(process.env.MYSQL_Password), databaseType: "mysql", schemaName: "ignored", - ssl: yn(process.env.MYSQL_SSL) + ssl: yn(process.env.MYSQL_SSL, { default: false }) }; await driver.ConnectToServer(connectionOptions); @@ -218,7 +218,7 @@ export async function createMariaDBModels( password: String(process.env.MARIADB_Password), databaseType: "mariadb", schemaName: "ignored", - ssl: yn(process.env.MARIADB_SSL) + ssl: yn(process.env.MARIADB_SSL, { default: false }) }; await driver.ConnectToServer(connectionOptions); @@ -262,7 +262,7 @@ export async function createOracleDBModels( password: String(process.env.ORACLE_PasswordSys), databaseType: "oracle", schemaName: String(process.env.ORACLE_Username), - ssl: yn(process.env.ORACLE_SSL) + ssl: yn(process.env.ORACLE_SSL, { default: false }) }; await driver.ConnectToServer(connectionOptions); connectionOptions.user = String(process.env.ORACLE_Username); diff --git a/tsconfig.json b/tsconfig.json index bcc555a..1a824ca 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,7 +1,7 @@ { "compilerOptions": { "module": "commonjs", - "target": "es6", + "target": "es2017", "noImplicitAny": false, "emitDecoratorMetadata": true, "experimentalDecorators": true, From 5f33127b4aef88282789dec1e9fe9b5d7ffe2d61 Mon Sep 17 00:00:00 2001 From: Kononnable Date: Sun, 13 Oct 2019 13:46:36 +0200 Subject: [PATCH 34/84] change travis ci settings --- .travis.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index c746455..60bb8cf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -41,9 +41,11 @@ before_script: - if [ -n "$DOCKER_USERNAME" ]; then mkdir /opt/oracle; npm i oracledb --no-save; docker cp typeorm-mg-oracle-client:/usr/lib/oracle/12.2/client64/lib /opt/oracle/instantclient_12_2; fi - export LD_LIBRARY_PATH=/opt/oracle/instantclient_12_2:$LD_LIBRARY_PATH script: -- docker ps -- travis_retry sh -c 'sleep 60 && docker ps && docker logs typeorm-mg-mariadb && docker logs typeorm-mg-mysql && npm t -- --colors' +- travis_retry sh -c 'sleep 60 && npm t -- --colors' after_success: - codecov +after_failure: +- docker ps +- docker-compose logs dd: secure: lONUbDz2a1LWId+Z2tTaxajK7MilX/XbQ875FYD6EE09DQ0xcoPdq2/KW5/pxuN1tz4QzTG7izMwra3XWtkBySxqFwJDUOibsgYVgn+EMMuPWNMNnQgXqTTmHbtbm1L1aSMHu4bCu4cJkJBX6503R0Kv4Hbdr2LFnSUI/9KqrevA1cVyksN71BlNBdRtvnHInwB5wNNvGULSLT+DR6qGytLGjq4ZF+pW7dH3A1LNGfDY4ivGPHt9eAWGHcVuESmudO1ADmf6XTZAJVdKqDy5eJguK48XyAqRmTc1vBxDJmCNDaU/mV6fkUoEkCjn9XfG5nJLOKviycc1j/OCuuWuqojmTlRInPGV8GDT8lNivwqLBMzvKoKgSQQROEVus4xzo64M808dFbUS30et3++O589X/7P9Wjmt+6HawcEsSq5TQfEutyB+tM9OwedTkB5Fwwmymuqx23zCAJ2orP7WoIG/ApmnKu6LmpoM340UxxSGkurztQP1OqFrf4u8kDVp9/xzqnd7qSfEd8iKvvb1bOykWGxx6dhyThCdSNyT5GQL3aub3LV6g0UB37lbhB+BVSrOAhN0r1cIWT2wr2mRxwoepObmrcNQ+AOUUXE/RcONsiEQr+STsEIjJb7bTANljRYMKpiPdsAdhvDaUZRyu8KBArTCDPotanzwQFERcw8= From e15efe75e7aa50b2a294a397ac9f9b2d4e00f27f Mon Sep 17 00:00:00 2001 From: Kononnable Date: Sun, 13 Oct 2019 17:20:17 +0200 Subject: [PATCH 35/84] code cleanup --- .eslintrc.js | 1 - src/Engine.ts | 5 +++-- src/ModelCustomization.ts | 16 ++++++++-------- src/ModelGeneration.ts | 8 ++++---- src/Utils.ts | 8 ++++---- test/utils/EntityFileToJson.ts | 21 ++++++++++++--------- test/utils/GeneralTestUtils.ts | 2 +- 7 files changed, 32 insertions(+), 29 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 587e3f8..5f47d85 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -28,7 +28,6 @@ module.exports = { "no-plusplus": ["error", { allowForLoopAfterthoughts: true }], "@typescript-eslint/no-non-null-assertion": ["off"], - "@typescript-eslint/no-object-literal-type-assertion": ["off"], "no-param-reassign": ["off"], "@typescript-eslint/no-explicit-any": ["off"], diff --git a/src/Engine.ts b/src/Engine.ts index cd9289a..026896c 100644 --- a/src/Engine.ts +++ b/src/Engine.ts @@ -10,6 +10,7 @@ import OracleDriver from "./drivers/OracleDriver"; import SqliteDriver from "./drivers/SqliteDriver"; import modelCustomizationPhase from "./ModelCustomization"; import modelGenerationPhase from "./ModelGeneration"; +import { Entity } from "./models/Entity"; export function createDriver(driverName: string): AbstractDriver { switch (driverName) { @@ -35,7 +36,7 @@ export async function createModelFromDatabase( driver: AbstractDriver, connectionOptions: IConnectionOptions, generationOptions: IGenerationOptions -) { +): Promise { let dbModel = await dataCollectionPhase( driver, connectionOptions, @@ -59,6 +60,6 @@ export async function dataCollectionPhase( driver: AbstractDriver, connectionOptions: IConnectionOptions, generationOptions: IGenerationOptions -) { +): Promise { return driver.GetDataFromServer(connectionOptions, generationOptions); } diff --git a/src/ModelCustomization.ts b/src/ModelCustomization.ts index 1bc2bea..6e0563d 100644 --- a/src/ModelCustomization.ts +++ b/src/ModelCustomization.ts @@ -9,7 +9,7 @@ export default function modelCustomizationPhase( dbModel: Entity[], generationOptions: IGenerationOptions, defaultValues: DataTypeDefaults -) { +): Entity[] { let namingStrategy: AbstractNamingStrategy; if ( generationOptions.customNamingStrategyPath && @@ -29,7 +29,7 @@ export default function modelCustomizationPhase( function removeColumnDefaultProperties( dbModel: Entity[], defaultValues: DataTypeDefaults -) { +): Entity[] { if (!defaultValues) { return dbModel; } @@ -70,7 +70,7 @@ function removeColumnDefaultProperties( function addImportsAndGenerationOptions( dbModel: Entity[], generationOptions: IGenerationOptions -) { +): Entity[] { dbModel.forEach(entity => { entity.relations.forEach(relation => { if (generationOptions.lazy) { @@ -91,14 +91,14 @@ function addImportsAndGenerationOptions( function applyNamingStrategy( namingStrategy: AbstractNamingStrategy, dbModel: Entity[] -) { +): Entity[] { let retVal = changeRelationNames(dbModel); retVal = changeRelationIdNames(retVal); retVal = changeEntityNames(retVal); retVal = changeColumnNames(retVal); return retVal; - function changeRelationIdNames(model: Entity[]) { + function changeRelationIdNames(model: Entity[]): Entity[] { model.forEach(entity => { entity.relationIds.forEach(relationId => { const oldName = relationId.fieldName; @@ -127,7 +127,7 @@ function applyNamingStrategy( return dbModel; } - function changeRelationNames(model: Entity[]) { + function changeRelationNames(model: Entity[]): Entity[] { model.forEach(entity => { entity.relations.forEach(relation => { const oldName = relation.fieldName; @@ -166,7 +166,7 @@ function applyNamingStrategy( return dbModel; } - function changeColumnNames(model: Entity[]) { + function changeColumnNames(model: Entity[]): Entity[] { model.forEach(entity => { entity.columns.forEach(column => { const oldName = column.tscName; @@ -187,7 +187,7 @@ function applyNamingStrategy( }); return model; } - function changeEntityNames(entities: Entity[]) { + function changeEntityNames(entities: Entity[]): Entity[] { entities.forEach(entity => { const newName = namingStrategy.entityName(entity.tscName, entity); entities.forEach(entity2 => { diff --git a/src/ModelGeneration.ts b/src/ModelGeneration.ts index 6f0b27e..743dd74 100644 --- a/src/ModelGeneration.ts +++ b/src/ModelGeneration.ts @@ -12,7 +12,7 @@ export default function modelGenerationPhase( connectionOptions: IConnectionOptions, generationOptions: IGenerationOptions, databaseModel: Entity[] -) { +): void { createHandlebarsHelpers(generationOptions); const templatePath = path.resolve(__dirname, "templates", "entity.mst"); const template = fs.readFileSync(templatePath, "UTF-8"); @@ -63,7 +63,7 @@ export default function modelGenerationPhase( }); } -function createHandlebarsHelpers(generationOptions: IGenerationOptions) { +function createHandlebarsHelpers(generationOptions: IGenerationOptions): void { Handlebars.registerHelper("json", context => { const json = JSON.stringify(context); const withoutQuotes = json.replace(/"([^(")"]+)":/g, "$1:"); @@ -158,7 +158,7 @@ function createHandlebarsHelpers(generationOptions: IGenerationOptions) { }); } -function createTsConfigFile(outputPath: string) { +function createTsConfigFile(outputPath: string): void { const templatePath = path.resolve(__dirname, "templates", "tsconfig.mst"); const template = fs.readFileSync(templatePath, "UTF-8"); const compliedTemplate = Handlebars.compile(template, { @@ -175,7 +175,7 @@ function createTsConfigFile(outputPath: string) { function createTypeOrmConfig( outputPath: string, connectionOptions: IConnectionOptions -) { +): void { const templatePath = path.resolve(__dirname, "templates", "ormconfig.mst"); const template = fs.readFileSync(templatePath, "UTF-8"); const compliedTemplate = Handlebars.compile(template, { diff --git a/src/Utils.ts b/src/Utils.ts index 700db61..2556fc8 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -5,10 +5,10 @@ export function LogError( errText: string, isABug = true, passedError?: string | ErrorConstructor -) { +): void { let errObject = passedError; console.error(errText); - console.error(`Error occured in typeorm-model-generator.`); + console.error(`Error occurred in typeorm-model-generator.`); 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}` @@ -20,14 +20,14 @@ export function LogError( console.error(errObject); } } -export function packageVersion() { +export function packageVersion(): string { return `${packagejson.name}@${packagejson.version}`; } export function findNameForNewField( _fieldName: string, entity: Entity, columnOldName = "" -) { +): string { let fieldName = _fieldName; const validNameCondition = () => (entity.columns.every( diff --git a/test/utils/EntityFileToJson.ts b/test/utils/EntityFileToJson.ts index 094a818..b9ea9b8 100644 --- a/test/utils/EntityFileToJson.ts +++ b/test/utils/EntityFileToJson.ts @@ -2,7 +2,7 @@ class EntityJson { public entityName: string; - public entityOptions: any = {}; + public entityOptions: { [key: string]: string | boolean } = {}; public columns: EntityColumn[] = [] as EntityColumn[]; @@ -13,7 +13,7 @@ class EntityColumn { public columnTypes: string[] = []; - public columnOptions: any = {}; + public columnOptions: { [key: string]: string | boolean } = {}; public relationType: "OneToOne" | "OneToMany" | "ManyToOne" | "ManyToMany"; @@ -28,7 +28,7 @@ class EntityIndex { } export default class EntityFileToJson { - public static getEntityOptions(trimmedLine: string, ent: EntityJson) { + public static getEntityOptions(trimmedLine: string, ent: EntityJson): void { const decoratorParameters = trimmedLine.slice( trimmedLine.indexOf("(") + 1, trimmedLine.lastIndexOf(")") @@ -57,7 +57,7 @@ export default class EntityFileToJson { public static getColumnOptionsAndType( trimmedLine: string, col: EntityColumn - ) { + ): void { const decoratorParameters = trimmedLine.slice( trimmedLine.indexOf("(") + 1, trimmedLine.lastIndexOf(")") @@ -100,8 +100,8 @@ export default class EntityFileToJson { } else { let badJSON = !primaryGeneratedColumn ? decoratorParameters.substring( - decoratorParameters.indexOf(",") + 1 - ) + decoratorParameters.indexOf(",") + 1 + ) : decoratorParameters; badJSON = badJSON.trim(); if (badJSON.lastIndexOf(",") === badJSON.length - 3) { @@ -117,7 +117,10 @@ export default class EntityFileToJson { } } - public static getRelationOptions(trimmedLine: string, col: EntityColumn) { + public static getRelationOptions( + trimmedLine: string, + col: EntityColumn + ): void { const decoratorParameters = trimmedLine.slice( trimmedLine.indexOf("(") + 1, trimmedLine.lastIndexOf(")") @@ -146,7 +149,7 @@ export default class EntityFileToJson { } } - public static getIndexOptions(trimmedLine: string, ind: EntityIndex) { + public static getIndexOptions(trimmedLine: string, ind: EntityIndex): void { const decoratorParameters = trimmedLine.slice( trimmedLine.indexOf("(") + 1, trimmedLine.lastIndexOf(")") @@ -499,7 +502,7 @@ export default class EntityFileToJson { return retVal; } - public static isPartOfMultilineStatement(statement: string) { + public static isPartOfMultilineStatement(statement: string): boolean { const matchStarting = statement.split("(").length + statement.split("{").length; const matchEnding = diff --git a/test/utils/GeneralTestUtils.ts b/test/utils/GeneralTestUtils.ts index 3a3976c..f507070 100644 --- a/test/utils/GeneralTestUtils.ts +++ b/test/utils/GeneralTestUtils.ts @@ -324,7 +324,7 @@ export function compileTsFiles( return compiledWithoutErrors; } -export function getEnabledDbDrivers() { +export function getEnabledDbDrivers():string[] { const dbDrivers: string[] = []; if (process.env.SQLITE_Skip === "0") { dbDrivers.push("sqlite"); From a4619dd9abdac7e7f6a0444ad684ec26e9c2a1db Mon Sep 17 00:00:00 2001 From: Kononnable Date: Sun, 27 Oct 2019 17:17:42 +0100 Subject: [PATCH 36/84] model customization tests --- src/ModelCustomization.ts | 6 + src/models/Entity.ts | 3 + src/templates/entity.mst | 17 +- test/integration/runTestsFromPath.test.ts | 2 +- .../modelCustomization.test.ts | 567 ++++++++++++++++++ 5 files changed, 589 insertions(+), 6 deletions(-) create mode 100644 test/modelCustomization/modelCustomization.test.ts diff --git a/src/ModelCustomization.ts b/src/ModelCustomization.ts index 6e0563d..10edab1 100644 --- a/src/ModelCustomization.ts +++ b/src/ModelCustomization.ts @@ -84,6 +84,12 @@ function addImportsAndGenerationOptions( entity.schema = undefined; entity.database = undefined; } + if (generationOptions.activeRecord) { + entity.activeRecord = true; + } + if (generationOptions.generateConstructor) { + entity.generateConstructor = true; + } }); return dbModel; } diff --git a/src/models/Entity.ts b/src/models/Entity.ts index 019aa20..8c189f9 100644 --- a/src/models/Entity.ts +++ b/src/models/Entity.ts @@ -14,5 +14,8 @@ export type Entity = { relationIds: RelationId[]; relations: Relation[]; indices: Index[]; + // TODO: move to sub-object or use handlebars helpers(?) fileImports: string[]; + activeRecord?: true; + generateConstructor?: true; }; diff --git a/src/templates/entity.mst b/src/templates/entity.mst index 3a6aea7..a4c6933 100644 --- a/src/templates/entity.mst +++ b/src/templates/entity.mst @@ -6,29 +6,36 @@ import { {{toEntityName .}} } from './{{toFileName .}}' {{/inline}} {{#*inline "Column"}} {{#generated}}@PrimaryGeneratedColumn({ type:"{{type}}", {{/generated}}{{^generated}}@Column("{{type}}",{ {{#primary}}primary:{{primary}},{{/primary}}{{/generated}}{{json options}}{{#default}},default: {{.}},{{/default}} }) -{{toPropertyName tscName}}:{{tscType}}; +{{printPropertyVisibility}}{{toPropertyName tscName}}{{strictMode}}:{{tscType}}; {{/inline}} {{#*inline "Relation"}} @{{relationType}}(()=>{{toEntityName relatedTable}},{{toEntityName relatedTable}}=>{{toEntityName relatedTable}}.{{toPropertyName relatedField}}{{#if relationOptions}},{ {{json relationOptions}} }{{/if}}) {{#if joinColumnOptions}}@JoinColumn([{{json joinColumnOptions}}]){{/if}} {{#if joinTableOptions}}@JoinTable({ {{json joinTableOptions}} }){{/if}} -{{toPropertyName fieldName}}:{{toRelation (toEntityName relatedTable) relationType}}; +{{printPropertyVisibility}}{{toPropertyName fieldName}}{{strictMode}}:{{toRelation (toEntityName relatedTable) relationType}}; {{/inline}} {{#*inline "RelationId"}} @RelationId(({{toPropertyName entityName}}:{{toEntityName entityName}})=>{{toPropertyName entityName}}.{{toPropertyName relationField}}) -{{toPropertyName fieldName}}:{{fieldType}}; +{{printPropertyVisibility}}{{toPropertyName fieldName}}{{strictMode}}:{{fieldType}}; +{{/inline}} +{{#*inline "Constructor"}} +{{printPropertyVisibility}}constructor(init?: Partial<{{toEntityName entityName}}>) { + {{#activeRecord}}super(); + {{/activeRecord}}Object.assign(this, init); +} {{/inline}} {{#*inline "Entity"}} {{#indices}}{{> Index}}{{/indices~}} -@Entity("{{sqlName}}",{schema:"{{schema}}",database:"{{database}}"}) -export class {{toEntityName tscName}} { +@Entity("{{sqlName}}"{{#schema}} ,{schema:"{{.}}"{{#if ../database}}, database:"{{../database}}"{{/if}} } {{/schema}}) +export class {{toEntityName tscName}}{{#activeRecord}} extends BaseEntity{{/activeRecord}} { {{#columns}}{{> Column}}{{/columns~}} {{#relations}}{{> Relation}}{{/relations~}} {{#relationIds}}{{> RelationId entityName=../tscName}}{{/relationIds~}} +{{#if generateConstructor}}{{>Constructor entityName=tscName}}{{/if~}} } {{/inline}} diff --git a/test/integration/runTestsFromPath.test.ts b/test/integration/runTestsFromPath.test.ts index e86fa39..b84cb12 100644 --- a/test/integration/runTestsFromPath.test.ts +++ b/test/integration/runTestsFromPath.test.ts @@ -199,7 +199,7 @@ function compareGeneratedFiles(filesOrgPathTS: string, filesGenPath: string) { }); } -function compileGeneratedModel(filesGenPath: string, drivers: string[]) { +export function compileGeneratedModel(filesGenPath: string, drivers: string[]) { const currentDirectoryFiles: string[] = []; drivers.forEach(driver => { const entitiesPath = path.resolve(filesGenPath, driver, "entities"); diff --git a/test/modelCustomization/modelCustomization.test.ts b/test/modelCustomization/modelCustomization.test.ts new file mode 100644 index 0000000..5ba0ff1 --- /dev/null +++ b/test/modelCustomization/modelCustomization.test.ts @@ -0,0 +1,567 @@ +import * as path from "path"; +import * as fs from "fs-extra"; +import * as chai from "chai"; +import * as chaiSubset from "chai-subset"; +import { Entity } from "../../src/models/Entity"; +import modelCustomizationPhase from "../../src/ModelCustomization"; +import IGenerationOptions from "../../src/IGenerationOptions"; +import modelGenerationPhase from "../../src/ModelGeneration"; +import IConnectionOptions from "../../src/IConnectionOptions"; +import { compileGeneratedModel } from "../integration/runTestsFromPath.test"; + +chai.use(chaiSubset); +const { expect } = chai; +describe("Model customization phase", async () => { + const generateSampleData: () => Entity[] = () => [ + { + columns: [ + { + generated: true, + type: "integer", + options: { name: "id" }, + tscName: "id", + tscType: "number", + primary: true + }, + { + type: "character varying", + options: { name: "name" }, + tscName: "name", + tscType: "string" + } + ], + indices: [ + { + columns: ["id"], + options: { unique: true }, + name: "PK_6571d08cfb2f1ab06c3aab425a6", + primary: true + } + ], + relations: [ + { + fieldName: "Post", + relatedField: "authorId", + relatedTable: "Post", + relationType: "OneToOne" + } + ], + relationIds: [], + sqlName: "PostAuthor", + tscName: "PostAuthor", + database: "", + schema: "public", + fileImports: ["Post"] + }, + { + columns: [ + { + generated: true, + type: "integer", + options: { name: "id" }, + tscName: "id", + tscType: "number", + primary: true + }, + { + type: "character varying", + options: { name: "title" }, + tscName: "title", + tscType: "string" + }, + { + type: "character varying", + options: { name: "text" }, + tscName: "text", + tscType: "string" + } + ], + indices: [ + { + columns: ["authorId"], + options: { unique: true }, + name: "REL_cef8d6e8edb69c82e5f10bb402" + }, + { + columns: ["id"], + options: { unique: true }, + name: "PK_c4d3b3dcd73db0b0129ea829f9f", + primary: true + } + ], + relations: [ + { + fieldName: "authorId", + relatedField: "Post", + joinColumnOptions: [ + { name: "authorId", referencedColumnName: "id" } + ], + relatedTable: "PostAuthor", + relationType: "OneToOne" + } + ], + relationIds: [], + sqlName: "Post", + tscName: "Post", + database: "", + schema: "public", + fileImports: ["PostAuthor"] + } + ]; + + const resultsPath = path.resolve(process.cwd(), `output`); + const generateGenerationOptions = () => { + const generationOptions = new IGenerationOptions(); + generationOptions.resultsPath = resultsPath; + return generationOptions; + }; + const clearGenerationDir = () => { + fs.ensureDirSync(resultsPath); + fs.emptyDirSync(resultsPath); + }; + describe("case-file", () => { + it("PascalCase", () => { + const data = generateSampleData(); + const generationOptions = generateGenerationOptions(); + clearGenerationDir(); + + generationOptions.convertCaseFile = "pascal"; + const customizedModel = modelCustomizationPhase( + data, + generationOptions, + {} + ); + modelGenerationPhase( + new IConnectionOptions(), + generationOptions, + customizedModel + ); + const filesGenPath = path.resolve(resultsPath, "entities"); + const files = fs.readdirSync(filesGenPath).sort(); + expect(files[0]).to.equal("Post.ts"); + expect(files[1]).to.equal("PostAuthor.ts"); + compileGeneratedModel(generationOptions.resultsPath, [""]); + }); + it("camelCase", () => { + const data = generateSampleData(); + const generationOptions = generateGenerationOptions(); + clearGenerationDir(); + + generationOptions.convertCaseFile = "camel"; + const customizedModel = modelCustomizationPhase( + data, + generationOptions, + {} + ); + modelGenerationPhase( + new IConnectionOptions(), + generationOptions, + customizedModel + ); + const filesGenPath = path.resolve(resultsPath, "entities"); + const files = fs.readdirSync(filesGenPath).sort(); + expect(files[0]).to.equal("post.ts"); + expect(files[1]).to.equal("postAuthor.ts"); + compileGeneratedModel(generationOptions.resultsPath, [""]); + }); + }); + describe("case-entity", () => { + it("PascalCase", () => { + const data = generateSampleData(); + const generationOptions = generateGenerationOptions(); + clearGenerationDir(); + + generationOptions.convertCaseEntity = "pascal"; + const customizedModel = modelCustomizationPhase( + data, + generationOptions, + {} + ); + modelGenerationPhase( + new IConnectionOptions(), + generationOptions, + customizedModel + ); + const filesGenPath = path.resolve(resultsPath, "entities"); + const postContent = fs + .readFileSync(path.resolve(filesGenPath, "Post.ts")) + .toString(); + const postAuthorContent = fs + .readFileSync(path.resolve(filesGenPath, "PostAuthor.ts")) + .toString(); + expect(postContent).to.contain("class Post {"); + expect(postAuthorContent).to.contain("class PostAuthor {"); + + compileGeneratedModel(generationOptions.resultsPath, [""]); + }); + it("camelCase", () => { + const data = generateSampleData(); + const generationOptions = generateGenerationOptions(); + clearGenerationDir(); + + generationOptions.convertCaseEntity = "camel"; + const customizedModel = modelCustomizationPhase( + data, + generationOptions, + {} + ); + modelGenerationPhase( + new IConnectionOptions(), + generationOptions, + customizedModel + ); + const filesGenPath = path.resolve(resultsPath, "entities"); + const postContent = fs + .readFileSync(path.resolve(filesGenPath, "Post.ts")) + .toString(); + const postAuthorContent = fs + .readFileSync(path.resolve(filesGenPath, "PostAuthor.ts")) + .toString(); + expect(postContent).to.contain("class post {"); + expect(postAuthorContent).to.contain("class postAuthor {"); + + compileGeneratedModel(generationOptions.resultsPath, [""]); + }); + }); + describe("case-property", async () => { + it("PascalCase", () => { + const data = generateSampleData(); + const generationOptions = generateGenerationOptions(); + clearGenerationDir(); + + generationOptions.convertCaseProperty = "pascal"; + const customizedModel = modelCustomizationPhase( + data, + generationOptions, + {} + ); + modelGenerationPhase( + new IConnectionOptions(), + generationOptions, + customizedModel + ); + const filesGenPath = path.resolve(resultsPath, "entities"); + const postContent = fs + .readFileSync(path.resolve(filesGenPath, "Post.ts")) + .toString(); + const postAuthorContent = fs + .readFileSync(path.resolve(filesGenPath, "PostAuthor.ts")) + .toString(); + expect(postContent).to.contain("Title: string;"); + expect(postAuthorContent).to.contain("Post: Post;"); + + compileGeneratedModel(generationOptions.resultsPath, [""]); + }); + it("camelCase", () => { + const data = generateSampleData(); + const generationOptions = generateGenerationOptions(); + clearGenerationDir(); + + generationOptions.convertCaseProperty = "camel"; + const customizedModel = modelCustomizationPhase( + data, + generationOptions, + {} + ); + modelGenerationPhase( + new IConnectionOptions(), + generationOptions, + customizedModel + ); + const filesGenPath = path.resolve(resultsPath, "entities"); + const postContent = fs + .readFileSync(path.resolve(filesGenPath, "Post.ts")) + .toString(); + const postAuthorContent = fs + .readFileSync(path.resolve(filesGenPath, "PostAuthor.ts")) + .toString(); + expect(postContent).to.contain("title: string;"); + expect(postAuthorContent).to.contain("post: Post;"); + + compileGeneratedModel(generationOptions.resultsPath, [""]); + }); + }); + describe("property-visibility", () => { + it("public", () => { + const data = generateSampleData(); + const generationOptions = generateGenerationOptions(); + clearGenerationDir(); + + generationOptions.propertyVisibility = "public"; + const customizedModel = modelCustomizationPhase( + data, + generationOptions, + {} + ); + modelGenerationPhase( + new IConnectionOptions(), + generationOptions, + customizedModel + ); + const filesGenPath = path.resolve(resultsPath, "entities"); + const postContent = fs + .readFileSync(path.resolve(filesGenPath, "Post.ts")) + .toString(); + const postAuthorContent = fs + .readFileSync(path.resolve(filesGenPath, "PostAuthor.ts")) + .toString(); + expect(postContent).to.have.string(" public title: string"); + expect(postAuthorContent).to.have.string(" public post: Post;"); + + compileGeneratedModel(generationOptions.resultsPath, [""]); + }); + it("none", () => { + const data = generateSampleData(); + const generationOptions = generateGenerationOptions(); + clearGenerationDir(); + + generationOptions.propertyVisibility = "none"; + const customizedModel = modelCustomizationPhase( + data, + generationOptions, + {} + ); + modelGenerationPhase( + new IConnectionOptions(), + generationOptions, + customizedModel + ); + const filesGenPath = path.resolve(resultsPath, "entities"); + const postContent = fs + .readFileSync(path.resolve(filesGenPath, "Post.ts")) + .toString(); + const postAuthorContent = fs + .readFileSync(path.resolve(filesGenPath, "PostAuthor.ts")) + .toString(); + expect(postContent).to.have.string(" title: string"); + expect(postAuthorContent).to.have.string(" post: Post;"); + + compileGeneratedModel(generationOptions.resultsPath, [""]); + }); + }); + it("lazy", async () => { + const data = generateSampleData(); + const generationOptions = generateGenerationOptions(); + clearGenerationDir(); + + generationOptions.lazy = true; + const customizedModel = modelCustomizationPhase( + data, + generationOptions, + {} + ); + modelGenerationPhase( + new IConnectionOptions(), + generationOptions, + customizedModel + ); + const filesGenPath = path.resolve(resultsPath, "entities"); + const postContent = fs + .readFileSync(path.resolve(filesGenPath, "Post.ts")) + .toString(); + const postAuthorContent = fs + .readFileSync(path.resolve(filesGenPath, "PostAuthor.ts")) + .toString(); + expect(postContent).to.have.string("lazy: true"); + expect(postContent).to.have.string("Promise;"); + expect(postAuthorContent).to.have.string("lazy: true"); + expect(postAuthorContent).to.have.string("Promise"); + + compileGeneratedModel(generationOptions.resultsPath, [""]); + }); + it("activeRecord", async () => { + const data = generateSampleData(); + const generationOptions = generateGenerationOptions(); + clearGenerationDir(); + + generationOptions.activeRecord = true; + const customizedModel = modelCustomizationPhase( + data, + generationOptions, + {} + ); + modelGenerationPhase( + new IConnectionOptions(), + generationOptions, + customizedModel + ); + const filesGenPath = path.resolve(resultsPath, "entities"); + const postContent = fs + .readFileSync(path.resolve(filesGenPath, "Post.ts")) + .toString(); + const postAuthorContent = fs + .readFileSync(path.resolve(filesGenPath, "PostAuthor.ts")) + .toString(); + expect(postContent).to.have.string( + `export class Post extends BaseEntity ` + ); + expect(postAuthorContent).to.have.string( + `export class PostAuthor extends BaseEntity ` + ); + + compileGeneratedModel(generationOptions.resultsPath, [""]); + }); + it("skipSchema", async () => { + const data = generateSampleData(); + const generationOptions = generateGenerationOptions(); + clearGenerationDir(); + + generationOptions.skipSchema = true; + const customizedModel = modelCustomizationPhase( + data, + generationOptions, + {} + ); + modelGenerationPhase( + new IConnectionOptions(), + generationOptions, + customizedModel + ); + const filesGenPath = path.resolve(resultsPath, "entities"); + const postContent = fs + .readFileSync(path.resolve(filesGenPath, "Post.ts")) + .toString(); + const postAuthorContent = fs + .readFileSync(path.resolve(filesGenPath, "PostAuthor.ts")) + .toString(); + expect(postContent).to.have.string(`@Entity("Post")`); + expect(postAuthorContent).to.have.string(`@Entity("PostAuthor")`); + + compileGeneratedModel(generationOptions.resultsPath, [""]); + }); + it("generateConstructor", async () => { + const data = generateSampleData(); + const generationOptions = generateGenerationOptions(); + clearGenerationDir(); + + generationOptions.generateConstructor = true; + const customizedModel = modelCustomizationPhase( + data, + generationOptions, + {} + ); + modelGenerationPhase( + new IConnectionOptions(), + generationOptions, + customizedModel + ); + const filesGenPath = path.resolve(resultsPath, "entities"); + const postContent = fs + .readFileSync(path.resolve(filesGenPath, "Post.ts")) + .toString(); + const postAuthorContent = fs + .readFileSync(path.resolve(filesGenPath, "PostAuthor.ts")) + .toString(); + expect(postContent).to.have.string(`constructor(init?: Partial)`); + expect(postContent).to.have.string(`Object.assign(this, init);`); + expect(postAuthorContent).to.have.string( + `constructor(init?: Partial)` + ); + expect(postAuthorContent).to.have.string(`Object.assign(this, init);`); + + compileGeneratedModel(generationOptions.resultsPath, [""]); + }); + it("generateConstructor with activeRecord", async () => { + const data = generateSampleData(); + const generationOptions = generateGenerationOptions(); + clearGenerationDir(); + + generationOptions.generateConstructor = true; + generationOptions.activeRecord = true; + const customizedModel = modelCustomizationPhase( + data, + generationOptions, + {} + ); + modelGenerationPhase( + new IConnectionOptions(), + generationOptions, + customizedModel + ); + const filesGenPath = path.resolve(resultsPath, "entities"); + const postContent = fs + .readFileSync(path.resolve(filesGenPath, "Post.ts")) + .toString(); + const postAuthorContent = fs + .readFileSync(path.resolve(filesGenPath, "PostAuthor.ts")) + .toString(); + expect(postContent).to.have.string(`constructor(init?: Partial)`); + expect(postContent).to.have.string(`super();`); + expect(postContent).to.have.string(`Object.assign(this, init);`); + expect(postAuthorContent).to.have.string( + `constructor(init?: Partial)` + ); + expect(postAuthorContent).to.have.string(`super();`); + expect(postAuthorContent).to.have.string(`Object.assign(this, init);`); + + compileGeneratedModel(generationOptions.resultsPath, [""]); + }); + describe("strictMode", () => { + it("!", async () => { + const data = generateSampleData(); + const generationOptions = generateGenerationOptions(); + clearGenerationDir(); + + generationOptions.strictMode = "!"; + const customizedModel = modelCustomizationPhase( + data, + generationOptions, + {} + ); + modelGenerationPhase( + new IConnectionOptions(), + generationOptions, + customizedModel + ); + const filesGenPath = path.resolve(resultsPath, "entities"); + const postContent = fs + .readFileSync(path.resolve(filesGenPath, "Post.ts")) + .toString(); + const postAuthorContent = fs + .readFileSync(path.resolve(filesGenPath, "PostAuthor.ts")) + .toString(); + expect(postContent).to.have.string(`id!: number;`); + expect(postContent).to.have.string(`title!: string;`); + expect(postContent).to.have.string(`text!: string;`); + expect(postContent).to.have.string(`author!: PostAuthor;`); + expect(postAuthorContent).to.have.string(`id!: number;`); + expect(postAuthorContent).to.have.string(`name!: string;`); + expect(postAuthorContent).to.have.string(`post!: Post;`); + + compileGeneratedModel(generationOptions.resultsPath, [""]); + }); + it("?", async () => { + const data = generateSampleData(); + const generationOptions = generateGenerationOptions(); + clearGenerationDir(); + + generationOptions.strictMode = "?"; + const customizedModel = modelCustomizationPhase( + data, + generationOptions, + {} + ); + modelGenerationPhase( + new IConnectionOptions(), + generationOptions, + customizedModel + ); + const filesGenPath = path.resolve(resultsPath, "entities"); + const postContent = fs + .readFileSync(path.resolve(filesGenPath, "Post.ts")) + .toString(); + const postAuthorContent = fs + .readFileSync(path.resolve(filesGenPath, "PostAuthor.ts")) + .toString(); + expect(postContent).to.have.string(`id?: number;`); + expect(postContent).to.have.string(`title?: string;`); + expect(postContent).to.have.string(`text?: string;`); + expect(postContent).to.have.string(`author?: PostAuthor;`); + expect(postAuthorContent).to.have.string(`id?: number;`); + expect(postAuthorContent).to.have.string(`name?: string;`); + expect(postAuthorContent).to.have.string(`post?: Post;`); + + compileGeneratedModel(generationOptions.resultsPath, [""]); + }); + }); +}); From b3c09ac285acb5504c45a3cc0ebe5da067376a56 Mon Sep 17 00:00:00 2001 From: Kononnable Date: Sun, 27 Oct 2019 17:31:51 +0100 Subject: [PATCH 37/84] disable linting error --- test/integration/runTestsFromPath.test.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/integration/runTestsFromPath.test.ts b/test/integration/runTestsFromPath.test.ts index b84cb12..32c143d 100644 --- a/test/integration/runTestsFromPath.test.ts +++ b/test/integration/runTestsFromPath.test.ts @@ -199,6 +199,8 @@ function compareGeneratedFiles(filesOrgPathTS: string, filesGenPath: string) { }); } +// TODO: Move(?) +// eslint-disable-next-line import/prefer-default-export export function compileGeneratedModel(filesGenPath: string, drivers: string[]) { const currentDirectoryFiles: string[] = []; drivers.forEach(driver => { From bef61595afa2a427e5aa9a8375604235724bb923 Mon Sep 17 00:00:00 2001 From: Kononnable Date: Sun, 27 Oct 2019 17:32:25 +0100 Subject: [PATCH 38/84] change tested node versions --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 60bb8cf..e0392eb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,6 @@ language: node_js node_js: +- 13 - 12 - 10 - 8 From 35c7e35f74a9e901bc4229ebda60f01002512efd Mon Sep 17 00:00:00 2001 From: Kononnable Date: Tue, 29 Oct 2019 22:18:35 +0100 Subject: [PATCH 39/84] #215 single primary key is always unique --- src/drivers/AbstractDriver.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/drivers/AbstractDriver.ts b/src/drivers/AbstractDriver.ts index 501de28..d27b212 100644 --- a/src/drivers/AbstractDriver.ts +++ b/src/drivers/AbstractDriver.ts @@ -424,6 +424,12 @@ export default abstract class AbstractDriver { .forEach(col => { // eslint-disable-next-line no-param-reassign col.primary = true; + if ( + primaryIndex!.columns.length === 1 && + col.options.unique + ) { + delete col.options.unique; + } }); if ( !entity.columns.some(v => { From 1057b665ac7c4a421402e2833740d553b9455fb6 Mon Sep 17 00:00:00 2001 From: Kononnable Date: Thu, 7 Nov 2019 22:03:01 +0100 Subject: [PATCH 40/84] remove unused import declarations --- src/ModelGeneration.ts | 19 ++++++++++++++++++- src/templates/entity.mst | 1 - 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/ModelGeneration.ts b/src/ModelGeneration.ts index 743dd74..226b1c7 100644 --- a/src/ModelGeneration.ts +++ b/src/ModelGeneration.ts @@ -55,13 +55,30 @@ export default function modelGenerationPhase( `${casedFileName}.ts` ); const rendered = compliedTemplate(element); - const formatted = Prettier.format(rendered, { parser: "typescript" }); + const withImportStatements = removeUnusedImports(rendered); + const formatted = Prettier.format(withImportStatements, { + parser: "typescript" + }); fs.writeFileSync(resultFilePath, formatted, { encoding: "UTF-8", flag: "w" }); }); } +function removeUnusedImports(rendered: string) { + const openBracketIndex = rendered.indexOf("{") + 1; + const closeBracketIndex = rendered.indexOf("}"); + const imports = rendered + .substring(openBracketIndex, closeBracketIndex) + .split(","); + const restOfEntityDefinition = rendered.substring(closeBracketIndex); + const distinctImports = imports.filter( + v => restOfEntityDefinition.indexOf(v) !== -1 + ); + return `${rendered.substring(0, openBracketIndex)}${distinctImports.join( + "," + )}${restOfEntityDefinition}`; +} function createHandlebarsHelpers(generationOptions: IGenerationOptions): void { Handlebars.registerHelper("json", context => { diff --git a/src/templates/entity.mst b/src/templates/entity.mst index a4c6933..17f714b 100644 --- a/src/templates/entity.mst +++ b/src/templates/entity.mst @@ -38,7 +38,6 @@ export class {{toEntityName tscName}}{{#activeRecord}} extends BaseEntity{{/acti {{#if generateConstructor}}{{>Constructor entityName=tscName}}{{/if~}} } {{/inline}} - import {BaseEntity,Column,Entity,Index,JoinColumn,JoinTable,ManyToMany,ManyToOne,OneToMany,OneToOne,PrimaryColumn,PrimaryGeneratedColumn,RelationId} from "typeorm"; {{#fileImports}}{{> Import}}{{/fileImports~}} From 2cc6b4f43c91de9fe3955854dc652a5f17e9984c Mon Sep 17 00:00:00 2001 From: Kononnable Date: Fri, 8 Nov 2019 23:57:01 +0100 Subject: [PATCH 41/84] fix generation of complex manyToMany relationships fix generation of multiple relations based on the same column --- src/ModelCustomization.ts | 11 ++++++++++- src/drivers/AbstractDriver.ts | 18 ++++++++---------- src/drivers/MssqlDriver.ts | 3 ++- src/drivers/MysqlDriver.ts | 3 ++- src/drivers/OracleDriver.ts | 3 ++- src/drivers/PostgresDriver.ts | 3 ++- src/drivers/SqliteDriver.ts | 3 ++- src/models/Column.ts | 3 ++- test/drivers/MssqlDriver.test.ts | 3 ++- .../modelCustomization.test.ts | 15 ++++++++++----- 10 files changed, 42 insertions(+), 23 deletions(-) diff --git a/src/ModelCustomization.ts b/src/ModelCustomization.ts index 10edab1..8c12c82 100644 --- a/src/ModelCustomization.ts +++ b/src/ModelCustomization.ts @@ -21,11 +21,20 @@ export default function modelCustomizationPhase( } else { namingStrategy = new NamingStrategy(); } - let retVal = applyNamingStrategy(namingStrategy, dbModel); + let retVal = removeColumnsInRelation(dbModel); + retVal = applyNamingStrategy(namingStrategy, dbModel); retVal = addImportsAndGenerationOptions(retVal, generationOptions); retVal = removeColumnDefaultProperties(retVal, defaultValues); return retVal; } +function removeColumnsInRelation(dbModel: Entity[]): Entity[] { + dbModel.forEach(entity => { + entity.columns = entity.columns.filter( + col => !col.isUsedInRelation || col.primary + ); + }); + return dbModel; +} function removeColumnDefaultProperties( dbModel: Entity[], defaultValues: DataTypeDefaults diff --git a/src/drivers/AbstractDriver.ts b/src/drivers/AbstractDriver.ts index d27b212..47dfe9e 100644 --- a/src/drivers/AbstractDriver.ts +++ b/src/drivers/AbstractDriver.ts @@ -88,6 +88,8 @@ export default abstract class AbstractDriver { ) && entity.relations[0].relatedTable !== entity.relations[1].relatedTable && + entity.relations[0].joinColumnOptions!.length === + entity.relations[1].joinColumnOptions!.length && entity.columns.length === entity.columns.filter(c => c.primary).length && entity.columns @@ -315,16 +317,12 @@ export default abstract class AbstractDriver { ); isOneToMany = !index; - ownerEntity.columns = ownerEntity.columns.filter( - v => - !relationTmp.ownerColumns.some(u => u === v.tscName) || - v.primary - ); - relationTmp.relatedTable.columns = relationTmp.relatedTable.columns.filter( - v => - !relationTmp.relatedColumns.some(u => u === v.tscName) || - v.primary - ); + ownerColumns.forEach(column => { + column.isUsedInRelation = true; + }); + relatedColumns.forEach(column => { + column.isUsedInRelation = true; + }); let fieldName = ""; if (ownerColumns.length === 1) { fieldName = TomgUtils.findNameForNewField( diff --git a/src/drivers/MssqlDriver.ts b/src/drivers/MssqlDriver.ts index 4b639fa..4adf75e 100644 --- a/src/drivers/MssqlDriver.ts +++ b/src/drivers/MssqlDriver.ts @@ -226,7 +226,8 @@ WHERE TABLE_TYPE='BASE TABLE' and TABLE_SCHEMA in (${schema}) AND TABLE_CATALOG default: defaultValue, options, tscName, - tscType + tscType, + isUsedInRelation: false }); } }); diff --git a/src/drivers/MysqlDriver.ts b/src/drivers/MysqlDriver.ts index 75aab4a..44b5acd 100644 --- a/src/drivers/MysqlDriver.ts +++ b/src/drivers/MysqlDriver.ts @@ -257,7 +257,8 @@ export default class MysqlDriver extends AbstractDriver { default: defaultValue, options, tscName, - tscType + tscType, + isUsedInRelation: false }); } }); diff --git a/src/drivers/OracleDriver.ts b/src/drivers/OracleDriver.ts index 38cf79b..16b255c 100644 --- a/src/drivers/OracleDriver.ts +++ b/src/drivers/OracleDriver.ts @@ -208,7 +208,8 @@ export default class OracleDriver extends AbstractDriver { default: defaultValue, options, tscName, - tscType + tscType, + isUsedInRelation: false }); } }); diff --git a/src/drivers/PostgresDriver.ts b/src/drivers/PostgresDriver.ts index c34402f..0aae984 100644 --- a/src/drivers/PostgresDriver.ts +++ b/src/drivers/PostgresDriver.ts @@ -159,7 +159,8 @@ export default class PostgresDriver extends AbstractDriver { default: defaultValue, options, tscName, - tscType + tscType, + isUsedInRelation: false }); } }); diff --git a/src/drivers/SqliteDriver.ts b/src/drivers/SqliteDriver.ts index 64ce684..1d07aba 100644 --- a/src/drivers/SqliteDriver.ts +++ b/src/drivers/SqliteDriver.ts @@ -226,7 +226,8 @@ export default class SqliteDriver extends AbstractDriver { default: defaultValue, options, tscName, - tscType + tscType, + isUsedInRelation: false }); } }); diff --git a/src/models/Column.ts b/src/models/Column.ts index bde92ce..b14fd41 100644 --- a/src/models/Column.ts +++ b/src/models/Column.ts @@ -3,7 +3,8 @@ import { ColumnType } from "typeorm"; export type Column = { tscType: string; tscName: string; - type: ColumnType | string; // todo: remove ? + type: ColumnType | string; // TODO: remove ? + isUsedInRelation: boolean; // TODO: move to separate object/calulate when us primary?: boolean; generated?: true | "increment" | "uuid"; diff --git a/test/drivers/MssqlDriver.test.ts b/test/drivers/MssqlDriver.test.ts index bfa577f..c7a5a2d 100644 --- a/test/drivers/MssqlDriver.test.ts +++ b/test/drivers/MssqlDriver.test.ts @@ -106,7 +106,8 @@ describe("MssqlDriver", () => { generated: true, default: `() => "'a'"`, tscName: "name", - tscType: "number" + tscType: "number", + isUsedInRelation: false }); const result = await driver.GetCoulmnsFromEntity( diff --git a/test/modelCustomization/modelCustomization.test.ts b/test/modelCustomization/modelCustomization.test.ts index 5ba0ff1..207f20c 100644 --- a/test/modelCustomization/modelCustomization.test.ts +++ b/test/modelCustomization/modelCustomization.test.ts @@ -21,13 +21,15 @@ describe("Model customization phase", async () => { options: { name: "id" }, tscName: "id", tscType: "number", - primary: true + primary: true, + isUsedInRelation: false }, { type: "character varying", options: { name: "name" }, tscName: "name", - tscType: "string" + tscType: "string", + isUsedInRelation: false } ], indices: [ @@ -61,19 +63,22 @@ describe("Model customization phase", async () => { options: { name: "id" }, tscName: "id", tscType: "number", - primary: true + primary: true, + isUsedInRelation: false }, { type: "character varying", options: { name: "title" }, tscName: "title", - tscType: "string" + tscType: "string", + isUsedInRelation: false }, { type: "character varying", options: { name: "text" }, tscName: "text", - tscType: "string" + tscType: "string", + isUsedInRelation: false } ], indices: [ From 06a28b70ae7d63bb9cc6a38c5a02609eab5549b7 Mon Sep 17 00:00:00 2001 From: Kononnable Date: Sat, 9 Nov 2019 11:49:51 +0100 Subject: [PATCH 42/84] remove unnecessary TODOs --- src/ModelGeneration.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/ModelGeneration.ts b/src/ModelGeneration.ts index 226b1c7..143fd30 100644 --- a/src/ModelGeneration.ts +++ b/src/ModelGeneration.ts @@ -124,7 +124,6 @@ function createHandlebarsHelpers(generationOptions: IGenerationOptions): void { return retStr; }); Handlebars.registerHelper("printPropertyVisibility", () => - // TODO: generationOptions.propertyVisibility !== "none" ? `${generationOptions.propertyVisibility} ` : "" @@ -160,7 +159,6 @@ function createHandlebarsHelpers(generationOptions: IGenerationOptions): void { } ); Handlebars.registerHelper("strictMode", () => - // TODO: generationOptions.strictMode ? generationOptions.strictMode : "" ); Handlebars.registerHelper({ From 396a461626e4e1e73d735b0eb9f53448c2586337 Mon Sep 17 00:00:00 2001 From: Kononnable Date: Sun, 10 Nov 2019 13:33:05 +0100 Subject: [PATCH 43/84] fix generation of duplicate field names --- src/Utils.ts | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/Utils.ts b/src/Utils.ts index 2556fc8..af39d98 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -1,3 +1,4 @@ +import * as changeCase from "change-case"; import * as packagejson from "../package.json"; import { Entity } from "./models/Entity"; @@ -31,16 +32,23 @@ export function findNameForNewField( let fieldName = _fieldName; const validNameCondition = () => (entity.columns.every( - v => v.tscName.toLowerCase() !== fieldName.toLowerCase() + v => + changeCase.camelCase(v.tscName) !== + changeCase.camelCase(fieldName) ) && entity.relations.every( - v => v.fieldName.toLowerCase() !== fieldName.toLowerCase() + v => + changeCase.camelCase(v.fieldName) !== + changeCase.camelCase(fieldName) ) && entity.relationIds.every( - v => v.fieldName.toLowerCase() !== fieldName.toLowerCase() + v => + changeCase.camelCase(v.fieldName) !== + changeCase.camelCase(fieldName) )) || (columnOldName && - columnOldName.toLowerCase() === fieldName.toLowerCase()); + changeCase.camelCase(columnOldName) === + changeCase.camelCase(fieldName)); if (!validNameCondition()) { fieldName += "_"; for ( From beaf3a09da96ed1bca2c945b3ad1c352a48f7af0 Mon Sep 17 00:00:00 2001 From: Kononnable Date: Sun, 10 Nov 2019 14:54:48 +0100 Subject: [PATCH 44/84] fix removal of some of columns from relations proper referencedColumnName value --- src/ModelCustomization.ts | 5 ++- src/drivers/AbstractDriver.ts | 4 +-- src/drivers/MssqlDriver.ts | 31 +++++++++---------- src/drivers/MysqlDriver.ts | 3 +- src/drivers/OracleDriver.ts | 3 +- src/drivers/PostgresDriver.ts | 3 +- src/drivers/SqliteDriver.ts | 3 +- src/models/Column.ts | 3 +- src/templates/entity.mst | 2 +- test/drivers/MssqlDriver.test.ts | 3 +- .../modelCustomization.test.ts | 15 +++------ 11 files changed, 34 insertions(+), 41 deletions(-) diff --git a/src/ModelCustomization.ts b/src/ModelCustomization.ts index 8c12c82..d635bb3 100644 --- a/src/ModelCustomization.ts +++ b/src/ModelCustomization.ts @@ -30,7 +30,10 @@ export default function modelCustomizationPhase( function removeColumnsInRelation(dbModel: Entity[]): Entity[] { dbModel.forEach(entity => { entity.columns = entity.columns.filter( - col => !col.isUsedInRelation || col.primary + col => + !col.isUsedInRelationAsOwner || + col.isUsedInRelationAsReferenced || + col.primary ); }); return dbModel; diff --git a/src/drivers/AbstractDriver.ts b/src/drivers/AbstractDriver.ts index 47dfe9e..cbfe754 100644 --- a/src/drivers/AbstractDriver.ts +++ b/src/drivers/AbstractDriver.ts @@ -318,10 +318,10 @@ export default abstract class AbstractDriver { isOneToMany = !index; ownerColumns.forEach(column => { - column.isUsedInRelation = true; + column.isUsedInRelationAsOwner = true; }); relatedColumns.forEach(column => { - column.isUsedInRelation = true; + column.isUsedInRelationAsReferenced = true; }); let fieldName = ""; if (ownerColumns.length === 1) { diff --git a/src/drivers/MssqlDriver.ts b/src/drivers/MssqlDriver.ts index 4adf75e..92efbc3 100644 --- a/src/drivers/MssqlDriver.ts +++ b/src/drivers/MssqlDriver.ts @@ -57,22 +57,22 @@ WHERE TABLE_TYPE='BASE TABLE' and TABLE_SCHEMA in (${schema}) AND TABLE_CATALOG IsIdentity: number; IsUnique: number; }[] = (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(*) - FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS tc - inner join INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE cu - on cu.CONSTRAINT_NAME = tc.CONSTRAINT_NAME - where - tc.CONSTRAINT_TYPE = 'UNIQUE' - and tc.TABLE_NAME = c.TABLE_NAME - and cu.COLUMN_NAME = c.COLUMN_NAME - and tc.TABLE_SCHEMA=c.TABLE_SCHEMA) IsUnique - FROM INFORMATION_SCHEMA.COLUMNS c - where TABLE_SCHEMA in (${schema}) AND TABLE_CATALOG in (${MssqlDriver.escapeCommaSeparatedList( + DATA_TYPE,CHARACTER_MAXIMUM_LENGTH,NUMERIC_PRECISION,NUMERIC_SCALE, + COLUMNPROPERTY(object_id(TABLE_NAME), COLUMN_NAME, 'IsIdentity') IsIdentity, + (SELECT count(*) + FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS tc + inner join INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE cu + on cu.CONSTRAINT_NAME = tc.CONSTRAINT_NAME + where + tc.CONSTRAINT_TYPE = 'UNIQUE' + and tc.TABLE_NAME = c.TABLE_NAME + and cu.COLUMN_NAME = c.COLUMN_NAME + and tc.TABLE_SCHEMA=c.TABLE_SCHEMA) IsUnique + FROM INFORMATION_SCHEMA.COLUMNS c + where TABLE_SCHEMA in (${schema}) AND TABLE_CATALOG in (${MssqlDriver.escapeCommaSeparatedList( dbNames )}) - order by ordinal_position`)).recordset; + order by ordinal_position`)).recordset; entities.forEach(ent => { response .filter(filterVal => { @@ -226,8 +226,7 @@ WHERE TABLE_TYPE='BASE TABLE' and TABLE_SCHEMA in (${schema}) AND TABLE_CATALOG default: defaultValue, options, tscName, - tscType, - isUsedInRelation: false + tscType }); } }); diff --git a/src/drivers/MysqlDriver.ts b/src/drivers/MysqlDriver.ts index 44b5acd..75aab4a 100644 --- a/src/drivers/MysqlDriver.ts +++ b/src/drivers/MysqlDriver.ts @@ -257,8 +257,7 @@ export default class MysqlDriver extends AbstractDriver { default: defaultValue, options, tscName, - tscType, - isUsedInRelation: false + tscType }); } }); diff --git a/src/drivers/OracleDriver.ts b/src/drivers/OracleDriver.ts index 16b255c..38cf79b 100644 --- a/src/drivers/OracleDriver.ts +++ b/src/drivers/OracleDriver.ts @@ -208,8 +208,7 @@ export default class OracleDriver extends AbstractDriver { default: defaultValue, options, tscName, - tscType, - isUsedInRelation: false + tscType }); } }); diff --git a/src/drivers/PostgresDriver.ts b/src/drivers/PostgresDriver.ts index 0aae984..c34402f 100644 --- a/src/drivers/PostgresDriver.ts +++ b/src/drivers/PostgresDriver.ts @@ -159,8 +159,7 @@ export default class PostgresDriver extends AbstractDriver { default: defaultValue, options, tscName, - tscType, - isUsedInRelation: false + tscType }); } }); diff --git a/src/drivers/SqliteDriver.ts b/src/drivers/SqliteDriver.ts index 1d07aba..64ce684 100644 --- a/src/drivers/SqliteDriver.ts +++ b/src/drivers/SqliteDriver.ts @@ -226,8 +226,7 @@ export default class SqliteDriver extends AbstractDriver { default: defaultValue, options, tscName, - tscType, - isUsedInRelation: false + tscType }); } }); diff --git a/src/models/Column.ts b/src/models/Column.ts index b14fd41..f62271e 100644 --- a/src/models/Column.ts +++ b/src/models/Column.ts @@ -4,7 +4,8 @@ export type Column = { tscType: string; tscName: string; type: ColumnType | string; // TODO: remove ? - isUsedInRelation: boolean; // TODO: move to separate object/calulate when us + isUsedInRelationAsOwner?: true; // TODO: move to separate object/calulate when us + isUsedInRelationAsReferenced?: true; // TODO: move to separate object/calulate when us primary?: boolean; generated?: true | "increment" | "uuid"; diff --git a/src/templates/entity.mst b/src/templates/entity.mst index 17f714b..8cfa03c 100644 --- a/src/templates/entity.mst +++ b/src/templates/entity.mst @@ -11,7 +11,7 @@ import { {{toEntityName .}} } from './{{toFileName .}}' {{/inline}} {{#*inline "Relation"}} @{{relationType}}(()=>{{toEntityName relatedTable}},{{toEntityName relatedTable}}=>{{toEntityName relatedTable}}.{{toPropertyName relatedField}}{{#if relationOptions}},{ {{json relationOptions}} }{{/if}}) -{{#if joinColumnOptions}}@JoinColumn([{{json joinColumnOptions}}]){{/if}} +{{#if joinColumnOptions}}@JoinColumn([{{#joinColumnOptions}}{ name: "{{name}}", referencedColumnName: "{{toPropertyName referencedColumnName}}" },{{/joinColumnOptions}}]){{/if}} {{#if joinTableOptions}}@JoinTable({ {{json joinTableOptions}} }){{/if}} {{printPropertyVisibility}}{{toPropertyName fieldName}}{{strictMode}}:{{toRelation (toEntityName relatedTable) relationType}}; diff --git a/test/drivers/MssqlDriver.test.ts b/test/drivers/MssqlDriver.test.ts index c7a5a2d..bfa577f 100644 --- a/test/drivers/MssqlDriver.test.ts +++ b/test/drivers/MssqlDriver.test.ts @@ -106,8 +106,7 @@ describe("MssqlDriver", () => { generated: true, default: `() => "'a'"`, tscName: "name", - tscType: "number", - isUsedInRelation: false + tscType: "number" }); const result = await driver.GetCoulmnsFromEntity( diff --git a/test/modelCustomization/modelCustomization.test.ts b/test/modelCustomization/modelCustomization.test.ts index 207f20c..5ba0ff1 100644 --- a/test/modelCustomization/modelCustomization.test.ts +++ b/test/modelCustomization/modelCustomization.test.ts @@ -21,15 +21,13 @@ describe("Model customization phase", async () => { options: { name: "id" }, tscName: "id", tscType: "number", - primary: true, - isUsedInRelation: false + primary: true }, { type: "character varying", options: { name: "name" }, tscName: "name", - tscType: "string", - isUsedInRelation: false + tscType: "string" } ], indices: [ @@ -63,22 +61,19 @@ describe("Model customization phase", async () => { options: { name: "id" }, tscName: "id", tscType: "number", - primary: true, - isUsedInRelation: false + primary: true }, { type: "character varying", options: { name: "title" }, tscName: "title", - tscType: "string", - isUsedInRelation: false + tscType: "string" }, { type: "character varying", options: { name: "text" }, tscName: "text", - tscType: "string", - isUsedInRelation: false + tscType: "string" } ], indices: [ From 5cdf4691f435cc4b8966092574137bb4564b8b03 Mon Sep 17 00:00:00 2001 From: Kononnable Date: Sun, 10 Nov 2019 16:23:32 +0100 Subject: [PATCH 45/84] fix removal of columns used in relations which where also used in indices --- src/ModelCustomization.ts | 34 +++++++++++++++++++++++++++++++++- src/drivers/AbstractDriver.ts | 2 +- src/models/Relation.ts | 2 +- 3 files changed, 35 insertions(+), 3 deletions(-) diff --git a/src/ModelCustomization.ts b/src/ModelCustomization.ts index d635bb3..6fbd896 100644 --- a/src/ModelCustomization.ts +++ b/src/ModelCustomization.ts @@ -1,4 +1,5 @@ import { DataTypeDefaults } from "typeorm/driver/types/DataTypeDefaults"; +import { DefaultNamingStrategy } from "typeorm/naming-strategy/DefaultNamingStrategy"; import { Entity } from "./models/Entity"; import IGenerationOptions from "./IGenerationOptions"; import AbstractNamingStrategy from "./AbstractNamingStrategy"; @@ -21,18 +22,49 @@ export default function modelCustomizationPhase( } else { namingStrategy = new NamingStrategy(); } - let retVal = removeColumnsInRelation(dbModel); + let retVal = removeIndicesGeneratedByTypeorm(dbModel); + retVal = removeColumnsInRelation(dbModel); retVal = applyNamingStrategy(namingStrategy, dbModel); retVal = addImportsAndGenerationOptions(retVal, generationOptions); retVal = removeColumnDefaultProperties(retVal, defaultValues); return retVal; } +function removeIndicesGeneratedByTypeorm(dbModel: Entity[]): Entity[] { + // TODO: Support typeorm CustomNamingStrategy + // TODO: PK index - ignores primaryKeyName(typeorm bug?) - to investigate + const namingStrategy = new DefaultNamingStrategy(); + dbModel.forEach(entity => { + entity.indices = entity.indices.filter( + v => !v.name.startsWith(`sqlite_autoindex_`) + ); + entity.relations + .filter(v => v.joinColumnOptions) + .forEach(rel => { + const columnNames = rel.joinColumnOptions!.map(v => v.name); + const idxName = namingStrategy.relationConstraintName( + entity.tscName, + columnNames + ); + const fkName = namingStrategy.foreignKeyName( + entity.tscName, + columnNames + ); + entity.indices = entity.indices.filter( + v => v.name !== idxName && v.name !== fkName + ); + }); + }); + return dbModel; +} function removeColumnsInRelation(dbModel: Entity[]): Entity[] { dbModel.forEach(entity => { entity.columns = entity.columns.filter( col => !col.isUsedInRelationAsOwner || col.isUsedInRelationAsReferenced || + entity.indices.some(idx => + idx.columns.some(v => v === col.tscName) + ) || col.primary ); }); diff --git a/src/drivers/AbstractDriver.ts b/src/drivers/AbstractDriver.ts index cbfe754..7682d41 100644 --- a/src/drivers/AbstractDriver.ts +++ b/src/drivers/AbstractDriver.ts @@ -348,7 +348,7 @@ export default abstract class AbstractDriver { relationTmp.relatedTable ), joinColumnOptions: relationTmp.ownerColumns.map((v, idx) => { - const retVal: JoinColumnOptions = { + const retVal: Required = { name: v, referencedColumnName: relationTmp.relatedColumns[idx] }; diff --git a/src/models/Relation.ts b/src/models/Relation.ts index c8cb02f..7c35c24 100644 --- a/src/models/Relation.ts +++ b/src/models/Relation.ts @@ -7,6 +7,6 @@ export type Relation = { relatedField: string; fieldName: string; relationOptions?: RelationOptions; - joinColumnOptions?: JoinColumnOptions[]; + joinColumnOptions?: Required[]; joinTableOptions?: JoinTableMultipleColumnsOptions; }; From d797c3d06d16f02baecf2596f5b84f1639cec174 Mon Sep 17 00:00:00 2001 From: Kononnable Date: Sun, 10 Nov 2019 17:28:56 +0100 Subject: [PATCH 46/84] proper colum names in ManyToMany relationships --- src/drivers/AbstractDriver.ts | 12 ++++++------ src/templates/entity.mst | 7 +++++-- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/drivers/AbstractDriver.ts b/src/drivers/AbstractDriver.ts index 7682d41..2b0072a 100644 --- a/src/drivers/AbstractDriver.ts +++ b/src/drivers/AbstractDriver.ts @@ -140,18 +140,18 @@ export default abstract class AbstractDriver { joinColumns: junctionEntity.relations[0].joinColumnOptions!.map( (v, i) => { return { - name: v.referencedColumnName, - referencedColumnName: junctionEntity.relations[1] - .joinColumnOptions![i].referencedColumnName + referencedColumnName: v.referencedColumnName, + name: junctionEntity.relations[0] + .joinColumnOptions![i].name }; } ), inverseJoinColumns: junctionEntity.relations[1].joinColumnOptions!.map( (v, i) => { return { - name: v.referencedColumnName, - referencedColumnName: junctionEntity.relations[0] - .joinColumnOptions![i].referencedColumnName + referencedColumnName: v.referencedColumnName, + name: junctionEntity.relations[1] + .joinColumnOptions![i].name }; } ) diff --git a/src/templates/entity.mst b/src/templates/entity.mst index 8cfa03c..1a874c8 100644 --- a/src/templates/entity.mst +++ b/src/templates/entity.mst @@ -8,11 +8,14 @@ import { {{toEntityName .}} } from './{{toFileName .}}' {{#generated}}@PrimaryGeneratedColumn({ type:"{{type}}", {{/generated}}{{^generated}}@Column("{{type}}",{ {{#primary}}primary:{{primary}},{{/primary}}{{/generated}}{{json options}}{{#default}},default: {{.}},{{/default}} }) {{printPropertyVisibility}}{{toPropertyName tscName}}{{strictMode}}:{{tscType}}; +{{/inline}} +{{#*inline "JoinColumnOptions"}} +{ name: "{{name}}", referencedColumnName: "{{toPropertyName referencedColumnName}}" }, {{/inline}} {{#*inline "Relation"}} @{{relationType}}(()=>{{toEntityName relatedTable}},{{toEntityName relatedTable}}=>{{toEntityName relatedTable}}.{{toPropertyName relatedField}}{{#if relationOptions}},{ {{json relationOptions}} }{{/if}}) -{{#if joinColumnOptions}}@JoinColumn([{{#joinColumnOptions}}{ name: "{{name}}", referencedColumnName: "{{toPropertyName referencedColumnName}}" },{{/joinColumnOptions}}]){{/if}} -{{#if joinTableOptions}}@JoinTable({ {{json joinTableOptions}} }){{/if}} +{{#if joinColumnOptions}}@JoinColumn([{{#joinColumnOptions}}{{> JoinColumnOptions}}{{/joinColumnOptions}}]){{/if}} +{{#joinTableOptions}}@JoinTable({ name:"{{name}}", joinColumns:[{{#joinColumns}}{{> JoinColumnOptions}}{{/joinColumns}}],inverseJoinColumns:[{{#inverseJoinColumns}}{{> JoinColumnOptions}}{{/inverseJoinColumns}}],{{#database}}database:"{{.}}",{{/database}}{{#schema}}schema:"{{.}}"{{/schema}} }){{/joinTableOptions}} {{printPropertyVisibility}}{{toPropertyName fieldName}}{{strictMode}}:{{toRelation (toEntityName relatedTable) relationType}}; {{/inline}} From f346c0b904ad747ebf286fd76a622f9c886273b2 Mon Sep 17 00:00:00 2001 From: Kononnable Date: Sun, 10 Nov 2019 18:41:21 +0100 Subject: [PATCH 47/84] remove generation of PK indices --- src/ModelCustomization.ts | 17 +++++++++++++++-- src/templates/entity.mst | 4 ++-- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/ModelCustomization.ts b/src/ModelCustomization.ts index 6fbd896..5ec3937 100644 --- a/src/ModelCustomization.ts +++ b/src/ModelCustomization.ts @@ -31,11 +31,24 @@ export default function modelCustomizationPhase( } function removeIndicesGeneratedByTypeorm(dbModel: Entity[]): Entity[] { // TODO: Support typeorm CustomNamingStrategy - // TODO: PK index - ignores primaryKeyName(typeorm bug?) - to investigate const namingStrategy = new DefaultNamingStrategy(); dbModel.forEach(entity => { entity.indices = entity.indices.filter( - v => !v.name.startsWith(`sqlite_autoindex_`) + v => + !v.name.startsWith(`sqlite_autoindex_`) && + (v.name !== "PRIMARY" && v.primary) + ); + const primaryColumns = entity.columns + .filter(v => v.primary) + .map(v => v.tscName); + entity.indices = entity.indices.filter( + v => + v.primary && + v.name !== + namingStrategy.primaryKeyName( + entity.tscName, + primaryColumns + ) ); entity.relations .filter(v => v.joinColumnOptions) diff --git a/src/templates/entity.mst b/src/templates/entity.mst index 1a874c8..6e16182 100644 --- a/src/templates/entity.mst +++ b/src/templates/entity.mst @@ -42,6 +42,6 @@ export class {{toEntityName tscName}}{{#activeRecord}} extends BaseEntity{{/acti } {{/inline}} import {BaseEntity,Column,Entity,Index,JoinColumn,JoinTable,ManyToMany,ManyToOne,OneToMany,OneToOne,PrimaryColumn,PrimaryGeneratedColumn,RelationId} from "typeorm"; -{{#fileImports}}{{> Import}}{{/fileImports~}} +{{#fileImports}}{{> Import}}{{/fileImports}} -{{~> Entity}} +{{> Entity}} From 314c0675f119b16f27584ee6e53f81a5eb9910d0 Mon Sep 17 00:00:00 2001 From: Kononnable Date: Sun, 10 Nov 2019 18:48:38 +0100 Subject: [PATCH 48/84] fix removal of unused typeorm imports --- src/ModelGeneration.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ModelGeneration.ts b/src/ModelGeneration.ts index 143fd30..fe27e46 100644 --- a/src/ModelGeneration.ts +++ b/src/ModelGeneration.ts @@ -73,7 +73,7 @@ function removeUnusedImports(rendered: string) { .split(","); const restOfEntityDefinition = rendered.substring(closeBracketIndex); const distinctImports = imports.filter( - v => restOfEntityDefinition.indexOf(v) !== -1 + v => restOfEntityDefinition.indexOf(`@${v}(`) !== -1 ); return `${rendered.substring(0, openBracketIndex)}${distinctImports.join( "," From a5f2a403eb476f0fc1ab9ec9c3f231c2c7803006 Mon Sep 17 00:00:00 2001 From: Kononnable Date: Sun, 10 Nov 2019 19:03:50 +0100 Subject: [PATCH 49/84] mssql no longer is default sql engine --- src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/index.ts b/src/index.ts index ba03a04..94764f2 100644 --- a/src/index.ts +++ b/src/index.ts @@ -92,7 +92,7 @@ function GetUtilParametersByArgs() { "oracle", "sqlite" ], - default: "mssql", + demand: true, describe: "Database engine" }, o: { From 0bc4d74f44b6bfafb8f565e600485041e797df4e Mon Sep 17 00:00:00 2001 From: Kononnable Date: Sun, 10 Nov 2019 19:48:13 +0100 Subject: [PATCH 50/84] fixbroken tests --- src/ModelCustomization.ts | 20 ++++++++++++-------- src/ModelGeneration.ts | 4 +++- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/ModelCustomization.ts b/src/ModelCustomization.ts index 5ec3937..0041e10 100644 --- a/src/ModelCustomization.ts +++ b/src/ModelCustomization.ts @@ -35,20 +35,24 @@ function removeIndicesGeneratedByTypeorm(dbModel: Entity[]): Entity[] { dbModel.forEach(entity => { entity.indices = entity.indices.filter( v => - !v.name.startsWith(`sqlite_autoindex_`) && - (v.name !== "PRIMARY" && v.primary) + !( + v.name.startsWith(`sqlite_autoindex_`) || + (v.primary && v.name === "PRIMARY") + ) ); const primaryColumns = entity.columns .filter(v => v.primary) .map(v => v.tscName); entity.indices = entity.indices.filter( v => - v.primary && - v.name !== - namingStrategy.primaryKeyName( - entity.tscName, - primaryColumns - ) + !( + v.primary && + v.name !== + namingStrategy.primaryKeyName( + entity.tscName, + primaryColumns + ) + ) ); entity.relations .filter(v => v.joinColumnOptions) diff --git a/src/ModelGeneration.ts b/src/ModelGeneration.ts index fe27e46..e50ebc4 100644 --- a/src/ModelGeneration.ts +++ b/src/ModelGeneration.ts @@ -73,7 +73,9 @@ function removeUnusedImports(rendered: string) { .split(","); const restOfEntityDefinition = rendered.substring(closeBracketIndex); const distinctImports = imports.filter( - v => restOfEntityDefinition.indexOf(`@${v}(`) !== -1 + v => + restOfEntityDefinition.indexOf(`@${v}(`) !== -1 || + (v === "BaseEntity" && restOfEntityDefinition.indexOf(v) !== -1) ); return `${rendered.substring(0, openBracketIndex)}${distinctImports.join( "," From 61c98f7592c9061eaf1af50b4690f318b939f4e3 Mon Sep 17 00:00:00 2001 From: Kononnable Date: Sun, 10 Nov 2019 23:57:04 +0100 Subject: [PATCH 51/84] tests: compare join column options --- .../github-issues/71/entity/PostAuthor.ts | 2 +- .../github-issues/71/entity/PostDetails.ts | 2 +- test/utils/EntityFileToJson.ts | 23 +++++++++++++++++-- 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/test/integration/github-issues/71/entity/PostAuthor.ts b/test/integration/github-issues/71/entity/PostAuthor.ts index b9b01df..b09cd20 100644 --- a/test/integration/github-issues/71/entity/PostAuthor.ts +++ b/test/integration/github-issues/71/entity/PostAuthor.ts @@ -22,7 +22,7 @@ export class PostAuthor { id: number; @OneToOne(type => Post, Post => Post.id, { - onDelete: "CASCADE" + // onDelete: "CASCADE" // onUpdate: "CASCADE" }) @JoinColumn() diff --git a/test/integration/github-issues/71/entity/PostDetails.ts b/test/integration/github-issues/71/entity/PostDetails.ts index 3feb93f..fb4f959 100644 --- a/test/integration/github-issues/71/entity/PostDetails.ts +++ b/test/integration/github-issues/71/entity/PostDetails.ts @@ -22,7 +22,7 @@ export class PostDetails { id: number; @OneToOne(type => Post, Post => Post.id, { - onDelete: "SET NULL" + // onDelete: "SET NULL" // onUpdate: "SET NULL" }) @JoinColumn() diff --git a/test/utils/EntityFileToJson.ts b/test/utils/EntityFileToJson.ts index b9ea9b8..73cd595 100644 --- a/test/utils/EntityFileToJson.ts +++ b/test/utils/EntityFileToJson.ts @@ -15,6 +15,8 @@ class EntityColumn { public columnOptions: { [key: string]: string | boolean } = {}; + public joinOptions: { [key: string]: string | boolean }[] = []; + public relationType: "OneToOne" | "OneToMany" | "ManyToOne" | "ManyToMany"; public isOwnerOfRelation = false; @@ -100,8 +102,8 @@ export default class EntityFileToJson { } else { let badJSON = !primaryGeneratedColumn ? decoratorParameters.substring( - decoratorParameters.indexOf(",") + 1 - ) + decoratorParameters.indexOf(",") + 1 + ) : decoratorParameters; badJSON = badJSON.trim(); if (badJSON.lastIndexOf(",") === badJSON.length - 3) { @@ -400,6 +402,23 @@ export default class EntityFileToJson { retVal.columns[ retVal.columns.length - 1 ].isOwnerOfRelation = true; + const decoratorParameters = trimmedLine + .substring( + trimmedLine.indexOf("(") + 1, + trimmedLine.indexOf(")") + ) + .trim() + .replace(/(['"])?([a-z0-9A-Z_]+)(['"])?:/g, '"$2": '); + if (decoratorParameters.length > 0) { + const column = + retVal.columns[retVal.columns.length - 1]; + const options = JSON.parse(decoratorParameters); + if (Array.isArray(options)) { + column.joinOptions = options as any; + } else { + column.joinOptions = [options] as any; + } + } } return; } From ecf9f5180604b2efd0564e95a6270185d5537131 Mon Sep 17 00:00:00 2001 From: Kononnable Date: Mon, 11 Nov 2019 01:23:04 +0100 Subject: [PATCH 52/84] tests: compare join table options fix removal of primary key index tests for #183 --- package-lock.json | 63 ++++++++++++++++++ package.json | 2 + src/ModelCustomization.ts | 2 +- .../github-issues/183/entity/Client.ts | 19 ++++++ .../183/entity/ClientCategory.ts | 11 ++++ test/integration/runTestsFromPath.test.ts | 65 ++++++++++++++++--- test/utils/EntityFileToJson.ts | 32 ++++++++- tsconfig.json | 2 +- 8 files changed, 182 insertions(+), 14 deletions(-) create mode 100644 test/integration/github-issues/183/entity/Client.ts create mode 100644 test/integration/github-issues/183/entity/ClientCategory.ts diff --git a/package-lock.json b/package-lock.json index 24cd216..93b6a1c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -209,6 +209,12 @@ "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==", "dev": true }, + "@types/array.prototype.flatmap": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@types/array.prototype.flatmap/-/array.prototype.flatmap-1.2.0.tgz", + "integrity": "sha512-sMRMigmTCA1EVX46F0jPhSFo51uFNo83GkeYlp7r4xKkXwfjkDpTm13vB9Tba4Ey+0rUXX3QjSWHAIwSb3qzrA==", + "dev": true + }, "@types/chai": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.2.3.tgz", @@ -706,6 +712,37 @@ "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", "dev": true }, + "array.prototype.flatmap": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.2.2.tgz", + "integrity": "sha512-ZZtPLE74KNE+0XcPv/vQmcivxN+8FhwOLvt2udHauO0aDEpsXDQrmd5HuJGpgPVyaV8HvkDPWnJ2iaem0oCKtA==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.15.0", + "function-bind": "^1.1.1" + }, + "dependencies": { + "es-abstract": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.16.0.tgz", + "integrity": "sha512-xdQnfykZ9JMEiasTAJZJdMWCQ1Vm00NBw79/AWi7ELfZuuPCSOMDZbT9mkOfSctVtfhb+sAAzrm+j//GjjLHLg==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.0", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.0", + "is-callable": "^1.1.4", + "is-regex": "^1.0.4", + "object-inspect": "^1.6.0", + "object-keys": "^1.1.1", + "string.prototype.trimleft": "^2.1.0", + "string.prototype.trimright": "^2.1.0" + } + } + } + }, "asn1": { "version": "0.2.4", "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", @@ -4092,6 +4129,12 @@ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" }, + "object-inspect": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.6.0.tgz", + "integrity": "sha512-GJzfBZ6DgDAmnuaM3104jR4s1Myxr3Y3zfIyN4z3UdqN69oSRacNK8UhnobDdC+7J2AHCjGwxQubNJfE70SXXQ==", + "dev": true + }, "object-keys": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", @@ -5043,6 +5086,26 @@ } } }, + "string.prototype.trimleft": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.0.tgz", + "integrity": "sha512-FJ6b7EgdKxxbDxc79cOlok6Afd++TTs5szo+zJTUyow3ycrRfJVE2pq3vcN53XexvKZu/DJMDfeI/qMiZTrjTw==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "function-bind": "^1.1.1" + } + }, + "string.prototype.trimright": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.0.tgz", + "integrity": "sha512-fXZTSV55dNBwv16uw+hh5jkghxSnc5oHq+5K/gXgizHwAvMetdAJlHqqoFC1FSDVPYWLkAKl2cxpUT41sV7nSg==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "function-bind": "^1.1.1" + } + }, "string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", diff --git a/package.json b/package.json index f10558a..1eb1a81 100644 --- a/package.json +++ b/package.json @@ -41,6 +41,7 @@ "yn": "^3.1.1" }, "devDependencies": { + "@types/array.prototype.flatmap": "^1.2.0", "@types/chai": "^4.2.3", "@types/chai-as-promised": "^7.1.2", "@types/chai-subset": "^1.3.3", @@ -61,6 +62,7 @@ "@typescript-eslint/eslint-plugin": "^2.3.3", "@typescript-eslint/parser": "^2.3.3", "@typescript-eslint/typescript-estree": "^2.3.3", + "array.prototype.flatmap": "^1.2.2", "chai": "^4.2.0", "chai-as-promised": "^7.1.1", "chai-subset": "^1.6.0", diff --git a/src/ModelCustomization.ts b/src/ModelCustomization.ts index 0041e10..d718222 100644 --- a/src/ModelCustomization.ts +++ b/src/ModelCustomization.ts @@ -47,7 +47,7 @@ function removeIndicesGeneratedByTypeorm(dbModel: Entity[]): Entity[] { v => !( v.primary && - v.name !== + v.name === namingStrategy.primaryKeyName( entity.tscName, primaryColumns diff --git a/test/integration/github-issues/183/entity/Client.ts b/test/integration/github-issues/183/entity/Client.ts new file mode 100644 index 0000000..e8b856d --- /dev/null +++ b/test/integration/github-issues/183/entity/Client.ts @@ -0,0 +1,19 @@ +import { PrimaryGeneratedColumn, Entity, ManyToMany, JoinTable } from "typeorm"; +import { ClientCategory } from "./ClientCategory"; + +@Entity("Client") +export class Client { + @PrimaryGeneratedColumn() + id: number; + + @ManyToMany( + () => ClientCategory, + (clientCategory: ClientCategory) => clientCategory.clients + ) + @JoinTable({ + name: "client_categories", + joinColumn: { name: "client_id" }, + inverseJoinColumn: { name: "category_id" } + }) + clientCategories: ClientCategory[]; +} diff --git a/test/integration/github-issues/183/entity/ClientCategory.ts b/test/integration/github-issues/183/entity/ClientCategory.ts new file mode 100644 index 0000000..b7aae65 --- /dev/null +++ b/test/integration/github-issues/183/entity/ClientCategory.ts @@ -0,0 +1,11 @@ +import { Entity, PrimaryGeneratedColumn, ManyToMany } from "typeorm"; +import { Client } from "./Client"; + +@Entity("ClientCategory") +export class ClientCategory { + @PrimaryGeneratedColumn() + id: number; + + @ManyToMany(() => Client, (client: Client) => client.clientCategories) + clients: Client[]; +} diff --git a/test/integration/runTestsFromPath.test.ts b/test/integration/runTestsFromPath.test.ts index 32c143d..71e4d3d 100644 --- a/test/integration/runTestsFromPath.test.ts +++ b/test/integration/runTestsFromPath.test.ts @@ -4,6 +4,7 @@ import * as ts from "typescript"; import * as fs from "fs-extra"; import * as path from "path"; import * as chaiSubset from "chai-subset"; +import * as flatMap from "array.prototype.flatmap"; import yn from "yn"; import EntityFileToJson from "../utils/EntityFileToJson"; import { createDriver, dataCollectionPhase } from "../../src/Engine"; @@ -15,6 +16,7 @@ import modelGenerationPhase from "../../src/ModelGeneration"; require("dotenv").config(); +flatMap.shim(); chai.use(chaiSubset); const { expect } = chai; @@ -186,17 +188,62 @@ function compareGeneratedFiles(filesOrgPathTS: string, filesGenPath: string) { expect(filesOrg, "Errors detected in model comparison").to.be.deep.equal( filesGen ); - filesOrg.forEach(file => { - const jsonEntityGen = EntityFileToJson.convert( + const generatedEntities = filesOrg.map(file => + EntityFileToJson.convert( fs.readFileSync(path.resolve(filesGenPath, file)) - ); - const jsonEntityOrg = EntityFileToJson.convert( + ) + ); + const originalEntities = filesGen.map(file => + EntityFileToJson.convert( fs.readFileSync(path.resolve(filesOrgPathTS, file)) - ); - expect(jsonEntityGen, `Error in file ${file}`).to.containSubset( - jsonEntityOrg - ); - }); + ) + ); + generatedEntities + .flatMap(entity => + entity.columns + .filter( + column => + column.relationType === "ManyToMany" && + column.joinOptions.length > 0 + ) + .map(v => { + return { + ownerColumn: v, + ownerEntity: entity + }; + }) + ) + + .forEach(({ ownerColumn, ownerEntity }) => { + const childColumn = generatedEntities + .find( + childEntity => + childEntity.entityName.toLowerCase() === + ownerColumn.columnTypes[0] + .substring(0, ownerColumn.columnTypes[0].length - 2) + .toLowerCase() + )! + .columns.find( + column => + column.columnTypes[0].toLowerCase() === + `${ownerEntity.entityName}[]`.toLowerCase() + )!; + childColumn.joinOptions = ownerColumn.joinOptions.map(options => { + return { + ...options, + joinColumns: options.inverseJoinColumns, + inverseJoinColumns: options.joinColumns + }; + }); + }); + // TODO: set relation options on ManyToMany to both side of relation + generatedEntities + .map((ent, i) => [ent, originalEntities[i], filesOrg[i]]) + .forEach(([generated, original, file]) => { + expect(generated, `Error in file ${file}`).to.containSubset( + original + ); + }); } // TODO: Move(?) diff --git a/test/utils/EntityFileToJson.ts b/test/utils/EntityFileToJson.ts index 73cd595..443aef1 100644 --- a/test/utils/EntityFileToJson.ts +++ b/test/utils/EntityFileToJson.ts @@ -398,7 +398,6 @@ export default class EntityFileToJson { priorPartOfMultilineStatement = trimmedLine; } else { isMultilineStatement = false; - // TODO: get joinColumnOptions options retVal.columns[ retVal.columns.length - 1 ].isOwnerOfRelation = true; @@ -428,8 +427,35 @@ export default class EntityFileToJson { priorPartOfMultilineStatement = trimmedLine; } else { isMultilineStatement = false; - // TODO: get joinTableOptions options - is it possible while JoinTable can be on either side of the relationship? - // it doesn't matter which side of ManyToMany relation is marked as owner + const decoratorParameters = trimmedLine + .substring( + trimmedLine.indexOf("(") + 1, + trimmedLine.indexOf(")") + ) + .trim() + .replace(/(['"])?([a-z0-9A-Z_]+)(['"])?:/g, '"$2": '); + if (decoratorParameters.length > 0) { + const column = + retVal.columns[retVal.columns.length - 1]; + const options = JSON.parse(decoratorParameters); + if ( + options.inverseJoinColumn && + !Array.isArray(options.inverseJoinColumn) + ) { + options.inverseJoinColumns = [ + options.inverseJoinColumn + ]; + delete options.inverseJoinColumn; + } + if ( + options.joinColumn && + !Array.isArray(options.joinColumn) + ) { + options.joinColumns = [options.joinColumn]; + delete options.joinColumn; + } + column.joinOptions = [options]; + } } return; } diff --git a/tsconfig.json b/tsconfig.json index 1a824ca..5d766ab 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -15,7 +15,7 @@ "newLine": "LF", "outDir": "dist", "lib": [ - "es2017" + "es2019","es2019.array" ], "resolveJsonModule": true, }, From 35987a98f92093bd3cf89855fdd44fee29e107f8 Mon Sep 17 00:00:00 2001 From: Vasil Rangelov Date: Mon, 11 Nov 2019 18:17:47 +0200 Subject: [PATCH 53/84] Added typeRoot to tsconfig.json to ensure successful compilation when running as a dependency. --- tsconfig.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tsconfig.json b/tsconfig.json index 5d766ab..93cff05 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -17,6 +17,9 @@ "lib": [ "es2019","es2019.array" ], + "typeRoots": [ + "./node_modules/@types" + ], "resolveJsonModule": true, }, "include": [ From 2ae07a7dbed7b31c36d8a2ad538d4e0bdb5abf6a Mon Sep 17 00:00:00 2001 From: Vasil Rangelov Date: Mon, 11 Nov 2019 19:21:42 +0200 Subject: [PATCH 54/84] Added explicit copy of package.json into dist/package.json. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1eb1a81..d9fa91b 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "bin": "bin/typeorm-model-generator", "scripts": { "start": "ts-node ./src/index.ts", - "build": "npm run clean && tsc && ncp src/templates/ dist/src/templates/", + "build": "npm run clean && tsc && ncp src/templates/ dist/src/templates/ && ncp package.json dist/package.json", "prepare": "npm run build", "pretest": "tsc --noEmit", "test": "nyc --reporter=lcov ts-node ./node_modules/mocha/bin/_mocha test/**/*.test.ts -- --bail", From 91f9f11b44a43ae29deb194a459b71a93fcadf37 Mon Sep 17 00:00:00 2001 From: Vasil Rangelov Date: Tue, 12 Nov 2019 11:04:59 +0200 Subject: [PATCH 55/84] Moved the import fetching to occur after the naming strategy is applied, to ensure correct imports. --- src/ModelCustomization.ts | 13 +++++++++++++ src/drivers/AbstractDriver.ts | 14 -------------- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/ModelCustomization.ts b/src/ModelCustomization.ts index d718222..7fa0516 100644 --- a/src/ModelCustomization.ts +++ b/src/ModelCustomization.ts @@ -128,10 +128,23 @@ function removeColumnDefaultProperties( }); return dbModel; } + +function findFileImports(dbModel: Entity[]) { + dbModel.forEach(entity => { + entity.relations.forEach(relation => { + if (!entity.fileImports.some(v => v === relation.relatedTable)) { + entity.fileImports.push(relation.relatedTable); + } + }); + }); + return dbModel; +} + function addImportsAndGenerationOptions( dbModel: Entity[], generationOptions: IGenerationOptions ): Entity[] { + dbModel = findFileImports(dbModel); dbModel.forEach(entity => { entity.relations.forEach(relation => { if (generationOptions.lazy) { diff --git a/src/drivers/AbstractDriver.ts b/src/drivers/AbstractDriver.ts index 2b0072a..bb6ee21 100644 --- a/src/drivers/AbstractDriver.ts +++ b/src/drivers/AbstractDriver.ts @@ -207,20 +207,6 @@ export default abstract class AbstractDriver { ); await this.DisconnectFromServer(); dbModel = AbstractDriver.FindManyToManyRelations(dbModel); - dbModel = AbstractDriver.FindFileImports(dbModel); - return dbModel; - } - - private static FindFileImports(dbModel: Entity[]) { - dbModel.forEach(entity => { - entity.relations.forEach(relation => { - if ( - !entity.fileImports.some(v => v === relation.relatedTable) - ) { - entity.fileImports.push(relation.relatedTable); - } - }); - }); return dbModel; } From bcb2d8700cc95279ea479dad079af6380c332c81 Mon Sep 17 00:00:00 2001 From: Vasil Rangelov Date: Tue, 12 Nov 2019 11:32:55 +0200 Subject: [PATCH 56/84] Fixed imports for relations to the same table. --- src/ModelCustomization.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/ModelCustomization.ts b/src/ModelCustomization.ts index 7fa0516..c2f9bfe 100644 --- a/src/ModelCustomization.ts +++ b/src/ModelCustomization.ts @@ -132,7 +132,10 @@ function removeColumnDefaultProperties( function findFileImports(dbModel: Entity[]) { dbModel.forEach(entity => { entity.relations.forEach(relation => { - if (!entity.fileImports.some(v => v === relation.relatedTable)) { + if ( + relation.relatedTable !== entity.tscName && + !entity.fileImports.some(v => v === relation.relatedTable) + ) { entity.fileImports.push(relation.relatedTable); } }); From 3bbabd127bb1a02a558a2e60470e3d8712cef3b5 Mon Sep 17 00:00:00 2001 From: Vasil Rangelov Date: Thu, 14 Nov 2019 11:46:18 +0200 Subject: [PATCH 57/84] Nullable columns now also add "| null" to the type declaration. Unknown DB types now generate properties with type "NonNullable" that also adds "| null" if the column is nullable. --- src/drivers/AbstractDriver.ts | 12 ++++++++++-- src/drivers/MssqlDriver.ts | 2 +- src/drivers/MysqlDriver.ts | 2 +- src/drivers/OracleDriver.ts | 2 +- src/drivers/PostgresDriver.ts | 37 +++++++++++++---------------------- src/drivers/SqliteDriver.ts | 2 +- src/templates/entity.mst | 2 +- 7 files changed, 29 insertions(+), 30 deletions(-) diff --git a/src/drivers/AbstractDriver.ts b/src/drivers/AbstractDriver.ts index 2b0072a..3002fae 100644 --- a/src/drivers/AbstractDriver.ts +++ b/src/drivers/AbstractDriver.ts @@ -376,11 +376,19 @@ export default abstract class AbstractDriver { ownerColumns[0].tscName, ownerEntity ); + let relationIdType = ownerColumns[0].tscType; + if (ownerColumns[0].options.nullable) { + relationIdType += " | null"; + } ownerEntity.relationIds.push({ fieldName: relationIdFieldName, fieldType: isOneToMany - ? `${ownerColumns[0].tscType}[]` - : ownerColumns[0].tscType, + ? `${ + relationIdType.includes(" ") + ? `(${relationIdType})` + : relationIdType + }[]` + : relationIdType, relationField: ownerRelation.fieldName }); // TODO: RelationId on ManyToMany diff --git a/src/drivers/MssqlDriver.ts b/src/drivers/MssqlDriver.ts index 92efbc3..94a84a0 100644 --- a/src/drivers/MssqlDriver.ts +++ b/src/drivers/MssqlDriver.ts @@ -90,7 +90,7 @@ WHERE TABLE_TYPE='BASE TABLE' and TABLE_SCHEMA in (${schema}) AND TABLE_CATALOG resp.COLUMN_DEFAULT ); const columnType = resp.DATA_TYPE; - let tscType = ""; + let tscType = "NonNullable"; switch (resp.DATA_TYPE) { case "bigint": tscType = "string"; diff --git a/src/drivers/MysqlDriver.ts b/src/drivers/MysqlDriver.ts index 75aab4a..7964dc3 100644 --- a/src/drivers/MysqlDriver.ts +++ b/src/drivers/MysqlDriver.ts @@ -69,7 +69,7 @@ export default class MysqlDriver extends AbstractDriver { .filter(filterVal => filterVal.TABLE_NAME === ent.tscName) .forEach(resp => { const tscName = resp.COLUMN_NAME; - let tscType = ""; + let tscType = "NonNullable"; const options: Column["options"] = { name: resp.COLUMN_NAME }; diff --git a/src/drivers/OracleDriver.ts b/src/drivers/OracleDriver.ts index 38cf79b..9215935 100644 --- a/src/drivers/OracleDriver.ts +++ b/src/drivers/OracleDriver.ts @@ -87,7 +87,7 @@ export default class OracleDriver extends AbstractDriver { ); const DATA_TYPE = resp.DATA_TYPE.replace(/\([0-9]+\)/g, ""); const columnType = DATA_TYPE.toLowerCase(); - let tscType = ""; + let tscType = "NonNullable"; switch (DATA_TYPE.toLowerCase()) { case "char": tscType = "string"; diff --git a/src/drivers/PostgresDriver.ts b/src/drivers/PostgresDriver.ts index c34402f..ce91556 100644 --- a/src/drivers/PostgresDriver.ts +++ b/src/drivers/PostgresDriver.ts @@ -99,7 +99,7 @@ export default class PostgresDriver extends AbstractDriver { resp.udt_name, resp.enumvalues ); - if (!columnTypes.sqlType || !columnTypes.tsType) { + if (columnTypes.tsType === "NonNullable") { if ( resp.data_type === "USER-DEFINED" || resp.data_type === "ARRAY" @@ -152,16 +152,15 @@ export default class PostgresDriver extends AbstractDriver { ? resp.character_maximum_length : undefined; } - if (columnType && tscType) { - ent.columns.push({ - generated, - type: columnType, - default: defaultValue, - options, - tscName, - tscType - }); - } + + ent.columns.push({ + generated, + type: columnType, + default: defaultValue, + options, + tscName, + tscType + }); }); }); return entities; @@ -173,17 +172,16 @@ export default class PostgresDriver extends AbstractDriver { enumValues: string | null ) { let ret: { - tsType?: Column["tscType"]; - sqlType: string | null; + tsType: Column["tscType"]; + sqlType: string; isArray: boolean; enumValues: string[]; } = { - tsType: undefined, - sqlType: null, + tsType: "NonNullable", + sqlType: dataType, isArray: false, enumValues: [] }; - ret.sqlType = dataType; switch (dataType) { case "int2": ret.tsType = "number"; @@ -389,17 +387,10 @@ export default class PostgresDriver extends AbstractDriver { .join('" | "')}"` as never) as string; ret.sqlType = "enum"; ret.enumValues = enumValues.split(","); - } else { - ret.tsType = undefined; - ret.sqlType = null; } break; } break; - default: - ret.tsType = undefined; - ret.sqlType = null; - break; } return ret; } diff --git a/src/drivers/SqliteDriver.ts b/src/drivers/SqliteDriver.ts index 64ce684..7f8e993 100644 --- a/src/drivers/SqliteDriver.ts +++ b/src/drivers/SqliteDriver.ts @@ -65,7 +65,7 @@ export default class SqliteDriver extends AbstractDriver { }>(`PRAGMA table_info('${ent.tscName}');`); response.forEach(resp => { const tscName = resp.name; - let tscType = ""; + let tscType = "NonNullable"; const options: Column["options"] = { name: resp.name }; if (resp.notnull === 0) options.nullable = true; const isPrimary = resp.pk > 0 ? true : undefined; diff --git a/src/templates/entity.mst b/src/templates/entity.mst index 6e16182..8667a11 100644 --- a/src/templates/entity.mst +++ b/src/templates/entity.mst @@ -6,7 +6,7 @@ import { {{toEntityName .}} } from './{{toFileName .}}' {{/inline}} {{#*inline "Column"}} {{#generated}}@PrimaryGeneratedColumn({ type:"{{type}}", {{/generated}}{{^generated}}@Column("{{type}}",{ {{#primary}}primary:{{primary}},{{/primary}}{{/generated}}{{json options}}{{#default}},default: {{.}},{{/default}} }) -{{printPropertyVisibility}}{{toPropertyName tscName}}{{strictMode}}:{{tscType}}; +{{printPropertyVisibility}}{{toPropertyName tscName}}{{strictMode}}:{{tscType}}{{#if options.nullable}} | null{{/if}}; {{/inline}} {{#*inline "JoinColumnOptions"}} From e15e1940784beeef542f63be25fa3457d286618f Mon Sep 17 00:00:00 2001 From: Kononnable Date: Sat, 16 Nov 2019 21:10:17 +0100 Subject: [PATCH 58/84] change travis config --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index e0392eb..ca336d4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -36,13 +36,13 @@ before_install: - if [ -z "$DOCKER_USERNAME" ]; then export ORACLE_Skip=1; else images=(${images[@]} oracle oracle_client); fi - if [ -n "$DOCKER_USERNAME" ]; then docker-compose up -d ${images[@]}; fi - echo ${images[@]} -- docker-compose pull --parallel --ignore-pull-failures ${images[@]} +- docker-compose pull --ignore-pull-failures ${images[@]} - docker-compose up -d ${images[@]} before_script: - if [ -n "$DOCKER_USERNAME" ]; then mkdir /opt/oracle; npm i oracledb --no-save; docker cp typeorm-mg-oracle-client:/usr/lib/oracle/12.2/client64/lib /opt/oracle/instantclient_12_2; fi - export LD_LIBRARY_PATH=/opt/oracle/instantclient_12_2:$LD_LIBRARY_PATH script: -- travis_retry sh -c 'sleep 60 && npm t -- --colors' +- travis_retry sh -c 'sleep 90 && npm t -- --colors' after_success: - codecov after_failure: From 20f3e24dc89fca0341a294e21c403525bbf0082a Mon Sep 17 00:00:00 2001 From: Kononnable Date: Sun, 17 Nov 2019 15:19:33 +0100 Subject: [PATCH 59/84] naming strategy test --- src/ModelCustomization.ts | 3 +- src/NamingStrategy.ts | 4 ++ .../modelCustomization.test.ts | 46 ++++++++++++++++++- test/modelCustomization/testNamingStrategy.ts | 24 ++++++++++ 4 files changed, 74 insertions(+), 3 deletions(-) create mode 100644 test/modelCustomization/testNamingStrategy.ts diff --git a/src/ModelCustomization.ts b/src/ModelCustomization.ts index c2f9bfe..2ad4f3b 100644 --- a/src/ModelCustomization.ts +++ b/src/ModelCustomization.ts @@ -18,7 +18,8 @@ export default function modelCustomizationPhase( ) { // eslint-disable-next-line global-require, import/no-dynamic-require, @typescript-eslint/no-var-requires const req = require(generationOptions.customNamingStrategyPath); - namingStrategy = new req.NamingStrategy(); + // eslint-disable-next-line new-cap + namingStrategy = new req.default(); } else { namingStrategy = new NamingStrategy(); } diff --git a/src/NamingStrategy.ts b/src/NamingStrategy.ts index 38423a7..6035634 100644 --- a/src/NamingStrategy.ts +++ b/src/NamingStrategy.ts @@ -5,6 +5,10 @@ import { RelationId } from "./models/RelationId"; import changeCase = require("change-case"); +// TODO: Use function instead of class +// TODO: Allow users to change only specific functions instead of all of them(with logging if used standard or user function) +// TODO: Fix naming strategy relative path + /* eslint-disable class-methods-use-this */ export default class NamingStrategy extends AbstractNamingStrategy { public relationIdName(relationId: RelationId, relation: Relation): string { diff --git a/test/modelCustomization/modelCustomization.test.ts b/test/modelCustomization/modelCustomization.test.ts index 5ba0ff1..00d5bbd 100644 --- a/test/modelCustomization/modelCustomization.test.ts +++ b/test/modelCustomization/modelCustomization.test.ts @@ -51,7 +51,7 @@ describe("Model customization phase", async () => { tscName: "PostAuthor", database: "", schema: "public", - fileImports: ["Post"] + fileImports: [] }, { columns: [ @@ -105,7 +105,7 @@ describe("Model customization phase", async () => { tscName: "Post", database: "", schema: "public", - fileImports: ["PostAuthor"] + fileImports: [] } ]; @@ -564,4 +564,46 @@ describe("Model customization phase", async () => { compileGeneratedModel(generationOptions.resultsPath, [""]); }); }); + it("naming strategy", async () => { + const data = generateSampleData(); + const generationOptions = generateGenerationOptions(); + clearGenerationDir(); + + generationOptions.customNamingStrategyPath = + "../test/modelCustomization/testNamingStrategy.ts"; + // TODO: relationId + + const customizedModel = modelCustomizationPhase( + data, + generationOptions, + {} + ); + modelGenerationPhase( + new IConnectionOptions(), + generationOptions, + customizedModel + ); + const filesGenPath = path.resolve(resultsPath, "entities"); + const postContent = fs + .readFileSync(path.resolve(filesGenPath, "Post_B.ts")) + .toString(); + const postAuthorContent = fs + .readFileSync(path.resolve(filesGenPath, "PostAuthor_B.ts")) + .toString(); + expect(postContent).to.have.string(`@Entity("Post"`); + expect(postContent).to.have.string(`class Post_B {`); + expect(postContent).to.have.string(`id_C: number;`); + expect(postContent).to.have.string(`author_A: PostAuthor_B`); + expect(postContent).to.have.string( + `import { PostAuthor_B } from "./PostAuthor_B";` + ); + expect(postAuthorContent).to.have.string(`@Entity("PostAuthor"`); + expect(postAuthorContent).to.have.string(`class PostAuthor_B`); + expect(postAuthorContent).to.have.string(`id_C: number;`); + expect(postAuthorContent).to.have.string( + `import { Post_B } from "./Post_B";` + ); + + compileGeneratedModel(generationOptions.resultsPath, [""]); + }); }); diff --git a/test/modelCustomization/testNamingStrategy.ts b/test/modelCustomization/testNamingStrategy.ts new file mode 100644 index 0000000..970204d --- /dev/null +++ b/test/modelCustomization/testNamingStrategy.ts @@ -0,0 +1,24 @@ +import StandardNamingStrategy from "../../src/NamingStrategy"; +import { RelationId } from "../../src/models/RelationId"; +import { Relation } from "../../src/models/Relation"; + +/* eslint-disable class-methods-use-this */ +export default class NamingStrategy extends StandardNamingStrategy { + public relationIdName(relationId: RelationId, relation: Relation): string { + return `${super.relationIdName(relationId, relation)}`; + } + + public relationName(relation: Relation): string { + return `${super.relationName(relation)}_A`; + } + + public entityName(entityName: string): string { + return `${super.entityName(entityName)}_B`; + } + + public columnName(columnName: string): string { + return `${super.columnName(columnName)}_C`; + } +} + +/* eslint-enable class-methods-use-this */ From 3496c0647b179ea5dae6e9e75e6902fe0af1463e Mon Sep 17 00:00:00 2001 From: Kononnable Date: Sun, 17 Nov 2019 16:43:52 +0100 Subject: [PATCH 60/84] naming strategy use functions instead class --- src/AbstractNamingStrategy.ts | 18 --- src/ModelCustomization.ts | 75 +++++++++-- src/NamingStrategy.ts | 121 +++++++++--------- test/modelCustomization/testNamingStrategy.ts | 36 +++--- 4 files changed, 141 insertions(+), 109 deletions(-) delete mode 100644 src/AbstractNamingStrategy.ts diff --git a/src/AbstractNamingStrategy.ts b/src/AbstractNamingStrategy.ts deleted file mode 100644 index 547367f..0000000 --- a/src/AbstractNamingStrategy.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { Relation } from "./models/Relation"; -import { Entity } from "./models/Entity"; -import { Column } from "./models/Column"; -import { RelationId } from "./models/RelationId"; - -export default abstract class AbstractNamingStrategy { - public abstract relationIdName( - relationId: RelationId, - relation: Relation, - owner: Entity - ): string; - - public abstract relationName(relation: Relation, owner: Entity): string; - - public abstract entityName(entityName: string, entity?: Entity): string; - - public abstract columnName(columnName: string, column?: Column): string; -} diff --git a/src/ModelCustomization.ts b/src/ModelCustomization.ts index 2ad4f3b..4c7dbb2 100644 --- a/src/ModelCustomization.ts +++ b/src/ModelCustomization.ts @@ -2,26 +2,83 @@ import { DataTypeDefaults } from "typeorm/driver/types/DataTypeDefaults"; import { DefaultNamingStrategy } from "typeorm/naming-strategy/DefaultNamingStrategy"; import { Entity } from "./models/Entity"; import IGenerationOptions from "./IGenerationOptions"; -import AbstractNamingStrategy from "./AbstractNamingStrategy"; -import NamingStrategy from "./NamingStrategy"; +import * as NamingStrategy from "./NamingStrategy"; import * as TomgUtils from "./Utils"; +import { Relation } from "./models/Relation"; +import { RelationId } from "./models/RelationId"; +import { Column } from "./models/Column"; + +type NamingStrategy = { + relationIdName: ( + relationId: RelationId, + relation: Relation, + owner: Entity + ) => string; + relationName: (relation: Relation, owner: Entity) => string; + columnName: (columnName: string, column?: Column) => string; + entityName: (entityName: string, entity?: Entity) => string; +}; export default function modelCustomizationPhase( dbModel: Entity[], generationOptions: IGenerationOptions, defaultValues: DataTypeDefaults ): Entity[] { - let namingStrategy: AbstractNamingStrategy; + const namingStrategy: NamingStrategy = { + columnName: NamingStrategy.columnName, + entityName: NamingStrategy.entityName, + relationIdName: NamingStrategy.relationIdName, + relationName: NamingStrategy.relationName + }; if ( generationOptions.customNamingStrategyPath && generationOptions.customNamingStrategyPath !== "" ) { + // TODO: change form of logging // eslint-disable-next-line global-require, import/no-dynamic-require, @typescript-eslint/no-var-requires - const req = require(generationOptions.customNamingStrategyPath); - // eslint-disable-next-line new-cap - namingStrategy = new req.default(); - } else { - namingStrategy = new NamingStrategy(); + const req = require(generationOptions.customNamingStrategyPath) as Partial< + NamingStrategy + >; + if (req.columnName) { + console.log( + `[${new Date().toLocaleTimeString()}] Using custom naming strategy for column names.` + ); + namingStrategy.columnName = req.columnName; + } else { + console.log( + `[${new Date().toLocaleTimeString()}] Using standard naming strategy for column names.` + ); + } + if (req.entityName) { + console.log( + `[${new Date().toLocaleTimeString()}] Using custom naming strategy for entity names.` + ); + namingStrategy.entityName = req.entityName; + } else { + console.log( + `[${new Date().toLocaleTimeString()}] Using standard naming strategy for entity names.` + ); + } + if (req.relationIdName) { + console.log( + `[${new Date().toLocaleTimeString()}] Using custom naming strategy for relationId field names.` + ); + namingStrategy.relationIdName = req.relationIdName; + } else { + console.log( + `[${new Date().toLocaleTimeString()}] Using standard naming strategy for relationId field names.` + ); + } + if (req.relationName) { + console.log( + `[${new Date().toLocaleTimeString()}] Using custom naming strategy for relation field names.` + ); + namingStrategy.relationName = req.relationName; + } else { + console.log( + `[${new Date().toLocaleTimeString()}] Using standard naming strategy for relation field names.` + ); + } } let retVal = removeIndicesGeneratedByTypeorm(dbModel); retVal = removeColumnsInRelation(dbModel); @@ -173,7 +230,7 @@ function addImportsAndGenerationOptions( } function applyNamingStrategy( - namingStrategy: AbstractNamingStrategy, + namingStrategy: NamingStrategy, dbModel: Entity[] ): Entity[] { let retVal = changeRelationNames(dbModel); diff --git a/src/NamingStrategy.ts b/src/NamingStrategy.ts index 6035634..fd077a0 100644 --- a/src/NamingStrategy.ts +++ b/src/NamingStrategy.ts @@ -1,77 +1,72 @@ import { plural } from "pluralize"; -import AbstractNamingStrategy from "./AbstractNamingStrategy"; import { Relation } from "./models/Relation"; import { RelationId } from "./models/RelationId"; import changeCase = require("change-case"); -// TODO: Use function instead of class -// TODO: Allow users to change only specific functions instead of all of them(with logging if used standard or user function) // TODO: Fix naming strategy relative path -/* eslint-disable class-methods-use-this */ -export default class NamingStrategy extends AbstractNamingStrategy { - public relationIdName(relationId: RelationId, relation: Relation): string { - const columnOldName = relationId.fieldName; +export function relationIdName( + relationId: RelationId, + relation: Relation +): string { + const columnOldName = relationId.fieldName; - const isRelationToMany = - relation.relationType === "OneToMany" || - relation.relationType === "ManyToMany"; - let columnName = changeCase.camelCase( - columnOldName.replace(/[0-9]$/, "") - ); + const isRelationToMany = + relation.relationType === "OneToMany" || + relation.relationType === "ManyToMany"; + let newColumnName = changeCase.camelCase( + columnOldName.replace(/[0-9]$/, "") + ); - if (!Number.isNaN(parseInt(columnName[columnName.length - 1], 10))) { - columnName = columnName.substring(0, columnName.length - 1); - } - if (!Number.isNaN(parseInt(columnName[columnName.length - 1], 10))) { - columnName = columnName.substring(0, columnName.length - 1); - } - if (isRelationToMany) { - columnName = plural(columnName); - } - - return columnName; + if (!Number.isNaN(parseInt(newColumnName[newColumnName.length - 1], 10))) { + newColumnName = newColumnName.substring(0, newColumnName.length - 1); + } + if (!Number.isNaN(parseInt(newColumnName[newColumnName.length - 1], 10))) { + newColumnName = newColumnName.substring(0, newColumnName.length - 1); + } + if (isRelationToMany) { + newColumnName = plural(newColumnName); } - public relationName(relation: Relation): string { - const columnOldName = relation.fieldName; - - const isRelationToMany = - relation.relationType === "OneToMany" || - relation.relationType === "ManyToMany"; - let columnName = changeCase.camelCase( - columnOldName.replace(/[0-9]$/, "") - ); - - if ( - columnName.toLowerCase().endsWith("id") && - !columnName.toLowerCase().endsWith("guid") - ) { - columnName = columnName.substring( - 0, - columnName.toLowerCase().lastIndexOf("id") - ); - } - if (!Number.isNaN(parseInt(columnName[columnName.length - 1], 10))) { - columnName = columnName.substring(0, columnName.length - 1); - } - if (!Number.isNaN(parseInt(columnName[columnName.length - 1], 10))) { - columnName = columnName.substring(0, columnName.length - 1); - } - if (isRelationToMany) { - columnName = plural(columnName); - } - return columnName; - } - - public entityName(entityName: string): string { - return entityName; - } - - public columnName(columnName: string): string { - return columnName; - } + return newColumnName; } -/* eslint-enable class-methods-use-this */ +export function relationName(relation: Relation): string { + const columnOldName = relation.fieldName; + + const isRelationToMany = + relation.relationType === "OneToMany" || + relation.relationType === "ManyToMany"; + let newColumnName = changeCase.camelCase( + columnOldName.replace(/[0-9]$/, "") + ); + + if ( + newColumnName.toLowerCase().endsWith("id") && + !newColumnName.toLowerCase().endsWith("guid") + ) { + newColumnName = newColumnName.substring( + 0, + newColumnName.toLowerCase().lastIndexOf("id") + ); + } + if (!Number.isNaN(parseInt(newColumnName[newColumnName.length - 1], 10))) { + newColumnName = newColumnName.substring(0, newColumnName.length - 1); + } + if (!Number.isNaN(parseInt(newColumnName[newColumnName.length - 1], 10))) { + newColumnName = newColumnName.substring(0, newColumnName.length - 1); + } + if (isRelationToMany) { + newColumnName = plural(newColumnName); + } + return newColumnName; +} + +export function entityName(oldEntityName: string): string { + return oldEntityName; +} + +export function columnName(oldColumnName: string): string { + return oldColumnName; +} diff --git a/test/modelCustomization/testNamingStrategy.ts b/test/modelCustomization/testNamingStrategy.ts index 970204d..b3ed507 100644 --- a/test/modelCustomization/testNamingStrategy.ts +++ b/test/modelCustomization/testNamingStrategy.ts @@ -1,24 +1,22 @@ -import StandardNamingStrategy from "../../src/NamingStrategy"; +import * as NamingStrategy from "../../src/NamingStrategy"; import { RelationId } from "../../src/models/RelationId"; import { Relation } from "../../src/models/Relation"; -/* eslint-disable class-methods-use-this */ -export default class NamingStrategy extends StandardNamingStrategy { - public relationIdName(relationId: RelationId, relation: Relation): string { - return `${super.relationIdName(relationId, relation)}`; - } - - public relationName(relation: Relation): string { - return `${super.relationName(relation)}_A`; - } - - public entityName(entityName: string): string { - return `${super.entityName(entityName)}_B`; - } - - public columnName(columnName: string): string { - return `${super.columnName(columnName)}_C`; - } +export function relationIdName( + relationId: RelationId, + relation: Relation +): string { + return `${NamingStrategy.relationIdName(relationId, relation)}`; } -/* eslint-enable class-methods-use-this */ +export function relationName(relation: Relation): string { + return `${NamingStrategy.relationName(relation)}_A`; +} + +export function entityName(oldEntityName: string): string { + return `${NamingStrategy.entityName(oldEntityName)}_B`; +} + +export function columnName(oldColumnName: string): string { + return `${NamingStrategy.columnName(oldColumnName)}_C`; +} From 9e931025b90217a8e449b31686d6485e99fb2863 Mon Sep 17 00:00:00 2001 From: Kononnable Date: Sun, 17 Nov 2019 19:21:54 +0100 Subject: [PATCH 61/84] fix naming strategy with relative path(#171) --- src/ModelCustomization.ts | 7 +++---- src/NamingStrategy.ts | 5 +---- src/Utils.ts | 14 ++++++++++++++ test/modelCustomization/modelCustomization.test.ts | 2 +- 4 files changed, 19 insertions(+), 9 deletions(-) diff --git a/src/ModelCustomization.ts b/src/ModelCustomization.ts index 4c7dbb2..3833d70 100644 --- a/src/ModelCustomization.ts +++ b/src/ModelCustomization.ts @@ -35,10 +35,9 @@ export default function modelCustomizationPhase( generationOptions.customNamingStrategyPath !== "" ) { // TODO: change form of logging - // eslint-disable-next-line global-require, import/no-dynamic-require, @typescript-eslint/no-var-requires - const req = require(generationOptions.customNamingStrategyPath) as Partial< - NamingStrategy - >; + const req = TomgUtils.requireLocalFile( + generationOptions.customNamingStrategyPath + ) as Partial; if (req.columnName) { console.log( `[${new Date().toLocaleTimeString()}] Using custom naming strategy for column names.` diff --git a/src/NamingStrategy.ts b/src/NamingStrategy.ts index fd077a0..8ff4546 100644 --- a/src/NamingStrategy.ts +++ b/src/NamingStrategy.ts @@ -1,11 +1,8 @@ import { plural } from "pluralize"; +import * as changeCase from "change-case"; import { Relation } from "./models/Relation"; import { RelationId } from "./models/RelationId"; -import changeCase = require("change-case"); - -// TODO: Fix naming strategy relative path - export function relationIdName( relationId: RelationId, relation: Relation diff --git a/src/Utils.ts b/src/Utils.ts index af39d98..d121435 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -1,4 +1,5 @@ import * as changeCase from "change-case"; +import * as path from "path"; import * as packagejson from "../package.json"; import { Entity } from "./models/Entity"; @@ -66,3 +67,16 @@ export function findNameForNewField( } return fieldName; } + +export function requireLocalFile(fileName: string): any { + try { + // eslint-disable-next-line global-require, import/no-dynamic-require, @typescript-eslint/no-var-requires + return require(fileName); + } catch (err) { + if (!path.isAbsolute(fileName)) { + // eslint-disable-next-line global-require, import/no-dynamic-require, @typescript-eslint/no-var-requires + return require(path.resolve(process.cwd(), fileName)); + } + throw err; + } +} diff --git a/test/modelCustomization/modelCustomization.test.ts b/test/modelCustomization/modelCustomization.test.ts index 00d5bbd..5ddb827 100644 --- a/test/modelCustomization/modelCustomization.test.ts +++ b/test/modelCustomization/modelCustomization.test.ts @@ -570,7 +570,7 @@ describe("Model customization phase", async () => { clearGenerationDir(); generationOptions.customNamingStrategyPath = - "../test/modelCustomization/testNamingStrategy.ts"; + "test/modelCustomization/testNamingStrategy.ts"; // TODO: relationId const customizedModel = modelCustomizationPhase( From 47b98a8d8ed96d7e9f8625e0a9be471aad8faa4f Mon Sep 17 00:00:00 2001 From: Kononnable Date: Thu, 12 Dec 2019 20:31:38 +0100 Subject: [PATCH 62/84] change passing parameters to CLI --- src/IConnectionOptions.ts | 50 ++- src/IGenerationOptions.ts | 60 +-- src/ModelGeneration.ts | 4 +- src/index.ts | 368 +++++++++++------- .../modelCustomization.test.ts | 46 ++- test/utils/GeneralTestUtils.ts | 4 +- 6 files changed, 321 insertions(+), 211 deletions(-) diff --git a/src/IConnectionOptions.ts b/src/IConnectionOptions.ts index c280478..138c49f 100644 --- a/src/IConnectionOptions.ts +++ b/src/IConnectionOptions.ts @@ -1,19 +1,35 @@ -export default class IConnectionOptions { - public host = ""; +// TODO: change name - public port = 0; - - public databaseName = ""; - - public user = ""; - - public password = ""; - - public databaseType = ""; - - public schemaName = ""; - - public ssl = false; - - public timeout?: number; +// eslint-disable-next-line @typescript-eslint/interface-name-prefix +export default interface IConnectionOptions { + host: string; + port: number; + databaseName: string; + user: string; + password: string; + databaseType: + | "mssql" + | "postgres" + | "mysql" + | "mariadb" + | "oracle" + | "sqlite"; + schemaName: string; + ssl: boolean; + timeout?: number; +} + +export function getDefaultConnectionOptions(): IConnectionOptions { + const connectionOptions: IConnectionOptions = { + host: "127.0.0.1", + port: 0, + databaseName: "", + user: "", + password: "", + databaseType: undefined as any, + schemaName: "", + ssl: false, + timeout: undefined + }; + return connectionOptions; } diff --git a/src/IGenerationOptions.ts b/src/IGenerationOptions.ts index 23180f6..1a1b534 100644 --- a/src/IGenerationOptions.ts +++ b/src/IGenerationOptions.ts @@ -1,28 +1,38 @@ -export default class IGenerationOptions { - public resultsPath = ""; +import path = require("path"); - public noConfigs = false; +// TODO: change name - public convertCaseFile: "pascal" | "param" | "camel" | "none" = "none"; - - public convertCaseEntity: "pascal" | "camel" | "none" = "none"; - - public convertCaseProperty: "pascal" | "camel" | "none" = "none"; - - public propertyVisibility: "public" | "protected" | "private" | "none" = - "none"; - - public lazy = false; - - public activeRecord = false; - - public generateConstructor = false; - - public customNamingStrategyPath = ""; - - public relationIds = false; - - public strictMode: false | "?" | "!" = false; - - public skipSchema = false; +// eslint-disable-next-line @typescript-eslint/interface-name-prefix +export default interface IGenerationOptions { + resultsPath: string; + noConfigs: boolean; + convertCaseFile: "pascal" | "param" | "camel" | "none"; + convertCaseEntity: "pascal" | "camel" | "none"; + convertCaseProperty: "pascal" | "camel" | "none"; + propertyVisibility: "public" | "protected" | "private" | "none"; + lazy: boolean; + activeRecord: boolean; + generateConstructor: boolean; + customNamingStrategyPath: string; + relationIds: boolean; + strictMode: "none" | "?" | "!"; + skipSchema: boolean; +} +export function getDefaultGenerationOptions(): IGenerationOptions { + const generationOptions: IGenerationOptions = { + resultsPath: path.resolve(process.cwd(), "output"), + noConfigs: false, + convertCaseFile: "pascal", + convertCaseEntity: "pascal", + convertCaseProperty: "camel", + propertyVisibility: "none", + lazy: false, + activeRecord: false, + generateConstructor: false, + customNamingStrategyPath: "", + relationIds: false, + strictMode: "none", + skipSchema: false + }; + return generationOptions; } diff --git a/src/ModelGeneration.ts b/src/ModelGeneration.ts index e50ebc4..dfc8e1f 100644 --- a/src/ModelGeneration.ts +++ b/src/ModelGeneration.ts @@ -161,7 +161,9 @@ function createHandlebarsHelpers(generationOptions: IGenerationOptions): void { } ); Handlebars.registerHelper("strictMode", () => - generationOptions.strictMode ? generationOptions.strictMode : "" + generationOptions.strictMode !== "none" + ? generationOptions.strictMode + : "" ); Handlebars.registerHelper({ and: (v1, v2) => v1 && v2, diff --git a/src/index.ts b/src/index.ts index 339dcf4..9880043 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,9 +1,12 @@ import * as Yargs from "yargs"; import { createDriver, createModelFromDatabase } from "./Engine"; import * as TomgUtils from "./Utils"; -import AbstractDriver from "./drivers/AbstractDriver"; -import IConnectionOptions from "./IConnectionOptions"; -import IGenerationOptions from "./IGenerationOptions"; +import IConnectionOptions, { + getDefaultConnectionOptions +} from "./IConnectionOptions"; +import IGenerationOptions, { + getDefaultGenerationOptions +} from "./IGenerationOptions"; import fs = require("fs-extra"); import inquirer = require("inquirer"); @@ -12,74 +15,136 @@ import path = require("path"); // eslint-disable-next-line @typescript-eslint/no-floating-promises CliLogic(); +type options = { + connectionOptions: IConnectionOptions; + generationOptions: IGenerationOptions; +}; + async function CliLogic() { console.log(TomgUtils.packageVersion()); - let driver: AbstractDriver; - let connectionOptions: IConnectionOptions; - let generationOptions: IGenerationOptions; + let options = makeDefaultConfigs(); + const TOMLConfig = readTOMLConfig(options); + options = TOMLConfig.options; if (process.argv.length > 2) { - const retVal = GetUtilParametersByArgs(); - connectionOptions = retVal.connectionOptions; - generationOptions = retVal.generationOptions; - driver = retVal.driver; - } else if (fs.existsSync(path.resolve(process.cwd(), ".tomg-config"))) { - console.log( - `[${new Date().toLocaleTimeString()}] Using configuration file. [${path.resolve( - process.cwd(), - ".tomg-config" - )}]` - ); - const retVal = await fs.readJson( - path.resolve(process.cwd(), ".tomg-config") - ); - [connectionOptions, generationOptions] = retVal; - driver = createDriver(connectionOptions.databaseType); - } else { - const retVal = await GetUtilParametersByInquirer(); - driver = retVal.driver; - connectionOptions = retVal.connectionOptions; - generationOptions = retVal.generationOptions; + options = checkYargsParameters(options); + } else if (!TOMLConfig.fullConfigFile) { + options = await useInquirer(options); } + const driver = createDriver(options.connectionOptions.databaseType); console.log( `[${new Date().toLocaleTimeString()}] Starting creation of model classes.` ); - await createModelFromDatabase(driver, connectionOptions, generationOptions); + await createModelFromDatabase( + driver, + options.connectionOptions, + options.generationOptions + ); console.info( `[${new Date().toLocaleTimeString()}] Typeorm model classes created.` ); -} -function GetUtilParametersByArgs() { + // TODO: parameter for generating config file from passed arguments(yargs+inquirer)? + // TODO: inquirer - option to save config without connection options(only for security) +} +function makeDefaultConfigs() { + const generationOptions = getDefaultGenerationOptions(); + const connectionOptions = getDefaultConnectionOptions(); + return { + generationOptions, + connectionOptions + }; +} +function readTOMLConfig( + options: options +): { options; fullConfigFile: boolean } { + if (!fs.existsSync(path.resolve(process.cwd(), ".tomg-config"))) { + return { options, fullConfigFile: false }; + } + console.log( + `[${new Date().toLocaleTimeString()}] Using configuration file. [${path.resolve( + process.cwd(), + ".tomg-config" + )}]` + ); + const retVal = fs.readJsonSync(path.resolve(process.cwd(), ".tomg-config")); + const [loadedGenerationOptions, loadedConnectionOptions] = retVal; + + let hasUnknownProperties = false; + Object.keys(loadedConnectionOptions).forEach(key => { + if ( + Object.prototype.hasOwnProperty.call(options.connectionOptions, key) + ) { + options.connectionOptions[key] = loadedConnectionOptions[key]; + } else { + console.error(`Unknown connection option ${key}.`); + hasUnknownProperties = true; + } + }); + Object.keys(loadedGenerationOptions).forEach(key => { + if ( + Object.prototype.hasOwnProperty.call(options.generationOptions, key) + ) { + options.generationOptions[key] = loadedGenerationOptions[key]; + } else { + console.error(`Unknown generation option ${key}.`); + hasUnknownProperties = true; + } + }); + if ( + !Object.prototype.hasOwnProperty.call( + loadedConnectionOptions, + "timeout" + ) + ) { + loadedConnectionOptions.timeout = undefined; + } + + const fullConfigFile = + !hasUnknownProperties && + Object.keys(loadedConnectionOptions).length === + Object.keys(options.connectionOptions).length && + Object.keys(loadedGenerationOptions).length === + Object.keys(options.generationOptions).length; + + return { + options, + fullConfigFile + }; +} +function checkYargsParameters(options: options): options { const { argv } = Yargs.usage( "Usage: typeorm-model-generator -h -d -p [port] -u -x [password] -e [engine]\nYou can also run program without specifying any parameters." ).options({ h: { alias: "host", string: true, - default: "127.0.0.1", + default: options.connectionOptions.host, describe: "IP address/Hostname for database server" }, d: { alias: "database", string: true, demand: true, + default: options.connectionOptions.databaseName, describe: "Database name(or path for sqlite). You can pass multiple values separated by comma." }, u: { alias: "user", string: true, + default: options.connectionOptions.user, describe: "Username for database server" }, x: { alias: "pass", string: true, - default: "", + default: options.connectionOptions.password, describe: "Password for database server" }, p: { number: true, alias: "port", + default: options.connectionOptions.port, describe: "Port number for database server" }, e: { @@ -93,138 +158,133 @@ function GetUtilParametersByArgs() { "sqlite" ], demand: true, + default: options.connectionOptions.databaseType, describe: "Database engine" }, o: { alias: "output", - default: path.resolve(process.cwd(), "output"), + default: options.generationOptions.resultsPath, describe: "Where to place generated models" }, s: { alias: "schema", string: true, + default: options.connectionOptions.schemaName, describe: "Schema name to create model from. Only for mssql and postgres. You can pass multiple values separated by comma eg. -s scheme1,scheme2,scheme3" }, ssl: { boolean: true, - default: false + default: options.connectionOptions.ssl }, noConfig: { boolean: true, - default: false, + default: options.generationOptions.noConfigs, describe: `Doesn't create tsconfig.json and ormconfig.json` }, cf: { alias: "case-file", choices: ["pascal", "param", "camel", "none"], - default: "pascal", + default: options.generationOptions.convertCaseFile, describe: "Convert file names to specified case" }, ce: { alias: "case-entity", choices: ["pascal", "camel", "none"], - default: "pascal", + default: options.generationOptions.convertCaseEntity, describe: "Convert class names to specified case" }, cp: { alias: "case-property", choices: ["pascal", "camel", "none"], - default: "camel", + default: options.generationOptions.convertCaseProperty, describe: "Convert property names to specified case" }, pv: { alias: "property-visibility", choices: ["public", "protected", "private", "none"], - default: "none", + default: options.generationOptions.propertyVisibility, describe: "Defines which visibility should have the generated property" }, lazy: { boolean: true, - default: false, + default: options.generationOptions.lazy, describe: "Generate lazy relations" }, a: { alias: "active-record", boolean: true, - default: false, + default: options.generationOptions.activeRecord, describe: "Use ActiveRecord syntax for generated models" }, namingStrategy: { describe: "Use custom naming strategy", + default: options.generationOptions.customNamingStrategyPath, string: true }, relationIds: { boolean: true, - default: false, + default: options.generationOptions.relationIds, describe: "Generate RelationId fields" }, skipSchema: { boolean: true, - default: false, + default: options.generationOptions.skipSchema, describe: "Omits schema identifier in generated entities" }, generateConstructor: { boolean: true, - default: false, + default: options.generationOptions.generateConstructor, describe: "Generate constructor allowing partial initialization" }, strictMode: { choices: ["none", "?", "!"], - default: "none", + default: options.generationOptions.strictMode, describe: "Mark fields as optional(?) or non-null(!)" }, timeout: { describe: "SQL Query timeout(ms)", + default: options.connectionOptions.timeout, number: true } }); - const driver = createDriver(argv.e); - const { standardPort, standardSchema, standardUser } = driver; - let namingStrategyPath: string; - if (argv.namingStrategy && argv.namingStrategy !== "") { - namingStrategyPath = argv.namingStrategy; - } else { - namingStrategyPath = ""; - } - const connectionOptions: IConnectionOptions = new IConnectionOptions(); - connectionOptions.databaseName = argv.d; - connectionOptions.databaseType = argv.e; - connectionOptions.host = argv.h; - connectionOptions.password = argv.x; - connectionOptions.port = argv.p || standardPort; - connectionOptions.schemaName = argv.s ? argv.s.toString() : standardSchema; - connectionOptions.ssl = argv.ssl; - connectionOptions.timeout = argv.timeout; - connectionOptions.user = argv.u ? argv.u.toString() : standardUser; - const generationOptions: IGenerationOptions = new IGenerationOptions(); - generationOptions.activeRecord = argv.a; - generationOptions.generateConstructor = argv.generateConstructor; - generationOptions.convertCaseEntity = argv.ce as IGenerationOptions["convertCaseEntity"]; - generationOptions.convertCaseFile = argv.cf as IGenerationOptions["convertCaseFile"]; - generationOptions.convertCaseProperty = argv.cp as IGenerationOptions["convertCaseProperty"]; - generationOptions.lazy = argv.lazy; - generationOptions.customNamingStrategyPath = namingStrategyPath; - generationOptions.noConfigs = argv.noConfig; - generationOptions.propertyVisibility = argv.pv as IGenerationOptions["propertyVisibility"]; - generationOptions.relationIds = argv.relationIds; - generationOptions.skipSchema = argv.skipSchema; - generationOptions.resultsPath = argv.o; - generationOptions.strictMode = - argv.strictMode === "none" - ? false - : (argv.strictMode as IGenerationOptions["strictMode"]); + options.connectionOptions.databaseName = argv.d; + options.connectionOptions.databaseType = argv.e; - return { driver, connectionOptions, generationOptions }; + const driver = createDriver(options.connectionOptions.databaseType); + const { standardPort, standardSchema, standardUser } = driver; + + options.connectionOptions.host = argv.h; + options.connectionOptions.password = argv.x; + options.connectionOptions.port = argv.p || standardPort; + options.connectionOptions.schemaName = argv.s + ? argv.s.toString() + : standardSchema; + options.connectionOptions.ssl = argv.ssl; + options.connectionOptions.timeout = argv.timeout; + options.connectionOptions.user = argv.u || standardUser; + options.generationOptions.activeRecord = argv.a; + options.generationOptions.generateConstructor = argv.generateConstructor; + options.generationOptions.convertCaseEntity = argv.ce as IGenerationOptions["convertCaseEntity"]; + options.generationOptions.convertCaseFile = argv.cf as IGenerationOptions["convertCaseFile"]; + options.generationOptions.convertCaseProperty = argv.cp as IGenerationOptions["convertCaseProperty"]; + options.generationOptions.lazy = argv.lazy; + options.generationOptions.customNamingStrategyPath = argv.namingStrategy; + options.generationOptions.noConfigs = argv.noConfig; + options.generationOptions.propertyVisibility = argv.pv as IGenerationOptions["propertyVisibility"]; + options.generationOptions.relationIds = argv.relationIds; + options.generationOptions.skipSchema = argv.skipSchema; + options.generationOptions.resultsPath = argv.o; + options.generationOptions.strictMode = argv.strictMode as IGenerationOptions["strictMode"]; + + return options; } -async function GetUtilParametersByInquirer() { - const connectionOptions: IConnectionOptions = new IConnectionOptions(); - const generationOptions: IGenerationOptions = new IGenerationOptions(); - - connectionOptions.databaseType = (await inquirer.prompt([ +async function useInquirer(options: options): Promise { + const oldDatabaseType = options.connectionOptions.databaseType; + options.connectionOptions.databaseType = (await inquirer.prompt([ { choices: [ "mssql", @@ -234,16 +294,22 @@ async function GetUtilParametersByInquirer() { "oracle", "sqlite" ], + default: options.connectionOptions.databaseType, message: "Choose database engine", name: "engine", type: "list" } ])).engine; - const driver = createDriver(connectionOptions.databaseType); - if (connectionOptions.databaseType !== "sqlite") { + const driver = createDriver(options.connectionOptions.databaseType); + if (options.connectionOptions.databaseType !== oldDatabaseType) { + options.connectionOptions.port = driver.standardPort; + options.connectionOptions.user = driver.standardUser; + options.connectionOptions.schemaName = driver.standardSchema; + } + if (options.connectionOptions.databaseType !== "sqlite") { const answ = await inquirer.prompt([ { - default: "localhost", + default: options.connectionOptions.host, message: "Database address:", name: "host", type: "input" @@ -252,16 +318,14 @@ async function GetUtilParametersByInquirer() { message: "Database port:", name: "port", type: "input", - default() { - return driver.standardPort; - }, + default: options.connectionOptions.port, validate(value) { const valid = !Number.isNaN(parseInt(value, 10)); return valid || "Please enter a valid port number"; } }, { - default: false, + default: options.connectionOptions.ssl, message: "Use SSL:", name: "ssl", type: "confirm" @@ -270,9 +334,7 @@ async function GetUtilParametersByInquirer() { message: "Database user name:", name: "login", type: "input", - default() { - return driver.standardUser; - } + default: options.connectionOptions.user }, { message: "Database user password:", @@ -280,7 +342,7 @@ async function GetUtilParametersByInquirer() { type: "password" }, { - default: "", + default: options.connectionOptions.databaseName, message: "Database name: (You can pass multiple values separated by comma)", name: "dbName", @@ -288,12 +350,12 @@ async function GetUtilParametersByInquirer() { } ]); if ( - connectionOptions.databaseType === "mssql" || - connectionOptions.databaseType === "postgres" + options.connectionOptions.databaseType === "mssql" || + options.connectionOptions.databaseType === "postgres" ) { - connectionOptions.schemaName = (await inquirer.prompt([ + options.connectionOptions.schemaName = (await inquirer.prompt([ { - default: driver.standardSchema, + default: options.connectionOptions.schemaName, message: "Database schema: (You can pass multiple values separated by comma)", name: "schema", @@ -301,25 +363,25 @@ async function GetUtilParametersByInquirer() { } ])).schema; } - connectionOptions.port = parseInt(answ.port, 10); - connectionOptions.host = answ.host; - connectionOptions.user = answ.login; - connectionOptions.password = answ.password; - connectionOptions.databaseName = answ.dbName; - connectionOptions.ssl = answ.ssl; + options.connectionOptions.port = parseInt(answ.port, 10); + options.connectionOptions.host = answ.host; + options.connectionOptions.user = answ.login; + options.connectionOptions.password = answ.password; + options.connectionOptions.databaseName = answ.dbName; + options.connectionOptions.ssl = answ.ssl; } else { - connectionOptions.databaseName = (await inquirer.prompt([ + options.connectionOptions.databaseName = (await inquirer.prompt([ { - default: "", + default: options.connectionOptions.databaseName, message: "Path to database file:", name: "dbName", type: "input" } ])).dbName; } - generationOptions.resultsPath = (await inquirer.prompt([ + options.generationOptions.resultsPath = (await inquirer.prompt([ { - default: path.resolve(process.cwd(), "output"), + default: options.generationOptions.resultsPath, message: "Path where generated models should be stored:", name: "output", type: "input" @@ -327,8 +389,8 @@ async function GetUtilParametersByInquirer() { ])).output; if ( - connectionOptions.databaseType === "mssql" || - connectionOptions.databaseType === "postgres" + options.connectionOptions.databaseType === "mssql" || + options.connectionOptions.databaseType === "postgres" ) { const { changeRequestTimeout } = await inquirer.prompt([ { @@ -343,12 +405,13 @@ async function GetUtilParametersByInquirer() { message: "Query timeout(ms):", name: "timeout", type: "input", + default: options.connectionOptions.timeout, validate(value) { const valid = !Number.isNaN(parseInt(value, 10)); return valid || "Please enter a valid number"; } }); - connectionOptions.timeout = parseInt(timeout, 10); + options.connectionOptions.timeout = parseInt(timeout, 10); } } const { customizeGeneration } = await inquirer.prompt([ @@ -364,13 +427,14 @@ async function GetUtilParametersByInquirer() { { choices: [ { - checked: true, + checked: !options.generationOptions.noConfigs, name: "Generate config files", value: "config" }, { name: "Generate lazy relations", - value: "lazy" + value: "lazy", + checked: options.generationOptions.lazy }, { name: "Use ActiveRecord syntax for generated models", @@ -378,24 +442,30 @@ async function GetUtilParametersByInquirer() { }, { name: "Use custom naming strategy", - value: "namingStrategy" + value: "namingStrategy", + checked: !!options.generationOptions + .customNamingStrategyPath }, { name: "Generate RelationId fields", - value: "relationId" + value: "relationId", + checked: options.generationOptions.relationIds }, { name: "Omits schema identifier in generated entities", - value: "skipSchema" + value: "skipSchema", + checked: options.generationOptions.skipSchema }, { name: "Generate constructor allowing partial initialization", - value: "constructor" + value: "constructor", + checked: options.generationOptions.generateConstructor }, { name: "Use specific naming convention", - value: "namingConvention" + value: "namingConvention", + checked: options.generationOptions.lazy } ], message: "Available customizations", @@ -404,44 +474,48 @@ async function GetUtilParametersByInquirer() { } ])).selected; - generationOptions.propertyVisibility = (await inquirer.prompt([ + options.generationOptions.propertyVisibility = (await inquirer.prompt([ { choices: ["public", "protected", "private", "none"], message: "Defines which visibility should have the generated property", name: "propertyVisibility", - default: "none", + default: options.generationOptions.propertyVisibility, type: "list" } ])).propertyVisibility; - const { strictModeRaw } = await inquirer.prompt([ + options.generationOptions.strictMode = (await inquirer.prompt([ { choices: ["none", "?", "!"], message: "Mark fields as optional(?) or non-null(!)", - name: "strictModeRaw", - default: "none", + name: "strictMode", + default: options.generationOptions.strictMode, type: "list" } - ]); + ])).strictMode; - generationOptions.strictMode = - strictModeRaw === "none" ? false : strictModeRaw; - generationOptions.noConfigs = !customizations.includes("config"); - generationOptions.lazy = customizations.includes("lazy"); - generationOptions.activeRecord = customizations.includes( + options.generationOptions.noConfigs = !customizations.includes( + "config" + ); + options.generationOptions.lazy = customizations.includes("lazy"); + options.generationOptions.activeRecord = customizations.includes( "activeRecord" ); - generationOptions.relationIds = customizations.includes("relationId"); - generationOptions.skipSchema = customizations.includes("skipSchema"); - generationOptions.generateConstructor = customizations.includes( + options.generationOptions.relationIds = customizations.includes( + "relationId" + ); + options.generationOptions.skipSchema = customizations.includes( + "skipSchema" + ); + options.generationOptions.generateConstructor = customizations.includes( "constructor" ); if (customizations.includes("namingStrategy")) { const namingStrategyPath = (await inquirer.prompt([ { - default: path.resolve(process.cwd()), + default: options.generationOptions.customNamingStrategyPath, message: "Path to custom naming strategy file:", name: "namingStrategy", type: "input", @@ -456,39 +530,41 @@ async function GetUtilParametersByInquirer() { ])).namingStrategy; if (namingStrategyPath && namingStrategyPath !== "") { - generationOptions.customNamingStrategyPath = namingStrategyPath; + options.generationOptions.customNamingStrategyPath = namingStrategyPath; } else { - generationOptions.customNamingStrategyPath = ""; + options.generationOptions.customNamingStrategyPath = ""; } } if (customizations.includes("namingConvention")) { const namingConventions = await inquirer.prompt([ { choices: ["pascal", "param", "camel", "none"], - default: "pascal", + default: options.generationOptions.convertCaseFile, message: "Convert file names to specified case:", name: "fileCase", type: "list" }, { choices: ["pascal", "camel", "none"], - default: "pascal", + default: options.generationOptions.convertCaseEntity, message: "Convert class names to specified case:", name: "entityCase", type: "list" }, { choices: ["pascal", "camel", "none"], - default: "camel", + default: options.generationOptions.convertCaseProperty, message: "Convert property names to specified case:", name: "propertyCase", type: "list" } ]); - generationOptions.convertCaseFile = namingConventions.fileCase; - generationOptions.convertCaseProperty = + options.generationOptions.convertCaseFile = + namingConventions.fileCase; + options.generationOptions.convertCaseProperty = namingConventions.propertyCase; - generationOptions.convertCaseEntity = namingConventions.entityCase; + options.generationOptions.convertCaseEntity = + namingConventions.entityCase; } } const { saveConfig } = await inquirer.prompt([ @@ -502,7 +578,7 @@ async function GetUtilParametersByInquirer() { if (saveConfig) { await fs.writeJson( path.resolve(process.cwd(), ".tomg-config"), - [connectionOptions, generationOptions], + [options.generationOptions, options.connectionOptions], { spaces: 2 } ); console.log(`[${new Date().toLocaleTimeString()}] Config file saved.`); @@ -510,5 +586,5 @@ async function GetUtilParametersByInquirer() { `\x1b[33m[${new Date().toLocaleTimeString()}] WARNING: Password was saved as plain text.\x1b[0m` ); } - return { driver, connectionOptions, generationOptions }; + return options; } diff --git a/test/modelCustomization/modelCustomization.test.ts b/test/modelCustomization/modelCustomization.test.ts index 5ddb827..7b0a3a1 100644 --- a/test/modelCustomization/modelCustomization.test.ts +++ b/test/modelCustomization/modelCustomization.test.ts @@ -4,9 +4,13 @@ import * as chai from "chai"; import * as chaiSubset from "chai-subset"; import { Entity } from "../../src/models/Entity"; import modelCustomizationPhase from "../../src/ModelCustomization"; -import IGenerationOptions from "../../src/IGenerationOptions"; +import { + getDefaultGenerationOptions +} from "../../src/IGenerationOptions"; import modelGenerationPhase from "../../src/ModelGeneration"; -import IConnectionOptions from "../../src/IConnectionOptions"; +import { + getDefaultConnectionOptions +} from "../../src/IConnectionOptions"; import { compileGeneratedModel } from "../integration/runTestsFromPath.test"; chai.use(chaiSubset); @@ -111,7 +115,7 @@ describe("Model customization phase", async () => { const resultsPath = path.resolve(process.cwd(), `output`); const generateGenerationOptions = () => { - const generationOptions = new IGenerationOptions(); + const generationOptions = getDefaultGenerationOptions(); generationOptions.resultsPath = resultsPath; return generationOptions; }; @@ -132,7 +136,7 @@ describe("Model customization phase", async () => { {} ); modelGenerationPhase( - new IConnectionOptions(), + getDefaultConnectionOptions(), generationOptions, customizedModel ); @@ -154,7 +158,7 @@ describe("Model customization phase", async () => { {} ); modelGenerationPhase( - new IConnectionOptions(), + getDefaultConnectionOptions(), generationOptions, customizedModel ); @@ -178,7 +182,7 @@ describe("Model customization phase", async () => { {} ); modelGenerationPhase( - new IConnectionOptions(), + getDefaultConnectionOptions(), generationOptions, customizedModel ); @@ -206,7 +210,7 @@ describe("Model customization phase", async () => { {} ); modelGenerationPhase( - new IConnectionOptions(), + getDefaultConnectionOptions(), generationOptions, customizedModel ); @@ -236,7 +240,7 @@ describe("Model customization phase", async () => { {} ); modelGenerationPhase( - new IConnectionOptions(), + getDefaultConnectionOptions(), generationOptions, customizedModel ); @@ -264,7 +268,7 @@ describe("Model customization phase", async () => { {} ); modelGenerationPhase( - new IConnectionOptions(), + getDefaultConnectionOptions(), generationOptions, customizedModel ); @@ -294,7 +298,7 @@ describe("Model customization phase", async () => { {} ); modelGenerationPhase( - new IConnectionOptions(), + getDefaultConnectionOptions(), generationOptions, customizedModel ); @@ -322,7 +326,7 @@ describe("Model customization phase", async () => { {} ); modelGenerationPhase( - new IConnectionOptions(), + getDefaultConnectionOptions(), generationOptions, customizedModel ); @@ -351,7 +355,7 @@ describe("Model customization phase", async () => { {} ); modelGenerationPhase( - new IConnectionOptions(), + getDefaultConnectionOptions(), generationOptions, customizedModel ); @@ -381,7 +385,7 @@ describe("Model customization phase", async () => { {} ); modelGenerationPhase( - new IConnectionOptions(), + getDefaultConnectionOptions(), generationOptions, customizedModel ); @@ -413,7 +417,7 @@ describe("Model customization phase", async () => { {} ); modelGenerationPhase( - new IConnectionOptions(), + getDefaultConnectionOptions(), generationOptions, customizedModel ); @@ -441,7 +445,7 @@ describe("Model customization phase", async () => { {} ); modelGenerationPhase( - new IConnectionOptions(), + getDefaultConnectionOptions(), generationOptions, customizedModel ); @@ -474,7 +478,7 @@ describe("Model customization phase", async () => { {} ); modelGenerationPhase( - new IConnectionOptions(), + getDefaultConnectionOptions(), generationOptions, customizedModel ); @@ -509,7 +513,7 @@ describe("Model customization phase", async () => { {} ); modelGenerationPhase( - new IConnectionOptions(), + getDefaultConnectionOptions(), generationOptions, customizedModel ); @@ -542,7 +546,7 @@ describe("Model customization phase", async () => { {} ); modelGenerationPhase( - new IConnectionOptions(), + getDefaultConnectionOptions(), generationOptions, customizedModel ); @@ -568,7 +572,9 @@ describe("Model customization phase", async () => { const data = generateSampleData(); const generationOptions = generateGenerationOptions(); clearGenerationDir(); - + generationOptions.convertCaseEntity = "none" + generationOptions.convertCaseFile = "none" + generationOptions.convertCaseProperty = "none" generationOptions.customNamingStrategyPath = "test/modelCustomization/testNamingStrategy.ts"; // TODO: relationId @@ -579,7 +585,7 @@ describe("Model customization phase", async () => { {} ); modelGenerationPhase( - new IConnectionOptions(), + getDefaultConnectionOptions(), generationOptions, customizedModel ); diff --git a/test/utils/GeneralTestUtils.ts b/test/utils/GeneralTestUtils.ts index f507070..84d7c09 100644 --- a/test/utils/GeneralTestUtils.ts +++ b/test/utils/GeneralTestUtils.ts @@ -25,7 +25,7 @@ export function getGenerationOptions(resultsPath: string): IGenerationOptions { relationIds: false, skipSchema: false, activeRecord: false, - strictMode: false + strictMode: "none" }; } @@ -324,7 +324,7 @@ export function compileTsFiles( return compiledWithoutErrors; } -export function getEnabledDbDrivers():string[] { +export function getEnabledDbDrivers(): string[] { const dbDrivers: string[] = []; if (process.env.SQLITE_Skip === "0") { dbDrivers.push("sqlite"); From 3c274e836109cd670d6df7f01e1db6d5c7a1ce64 Mon Sep 17 00:00:00 2001 From: Kononnable Date: Sun, 15 Dec 2019 10:09:29 +0100 Subject: [PATCH 63/84] Option to save .tomg-config file without connection details --- src/index.ts | 84 +++++++++++++++++++++++++++++++++------------------- 1 file changed, 53 insertions(+), 31 deletions(-) diff --git a/src/index.ts b/src/index.ts index 9880043..ce1ae5a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -42,9 +42,6 @@ async function CliLogic() { console.info( `[${new Date().toLocaleTimeString()}] Typeorm model classes created.` ); - - // TODO: parameter for generating config file from passed arguments(yargs+inquirer)? - // TODO: inquirer - option to save config without connection options(only for security) } function makeDefaultConfigs() { const generationOptions = getDefaultGenerationOptions(); @@ -70,37 +67,49 @@ function readTOMLConfig( const [loadedGenerationOptions, loadedConnectionOptions] = retVal; let hasUnknownProperties = false; - Object.keys(loadedConnectionOptions).forEach(key => { + if (loadedConnectionOptions) { + Object.keys(loadedConnectionOptions).forEach(key => { + if ( + Object.prototype.hasOwnProperty.call( + options.connectionOptions, + key + ) + ) { + options.connectionOptions[key] = loadedConnectionOptions[key]; + } else { + console.error(`Unknown connection option ${key}.`); + hasUnknownProperties = true; + } + }); if ( - Object.prototype.hasOwnProperty.call(options.connectionOptions, key) + !Object.prototype.hasOwnProperty.call( + loadedConnectionOptions, + "timeout" + ) ) { - options.connectionOptions[key] = loadedConnectionOptions[key]; - } else { - console.error(`Unknown connection option ${key}.`); - hasUnknownProperties = true; + loadedConnectionOptions.timeout = undefined; } - }); - Object.keys(loadedGenerationOptions).forEach(key => { - if ( - Object.prototype.hasOwnProperty.call(options.generationOptions, key) - ) { - options.generationOptions[key] = loadedGenerationOptions[key]; - } else { - console.error(`Unknown generation option ${key}.`); - hasUnknownProperties = true; - } - }); - if ( - !Object.prototype.hasOwnProperty.call( - loadedConnectionOptions, - "timeout" - ) - ) { - loadedConnectionOptions.timeout = undefined; + } + if (loadedGenerationOptions) { + Object.keys(loadedGenerationOptions).forEach(key => { + if ( + Object.prototype.hasOwnProperty.call( + options.generationOptions, + key + ) + ) { + options.generationOptions[key] = loadedGenerationOptions[key]; + } else { + console.error(`Unknown generation option ${key}.`); + hasUnknownProperties = true; + } + }); } const fullConfigFile = !hasUnknownProperties && + loadedConnectionOptions && + loadedGenerationOptions && Object.keys(loadedConnectionOptions).length === Object.keys(options.connectionOptions).length && Object.keys(loadedGenerationOptions).length === @@ -438,7 +447,8 @@ async function useInquirer(options: options): Promise { }, { name: "Use ActiveRecord syntax for generated models", - value: "activeRecord" + value: "activeRecord", + checked: options.generationOptions.activeRecord }, { name: "Use custom naming strategy", @@ -569,13 +579,18 @@ async function useInquirer(options: options): Promise { } const { saveConfig } = await inquirer.prompt([ { - default: false, + choices: [ + "Yes, only model customization options", + "Yes, with connection details", + "No" + ], + default: "No", message: "Save configuration to config file?", name: "saveConfig", - type: "confirm" + type: "list" } ]); - if (saveConfig) { + if (saveConfig === "Yes, with connection details") { await fs.writeJson( path.resolve(process.cwd(), ".tomg-config"), [options.generationOptions, options.connectionOptions], @@ -585,6 +600,13 @@ async function useInquirer(options: options): Promise { console.warn( `\x1b[33m[${new Date().toLocaleTimeString()}] WARNING: Password was saved as plain text.\x1b[0m` ); + } else if (saveConfig === "Yes, only model customization options") { + await fs.writeJson( + path.resolve(process.cwd(), ".tomg-config"), + [options.generationOptions], + { spaces: 2 } + ); + console.log(`[${new Date().toLocaleTimeString()}] Config file saved.`); } return options; } From f720f34bc78cf795ea388e828c78e3a179ebb937 Mon Sep 17 00:00:00 2001 From: Kononnable Date: Sun, 15 Dec 2019 12:57:19 +0100 Subject: [PATCH 64/84] remove sleep parameter sql query execution timeout now set to 1hr --- src/IConnectionOptions.ts | 4 +-- src/drivers/MssqlDriver.ts | 2 +- src/drivers/MysqlDriver.ts | 4 +-- src/drivers/OracleDriver.ts | 2 +- src/drivers/PostgresDriver.ts | 2 +- src/index.ts | 41 ----------------------- test/integration/runTestsFromPath.test.ts | 2 +- 7 files changed, 7 insertions(+), 50 deletions(-) diff --git a/src/IConnectionOptions.ts b/src/IConnectionOptions.ts index 138c49f..8be2079 100644 --- a/src/IConnectionOptions.ts +++ b/src/IConnectionOptions.ts @@ -16,7 +16,6 @@ export default interface IConnectionOptions { | "sqlite"; schemaName: string; ssl: boolean; - timeout?: number; } export function getDefaultConnectionOptions(): IConnectionOptions { @@ -28,8 +27,7 @@ export function getDefaultConnectionOptions(): IConnectionOptions { password: "", databaseType: undefined as any, schemaName: "", - ssl: false, - timeout: undefined + ssl: false }; return connectionOptions; } diff --git a/src/drivers/MssqlDriver.ts b/src/drivers/MssqlDriver.ts index 92efbc3..4f513ac 100644 --- a/src/drivers/MssqlDriver.ts +++ b/src/drivers/MssqlDriver.ts @@ -440,7 +440,7 @@ WHERE TABLE_TYPE='BASE TABLE' and TABLE_SCHEMA in (${schema}) AND TABLE_CATALOG }, password: connectionOptons.password, port: connectionOptons.port, - requestTimeout: connectionOptons.timeout, + requestTimeout: 60 * 60 * 1000, server: connectionOptons.host, user: connectionOptons.user }; diff --git a/src/drivers/MysqlDriver.ts b/src/drivers/MysqlDriver.ts index 75aab4a..4e40085 100644 --- a/src/drivers/MysqlDriver.ts +++ b/src/drivers/MysqlDriver.ts @@ -421,7 +421,7 @@ export default class MysqlDriver extends AbstractDriver { ssl: { rejectUnauthorized: false }, - timeout: connectionOptons.timeout, + timeout: 60 * 60 * 1000, user: connectionOptons.user }; } else { @@ -430,7 +430,7 @@ export default class MysqlDriver extends AbstractDriver { host: connectionOptons.host, password: connectionOptons.password, port: connectionOptons.port, - timeout: connectionOptons.timeout, + timeout: 60 * 60 * 1000, user: connectionOptons.user }; } diff --git a/src/drivers/OracleDriver.ts b/src/drivers/OracleDriver.ts index 38cf79b..1d90233 100644 --- a/src/drivers/OracleDriver.ts +++ b/src/drivers/OracleDriver.ts @@ -42,7 +42,7 @@ export default class OracleDriver extends AbstractDriver { TABLE_NAME: string; DB_NAME: string; }[] = (await this.Connection.execute( - ` SELECT NULL AS TABLE_SCHEMA, TABLE_NAME, NULL AS DB_NAME FROM all_tables WHERE owner = (select user from dual)` + `SELECT NULL AS TABLE_SCHEMA, TABLE_NAME, NULL AS DB_NAME FROM all_tables WHERE owner = (select user from dual)` )).rows!; return response; }; diff --git a/src/drivers/PostgresDriver.ts b/src/drivers/PostgresDriver.ts index c34402f..446ad83 100644 --- a/src/drivers/PostgresDriver.ts +++ b/src/drivers/PostgresDriver.ts @@ -594,7 +594,7 @@ export default class PostgresDriver extends AbstractDriver { port: connectionOptons.port, ssl: connectionOptons.ssl, // eslint-disable-next-line @typescript-eslint/camelcase - statement_timeout: connectionOptons.timeout, + statement_timeout: 60 * 60 * 1000, user: connectionOptons.user }); diff --git a/src/index.ts b/src/index.ts index ce1ae5a..99ebe28 100644 --- a/src/index.ts +++ b/src/index.ts @@ -81,14 +81,6 @@ function readTOMLConfig( hasUnknownProperties = true; } }); - if ( - !Object.prototype.hasOwnProperty.call( - loadedConnectionOptions, - "timeout" - ) - ) { - loadedConnectionOptions.timeout = undefined; - } } if (loadedGenerationOptions) { Object.keys(loadedGenerationOptions).forEach(key => { @@ -251,11 +243,6 @@ function checkYargsParameters(options: options): options { choices: ["none", "?", "!"], default: options.generationOptions.strictMode, describe: "Mark fields as optional(?) or non-null(!)" - }, - timeout: { - describe: "SQL Query timeout(ms)", - default: options.connectionOptions.timeout, - number: true } }); @@ -272,7 +259,6 @@ function checkYargsParameters(options: options): options { ? argv.s.toString() : standardSchema; options.connectionOptions.ssl = argv.ssl; - options.connectionOptions.timeout = argv.timeout; options.connectionOptions.user = argv.u || standardUser; options.generationOptions.activeRecord = argv.a; options.generationOptions.generateConstructor = argv.generateConstructor; @@ -396,33 +382,6 @@ async function useInquirer(options: options): Promise { type: "input" } ])).output; - - if ( - options.connectionOptions.databaseType === "mssql" || - options.connectionOptions.databaseType === "postgres" - ) { - const { changeRequestTimeout } = await inquirer.prompt([ - { - default: false, - message: "Do you want to change default sql query timeout?", - name: "changeRequestTimeout", - type: "confirm" - } - ]); - if (changeRequestTimeout) { - const { timeout } = await inquirer.prompt({ - message: "Query timeout(ms):", - name: "timeout", - type: "input", - default: options.connectionOptions.timeout, - validate(value) { - const valid = !Number.isNaN(parseInt(value, 10)); - return valid || "Please enter a valid number"; - } - }); - options.connectionOptions.timeout = parseInt(timeout, 10); - } - } const { customizeGeneration } = await inquirer.prompt([ { default: false, diff --git a/test/integration/runTestsFromPath.test.ts b/test/integration/runTestsFromPath.test.ts index 71e4d3d..c394a6f 100644 --- a/test/integration/runTestsFromPath.test.ts +++ b/test/integration/runTestsFromPath.test.ts @@ -23,7 +23,7 @@ const { expect } = chai; it("Column default values", async () => { const testPartialPath = "test/integration/defaultValues"; await runTestsFromPath(testPartialPath, true); -}).timeout(); +}) it("Platform specific types", async () => { const testPartialPath = "test/integration/entityTypes"; await runTestsFromPath(testPartialPath, true); From ddfc9f52d9fe7ef54c5af301665396e7985cc397 Mon Sep 17 00:00:00 2001 From: Kononnable Date: Sun, 15 Dec 2019 16:39:56 +0100 Subject: [PATCH 65/84] support for old oracle versions (#195) --- src/drivers/OracleDriver.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/drivers/OracleDriver.ts b/src/drivers/OracleDriver.ts index 1d90233..7c259db 100644 --- a/src/drivers/OracleDriver.ts +++ b/src/drivers/OracleDriver.ts @@ -57,12 +57,10 @@ export default class OracleDriver extends AbstractDriver { DATA_LENGTH: number; DATA_PRECISION: number; DATA_SCALE: number; - IDENTITY_COLUMN: string; + IDENTITY_COLUMN: string; // doesn't exist in old oracle versions (#195) 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 + .execute(`SELECT utc.*, (select count(*) from USER_CONS_COLUMNS ucc JOIN USER_CONSTRAINTS uc ON uc.CONSTRAINT_NAME = ucc.CONSTRAINT_NAME and uc.CONSTRAINT_TYPE='U' where ucc.column_name = utc.COLUMN_NAME AND ucc.table_name = utc.TABLE_NAME) IS_UNIQUE FROM USER_TAB_COLUMNS utc`)).rows!; From 57cec40afbe0e1323404b15caf32450ed4993b03 Mon Sep 17 00:00:00 2001 From: Kononnable Date: Wed, 18 Dec 2019 22:24:05 +0100 Subject: [PATCH 66/84] update dependencies --- .eslintrc.js | 2 +- package-lock.json | 2140 ++++++++++++++++++++++----------- package.json | 60 +- src/drivers/MssqlDriver.ts | 34 +- src/drivers/OracleDriver.ts | 33 +- src/drivers/PostgresDriver.ts | 28 +- src/index.ts | 266 ++-- 7 files changed, 1664 insertions(+), 899 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 5f47d85..7046abe 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -28,7 +28,7 @@ module.exports = { "no-plusplus": ["error", { allowForLoopAfterthoughts: true }], "@typescript-eslint/no-non-null-assertion": ["off"], - + "import/extensions": ["off"], "no-param-reassign": ["off"], "@typescript-eslint/no-explicit-any": ["off"], "no-loop-func": ["off"] diff --git a/package-lock.json b/package-lock.json index 93b6a1c..1c9829f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,6 +4,36 @@ "lockfileVersion": 1, "requires": true, "dependencies": { + "@azure/ms-rest-azure-env": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@azure/ms-rest-azure-env/-/ms-rest-azure-env-1.1.2.tgz", + "integrity": "sha512-l7z0DPCi2Hp88w12JhDTtx5d0Y3+vhfE7JKJb9O7sEz71Cwp053N8piTtTnnk/tUor9oZHgEKi/p3tQQmLPjvA==" + }, + "@azure/ms-rest-js": { + "version": "1.8.14", + "resolved": "https://registry.npmjs.org/@azure/ms-rest-js/-/ms-rest-js-1.8.14.tgz", + "integrity": "sha512-IrCPN22c8RbKWA06ZXuFwwEb15cSnr0zZ6J8Fspp9ns1SSNTERf7hv+gWvTIis1FlwHy42Mfk8hVu0/r3a0AWA==", + "requires": { + "@types/tunnel": "0.0.0", + "axios": "^0.19.0", + "form-data": "^2.3.2", + "tough-cookie": "^2.4.3", + "tslib": "^1.9.2", + "tunnel": "0.0.6", + "uuid": "^3.2.1", + "xml2js": "^0.4.19" + } + }, + "@azure/ms-rest-nodeauth": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@azure/ms-rest-nodeauth/-/ms-rest-nodeauth-2.0.2.tgz", + "integrity": "sha512-KmNNICOxt3EwViAJI3iu2VH8t8BQg5J2rSAyO4IUYLF9ZwlyYsP419pdvl4NBUhluAP2cgN7dfD2V6E6NOMZlQ==", + "requires": { + "@azure/ms-rest-azure-env": "^1.1.2", + "@azure/ms-rest-js": "^1.8.7", + "adal-node": "^0.1.28" + } + }, "@babel/code-frame": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz", @@ -216,9 +246,9 @@ "dev": true }, "@types/chai": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.2.3.tgz", - "integrity": "sha512-VRw2xEGbll3ZiTQ4J02/hUjNqZoue1bMhoo2dgM2LXjDdyaq4q80HgBDHwpI0/VKlo4Eg+BavyQMv/NYgTetzA==", + "version": "4.2.7", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.2.7.tgz", + "integrity": "sha512-luq8meHGYwvky0O7u0eQZdA7B4Wd9owUCqvbw2m3XCrCU8mplYOujMBbvyS547AxJkC+pGnd0Cm15eNxEUNU8g==", "dev": true }, "@types/chai-as-promised": { @@ -239,6 +269,11 @@ "@types/chai": "*" } }, + "@types/color-name": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", + "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==" + }, "@types/eslint-visitor-keys": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", @@ -252,9 +287,9 @@ "dev": true }, "@types/fs-extra": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-8.0.0.tgz", - "integrity": "sha512-bCtL5v9zdbQW86yexOlXWTEGvLNqWxMFyi7gQA7Gcthbezr2cPSOb8SkESVKA937QD5cIwOFLDFt0MQoXOEr9Q==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-8.0.1.tgz", + "integrity": "sha512-J00cVDALmi/hJOYsunyT52Hva5TnJeKP5yd1r+mH/ZU0mbYZflR0Z5kw5kITtKTRYMhm1JMClOFYdHnQszEvqw==", "dev": true, "requires": { "@types/node": "*" @@ -309,9 +344,9 @@ "dev": true }, "@types/mssql": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@types/mssql/-/mssql-4.3.1.tgz", - "integrity": "sha512-LB+fDgwAbcvGfFCWN89gqZgyTIbEmnLW4RzVZeiaDSZJwL8xv8Rei2zM/5E62eW9G0UoY/4fHDXxTNRnCdlJRg==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@types/mssql/-/mssql-6.0.0.tgz", + "integrity": "sha512-Mn+PYRNugxJQlfY50xUa2PuKUO3knie8/MclSGQGOTh0fITd6l+yjotq23tmahmTml3hiARwTksqV0hjLrVnhA==", "dev": true, "requires": { "@types/node": "*", @@ -319,19 +354,18 @@ } }, "@types/mysql": { - "version": "2.15.7", - "resolved": "https://registry.npmjs.org/@types/mysql/-/mysql-2.15.7.tgz", - "integrity": "sha512-S7cpDl+heeTe2zd7LGeAodEsx9AnkzW1vHJ9kKwr9ype1KohW01jaUmCYhpafrQvnxzcUJAfeYdDr3fET8ufPw==", + "version": "2.15.8", + "resolved": "https://registry.npmjs.org/@types/mysql/-/mysql-2.15.8.tgz", + "integrity": "sha512-l0TUdg6KDEaLO75/yjdjksobJDRWv8iZlpRfv/WW1lQZCQDKdTDnKCkeH10oapzP/JTuKiTy6Cvq/sm/0GgcUw==", "dev": true, "requires": { "@types/node": "*" } }, "@types/node": { - "version": "12.7.12", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.7.12.tgz", - "integrity": "sha512-KPYGmfD0/b1eXurQ59fXD1GBzhSQfz6/lKBxkaHX9dKTzjXbK68Zt7yGUxUsCS1jeTy/8aL+d9JEr+S54mpkWQ==", - "dev": true + "version": "12.12.21", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.21.tgz", + "integrity": "sha512-8sRGhbpU+ck1n0PGAUgVrWrWdjSW2aqNeyC15W88GRsMpSwzv6RJGlLhE7s2RhVSOdyDmxbqlWSeThq4/7xqlA==" }, "@types/normalize-package-data": { "version": "2.4.0", @@ -340,12 +374,21 @@ "dev": true }, "@types/oracledb": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@types/oracledb/-/oracledb-4.0.4.tgz", - "integrity": "sha512-csHiM6eeV6Yzb4riR7+SHsEGZ19+mm+gbEbN3gGpA4nQa2ICLMJReesWfz+GWka6RMCjNNEflfenXgZ8HVsU5Q==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@types/oracledb/-/oracledb-4.1.1.tgz", + "integrity": "sha512-Vjk5RLENuQKzgqjoIyGH9wZCGOxc4r4j2nh7jKo32+yJ4zwwPiKp808YZh0iRPgXOZeqFVaQYHB0xpEFuV4lug==", "dev": true, "requires": { - "@types/node": "*" + "@types/node": "*", + "dotenv": "^8.2.0" + }, + "dependencies": { + "dotenv": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz", + "integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==", + "dev": true + } } }, "@types/pg": { @@ -374,15 +417,24 @@ "dev": true }, "@types/prettier": { - "version": "1.18.3", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-1.18.3.tgz", - "integrity": "sha512-48rnerQdcZ26odp+HOvDGX8IcUkYOCuMc2BodWYTe956MqkHlOGAG4oFQ83cjZ0a4GAgj7mb4GUClxYd2Hlodg==", + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-1.19.0.tgz", + "integrity": "sha512-gDE8JJEygpay7IjA/u3JiIURvwZW08f0cZSZLAzFoX/ZmeqvS0Sqv+97aKuHpNsalAMMhwPe+iAS6fQbfmbt7A==", "dev": true }, + "@types/readable-stream": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@types/readable-stream/-/readable-stream-2.3.5.tgz", + "integrity": "sha512-Mq2eLkGYamlcolW603FY2ROBvcl90jPF+3jLkjpBV6qS+2aVeJqlgRG0TVAa1oWbmPdb5yOWlOPVvQle76nUNw==", + "requires": { + "@types/node": "*", + "safe-buffer": "*" + } + }, "@types/sinon": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-7.5.0.tgz", - "integrity": "sha512-NyzhuSBy97B/zE58cDw4NyGvByQbAHNP9069KVSgnXt/sc0T6MFRh0InKAeBVHJWdSXG1S3+PxgVIgKo9mTHbw==", + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-7.5.1.tgz", + "integrity": "sha512-EZQUP3hSZQyTQRfiLqelC9NMWd1kqLcmQE0dMiklxBkgi84T+cHOhnKpgk4NnOWpGX863yE6+IaGnOXUNFqDnQ==", "dev": true }, "@types/sqlite3": { @@ -412,6 +464,14 @@ "@types/node": "*" } }, + "@types/tunnel": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/@types/tunnel/-/tunnel-0.0.0.tgz", + "integrity": "sha512-FGDp0iBRiBdPjOgjJmn1NH0KDLN+Z8fRmo+9J7XGBhubq1DPrGrbmG4UTlGzrpbCpesMqD0sWkzi27EYkOMHyg==", + "requires": { + "@types/node": "*" + } + }, "@types/yargs": { "version": "13.0.3", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.3.tgz", @@ -428,78 +488,71 @@ "dev": true }, "@typescript-eslint/eslint-plugin": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.3.3.tgz", - "integrity": "sha512-12cCbwu5PbQudkq2xCIS/QhB7hCMrsNPXK+vJtqy/zFqtzVkPRGy12O5Yy0gUK086f3VHV/P4a4R4CjMW853pA==", + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.12.0.tgz", + "integrity": "sha512-1t4r9rpLuEwl3hgt90jY18wJHSyb0E3orVL3DaqwmpiSDHmHiSspVsvsFF78BJ/3NNG3qmeso836jpuBWYziAA==", "dev": true, "requires": { - "@typescript-eslint/experimental-utils": "2.3.3", - "eslint-utils": "^1.4.2", + "@typescript-eslint/experimental-utils": "2.12.0", + "eslint-utils": "^1.4.3", "functional-red-black-tree": "^1.0.1", - "regexpp": "^2.0.1", + "regexpp": "^3.0.0", "tsutils": "^3.17.1" - } - }, - "@typescript-eslint/experimental-utils": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-2.3.3.tgz", - "integrity": "sha512-MQ4jKPMTU1ty4TigJCRKFPye2qyQdH8jzIIkceaHgecKFmkNS1hXPqKiZ+mOehkz6+HcN5Nuvwm+frmWZR9tdg==", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.3", - "@typescript-eslint/typescript-estree": "2.3.3", - "eslint-scope": "^5.0.0" - } - }, - "@typescript-eslint/parser": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-2.3.3.tgz", - "integrity": "sha512-+cV53HuYFeeyrNW8x/rgPmbVrzzp/rpRmwbJnNtwn4K8mroL1BdjxwQh7X9cUHp9rm4BBiEWmD3cSBjKG7d5mw==", - "dev": true, - "requires": { - "@types/eslint-visitor-keys": "^1.0.0", - "@typescript-eslint/experimental-utils": "2.3.3", - "@typescript-eslint/typescript-estree": "2.3.3", - "eslint-visitor-keys": "^1.1.0" }, "dependencies": { "@typescript-eslint/experimental-utils": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-2.3.3.tgz", - "integrity": "sha512-MQ4jKPMTU1ty4TigJCRKFPye2qyQdH8jzIIkceaHgecKFmkNS1hXPqKiZ+mOehkz6+HcN5Nuvwm+frmWZR9tdg==", + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-2.12.0.tgz", + "integrity": "sha512-jv4gYpw5N5BrWF3ntROvCuLe1IjRenLy5+U57J24NbPGwZFAjhnM45qpq0nDH1y/AZMb3Br25YiNVwyPbz6RkA==", "dev": true, "requires": { "@types/json-schema": "^7.0.3", - "@typescript-eslint/typescript-estree": "2.3.3", + "@typescript-eslint/typescript-estree": "2.12.0", "eslint-scope": "^5.0.0" } }, "@typescript-eslint/typescript-estree": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-2.3.3.tgz", - "integrity": "sha512-GkACs12Xp8d/STunNv/iSMYJFQrkrax9vuPZySlgSzoJJtw1cp6tbEw4qsLskQv6vloLrkFJHcTJ0a/yCB5cIA==", + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-2.12.0.tgz", + "integrity": "sha512-rGehVfjHEn8Frh9UW02ZZIfJs6SIIxIu/K1bbci8rFfDE/1lQ8krIJy5OXOV3DVnNdDPtoiPOdEANkLMrwXbiQ==", "dev": true, "requires": { - "glob": "^7.1.4", + "debug": "^4.1.1", + "eslint-visitor-keys": "^1.1.0", + "glob": "^7.1.6", "is-glob": "^4.0.1", "lodash.unescape": "4.0.1", - "semver": "^6.3.0" + "semver": "^6.3.0", + "tsutils": "^3.17.1" } }, - "eslint-scope": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.0.0.tgz", - "integrity": "sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw==", + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", "dev": true, "requires": { - "esrecurse": "^4.1.0", - "estraverse": "^4.1.1" + "ms": "^2.1.1" } }, - "eslint-visitor-keys": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz", - "integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==", + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "regexpp": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.0.0.tgz", + "integrity": "sha512-Z+hNr7RAVWxznLPuA7DIh8UNX1j9CDrUQxskw9IrBE1Dxue2lyXT+shqEIeLUjrokxIP8CMy1WkjgG3rTsd5/g==", "dev": true }, "semver": { @@ -510,18 +563,159 @@ } } }, - "@typescript-eslint/typescript-estree": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-2.3.3.tgz", - "integrity": "sha512-GkACs12Xp8d/STunNv/iSMYJFQrkrax9vuPZySlgSzoJJtw1cp6tbEw4qsLskQv6vloLrkFJHcTJ0a/yCB5cIA==", + "@typescript-eslint/experimental-utils": { + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-2.12.0.tgz", + "integrity": "sha512-jv4gYpw5N5BrWF3ntROvCuLe1IjRenLy5+U57J24NbPGwZFAjhnM45qpq0nDH1y/AZMb3Br25YiNVwyPbz6RkA==", "dev": true, "requires": { - "glob": "^7.1.4", - "is-glob": "^4.0.1", - "lodash.unescape": "4.0.1", - "semver": "^6.3.0" + "@types/json-schema": "^7.0.3", + "@typescript-eslint/typescript-estree": "2.12.0", + "eslint-scope": "^5.0.0" }, "dependencies": { + "@typescript-eslint/typescript-estree": { + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-2.12.0.tgz", + "integrity": "sha512-rGehVfjHEn8Frh9UW02ZZIfJs6SIIxIu/K1bbci8rFfDE/1lQ8krIJy5OXOV3DVnNdDPtoiPOdEANkLMrwXbiQ==", + "dev": true, + "requires": { + "debug": "^4.1.1", + "eslint-visitor-keys": "^1.1.0", + "glob": "^7.1.6", + "is-glob": "^4.0.1", + "lodash.unescape": "4.0.1", + "semver": "^6.3.0", + "tsutils": "^3.17.1" + } + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "@typescript-eslint/parser": { + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-2.12.0.tgz", + "integrity": "sha512-lPdkwpdzxEfjI8TyTzZqPatkrswLSVu4bqUgnB03fHSOwpC7KSerPgJRgIAf11UGNf7HKjJV6oaPZI4AghLU6g==", + "dev": true, + "requires": { + "@types/eslint-visitor-keys": "^1.0.0", + "@typescript-eslint/experimental-utils": "2.12.0", + "@typescript-eslint/typescript-estree": "2.12.0", + "eslint-visitor-keys": "^1.1.0" + }, + "dependencies": { + "@typescript-eslint/typescript-estree": { + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-2.12.0.tgz", + "integrity": "sha512-rGehVfjHEn8Frh9UW02ZZIfJs6SIIxIu/K1bbci8rFfDE/1lQ8krIJy5OXOV3DVnNdDPtoiPOdEANkLMrwXbiQ==", + "dev": true, + "requires": { + "debug": "^4.1.1", + "eslint-visitor-keys": "^1.1.0", + "glob": "^7.1.6", + "is-glob": "^4.0.1", + "lodash.unescape": "4.0.1", + "semver": "^6.3.0", + "tsutils": "^3.17.1" + } + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "@typescript-eslint/typescript-estree": { + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-2.12.0.tgz", + "integrity": "sha512-rGehVfjHEn8Frh9UW02ZZIfJs6SIIxIu/K1bbci8rFfDE/1lQ8krIJy5OXOV3DVnNdDPtoiPOdEANkLMrwXbiQ==", + "dev": true, + "requires": { + "debug": "^4.1.1", + "eslint-visitor-keys": "^1.1.0", + "glob": "^7.1.6", + "is-glob": "^4.0.1", + "lodash.unescape": "4.0.1", + "semver": "^6.3.0", + "tsutils": "^3.17.1" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, "semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", @@ -542,9 +736,9 @@ "dev": true }, "acorn-jsx": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.0.2.tgz", - "integrity": "sha512-tiNTrP1MP0QrChmD2DdupCr6HWSFeKVw5d/dHTu4Y7rkAkRhU/Dt7dphAfIUyxtHpl/eBVip5uTNSpQJHylpAw==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.1.0.tgz", + "integrity": "sha512-tMUqwBWfLFbJbizRmEcWSLw6HnFzfdJs2sOJEOwwtVPMoH/0Ay+E703oZz78VSXZiiDcZrQ5XKjPIUQixhmgVw==", "dev": true }, "adal-node": { @@ -564,9 +758,9 @@ }, "dependencies": { "@types/node": { - "version": "8.10.49", - "resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.49.tgz", - "integrity": "sha512-YX30JVx0PvSmJ3Eqr74fYLGeBxD+C7vIL20ek+GGGLJeUbVYRUW3EzyAXpIRA0K8c8o0UWqR/GwEFYiFoz1T8w==" + "version": "8.10.59", + "resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.59.tgz", + "integrity": "sha512-8RkBivJrDCyPpBXhVZcjh7cQxVBSmRk9QM7hOketZzp6Tg79c0N8kkpAIito9bnJ3HCVCHVYz+KHTEbfQNfeVQ==" } } }, @@ -637,9 +831,9 @@ "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=" }, "app-root-path": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/app-root-path/-/app-root-path-2.2.1.tgz", - "integrity": "sha512-91IFKeKk7FjfmezPKkwtaRvSpnUc4gDwPAjA1YZ9Gn0q0PPeW+vbeUsZuyDwjI7+QTHhcLen2v25fi/AmhvbJA==" + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/app-root-path/-/app-root-path-3.0.0.tgz", + "integrity": "sha512-qMcx+Gy2UZynHjOHOIXPNvpf+9cjvk3cWrBBK7zg4gH9+clobJRb9NGzcT7mQTcV/6Gm/1WelUtqxVXnNlrwcw==" }, "append-transform": { "version": "1.0.0", @@ -671,9 +865,9 @@ } }, "arg": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.1.tgz", - "integrity": "sha512-SlmP3fEA88MBv0PypnXZ8ZfJhwmDeIE3SP71j37AiXQBXYosPV0x6uISAaHYSlSVhmHOVkomen0tbGk6Anlebw==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.2.tgz", + "integrity": "sha512-+ytCkGcBtHZ3V2r2Z06AncYO8jz46UEamcspGoU8lHcEbpn6J77QK0vdWvChsclg/tM5XIJC5tnjmPp7Eq6Obg==", "dev": true }, "argparse": { @@ -697,13 +891,51 @@ "dev": true }, "array-includes": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.0.3.tgz", - "integrity": "sha1-GEtI9i2S10UrsxsyMWXH+L0CJm0=", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.0.tgz", + "integrity": "sha512-ONOEQoKrvXPKk7Su92Co0YMqYO32FfqJTzkKU9u2UpIXyYZIzLSvpdg4AwvSw4mSUW0czu6inK+zby6Oj6gDjQ==", "dev": true, "requires": { - "define-properties": "^1.1.2", - "es-abstract": "^1.7.0" + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.0" + }, + "dependencies": { + "es-abstract": { + "version": "1.17.0-next.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.0-next.1.tgz", + "integrity": "sha512-7MmGr03N7Rnuid6+wyhD9sHNE2n4tFSwExnU2lQl3lIo2ShXWGePY80zYaoMOmILWv57H0amMjZGHNzzGG70Rw==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.1.4", + "is-regex": "^1.0.4", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimleft": "^2.1.0", + "string.prototype.trimright": "^2.1.0" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "dev": true + } } }, "array-union": { @@ -712,34 +944,100 @@ "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", "dev": true }, - "array.prototype.flatmap": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.2.2.tgz", - "integrity": "sha512-ZZtPLE74KNE+0XcPv/vQmcivxN+8FhwOLvt2udHauO0aDEpsXDQrmd5HuJGpgPVyaV8HvkDPWnJ2iaem0oCKtA==", + "array.prototype.flat": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.3.tgz", + "integrity": "sha512-gBlRZV0VSmfPIeWfuuy56XZMvbVfbEUnOXUvt3F/eUUUSyzlgLxhEX4YAEpxNAogRGehPSnfXyPtYyKAhkzQhQ==", "dev": true, "requires": { "define-properties": "^1.1.3", - "es-abstract": "^1.15.0", + "es-abstract": "^1.17.0-next.1" + }, + "dependencies": { + "es-abstract": { + "version": "1.17.0-next.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.0-next.1.tgz", + "integrity": "sha512-7MmGr03N7Rnuid6+wyhD9sHNE2n4tFSwExnU2lQl3lIo2ShXWGePY80zYaoMOmILWv57H0amMjZGHNzzGG70Rw==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.1.4", + "is-regex": "^1.0.4", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimleft": "^2.1.0", + "string.prototype.trimright": "^2.1.0" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "dev": true + } + } + }, + "array.prototype.flatmap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.2.3.tgz", + "integrity": "sha512-OOEk+lkePcg+ODXIpvuU9PAryCikCJyo7GlDG1upleEpQRx6mzL9puEBkozQ5iAx20KV0l3DbyQwqciJtqe5Pg==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1", "function-bind": "^1.1.1" }, "dependencies": { "es-abstract": { - "version": "1.16.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.16.0.tgz", - "integrity": "sha512-xdQnfykZ9JMEiasTAJZJdMWCQ1Vm00NBw79/AWi7ELfZuuPCSOMDZbT9mkOfSctVtfhb+sAAzrm+j//GjjLHLg==", + "version": "1.17.0-next.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.0-next.1.tgz", + "integrity": "sha512-7MmGr03N7Rnuid6+wyhD9sHNE2n4tFSwExnU2lQl3lIo2ShXWGePY80zYaoMOmILWv57H0amMjZGHNzzGG70Rw==", "dev": true, "requires": { - "es-to-primitive": "^1.2.0", + "es-to-primitive": "^1.2.1", "function-bind": "^1.1.1", "has": "^1.0.3", - "has-symbols": "^1.0.0", + "has-symbols": "^1.0.1", "is-callable": "^1.1.4", "is-regex": "^1.0.4", - "object-inspect": "^1.6.0", + "object-inspect": "^1.7.0", "object-keys": "^1.1.1", + "object.assign": "^4.1.0", "string.prototype.trimleft": "^2.1.0", "string.prototype.trimright": "^2.1.0" } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "dev": true } } }, @@ -769,9 +1067,9 @@ "dev": true }, "async": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", - "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=" + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/async/-/async-3.1.0.tgz", + "integrity": "sha512-4vx/aaY6j/j3Lw3fbCHNWP0pPaTCew3F6F3hYyl/tHs/ndmV1q7NW9T5yuJ2XAGwdQrP+6Wu20x06U4APo/iQQ==" }, "asynckit": { "version": "0.4.0", @@ -788,6 +1086,15 @@ "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==" }, + "axios": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.19.0.tgz", + "integrity": "sha512-1uvKqKQta3KBxIz14F2v06AEHZ/dIoeKfbTRkK1E5oqjDnuEerLmYTgJB5AiQZHJcljpg1TuRzdjDR06qNk0DQ==", + "requires": { + "follow-redirects": "1.5.10", + "is-buffer": "^2.0.2" + } + }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", @@ -806,23 +1113,29 @@ "tweetnacl": "^0.14.3" } }, - "big-number": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/big-number/-/big-number-1.0.0.tgz", - "integrity": "sha512-cHUzdT+mMXd1ozht8n5ZwBlNiPO/4zCqqkyp3lF1TMPsRJLXUbQ7cKnfXRkrW475H5SOtSOP0HFeihNbpa53MQ==" - }, "bignumber.js": { "version": "7.2.1", "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-7.2.1.tgz", "integrity": "sha512-S4XzBk5sMB+Rcb/LNcpzXr57VRTxgAvaAEDAl1AwRx27j00hT84O6OkteE7u8UB3NuaaygCRrEpqox4uDOrbdQ==" }, "bl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-2.2.0.tgz", - "integrity": "sha512-wbgvOpqopSr7uq6fJrLH8EsvYMJf9gzfo2jCsL2eTy75qXPukA4pCgHamOQkZtY5vmfVtjB+P3LNlMHW5CEZXA==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-3.0.0.tgz", + "integrity": "sha512-EUAyP5UHU5hxF8BPT0LKW8gjYLhq1DQIcneOX/pL/m2Alo+OYDQAJlHq+yseMP50Os2nHXOSic6Ss3vSQeyf4A==", "requires": { - "readable-stream": "^2.3.5", - "safe-buffer": "^5.1.1" + "readable-stream": "^3.0.1" + }, + "dependencies": { + "readable-stream": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz", + "integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } } }, "brace-expansion": { @@ -919,12 +1232,19 @@ "dev": true }, "camel-case": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz", - "integrity": "sha1-yjw2iKTpzzpM2nd9xNy8cTJJz3M=", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.0.tgz", + "integrity": "sha512-vmHTVppun53Le+K8wHxA0f4oI192u2i6eL9qHrqByibpxRbdkvI1o1fAA6ozxpLGEnsDS3MBjPJAi7ArJU9ZDg==", "requires": { - "no-case": "^2.2.0", - "upper-case": "^1.1.1" + "pascal-case": "^3.1.0", + "tslib": "^1.10.0" + }, + "dependencies": { + "tslib": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", + "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==" + } } }, "camelcase": { @@ -932,6 +1252,23 @@ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" }, + "capital-case": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/capital-case/-/capital-case-1.0.2.tgz", + "integrity": "sha512-7dF2q6pv+qqMkFG+AS0c6/UnYAL5ldR2rUbjKoJrHz9S0bn14jOLIpXxwabIeyakcRWNeGguWzNxJRPAGe4lFA==", + "requires": { + "no-case": "^3.0.2", + "tslib": "^1.10.0", + "upper-case-first": "^2.0.1" + }, + "dependencies": { + "tslib": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", + "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==" + } + } + }, "caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", @@ -977,28 +1314,29 @@ } }, "change-case": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/change-case/-/change-case-3.1.0.tgz", - "integrity": "sha512-2AZp7uJZbYEzRPsFoa+ijKdvp9zsrnnt6+yFokfwEpeJm0xuJDVoxiRCAaTzyJND8GJkofo2IcKWaUZ/OECVzw==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/change-case/-/change-case-4.1.0.tgz", + "integrity": "sha512-jz4NjT8d6J9ggFuGHJ860Trta1IXjtnG+T3HGKdN/9ihDefiN241SQhJlD/fbNdiH4YUwPAp00X030vqc/LRcw==", "requires": { - "camel-case": "^3.0.0", - "constant-case": "^2.0.0", - "dot-case": "^2.1.0", - "header-case": "^1.0.0", - "is-lower-case": "^1.1.0", - "is-upper-case": "^1.1.0", - "lower-case": "^1.1.1", - "lower-case-first": "^1.0.0", - "no-case": "^2.3.2", - "param-case": "^2.1.0", - "pascal-case": "^2.0.0", - "path-case": "^2.1.0", - "sentence-case": "^2.1.0", - "snake-case": "^2.1.0", - "swap-case": "^1.1.0", - "title-case": "^2.1.0", - "upper-case": "^1.1.1", - "upper-case-first": "^1.1.0" + "camel-case": "^4.1.0", + "capital-case": "^1.0.2", + "constant-case": "^3.0.2", + "dot-case": "^3.0.2", + "header-case": "^2.0.2", + "no-case": "^3.0.2", + "param-case": "^3.0.2", + "pascal-case": "^3.1.0", + "path-case": "^3.0.2", + "sentence-case": "^3.0.2", + "snake-case": "^3.0.2", + "tslib": "^1.10.0" + }, + "dependencies": { + "tslib": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", + "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==" + } } }, "chardet": { @@ -1039,48 +1377,167 @@ } }, "cli-highlight": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/cli-highlight/-/cli-highlight-2.1.1.tgz", - "integrity": "sha512-0y0VlNmdD99GXZHYnvrQcmHxP8Bi6T00qucGgBgGv4kJ0RyDthNnnFPupHV7PYv/OXSVk+azFbOeaW6+vGmx9A==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/cli-highlight/-/cli-highlight-2.1.4.tgz", + "integrity": "sha512-s7Zofobm20qriqDoU9sXptQx0t2R9PEgac92mENNm7xaEe1hn71IIMsXMK+6encA6WRCWWxIGQbipr3q998tlQ==", "requires": { - "chalk": "^2.3.0", + "chalk": "^3.0.0", "highlight.js": "^9.6.0", "mz": "^2.4.0", - "parse5": "^4.0.0", - "yargs": "^13.0.0" + "parse5": "^5.1.1", + "parse5-htmlparser2-tree-adapter": "^5.1.1", + "yargs": "^15.0.0" }, "dependencies": { - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==" + }, + "ansi-styles": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.0.tgz", + "integrity": "sha512-7kFQgnEaMdRtwf6uSfUnVr9gSGC7faurn+J/Mv90/W+iTtN0405/nLdopfMWwchyxhbGYl6TC4Sccn9TUkGAgg==", "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "requires": { + "p-locate": "^4.1.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "requires": { + "p-limit": "^2.2.0" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" + }, + "string-width": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + } + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "requires": { + "ansi-regex": "^5.0.0" + } + }, + "supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "requires": { + "has-flag": "^4.0.0" + } + }, + "wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" } }, "yargs": { - "version": "13.3.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.0.tgz", - "integrity": "sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA==", + "version": "15.0.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.0.2.tgz", + "integrity": "sha512-GH/X/hYt+x5hOat4LMnCqMd8r5Cv78heOMIJn1hr7QPPBqfeC6p89Y78+WB9yGDvfpCvgasfmWLzNzEioOUD9Q==", "requires": { - "cliui": "^5.0.0", - "find-up": "^3.0.0", + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", "get-caller-file": "^2.0.1", "require-directory": "^2.1.1", "require-main-filename": "^2.0.0", "set-blocking": "^2.0.0", - "string-width": "^3.0.0", + "string-width": "^4.2.0", "which-module": "^2.0.0", "y18n": "^4.0.0", - "yargs-parser": "^13.1.1" + "yargs-parser": "^16.1.0" } }, "yargs-parser": { - "version": "13.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz", - "integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==", + "version": "16.1.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-16.1.0.tgz", + "integrity": "sha512-H/V41UNZQPkUMIT5h5hiwg4QKIY1RPvoBV4XcjUbRM8Bk2oKqqyZ0DIEbTFZB0XjbtSPG8SAa/0DxCQmiRgzKg==", "requires": { "camelcase": "^5.0.0", "decamelize": "^1.2.0" @@ -1218,9 +1675,9 @@ } }, "commander": { - "version": "2.20.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz", - "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==" + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" }, "commondir": { "version": "1.0.1", @@ -1245,12 +1702,20 @@ "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" }, "constant-case": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/constant-case/-/constant-case-2.0.0.tgz", - "integrity": "sha1-QXV2TTidP6nI7NKRhu1gBSQ7akY=", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/constant-case/-/constant-case-3.0.2.tgz", + "integrity": "sha512-VxthHv7/VKSXl9kToCoulqM5hH6KpLdAdBCRMFj1SzaHTHMZkQYbRlMwEiLHYJfMN7xE8UiUtyBAJjPXOtbjjA==", "requires": { - "snake-case": "^2.1.0", - "upper-case": "^1.1.1" + "no-case": "^3.0.2", + "tslib": "^1.10.0", + "upper-case": "^2.0.1" + }, + "dependencies": { + "tslib": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", + "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==" + } } }, "contains-path": { @@ -1437,19 +1902,10 @@ }, "dependencies": { "graceful-fs": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.2.tgz", - "integrity": "sha512-IItsdsea19BoLC7ELy13q1iJFNmd7ofZH5+X/pJr90/nRoPEX0DJo1dHDbgtYWOhJhcCgMDTOw84RZ72q6lB+Q==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", + "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==", "dev": true - }, - "rimraf": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.0.tgz", - "integrity": "sha512-NDGVxTsjqfunkds7CqsOiEnxln4Bo7Nddl3XhS4pXg5OzwkLqJ971ZVAAnB+DDLnF76N+VnDEiBHaVV8I06SUg==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } } } }, @@ -1464,9 +1920,9 @@ "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" }, "depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" }, "detect-libc": { "version": "1.0.3", @@ -1506,17 +1962,25 @@ } }, "dot-case": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-2.1.1.tgz", - "integrity": "sha1-NNzzf1Co6TwrO8qLt/uRVcfaO+4=", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.2.tgz", + "integrity": "sha512-z3vMZEW2o3btKlM9I6FQF0pIWTzBuW+udrAaJr+A6JA3+p62ADZjeFthKxqxKHZlUxQmkKeEWvaKLJdwpc5u6g==", "requires": { - "no-case": "^2.2.0" + "no-case": "^3.0.2", + "tslib": "^1.10.0" + }, + "dependencies": { + "tslib": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", + "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==" + } } }, "dotenv": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.1.0.tgz", - "integrity": "sha512-GUE3gqcDCaMltj2++g6bRQ5rBJWtkWTmqmD0fo1RnnMuUqHNCt2oTPeDnS9n6fKYvlhn7AeBkb38lymBtWBQdA==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz", + "integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==", "dev": true }, "ecc-jsbn": { @@ -1569,6 +2033,7 @@ "version": "1.13.0", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.13.0.tgz", "integrity": "sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg==", + "dev": true, "requires": { "es-to-primitive": "^1.2.0", "function-bind": "^1.1.1", @@ -1582,6 +2047,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", + "dev": true, "requires": { "is-callable": "^1.1.4", "is-date-object": "^1.0.1", @@ -1615,9 +2081,9 @@ "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" }, "eslint": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.5.1.tgz", - "integrity": "sha512-32h99BoLYStT1iq1v2P9uwpyznQ4M2jRiFB6acitKz52Gqn+vPaMDUTB1bYi1WN4Nquj2w+t+bimYUG83DC55A==", + "version": "6.7.2", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.7.2.tgz", + "integrity": "sha512-qMlSWJaCSxDFr8fBPvJM9kJwbazrhNcBU3+DszDW1OlEwKBBRWsJc7NJFelvwQpanHCR14cOLD41x8Eqvo3Nng==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", @@ -1627,19 +2093,19 @@ "debug": "^4.0.1", "doctrine": "^3.0.0", "eslint-scope": "^5.0.0", - "eslint-utils": "^1.4.2", + "eslint-utils": "^1.4.3", "eslint-visitor-keys": "^1.1.0", - "espree": "^6.1.1", + "espree": "^6.1.2", "esquery": "^1.0.1", "esutils": "^2.0.2", "file-entry-cache": "^5.0.1", "functional-red-black-tree": "^1.0.1", "glob-parent": "^5.0.0", - "globals": "^11.7.0", + "globals": "^12.1.0", "ignore": "^4.0.6", "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", - "inquirer": "^6.4.1", + "inquirer": "^7.0.0", "is-glob": "^4.0.0", "js-yaml": "^3.13.1", "json-stable-stringify-without-jsonify": "^1.0.1", @@ -1648,7 +2114,7 @@ "minimatch": "^3.0.4", "mkdirp": "^0.5.1", "natural-compare": "^1.4.0", - "optionator": "^0.8.2", + "optionator": "^0.8.3", "progress": "^2.0.0", "regexpp": "^2.0.1", "semver": "^6.1.2", @@ -1668,54 +2134,26 @@ "ms": "^2.1.1" } }, - "eslint-scope": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.0.0.tgz", - "integrity": "sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw==", + "globals": { + "version": "12.3.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.3.0.tgz", + "integrity": "sha512-wAfjdLgFsPZsklLJvOBUBmzYE8/CwhEqSBEMRXA3qxIiNtyqvjYurAtIfDh6chlEPUfmTY3MnZh5Hfh4q0UlIw==", "dev": true, "requires": { - "esrecurse": "^4.1.0", - "estraverse": "^4.1.1" + "type-fest": "^0.8.1" } }, - "eslint-visitor-keys": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz", - "integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==", - "dev": true - }, - "inquirer": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.5.2.tgz", - "integrity": "sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ==", - "dev": true, - "requires": { - "ansi-escapes": "^3.2.0", - "chalk": "^2.4.2", - "cli-cursor": "^2.1.0", - "cli-width": "^2.0.0", - "external-editor": "^3.0.3", - "figures": "^2.0.0", - "lodash": "^4.17.12", - "mute-stream": "0.0.7", - "run-async": "^2.2.0", - "rxjs": "^6.4.0", - "string-width": "^2.1.0", - "strip-ansi": "^5.1.0", - "through": "^2.3.6" - } - }, - "mute-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", - "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", - "dev": true - }, "semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true + }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true } } }, @@ -1731,9 +2169,9 @@ } }, "eslint-config-prettier": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-6.4.0.tgz", - "integrity": "sha512-YrKucoFdc7SEko5Sxe4r6ixqXPDP1tunGw91POeZTTRKItf/AMFYt/YLEQtZMkR2LVpAVhcAcZgcWpm1oGPW7w==", + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-6.7.0.tgz", + "integrity": "sha512-FamQVKM3jjUVwhG4hEMnbtsq7xOIDm+SY5iBPfR8gKsJoAB2IQnNF+bk1+8Fy44Nq7PPJaLvkRxILYdJWoguKQ==", "dev": true, "requires": { "get-stdin": "^6.0.0" @@ -1767,12 +2205,12 @@ } }, "eslint-module-utils": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.4.1.tgz", - "integrity": "sha512-H6DOj+ejw7Tesdgbfs4jeS4YMFrT8uI8xwd1gtQqXssaR0EQ26L+2O/w6wkYFy2MymON0fTwHmXBvvfLNZVZEw==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.5.0.tgz", + "integrity": "sha512-kCo8pZaNz2dsAW7nCUjuVoI11EBXXpIzfNxmaoLhXoRDOnqXLC4iSGVRdZPhOitfbdEfMEfKOiENaK6wDPZEGw==", "dev": true, "requires": { - "debug": "^2.6.8", + "debug": "^2.6.9", "pkg-dir": "^2.0.0" }, "dependencies": { @@ -1785,83 +2223,32 @@ "ms": "2.0.0" } }, - "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "dev": true, - "requires": { - "locate-path": "^2.0.0" - } - }, - "locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", - "dev": true, - "requires": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" - } - }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true - }, - "p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", - "dev": true, - "requires": { - "p-try": "^1.0.0" - } - }, - "p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", - "dev": true, - "requires": { - "p-limit": "^1.1.0" - } - }, - "p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", - "dev": true - }, - "pkg-dir": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", - "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", - "dev": true, - "requires": { - "find-up": "^2.1.0" - } } } }, "eslint-plugin-import": { - "version": "2.18.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.18.2.tgz", - "integrity": "sha512-5ohpsHAiUBRNaBWAF08izwUGlbrJoJJ+W9/TBwsGoR1MnlgfwMIKrFeSjWbt6moabiXW9xNvtFz+97KHRfI4HQ==", + "version": "2.19.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.19.1.tgz", + "integrity": "sha512-x68131aKoCZlCae7rDXKSAQmbT5DQuManyXo2sK6fJJ0aK5CWAkv6A6HJZGgqC8IhjQxYPgo6/IY4Oz8AFsbBw==", "dev": true, "requires": { "array-includes": "^3.0.3", + "array.prototype.flat": "^1.2.1", "contains-path": "^0.1.0", "debug": "^2.6.9", "doctrine": "1.5.0", "eslint-import-resolver-node": "^0.3.2", - "eslint-module-utils": "^2.4.0", + "eslint-module-utils": "^2.4.1", "has": "^1.0.3", "minimatch": "^3.0.4", "object.values": "^1.1.0", "read-pkg-up": "^2.0.0", - "resolve": "^1.11.0" + "resolve": "^1.12.0" }, "dependencies": { "debug": { @@ -1892,18 +2279,6 @@ "locate-path": "^2.0.0" } }, - "load-json-file": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", - "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", - "strip-bom": "^3.0.0" - } - }, "locate-path": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", @@ -1944,41 +2319,6 @@ "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", "dev": true }, - "parse-json": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", - "dev": true, - "requires": { - "error-ex": "^1.2.0" - } - }, - "path-type": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", - "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", - "dev": true, - "requires": { - "pify": "^2.0.0" - } - }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true - }, - "read-pkg": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", - "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", - "dev": true, - "requires": { - "load-json-file": "^2.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^2.0.0" - } - }, "read-pkg-up": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", @@ -2002,37 +2342,29 @@ } }, "eslint-utils": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.2.tgz", - "integrity": "sha512-eAZS2sEUMlIeCjBeubdj45dmBHQwPHWyBcT1VSYB7o9x9WRRqKxyUoiXlRjyAwzN7YEzHJlYg0NmzDRWx6GP4Q==", + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz", + "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==", "dev": true, "requires": { - "eslint-visitor-keys": "^1.0.0" + "eslint-visitor-keys": "^1.1.0" } }, "eslint-visitor-keys": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", - "integrity": "sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz", + "integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==", "dev": true }, "espree": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-6.1.1.tgz", - "integrity": "sha512-EYbr8XZUhWbYCqQRW0duU5LxzL5bETN6AjKBGy1302qqzPaCH10QbRg3Wvco79Z8x9WbiE8HYB4e75xl6qUYvQ==", + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/espree/-/espree-6.1.2.tgz", + "integrity": "sha512-2iUPuuPP+yW1PZaMSDM9eyVf8D5P0Hi8h83YtZ5bPc/zHYjII5khoixIUTMO794NOY8F/ThF1Bo8ncZILarUTA==", "dev": true, "requires": { - "acorn": "^7.0.0", - "acorn-jsx": "^5.0.2", + "acorn": "^7.1.0", + "acorn-jsx": "^5.1.0", "eslint-visitor-keys": "^1.1.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz", - "integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==", - "dev": true - } } }, "esprima": { @@ -2059,9 +2391,9 @@ } }, "estraverse": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", - "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", "dev": true }, "esutils": { @@ -2111,9 +2443,9 @@ "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=" }, "fast-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.1.0.tgz", - "integrity": "sha512-TrUz3THiq2Vy3bjfQUB2wNyPdGBeGmdjbzzBLhfHN4YFurYptCKwGq/TfiRavbGywFRzY6U2CdmQ1zmsY5yYaw==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.1.1.tgz", + "integrity": "sha512-nTCREpBY8w8r+boyFYAx21iL6faSsQynliPHM4Uf56SbkyohCNxpVPEH9xrF5TXKy+IsjkPUHDKiUkzBVRXn9g==", "dev": true, "requires": { "@nodelib/fs.stat": "^2.0.2", @@ -2149,12 +2481,13 @@ "integrity": "sha512-mv8YA9RruB4C5QawPaD29rEVx3N97ZTyNrE4DAfbhuo6tpcMdKnPVo8MlyT3RP5uPcg5M14bEJBq7kjFf4kAWg==" }, "figures": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", - "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", + "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", "dev": true, "requires": { - "escape-string-regexp": "^1.0.5" + "escape-string-regexp": "^1.0.5", + "object-assign": "^4.1.0" } }, "file-entry-cache": { @@ -2242,6 +2575,29 @@ "integrity": "sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg==", "dev": true }, + "follow-redirects": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", + "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", + "requires": { + "debug": "=3.1.0" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, "foreground-child": { "version": "1.5.6", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-1.5.6.tgz", @@ -2368,11 +2724,6 @@ } } }, - "generic-pool": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.7.1.tgz", - "integrity": "sha512-ug6DAZoNgWm6q5KhPFA+hzXfBLFQu5sTXxPpv44DmE0A2g+CiHoq9LTVdkXpZMkYVMoGw83F6W+WT0h0MFMK/w==" - }, "get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", @@ -2385,9 +2736,9 @@ "dev": true }, "get-own-enumerable-property-symbols": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.1.tgz", - "integrity": "sha512-09/VS4iek66Dh2bctjRkowueRJbY1JDGR1L/zRxO1Qk8Uxs6PnqaNSqalpizPT+CDjre3hnEsuzvhgomz9qYrA==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz", + "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==", "dev": true }, "get-stdin": { @@ -2477,9 +2828,9 @@ "dev": true }, "handlebars": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.4.3.tgz", - "integrity": "sha512-B0W4A2U1ww3q7VVthTKfh+epHx+q4mCt6iK+zEAzbMBpWQAwxCeKxEGpj/1oQTpzPXDNSOG7hmG14TsISH50yw==", + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.5.3.tgz", + "integrity": "sha512-3yPecJoJHK/4c6aZhSvxOyG4vJKDshV36VHp0iVCDVh7o9w2vwi3NSnL2MMPj3YdduqaBcu7cGbggJQM0br9xA==", "requires": { "neo-async": "^2.6.0", "optimist": "^0.6.1", @@ -2555,18 +2906,28 @@ "dev": true }, "header-case": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/header-case/-/header-case-1.0.1.tgz", - "integrity": "sha1-lTWXMZfBRLCWE81l0xfvGZY70C0=", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/header-case/-/header-case-2.0.2.tgz", + "integrity": "sha512-DkrKDkNEXG3ZC3urlbt+O9j9qbwFvJwDB1PSKBQqZLVbh2wr7PKpfjGWo/Dw9cpG1IqZM6QTsnVsB3FwdCuEkg==", "requires": { - "no-case": "^2.2.0", - "upper-case": "^1.1.3" + "capital-case": "^1.0.2", + "tslib": "^1.10.0" + }, + "dependencies": { + "tslib": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", + "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==" + } } }, "highlight.js": { - "version": "9.15.10", - "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.15.10.tgz", - "integrity": "sha512-RoV7OkQm0T3os3Dd2VHLNMoaoDVx77Wygln3n9l5YV172XonWG6rgQD3XnF/BuFFZw9A0TJgmMSO8FEWQgvcXw==" + "version": "9.17.1", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.17.1.tgz", + "integrity": "sha512-TA2/doAur5Ol8+iM3Ov7qy3jYcr/QiJ2eDTdRF4dfbjG7AaaB99J5G+zSl11ljbl6cIcahgPY6SKb3sC3EJ0fw==", + "requires": { + "handlebars": "^4.5.3" + } }, "hosted-git-info": { "version": "2.7.1", @@ -2595,29 +2956,96 @@ } }, "husky": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/husky/-/husky-3.0.8.tgz", - "integrity": "sha512-HFOsgcyrX3qe/rBuqyTt+P4Gxn5P0seJmr215LAZ/vnwK3jWB3r0ck7swbzGRUbufCf9w/lgHPVbF/YXQALgfQ==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/husky/-/husky-3.1.0.tgz", + "integrity": "sha512-FJkPoHHB+6s4a+jwPqBudBDvYZsoQW5/HBuMSehC8qDiCe50kpcxeqFoDSlow+9I6wg47YxBoT3WxaURlrDIIQ==", "dev": true, "requires": { "chalk": "^2.4.2", + "ci-info": "^2.0.0", "cosmiconfig": "^5.2.1", "execa": "^1.0.0", "get-stdin": "^7.0.0", - "is-ci": "^2.0.0", "opencollective-postinstall": "^2.0.2", "pkg-dir": "^4.2.0", "please-upgrade-node": "^3.2.0", - "read-pkg": "^5.1.1", + "read-pkg": "^5.2.0", "run-node": "^1.0.0", "slash": "^3.0.0" }, "dependencies": { + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, "get-stdin": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-7.0.0.tgz", "integrity": "sha512-zRKcywvrXlXsA0v0i9Io4KDRaAw7+a1ZpjRwl9Wox8PFlVCCHra7E9c4kqXCoCM9nR5tBkaTTZRBoCm60bFqTQ==", "dev": true + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "parse-json": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.0.0.tgz", + "integrity": "sha512-OOY5b7PAEFV0E2Fir1KOkxchnZNCdowAJgQ5NuxjpBKTRP3pQhwkrkxqQjeoKJ+fO7bCpmIZaogI4eZGDMEGOw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1", + "lines-and-columns": "^1.1.6" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "requires": { + "find-up": "^4.0.0" + } + }, + "read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "dev": true, + "requires": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + } } } }, @@ -2649,9 +3077,9 @@ } }, "import-fresh": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.1.0.tgz", - "integrity": "sha512-PpuksHKGt8rXfWEr9m9EHIpgyyaltBy8+eF6GJM0QCAxMgxCfucMF3mjecK2QsJr0amJW7gTqh5/wht0z2UhEQ==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz", + "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==", "dev": true, "requires": { "parent-module": "^1.0.0", @@ -2690,9 +3118,9 @@ "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" }, "inquirer": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.0.0.tgz", - "integrity": "sha512-rSdC7zelHdRQFkWnhsMu2+2SO41mpv2oF2zy4tMhmiLWkcKbOAs87fWAJhVXttKVwhdZvymvnuM95EyEXg2/tQ==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.0.1.tgz", + "integrity": "sha512-V1FFQ3TIO15det8PijPLFR9M9baSlnRs9nL7zWu1MNVA2T9YVl9ZbrHJhYs7e9X8jeMZ3lr2JH/rdHFgNCBdYw==", "requires": { "ansi-escapes": "^4.2.1", "chalk": "^2.4.2", @@ -2703,20 +3131,25 @@ "lodash": "^4.17.15", "mute-stream": "0.0.8", "run-async": "^2.2.0", - "rxjs": "^6.4.0", + "rxjs": "^6.5.3", "string-width": "^4.1.0", "strip-ansi": "^5.1.0", "through": "^2.3.6" }, "dependencies": { "ansi-escapes": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.2.1.tgz", - "integrity": "sha512-Cg3ymMAdN10wOk/VYfLV7KCQyv7EDirJ64500sU7n9UlmioEtDuU5Gd+hj73hXSU/ex7tHJSssmyftDdkMLO8Q==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.0.tgz", + "integrity": "sha512-EiYhwo0v255HUL6eDyuLrXEkTi7WwVCLAw+SeOQ7M7qdun1z1pum4DEm/nuqIVbPvi9RPPc9k9LbyBv6H0DwVg==", "requires": { - "type-fest": "^0.5.2" + "type-fest": "^0.8.1" } }, + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==" + }, "cli-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", @@ -2731,9 +3164,9 @@ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" }, "figures": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-3.0.0.tgz", - "integrity": "sha512-HKri+WoWoUgr83pehn/SIgLOMZ9nAWC6dcGj26RY2R4F50u4+RTUz0RCrUlOV3nKRAICW1UGzyb+kcX2qK1S/g==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.1.0.tgz", + "integrity": "sha512-ravh8VRXqHuMvZt/d8GblBeqDMkdJMBdv/2KntFH+ra5MXkO7nxNKpzQ3n6QD/2da1kH0aWmNISdvhM7gl2gVg==", "requires": { "escape-string-regexp": "^1.0.5" } @@ -2770,20 +3203,38 @@ "signal-exit": "^3.0.2" } }, + "rxjs": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.3.tgz", + "integrity": "sha512-wuYsAYYFdWTAnAaPoKGNhfpWwKZbJW+HgAJ+mImp+Epl7BG8oNWBCTyRM8gba9k4lk8BgWdoYm21Mo/RYhhbgA==", + "requires": { + "tslib": "^1.9.0" + } + }, "string-width": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.1.0.tgz", - "integrity": "sha512-NrX+1dVVh+6Y9dnQ19pR0pP4FiEIlUvdTGn8pw6CKTNq5sgib2nIhmUNT5TAmhWmvKr3WcxBcP3E8nWezuipuQ==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", "requires": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^5.2.0" + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "requires": { + "ansi-regex": "^5.0.0" + } + } } }, "type-fest": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.5.2.tgz", - "integrity": "sha512-DWkS49EQKVX//Tbupb9TFa19c7+MK1XmzkrZUR8TAktmE/DizXoaoJV6TZ/tSIPXipqNiRI6CyAe7x69Jb6RSw==" + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==" } } }, @@ -2796,23 +3247,13 @@ "is-buffer": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz", - "integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==", - "dev": true + "integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==" }, "is-callable": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==" }, - "is-ci": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", - "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", - "dev": true, - "requires": { - "ci-info": "^2.0.0" - } - }, "is-date-object": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", @@ -2844,14 +3285,6 @@ "is-extglob": "^2.1.1" } }, - "is-lower-case": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/is-lower-case/-/is-lower-case-1.1.3.tgz", - "integrity": "sha1-fhR75HaNxGbbO/shzGCzHmrWk5M=", - "requires": { - "lower-case": "^1.1.0" - } - }, "is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -2923,14 +3356,6 @@ "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" }, - "is-upper-case": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-upper-case/-/is-upper-case-1.1.2.tgz", - "integrity": "sha1-jQsfp+eTOh5YSDYA7H2WYcuvdW8=", - "requires": { - "upper-case": "^1.1.0" - } - }, "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", @@ -3064,6 +3489,11 @@ "esprima": "^4.0.0" } }, + "jsbi": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/jsbi/-/jsbi-3.1.1.tgz", + "integrity": "sha512-+HQESPaV0mRiH614z4JPVPAftcRC2p53x92lySPzUzFwJbJTMpzHz8OYUkcXPN3fOcHUe0NdVcHnCtX/1+eCrA==" + }, "jsbn": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", @@ -3163,9 +3593,9 @@ "dev": true }, "lint-staged": { - "version": "9.4.2", - "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-9.4.2.tgz", - "integrity": "sha512-OFyGokJSWTn2M6vngnlLXjaHhi8n83VIZZ5/1Z26SULRUWgR3ITWpAEQC9Pnm3MC/EpCxlwts/mQWDHNji2+zA==", + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-9.5.0.tgz", + "integrity": "sha512-nawMob9cb/G1J98nb8v3VC/E8rcX1rryUYXVZ69aT9kde6YWX+uvNOEHY5yf2gcWcTJGiD0kqXmCnS3oD75GIA==", "dev": true, "requires": { "chalk": "^2.4.2", @@ -3236,12 +3666,6 @@ "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", "dev": true }, - "mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true - }, "npm-run-path": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-3.1.0.tgz", @@ -3251,15 +3675,6 @@ "path-key": "^3.0.0" } }, - "onetime": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.0.tgz", - "integrity": "sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==", - "dev": true, - "requires": { - "mimic-fn": "^2.1.0" - } - }, "p-finally": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-2.0.1.tgz", @@ -3267,9 +3682,9 @@ "dev": true }, "path-key": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.0.tgz", - "integrity": "sha512-8cChqz0RP6SHJkMt48FW0A7+qUOn+OsnOsVtzI59tZ8m+5bCSk7hzwET0pulwOM2YMn9J1efb07KB9l9f30SGg==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true }, "shebang-command": { @@ -3288,9 +3703,9 @@ "dev": true }, "which": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.1.tgz", - "integrity": "sha512-N7GBZOTswtB9lkQBZA4+zAXrjEIWAUOB93AvzUiudRzRxhUdLURQ7D/gAIMY1gatT/LTbmbcv8SiYazy3eYB7w==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, "requires": { "isexe": "^2.0.0" @@ -3370,16 +3785,6 @@ "supports-color": "^2.0.0" } }, - "figures": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", - "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", - "dev": true, - "requires": { - "escape-string-regexp": "^1.0.5", - "object-assign": "^4.1.0" - } - }, "indent-string": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", @@ -3422,6 +3827,17 @@ "cli-cursor": "^2.1.0", "date-fns": "^1.27.2", "figures": "^2.0.0" + }, + "dependencies": { + "figures": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", + "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + } + } } }, "load-json-file": { @@ -3490,16 +3906,18 @@ "dev": true }, "lower-case": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz", - "integrity": "sha1-miyr0bno4K6ZOkv31YdcOcQujqw=" - }, - "lower-case-first": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/lower-case-first/-/lower-case-first-1.0.2.tgz", - "integrity": "sha1-5dp8JvKacHO+AtUrrJmA5ZIq36E=", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.1.tgz", + "integrity": "sha512-LiWgfDLLb1dwbFQZsSglpRj+1ctGnayXz3Uv0/WO8n558JycT5fg6zkNcnW0G68Nn0aEldTFeEfmjCfmqry/rQ==", "requires": { - "lower-case": "^1.1.2" + "tslib": "^1.10.0" + }, + "dependencies": { + "tslib": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", + "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==" + } } }, "lru-cache": { @@ -3595,9 +4013,9 @@ } }, "mimic-fn": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", - "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", "dev": true }, "minimatch": { @@ -3653,9 +4071,9 @@ } }, "mocha": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-6.2.1.tgz", - "integrity": "sha512-VCcWkLHwk79NYQc8cxhkmI8IigTIhsCwZ6RTxQsqK6go4UvEhzJkYuHm8B2YtlSxcYq2fY+ucr4JBwoD6ci80A==", + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-6.2.2.tgz", + "integrity": "sha512-FgDS9Re79yU1xz5d+C4rv1G7QagNGHZ+iXF81hO8zY35YZZcLEsJVfFolfsqKFWunATEvNzMK0r/CwWd/szO9A==", "dev": true, "requires": { "ansi-colors": "3.2.3", @@ -3783,13 +4201,23 @@ "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" }, "mssql": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/mssql/-/mssql-5.1.0.tgz", - "integrity": "sha512-eHrqRWCEBaXo48y2ZBaDleFvrWm2vYm6dNm1ci0XLYxm6kUb4KRsvjl74iKFhfYyuF9z6qzmTe/QmoQk+YVcVw==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/mssql/-/mssql-6.0.1.tgz", + "integrity": "sha512-7oPhbQjotFJBgMPlzLmPwWlnrryxrDltjCNCD9BK7Df7TA9wc6Mb/0Bcx04NJyHCMAhw8C/iWjbJoeDyUfRNUA==", "requires": { - "debug": "^3.2.6", - "generic-pool": "^3.6.1", - "tedious": "^4.2.0" + "debug": "^4", + "tarn": "^1.1.5", + "tedious": "^6.6.2" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "requires": { + "ms": "^2.1.1" + } + } } }, "mute-stream": { @@ -3888,11 +4316,19 @@ } }, "no-case": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz", - "integrity": "sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.2.tgz", + "integrity": "sha512-Yber3mEOA3T9+as7Z70TJUQCUPRmmq6s8NmsZX5aSB1qk+Mt+3a5JVPpnAnONUShLTkMDF4PJY3h0GKlXdRTNA==", "requires": { - "lower-case": "^1.1.1" + "lower-case": "^2.0.1", + "tslib": "^1.10.0" + }, + "dependencies": { + "tslib": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", + "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==" + } } }, "node-environment-flags": { @@ -3990,14 +4426,22 @@ "dev": true }, "npm-bundled": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.0.6.tgz", - "integrity": "sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g==" + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.1.tgz", + "integrity": "sha512-gqkfgGePhTpAEgUsGEgcq1rqPXA+tv/aVBlgEzfXwA1yiUJF7xtEt3CtVwOjNYQOVknDk0F20w58Fnm3EtG0fA==", + "requires": { + "npm-normalize-package-bin": "^1.0.1" + } + }, + "npm-normalize-package-bin": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", + "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==" }, "npm-packlist": { - "version": "1.4.6", - "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.6.tgz", - "integrity": "sha512-u65uQdb+qwtGvEJh/DgQgW1Xg7sqeNbmxYyrvlNznaVTjV3E5P6F/EFjM+BVHXl7JJlsdG8A64M0XI8FI/IOlg==", + "version": "1.4.7", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.7.tgz", + "integrity": "sha512-vAj7dIkp5NhieaGZxBJB8fF4R0078rqsmhJcAfXZ6O7JJhjhPK96n5Ry1oZcfLXgfun0GWTZPOxaEyqv8GBykQ==", "requires": { "ignore-walk": "^3.0.1", "npm-bundled": "^1.0.1" @@ -4130,10 +4574,9 @@ "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" }, "object-inspect": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.6.0.tgz", - "integrity": "sha512-GJzfBZ6DgDAmnuaM3104jR4s1Myxr3Y3zfIyN4z3UdqN69oSRacNK8UhnobDdC+7J2AHCjGwxQubNJfE70SXXQ==", - "dev": true + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz", + "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==" }, "object-keys": { "version": "1.1.1", @@ -4144,7 +4587,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", - "dev": true, "requires": { "define-properties": "^1.1.2", "function-bind": "^1.1.1", @@ -4165,24 +4607,97 @@ } }, "object.getownpropertydescriptors": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz", - "integrity": "sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY=", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.0.tgz", + "integrity": "sha512-Z53Oah9A3TdLoblT7VKJaTDdXdT+lQO+cNpKVnya5JDe9uLvzu1YyY1yFDFrcxrlRgWrEFH0jJtD/IbuwjcEVg==", "requires": { - "define-properties": "^1.1.2", - "es-abstract": "^1.5.1" + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1" + }, + "dependencies": { + "es-abstract": { + "version": "1.17.0-next.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.0-next.1.tgz", + "integrity": "sha512-7MmGr03N7Rnuid6+wyhD9sHNE2n4tFSwExnU2lQl3lIo2ShXWGePY80zYaoMOmILWv57H0amMjZGHNzzGG70Rw==", + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.1.4", + "is-regex": "^1.0.4", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimleft": "^2.1.0", + "string.prototype.trimright": "^2.1.0" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==" + } } }, "object.values": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.0.tgz", - "integrity": "sha512-8mf0nKLAoFX6VlNVdhGj31SVYpaNFtUnuoOXWyFEstsWRgU837AK+JYM0iAxwkSzGRbwn8cbFmgbyxj1j4VbXg==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.1.tgz", + "integrity": "sha512-WTa54g2K8iu0kmS/us18jEmdv1a4Wi//BZ/DTVYEcH0XhLM5NYdpDHja3gt57VrZLcNAO2WGA+KpWsDBaHt6eA==", "dev": true, "requires": { "define-properties": "^1.1.3", - "es-abstract": "^1.12.0", + "es-abstract": "^1.17.0-next.1", "function-bind": "^1.1.1", "has": "^1.0.3" + }, + "dependencies": { + "es-abstract": { + "version": "1.17.0-next.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.0-next.1.tgz", + "integrity": "sha512-7MmGr03N7Rnuid6+wyhD9sHNE2n4tFSwExnU2lQl3lIo2ShXWGePY80zYaoMOmILWv57H0amMjZGHNzzGG70Rw==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.1.4", + "is-regex": "^1.0.4", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimleft": "^2.1.0", + "string.prototype.trimright": "^2.1.0" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "dev": true + } } }, "once": { @@ -4194,12 +4709,12 @@ } }, "onetime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", - "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.0.tgz", + "integrity": "sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==", "dev": true, "requires": { - "mimic-fn": "^1.0.0" + "mimic-fn": "^2.1.0" } }, "opencollective-postinstall": { @@ -4215,27 +4730,20 @@ "requires": { "minimist": "~0.0.1", "wordwrap": "~0.0.2" - }, - "dependencies": { - "wordwrap": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", - "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=" - } } }, "optionator": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", - "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", "dev": true, "requires": { "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.4", + "fast-levenshtein": "~2.0.6", "levn": "~0.3.0", "prelude-ls": "~1.1.2", "type-check": "~0.3.2", - "wordwrap": "~1.0.0" + "word-wrap": "~1.2.3" } }, "os-homedir": { @@ -4311,11 +4819,19 @@ "integrity": "sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==" }, "param-case": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/param-case/-/param-case-2.1.1.tgz", - "integrity": "sha1-35T9jPZTHs915r75oIWPvHK+Ikc=", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.2.tgz", + "integrity": "sha512-9UF3HbbJwzBVJlFFOvfBpWUpGFMX01q3dKavdRyv+71HI3GO4UTQIiuG51pckuqPlHzx1jmUijim8J282goaLg==", "requires": { - "no-case": "^2.2.0" + "dot-case": "^3.0.2", + "tslib": "^1.10.0" + }, + "dependencies": { + "tslib": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", + "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==" + } } }, "parent-module": { @@ -4343,25 +4859,48 @@ } }, "parse5": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-4.0.0.tgz", - "integrity": "sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA==" + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", + "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==" + }, + "parse5-htmlparser2-tree-adapter": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-5.1.1.tgz", + "integrity": "sha512-CF+TKjXqoqyDwHqBhFQ+3l5t83xYi6fVT1tQNg+Ye0JRLnTxWvIroCjEp1A0k4lneHNBGnICUf0cfYVYGEazqw==", + "requires": { + "parse5": "^5.1.1" + } }, "pascal-case": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-2.0.1.tgz", - "integrity": "sha1-LVeNNFX2YNpl7KGO+VtODekSdh4=", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.0.tgz", + "integrity": "sha512-7cINxTsRAFym4dLVMdObWx2wr/FjVz8BfCdLPC069kAFLal/5dZhxObpAIM40GwZ/Xik1J37z+Nw6/TVy5fmIg==", "requires": { - "camel-case": "^3.0.0", - "upper-case-first": "^1.1.0" + "no-case": "^3.0.2", + "tslib": "^1.10.0" + }, + "dependencies": { + "tslib": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", + "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==" + } } }, "path-case": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/path-case/-/path-case-2.1.1.tgz", - "integrity": "sha1-lLgDfDctP+KQbkZbtF4l0ibo7qU=", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/path-case/-/path-case-3.0.2.tgz", + "integrity": "sha512-vTXKSmzkegC4tBZTogrHleuSEhdMgtY3+vxqN0wFM8TmVs8+0xy+oh1+07SuxYzDlXl/FO8jwEtRfAQ7G+jxCg==", "requires": { - "no-case": "^2.2.0" + "dot-case": "^3.0.2", + "tslib": "^1.10.0" + }, + "dependencies": { + "tslib": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", + "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==" + } } }, "path-exists": { @@ -4424,14 +4963,14 @@ "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" }, "pg": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/pg/-/pg-7.12.1.tgz", - "integrity": "sha512-l1UuyfEvoswYfcUe6k+JaxiN+5vkOgYcVSbSuw3FvdLqDbaoa2RJo1zfJKfPsSYPFVERd4GHvX3s2PjG1asSDA==", + "version": "7.15.0", + "resolved": "https://registry.npmjs.org/pg/-/pg-7.15.0.tgz", + "integrity": "sha512-eHE1n/98QB/T8J9Mc9AKTIC4yzo2Q7C2MT+IHp9TZR18nobqpsH8dmDO33dUhZ8A5Nfu6tC1TIkjrT3JoWHcOw==", "requires": { "buffer-writer": "2.0.0", "packet-reader": "1.0.0", "pg-connection-string": "0.1.3", - "pg-pool": "^2.0.4", + "pg-pool": "^2.0.7", "pg-types": "^2.1.0", "pgpass": "1.x", "semver": "4.3.2" @@ -4473,9 +5012,9 @@ } }, "picomatch": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.0.7.tgz", - "integrity": "sha512-oLHIdio3tZ0qH76NybpeneBhYVj0QFTfXEFTc/B3zKQspYfYYkWYgFsmzo+4kvId/bQRcNkVeguI3y+CD22BtA==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.1.1.tgz", + "integrity": "sha512-OYMyqkKzK7blWO/+XZYP6w8hH0LDvkBvdvKukti+7kqYFCiEAk+gI3DWnryapc0Dau05ugGTy0foQ6mqn4AHYA==", "dev": true }, "pify": { @@ -4485,46 +5024,55 @@ "dev": true }, "pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", + "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", "dev": true, "requires": { - "find-up": "^4.0.0" + "find-up": "^2.1.0" }, "dependencies": { "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", "dev": true, "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" + "locate-path": "^2.0.0" } }, "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", "dev": true, "requires": { - "p-locate": "^4.1.0" + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" } }, "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", "dev": true, "requires": { - "p-limit": "^2.2.0" + "p-limit": "^1.1.0" } }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", "dev": true } } @@ -4573,9 +5121,9 @@ "dev": true }, "prettier": { - "version": "1.18.2", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.18.2.tgz", - "integrity": "sha512-OeHeMc0JhFE9idD4ZdtNibzY0+TPHSpSSb9h8FqtP+YnoZZ1sl8Vc9b1sasjfymH3SonAF4QcA2+mzHPhMvIiw==" + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz", + "integrity": "sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==" }, "progress": { "version": "2.0.3", @@ -4638,28 +5186,51 @@ } }, "read-pkg": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", - "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", + "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", "dev": true, "requires": { - "@types/normalize-package-data": "^2.4.0", - "normalize-package-data": "^2.5.0", - "parse-json": "^5.0.0", - "type-fest": "^0.6.0" + "load-json-file": "^2.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^2.0.0" }, "dependencies": { - "parse-json": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.0.0.tgz", - "integrity": "sha512-OOY5b7PAEFV0E2Fir1KOkxchnZNCdowAJgQ5NuxjpBKTRP3pQhwkrkxqQjeoKJ+fO7bCpmIZaogI4eZGDMEGOw==", + "load-json-file": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", + "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", "dev": true, "requires": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1", - "lines-and-columns": "^1.1.6" + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "strip-bom": "^3.0.0" } + }, + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true, + "requires": { + "error-ex": "^1.2.0" + } + }, + "path-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", + "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", + "dev": true, + "requires": { + "pify": "^2.0.0" + } + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true } } }, @@ -4772,9 +5343,9 @@ "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" }, "resolve": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.0.tgz", - "integrity": "sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==", + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.14.0.tgz", + "integrity": "sha512-uviWSi5N67j3t3UKFxej1loCH0VZn5XuqdNxoLShPcYPw6cUZn74K1VRj+9myynRX03bxIBEkwlkob/ujLsJVw==", "dev": true, "requires": { "path-parse": "^1.0.6" @@ -4794,6 +5365,23 @@ "requires": { "onetime": "^2.0.0", "signal-exit": "^3.0.2" + }, + "dependencies": { + "mimic-fn": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", + "dev": true + }, + "onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "dev": true, + "requires": { + "mimic-fn": "^1.0.0" + } + } } }, "reusify": { @@ -4835,6 +5423,7 @@ "version": "6.5.2", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.2.tgz", "integrity": "sha512-HUb7j3kvb7p7eCUHE3FqjoDsC1xfZQ4AHFWfTKSpZ+sAhhz5X1WX0ZuUqWbzB2QhSLp3DoLUG+hMdEDKqWo2Zg==", + "dev": true, "requires": { "tslib": "^1.9.0" } @@ -4866,12 +5455,20 @@ "dev": true }, "sentence-case": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/sentence-case/-/sentence-case-2.1.1.tgz", - "integrity": "sha1-H24t2jnBaL+S0T+G1KkYkz9mftQ=", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/sentence-case/-/sentence-case-3.0.2.tgz", + "integrity": "sha512-15UhaONq0mYjSpFHbrO2VoPjzy/3mo8nAy8/2rr32IjsUg4hCeapON4aS84YEtOL5SOccaAaopThdSPCnndFFQ==", "requires": { - "no-case": "^2.2.0", - "upper-case-first": "^1.1.2" + "no-case": "^3.0.2", + "tslib": "^1.10.0", + "upper-case-first": "^2.0.1" + }, + "dependencies": { + "tslib": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", + "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==" + } } }, "set-blocking": { @@ -4938,11 +5535,19 @@ } }, "snake-case": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-2.1.0.tgz", - "integrity": "sha1-Qb2xtz8w7GagTU4srRt2OH1NbZ8=", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.2.tgz", + "integrity": "sha512-1fRJdasXJTcsrGnUkDsnKNjHoP9NGclbIkYyY6Vv0vBVgz32rqhPFPg/Y0yIP4hwOd41Dh8rocCRHjNIuK4EZg==", "requires": { - "no-case": "^2.2.0" + "dot-case": "^3.0.2", + "tslib": "^1.10.0" + }, + "dependencies": { + "tslib": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", + "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==" + } } }, "source-map": { @@ -4951,9 +5556,9 @@ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" }, "source-map-support": { - "version": "0.5.13", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", - "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.16.tgz", + "integrity": "sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ==", "dev": true, "requires": { "buffer-from": "^1.0.0", @@ -5031,9 +5636,9 @@ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" }, "sqlite3": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/sqlite3/-/sqlite3-4.1.0.tgz", - "integrity": "sha512-RvqoKxq+8pDHsJo7aXxsFR18i+dU2Wp5o12qAJOV5LNcDt+fgJsc2QKKg3sIRfXrN9ZjzY1T7SNe/DFVqAXjaw==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/sqlite3/-/sqlite3-4.1.1.tgz", + "integrity": "sha512-CvT5XY+MWnn0HkbwVKJAyWEMfzpAPwnTiB3TobA5Mri44SrTovmmh499NPQP+gatkeOipqPlBLel7rn4E/PCQg==", "requires": { "nan": "^2.12.1", "node-pre-gyp": "^0.11.0", @@ -5090,7 +5695,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.0.tgz", "integrity": "sha512-FJ6b7EgdKxxbDxc79cOlok6Afd++TTs5szo+zJTUyow3ycrRfJVE2pq3vcN53XexvKZu/DJMDfeI/qMiZTrjTw==", - "dev": true, "requires": { "define-properties": "^1.1.3", "function-bind": "^1.1.1" @@ -5100,7 +5704,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.0.tgz", "integrity": "sha512-fXZTSV55dNBwv16uw+hh5jkghxSnc5oHq+5K/gXgizHwAvMetdAJlHqqoFC1FSDVPYWLkAKl2cxpUT41sV7nSg==", - "dev": true, "requires": { "define-properties": "^1.1.3", "function-bind": "^1.1.1" @@ -5172,15 +5775,6 @@ "has-flag": "^3.0.0" } }, - "swap-case": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/swap-case/-/swap-case-1.1.2.tgz", - "integrity": "sha1-w5IDpFhzhfrTyFCgvRvK+ggZdOM=", - "requires": { - "lower-case": "^1.1.1", - "upper-case": "^1.1.1" - } - }, "symbol-observable": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", @@ -5245,22 +5839,37 @@ } } }, + "tarn": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/tarn/-/tarn-1.1.5.tgz", + "integrity": "sha512-PMtJ3HCLAZeedWjJPgGnCvcphbCOMbtZpjKgLq3qM5Qq9aQud+XHrL0WlrlgnTyS8U+jrjGbEXprFcQrxPy52g==" + }, "tedious": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/tedious/-/tedious-4.2.0.tgz", - "integrity": "sha512-Py59XmvMcYWdjc1qyXDsbBwQE3yM8CJzuDnagjRpwjgndaBQXBULDI3D6OxKClbTNxA3qaLBFd9DjfV+is3AYA==", + "version": "6.6.2", + "resolved": "https://registry.npmjs.org/tedious/-/tedious-6.6.2.tgz", + "integrity": "sha512-0Yziuys2h66dVlqMPJpNFciQ/N2VrgwY8o8TXyj4OZBaxrvqRPeMuTKZZVBFTGOjt/J15fR0fX0HBnCHjm7QWA==", "requires": { - "adal-node": "^0.1.22", - "big-number": "1.0.0", - "bl": "^2.0.1", - "depd": "^1.1.2", - "iconv-lite": "^0.4.23", + "@azure/ms-rest-nodeauth": "2.0.2", + "@types/node": "^12.7.11", + "@types/readable-stream": "^2.3.5", + "bl": "^3.0.0", + "depd": "^2.0.0", + "iconv-lite": "^0.5.0", + "jsbi": "^3.1.1", "native-duplexpair": "^1.0.0", "punycode": "^2.1.0", - "readable-stream": "^3.0.3", - "sprintf-js": "^1.1.1" + "readable-stream": "^3.4.0", + "sprintf-js": "^1.1.2" }, "dependencies": { + "iconv-lite": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.5.0.tgz", + "integrity": "sha512-NnEhI9hIEKHOzJ4f697DMz9IQEXr/MMJ5w64vN2/4Ai+wRnvV7SBrL0KLoRlwaKVghOc7LQ5YkPLuX146b6Ydw==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, "readable-stream": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz", @@ -5328,15 +5937,6 @@ "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" }, - "title-case": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/title-case/-/title-case-2.1.1.tgz", - "integrity": "sha1-PhJyFtpY0rxb7PE3q5Ha46fNj6o=", - "requires": { - "no-case": "^2.2.0", - "upper-case": "^1.0.3" - } - }, "tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", @@ -5383,9 +5983,9 @@ "dev": true }, "ts-node": { - "version": "8.4.1", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.4.1.tgz", - "integrity": "sha512-5LpRN+mTiCs7lI5EtbXmF/HfMeCjzt7DH9CZwtkr6SywStrNQC723wG+aOWFiLNn7zT3kD/RnFqi3ZUfr4l5Qw==", + "version": "8.5.4", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.5.4.tgz", + "integrity": "sha512-izbVCRV68EasEPQ8MSIGBNK9dc/4sYJJKYA+IarMQct1RtEot6Xp0bXuClsbUSnKpg50ho+aOAx8en5c+y4OFw==", "dev": true, "requires": { "arg": "^4.1.0", @@ -5423,6 +6023,11 @@ "tslib": "^1.8.1" } }, + "tunnel": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", + "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==" + }, "tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", @@ -5458,11 +6063,11 @@ "dev": true }, "typeorm": { - "version": "0.2.19", - "resolved": "https://registry.npmjs.org/typeorm/-/typeorm-0.2.19.tgz", - "integrity": "sha512-xKVx/W41zckQ7v8WYcpRhSKpjXDKG/Jgjy0RWvYelR8ZnfyblNRL12jF4P8tIhwXv6l5t01s7HEc9lR+zb6Gtg==", + "version": "0.2.21", + "resolved": "https://registry.npmjs.org/typeorm/-/typeorm-0.2.21.tgz", + "integrity": "sha512-4abj5aFjwt4Y+Gs3VmykcjURUZwIezwPWYVMNl2swRk8/iluGZZ9Lbwd4tdzJ7ZdsgKyHsT8zf8zPZPL5jH+EQ==", "requires": { - "app-root-path": "^2.0.1", + "app-root-path": "^3.0.0", "buffer": "^5.1.0", "chalk": "^2.4.2", "cli-highlight": "^2.0.0", @@ -5530,17 +6135,17 @@ } }, "typescript": { - "version": "3.6.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.6.4.tgz", - "integrity": "sha512-unoCll1+l+YK4i4F8f22TaNVPRHcD9PA3yCuZ8g5e0qGqlVlJ/8FSateOLLSagn+Yg5+ZwuPkL8LFUc0Jcvksg==" + "version": "3.7.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.7.3.tgz", + "integrity": "sha512-Mcr/Qk7hXqFBXMN7p7Lusj1ktCBydylfQM/FZCk5glCNQJrCUKPkMHdo9R0MTFWsC/4kPFvDS0fDPvukfCkFsw==" }, "uglify-js": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.6.1.tgz", - "integrity": "sha512-+dSJLJpXBb6oMHP+Yvw8hUgElz4gLTh82XuX68QiJVTXaE5ibl6buzhNkQdYhBlIhozWOC9ge16wyRmjG4TwVQ==", + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.7.2.tgz", + "integrity": "sha512-uhRwZcANNWVLrxLfNFEdltoPNhECUR3lc+UdJoG9CBpMcSnKyWA94tc3eAujB1GcMY5Uwq8ZMp4qWpxWYDQmaA==", "optional": true, "requires": { - "commander": "2.20.0", + "commander": "~2.20.3", "source-map": "~0.6.1" } }, @@ -5555,16 +6160,33 @@ "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" }, "upper-case": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz", - "integrity": "sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg=" + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-2.0.1.tgz", + "integrity": "sha512-laAsbea9SY5osxrv7S99vH9xAaJKrw5Qpdh4ENRLcaxipjKsiaBwiAsxfa8X5mObKNTQPsupSq0J/VIxsSJe3A==", + "requires": { + "tslib": "^1.10.0" + }, + "dependencies": { + "tslib": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", + "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==" + } + } }, "upper-case-first": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/upper-case-first/-/upper-case-first-1.1.2.tgz", - "integrity": "sha1-XXm+3P8UQZUY/S7bCgUHybaFkRU=", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/upper-case-first/-/upper-case-first-2.0.1.tgz", + "integrity": "sha512-105J8XqQ+9RxW3l9gHZtgve5oaiR9TIwvmZAMAIZWRHe00T21cdvewKORTlOJf/zXW6VukuTshM+HXZNWz7N5w==", "requires": { - "upper-case": "^1.1.1" + "tslib": "^1.10.0" + }, + "dependencies": { + "tslib": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", + "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==" + } } }, "uri-js": { @@ -5648,12 +6270,17 @@ "string-width": "^1.0.2 || 2" } }, - "wordwrap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", "dev": true }, + "wordwrap": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=" + }, "wrap-ansi": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-3.0.1.tgz", @@ -5788,37 +6415,132 @@ } }, "yargs": { - "version": "14.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-14.2.0.tgz", - "integrity": "sha512-/is78VKbKs70bVZH7w4YaZea6xcJWOAwkhbR0CFuZBmYtfTYF0xjGJF43AYd8g2Uii1yJwmS5GR2vBmrc32sbg==", + "version": "15.0.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.0.2.tgz", + "integrity": "sha512-GH/X/hYt+x5hOat4LMnCqMd8r5Cv78heOMIJn1hr7QPPBqfeC6p89Y78+WB9yGDvfpCvgasfmWLzNzEioOUD9Q==", "requires": { - "cliui": "^5.0.0", + "cliui": "^6.0.0", "decamelize": "^1.2.0", - "find-up": "^3.0.0", + "find-up": "^4.1.0", "get-caller-file": "^2.0.1", "require-directory": "^2.1.1", "require-main-filename": "^2.0.0", "set-blocking": "^2.0.0", - "string-width": "^3.0.0", + "string-width": "^4.2.0", "which-module": "^2.0.0", "y18n": "^4.0.0", - "yargs-parser": "^15.0.0" + "yargs-parser": "^16.1.0" }, "dependencies": { - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==" + }, + "ansi-styles": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.0.tgz", + "integrity": "sha512-7kFQgnEaMdRtwf6uSfUnVr9gSGC7faurn+J/Mv90/W+iTtN0405/nLdopfMWwchyxhbGYl6TC4Sccn9TUkGAgg==", "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "requires": { + "p-locate": "^4.1.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "requires": { + "p-limit": "^2.2.0" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" + }, + "string-width": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + } + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "requires": { + "ansi-regex": "^5.0.0" + } + }, + "wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" } }, "yargs-parser": { - "version": "15.0.0", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-15.0.0.tgz", - "integrity": "sha512-xLTUnCMc4JhxrPEPUYD5IBR1mWCK/aT6+RJ/K29JY2y1vD+FhtgKK0AXRWvI262q3QSffAQuTouFIKUuHX89wQ==", + "version": "16.1.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-16.1.0.tgz", + "integrity": "sha512-H/V41UNZQPkUMIT5h5hiwg4QKIY1RPvoBV4XcjUbRM8Bk2oKqqyZ0DIEbTFZB0XjbtSPG8SAa/0DxCQmiRgzKg==", "requires": { "camelcase": "^5.0.0", "decamelize": "^1.2.0" diff --git a/package.json b/package.json index d9fa91b..d70caee 100644 --- a/package.json +++ b/package.json @@ -24,63 +24,63 @@ }, "homepage": "https://github.com/Kononnable/typeorm-model-generator#readme", "dependencies": { - "change-case": "^3.1.0", + "change-case": "^4.1.0", "fs-extra": "^8.1.0", - "handlebars": "^4.4.3", - "inquirer": "^7.0.0", - "mssql": "^5.1.0", + "handlebars": "^4.5.3", + "inquirer": "^7.0.1", + "mssql": "^6.0.1", "mysql": "^2.17.1", - "pg": "^7.12.1", + "pg": "^7.15.0", "pluralize": "^8.0.0", - "prettier": "^1.18.2", + "prettier": "^1.19.1", "reflect-metadata": "^0.1.13", - "sqlite3": "^4.1.0", - "typeorm": "^0.2.19", - "typescript": "^3.6.4", - "yargs": "^14.2.0", + "sqlite3": "^4.1.1", + "typeorm": "^0.2.21", + "typescript": "^3.7.3", + "yargs": "^15.0.2", "yn": "^3.1.1" }, "devDependencies": { "@types/array.prototype.flatmap": "^1.2.0", - "@types/chai": "^4.2.3", + "@types/chai": "^4.2.7", "@types/chai-as-promised": "^7.1.2", "@types/chai-subset": "^1.3.3", - "@types/fs-extra": "^8.0.0", + "@types/fs-extra": "^8.0.1", "@types/handlebars": "^4.1.0", "@types/inquirer": "^6.5.0", "@types/mocha": "^5.2.7", - "@types/mssql": "^4.3.1", - "@types/mysql": "^2.15.7", - "@types/node": "^12.7.12", - "@types/oracledb": "^4.0.4", + "@types/mssql": "^6.0.0", + "@types/mysql": "^2.15.8", + "@types/node": "^12.12.21", + "@types/oracledb": "^4.1.1", "@types/pg": "^7.11.2", "@types/pluralize": "0.0.29", - "@types/prettier": "^1.18.3", - "@types/sinon": "^7.5.0", + "@types/prettier": "^1.19.0", + "@types/sinon": "^7.5.1", "@types/sqlite3": "^3.1.5", "@types/yargs": "^13.0.3", - "@typescript-eslint/eslint-plugin": "^2.3.3", - "@typescript-eslint/parser": "^2.3.3", - "@typescript-eslint/typescript-estree": "^2.3.3", - "array.prototype.flatmap": "^1.2.2", + "@typescript-eslint/eslint-plugin": "^2.12.0", + "@typescript-eslint/parser": "^2.12.0", + "@typescript-eslint/typescript-estree": "^2.12.0", + "array.prototype.flatmap": "^1.2.3", "chai": "^4.2.0", "chai-as-promised": "^7.1.1", "chai-subset": "^1.6.0", "codecov": "^3.6.1", - "dotenv": "^8.1.0", - "eslint": "^6.5.1", + "dotenv": "^8.2.0", + "eslint": "^6.7.2", "eslint-config-airbnb-base": "^14.0.0", - "eslint-config-prettier": "^6.4.0", - "eslint-plugin-import": "^2.18.2", - "husky": "^3.0.8", - "lint-staged": "^9.4.2", - "mocha": "^6.2.1", + "eslint-config-prettier": "^6.7.0", + "eslint-plugin-import": "^2.19.1", + "husky": "^3.1.0", + "lint-staged": "^9.5.0", + "mocha": "^6.2.2", "ncp": "^2.0.0", "nyc": "^14.1.1", "rimraf": "^3.0.0", "sinon": "^7.5.0", "sinon-chai": "^3.3.0", - "ts-node": "^8.4.1" + "ts-node": "^8.5.4" }, "husky": { "hooks": { diff --git a/src/drivers/MssqlDriver.ts b/src/drivers/MssqlDriver.ts index 4f513ac..a541c85 100644 --- a/src/drivers/MssqlDriver.ts +++ b/src/drivers/MssqlDriver.ts @@ -30,12 +30,14 @@ export default class MssqlDriver extends AbstractDriver { TABLE_SCHEMA: string; TABLE_NAME: string; DB_NAME: string; - }[] = (await request.query( - `SELECT TABLE_SCHEMA,TABLE_NAME, table_catalog as "DB_NAME" FROM INFORMATION_SCHEMA.TABLES + }[] = ( + await request.query( + `SELECT TABLE_SCHEMA,TABLE_NAME, table_catalog as "DB_NAME" FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE='BASE TABLE' and TABLE_SCHEMA in (${schema}) AND TABLE_CATALOG in (${MssqlDriver.escapeCommaSeparatedList( - dbNames - )})` - )).recordset; + dbNames + )})` + ) + ).recordset; return response; }; @@ -56,7 +58,8 @@ WHERE TABLE_TYPE='BASE TABLE' and TABLE_SCHEMA in (${schema}) AND TABLE_CATALOG 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(*) @@ -70,9 +73,10 @@ WHERE TABLE_TYPE='BASE TABLE' and TABLE_SCHEMA in (${schema}) AND TABLE_CATALOG and tc.TABLE_SCHEMA=c.TABLE_SCHEMA) IsUnique FROM INFORMATION_SCHEMA.COLUMNS c where TABLE_SCHEMA in (${schema}) AND TABLE_CATALOG in (${MssqlDriver.escapeCommaSeparatedList( - dbNames - )}) - order by ordinal_position`)).recordset; + dbNames + )}) + order by ordinal_position`) + ).recordset; entities.forEach(ent => { response .filter(filterVal => { @@ -256,7 +260,8 @@ WHERE TABLE_TYPE='BASE TABLE' and TABLE_SCHEMA in (${schema}) AND TABLE_CATALOG ColumnName: string; is_unique: boolean; is_primary_key: boolean; - }[] = (await request.query(`SELECT + }[] = ( + await request.query(`SELECT TableName = t.name, IndexName = ind.name, ColumnName = col.name, @@ -275,7 +280,8 @@ WHERE TABLE_TYPE='BASE TABLE' and TABLE_SCHEMA in (${schema}) AND TABLE_CATALOG WHERE t.is_ms_shipped = 0 and s.name in (${schema}) ORDER BY - t.name, ind.name, ind.index_id, ic.key_ordinal;`)).recordset; + t.name, ind.name, ind.index_id, ic.key_ordinal;`) + ).recordset; response.push(...resp); }) ); @@ -335,7 +341,8 @@ WHERE TABLE_TYPE='BASE TABLE' and TABLE_SCHEMA in (${schema}) AND TABLE_CATALOG onDelete: "RESTRICT" | "CASCADE" | "SET_NULL" | "NO_ACTION"; onUpdate: "RESTRICT" | "CASCADE" | "SET_NULL" | "NO_ACTION"; objectId: number; - }[] = (await request.query(`select + }[] = ( + await request.query(`select parentTable.name as TableWithForeignKey, fkc.constraint_column_id as FK_PartNo, parentColumn.name as ForeignKeyColumn, @@ -361,7 +368,8 @@ WHERE TABLE_TYPE='BASE TABLE' and TABLE_SCHEMA in (${schema}) AND TABLE_CATALOG where fk.is_disabled=0 and fk.is_ms_shipped=0 and parentSchema.name in (${schema}) order by - TableWithForeignKey, FK_PartNo`)).recordset; + TableWithForeignKey, FK_PartNo`) + ).recordset; response.push(...resp); }) ); diff --git a/src/drivers/OracleDriver.ts b/src/drivers/OracleDriver.ts index 7c259db..bf045a7 100644 --- a/src/drivers/OracleDriver.ts +++ b/src/drivers/OracleDriver.ts @@ -41,9 +41,11 @@ export default class OracleDriver extends AbstractDriver { TABLE_SCHEMA: string; TABLE_NAME: string; DB_NAME: string; - }[] = (await this.Connection.execute( - `SELECT NULL AS TABLE_SCHEMA, TABLE_NAME, NULL AS DB_NAME FROM all_tables WHERE owner = (select user from dual)` - )).rows!; + }[] = ( + await this.Connection.execute( + `SELECT NULL AS TABLE_SCHEMA, TABLE_NAME, NULL AS DB_NAME FROM all_tables WHERE owner = (select user from dual)` + ) + ).rows!; return response; }; @@ -59,11 +61,13 @@ export default class OracleDriver extends AbstractDriver { DATA_SCALE: number; IDENTITY_COLUMN: string; // doesn't exist in old oracle versions (#195) IS_UNIQUE: number; - }[] = (await this.Connection - .execute(`SELECT utc.*, (select count(*) from USER_CONS_COLUMNS ucc + }[] = ( + await this.Connection + .execute(`SELECT utc.*, (select count(*) from USER_CONS_COLUMNS ucc JOIN USER_CONSTRAINTS uc ON uc.CONSTRAINT_NAME = ucc.CONSTRAINT_NAME and uc.CONSTRAINT_TYPE='U' where ucc.column_name = utc.COLUMN_NAME AND ucc.table_name = utc.TABLE_NAME) IS_UNIQUE - FROM USER_TAB_COLUMNS utc`)).rows!; + FROM USER_TAB_COLUMNS utc`) + ).rows!; entities.forEach(ent => { response @@ -221,12 +225,14 @@ export default class OracleDriver extends AbstractDriver { INDEX_NAME: string; UNIQUENESS: string; ISPRIMARYKEY: number; - }[] = (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 + }[] = ( + 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 LEFT JOIN USER_CONSTRAINTS uc ON uc.INDEX_NAME = ind.INDEX_NAME - ORDER BY col.INDEX_NAME ASC ,col.COLUMN_POSITION ASC`)).rows!; + ORDER BY col.INDEX_NAME ASC ,col.COLUMN_POSITION ASC`) + ).rows!; entities.forEach(ent => { const entityIndices = response.filter( @@ -269,8 +275,9 @@ export default class OracleDriver extends AbstractDriver { CHILD_COLUMN_NAME: string; DELETE_RULE: "RESTRICT" | "CASCADE" | "SET NULL" | "NO ACTION"; CONSTRAINT_NAME: string; - }[] = (await this.Connection - .execute(`select owner.TABLE_NAME OWNER_TABLE_NAME,ownCol.POSITION OWNER_POSITION,ownCol.COLUMN_NAME OWNER_COLUMN_NAME, + }[] = ( + 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, owner.CONSTRAINT_NAME @@ -278,8 +285,8 @@ export default class OracleDriver extends AbstractDriver { join user_constraints child on owner.r_constraint_name=child.CONSTRAINT_NAME and child.constraint_type in ('P','U') JOIN USER_CONS_COLUMNS ownCol ON owner.CONSTRAINT_NAME = ownCol.CONSTRAINT_NAME JOIN USER_CONS_COLUMNS childCol ON child.CONSTRAINT_NAME = childCol.CONSTRAINT_NAME AND ownCol.POSITION=childCol.POSITION - ORDER BY OWNER_TABLE_NAME ASC, owner.CONSTRAINT_NAME ASC, OWNER_POSITION ASC`)) - .rows!; + ORDER BY OWNER_TABLE_NAME ASC, owner.CONSTRAINT_NAME ASC, OWNER_POSITION ASC`) + ).rows!; const relationsTemp: RelationInternal[] = [] as RelationInternal[]; const relationKeys = new Set(response.map(v => v.CONSTRAINT_NAME)); diff --git a/src/drivers/PostgresDriver.ts b/src/drivers/PostgresDriver.ts index 446ad83..4f6f105 100644 --- a/src/drivers/PostgresDriver.ts +++ b/src/drivers/PostgresDriver.ts @@ -29,9 +29,11 @@ export default class PostgresDriver extends AbstractDriver { TABLE_SCHEMA: string; TABLE_NAME: string; DB_NAME: string; - }[] = (await this.Connection.query( - `SELECT table_schema as "TABLE_SCHEMA",table_name as "TABLE_NAME", table_catalog as "DB_NAME" FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE='BASE TABLE' AND table_schema in (${schema}) ` - )).rows; + }[] = ( + await this.Connection.query( + `SELECT table_schema as "TABLE_SCHEMA",table_name as "TABLE_NAME", table_catalog as "DB_NAME" FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE='BASE TABLE' AND table_schema in (${schema}) ` + ) + ).rows; return response; }; @@ -52,8 +54,9 @@ export default class PostgresDriver extends AbstractDriver { isidentity: string; isunique: string; enumvalues: string | null; - }[] = (await this.Connection - .query(`SELECT table_name,column_name,udt_name,column_default,is_nullable, + }[] = ( + 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, (SELECT count(*) @@ -74,7 +77,8 @@ export default class PostgresDriver extends AbstractDriver { ) enumValues FROM INFORMATION_SCHEMA.COLUMNS c where table_schema in (${schema}) - order by ordinal_position`)).rows; + order by ordinal_position`) + ).rows; entities.forEach(ent => { response .filter(filterVal => filterVal.table_name === ent.tscName) @@ -414,7 +418,8 @@ export default class PostgresDriver extends AbstractDriver { 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, @@ -437,7 +442,8 @@ export default class PostgresDriver extends AbstractDriver { AND n.nspname in (${schema}) AND f.attnum > 0 AND i.oid<>0 - ORDER BY c.relname,f.attname;`)).rows; + ORDER BY c.relname,f.attname;`) + ).rows; entities.forEach(ent => { const entityIndices = response.filter( filterVal => filterVal.tablename === ent.tscName @@ -480,7 +486,8 @@ export default class PostgresDriver extends AbstractDriver { onupdate: "RESTRICT" | "CASCADE" | "SET NULL" | "NO ACTION"; object_id: string; // Distinct because of note in https://www.postgresql.org/docs/9.1/information-schema.html - }[] = (await this.Connection.query(`SELECT DISTINCT + }[] = ( + await this.Connection.query(`SELECT DISTINCT con.relname AS tablewithforeignkey, att.attnum as fk_partno, att2.attname AS foreignkeycolumn, @@ -519,7 +526,8 @@ export default class PostgresDriver extends AbstractDriver { AND att2.attrelid = con.conrelid AND att2.attnum = con.parent AND rc.constraint_name= con.conname AND constraint_catalog=current_database() AND rc.constraint_schema=nspname - `)).rows; + `) + ).rows; const relationsTemp: RelationInternal[] = [] as RelationInternal[]; const relationKeys = new Set(response.map(v => v.object_id)); diff --git a/src/index.ts b/src/index.ts index 99ebe28..2ac40d3 100644 --- a/src/index.ts +++ b/src/index.ts @@ -279,22 +279,24 @@ function checkYargsParameters(options: options): options { async function useInquirer(options: options): Promise { const oldDatabaseType = options.connectionOptions.databaseType; - options.connectionOptions.databaseType = (await inquirer.prompt([ - { - choices: [ - "mssql", - "postgres", - "mysql", - "mariadb", - "oracle", - "sqlite" - ], - default: options.connectionOptions.databaseType, - message: "Choose database engine", - name: "engine", - type: "list" - } - ])).engine; + options.connectionOptions.databaseType = ( + await inquirer.prompt([ + { + choices: [ + "mssql", + "postgres", + "mysql", + "mariadb", + "oracle", + "sqlite" + ], + default: options.connectionOptions.databaseType, + message: "Choose database engine", + name: "engine", + type: "list" + } + ]) + ).engine; const driver = createDriver(options.connectionOptions.databaseType); if (options.connectionOptions.databaseType !== oldDatabaseType) { options.connectionOptions.port = driver.standardPort; @@ -348,15 +350,17 @@ async function useInquirer(options: options): Promise { options.connectionOptions.databaseType === "mssql" || options.connectionOptions.databaseType === "postgres" ) { - options.connectionOptions.schemaName = (await inquirer.prompt([ - { - default: options.connectionOptions.schemaName, - message: - "Database schema: (You can pass multiple values separated by comma)", - name: "schema", - type: "input" - } - ])).schema; + options.connectionOptions.schemaName = ( + await inquirer.prompt([ + { + default: options.connectionOptions.schemaName, + message: + "Database schema: (You can pass multiple values separated by comma)", + name: "schema", + type: "input" + } + ]) + ).schema; } options.connectionOptions.port = parseInt(answ.port, 10); options.connectionOptions.host = answ.host; @@ -365,23 +369,27 @@ async function useInquirer(options: options): Promise { options.connectionOptions.databaseName = answ.dbName; options.connectionOptions.ssl = answ.ssl; } else { - options.connectionOptions.databaseName = (await inquirer.prompt([ + options.connectionOptions.databaseName = ( + await inquirer.prompt([ + { + default: options.connectionOptions.databaseName, + message: "Path to database file:", + name: "dbName", + type: "input" + } + ]) + ).dbName; + } + options.generationOptions.resultsPath = ( + await inquirer.prompt([ { - default: options.connectionOptions.databaseName, - message: "Path to database file:", - name: "dbName", + default: options.generationOptions.resultsPath, + message: "Path where generated models should be stored:", + name: "output", type: "input" } - ])).dbName; - } - options.generationOptions.resultsPath = (await inquirer.prompt([ - { - default: options.generationOptions.resultsPath, - message: "Path where generated models should be stored:", - name: "output", - type: "input" - } - ])).output; + ]) + ).output; const { customizeGeneration } = await inquirer.prompt([ { default: false, @@ -391,78 +399,87 @@ async function useInquirer(options: options): Promise { } ]); if (customizeGeneration) { - const customizations: string[] = (await inquirer.prompt([ - { - choices: [ - { - checked: !options.generationOptions.noConfigs, - name: "Generate config files", - value: "config" - }, - { - name: "Generate lazy relations", - value: "lazy", - checked: options.generationOptions.lazy - }, - { - name: "Use ActiveRecord syntax for generated models", - value: "activeRecord", - checked: options.generationOptions.activeRecord - }, - { - name: "Use custom naming strategy", - value: "namingStrategy", - checked: !!options.generationOptions - .customNamingStrategyPath - }, - { - name: "Generate RelationId fields", - value: "relationId", - checked: options.generationOptions.relationIds - }, - { - name: "Omits schema identifier in generated entities", - value: "skipSchema", - checked: options.generationOptions.skipSchema - }, - { - name: - "Generate constructor allowing partial initialization", - value: "constructor", - checked: options.generationOptions.generateConstructor - }, - { - name: "Use specific naming convention", - value: "namingConvention", - checked: options.generationOptions.lazy - } - ], - message: "Available customizations", - name: "selected", - type: "checkbox" - } - ])).selected; + const customizations: string[] = ( + await inquirer.prompt([ + { + choices: [ + { + checked: !options.generationOptions.noConfigs, + name: "Generate config files", + value: "config" + }, + { + name: "Generate lazy relations", + value: "lazy", + checked: options.generationOptions.lazy + }, + { + name: + "Use ActiveRecord syntax for generated models", + value: "activeRecord", + checked: options.generationOptions.activeRecord + }, + { + name: "Use custom naming strategy", + value: "namingStrategy", + checked: !!options.generationOptions + .customNamingStrategyPath + }, + { + name: "Generate RelationId fields", + value: "relationId", + checked: options.generationOptions.relationIds + }, + { + name: + "Omits schema identifier in generated entities", + value: "skipSchema", + checked: options.generationOptions.skipSchema + }, + { + name: + "Generate constructor allowing partial initialization", + value: "constructor", + checked: + options.generationOptions.generateConstructor + }, + { + name: "Use specific naming convention", + value: "namingConvention", + checked: options.generationOptions.lazy + } + ], + message: "Available customizations", + name: "selected", + type: "checkbox" + } + ]) + ).selected; - options.generationOptions.propertyVisibility = (await inquirer.prompt([ - { - choices: ["public", "protected", "private", "none"], - message: - "Defines which visibility should have the generated property", - name: "propertyVisibility", - default: options.generationOptions.propertyVisibility, - type: "list" - } - ])).propertyVisibility; + options.generationOptions.propertyVisibility = ( + await inquirer.prompt([ + { + choices: ["public", "protected", "private", "none"], + message: + "Defines which visibility should have the generated property", + name: "propertyVisibility", + default: options.generationOptions.propertyVisibility, + type: "list" + } + ]) + ).propertyVisibility; - options.generationOptions.strictMode = (await inquirer.prompt([ - { - choices: ["none", "?", "!"], - message: "Mark fields as optional(?) or non-null(!)", - name: "strictMode", - default: options.generationOptions.strictMode, - type: "list" - } - ])).strictMode; + options.generationOptions.strictMode = ( + await inquirer.prompt([ + { + choices: ["none", "?", "!"], + message: "Mark fields as optional(?) or non-null(!)", + name: "strictMode", + default: options.generationOptions.strictMode, + type: "list" + } + ]) + ).strictMode; options.generationOptions.noConfigs = !customizations.includes( "config" @@ -482,21 +499,24 @@ async function useInquirer(options: options): Promise { ); if (customizations.includes("namingStrategy")) { - const namingStrategyPath = (await inquirer.prompt([ - { - default: options.generationOptions.customNamingStrategyPath, - message: "Path to custom naming strategy file:", - name: "namingStrategy", - type: "input", - validate(value) { - const valid = value === "" || fs.existsSync(value); - return ( - valid || - "Please enter a a valid path to custom naming strategy file" - ); + const namingStrategyPath = ( + await inquirer.prompt([ + { + default: + options.generationOptions.customNamingStrategyPath, + message: "Path to custom naming strategy file:", + name: "namingStrategy", + type: "input", + validate(value) { + const valid = value === "" || fs.existsSync(value); + return ( + valid || + "Please enter a a valid path to custom naming strategy file" + ); + } } - } - ])).namingStrategy; + ]) + ).namingStrategy; if (namingStrategyPath && namingStrategyPath !== "") { options.generationOptions.customNamingStrategyPath = namingStrategyPath; From 7679ef2b77934e07ef2f85b0bbf95e84c0e9fc9f Mon Sep 17 00:00:00 2001 From: Kononnable Date: Thu, 19 Dec 2019 17:43:03 +0100 Subject: [PATCH 67/84] support for mysql set type (#91) --- src/drivers/MysqlDriver.ts | 23 +++++++++++++++++-- .../entityTypes/mariadb/entity/Post.ts | 6 +++++ .../entityTypes/mysql/entity/Post.ts | 6 +++++ 3 files changed, 33 insertions(+), 2 deletions(-) diff --git a/src/drivers/MysqlDriver.ts b/src/drivers/MysqlDriver.ts index 4e40085..b7185fc 100644 --- a/src/drivers/MysqlDriver.ts +++ b/src/drivers/MysqlDriver.ts @@ -75,7 +75,8 @@ export default class MysqlDriver extends AbstractDriver { }; const generated = resp.IsIdentity === 1 ? true : undefined; const defaultValue = MysqlDriver.ReturnDefaultValueFunction( - resp.COLUMN_DEFAULT + resp.COLUMN_DEFAULT, + resp.DATA_TYPE ); let columnType = resp.DATA_TYPE; if (resp.IS_NULLABLE === "YES") options.nullable = true; @@ -178,6 +179,20 @@ export default class MysqlDriver extends AbstractDriver { .replace(/'/gi, "") .split(","); break; + case "set": + tscType = `(${resp.COLUMN_TYPE.substring( + 4, + resp.COLUMN_TYPE.length - 1 + ) + .replace(/'/gi, '"') + .replace(/","/gi, '" | "')})[]`; + options.enum = resp.COLUMN_TYPE.substring( + 4, + resp.COLUMN_TYPE.length - 1 + ) + .replace(/'/gi, "") + .split(","); + break; case "json": tscType = "object"; break; @@ -488,7 +503,8 @@ export default class MysqlDriver extends AbstractDriver { } private static ReturnDefaultValueFunction( - defVal: string | undefined + defVal: string | undefined, + dataType: string ): string | undefined { let defaultValue = defVal; if (!defaultValue || defaultValue === "NULL") { @@ -503,6 +519,9 @@ export default class MysqlDriver extends AbstractDriver { ) { return `() => "${defaultValue}"`; } + if (dataType === "set") { + return `() => ['${defaultValue.split(",").join("','")}']`; + } return `() => "'${defaultValue}'"`; } } diff --git a/test/integration/entityTypes/mariadb/entity/Post.ts b/test/integration/entityTypes/mariadb/entity/Post.ts index 972bd30..271bad0 100644 --- a/test/integration/entityTypes/mariadb/entity/Post.ts +++ b/test/integration/entityTypes/mariadb/entity/Post.ts @@ -116,4 +116,10 @@ export class Post { @Column("geometrycollection") geometrycollection: string; + + @Column("set", { + enum: ["A", "B", "C"], + default: ["A", "B"] + }) + roles: ("A" | "B" | "C")[] } diff --git a/test/integration/entityTypes/mysql/entity/Post.ts b/test/integration/entityTypes/mysql/entity/Post.ts index f76777f..d529f2e 100644 --- a/test/integration/entityTypes/mysql/entity/Post.ts +++ b/test/integration/entityTypes/mysql/entity/Post.ts @@ -118,4 +118,10 @@ export class Post { @Column("geometrycollection") geometrycollection: string; + + @Column("set", { + enum: ["A", "B", "C"], + default: ["A", "B"] + }) + roles: ("A" | "B" | "C")[] } From ff637721eddb8ba48453707d76db7c6506f10962 Mon Sep 17 00:00:00 2001 From: Kononnable Date: Fri, 20 Dec 2019 19:24:15 +0100 Subject: [PATCH 68/84] Option to disable column name pluralization (#142) --- src/IGenerationOptions.ts | 2 + src/ModelCustomization.ts | 13 ++++ src/NamingStrategy.ts | 10 ++- src/index.ts | 26 ++++++- .../modelCustomization.test.ts | 69 ++++++++++++++++--- test/utils/GeneralTestUtils.ts | 22 ++---- 6 files changed, 113 insertions(+), 29 deletions(-) diff --git a/src/IGenerationOptions.ts b/src/IGenerationOptions.ts index 1a1b534..a12b3c4 100644 --- a/src/IGenerationOptions.ts +++ b/src/IGenerationOptions.ts @@ -5,6 +5,7 @@ import path = require("path"); // eslint-disable-next-line @typescript-eslint/interface-name-prefix export default interface IGenerationOptions { resultsPath: string; + pluralizeNames: boolean; noConfigs: boolean; convertCaseFile: "pascal" | "param" | "camel" | "none"; convertCaseEntity: "pascal" | "camel" | "none"; @@ -21,6 +22,7 @@ export default interface IGenerationOptions { export function getDefaultGenerationOptions(): IGenerationOptions { const generationOptions: IGenerationOptions = { resultsPath: path.resolve(process.cwd(), "output"), + pluralizeNames: true, noConfigs: false, convertCaseFile: "pascal", convertCaseEntity: "pascal", diff --git a/src/ModelCustomization.ts b/src/ModelCustomization.ts index 3833d70..46f80d0 100644 --- a/src/ModelCustomization.ts +++ b/src/ModelCustomization.ts @@ -9,6 +9,7 @@ import { RelationId } from "./models/RelationId"; import { Column } from "./models/Column"; type NamingStrategy = { + enablePluralization: (value: boolean) => void; relationIdName: ( relationId: RelationId, relation: Relation, @@ -25,6 +26,7 @@ export default function modelCustomizationPhase( defaultValues: DataTypeDefaults ): Entity[] { const namingStrategy: NamingStrategy = { + enablePluralization: NamingStrategy.enablePluralization, columnName: NamingStrategy.columnName, entityName: NamingStrategy.entityName, relationIdName: NamingStrategy.relationIdName, @@ -78,7 +80,18 @@ export default function modelCustomizationPhase( `[${new Date().toLocaleTimeString()}] Using standard naming strategy for relation field names.` ); } + if (req.enablePluralization) { + console.log( + `[${new Date().toLocaleTimeString()}] Using custom pluralization method for OneToMany, ManyToMany relation field names.` + ); + namingStrategy.enablePluralization = req.enablePluralization; + } else { + console.log( + `[${new Date().toLocaleTimeString()}] Using custom pluralization method for OneToMany, ManyToMany relation field names.` + ); + } } + namingStrategy.enablePluralization(generationOptions.pluralizeNames); let retVal = removeIndicesGeneratedByTypeorm(dbModel); retVal = removeColumnsInRelation(dbModel); retVal = applyNamingStrategy(namingStrategy, dbModel); diff --git a/src/NamingStrategy.ts b/src/NamingStrategy.ts index 8ff4546..4836377 100644 --- a/src/NamingStrategy.ts +++ b/src/NamingStrategy.ts @@ -3,6 +3,12 @@ import * as changeCase from "change-case"; import { Relation } from "./models/Relation"; import { RelationId } from "./models/RelationId"; +let pluralize: boolean; + +export function enablePluralization(value: boolean) { + pluralize = value; +} + export function relationIdName( relationId: RelationId, relation: Relation @@ -22,7 +28,7 @@ export function relationIdName( if (!Number.isNaN(parseInt(newColumnName[newColumnName.length - 1], 10))) { newColumnName = newColumnName.substring(0, newColumnName.length - 1); } - if (isRelationToMany) { + if (isRelationToMany && pluralize) { newColumnName = plural(newColumnName); } @@ -54,7 +60,7 @@ export function relationName(relation: Relation): string { if (!Number.isNaN(parseInt(newColumnName[newColumnName.length - 1], 10))) { newColumnName = newColumnName.substring(0, newColumnName.length - 1); } - if (isRelationToMany) { + if (isRelationToMany && pluralize) { newColumnName = plural(newColumnName); } return newColumnName; diff --git a/src/index.ts b/src/index.ts index 2ac40d3..e84e68e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -239,6 +239,12 @@ function checkYargsParameters(options: options): options { default: options.generationOptions.generateConstructor, describe: "Generate constructor allowing partial initialization" }, + disablePluralization: { + boolean: true, + default: !options.generationOptions.pluralizeNames, + describe: + "Disable pluralization of OneToMany, ManyToMany relation names." + }, strictMode: { choices: ["none", "?", "!"], default: options.generationOptions.strictMode, @@ -272,6 +278,7 @@ function checkYargsParameters(options: options): options { options.generationOptions.relationIds = argv.relationIds; options.generationOptions.skipSchema = argv.skipSchema; options.generationOptions.resultsPath = argv.o; + options.generationOptions.pluralizeNames = !argv.disablePluralization; options.generationOptions.strictMode = argv.strictMode as IGenerationOptions["strictMode"]; return options; @@ -399,6 +406,7 @@ async function useInquirer(options: options): Promise { } ]); if (customizeGeneration) { + const defaultGenerationOptions = getDefaultGenerationOptions(); const customizations: string[] = ( await inquirer.prompt([ { @@ -446,7 +454,20 @@ async function useInquirer(options: options): Promise { { name: "Use specific naming convention", value: "namingConvention", - checked: options.generationOptions.lazy + checked: + options.generationOptions.convertCaseEntity !== + defaultGenerationOptions.convertCaseEntity || + options.generationOptions + .convertCaseProperty !== + defaultGenerationOptions.convertCaseProperty || + options.generationOptions.convertCaseFile !== + defaultGenerationOptions.convertCaseFile + }, + { + name: + "Pluralize OneToMany, ManyToMany relation names.", + value: "pluralize", + checked: options.generationOptions.pluralizeNames } ], message: "Available customizations", @@ -484,6 +505,9 @@ async function useInquirer(options: options): Promise { options.generationOptions.noConfigs = !customizations.includes( "config" ); + options.generationOptions.pluralizeNames = customizations.includes( + "pluralize" + ); options.generationOptions.lazy = customizations.includes("lazy"); options.generationOptions.activeRecord = customizations.includes( "activeRecord" diff --git a/test/modelCustomization/modelCustomization.test.ts b/test/modelCustomization/modelCustomization.test.ts index 7b0a3a1..da60c12 100644 --- a/test/modelCustomization/modelCustomization.test.ts +++ b/test/modelCustomization/modelCustomization.test.ts @@ -47,7 +47,7 @@ describe("Model customization phase", async () => { fieldName: "Post", relatedField: "authorId", relatedTable: "Post", - relationType: "OneToOne" + relationType: "OneToMany" } ], relationIds: [], @@ -101,7 +101,7 @@ describe("Model customization phase", async () => { { name: "authorId", referencedColumnName: "id" } ], relatedTable: "PostAuthor", - relationType: "OneToOne" + relationType: "ManyToOne" } ], relationIds: [], @@ -252,7 +252,7 @@ describe("Model customization phase", async () => { .readFileSync(path.resolve(filesGenPath, "PostAuthor.ts")) .toString(); expect(postContent).to.contain("Title: string;"); - expect(postAuthorContent).to.contain("Post: Post;"); + expect(postAuthorContent).to.contain("Posts: Post[];"); compileGeneratedModel(generationOptions.resultsPath, [""]); }); @@ -280,7 +280,7 @@ describe("Model customization phase", async () => { .readFileSync(path.resolve(filesGenPath, "PostAuthor.ts")) .toString(); expect(postContent).to.contain("title: string;"); - expect(postAuthorContent).to.contain("post: Post;"); + expect(postAuthorContent).to.contain("posts: Post[];"); compileGeneratedModel(generationOptions.resultsPath, [""]); }); @@ -310,7 +310,7 @@ describe("Model customization phase", async () => { .readFileSync(path.resolve(filesGenPath, "PostAuthor.ts")) .toString(); expect(postContent).to.have.string(" public title: string"); - expect(postAuthorContent).to.have.string(" public post: Post;"); + expect(postAuthorContent).to.have.string(" public posts: Post[];"); compileGeneratedModel(generationOptions.resultsPath, [""]); }); @@ -338,7 +338,7 @@ describe("Model customization phase", async () => { .readFileSync(path.resolve(filesGenPath, "PostAuthor.ts")) .toString(); expect(postContent).to.have.string(" title: string"); - expect(postAuthorContent).to.have.string(" post: Post;"); + expect(postAuthorContent).to.have.string(" posts: Post[];"); compileGeneratedModel(generationOptions.resultsPath, [""]); }); @@ -349,6 +349,7 @@ describe("Model customization phase", async () => { clearGenerationDir(); generationOptions.lazy = true; + generationOptions.pluralizeNames = false; const customizedModel = modelCustomizationPhase( data, generationOptions, @@ -369,7 +370,7 @@ describe("Model customization phase", async () => { expect(postContent).to.have.string("lazy: true"); expect(postContent).to.have.string("Promise;"); expect(postAuthorContent).to.have.string("lazy: true"); - expect(postAuthorContent).to.have.string("Promise"); + expect(postAuthorContent).to.have.string("Promise"); compileGeneratedModel(generationOptions.resultsPath, [""]); }); @@ -530,7 +531,7 @@ describe("Model customization phase", async () => { expect(postContent).to.have.string(`author!: PostAuthor;`); expect(postAuthorContent).to.have.string(`id!: number;`); expect(postAuthorContent).to.have.string(`name!: string;`); - expect(postAuthorContent).to.have.string(`post!: Post;`); + expect(postAuthorContent).to.have.string(`posts!: Post[];`); compileGeneratedModel(generationOptions.resultsPath, [""]); }); @@ -563,7 +564,7 @@ describe("Model customization phase", async () => { expect(postContent).to.have.string(`author?: PostAuthor;`); expect(postAuthorContent).to.have.string(`id?: number;`); expect(postAuthorContent).to.have.string(`name?: string;`); - expect(postAuthorContent).to.have.string(`post?: Post;`); + expect(postAuthorContent).to.have.string(`posts?: Post[];`); compileGeneratedModel(generationOptions.resultsPath, [""]); }); @@ -612,4 +613,54 @@ describe("Model customization phase", async () => { compileGeneratedModel(generationOptions.resultsPath, [""]); }); + describe("pluralization", () => { + it("enabled", async () => { + + const data = generateSampleData(); + const generationOptions = generateGenerationOptions(); + generationOptions.pluralizeNames = true; + clearGenerationDir(); + + const customizedModel = modelCustomizationPhase( + data, + generationOptions, + {} + ); + modelGenerationPhase( + getDefaultConnectionOptions(), + generationOptions, + customizedModel + ); + const filesGenPath = path.resolve(resultsPath, "entities"); + const postAuthorContent = fs + .readFileSync(path.resolve(filesGenPath, "PostAuthor.ts")) + .toString(); + expect(postAuthorContent).to.contain("posts: Post[];"); + compileGeneratedModel(generationOptions.resultsPath, [""]); + }) + it("disabled", async () => { + + const data = generateSampleData(); + const generationOptions = generateGenerationOptions(); + generationOptions.pluralizeNames = false; + clearGenerationDir(); + + const customizedModel = modelCustomizationPhase( + data, + generationOptions, + {} + ); + modelGenerationPhase( + getDefaultConnectionOptions(), + generationOptions, + customizedModel + ); + const filesGenPath = path.resolve(resultsPath, "entities"); + const postAuthorContent = fs + .readFileSync(path.resolve(filesGenPath, "PostAuthor.ts")) + .toString(); + expect(postAuthorContent).to.contain("post: Post[];"); + compileGeneratedModel(generationOptions.resultsPath, [""]); + }) + }) }); diff --git a/test/utils/GeneralTestUtils.ts b/test/utils/GeneralTestUtils.ts index 84d7c09..bf2fe82 100644 --- a/test/utils/GeneralTestUtils.ts +++ b/test/utils/GeneralTestUtils.ts @@ -1,7 +1,7 @@ import { ConnectionOptions, createConnection } from "typeorm"; import * as ts from "typescript"; import * as yn from "yn"; -import IGenerationOptions from "../../src/IGenerationOptions"; +import IGenerationOptions, { getDefaultGenerationOptions } from "../../src/IGenerationOptions"; import IConnectionOptions from "../../src/IConnectionOptions"; import MssqlDriver from "../../src/drivers/MssqlDriver"; import MariaDbDriver from "../../src/drivers/MariaDbDriver"; @@ -12,21 +12,9 @@ import MysqlDriver from "../../src/drivers/MysqlDriver"; import path = require("path"); export function getGenerationOptions(resultsPath: string): IGenerationOptions { - return { - resultsPath, - noConfigs: false, - convertCaseEntity: "pascal", - convertCaseFile: "pascal", - convertCaseProperty: "camel", - propertyVisibility: "none", - lazy: false, - generateConstructor: false, - customNamingStrategyPath: "", - relationIds: false, - skipSchema: false, - activeRecord: false, - strictMode: "none" - }; + const retVal = getDefaultGenerationOptions(); + retVal.resultsPath = resultsPath; + return retVal; } export async function createMSSQLModels( @@ -316,7 +304,7 @@ export function compileTsFiles( ); console.log( `${diagnostic.file!.fileName} (${lineAndCharacter.line + - 1},${lineAndCharacter.character + 1}): ${message}` + 1},${lineAndCharacter.character + 1}): ${message}` ); compiledWithoutErrors = false; }); From 53da13e043d3ddd256be275087950a7fc9b5ddde Mon Sep 17 00:00:00 2001 From: David Castro Date: Fri, 20 Dec 2019 16:51:24 -0800 Subject: [PATCH 69/84] Provide main entrypoint and generated typings to use the core as a library --- package.json | 2 ++ src/library.ts | 19 +++++++++++++++++++ tsconfig.json | 2 +- 3 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 src/library.ts diff --git a/package.json b/package.json index d70caee..acdce5f 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,8 @@ "version": "0.3.5", "description": "Generates models for TypeORM from existing databases.", "bin": "bin/typeorm-model-generator", + "main": "./dist/src/library.js", + "types": "./dist/src/library.d.ts", "scripts": { "start": "ts-node ./src/index.ts", "build": "npm run clean && tsc && ncp src/templates/ dist/src/templates/ && ncp package.json dist/package.json", diff --git a/src/library.ts b/src/library.ts new file mode 100644 index 0000000..cc700ea --- /dev/null +++ b/src/library.ts @@ -0,0 +1,19 @@ +import { Column } from "./models/Column"; +import { Entity } from "./models/Entity"; +import { Index } from "./models/Index"; +import { Relation } from "./models/Relation"; +import { RelationId } from "./models/RelationId"; + +// models exports - there may be a more succinct way to export default classes, +// but this was the only one I could find that seemed happy +export type Column = Column; +export type Entity = Entity; +export type Index = Index; +export type Relation = Relation; +export type RelationId = RelationId; + +export * from "./Engine"; +export * from "./IConnectionOptions"; +export * from "./IGenerationOptions"; +export * from "./NamingStrategy"; +export * from "./Utils"; diff --git a/tsconfig.json b/tsconfig.json index 93cff05..f141ecc 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -6,7 +6,7 @@ "emitDecoratorMetadata": true, "experimentalDecorators": true, "sourceMap": true, - "declaration": false, + "declaration": true, "noFallthroughCasesInSwitch": true, "noImplicitReturns": true, "stripInternal": true, From 0d16f0e6fc01f8910426cdb42185e16e925b1234 Mon Sep 17 00:00:00 2001 From: David Castro Date: Sat, 21 Dec 2019 21:40:51 -0800 Subject: [PATCH 70/84] adjustment for entrypoint to import classes as different names to avoid collisions on export names --- src/library.ts | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/library.ts b/src/library.ts index cc700ea..f054312 100644 --- a/src/library.ts +++ b/src/library.ts @@ -1,16 +1,16 @@ -import { Column } from "./models/Column"; -import { Entity } from "./models/Entity"; -import { Index } from "./models/Index"; -import { Relation } from "./models/Relation"; -import { RelationId } from "./models/RelationId"; +import { Column as ColumnModel } from "./models/Column"; +import { Entity as EntityModel } from "./models/Entity"; +import { Index as IndexModel } from "./models/Index"; +import { Relation as RelationModel } from "./models/Relation"; +import { RelationId as RelationIdModel } from "./models/RelationId"; // models exports - there may be a more succinct way to export default classes, // but this was the only one I could find that seemed happy -export type Column = Column; -export type Entity = Entity; -export type Index = Index; -export type Relation = Relation; -export type RelationId = RelationId; +export type Column = ColumnModel; +export type Entity = EntityModel; +export type Index = IndexModel; +export type Relation = RelationModel; +export type RelationId = RelationIdModel; export * from "./Engine"; export * from "./IConnectionOptions"; From 018200e78dc640b1c0dbe7cadc9aee159cc68755 Mon Sep 17 00:00:00 2001 From: David Castro Date: Sat, 21 Dec 2019 22:03:19 -0800 Subject: [PATCH 71/84] ignore generated type definitions from lint'ng --- .eslintignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.eslintignore b/.eslintignore index 44ccaa3..2cb6327 100644 --- a/.eslintignore +++ b/.eslintignore @@ -2,4 +2,5 @@ test/integration/defaultValues/**/*.ts test/integration/entityTypes/**/*.ts test/integration/examples/**/*.ts -test/integration/github-issues/**/*.ts \ No newline at end of file +test/integration/github-issues/**/*.ts +dist/**/*.d.ts From f52ba8f4c45c871e54edf8a61be6dba92fe204f7 Mon Sep 17 00:00:00 2001 From: Kononnable Date: Sun, 22 Dec 2019 16:58:13 +0100 Subject: [PATCH 72/84] Ignore tables parameter (#120) --- src/IConnectionOptions.ts | 4 ++- src/drivers/AbstractDriver.ts | 15 +++++--- src/drivers/MssqlDriver.ts | 12 +++++-- src/drivers/MysqlDriver.ts | 12 +++++-- src/drivers/OracleDriver.ts | 12 +++++-- src/drivers/PostgresDriver.ts | 12 +++++-- src/drivers/SqliteDriver.ts | 12 +++++-- src/index.ts | 36 ++++++++++++++++++- test/drivers/MssqlDriver.test.ts | 2 +- test/integration/runTestsFromPath.test.ts | 6 ++-- .../modelCustomization.test.ts | 2 ++ test/utils/GeneralTestUtils.ts | 18 ++++++---- 12 files changed, 118 insertions(+), 25 deletions(-) diff --git a/src/IConnectionOptions.ts b/src/IConnectionOptions.ts index 8be2079..5aef82d 100644 --- a/src/IConnectionOptions.ts +++ b/src/IConnectionOptions.ts @@ -16,6 +16,7 @@ export default interface IConnectionOptions { | "sqlite"; schemaName: string; ssl: boolean; + skipTables: string[]; } export function getDefaultConnectionOptions(): IConnectionOptions { @@ -27,7 +28,8 @@ export function getDefaultConnectionOptions(): IConnectionOptions { password: "", databaseType: undefined as any, schemaName: "", - ssl: false + ssl: false, + skipTables: [] }; return connectionOptions; } diff --git a/src/drivers/AbstractDriver.ts b/src/drivers/AbstractDriver.ts index bb6ee21..a086f00 100644 --- a/src/drivers/AbstractDriver.ts +++ b/src/drivers/AbstractDriver.ts @@ -69,7 +69,8 @@ export default abstract class AbstractDriver { public abstract GetAllTablesQuery: ( schema: string, - dbNames: string + dbNames: string, + tableNames: string[] ) => Promise< { TABLE_SCHEMA: string; @@ -186,7 +187,8 @@ export default abstract class AbstractDriver { ); dbModel = await this.GetAllTables( sqlEscapedSchema, - connectionOptions.databaseName + connectionOptions.databaseName, + connectionOptions.skipTables ); await this.GetCoulmnsFromEntity( dbModel, @@ -214,9 +216,14 @@ export default abstract class AbstractDriver { public async GetAllTables( schema: string, - dbNames: string + dbNames: string, + tableNames: string[] ): Promise { - const response = await this.GetAllTablesQuery(schema, dbNames); + const response = await this.GetAllTablesQuery( + schema, + dbNames, + tableNames + ); const ret: Entity[] = [] as Entity[]; response.forEach(val => { ret.push({ diff --git a/src/drivers/MssqlDriver.ts b/src/drivers/MssqlDriver.ts index a541c85..e760810 100644 --- a/src/drivers/MssqlDriver.ts +++ b/src/drivers/MssqlDriver.ts @@ -24,8 +24,16 @@ export default class MssqlDriver extends AbstractDriver { private Connection: MSSQL.ConnectionPool; - public GetAllTablesQuery = async (schema: string, dbNames: string) => { + public GetAllTablesQuery = async ( + schema: string, + dbNames: string, + tableNames: string[] + ) => { const request = new MSSQL.Request(this.Connection); + const tableCondition = + tableNames.length > 0 + ? ` AND NOT TABLE_NAME IN ('${tableNames.join("','")}')` + : ""; const response: { TABLE_SCHEMA: string; TABLE_NAME: string; @@ -35,7 +43,7 @@ export default class MssqlDriver extends AbstractDriver { `SELECT TABLE_SCHEMA,TABLE_NAME, table_catalog as "DB_NAME" FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE='BASE TABLE' and TABLE_SCHEMA in (${schema}) AND TABLE_CATALOG in (${MssqlDriver.escapeCommaSeparatedList( dbNames - )})` + )}) ${tableCondition}` ) ).recordset; return response; diff --git a/src/drivers/MysqlDriver.ts b/src/drivers/MysqlDriver.ts index b7185fc..f63212c 100644 --- a/src/drivers/MysqlDriver.ts +++ b/src/drivers/MysqlDriver.ts @@ -26,7 +26,15 @@ export default class MysqlDriver extends AbstractDriver { private Connection: MYSQL.Connection; - public GetAllTablesQuery = async (schema: string, dbNames: string) => { + public GetAllTablesQuery = async ( + schema: string, + dbNames: string, + tableNames: string[] + ) => { + const tableCondition = + tableNames.length > 0 + ? ` AND NOT TABLE_NAME IN ('${tableNames.join("','")}')` + : ""; const response = this.ExecQuery<{ TABLE_SCHEMA: string; TABLE_NAME: string; @@ -36,7 +44,7 @@ export default class MysqlDriver extends AbstractDriver { WHERE table_type='BASE TABLE' AND table_schema IN (${MysqlDriver.escapeCommaSeparatedList( dbNames - )})`); + )}) ${tableCondition}`); return response; }; diff --git a/src/drivers/OracleDriver.ts b/src/drivers/OracleDriver.ts index bf045a7..f5f7c04 100644 --- a/src/drivers/OracleDriver.ts +++ b/src/drivers/OracleDriver.ts @@ -36,14 +36,22 @@ export default class OracleDriver extends AbstractDriver { } } - public GetAllTablesQuery = async () => { + public GetAllTablesQuery = async ( + schema: string, + dbNames: string, + tableNames: string[] + ) => { + const tableCondition = + tableNames.length > 0 + ? ` AND NOT TABLE_NAME IN ('${tableNames.join("','")}')` + : ""; const response: { TABLE_SCHEMA: string; TABLE_NAME: string; DB_NAME: string; }[] = ( await this.Connection.execute( - `SELECT NULL AS TABLE_SCHEMA, TABLE_NAME, NULL AS DB_NAME FROM all_tables WHERE owner = (select user from dual)` + `SELECT NULL AS TABLE_SCHEMA, TABLE_NAME, NULL AS DB_NAME FROM all_tables WHERE owner = (select user from dual) ${tableCondition}` ) ).rows!; return response; diff --git a/src/drivers/PostgresDriver.ts b/src/drivers/PostgresDriver.ts index 4f6f105..2703f59 100644 --- a/src/drivers/PostgresDriver.ts +++ b/src/drivers/PostgresDriver.ts @@ -24,14 +24,22 @@ export default class PostgresDriver extends AbstractDriver { private Connection: PG.Client; - public GetAllTablesQuery = async (schema: string) => { + public GetAllTablesQuery = async ( + schema: string, + dbNames: string, + tableNames: string[] + ) => { + const tableCondition = + tableNames.length > 0 + ? ` AND NOT table_name IN ('${tableNames.join("','")}')` + : ""; const response: { TABLE_SCHEMA: string; TABLE_NAME: string; DB_NAME: string; }[] = ( await this.Connection.query( - `SELECT table_schema as "TABLE_SCHEMA",table_name as "TABLE_NAME", table_catalog as "DB_NAME" FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE='BASE TABLE' AND table_schema in (${schema}) ` + `SELECT table_schema as "TABLE_SCHEMA",table_name as "TABLE_NAME", table_catalog as "DB_NAME" FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE='BASE TABLE' AND table_schema in (${schema}) ${tableCondition}` ) ).rows; return response; diff --git a/src/drivers/SqliteDriver.ts b/src/drivers/SqliteDriver.ts index 64ce684..ac99030 100644 --- a/src/drivers/SqliteDriver.ts +++ b/src/drivers/SqliteDriver.ts @@ -30,10 +30,18 @@ export default class SqliteDriver extends AbstractDriver { public GetAllTablesQuery: any; - public async GetAllTables(): Promise { + public async GetAllTables( + schema: string, + dbNames: string, + tableNames: string[] + ): Promise { const ret: Entity[] = [] as Entity[]; + const tableCondition = + tableNames.length > 0 + ? ` AND NOT tbl_name IN ('${tableNames.join("','")}')` + : ""; 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_%'` + `SELECT tbl_name, sql FROM "sqlite_master" WHERE "type" = 'table' AND name NOT LIKE 'sqlite_%' ${tableCondition}` ); rows.forEach(val => { if (val.sql.includes("AUTOINCREMENT")) { diff --git a/src/index.ts b/src/index.ts index e84e68e..b0264fb 100644 --- a/src/index.ts +++ b/src/index.ts @@ -243,7 +243,13 @@ function checkYargsParameters(options: options): options { boolean: true, default: !options.generationOptions.pluralizeNames, describe: - "Disable pluralization of OneToMany, ManyToMany relation names." + "Disable pluralization of OneToMany, ManyToMany relation names" + }, + skipTables: { + string: true, + default: options.connectionOptions.skipTables.join(","), + describe: + "Skip schema generation for specific tables. You can pass multiple values separated by comma" }, strictMode: { choices: ["none", "?", "!"], @@ -280,6 +286,7 @@ function checkYargsParameters(options: options): options { options.generationOptions.resultsPath = argv.o; options.generationOptions.pluralizeNames = !argv.disablePluralization; options.generationOptions.strictMode = argv.strictMode as IGenerationOptions["strictMode"]; + options.connectionOptions.skipTables = argv.skipTables.split(","); return options; } @@ -387,6 +394,33 @@ async function useInquirer(options: options): Promise { ]) ).dbName; } + + const ignoreSpecyficTables = ( + await inquirer.prompt([ + { + default: + options.connectionOptions.skipTables.length === 0 + ? "All of them" + : "Ignore specific tables", + message: "Generate schema for tables:", + choices: ["All of them", "Ignore specific tables"], + name: "specyficTables", + type: "list" + } + ]) + ).specyficTables; + if (ignoreSpecyficTables === "Ignore specific tables") { + const { tableNames } = await inquirer.prompt({ + default: options.connectionOptions.skipTables.join(","), + message: "Table names(separated by comma)", + name: "tableNames", + type: "input" + }); + options.connectionOptions.skipTables = tableNames.split(","); + } else { + options.connectionOptions.skipTables = []; + } + options.generationOptions.resultsPath = ( await inquirer.prompt([ { diff --git a/test/drivers/MssqlDriver.test.ts b/test/drivers/MssqlDriver.test.ts index bfa577f..cff8cdc 100644 --- a/test/drivers/MssqlDriver.test.ts +++ b/test/drivers/MssqlDriver.test.ts @@ -47,7 +47,7 @@ describe("MssqlDriver", () => { return response; } }); - const result = await driver.GetAllTables("schema", "db"); + const result = await driver.GetAllTables("schema", "db", []); const expectedResult = [] as Entity[]; const y: Entity = { columns: [], diff --git a/test/integration/runTestsFromPath.test.ts b/test/integration/runTestsFromPath.test.ts index c394a6f..ec5eb24 100644 --- a/test/integration/runTestsFromPath.test.ts +++ b/test/integration/runTestsFromPath.test.ts @@ -320,7 +320,8 @@ async function prepareTestRuns( password: String(process.env.MYSQL_Password), databaseType: "mysql", schemaName: "ignored", - ssl: yn(process.env.MYSQL_SSL, { default: false }) + ssl: yn(process.env.MYSQL_SSL, { default: false }), + skipTables: [] }; break; case "mariadb": @@ -332,7 +333,8 @@ async function prepareTestRuns( password: String(process.env.MARIADB_Password), databaseType: "mariadb", schemaName: "ignored", - ssl: yn(process.env.MARIADB_SSL, { default: false }) + ssl: yn(process.env.MARIADB_SSL, { default: false }), + skipTables: [] }; break; diff --git a/test/modelCustomization/modelCustomization.test.ts b/test/modelCustomization/modelCustomization.test.ts index da60c12..b474300 100644 --- a/test/modelCustomization/modelCustomization.test.ts +++ b/test/modelCustomization/modelCustomization.test.ts @@ -15,6 +15,8 @@ import { compileGeneratedModel } from "../integration/runTestsFromPath.test"; chai.use(chaiSubset); const { expect } = chai; + +// TODO: test for connectionOptions.specyficTables describe("Model customization phase", async () => { const generateSampleData: () => Entity[] = () => [ { diff --git a/test/utils/GeneralTestUtils.ts b/test/utils/GeneralTestUtils.ts index bf2fe82..6821ee6 100644 --- a/test/utils/GeneralTestUtils.ts +++ b/test/utils/GeneralTestUtils.ts @@ -29,7 +29,8 @@ export async function createMSSQLModels( password: String(process.env.MSSQL_Password), databaseType: "mssql", schemaName: "dbo,sch1,sch2", - ssl: yn(process.env.MSSQL_SSL, { default: false }) + ssl: yn(process.env.MSSQL_SSL, { default: false }), + skipTables: [] }; await driver.ConnectToServer(connectionOptions); connectionOptions.databaseName = String(process.env.MSSQL_Database); @@ -80,7 +81,8 @@ export async function createPostgresModels( password: String(process.env.POSTGRES_Password), databaseType: "postgres", schemaName: "public,sch1,sch2", - ssl: yn(process.env.POSTGRES_SSL, { default: false }) + ssl: yn(process.env.POSTGRES_SSL, { default: false }), + skipTables: [] }; await driver.ConnectToServer(connectionOptions); connectionOptions.databaseName = String(process.env.POSTGRES_Database); @@ -130,7 +132,8 @@ export async function createSQLiteModels( password: "", databaseType: "sqlite", schemaName: "", - ssl: false + ssl: false, + skipTables: [] }; const connOpt: ConnectionOptions = { @@ -164,7 +167,8 @@ export async function createMysqlModels( password: String(process.env.MYSQL_Password), databaseType: "mysql", schemaName: "ignored", - ssl: yn(process.env.MYSQL_SSL, { default: false }) + ssl: yn(process.env.MYSQL_SSL, { default: false }), + skipTables: [] }; await driver.ConnectToServer(connectionOptions); @@ -206,7 +210,8 @@ export async function createMariaDBModels( password: String(process.env.MARIADB_Password), databaseType: "mariadb", schemaName: "ignored", - ssl: yn(process.env.MARIADB_SSL, { default: false }) + ssl: yn(process.env.MARIADB_SSL, { default: false }), + skipTables: [] }; await driver.ConnectToServer(connectionOptions); @@ -250,7 +255,8 @@ export async function createOracleDBModels( password: String(process.env.ORACLE_PasswordSys), databaseType: "oracle", schemaName: String(process.env.ORACLE_Username), - ssl: yn(process.env.ORACLE_SSL, { default: false }) + ssl: yn(process.env.ORACLE_SSL, { default: false }), + skipTables: [] }; await driver.ConnectToServer(connectionOptions); connectionOptions.user = String(process.env.ORACLE_Username); From 57c6c307b06f8fcf31baff306a959a69ad126580 Mon Sep 17 00:00:00 2001 From: Kononnable Date: Tue, 24 Dec 2019 09:53:53 +0100 Subject: [PATCH 73/84] Run eslint on models generated by tests --- .eslintrc.js | 2 +- package-lock.json | 16 +++++++ package.json | 1 + src/templates/entity.mst | 2 +- test/configs/.eslintrc.js | 30 +++++++++++++ test/configs/tsconfig.json | 17 +++++++ test/integration/runTestsFromPath.test.ts | 10 +++++ tsconfig.json | 55 ++++++++++++----------- 8 files changed, 104 insertions(+), 29 deletions(-) create mode 100644 test/configs/.eslintrc.js create mode 100644 test/configs/tsconfig.json diff --git a/.eslintrc.js b/.eslintrc.js index 7046abe..fc4df69 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -36,7 +36,7 @@ module.exports = { settings: { "import/resolver": { node: { - extensions: [".js", ".jsx", ".ts", ".tsx"] + extensions: [".ts"] } } } diff --git a/package-lock.json b/package-lock.json index 1c9829f..08564cc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -274,12 +274,28 @@ "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==" }, + "@types/eslint": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-6.1.3.tgz", + "integrity": "sha512-llYf1QNZaDweXtA7uY6JczcwHmFwJL9TpK3E6sY0B18l6ulDT6VWNMAdEjYccFHiDfxLPxffd8QmSDV4QUUspA==", + "dev": true, + "requires": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, "@types/eslint-visitor-keys": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", "integrity": "sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag==", "dev": true }, + "@types/estree": { + "version": "0.0.41", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.41.tgz", + "integrity": "sha512-rIAmXyJlqw4KEBO7+u9gxZZSQHaCNnIzYrnNmYVpgfJhxTqO0brCX0SYpqUTkVI5mwwUwzmtspLBGBKroMeynA==", + "dev": true + }, "@types/events": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz", diff --git a/package.json b/package.json index d70caee..4ec7766 100644 --- a/package.json +++ b/package.json @@ -45,6 +45,7 @@ "@types/chai": "^4.2.7", "@types/chai-as-promised": "^7.1.2", "@types/chai-subset": "^1.3.3", + "@types/eslint": "^6.1.3", "@types/fs-extra": "^8.0.1", "@types/handlebars": "^4.1.0", "@types/inquirer": "^6.5.0", diff --git a/src/templates/entity.mst b/src/templates/entity.mst index 6e16182..ce84e6b 100644 --- a/src/templates/entity.mst +++ b/src/templates/entity.mst @@ -13,7 +13,7 @@ import { {{toEntityName .}} } from './{{toFileName .}}' { name: "{{name}}", referencedColumnName: "{{toPropertyName referencedColumnName}}" }, {{/inline}} {{#*inline "Relation"}} -@{{relationType}}(()=>{{toEntityName relatedTable}},{{toEntityName relatedTable}}=>{{toEntityName relatedTable}}.{{toPropertyName relatedField}}{{#if relationOptions}},{ {{json relationOptions}} }{{/if}}) +@{{relationType}}(()=>{{toEntityName relatedTable}},{{toEntityName relatedTable}}_=>{{toEntityName relatedTable}}_.{{toPropertyName relatedField}}{{#if relationOptions}},{ {{json relationOptions}} }{{/if}}) {{#if joinColumnOptions}}@JoinColumn([{{#joinColumnOptions}}{{> JoinColumnOptions}}{{/joinColumnOptions}}]){{/if}} {{#joinTableOptions}}@JoinTable({ name:"{{name}}", joinColumns:[{{#joinColumns}}{{> JoinColumnOptions}}{{/joinColumns}}],inverseJoinColumns:[{{#inverseJoinColumns}}{{> JoinColumnOptions}}{{/inverseJoinColumns}}],{{#database}}database:"{{.}}",{{/database}}{{#schema}}schema:"{{.}}"{{/schema}} }){{/joinTableOptions}} {{printPropertyVisibility}}{{toPropertyName fieldName}}{{strictMode}}:{{toRelation (toEntityName relatedTable) relationType}}; diff --git a/test/configs/.eslintrc.js b/test/configs/.eslintrc.js new file mode 100644 index 0000000..c2a28ca --- /dev/null +++ b/test/configs/.eslintrc.js @@ -0,0 +1,30 @@ +module.exports = { + env: { + node: true, + }, + extends: [ + "airbnb-base", + "plugin:@typescript-eslint/recommended", + "prettier", + "prettier/@typescript-eslint" + ], + parser: "@typescript-eslint/parser", + parserOptions: { + project: "test/configs/tsconfig.json" + }, + plugins: ["@typescript-eslint"], + rules: { // TODO: remove some rule overrides after disabling eslint on model customization tests(?) + "import/extensions": ["off"], + "import/prefer-default-export": ["off"], + "@typescript-eslint/no-explicit-any": ["off"], + "@typescript-eslint/camelcase": ["off"], + "@typescript-eslint/class-name-casing": ["off"] + }, + settings: { + "import/resolver": { + node: { + extensions: [".ts"] + } + } + } +}; diff --git a/test/configs/tsconfig.json b/test/configs/tsconfig.json new file mode 100644 index 0000000..8d56403 --- /dev/null +++ b/test/configs/tsconfig.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "module": "commonjs", + "target": "es2017", + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "moduleResolution": "node", + "newLine": "LF", + "typeRoots": [ + "../../node_modules/@types" + ], + "resolveJsonModule": true, + }, + "include": [ + "../../output" + ] +} diff --git a/test/integration/runTestsFromPath.test.ts b/test/integration/runTestsFromPath.test.ts index ec5eb24..10981de 100644 --- a/test/integration/runTestsFromPath.test.ts +++ b/test/integration/runTestsFromPath.test.ts @@ -6,6 +6,7 @@ import * as path from "path"; import * as chaiSubset from "chai-subset"; import * as flatMap from "array.prototype.flatmap"; import yn from "yn"; +import { CLIEngine } from "eslint"; import EntityFileToJson from "../utils/EntityFileToJson"; import { createDriver, dataCollectionPhase } from "../../src/Engine"; import * as GTU from "../utils/GeneralTestUtils"; @@ -277,6 +278,15 @@ export function compileGeneratedModel(filesGenPath: string, drivers: string[]) { compiledWithoutErrors, "Errors detected while compiling generated model" ).to.equal(true); + + + const cli = new CLIEngine({ configFile: "test/configs/.eslintrc.js" }); + const lintReport = cli.executeOnFiles(currentDirectoryFiles) + lintReport.results.forEach(result => result.messages.forEach(message => { + console.error(`${result.filePath}:${message.line} - ${message.message}`) + })) + expect(lintReport.errorCount).to.equal(0) + expect(lintReport.warningCount).to.equal(0) } async function prepareTestRuns( diff --git a/tsconfig.json b/tsconfig.json index 93cff05..3c6e9eb 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,29 +1,30 @@ { - "compilerOptions": { - "module": "commonjs", - "target": "es2017", - "noImplicitAny": false, - "emitDecoratorMetadata": true, - "experimentalDecorators": true, - "sourceMap": true, - "declaration": false, - "noFallthroughCasesInSwitch": true, - "noImplicitReturns": true, - "stripInternal": true, - "strictNullChecks": true, - "moduleResolution": "node", - "newLine": "LF", - "outDir": "dist", - "lib": [ - "es2019","es2019.array" - ], - "typeRoots": [ - "./node_modules/@types" - ], - "resolveJsonModule": true, - }, - "include": [ - "src", - "test" - ] + "compilerOptions": { + "module": "commonjs", + "target": "es2017", + "noImplicitAny": false, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "sourceMap": true, + "declaration": false, + "noFallthroughCasesInSwitch": true, + "noImplicitReturns": true, + "stripInternal": true, + "strictNullChecks": true, + "moduleResolution": "node", + "newLine": "LF", + "outDir": "dist", + "lib": [ + "es2019", + "es2019.array" + ], + "typeRoots": [ + "./node_modules/@types" + ], + "resolveJsonModule": true, + }, + "include": [ + "src", + "test", + ] } From dc4208ad0f42ad8516cb7c1d7c48dfc269b82934 Mon Sep 17 00:00:00 2001 From: Kononnable Date: Tue, 24 Dec 2019 10:40:36 +0100 Subject: [PATCH 74/84] Option to generate index file (#174) --- src/IGenerationOptions.ts | 4 +- src/ModelGeneration.ts | 59 +++++++++++++++++-- src/index.ts | 16 ++++- src/templates/index.mst | 3 + .../modelCustomization.test.ts | 48 +++++++++++++++ 5 files changed, 123 insertions(+), 7 deletions(-) create mode 100644 src/templates/index.mst diff --git a/src/IGenerationOptions.ts b/src/IGenerationOptions.ts index a12b3c4..1cb8568 100644 --- a/src/IGenerationOptions.ts +++ b/src/IGenerationOptions.ts @@ -18,6 +18,7 @@ export default interface IGenerationOptions { relationIds: boolean; strictMode: "none" | "?" | "!"; skipSchema: boolean; + indexFile: boolean; } export function getDefaultGenerationOptions(): IGenerationOptions { const generationOptions: IGenerationOptions = { @@ -34,7 +35,8 @@ export function getDefaultGenerationOptions(): IGenerationOptions { customNamingStrategyPath: "", relationIds: false, strictMode: "none", - skipSchema: false + skipSchema: false, + indexFile: false }; return generationOptions; } diff --git a/src/ModelGeneration.ts b/src/ModelGeneration.ts index dfc8e1f..758dc2a 100644 --- a/src/ModelGeneration.ts +++ b/src/ModelGeneration.ts @@ -14,8 +14,7 @@ export default function modelGenerationPhase( databaseModel: Entity[] ): void { createHandlebarsHelpers(generationOptions); - const templatePath = path.resolve(__dirname, "templates", "entity.mst"); - const template = fs.readFileSync(templatePath, "UTF-8"); + const resultPath = generationOptions.resultsPath; if (!fs.existsSync(resultPath)) { fs.mkdirSync(resultPath); @@ -29,7 +28,24 @@ export default function modelGenerationPhase( fs.mkdirSync(entitiesPath); } } - const compliedTemplate = Handlebars.compile(template, { + if (generationOptions.indexFile) { + createIndexFile(databaseModel, generationOptions, entitiesPath); + } + generateModels(databaseModel, generationOptions, entitiesPath); +} + +function generateModels( + databaseModel: Entity[], + generationOptions: IGenerationOptions, + entitiesPath: string +) { + const entityTemplatePath = path.resolve( + __dirname, + "templates", + "entity.mst" + ); + const entityTemplate = fs.readFileSync(entityTemplatePath, "UTF-8"); + const entityCompliedTemplate = Handlebars.compile(entityTemplate, { noEscape: true }); databaseModel.forEach(element => { @@ -54,7 +70,7 @@ export default function modelGenerationPhase( entitiesPath, `${casedFileName}.ts` ); - const rendered = compliedTemplate(element); + const rendered = entityCompliedTemplate(element); const withImportStatements = removeUnusedImports(rendered); const formatted = Prettier.format(withImportStatements, { parser: "typescript" @@ -65,6 +81,41 @@ export default function modelGenerationPhase( }); }); } + +function createIndexFile( + databaseModel: Entity[], + generationOptions: IGenerationOptions, + entitiesPath: string +) { + const templatePath = path.resolve(__dirname, "templates", "index.mst"); + const template = fs.readFileSync(templatePath, "UTF-8"); + const compliedTemplate = Handlebars.compile(template, { + noEscape: true + }); + const rendered = compliedTemplate({ entities: databaseModel }); + const formatted = Prettier.format(rendered, { + parser: "typescript" + }); + let fileName = "index"; + switch (generationOptions.convertCaseFile) { + case "camel": + fileName = changeCase.camelCase(fileName); + break; + case "param": + fileName = changeCase.paramCase(fileName); + break; + case "pascal": + fileName = changeCase.pascalCase(fileName); + break; + default: + } + const resultFilePath = path.resolve(entitiesPath, `${fileName}.ts`); + fs.writeFileSync(resultFilePath, formatted, { + encoding: "UTF-8", + flag: "w" + }); +} + function removeUnusedImports(rendered: string) { const openBracketIndex = rendered.indexOf("{") + 1; const closeBracketIndex = rendered.indexOf("}"); diff --git a/src/index.ts b/src/index.ts index b0264fb..07375ba 100644 --- a/src/index.ts +++ b/src/index.ts @@ -255,6 +255,11 @@ function checkYargsParameters(options: options): options { choices: ["none", "?", "!"], default: options.generationOptions.strictMode, describe: "Mark fields as optional(?) or non-null(!)" + }, + index: { + boolean: true, + default: options.generationOptions.indexFile, + describe: "Generate index file" } }); @@ -272,6 +277,7 @@ function checkYargsParameters(options: options): options { : standardSchema; options.connectionOptions.ssl = argv.ssl; options.connectionOptions.user = argv.u || standardUser; + options.connectionOptions.skipTables = argv.skipTables.split(","); options.generationOptions.activeRecord = argv.a; options.generationOptions.generateConstructor = argv.generateConstructor; options.generationOptions.convertCaseEntity = argv.ce as IGenerationOptions["convertCaseEntity"]; @@ -286,7 +292,7 @@ function checkYargsParameters(options: options): options { options.generationOptions.resultsPath = argv.o; options.generationOptions.pluralizeNames = !argv.disablePluralization; options.generationOptions.strictMode = argv.strictMode as IGenerationOptions["strictMode"]; - options.connectionOptions.skipTables = argv.skipTables.split(","); + options.generationOptions.indexFile = argv.index; return options; } @@ -499,9 +505,14 @@ async function useInquirer(options: options): Promise { }, { name: - "Pluralize OneToMany, ManyToMany relation names.", + "Pluralize OneToMany, ManyToMany relation names", value: "pluralize", checked: options.generationOptions.pluralizeNames + }, + { + name: "Generate index file", + value: "index", + checked: options.generationOptions.indexFile } ], message: "Available customizations", @@ -555,6 +566,7 @@ async function useInquirer(options: options): Promise { options.generationOptions.generateConstructor = customizations.includes( "constructor" ); + options.generationOptions.indexFile = customizations.includes("index"); if (customizations.includes("namingStrategy")) { const namingStrategyPath = ( diff --git a/src/templates/index.mst b/src/templates/index.mst new file mode 100644 index 0000000..928dd19 --- /dev/null +++ b/src/templates/index.mst @@ -0,0 +1,3 @@ +{{#entities~}} +export { {{toEntityName tscName}} } from './{{toFileName tscName}}' +{{/entities~}} \ No newline at end of file diff --git a/test/modelCustomization/modelCustomization.test.ts b/test/modelCustomization/modelCustomization.test.ts index b474300..acbde5f 100644 --- a/test/modelCustomization/modelCustomization.test.ts +++ b/test/modelCustomization/modelCustomization.test.ts @@ -665,4 +665,52 @@ describe("Model customization phase", async () => { compileGeneratedModel(generationOptions.resultsPath, [""]); }) }) + describe("index file generation", () => { + it("enabled", async () => { + + const data = generateSampleData(); + const generationOptions = generateGenerationOptions(); + generationOptions.indexFile = true; + clearGenerationDir(); + + const customizedModel = modelCustomizationPhase( + data, + generationOptions, + {} + ); + modelGenerationPhase( + getDefaultConnectionOptions(), + generationOptions, + customizedModel + ); + const filesGenPath = path.resolve(resultsPath, "entities"); + const indexFileContent = fs + .readFileSync(path.resolve(filesGenPath, "Index.ts")) + .toString(); + expect(indexFileContent).to.contain('export { Post } from "./Post";'); + expect(indexFileContent).to.contain('export { PostAuthor } from "./PostAuthor";'); + compileGeneratedModel(generationOptions.resultsPath, [""]); + }) + it("disabled", async () => { + + const data = generateSampleData(); + const generationOptions = generateGenerationOptions(); + generationOptions.pluralizeNames = false; + clearGenerationDir(); + + const customizedModel = modelCustomizationPhase( + data, + generationOptions, + {} + ); + modelGenerationPhase( + getDefaultConnectionOptions(), + generationOptions, + customizedModel + ); + const filesGenPath = path.resolve(resultsPath, "entities"); + expect(fs.existsSync(path.resolve(filesGenPath, "Index.ts"))).to.equal(false); + compileGeneratedModel(generationOptions.resultsPath, [""]); + }) + }) }); From 88d3947d32d9f24c6fd1e8bd2e6288df05b64bfb Mon Sep 17 00:00:00 2001 From: Kononnable Date: Wed, 25 Dec 2019 20:35:38 +0100 Subject: [PATCH 75/84] ability to generate models with default exports (instead of name exports) --- src/IGenerationOptions.ts | 4 ++- src/ModelGeneration.ts | 8 +++++ src/index.ts | 20 +++++++++++ src/templates/entity.mst | 4 +-- src/templates/index.mst | 6 ++-- .../modelCustomization.test.ts | 35 +++++++++++++++++-- 6 files changed, 69 insertions(+), 8 deletions(-) diff --git a/src/IGenerationOptions.ts b/src/IGenerationOptions.ts index 1cb8568..7e3ae8f 100644 --- a/src/IGenerationOptions.ts +++ b/src/IGenerationOptions.ts @@ -19,6 +19,7 @@ export default interface IGenerationOptions { strictMode: "none" | "?" | "!"; skipSchema: boolean; indexFile: boolean; + exportType: "named" | "default"; } export function getDefaultGenerationOptions(): IGenerationOptions { const generationOptions: IGenerationOptions = { @@ -36,7 +37,8 @@ export function getDefaultGenerationOptions(): IGenerationOptions { relationIds: false, strictMode: "none", skipSchema: false, - indexFile: false + indexFile: false, + exportType: "named" }; return generationOptions; } diff --git a/src/ModelGeneration.ts b/src/ModelGeneration.ts index 758dc2a..c723447 100644 --- a/src/ModelGeneration.ts +++ b/src/ModelGeneration.ts @@ -211,6 +211,14 @@ function createHandlebarsHelpers(generationOptions: IGenerationOptions): void { return retVal; } ); + Handlebars.registerHelper("defaultExport", () => + generationOptions.exportType === "default" ? "default" : "" + ); + Handlebars.registerHelper("localImport", (entityName: string) => + generationOptions.exportType === "default" + ? entityName + : `{${entityName}}` + ); Handlebars.registerHelper("strictMode", () => generationOptions.strictMode !== "none" ? generationOptions.strictMode diff --git a/src/index.ts b/src/index.ts index 07375ba..954f298 100644 --- a/src/index.ts +++ b/src/index.ts @@ -260,6 +260,11 @@ function checkYargsParameters(options: options): options { boolean: true, default: options.generationOptions.indexFile, describe: "Generate index file" + }, + defaultExport: { + boolean: true, + default: options.generationOptions.exportType === "default", + describe: "Generate index file" } }); @@ -293,6 +298,9 @@ function checkYargsParameters(options: options): options { options.generationOptions.pluralizeNames = !argv.disablePluralization; options.generationOptions.strictMode = argv.strictMode as IGenerationOptions["strictMode"]; options.generationOptions.indexFile = argv.index; + options.generationOptions.exportType = argv.defaultExport + ? "default" + : "named"; return options; } @@ -513,6 +521,13 @@ async function useInquirer(options: options): Promise { name: "Generate index file", value: "index", checked: options.generationOptions.indexFile + }, + { + name: "Prefer default exports", + value: "defaultExport", + checked: + options.generationOptions.exportType === + "default" } ], message: "Available customizations", @@ -567,6 +582,11 @@ async function useInquirer(options: options): Promise { "constructor" ); options.generationOptions.indexFile = customizations.includes("index"); + options.generationOptions.exportType = customizations.includes( + "defaultExport" + ) + ? "default" + : "named"; if (customizations.includes("namingStrategy")) { const namingStrategyPath = ( diff --git a/src/templates/entity.mst b/src/templates/entity.mst index ce84e6b..2c2c1c9 100644 --- a/src/templates/entity.mst +++ b/src/templates/entity.mst @@ -2,7 +2,7 @@ @Index("{{name}}",[{{#columns}}"{{toPropertyName .}}",{{/columns~}}],{ {{json options}} }) {{/inline}} {{#*inline "Import"}} -import { {{toEntityName .}} } from './{{toFileName .}}' +import {{localImport (toEntityName .)}} from './{{toFileName .}}' {{/inline}} {{#*inline "Column"}} {{#generated}}@PrimaryGeneratedColumn({ type:"{{type}}", {{/generated}}{{^generated}}@Column("{{type}}",{ {{#primary}}primary:{{primary}},{{/primary}}{{/generated}}{{json options}}{{#default}},default: {{.}},{{/default}} }) @@ -33,7 +33,7 @@ import { {{toEntityName .}} } from './{{toFileName .}}' {{#*inline "Entity"}} {{#indices}}{{> Index}}{{/indices~}} @Entity("{{sqlName}}"{{#schema}} ,{schema:"{{.}}"{{#if ../database}}, database:"{{../database}}"{{/if}} } {{/schema}}) -export class {{toEntityName tscName}}{{#activeRecord}} extends BaseEntity{{/activeRecord}} { +export {{defaultExport}} class {{toEntityName tscName}}{{#activeRecord}} extends BaseEntity{{/activeRecord}} { {{#columns}}{{> Column}}{{/columns~}} {{#relations}}{{> Relation}}{{/relations~}} diff --git a/src/templates/index.mst b/src/templates/index.mst index 928dd19..4c7d5fe 100644 --- a/src/templates/index.mst +++ b/src/templates/index.mst @@ -1,3 +1,5 @@ {{#entities~}} -export { {{toEntityName tscName}} } from './{{toFileName tscName}}' -{{/entities~}} \ No newline at end of file +import {{localImport (toEntityName tscName)}} from './{{toFileName tscName}}' +{{/entities}} + +export { {{#entities}}{{toEntityName tscName}},{{/entities~}} } diff --git a/test/modelCustomization/modelCustomization.test.ts b/test/modelCustomization/modelCustomization.test.ts index acbde5f..1f6cd47 100644 --- a/test/modelCustomization/modelCustomization.test.ts +++ b/test/modelCustomization/modelCustomization.test.ts @@ -666,7 +666,7 @@ describe("Model customization phase", async () => { }) }) describe("index file generation", () => { - it("enabled", async () => { + it("named export", async () => { const data = generateSampleData(); const generationOptions = generateGenerationOptions(); @@ -687,8 +687,36 @@ describe("Model customization phase", async () => { const indexFileContent = fs .readFileSync(path.resolve(filesGenPath, "Index.ts")) .toString(); - expect(indexFileContent).to.contain('export { Post } from "./Post";'); - expect(indexFileContent).to.contain('export { PostAuthor } from "./PostAuthor";'); + expect(indexFileContent).to.contain('import { PostAuthor } from "./PostAuthor'); + expect(indexFileContent).to.contain('import { Post } from "./Post'); + expect(indexFileContent).to.contain('export { PostAuthor, Post }'); + compileGeneratedModel(generationOptions.resultsPath, [""]); + }) + it("default export", async () => { + + const data = generateSampleData(); + const generationOptions = generateGenerationOptions(); + generationOptions.indexFile = true; + generationOptions.exportType = "default" + clearGenerationDir(); + + const customizedModel = modelCustomizationPhase( + data, + generationOptions, + {} + ); + modelGenerationPhase( + getDefaultConnectionOptions(), + generationOptions, + customizedModel + ); + const filesGenPath = path.resolve(resultsPath, "entities"); + const indexFileContent = fs + .readFileSync(path.resolve(filesGenPath, "Index.ts")) + .toString(); + expect(indexFileContent).to.contain('import PostAuthor from "./PostAuthor'); + expect(indexFileContent).to.contain('import Post from "./Post'); + expect(indexFileContent).to.contain('export { PostAuthor, Post }'); compileGeneratedModel(generationOptions.resultsPath, [""]); }) it("disabled", async () => { @@ -713,4 +741,5 @@ describe("Model customization phase", async () => { compileGeneratedModel(generationOptions.resultsPath, [""]); }) }) + }); From 0e3d766e7383ce667d81028fd13cafd5a4b50a22 Mon Sep 17 00:00:00 2001 From: Kononnable Date: Sat, 28 Dec 2019 12:01:52 +0100 Subject: [PATCH 76/84] avoid name colisions in tomg exports --- src/library.ts | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/src/library.ts b/src/library.ts index f054312..a7d8584 100644 --- a/src/library.ts +++ b/src/library.ts @@ -1,19 +1,18 @@ -import { Column as ColumnModel } from "./models/Column"; -import { Entity as EntityModel } from "./models/Entity"; -import { Index as IndexModel } from "./models/Index"; -import { Relation as RelationModel } from "./models/Relation"; -import { RelationId as RelationIdModel } from "./models/RelationId"; +import * as Engine from "./Engine"; +import * as IConnectionOptions from "./IConnectionOptions"; +import * as IGenerationOptions from "./IGenerationOptions"; +import * as NamingStrategy from "./NamingStrategy"; +import * as Utils from "./Utils"; -// models exports - there may be a more succinct way to export default classes, -// but this was the only one I could find that seemed happy -export type Column = ColumnModel; -export type Entity = EntityModel; -export type Index = IndexModel; -export type Relation = RelationModel; -export type RelationId = RelationIdModel; - -export * from "./Engine"; -export * from "./IConnectionOptions"; -export * from "./IGenerationOptions"; -export * from "./NamingStrategy"; -export * from "./Utils"; +export { Column } from "./models/Column"; +export { Entity } from "./models/Entity"; +export { Index } from "./models/Index"; +export { Relation } from "./models/Relation"; +export { RelationId } from "./models/RelationId"; +export { + Engine, + IConnectionOptions, + IGenerationOptions, + NamingStrategy, + Utils +}; From f0a6f67429aab4cd1e8bd17946725d05f9765d6f Mon Sep 17 00:00:00 2001 From: Kononnable Date: Sun, 29 Dec 2019 22:54:30 +0100 Subject: [PATCH 77/84] code changes, test for nullable columns --- src/drivers/AbstractDriver.ts | 21 +++++++++-------- src/drivers/MssqlDriver.ts | 22 ++++++++---------- src/drivers/MysqlDriver.ts | 21 ++++++++--------- src/drivers/OracleDriver.ts | 21 ++++++++--------- src/drivers/PostgresDriver.ts | 10 +++++--- src/drivers/SqliteDriver.ts | 23 +++++++++---------- test/drivers/MssqlDriver.test.ts | 3 +-- .../github-issues/227/entity/Post.ts | 15 ++++++++++++ 8 files changed, 75 insertions(+), 61 deletions(-) create mode 100644 test/integration/github-issues/227/entity/Post.ts diff --git a/src/drivers/AbstractDriver.ts b/src/drivers/AbstractDriver.ts index 3002fae..24d6c84 100644 --- a/src/drivers/AbstractDriver.ts +++ b/src/drivers/AbstractDriver.ts @@ -376,19 +376,20 @@ export default abstract class AbstractDriver { ownerColumns[0].tscName, ownerEntity ); - let relationIdType = ownerColumns[0].tscType; - if (ownerColumns[0].options.nullable) { - relationIdType += " | null"; + + let fieldType = ""; + if (isOneToMany) { + fieldType = `${ownerColumns[0].tscType}[]`; + } else { + fieldType = ownerColumns[0].tscType; + if (ownerColumns[0].options.nullable) { + fieldType += " | null"; + } } + ownerEntity.relationIds.push({ fieldName: relationIdFieldName, - fieldType: isOneToMany - ? `${ - relationIdType.includes(" ") - ? `(${relationIdType})` - : relationIdType - }[]` - : relationIdType, + fieldType, relationField: ownerRelation.fieldName }); // TODO: RelationId on ManyToMany diff --git a/src/drivers/MssqlDriver.ts b/src/drivers/MssqlDriver.ts index 94a84a0..706042b 100644 --- a/src/drivers/MssqlDriver.ts +++ b/src/drivers/MssqlDriver.ts @@ -90,7 +90,7 @@ WHERE TABLE_TYPE='BASE TABLE' and TABLE_SCHEMA in (${schema}) AND TABLE_CATALOG resp.COLUMN_DEFAULT ); const columnType = resp.DATA_TYPE; - let tscType = "NonNullable"; + let tscType = ""; switch (resp.DATA_TYPE) { case "bigint": tscType = "string"; @@ -192,6 +192,7 @@ WHERE TABLE_TYPE='BASE TABLE' and TABLE_SCHEMA in (${schema}) AND TABLE_CATALOG tscType = "string"; break; default: + tscType = "NonNullable"; TomgUtils.LogError( `Unknown column type: ${resp.DATA_TYPE} table name: ${resp.TABLE_NAME} column name: ${resp.COLUMN_NAME}` ); @@ -218,17 +219,14 @@ WHERE TABLE_TYPE='BASE TABLE' and TABLE_SCHEMA in (${schema}) AND TABLE_CATALOG ? resp.CHARACTER_MAXIMUM_LENGTH : undefined; } - - if (columnType) { - ent.columns.push({ - generated, - type: columnType, - default: defaultValue, - options, - tscName, - tscType - }); - } + ent.columns.push({ + generated, + type: columnType, + default: defaultValue, + options, + tscName, + tscType + }); }); }); return entities; diff --git a/src/drivers/MysqlDriver.ts b/src/drivers/MysqlDriver.ts index 7964dc3..88d5786 100644 --- a/src/drivers/MysqlDriver.ts +++ b/src/drivers/MysqlDriver.ts @@ -69,7 +69,7 @@ export default class MysqlDriver extends AbstractDriver { .filter(filterVal => filterVal.TABLE_NAME === ent.tscName) .forEach(resp => { const tscName = resp.COLUMN_NAME; - let tscType = "NonNullable"; + let tscType = ""; const options: Column["options"] = { name: resp.COLUMN_NAME }; @@ -214,6 +214,7 @@ export default class MysqlDriver extends AbstractDriver { tscType = "string"; break; default: + tscType = "NonNullable"; TomgUtils.LogError( `Unknown column type: ${resp.DATA_TYPE} table name: ${resp.TABLE_NAME} column name: ${resp.COLUMN_NAME}` ); @@ -250,16 +251,14 @@ export default class MysqlDriver extends AbstractDriver { : undefined; } - if (columnType) { - ent.columns.push({ - generated, - type: columnType, - default: defaultValue, - options, - tscName, - tscType - }); - } + ent.columns.push({ + generated, + type: columnType, + default: defaultValue, + options, + tscName, + tscType + }); }); }); return entities; diff --git a/src/drivers/OracleDriver.ts b/src/drivers/OracleDriver.ts index 9215935..08ea44e 100644 --- a/src/drivers/OracleDriver.ts +++ b/src/drivers/OracleDriver.ts @@ -87,7 +87,7 @@ export default class OracleDriver extends AbstractDriver { ); const DATA_TYPE = resp.DATA_TYPE.replace(/\([0-9]+\)/g, ""); const columnType = DATA_TYPE.toLowerCase(); - let tscType = "NonNullable"; + let tscType = ""; switch (DATA_TYPE.toLowerCase()) { case "char": tscType = "string"; @@ -177,6 +177,7 @@ export default class OracleDriver extends AbstractDriver { tscType = "number"; break; default: + tscType = "NonNullable"; TomgUtils.LogError( `Unknown column type:${DATA_TYPE}` ); @@ -201,16 +202,14 @@ export default class OracleDriver extends AbstractDriver { resp.DATA_LENGTH > 0 ? resp.DATA_LENGTH : undefined; } - if (columnType) { - ent.columns.push({ - generated, - type: columnType, - default: defaultValue, - options, - tscName, - tscType - }); - } + ent.columns.push({ + generated, + type: columnType, + default: defaultValue, + options, + tscName, + tscType + }); }); }); return entities; diff --git a/src/drivers/PostgresDriver.ts b/src/drivers/PostgresDriver.ts index ce91556..d5169ad 100644 --- a/src/drivers/PostgresDriver.ts +++ b/src/drivers/PostgresDriver.ts @@ -105,15 +105,16 @@ export default class PostgresDriver extends AbstractDriver { resp.data_type === "ARRAY" ) { TomgUtils.LogError( - `Unknown ${resp.data_type} column type: ${resp.udt_name} table name: ${resp.table_name} column name: ${resp.column_name}` + `Unknown ${resp.data_type} column type: ${resp.udt_name} table name: ${resp.table_name} column name: ${resp.column_name}` ); } else { TomgUtils.LogError( - `Unknown column type: ${resp.data_type} table name: ${resp.table_name} column name: ${resp.column_name}` + `Unknown column type: ${resp.data_type} table name: ${resp.table_name} column name: ${resp.column_name}` ); } return; } + const columnType = columnTypes.sqlType; let tscType = columnTypes.tsType; if (columnTypes.isArray) options.array = true; @@ -177,7 +178,7 @@ export default class PostgresDriver extends AbstractDriver { isArray: boolean; enumValues: string[]; } = { - tsType: "NonNullable", + tsType: "", sqlType: dataType, isArray: false, enumValues: [] @@ -391,6 +392,9 @@ export default class PostgresDriver extends AbstractDriver { break; } break; + default: + ret.tsType = "NonNullable"; + break; } return ret; } diff --git a/src/drivers/SqliteDriver.ts b/src/drivers/SqliteDriver.ts index 7f8e993..87392dc 100644 --- a/src/drivers/SqliteDriver.ts +++ b/src/drivers/SqliteDriver.ts @@ -65,7 +65,7 @@ export default class SqliteDriver extends AbstractDriver { }>(`PRAGMA table_info('${ent.tscName}');`); response.forEach(resp => { const tscName = resp.name; - let tscType = "NonNullable"; + let tscType = ""; const options: Column["options"] = { name: resp.name }; if (resp.notnull === 0) options.nullable = true; const isPrimary = resp.pk > 0 ? true : undefined; @@ -164,6 +164,7 @@ export default class SqliteDriver extends AbstractDriver { tscType = "Date"; break; default: + tscType = "NonNullable"; TomgUtils.LogError( `Unknown column type: ${columnType} table name: ${ent.tscName} column name: ${resp.name}` ); @@ -218,17 +219,15 @@ export default class SqliteDriver extends AbstractDriver { ); } - if (columnType) { - ent.columns.push({ - generated, - primary: isPrimary, - type: columnType, - default: defaultValue, - options, - tscName, - tscType - }); - } + ent.columns.push({ + generated, + primary: isPrimary, + type: columnType, + default: defaultValue, + options, + tscName, + tscType + }); }); }) ); diff --git a/test/drivers/MssqlDriver.test.ts b/test/drivers/MssqlDriver.test.ts index bfa577f..cf132be 100644 --- a/test/drivers/MssqlDriver.test.ts +++ b/test/drivers/MssqlDriver.test.ts @@ -74,7 +74,7 @@ describe("MssqlDriver", () => { COLUMN_DEFAULT: "'a'", COLUMN_NAME: "name", DATA_TYPE: "int", - IS_NULLABLE: "YES", + IS_NULLABLE: "NO", NUMERIC_PRECISION: 0, NUMERIC_SCALE: 0, IsIdentity: 1 @@ -99,7 +99,6 @@ describe("MssqlDriver", () => { const expected: Entity[] = JSON.parse(JSON.stringify(entities)); expected[0].columns.push({ options: { - nullable: true, name: "name" }, type: "int", diff --git a/test/integration/github-issues/227/entity/Post.ts b/test/integration/github-issues/227/entity/Post.ts new file mode 100644 index 0000000..20ce4c5 --- /dev/null +++ b/test/integration/github-issues/227/entity/Post.ts @@ -0,0 +1,15 @@ +import { PrimaryGeneratedColumn, Column, Entity, OneToOne, JoinColumn, Index } from "typeorm"; + +@Entity("Post") +export class Post { + + @PrimaryGeneratedColumn() + id: number; + + @Column("varchar", { nullable: true }) + title: string | null; + + @Column() + text: string; + +} From 30e72cfed75a9c9f7019af097f6511c204f3bace Mon Sep 17 00:00:00 2001 From: Pawe Kotarski Date: Mon, 30 Dec 2019 09:24:33 +0100 Subject: [PATCH 78/84] change tsconfig to fix issue with yarn(#203) --- tsconfig.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tsconfig.json b/tsconfig.json index 2db14d9..85e2d71 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -26,5 +26,6 @@ "include": [ "src", "test", - ] + ], + "exclude": ["**/node_modules", "node_modules"] } From 68427b8ea1d83b055561e4c2202c02725f57db3a Mon Sep 17 00:00:00 2001 From: Kononnable Date: Mon, 30 Dec 2019 09:51:19 +0100 Subject: [PATCH 79/84] removed nodejs verion reaching EOL --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index ca336d4..9af7e5c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,7 +3,6 @@ node_js: - 13 - 12 - 10 -- 8 cache: npm sudo: required services: From 7de3216c82c5ea52d451ca9c967569128f145ebe Mon Sep 17 00:00:00 2001 From: Kononnable Date: Mon, 30 Dec 2019 11:03:52 +0100 Subject: [PATCH 80/84] update docker mssql image - consume less resources --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index 5ff1d03..57dc65e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -38,7 +38,7 @@ services: # mssql mssql: - image: "mcr.microsoft.com/mssql/server:2017-GA-ubuntu" + image: "mcr.microsoft.com/mssql/server:2017-latest-ubuntu" container_name: "typeorm-mg-mssql" ports: - "1433:1433" From 51ac139ad7447ca610f85d2eecdbd93577b37995 Mon Sep 17 00:00:00 2001 From: Kononnable Date: Sun, 5 Jan 2020 01:29:14 +0100 Subject: [PATCH 81/84] proper fix for shadowed names --- src/templates/entity.mst | 2 +- test/integration/runTestsFromPath.test.ts | 29 ++++++---- .../modelCustomization.test.ts | 58 +++++++++---------- 3 files changed, 47 insertions(+), 42 deletions(-) diff --git a/src/templates/entity.mst b/src/templates/entity.mst index 12382ad..c9b57e8 100644 --- a/src/templates/entity.mst +++ b/src/templates/entity.mst @@ -13,7 +13,7 @@ import {{localImport (toEntityName .)}} from './{{toFileName .}}' { name: "{{name}}", referencedColumnName: "{{toPropertyName referencedColumnName}}" }, {{/inline}} {{#*inline "Relation"}} -@{{relationType}}(()=>{{toEntityName relatedTable}},{{toEntityName relatedTable}}_=>{{toEntityName relatedTable}}_.{{toPropertyName relatedField}}{{#if relationOptions}},{ {{json relationOptions}} }{{/if}}) +@{{relationType}}(()=>{{toEntityName relatedTable}},{{toPropertyName relatedTable}}=>{{toPropertyName relatedTable}}.{{toPropertyName relatedField}}{{#if relationOptions}},{ {{json relationOptions}} }{{/if}}) {{#if joinColumnOptions}}@JoinColumn([{{#joinColumnOptions}}{{> JoinColumnOptions}}{{/joinColumnOptions}}]){{/if}} {{#joinTableOptions}}@JoinTable({ name:"{{name}}", joinColumns:[{{#joinColumns}}{{> JoinColumnOptions}}{{/joinColumns}}],inverseJoinColumns:[{{#inverseJoinColumns}}{{> JoinColumnOptions}}{{/inverseJoinColumns}}],{{#database}}database:"{{.}}",{{/database}}{{#schema}}schema:"{{.}}"{{/schema}} }){{/joinTableOptions}} {{printPropertyVisibility}}{{toPropertyName fieldName}}{{strictMode}}:{{toRelation (toEntityName relatedTable) relationType}}; diff --git a/test/integration/runTestsFromPath.test.ts b/test/integration/runTestsFromPath.test.ts index 10981de..9b52340 100644 --- a/test/integration/runTestsFromPath.test.ts +++ b/test/integration/runTestsFromPath.test.ts @@ -24,7 +24,7 @@ const { expect } = chai; it("Column default values", async () => { const testPartialPath = "test/integration/defaultValues"; await runTestsFromPath(testPartialPath, true); -}) +}); it("Platform specific types", async () => { const testPartialPath = "test/integration/entityTypes"; await runTestsFromPath(testPartialPath, true); @@ -249,7 +249,11 @@ function compareGeneratedFiles(filesOrgPathTS: string, filesGenPath: string) { // TODO: Move(?) // eslint-disable-next-line import/prefer-default-export -export function compileGeneratedModel(filesGenPath: string, drivers: string[]) { +export function compileGeneratedModel( + filesGenPath: string, + drivers: string[], + lintGeneratedFiles = true +) { const currentDirectoryFiles: string[] = []; drivers.forEach(driver => { const entitiesPath = path.resolve(filesGenPath, driver, "entities"); @@ -279,14 +283,19 @@ export function compileGeneratedModel(filesGenPath: string, drivers: string[]) { "Errors detected while compiling generated model" ).to.equal(true); - - const cli = new CLIEngine({ configFile: "test/configs/.eslintrc.js" }); - const lintReport = cli.executeOnFiles(currentDirectoryFiles) - lintReport.results.forEach(result => result.messages.forEach(message => { - console.error(`${result.filePath}:${message.line} - ${message.message}`) - })) - expect(lintReport.errorCount).to.equal(0) - expect(lintReport.warningCount).to.equal(0) + if (lintGeneratedFiles) { + const cli = new CLIEngine({ configFile: "test/configs/.eslintrc.js" }); + const lintReport = cli.executeOnFiles(currentDirectoryFiles); + lintReport.results.forEach(result => + result.messages.forEach(message => { + console.error( + `${result.filePath}:${message.line} - ${message.message}` + ); + }) + ); + expect(lintReport.errorCount).to.equal(0); + expect(lintReport.warningCount).to.equal(0); + } } async function prepareTestRuns( diff --git a/test/modelCustomization/modelCustomization.test.ts b/test/modelCustomization/modelCustomization.test.ts index 1f6cd47..8082c48 100644 --- a/test/modelCustomization/modelCustomization.test.ts +++ b/test/modelCustomization/modelCustomization.test.ts @@ -4,13 +4,9 @@ import * as chai from "chai"; import * as chaiSubset from "chai-subset"; import { Entity } from "../../src/models/Entity"; import modelCustomizationPhase from "../../src/ModelCustomization"; -import { - getDefaultGenerationOptions -} from "../../src/IGenerationOptions"; +import { getDefaultGenerationOptions } from "../../src/IGenerationOptions"; import modelGenerationPhase from "../../src/ModelGeneration"; -import { - getDefaultConnectionOptions -} from "../../src/IConnectionOptions"; +import { getDefaultConnectionOptions } from "../../src/IConnectionOptions"; import { compileGeneratedModel } from "../integration/runTestsFromPath.test"; chai.use(chaiSubset); @@ -226,7 +222,7 @@ describe("Model customization phase", async () => { expect(postContent).to.contain("class post {"); expect(postAuthorContent).to.contain("class postAuthor {"); - compileGeneratedModel(generationOptions.resultsPath, [""]); + compileGeneratedModel(generationOptions.resultsPath, [""], false); }); }); describe("case-property", async () => { @@ -256,7 +252,7 @@ describe("Model customization phase", async () => { expect(postContent).to.contain("Title: string;"); expect(postAuthorContent).to.contain("Posts: Post[];"); - compileGeneratedModel(generationOptions.resultsPath, [""]); + compileGeneratedModel(generationOptions.resultsPath, [""], false); }); it("camelCase", () => { const data = generateSampleData(); @@ -575,9 +571,9 @@ describe("Model customization phase", async () => { const data = generateSampleData(); const generationOptions = generateGenerationOptions(); clearGenerationDir(); - generationOptions.convertCaseEntity = "none" - generationOptions.convertCaseFile = "none" - generationOptions.convertCaseProperty = "none" + generationOptions.convertCaseEntity = "none"; + generationOptions.convertCaseFile = "none"; + generationOptions.convertCaseProperty = "none"; generationOptions.customNamingStrategyPath = "test/modelCustomization/testNamingStrategy.ts"; // TODO: relationId @@ -613,11 +609,10 @@ describe("Model customization phase", async () => { `import { Post_B } from "./Post_B";` ); - compileGeneratedModel(generationOptions.resultsPath, [""]); + compileGeneratedModel(generationOptions.resultsPath, [""], false); }); describe("pluralization", () => { it("enabled", async () => { - const data = generateSampleData(); const generationOptions = generateGenerationOptions(); generationOptions.pluralizeNames = true; @@ -639,9 +634,8 @@ describe("Model customization phase", async () => { .toString(); expect(postAuthorContent).to.contain("posts: Post[];"); compileGeneratedModel(generationOptions.resultsPath, [""]); - }) + }); it("disabled", async () => { - const data = generateSampleData(); const generationOptions = generateGenerationOptions(); generationOptions.pluralizeNames = false; @@ -663,11 +657,10 @@ describe("Model customization phase", async () => { .toString(); expect(postAuthorContent).to.contain("post: Post[];"); compileGeneratedModel(generationOptions.resultsPath, [""]); - }) - }) + }); + }); describe("index file generation", () => { it("named export", async () => { - const data = generateSampleData(); const generationOptions = generateGenerationOptions(); generationOptions.indexFile = true; @@ -687,17 +680,18 @@ describe("Model customization phase", async () => { const indexFileContent = fs .readFileSync(path.resolve(filesGenPath, "Index.ts")) .toString(); - expect(indexFileContent).to.contain('import { PostAuthor } from "./PostAuthor'); + expect(indexFileContent).to.contain( + 'import { PostAuthor } from "./PostAuthor' + ); expect(indexFileContent).to.contain('import { Post } from "./Post'); - expect(indexFileContent).to.contain('export { PostAuthor, Post }'); + expect(indexFileContent).to.contain("export { PostAuthor, Post }"); compileGeneratedModel(generationOptions.resultsPath, [""]); - }) + }); it("default export", async () => { - const data = generateSampleData(); const generationOptions = generateGenerationOptions(); generationOptions.indexFile = true; - generationOptions.exportType = "default" + generationOptions.exportType = "default"; clearGenerationDir(); const customizedModel = modelCustomizationPhase( @@ -714,13 +708,14 @@ describe("Model customization phase", async () => { const indexFileContent = fs .readFileSync(path.resolve(filesGenPath, "Index.ts")) .toString(); - expect(indexFileContent).to.contain('import PostAuthor from "./PostAuthor'); + expect(indexFileContent).to.contain( + 'import PostAuthor from "./PostAuthor' + ); expect(indexFileContent).to.contain('import Post from "./Post'); - expect(indexFileContent).to.contain('export { PostAuthor, Post }'); + expect(indexFileContent).to.contain("export { PostAuthor, Post }"); compileGeneratedModel(generationOptions.resultsPath, [""]); - }) + }); it("disabled", async () => { - const data = generateSampleData(); const generationOptions = generateGenerationOptions(); generationOptions.pluralizeNames = false; @@ -737,9 +732,10 @@ describe("Model customization phase", async () => { customizedModel ); const filesGenPath = path.resolve(resultsPath, "entities"); - expect(fs.existsSync(path.resolve(filesGenPath, "Index.ts"))).to.equal(false); + expect( + fs.existsSync(path.resolve(filesGenPath, "Index.ts")) + ).to.equal(false); compileGeneratedModel(generationOptions.resultsPath, [""]); - }) - }) - + }); + }); }); From 5e4777318c61541046586d45fe6a1bbb00690498 Mon Sep 17 00:00:00 2001 From: Kononnable Date: Sun, 5 Jan 2020 18:16:45 +0100 Subject: [PATCH 82/84] disallow generation of relationId fields with lazy relations --- src/index.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/index.ts b/src/index.ts index 954f298..9f40faf 100644 --- a/src/index.ts +++ b/src/index.ts @@ -30,6 +30,7 @@ async function CliLogic() { } else if (!TOMLConfig.fullConfigFile) { options = await useInquirer(options); } + options = validateConfig(options); const driver = createDriver(options.connectionOptions.databaseType); console.log( `[${new Date().toLocaleTimeString()}] Starting creation of model classes.` @@ -43,6 +44,19 @@ async function CliLogic() { `[${new Date().toLocaleTimeString()}] Typeorm model classes created.` ); } +function validateConfig(options: options): options { + if ( + options.generationOptions.lazy && + options.generationOptions.relationIds + ) { + TomgUtils.LogError( + "Typeorm doesn't support RelationId fields for lazy relations.", + false + ); + options.generationOptions.relationIds = false; + } + return options; +} function makeDefaultConfigs() { const generationOptions = getDefaultGenerationOptions(); const connectionOptions = getDefaultConnectionOptions(); From 4abf8efef0299fd08a7c715fea655283a11b2586 Mon Sep 17 00:00:00 2001 From: Kononnable Date: Sun, 5 Jan 2020 20:00:56 +0100 Subject: [PATCH 83/84] dependencies update --- package-lock.json | 1652 +++++++++++++++++++++++---------------------- package.json | 36 +- 2 files changed, 851 insertions(+), 837 deletions(-) diff --git a/package-lock.json b/package-lock.json index 08564cc..86dd18f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -43,17 +43,70 @@ "@babel/highlight": "^7.0.0" } }, - "@babel/generator": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.4.4.tgz", - "integrity": "sha512-53UOLK6TVNqKxf7RUh8NE851EHRxOOeVXKbK2bivdb+iziMyk03Sr4eaE9OELCbyZAAafAKPDwF2TPUES5QbxQ==", + "@babel/core": { + "version": "7.7.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.7.7.tgz", + "integrity": "sha512-jlSjuj/7z138NLZALxVgrx13AOtqip42ATZP7+kYl53GvDV6+4dCek1mVUo8z8c8Xnw/mx2q3d9HWh3griuesQ==", "dev": true, "requires": { - "@babel/types": "^7.4.4", + "@babel/code-frame": "^7.5.5", + "@babel/generator": "^7.7.7", + "@babel/helpers": "^7.7.4", + "@babel/parser": "^7.7.7", + "@babel/template": "^7.7.4", + "@babel/traverse": "^7.7.4", + "@babel/types": "^7.7.4", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "json5": "^2.1.0", + "lodash": "^4.17.13", + "resolve": "^1.3.2", + "semver": "^5.4.1", + "source-map": "^0.5.0" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.5.5.tgz", + "integrity": "sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw==", + "dev": true, + "requires": { + "@babel/highlight": "^7.0.0" + } + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "@babel/generator": { + "version": "7.7.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.7.7.tgz", + "integrity": "sha512-/AOIBpHh/JU1l0ZFS4kiRCBnLi6OTHzh0RPk3h9isBxkkqELtQNFi1Vr/tiG9p1yfoUdKVwISuXWQR+hwwM4VQ==", + "dev": true, + "requires": { + "@babel/types": "^7.7.4", "jsesc": "^2.5.1", - "lodash": "^4.17.11", - "source-map": "^0.5.0", - "trim-right": "^1.0.1" + "lodash": "^4.17.13", + "source-map": "^0.5.0" }, "dependencies": { "source-map": { @@ -65,32 +118,43 @@ } }, "@babel/helper-function-name": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz", - "integrity": "sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.7.4.tgz", + "integrity": "sha512-AnkGIdiBhEuiwdoMnKm7jfPfqItZhgRaZfMg1XX3bS25INOnLPjPG1Ppnajh8eqgt5kPJnfqrRHqFqmjKDZLzQ==", "dev": true, "requires": { - "@babel/helper-get-function-arity": "^7.0.0", - "@babel/template": "^7.1.0", - "@babel/types": "^7.0.0" + "@babel/helper-get-function-arity": "^7.7.4", + "@babel/template": "^7.7.4", + "@babel/types": "^7.7.4" } }, "@babel/helper-get-function-arity": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz", - "integrity": "sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.7.4.tgz", + "integrity": "sha512-QTGKEdCkjgzgfJ3bAyRwF4yyT3pg+vDgan8DSivq1eS0gwi+KGKE5x8kRcbeFTb/673mkO5SN1IZfmCfA5o+EA==", "dev": true, "requires": { - "@babel/types": "^7.0.0" + "@babel/types": "^7.7.4" } }, "@babel/helper-split-export-declaration": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.4.tgz", - "integrity": "sha512-Ro/XkzLf3JFITkW6b+hNxzZ1n5OQ80NvIUdmHspih1XAhtN3vPTuUFT4eQnela+2MaZ5ulH+iyP513KJrxbN7Q==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.7.4.tgz", + "integrity": "sha512-guAg1SXFcVr04Guk9eq0S4/rWS++sbmyqosJzVs8+1fH5NI+ZcmkaSkc7dmtAFbHFva6yRJnjW3yAcGxjueDug==", "dev": true, "requires": { - "@babel/types": "^7.4.4" + "@babel/types": "^7.7.4" + } + }, + "@babel/helpers": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.7.4.tgz", + "integrity": "sha512-ak5NGZGJ6LV85Q1Zc9gn2n+ayXOizryhjSUBTdu5ih1tlVCJeuQENzc4ItyCVhINVXvIT/ZQ4mheGIsfBkpskg==", + "dev": true, + "requires": { + "@babel/template": "^7.7.4", + "@babel/traverse": "^7.7.4", + "@babel/types": "^7.7.4" } }, "@babel/highlight": { @@ -105,39 +169,48 @@ } }, "@babel/parser": { - "version": "7.4.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.4.5.tgz", - "integrity": "sha512-9mUqkL1FF5T7f0WDFfAoDdiMVPWsdD1gZYzSnaXsxUCUqzuch/8of9G3VUSNiZmMBoRxT3neyVsqeiL/ZPcjew==", + "version": "7.7.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.7.7.tgz", + "integrity": "sha512-WtTZMZAZLbeymhkd/sEaPD8IQyGAhmuTuvTzLiCFM7iXiVdY0gc0IaI+cW0fh1BnSMbJSzXX6/fHllgHKwHhXw==", "dev": true }, "@babel/template": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.4.4.tgz", - "integrity": "sha512-CiGzLN9KgAvgZsnivND7rkA+AeJ9JB0ciPOD4U59GKbQP2iQl+olF1l76kJOupqidozfZ32ghwBEJDhnk9MEcw==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.7.4.tgz", + "integrity": "sha512-qUzihgVPguAzXCK7WXw8pqs6cEwi54s3E+HrejlkuWO6ivMKx9hZl3Y2fSXp9i5HgyWmj7RKP+ulaYnKM4yYxw==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", - "@babel/parser": "^7.4.4", - "@babel/types": "^7.4.4" + "@babel/parser": "^7.7.4", + "@babel/types": "^7.7.4" } }, "@babel/traverse": { - "version": "7.4.5", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.4.5.tgz", - "integrity": "sha512-Vc+qjynwkjRmIFGxy0KYoPj4FdVDxLej89kMHFsWScq999uX+pwcX4v9mWRjW0KcAYTPAuVQl2LKP1wEVLsp+A==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.7.4.tgz", + "integrity": "sha512-P1L58hQyupn8+ezVA2z5KBm4/Zr4lCC8dwKCMYzsa5jFMDMQAzaBNy9W5VjB+KAmBjb40U7a/H6ao+Xo+9saIw==", "dev": true, "requires": { - "@babel/code-frame": "^7.0.0", - "@babel/generator": "^7.4.4", - "@babel/helper-function-name": "^7.1.0", - "@babel/helper-split-export-declaration": "^7.4.4", - "@babel/parser": "^7.4.5", - "@babel/types": "^7.4.4", + "@babel/code-frame": "^7.5.5", + "@babel/generator": "^7.7.4", + "@babel/helper-function-name": "^7.7.4", + "@babel/helper-split-export-declaration": "^7.7.4", + "@babel/parser": "^7.7.4", + "@babel/types": "^7.7.4", "debug": "^4.1.0", "globals": "^11.1.0", - "lodash": "^4.17.11" + "lodash": "^4.17.13" }, "dependencies": { + "@babel/code-frame": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.5.5.tgz", + "integrity": "sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw==", + "dev": true, + "requires": { + "@babel/highlight": "^7.0.0" + } + }, "debug": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", @@ -150,16 +223,76 @@ } }, "@babel/types": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.4.4.tgz", - "integrity": "sha512-dOllgYdnEFOebhkKCjzSVFqw/PmmB8pH6RGOWkY4GsboQNd47b1fBThBSwlHAq9alF9vc1M3+6oqR47R50L0tQ==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.7.4.tgz", + "integrity": "sha512-cz5Ji23KCi4T+YIE/BolWosrJuSmoZeN1EFnRtBwF+KKLi8GG/Z2c2hOJJeCXPk4mwk4QFvTmwIodJowXgttRA==", "dev": true, "requires": { "esutils": "^2.0.2", - "lodash": "^4.17.11", + "lodash": "^4.17.13", "to-fast-properties": "^2.0.0" } }, + "@istanbuljs/load-nyc-config": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.0.0.tgz", + "integrity": "sha512-ZR0rq/f/E4f4XcgnDvtMWXCUJpi8eO0rssVhmztsZqLIEFA9UUP9zmpE0VxlM+kv/E1ul2I876Fwil2ayptDVg==", + "dev": true, + "requires": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "dependencies": { + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true + } + } + }, + "@istanbuljs/schema": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.2.tgz", + "integrity": "sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw==", + "dev": true + }, "@nodelib/fs.scandir": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz", @@ -196,9 +329,9 @@ } }, "@sinonjs/commons": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.6.0.tgz", - "integrity": "sha512-w4/WHG7C4WWFyE5geCieFJF6MZkbW4VAriol5KlmQXpAQdxvV0p26sqNZOW6Qyw6Y0l9K4g+cHvvczR2sEEpqg==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.7.0.tgz", + "integrity": "sha512-qbk9AP+cZUsKdW1GJsBpxPKFmCJ0T8swwzVje3qFd+AkQb74Q/tiuzrdfFg8AD2g5HH/XbE/I8Uc1KYHVYWfhg==", "dev": true, "requires": { "type-detect": "4.0.8" @@ -379,9 +512,9 @@ } }, "@types/node": { - "version": "12.12.21", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.21.tgz", - "integrity": "sha512-8sRGhbpU+ck1n0PGAUgVrWrWdjSW2aqNeyC15W88GRsMpSwzv6RJGlLhE7s2RhVSOdyDmxbqlWSeThq4/7xqlA==" + "version": "13.1.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-13.1.4.tgz", + "integrity": "sha512-Lue/mlp2egZJoHXZr4LndxDAd7i/7SQYhV0EjWfb/a4/OZ6tuVwMCVPiwkU5nsEipxEf7hmkSU7Em5VQ8P5NGA==" }, "@types/normalize-package-data": { "version": "2.4.0", @@ -408,9 +541,9 @@ } }, "@types/pg": { - "version": "7.11.2", - "resolved": "https://registry.npmjs.org/@types/pg/-/pg-7.11.2.tgz", - "integrity": "sha512-4+rj7fnidA77jFURNanuPPc1HrQv+RkhI6s+K18G9zOKbOUUpChA/rbNMqFukNuZ89LoIt/I9dAlxf329TjCNw==", + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/@types/pg/-/pg-7.14.1.tgz", + "integrity": "sha512-gQgg4bLuykokypx4O1fwEzl5e6UjjyaBtN3znn5zhm0YB9BnKyHDw+e4cQY9rAPzpdM2qpJbn9TNzUazbmTsdw==", "dev": true, "requires": { "@types/node": "*", @@ -418,13 +551,10 @@ } }, "@types/pg-types": { - "version": "1.11.4", - "resolved": "https://registry.npmjs.org/@types/pg-types/-/pg-types-1.11.4.tgz", - "integrity": "sha512-WdIiQmE347LGc1Vq3Ki8sk3iyCuLgnccqVzgxek6gEHp2H0p3MQ3jniIHt+bRODXKju4kNQ+mp53lmP5+/9moQ==", - "dev": true, - "requires": { - "moment": ">=2.14.0" - } + "version": "1.11.5", + "resolved": "https://registry.npmjs.org/@types/pg-types/-/pg-types-1.11.5.tgz", + "integrity": "sha512-L8ogeT6vDzT1vxlW3KITTCt+BVXXVkLXfZ/XNm6UqbcJgxf+KPO7yjWx7dQQE8RW07KopL10x2gNMs41+IkMGQ==", + "dev": true }, "@types/pluralize": { "version": "0.0.29", @@ -454,9 +584,9 @@ "dev": true }, "@types/sqlite3": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/@types/sqlite3/-/sqlite3-3.1.5.tgz", - "integrity": "sha512-upsrd1zEYMa4Y+prurQ+vpo5SN63BUF6tOjeTv3ziF+9W9PHVh4/S5cy0qAqkHvmOEm/AZhEKd7V/0bR2udmFw==", + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/@types/sqlite3/-/sqlite3-3.1.6.tgz", + "integrity": "sha512-OBsK0KIGUICExQ/ZvnPY4cKx5Kz4NcrVyGTIvOL5y4ajXu7r++RfBajfpGfGDmDVCKcoCDX1dO84/oeyeITnxA==", "dev": true, "requires": { "@types/node": "*" @@ -489,9 +619,9 @@ } }, "@types/yargs": { - "version": "13.0.3", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.3.tgz", - "integrity": "sha512-K8/LfZq2duW33XW/tFwEAfnZlqIfVsoyRB3kfXdPXYhl0nfM8mmh7GS0jg7WrX2Dgq/0Ha/pR1PaR+BvmWwjiQ==", + "version": "13.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.4.tgz", + "integrity": "sha512-Ke1WmBbIkVM8bpvsNEcGgQM70XcEh/nbpxQhW7FhrsbCsXSY9BmLB1+LHtD7r9zrsOcFlLiF+a/UeJsdfw3C5A==", "dev": true, "requires": { "@types/yargs-parser": "*" @@ -504,200 +634,45 @@ "dev": true }, "@typescript-eslint/eslint-plugin": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.12.0.tgz", - "integrity": "sha512-1t4r9rpLuEwl3hgt90jY18wJHSyb0E3orVL3DaqwmpiSDHmHiSspVsvsFF78BJ/3NNG3qmeso836jpuBWYziAA==", + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.14.0.tgz", + "integrity": "sha512-sneOJ3Hu0m5whJiVIxGBZZZMxMJ7c0LhAJzeMJgHo+n5wFs+/6rSR/gl7crkdR2kNwfOOSdzdc0gMvatG4dX2Q==", "dev": true, "requires": { - "@typescript-eslint/experimental-utils": "2.12.0", + "@typescript-eslint/experimental-utils": "2.14.0", "eslint-utils": "^1.4.3", "functional-red-black-tree": "^1.0.1", "regexpp": "^3.0.0", "tsutils": "^3.17.1" - }, - "dependencies": { - "@typescript-eslint/experimental-utils": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-2.12.0.tgz", - "integrity": "sha512-jv4gYpw5N5BrWF3ntROvCuLe1IjRenLy5+U57J24NbPGwZFAjhnM45qpq0nDH1y/AZMb3Br25YiNVwyPbz6RkA==", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.3", - "@typescript-eslint/typescript-estree": "2.12.0", - "eslint-scope": "^5.0.0" - } - }, - "@typescript-eslint/typescript-estree": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-2.12.0.tgz", - "integrity": "sha512-rGehVfjHEn8Frh9UW02ZZIfJs6SIIxIu/K1bbci8rFfDE/1lQ8krIJy5OXOV3DVnNdDPtoiPOdEANkLMrwXbiQ==", - "dev": true, - "requires": { - "debug": "^4.1.1", - "eslint-visitor-keys": "^1.1.0", - "glob": "^7.1.6", - "is-glob": "^4.0.1", - "lodash.unescape": "4.0.1", - "semver": "^6.3.0", - "tsutils": "^3.17.1" - } - }, - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "regexpp": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.0.0.tgz", - "integrity": "sha512-Z+hNr7RAVWxznLPuA7DIh8UNX1j9CDrUQxskw9IrBE1Dxue2lyXT+shqEIeLUjrokxIP8CMy1WkjgG3rTsd5/g==", - "dev": true - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } } }, "@typescript-eslint/experimental-utils": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-2.12.0.tgz", - "integrity": "sha512-jv4gYpw5N5BrWF3ntROvCuLe1IjRenLy5+U57J24NbPGwZFAjhnM45qpq0nDH1y/AZMb3Br25YiNVwyPbz6RkA==", + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-2.14.0.tgz", + "integrity": "sha512-KcyKS7G6IWnIgl3ZpyxyBCxhkBPV+0a5Jjy2g5HxlrbG2ZLQNFeneIBVXdaBCYOVjvGmGGFKom1kgiAY75SDeQ==", "dev": true, "requires": { "@types/json-schema": "^7.0.3", - "@typescript-eslint/typescript-estree": "2.12.0", + "@typescript-eslint/typescript-estree": "2.14.0", "eslint-scope": "^5.0.0" - }, - "dependencies": { - "@typescript-eslint/typescript-estree": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-2.12.0.tgz", - "integrity": "sha512-rGehVfjHEn8Frh9UW02ZZIfJs6SIIxIu/K1bbci8rFfDE/1lQ8krIJy5OXOV3DVnNdDPtoiPOdEANkLMrwXbiQ==", - "dev": true, - "requires": { - "debug": "^4.1.1", - "eslint-visitor-keys": "^1.1.0", - "glob": "^7.1.6", - "is-glob": "^4.0.1", - "lodash.unescape": "4.0.1", - "semver": "^6.3.0", - "tsutils": "^3.17.1" - } - }, - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } } }, "@typescript-eslint/parser": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-2.12.0.tgz", - "integrity": "sha512-lPdkwpdzxEfjI8TyTzZqPatkrswLSVu4bqUgnB03fHSOwpC7KSerPgJRgIAf11UGNf7HKjJV6oaPZI4AghLU6g==", + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-2.14.0.tgz", + "integrity": "sha512-haS+8D35fUydIs+zdSf4BxpOartb/DjrZ2IxQ5sR8zyGfd77uT9ZJZYF8+I0WPhzqHmfafUBx8MYpcp8pfaoSA==", "dev": true, "requires": { "@types/eslint-visitor-keys": "^1.0.0", - "@typescript-eslint/experimental-utils": "2.12.0", - "@typescript-eslint/typescript-estree": "2.12.0", + "@typescript-eslint/experimental-utils": "2.14.0", + "@typescript-eslint/typescript-estree": "2.14.0", "eslint-visitor-keys": "^1.1.0" - }, - "dependencies": { - "@typescript-eslint/typescript-estree": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-2.12.0.tgz", - "integrity": "sha512-rGehVfjHEn8Frh9UW02ZZIfJs6SIIxIu/K1bbci8rFfDE/1lQ8krIJy5OXOV3DVnNdDPtoiPOdEANkLMrwXbiQ==", - "dev": true, - "requires": { - "debug": "^4.1.1", - "eslint-visitor-keys": "^1.1.0", - "glob": "^7.1.6", - "is-glob": "^4.0.1", - "lodash.unescape": "4.0.1", - "semver": "^6.3.0", - "tsutils": "^3.17.1" - } - }, - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } } }, "@typescript-eslint/typescript-estree": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-2.12.0.tgz", - "integrity": "sha512-rGehVfjHEn8Frh9UW02ZZIfJs6SIIxIu/K1bbci8rFfDE/1lQ8krIJy5OXOV3DVnNdDPtoiPOdEANkLMrwXbiQ==", + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-2.14.0.tgz", + "integrity": "sha512-pnLpUcMNG7GfFFfNQbEX6f1aPa5fMnH2G9By+A1yovYI4VIOK2DzkaRuUlIkbagpAcrxQHLqovI1YWqEcXyRnA==", "dev": true, "requires": { "debug": "^4.1.1", @@ -846,18 +821,28 @@ "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=" }, + "anymatch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", + "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, "app-root-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/app-root-path/-/app-root-path-3.0.0.tgz", "integrity": "sha512-qMcx+Gy2UZynHjOHOIXPNvpf+9cjvk3cWrBBK7zg4gH9+clobJRb9NGzcT7mQTcV/6Gm/1WelUtqxVXnNlrwcw==" }, "append-transform": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-1.0.0.tgz", - "integrity": "sha512-P009oYkeHyU742iSZJzZZywj4QRJdnTWffaKuJQLablCZ1uz6/cW4yaRgcDaoQ+uwOxxnt0gRUcwfsNP2ri0gw==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-2.0.0.tgz", + "integrity": "sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg==", "dev": true, "requires": { - "default-require-extensions": "^2.0.0" + "default-require-extensions": "^3.0.0" } }, "aproba": { @@ -1134,6 +1119,12 @@ "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-7.2.1.tgz", "integrity": "sha512-S4XzBk5sMB+Rcb/LNcpzXr57VRTxgAvaAEDAl1AwRx27j00hT84O6OkteE7u8UB3NuaaygCRrEpqox4uDOrbdQ==" }, + "binary-extensions": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.0.0.tgz", + "integrity": "sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==", + "dev": true + }, "bl": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/bl/-/bl-3.0.0.tgz", @@ -1204,15 +1195,15 @@ "integrity": "sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==" }, "caching-transform": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-3.0.2.tgz", - "integrity": "sha512-Mtgcv3lh3U0zRii/6qVgQODdPA4G3zhG+jtbCWj39RXuUFTMzH0vcdMtaJS1jPowd+It2Pqr6y3NJMQqOqCE2w==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-4.0.0.tgz", + "integrity": "sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA==", "dev": true, "requires": { - "hasha": "^3.0.0", - "make-dir": "^2.0.0", - "package-hash": "^3.0.0", - "write-file-atomic": "^2.4.2" + "hasha": "^5.0.0", + "make-dir": "^3.0.0", + "package-hash": "^4.0.0", + "write-file-atomic": "^3.0.0" } }, "caller-callsite": { @@ -1248,11 +1239,11 @@ "dev": true }, "camel-case": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.0.tgz", - "integrity": "sha512-vmHTVppun53Le+K8wHxA0f4oI192u2i6eL9qHrqByibpxRbdkvI1o1fAA6ozxpLGEnsDS3MBjPJAi7ArJU9ZDg==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.1.tgz", + "integrity": "sha512-7fa2WcG4fYFkclIvEmxBbTvmibwF2/agfEBc6q3lOpVu0A13ltLsA+Hr/8Hp6kp5f+G7hKi6t8lys6XxP+1K6Q==", "requires": { - "pascal-case": "^3.1.0", + "pascal-case": "^3.1.1", "tslib": "^1.10.0" }, "dependencies": { @@ -1269,11 +1260,11 @@ "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" }, "capital-case": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/capital-case/-/capital-case-1.0.2.tgz", - "integrity": "sha512-7dF2q6pv+qqMkFG+AS0c6/UnYAL5ldR2rUbjKoJrHz9S0bn14jOLIpXxwabIeyakcRWNeGguWzNxJRPAGe4lFA==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/capital-case/-/capital-case-1.0.3.tgz", + "integrity": "sha512-OlUSJpUr7SY0uZFOxcwnDOU7/MpHlKTZx2mqnDYQFrDudXLFm0JJ9wr/l4csB+rh2Ug0OPuoSO53PqiZBqno9A==", "requires": { - "no-case": "^3.0.2", + "no-case": "^3.0.3", "tslib": "^1.10.0", "upper-case-first": "^2.0.1" }, @@ -1330,21 +1321,21 @@ } }, "change-case": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/change-case/-/change-case-4.1.0.tgz", - "integrity": "sha512-jz4NjT8d6J9ggFuGHJ860Trta1IXjtnG+T3HGKdN/9ihDefiN241SQhJlD/fbNdiH4YUwPAp00X030vqc/LRcw==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/change-case/-/change-case-4.1.1.tgz", + "integrity": "sha512-qRlUWn/hXnX1R1LBDF/RelJLiqNjKjUqlmuBVSEIyye8kq49CXqkZWKmi8XeUAdDXWFOcGLUMZ+aHn3Q5lzUXw==", "requires": { - "camel-case": "^4.1.0", - "capital-case": "^1.0.2", - "constant-case": "^3.0.2", - "dot-case": "^3.0.2", - "header-case": "^2.0.2", - "no-case": "^3.0.2", - "param-case": "^3.0.2", - "pascal-case": "^3.1.0", - "path-case": "^3.0.2", - "sentence-case": "^3.0.2", - "snake-case": "^3.0.2", + "camel-case": "^4.1.1", + "capital-case": "^1.0.3", + "constant-case": "^3.0.3", + "dot-case": "^3.0.3", + "header-case": "^2.0.3", + "no-case": "^3.0.3", + "param-case": "^3.0.3", + "pascal-case": "^3.1.1", + "path-case": "^3.0.3", + "sentence-case": "^3.0.3", + "snake-case": "^3.0.3", "tslib": "^1.10.0" }, "dependencies": { @@ -1366,6 +1357,22 @@ "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", "dev": true }, + "chokidar": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.0.tgz", + "integrity": "sha512-dGmKLDdT3Gdl7fBUe8XK+gAtGmzy5Fn0XkkWQuYxGIgWVPPse2CxFA5mtrlD0TOHaHjEUqkWNyP1XdHoJES/4A==", + "dev": true, + "requires": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "fsevents": "~2.1.1", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.2.0" + } + }, "chownr": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.3.tgz", @@ -1405,15 +1412,10 @@ "yargs": "^15.0.0" }, "dependencies": { - "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==" - }, "ansi-styles": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.0.tgz", - "integrity": "sha512-7kFQgnEaMdRtwf6uSfUnVr9gSGC7faurn+J/Mv90/W+iTtN0405/nLdopfMWwchyxhbGYl6TC4Sccn9TUkGAgg==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", "requires": { "@types/color-name": "^1.1.1", "color-convert": "^2.0.1" @@ -1428,16 +1430,6 @@ "supports-color": "^7.1.0" } }, - "cliui": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" - } - }, "color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -1451,69 +1443,11 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" - }, - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "requires": { - "p-locate": "^4.1.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "requires": { - "p-limit": "^2.2.0" - } - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" - }, - "string-width": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", - "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - } - }, - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "requires": { - "ansi-regex": "^5.0.0" - } - }, "supports-color": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", @@ -1521,43 +1455,6 @@ "requires": { "has-flag": "^4.0.0" } - }, - "wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } - }, - "yargs": { - "version": "15.0.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.0.2.tgz", - "integrity": "sha512-GH/X/hYt+x5hOat4LMnCqMd8r5Cv78heOMIJn1hr7QPPBqfeC6p89Y78+WB9yGDvfpCvgasfmWLzNzEioOUD9Q==", - "requires": { - "cliui": "^6.0.0", - "decamelize": "^1.2.0", - "find-up": "^4.1.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^4.2.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^16.1.0" - } - }, - "yargs-parser": { - "version": "16.1.0", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-16.1.0.tgz", - "integrity": "sha512-H/V41UNZQPkUMIT5h5hiwg4QKIY1RPvoBV4XcjUbRM8Bk2oKqqyZ0DIEbTFZB0XjbtSPG8SAa/0DxCQmiRgzKg==", - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } } } }, @@ -1718,11 +1615,11 @@ "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" }, "constant-case": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/constant-case/-/constant-case-3.0.2.tgz", - "integrity": "sha512-VxthHv7/VKSXl9kToCoulqM5hH6KpLdAdBCRMFj1SzaHTHMZkQYbRlMwEiLHYJfMN7xE8UiUtyBAJjPXOtbjjA==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/constant-case/-/constant-case-3.0.3.tgz", + "integrity": "sha512-FXtsSnnrFYpzDmvwDGQW+l8XK3GV1coLyBN0eBz16ZUzGaZcT2ANVCJmLeuw2GQgxKHQIe9e0w2dzkSfaRlUmA==", "requires": { - "no-case": "^3.0.2", + "no-case": "^3.0.3", "tslib": "^1.10.0", "upper-case": "^2.0.1" }, @@ -1741,9 +1638,9 @@ "dev": true }, "convert-source-map": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz", - "integrity": "sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", + "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", "dev": true, "requires": { "safe-buffer": "~5.1.1" @@ -1784,27 +1681,6 @@ } } }, - "cp-file": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/cp-file/-/cp-file-6.2.0.tgz", - "integrity": "sha512-fmvV4caBnofhPe8kOcitBwSn2f39QLjnAnGq3gO9dfd75mUytzKNZB1hde6QHunW2Rt+OwuBOMc3i1tNElbszA==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "make-dir": "^2.0.0", - "nested-error-stacks": "^2.0.0", - "pify": "^4.0.1", - "safe-buffer": "^5.0.1" - }, - "dependencies": { - "pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "dev": true - } - } - }, "cross-spawn": { "version": "6.0.5", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", @@ -1885,12 +1761,20 @@ "dev": true }, "default-require-extensions": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-2.0.0.tgz", - "integrity": "sha1-9fj7sYp9bVCyH2QfZJ67Uiz+JPc=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-3.0.0.tgz", + "integrity": "sha512-ek6DpXq/SCpvjhpFsLFRVtIxJCRw6fUR42lYMVZuUMK7n8eMz4Uh5clckdBjEpLhn/gEBZo7hDJnJcwdKLKQjg==", "dev": true, "requires": { - "strip-bom": "^3.0.0" + "strip-bom": "^4.0.0" + }, + "dependencies": { + "strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true + } } }, "define-properties": { @@ -1978,11 +1862,11 @@ } }, "dot-case": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.2.tgz", - "integrity": "sha512-z3vMZEW2o3btKlM9I6FQF0pIWTzBuW+udrAaJr+A6JA3+p62ADZjeFthKxqxKHZlUxQmkKeEWvaKLJdwpc5u6g==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.3.tgz", + "integrity": "sha512-7hwEmg6RiSQfm/GwPL4AAWXKy3YNNZA3oFv2Pdiey0mwkRCPZ9x6SZbkLcn8Ma5PYeVokzoD4Twv2n7LKp5WeA==", "requires": { - "no-case": "^3.0.2", + "no-case": "^3.0.3", "tslib": "^1.10.0" }, "dependencies": { @@ -2097,9 +1981,9 @@ "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" }, "eslint": { - "version": "6.7.2", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.7.2.tgz", - "integrity": "sha512-qMlSWJaCSxDFr8fBPvJM9kJwbazrhNcBU3+DszDW1OlEwKBBRWsJc7NJFelvwQpanHCR14cOLD41x8Eqvo3Nng==", + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.8.0.tgz", + "integrity": "sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", @@ -2159,6 +2043,12 @@ "type-fest": "^0.8.1" } }, + "regexpp": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", + "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", + "dev": true + }, "semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", @@ -2185,9 +2075,9 @@ } }, "eslint-config-prettier": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-6.7.0.tgz", - "integrity": "sha512-FamQVKM3jjUVwhG4hEMnbtsq7xOIDm+SY5iBPfR8gKsJoAB2IQnNF+bk1+8Fy44Nq7PPJaLvkRxILYdJWoguKQ==", + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-6.9.0.tgz", + "integrity": "sha512-k4E14HBtcLv0uqThaI6I/n1LEqROp8XaPu6SO9Z32u5NlGRC07Enu1Bh2KEFw4FNHbekH8yzbIU9kUGxbiGmCA==", "dev": true, "requires": { "get-stdin": "^6.0.0" @@ -2525,23 +2415,57 @@ } }, "find-cache-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", - "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.2.0.tgz", + "integrity": "sha512-1JKclkYYsf1q9WIJKLZa9S9muC+08RIjzAlLrK4QcYLJMS6mk9yombQ9qf+zJ7H9LS800k0s44L4sDq9VYzqyg==", "dev": true, "requires": { "commondir": "^1.0.1", - "make-dir": "^2.0.0", - "pkg-dir": "^3.0.0" + "make-dir": "^3.0.0", + "pkg-dir": "^4.1.0" }, "dependencies": { - "pkg-dir": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", - "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, "requires": { - "find-up": "^3.0.0" + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "requires": { + "find-up": "^4.0.0" } } } @@ -2615,23 +2539,54 @@ } }, "foreground-child": { - "version": "1.5.6", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-1.5.6.tgz", - "integrity": "sha1-T9ca0t/elnibmApcCilZN8svXOk=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", + "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==", "dev": true, "requires": { - "cross-spawn": "^4", - "signal-exit": "^3.0.0" + "cross-spawn": "^7.0.0", + "signal-exit": "^3.0.2" }, "dependencies": { "cross-spawn": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-4.0.2.tgz", - "integrity": "sha1-e5JHYhwjrf3ThWAEqCPL45dCTUE=", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.1.tgz", + "integrity": "sha512-u7v4o84SwFpD32Z8IIcPZ6z1/ie24O6RU3RbtL5Y316l3KuHVPx9ItBgWQ6VlfAFnRnTtMUrsQ9MUUTuEZjogg==", "dev": true, "requires": { - "lru-cache": "^4.0.1", - "which": "^1.2.9" + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" } } } @@ -2651,6 +2606,12 @@ "mime-types": "^2.1.12" } }, + "fromentries": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fromentries/-/fromentries-1.2.0.tgz", + "integrity": "sha512-33X7H/wdfO99GdRLLgkjUrD4geAFdq/Uv0kl3HD4da6HDixd2GUg8Mw7dahLCV9r/EARkmtYBB6Tch4EEokFTQ==", + "dev": true + }, "fs-extra": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", @@ -2681,6 +2642,13 @@ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, + "fsevents": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.2.tgz", + "integrity": "sha512-R4wDiBwZ0KzpgOWetKDug1FZcYhqYnUYKtfZYt4mD5SBz76q0KR4Q9o7GIPamsVPGmW3EYPPJ0dOOjvx32ldZA==", + "dev": true, + "optional": true + }, "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", @@ -2907,12 +2875,27 @@ "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" }, "hasha": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/hasha/-/hasha-3.0.0.tgz", - "integrity": "sha1-UqMvq4Vp1BymmmH/GiFPjrfIvTk=", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/hasha/-/hasha-5.1.0.tgz", + "integrity": "sha512-OFPDWmzPN1l7atOV1TgBVmNtBxaIysToK6Ve9DK+vT6pYuklw/nPNT+HJbZi0KDcI6vWB+9tgvZ5YD7fA3CXcA==", "dev": true, "requires": { - "is-stream": "^1.0.1" + "is-stream": "^2.0.0", + "type-fest": "^0.8.0" + }, + "dependencies": { + "is-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", + "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", + "dev": true + }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true + } } }, "he": { @@ -2922,11 +2905,11 @@ "dev": true }, "header-case": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/header-case/-/header-case-2.0.2.tgz", - "integrity": "sha512-DkrKDkNEXG3ZC3urlbt+O9j9qbwFvJwDB1PSKBQqZLVbh2wr7PKpfjGWo/Dw9cpG1IqZM6QTsnVsB3FwdCuEkg==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/header-case/-/header-case-2.0.3.tgz", + "integrity": "sha512-LChe/V32mnUQnTwTxd3aAlNMk8ia9tjCDb/LjYtoMrdAPApxLB+azejUk5ERZIZdIqvinwv6BAUuFXH/tQPdZA==", "requires": { - "capital-case": "^1.0.2", + "capital-case": "^1.0.3", "tslib": "^1.10.0" }, "dependencies": { @@ -2951,6 +2934,12 @@ "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==", "dev": true }, + "html-escaper": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.0.tgz", + "integrity": "sha512-a4u9BeERWGu/S8JiWEAQcdrg9v4QArtP9keViQjGMdff20fBdd8waotXaNmODqBe6uZ3Nafi7K/ho4gCQHV3Ig==", + "dev": true + }, "http-signature": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", @@ -3134,9 +3123,9 @@ "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" }, "inquirer": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.0.1.tgz", - "integrity": "sha512-V1FFQ3TIO15det8PijPLFR9M9baSlnRs9nL7zWu1MNVA2T9YVl9ZbrHJhYs7e9X8jeMZ3lr2JH/rdHFgNCBdYw==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.0.2.tgz", + "integrity": "sha512-cZGvHaHwcR9E3xK9EGO5pHKELU+yaeJO7l2qGKIbqk4bCuDuAn15LCoUTS2nSkfv9JybFlnAGrOcVpCDZZOLhw==", "requires": { "ansi-escapes": "^4.2.1", "chalk": "^2.4.2", @@ -3197,19 +3186,6 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" }, - "mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==" - }, - "onetime": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.0.tgz", - "integrity": "sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==", - "requires": { - "mimic-fn": "^2.1.0" - } - }, "restore-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", @@ -3220,9 +3196,9 @@ } }, "rxjs": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.3.tgz", - "integrity": "sha512-wuYsAYYFdWTAnAaPoKGNhfpWwKZbJW+HgAJ+mImp+Epl7BG8oNWBCTyRM8gba9k4lk8BgWdoYm21Mo/RYhhbgA==", + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.4.tgz", + "integrity": "sha512-naMQXcgEo3csAEGvw/NydRA0fuS2nDZJiw1YUWFKU7aPPAPGZEsD4Iimit96qwCieH6y614MCLYwdkrWx7z/7Q==", "requires": { "tslib": "^1.9.0" } @@ -3260,6 +3236,15 @@ "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", "dev": true }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, "is-buffer": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz", @@ -3372,6 +3357,12 @@ "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true + }, "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", @@ -3389,75 +3380,143 @@ "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" }, "istanbul-lib-coverage": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz", - "integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz", + "integrity": "sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg==", "dev": true }, "istanbul-lib-hook": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-2.0.7.tgz", - "integrity": "sha512-vrRztU9VRRFDyC+aklfLoeXyNdTfga2EI3udDGn4cZ6fpSXpHLV9X6CHvfoMCPtggg8zvDDmC4b9xfu0z6/llA==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-3.0.0.tgz", + "integrity": "sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ==", "dev": true, "requires": { - "append-transform": "^1.0.0" + "append-transform": "^2.0.0" } }, "istanbul-lib-instrument": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-3.3.0.tgz", - "integrity": "sha512-5nnIN4vo5xQZHdXno/YDXJ0G+I3dAm4XgzfSVTPLQpj/zAV2dV6Juy0yaf10/zrJOJeHoN3fraFe+XRq2bFVZA==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.0.tgz", + "integrity": "sha512-Nm4wVHdo7ZXSG30KjZ2Wl5SU/Bw7bDx1PdaiIFzEStdjs0H12mOTncn1GVYuqQSaZxpg87VGBRsVRPGD2cD1AQ==", "dev": true, "requires": { - "@babel/generator": "^7.4.0", - "@babel/parser": "^7.4.3", - "@babel/template": "^7.4.0", - "@babel/traverse": "^7.4.3", - "@babel/types": "^7.4.0", - "istanbul-lib-coverage": "^2.0.5", - "semver": "^6.0.0" + "@babel/core": "^7.7.5", + "@babel/parser": "^7.7.5", + "@babel/template": "^7.7.4", + "@babel/traverse": "^7.7.4", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.0.0", + "semver": "^6.3.0" }, "dependencies": { "semver": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.1.1.tgz", - "integrity": "sha512-rWYq2e5iYW+fFe/oPPtYJxYgjBm8sC4rmoGdUOgBB7VnwKt6HrL793l2voH1UlsyYZpJ4g0wfjnTEO1s1NP2eQ==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true } } }, - "istanbul-lib-report": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-2.0.8.tgz", - "integrity": "sha512-fHBeG573EIihhAblwgxrSenp0Dby6tJMFR/HvlerBsrCTD5bkUuoNtn3gVh29ZCS824cGGBPn7Sg7cNk+2xUsQ==", + "istanbul-lib-processinfo": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-processinfo/-/istanbul-lib-processinfo-2.0.2.tgz", + "integrity": "sha512-kOwpa7z9hme+IBPZMzQ5vdQj8srYgAtaRqeI48NGmAQ+/5yKiHLV0QbYqQpxsdEF0+w14SoB8YbnHKcXE2KnYw==", "dev": true, "requires": { - "istanbul-lib-coverage": "^2.0.5", - "make-dir": "^2.1.0", - "supports-color": "^6.1.0" + "archy": "^1.0.0", + "cross-spawn": "^7.0.0", + "istanbul-lib-coverage": "^3.0.0-alpha.1", + "make-dir": "^3.0.0", + "p-map": "^3.0.0", + "rimraf": "^3.0.0", + "uuid": "^3.3.3" }, "dependencies": { - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "cross-spawn": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.1.tgz", + "integrity": "sha512-u7v4o84SwFpD32Z8IIcPZ6z1/ie24O6RU3RbtL5Y316l3KuHVPx9ItBgWQ6VlfAFnRnTtMUrsQ9MUUTuEZjogg==", "dev": true, "requires": { - "has-flag": "^3.0.0" + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "uuid": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz", + "integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==", + "dev": true + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", + "dev": true, + "requires": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" } } } }, "istanbul-lib-source-maps": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.6.tgz", - "integrity": "sha512-R47KzMtDJH6X4/YW9XTx+jrLnZnscW4VpNN+1PViSYTejLVPWv7oov+Duf8YQSPyVRUvueQqz1TcsC6mooZTXw==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.0.tgz", + "integrity": "sha512-c16LpFRkR8vQXyHZ5nLpY35JZtzj1PQY1iZmesUbf1FZHbIupcWfjgOXBY9YHkLEQ6puz1u4Dgj6qmU/DisrZg==", "dev": true, "requires": { "debug": "^4.1.1", - "istanbul-lib-coverage": "^2.0.5", - "make-dir": "^2.1.0", - "rimraf": "^2.6.3", + "istanbul-lib-coverage": "^3.0.0", "source-map": "^0.6.1" }, "dependencies": { @@ -3469,25 +3528,17 @@ "requires": { "ms": "^2.1.1" } - }, - "rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } } } }, "istanbul-reports": { - "version": "2.2.6", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-2.2.6.tgz", - "integrity": "sha512-SKi4rnMyLBKe0Jy2uUdx28h8oG7ph2PPuQPvIAh31d+Ci+lSiEu4C+h3oBPuJ9+mPKhOyW0M8gY4U5NM1WLeXA==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.0.tgz", + "integrity": "sha512-2osTcC8zcOSUkImzN2EWQta3Vdi4WjjKw99P2yWx5mLnigAM0Rd5uYFn1cf2i/Ois45GkNjaoTqc5CxgMSX80A==", "dev": true, "requires": { - "handlebars": "^4.1.2" + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" } }, "js-tokens": { @@ -3548,6 +3599,23 @@ "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" }, + "json5": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.1.tgz", + "integrity": "sha512-l+3HXD0GEI3huGq1njuqtzYK8OYJyXMkOLtQ53pjWh89tvWS2h6l+1zMkYWqlb57+SiQodKZyvMEFb2X+KrFhQ==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } + }, "jsonfile": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", @@ -3856,18 +3924,6 @@ } } }, - "load-json-file": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", - "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^4.0.0", - "pify": "^3.0.0", - "strip-bom": "^3.0.0" - } - }, "locate-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", @@ -3936,44 +3992,19 @@ } } }, - "lru-cache": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", - "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", - "dev": true, - "requires": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - }, - "dependencies": { - "yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", - "dev": true - } - } - }, "make-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", - "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.0.0.tgz", + "integrity": "sha512-grNJDhb8b1Jm1qeqW5R/O63wUo4UXo2v2HMic6YT9i/HBlF93S8jkMgH7yugvY9ABDShH4VZMn8I+U8+fCNegw==", "dev": true, "requires": { - "pify": "^4.0.1", - "semver": "^5.6.0" + "semver": "^6.0.0" }, "dependencies": { - "pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "dev": true - }, "semver": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", - "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true } } @@ -3984,15 +4015,6 @@ "integrity": "sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g==", "dev": true }, - "merge-source-map": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/merge-source-map/-/merge-source-map-1.1.0.tgz", - "integrity": "sha512-Qkcp7P2ygktpMPh2mCQZaf3jhN6D3Z/qVZHSdWvQ+2Ef5HgRAPBO57A77+ENm0CPx2+1Ce/MYKi3ymqdfuqibw==", - "dev": true, - "requires": { - "source-map": "^0.6.1" - } - }, "merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", @@ -4031,8 +4053,7 @@ "mimic-fn": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==" }, "minimatch": { "version": "3.0.4", @@ -4087,13 +4108,14 @@ } }, "mocha": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-6.2.2.tgz", - "integrity": "sha512-FgDS9Re79yU1xz5d+C4rv1G7QagNGHZ+iXF81hO8zY35YZZcLEsJVfFolfsqKFWunATEvNzMK0r/CwWd/szO9A==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-7.0.0.tgz", + "integrity": "sha512-CirsOPbO3jU86YKjjMzFLcXIb5YiGLUrjrXFHoJ3e2z9vWiaZVCZQ2+gtRGMPWF+nFhN6AWwLM/juzAQ6KRkbA==", "dev": true, "requires": { "ansi-colors": "3.2.3", "browser-stdout": "1.3.1", + "chokidar": "3.3.0", "debug": "3.2.6", "diff": "3.5.0", "escape-string-regexp": "1.0.5", @@ -4106,7 +4128,7 @@ "minimatch": "3.0.4", "mkdirp": "0.5.1", "ms": "2.1.1", - "node-environment-flags": "1.0.5", + "node-environment-flags": "1.0.6", "object.assign": "4.1.0", "strip-json-comments": "2.0.1", "supports-color": "6.0.0", @@ -4205,12 +4227,6 @@ } } }, - "moment": { - "version": "2.24.0", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz", - "integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==", - "dev": true - }, "ms": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", @@ -4306,12 +4322,6 @@ "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz", "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==" }, - "nested-error-stacks": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/nested-error-stacks/-/nested-error-stacks-2.1.0.tgz", - "integrity": "sha512-AO81vsIO1k1sM4Zrd6Hu7regmJN1NSiAja10gc4bX3F0wd+9rQmcuHQaHVQCYIEC8iFXnE+mavh23GOt7wBgug==", - "dev": true - }, "nice-try": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", @@ -4319,22 +4329,33 @@ "dev": true }, "nise": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/nise/-/nise-1.5.2.tgz", - "integrity": "sha512-/6RhOUlicRCbE9s+94qCUsyE+pKlVJ5AhIv+jEE7ESKwnbXqulKZ1FYU+XAtHHWE9TinYvAxDUJAb912PwPoWA==", + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/nise/-/nise-1.5.3.tgz", + "integrity": "sha512-Ymbac/94xeIrMf59REBPOv0thr+CJVFMhrlAkW/gjCIE58BGQdCj0x7KRCb3yz+Ga2Rz3E9XXSvUyyxqqhjQAQ==", "dev": true, "requires": { "@sinonjs/formatio": "^3.2.1", "@sinonjs/text-encoding": "^0.7.1", "just-extend": "^4.0.2", - "lolex": "^4.1.0", + "lolex": "^5.0.1", "path-to-regexp": "^1.7.0" + }, + "dependencies": { + "lolex": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/lolex/-/lolex-5.1.2.tgz", + "integrity": "sha512-h4hmjAvHTmd+25JSwrtTIuwbKdwg5NzZVRMLn9saij4SZaepCrTCxPr35H/3bjwfMJtN+t3CX8672UIkglz28A==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.7.0" + } + } } }, "no-case": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.2.tgz", - "integrity": "sha512-Yber3mEOA3T9+as7Z70TJUQCUPRmmq6s8NmsZX5aSB1qk+Mt+3a5JVPpnAnONUShLTkMDF4PJY3h0GKlXdRTNA==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.3.tgz", + "integrity": "sha512-ehY/mVQCf9BL0gKfsJBvFJen+1V//U+0HQMPrWct40ixE4jnv0bfvxDbWtAHL9EcaPEOJHVVYKoQn1TlZUB8Tw==", "requires": { "lower-case": "^2.0.1", "tslib": "^1.10.0" @@ -4348,9 +4369,9 @@ } }, "node-environment-flags": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.5.tgz", - "integrity": "sha512-VNYPRfGfmZLx0Ye20jWzHUjyTW/c+6Wq+iLhDzUI4XmhrDd9l/FozXV3F2xOaXjvp0co0+v1YSR3CMP6g+VvLQ==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.6.tgz", + "integrity": "sha512-5Evy2epuL+6TM0lCQGpFIj6KwiEsGh1SrHUhTbNX+sLbBtjidPZFAnVK9y5yU1+h//RitLbRHTIMyxQPtxMdHw==", "dev": true, "requires": { "object.getownpropertydescriptors": "^2.0.3", @@ -4403,6 +4424,15 @@ } } }, + "node-preload": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz", + "integrity": "sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ==", + "dev": true, + "requires": { + "process-on-spawn": "^1.0.0" + } + }, "nopt": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz", @@ -4489,93 +4519,100 @@ "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" }, "nyc": { - "version": "14.1.1", - "resolved": "https://registry.npmjs.org/nyc/-/nyc-14.1.1.tgz", - "integrity": "sha512-OI0vm6ZGUnoGZv/tLdZ2esSVzDwUC88SNs+6JoSOMVxA+gKMB8Tk7jBwgemLx4O40lhhvZCVw1C+OYLOBOPXWw==", + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/nyc/-/nyc-15.0.0.tgz", + "integrity": "sha512-qcLBlNCKMDVuKb7d1fpxjPR8sHeMVX0CHarXAVzrVWoFrigCkYR8xcrjfXSPi5HXM7EU78L6ywO7w1c5rZNCNg==", "dev": true, "requires": { - "archy": "^1.0.0", - "caching-transform": "^3.0.2", - "convert-source-map": "^1.6.0", - "cp-file": "^6.2.0", - "find-cache-dir": "^2.1.0", - "find-up": "^3.0.0", - "foreground-child": "^1.5.6", - "glob": "^7.1.3", - "istanbul-lib-coverage": "^2.0.5", - "istanbul-lib-hook": "^2.0.7", - "istanbul-lib-instrument": "^3.3.0", - "istanbul-lib-report": "^2.0.8", - "istanbul-lib-source-maps": "^3.0.6", - "istanbul-reports": "^2.2.4", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "caching-transform": "^4.0.0", + "convert-source-map": "^1.7.0", + "decamelize": "^1.2.0", + "find-cache-dir": "^3.2.0", + "find-up": "^4.1.0", + "foreground-child": "^2.0.0", + "glob": "^7.1.6", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-hook": "^3.0.0", + "istanbul-lib-instrument": "^4.0.0", + "istanbul-lib-processinfo": "^2.0.2", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.0.0", "js-yaml": "^3.13.1", - "make-dir": "^2.1.0", - "merge-source-map": "^1.1.0", - "resolve-from": "^4.0.0", - "rimraf": "^2.6.3", + "make-dir": "^3.0.0", + "node-preload": "^0.2.0", + "p-map": "^3.0.0", + "process-on-spawn": "^1.0.0", + "resolve-from": "^5.0.0", + "rimraf": "^3.0.0", "signal-exit": "^3.0.2", - "spawn-wrap": "^1.4.2", - "test-exclude": "^5.2.3", - "uuid": "^3.3.2", - "yargs": "^13.2.2", - "yargs-parser": "^13.0.0" + "spawn-wrap": "^2.0.0", + "test-exclude": "^6.0.0", + "uuid": "^3.3.3", + "yargs": "^15.0.2" }, "dependencies": { - "resolve-from": { + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "path-exists": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true }, - "rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, - "yargs": { - "version": "13.3.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.0.tgz", - "integrity": "sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA==", - "dev": true, - "requires": { - "cliui": "^5.0.0", - "find-up": "^3.0.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^3.0.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^13.1.1" - }, - "dependencies": { - "yargs-parser": { - "version": "13.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz", - "integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==", - "dev": true, - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } - } - } + "uuid": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz", + "integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==", + "dev": true } } }, @@ -4728,7 +4765,6 @@ "version": "5.1.0", "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.0.tgz", "integrity": "sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==", - "dev": true, "requires": { "mimic-fn": "^2.1.0" } @@ -4818,13 +4854,13 @@ "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" }, "package-hash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/package-hash/-/package-hash-3.0.0.tgz", - "integrity": "sha512-lOtmukMDVvtkL84rJHI7dpTYq+0rli8N2wlnqUcBuDWCfVhRUfOmnR9SsoHFMLpACvEV60dX7rd0rFaYDZI+FA==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/package-hash/-/package-hash-4.0.0.tgz", + "integrity": "sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ==", "dev": true, "requires": { "graceful-fs": "^4.1.15", - "hasha": "^3.0.0", + "hasha": "^5.0.0", "lodash.flattendeep": "^4.4.0", "release-zalgo": "^1.0.0" } @@ -4835,11 +4871,11 @@ "integrity": "sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==" }, "param-case": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.2.tgz", - "integrity": "sha512-9UF3HbbJwzBVJlFFOvfBpWUpGFMX01q3dKavdRyv+71HI3GO4UTQIiuG51pckuqPlHzx1jmUijim8J282goaLg==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.3.tgz", + "integrity": "sha512-VWBVyimc1+QrzappRs7waeN2YmoZFCGXWASRYX1/rGHtXqEcrGEIDm+jqIwFa2fRXNgQEwrxaYuIrX0WcAguTA==", "requires": { - "dot-case": "^3.0.2", + "dot-case": "^3.0.3", "tslib": "^1.10.0" }, "dependencies": { @@ -4888,11 +4924,11 @@ } }, "pascal-case": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.0.tgz", - "integrity": "sha512-7cINxTsRAFym4dLVMdObWx2wr/FjVz8BfCdLPC069kAFLal/5dZhxObpAIM40GwZ/Xik1J37z+Nw6/TVy5fmIg==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.1.tgz", + "integrity": "sha512-XIeHKqIrsquVTQL2crjq3NfJUxmdLasn3TYOU0VBM+UX2a6ztAWBlJQBePLGY7VHW8+2dRadeIPK5+KImwTxQA==", "requires": { - "no-case": "^3.0.2", + "no-case": "^3.0.3", "tslib": "^1.10.0" }, "dependencies": { @@ -4904,11 +4940,11 @@ } }, "path-case": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/path-case/-/path-case-3.0.2.tgz", - "integrity": "sha512-vTXKSmzkegC4tBZTogrHleuSEhdMgtY3+vxqN0wFM8TmVs8+0xy+oh1+07SuxYzDlXl/FO8jwEtRfAQ7G+jxCg==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/path-case/-/path-case-3.0.3.tgz", + "integrity": "sha512-UMFU6UETFpCNWbIWNczshPrnK/7JAXBP2NYw80ojElbQ2+JYxdqWDBkvvqM93u4u6oLmuJ/tPOf2tM8KtXv4eg==", "requires": { - "dot-case": "^3.0.2", + "dot-case": "^3.0.3", "tslib": "^1.10.0" }, "dependencies": { @@ -4942,9 +4978,9 @@ "dev": true }, "path-to-regexp": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.7.0.tgz", - "integrity": "sha1-Wf3g9DW62suhA6hOnTvGTpa5k30=", + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", + "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", "dev": true, "requires": { "isarray": "0.0.1" @@ -4958,15 +4994,6 @@ } } }, - "path-type": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", - "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", - "dev": true, - "requires": { - "pify": "^3.0.0" - } - }, "pathval": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz", @@ -4979,14 +5006,15 @@ "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" }, "pg": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/pg/-/pg-7.15.0.tgz", - "integrity": "sha512-eHE1n/98QB/T8J9Mc9AKTIC4yzo2Q7C2MT+IHp9TZR18nobqpsH8dmDO33dUhZ8A5Nfu6tC1TIkjrT3JoWHcOw==", + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/pg/-/pg-7.17.0.tgz", + "integrity": "sha512-70Q4ZzIdPgwMPb3zUIzAUwigNJ4v5vsWdMED6OzXMfOECeYTvTm7iSC3FpKizu/R1BHL8Do3bLs6ltGfOTAnqg==", "requires": { "buffer-writer": "2.0.0", "packet-reader": "1.0.0", "pg-connection-string": "0.1.3", - "pg-pool": "^2.0.7", + "pg-packet-stream": "^1.1.0", + "pg-pool": "^2.0.9", "pg-types": "^2.1.0", "pgpass": "1.x", "semver": "4.3.2" @@ -5002,10 +5030,15 @@ "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==" }, + "pg-packet-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pg-packet-stream/-/pg-packet-stream-1.1.0.tgz", + "integrity": "sha512-kRBH0tDIW/8lfnnOyTwKD23ygJ/kexQVXZs7gEyBljw4FYqimZFxnMMx50ndZ8In77QgfGuItS5LLclC2TtjYg==" + }, "pg-pool": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-2.0.7.tgz", - "integrity": "sha512-UiJyO5B9zZpu32GSlP0tXy8J2NsJ9EFGFfz5v6PSbdz/1hBLX1rNiiy5+mAm5iJJYwfCv4A0EBcQLGWwjbpzZw==" + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-2.0.9.tgz", + "integrity": "sha512-gNiuIEKNCT3OnudQM2kvgSnXsLkSpd6mS/fRnqs6ANtrke6j8OY5l9mnAryf1kgwJMWLg0C1N1cYTZG1xmEYHQ==" }, "pg-types": { "version": "2.2.0", @@ -5033,12 +5066,6 @@ "integrity": "sha512-OYMyqkKzK7blWO/+XZYP6w8hH0LDvkBvdvKukti+7kqYFCiEAk+gI3DWnryapc0Dau05ugGTy0foQ6mqn4AHYA==", "dev": true }, - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true - }, "pkg-dir": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", @@ -5141,18 +5168,21 @@ "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz", "integrity": "sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==" }, + "process-on-spawn": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/process-on-spawn/-/process-on-spawn-1.0.0.tgz", + "integrity": "sha512-1WsPDsUSMmZH5LeMLegqkPDrsGgsWwk1Exipy2hvB0o/F0ASzbpIctSCcZIK1ykJvtTJULEH+20WOFjMvGnCTg==", + "dev": true, + "requires": { + "fromentries": "^1.2.0" + } + }, "progress": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", "dev": true }, - "pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", - "dev": true - }, "psl": { "version": "1.1.32", "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.32.tgz", @@ -5250,29 +5280,6 @@ } } }, - "read-pkg-up": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-4.0.0.tgz", - "integrity": "sha512-6etQSH7nJGsK0RbG/2TeDzZFa8shjQ1um+SwQQ5cwKy0dhSXdOncEhb1CPpvQG4h7FyOV6EB6YlV0yJvZQNAkA==", - "dev": true, - "requires": { - "find-up": "^3.0.0", - "read-pkg": "^3.0.0" - }, - "dependencies": { - "read-pkg": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", - "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", - "dev": true, - "requires": { - "load-json-file": "^4.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^3.0.0" - } - } - } - }, "readable-stream": { "version": "2.3.6", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", @@ -5294,15 +5301,24 @@ } } }, + "readdirp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.2.0.tgz", + "integrity": "sha512-crk4Qu3pmXwgxdSgGhgA/eXiJAPQiX4GMOZZMXnqKxHX7TaoL+3gQVo/WeuAiogr07DpnfjIMpXXa+PAIvwPGQ==", + "dev": true, + "requires": { + "picomatch": "^2.0.4" + } + }, "reflect-metadata": { "version": "0.1.13", "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==" }, "regexpp": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", - "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.0.0.tgz", + "integrity": "sha512-Z+hNr7RAVWxznLPuA7DIh8UNX1j9CDrUQxskw9IrBE1Dxue2lyXT+shqEIeLUjrokxIP8CMy1WkjgG3rTsd5/g==", "dev": true }, "release-zalgo": { @@ -5471,11 +5487,11 @@ "dev": true }, "sentence-case": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/sentence-case/-/sentence-case-3.0.2.tgz", - "integrity": "sha512-15UhaONq0mYjSpFHbrO2VoPjzy/3mo8nAy8/2rr32IjsUg4hCeapON4aS84YEtOL5SOccaAaopThdSPCnndFFQ==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/sentence-case/-/sentence-case-3.0.3.tgz", + "integrity": "sha512-ZPr4dgTcNkEfcGOMFQyDdJrTU9uQO1nb1cjf+nuzb6FxgMDgKddZOM29qEsB7jvsZSMruLRcL2KfM4ypKpa0LA==", "requires": { - "no-case": "^3.0.2", + "no-case": "^3.0.3", "tslib": "^1.10.0", "upper-case-first": "^2.0.1" }, @@ -5528,9 +5544,9 @@ } }, "sinon-chai": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/sinon-chai/-/sinon-chai-3.3.0.tgz", - "integrity": "sha512-r2JhDY7gbbmh5z3Q62pNbrjxZdOAjpsqW/8yxAZRSqLZqowmfGZPGUZPFf3UX36NLis0cv8VEM5IJh9HgkSOAA==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/sinon-chai/-/sinon-chai-3.4.0.tgz", + "integrity": "sha512-BpVxsjEkGi6XPbDXrgWUe7Cb1ZzIfxKUbu/MmH5RoUnS7AXpKo3aIYIyQUg0FMvlUL05aPt7VZuAdaeQhEnWxg==", "dev": true }, "slash": { @@ -5551,11 +5567,11 @@ } }, "snake-case": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.2.tgz", - "integrity": "sha512-1fRJdasXJTcsrGnUkDsnKNjHoP9NGclbIkYyY6Vv0vBVgz32rqhPFPg/Y0yIP4hwOd41Dh8rocCRHjNIuK4EZg==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.3.tgz", + "integrity": "sha512-WM1sIXEO+rsAHBKjGf/6R1HBBcgbncKS08d2Aqec/mrDSpU80SiOU41hO7ny6DToHSyrlwTYzQBIK1FPSx4Y3Q==", "requires": { - "dot-case": "^3.0.2", + "dot-case": "^3.0.3", "tslib": "^1.10.0" }, "dependencies": { @@ -5582,26 +5598,26 @@ } }, "spawn-wrap": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-1.4.2.tgz", - "integrity": "sha512-vMwR3OmmDhnxCVxM8M+xO/FtIp6Ju/mNaDfCMMW7FDcLRTPFWUswec4LXJHTJE2hwTI9O0YBfygu4DalFl7Ylg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-2.0.0.tgz", + "integrity": "sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg==", "dev": true, "requires": { - "foreground-child": "^1.5.6", - "mkdirp": "^0.5.0", - "os-homedir": "^1.0.1", - "rimraf": "^2.6.2", + "foreground-child": "^2.0.0", + "is-windows": "^1.0.2", + "make-dir": "^3.0.0", + "rimraf": "^3.0.0", "signal-exit": "^3.0.2", - "which": "^1.3.0" + "which": "^2.0.1" }, "dependencies": { - "rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, "requires": { - "glob": "^7.1.3" + "isexe": "^2.0.0" } } } @@ -5878,6 +5894,11 @@ "sprintf-js": "^1.1.2" }, "dependencies": { + "@types/node": { + "version": "12.12.24", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.24.tgz", + "integrity": "sha512-1Ciqv9pqwVtW6FsIUKSZNB82E5Cu1I2bBTj1xuIHXLe/1zYLl3956Nbhg2MzSYHVfl9/rmanjbQIb7LibfCnug==" + }, "iconv-lite": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.5.0.tgz", @@ -5915,15 +5936,14 @@ } }, "test-exclude": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-5.2.3.tgz", - "integrity": "sha512-M+oxtseCFO3EDtAaGH7iiej3CBkzXqFMbzqYAACdzKui4eZA+pq3tZEwChvOdNfa7xxy8BfbmgJSIr43cC/+2g==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", "dev": true, "requires": { - "glob": "^7.1.3", - "minimatch": "^3.0.4", - "read-pkg-up": "^4.0.0", - "require-main-filename": "^2.0.0" + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" } }, "text-table": { @@ -5992,12 +6012,6 @@ } } }, - "trim-right": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", - "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=", - "dev": true - }, "ts-node": { "version": "8.5.4", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.5.4.tgz", @@ -6078,10 +6092,19 @@ "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", "dev": true }, + "typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dev": true, + "requires": { + "is-typedarray": "^1.0.0" + } + }, "typeorm": { - "version": "0.2.21", - "resolved": "https://registry.npmjs.org/typeorm/-/typeorm-0.2.21.tgz", - "integrity": "sha512-4abj5aFjwt4Y+Gs3VmykcjURUZwIezwPWYVMNl2swRk8/iluGZZ9Lbwd4tdzJ7ZdsgKyHsT8zf8zPZPL5jH+EQ==", + "version": "0.2.22", + "resolved": "https://registry.npmjs.org/typeorm/-/typeorm-0.2.22.tgz", + "integrity": "sha512-mDEnMtzRwX4zMYbyzM9xDn7jvGs8hfQ2ymOBq36Zxq1RVM642numwlRbr4W8dU7ZYx8CQUE9rmk+sU0baHD9Rw==", "requires": { "app-root-path": "^3.0.0", "buffer": "^5.1.0", @@ -6151,9 +6174,9 @@ } }, "typescript": { - "version": "3.7.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.7.3.tgz", - "integrity": "sha512-Mcr/Qk7hXqFBXMN7p7Lusj1ktCBydylfQM/FZCk5glCNQJrCUKPkMHdo9R0MTFWsC/4kPFvDS0fDPvukfCkFsw==" + "version": "3.7.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.7.4.tgz", + "integrity": "sha512-A25xv5XCtarLwXpcDNZzCGvW2D1S3/bACratYBx2sax8PefsFhlYmkQicKHvpYflFS8if4zne5zT5kpJ7pzuvw==" }, "uglify-js": { "version": "3.7.2", @@ -6333,14 +6356,15 @@ } }, "write-file-atomic": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz", - "integrity": "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.1.tgz", + "integrity": "sha512-JPStrIyyVJ6oCSz/691fAjFtefZ6q+fP6tm+OS4Qw6o+TGQxNp1ziY2PgS+X/m0V8OWhZiO/m4xSj+Pr4RrZvw==", "dev": true, "requires": { - "graceful-fs": "^4.1.11", "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.2" + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" } }, "xml2js": { @@ -6431,9 +6455,9 @@ } }, "yargs": { - "version": "15.0.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.0.2.tgz", - "integrity": "sha512-GH/X/hYt+x5hOat4LMnCqMd8r5Cv78heOMIJn1hr7QPPBqfeC6p89Y78+WB9yGDvfpCvgasfmWLzNzEioOUD9Q==", + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.1.0.tgz", + "integrity": "sha512-T39FNN1b6hCW4SOIk1XyTOWxtXdcen0t+XYrysQmChzSipvhBO8Bj0nK1ozAasdk24dNWuMZvr4k24nz+8HHLg==", "requires": { "cliui": "^6.0.0", "decamelize": "^1.2.0", @@ -6454,9 +6478,9 @@ "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==" }, "ansi-styles": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.0.tgz", - "integrity": "sha512-7kFQgnEaMdRtwf6uSfUnVr9gSGC7faurn+J/Mv90/W+iTtN0405/nLdopfMWwchyxhbGYl6TC4Sccn9TUkGAgg==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", "requires": { "@types/color-name": "^1.1.1", "color-convert": "^2.0.1" @@ -6564,16 +6588,6 @@ } } }, - "yargs-parser": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.0.0.tgz", - "integrity": "sha512-w2LXjoL8oRdRQN+hOyppuXs+V/fVAYtpcrRxZuF7Kt/Oc+Jr2uAcVntaUTNT6w5ihoWfFDpNY8CPx1QskxZ/pw==", - "dev": true, - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } - }, "yargs-unparser": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.6.0.tgz", diff --git a/package.json b/package.json index d8df90b..2f950c6 100644 --- a/package.json +++ b/package.json @@ -26,20 +26,20 @@ }, "homepage": "https://github.com/Kononnable/typeorm-model-generator#readme", "dependencies": { - "change-case": "^4.1.0", + "change-case": "^4.1.1", "fs-extra": "^8.1.0", "handlebars": "^4.5.3", - "inquirer": "^7.0.1", + "inquirer": "^7.0.2", "mssql": "^6.0.1", "mysql": "^2.17.1", - "pg": "^7.15.0", + "pg": "^7.17.0", "pluralize": "^8.0.0", "prettier": "^1.19.1", "reflect-metadata": "^0.1.13", "sqlite3": "^4.1.1", - "typeorm": "^0.2.21", - "typescript": "^3.7.3", - "yargs": "^15.0.2", + "typeorm": "^0.2.22", + "typescript": "^3.7.4", + "yargs": "^15.1.0", "yn": "^3.1.1" }, "devDependencies": { @@ -54,35 +54,35 @@ "@types/mocha": "^5.2.7", "@types/mssql": "^6.0.0", "@types/mysql": "^2.15.8", - "@types/node": "^12.12.21", + "@types/node": "^13.1.4", "@types/oracledb": "^4.1.1", - "@types/pg": "^7.11.2", + "@types/pg": "^7.14.1", "@types/pluralize": "0.0.29", "@types/prettier": "^1.19.0", "@types/sinon": "^7.5.1", - "@types/sqlite3": "^3.1.5", - "@types/yargs": "^13.0.3", - "@typescript-eslint/eslint-plugin": "^2.12.0", - "@typescript-eslint/parser": "^2.12.0", - "@typescript-eslint/typescript-estree": "^2.12.0", + "@types/sqlite3": "^3.1.6", + "@types/yargs": "^13.0.4", + "@typescript-eslint/eslint-plugin": "^2.14.0", + "@typescript-eslint/parser": "^2.14.0", + "@typescript-eslint/typescript-estree": "^2.14.0", "array.prototype.flatmap": "^1.2.3", "chai": "^4.2.0", "chai-as-promised": "^7.1.1", "chai-subset": "^1.6.0", "codecov": "^3.6.1", "dotenv": "^8.2.0", - "eslint": "^6.7.2", + "eslint": "^6.8.0", "eslint-config-airbnb-base": "^14.0.0", - "eslint-config-prettier": "^6.7.0", + "eslint-config-prettier": "^6.9.0", "eslint-plugin-import": "^2.19.1", "husky": "^3.1.0", "lint-staged": "^9.5.0", - "mocha": "^6.2.2", + "mocha": "^7.0.0", "ncp": "^2.0.0", - "nyc": "^14.1.1", + "nyc": "^15.0.0", "rimraf": "^3.0.0", "sinon": "^7.5.0", - "sinon-chai": "^3.3.0", + "sinon-chai": "^3.4.0", "ts-node": "^8.5.4" }, "husky": { From cc92628572429a699b5e9556e8809ef95f4849cb Mon Sep 17 00:00:00 2001 From: Kononnable Date: Sun, 5 Jan 2020 20:13:38 +0100 Subject: [PATCH 84/84] changelog --- CHANGELOG.md | 38 ++++++++++++++++++++++++++++++++++---- 1 file changed, 34 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 08134e0..70d553b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,40 @@ # Changelog -## Unreleased +## 0.4.0 -* change default case conversions for generated files (#196) -* enum type safety (#205) -* postgress geography type support (#232) +### BREAKING CHANGES + +* Custom NamingStrategy is now defined as separate functions instead of a class +* Rework how parameters are passed to the library: + - Utilization of partial config files + - Option to save .tomg-config file without connection options +* Generation of separate fields for primary columns which are used in relations(old approach won't be compatible with typeorm@0.3.0) +* Remove timeout parameter - query timeout is now set by default to 1 hr +* Change default case conversions for generated files (#196) + +### FIXES +* Support complex relationships (#117) +* Proper support for many to many relations +* Proper pluralization of entity names (#142) +* Skip generation of imports not used by entity definition files +* Skip generation of indices generated by PKs or relations +* Columns with unrecognized sql type are generated with unknown type +* Generation of proper type for nullable columns +* Fixed specifying custom naming strategy by relative path (#171) +* Disallow generation of relationId fields with lazy relations(not supported in typeorm) + +### ENHANCEMENTS +* Support for old oracle versions (#195) +* New options: + * Disable column name pluralization (#142) + * Ignore tables parameter (#120) + * Generation of index file (#174) + * Default exports on generated models +* Enum type safety (#205) +* Mysql set type support (#91) +* Postgres geography type support (#232) +* Make generated models compatible with common ESLint rules +* Ability to use typeorm-model-generator as library in other projects (but no guarantees about api compatibility between different version) ## 0.3.5