From 51af310b2104fe1f2dd619f63fdda9699bdd47a2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 16 Jul 2020 14:53:47 +0300 Subject: [PATCH 001/212] chore(deps): bump lodash from 4.17.15 to 4.17.19 (#6408) Bumps [lodash](https://github.com/lodash/lodash) from 4.17.15 to 4.17.19. - [Release notes](https://github.com/lodash/lodash/releases) - [Commits](https://github.com/lodash/lodash/compare/4.17.15...4.17.19) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 73 +++++++++++++++++++++++++++++------------------ 1 file changed, 46 insertions(+), 27 deletions(-) diff --git a/package-lock.json b/package-lock.json index 34e387ab334..1cda64a9197 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1860,14 +1860,6 @@ "assert-plus": "^1.0.0" } }, - "data-api-client": { - "version": "github:ArsenyYankovsky/data-api-client#043f3320f8d665c21250d615101e7b3bc8f1d298", - "from": "github:ArsenyYankovsky/data-api-client#support-postgres", - "dev": true, - "requires": { - "sqlstring": "^2.3.1" - } - }, "date-fns": { "version": "1.30.1", "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-1.30.1.tgz", @@ -2753,7 +2745,8 @@ "version": "2.1.1", "resolved": false, "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true + "dev": true, + "optional": true }, "aproba": { "version": "1.2.0", @@ -2777,13 +2770,15 @@ "version": "1.0.0", "resolved": false, "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true + "dev": true, + "optional": true }, "brace-expansion": { "version": "1.1.11", "resolved": false, "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, + "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -2793,19 +2788,22 @@ "version": "1.1.0", "resolved": false, "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "dev": true + "dev": true, + "optional": true }, "concat-map": { "version": "0.0.1", "resolved": false, "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true + "dev": true, + "optional": true }, "console-control-strings": { "version": "1.1.0", "resolved": false, "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", - "dev": true + "dev": true, + "optional": true }, "core-util-is": { "version": "1.0.2", @@ -2926,7 +2924,8 @@ "version": "2.0.3", "resolved": false, "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true + "dev": true, + "optional": true }, "ini": { "version": "1.3.5", @@ -2940,6 +2939,7 @@ "resolved": false, "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "dev": true, + "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -2956,6 +2956,7 @@ "resolved": false, "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, + "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -2964,13 +2965,15 @@ "version": "0.0.8", "resolved": false, "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", - "dev": true + "dev": true, + "optional": true }, "mkdirp": { "version": "0.5.1", "resolved": false, "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "dev": true, + "optional": true, "requires": { "minimist": "0.0.8" } @@ -3059,7 +3062,8 @@ "version": "1.0.1", "resolved": false, "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "dev": true + "dev": true, + "optional": true }, "object-assign": { "version": "4.1.1", @@ -3073,6 +3077,7 @@ "resolved": false, "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, + "optional": true, "requires": { "wrappy": "1" } @@ -3168,7 +3173,8 @@ "version": "5.1.1", "resolved": false, "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", - "dev": true + "dev": true, + "optional": true }, "safer-buffer": { "version": "2.1.2", @@ -3210,6 +3216,7 @@ "resolved": false, "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, + "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -3231,6 +3238,7 @@ "resolved": false, "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, + "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -3288,7 +3296,8 @@ "version": "1.0.2", "resolved": false, "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true + "dev": true, + "optional": true }, "yallist": { "version": "3.0.3", @@ -3794,7 +3803,7 @@ }, "os-locale": { "version": "1.4.0", - "resolved": "http://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", "dev": true, "requires": { @@ -4544,7 +4553,7 @@ }, "is-accessor-descriptor": { "version": "0.1.6", - "resolved": "http://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", "dev": true, "requires": { @@ -4609,7 +4618,7 @@ }, "is-data-descriptor": { "version": "0.1.4", - "resolved": "http://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", "dev": true, "requires": { @@ -5352,7 +5361,7 @@ }, "load-json-file": { "version": "1.1.0", - "resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", "dev": true, "requires": { @@ -5365,7 +5374,7 @@ "dependencies": { "pify": { "version": "2.3.0", - "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", "dev": true } @@ -5381,9 +5390,9 @@ } }, "lodash": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "version": "4.17.19", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", + "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==", "dev": true }, "lodash._reinterpolate": { @@ -6847,7 +6856,7 @@ "dependencies": { "pify": { "version": "2.3.0", - "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", "dev": true } @@ -8549,6 +8558,16 @@ "dev": true, "requires": { "data-api-client": "github:ArsenyYankovsky/data-api-client#043f3320f8d665c21250d615101e7b3bc8f1d298" + }, + "dependencies": { + "data-api-client": { + "version": "github:ArsenyYankovsky/data-api-client#043f3320f8d665c21250d615101e7b3bc8f1d298", + "from": "github:ArsenyYankovsky/data-api-client#support-postgres", + "dev": true, + "requires": { + "sqlstring": "^2.3.1" + } + } } }, "typescript": { From c9f184e887baa87d92790a91e495c6d2e52ff12f Mon Sep 17 00:00:00 2001 From: Fernando Moreira Date: Thu, 16 Jul 2020 08:54:30 -0300 Subject: [PATCH 002/212] docs: update using-cli.md (#6407) --- docs/using-cli.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/using-cli.md b/docs/using-cli.md index 0abcc8f971a..a240a9bf9d5 100644 --- a/docs/using-cli.md +++ b/docs/using-cli.md @@ -5,7 +5,7 @@ * [Create a new entity](#create-a-new-entity) * [Create a new subscriber](#create-a-new-subscriber) * [Create a new migration](#create-a-new-migration) -* [Generate a migration from existing table schema](#generate-a-migration-from-exist-table-schema) +* [Generate a migration from existing table schema](#generate-a-migration-from-existing-table-schema) * [Run migrations](#run-migrations) * [Revert migrations](#revert-migrations) * [Show migrations](#show-migrations) From afc62fdfffe60b32b7db322268c738fc9a35ec59 Mon Sep 17 00:00:00 2001 From: Pouria Tajdivand Date: Thu, 16 Jul 2020 16:25:29 +0430 Subject: [PATCH 003/212] docs: Added one-to-one-relations.md & many-to-one-one-to-many-relations.md cascades link (#6406) * docs: one-to-one-relations.md cascades link * docs: many-to-one-one-to-many-relations.md cascades link --- docs/many-to-one-one-to-many-relations.md | 2 +- docs/one-to-one-relations.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/many-to-one-one-to-many-relations.md b/docs/many-to-one-one-to-many-relations.md index 0a4e53d73e6..16c24e23839 100644 --- a/docs/many-to-one-one-to-many-relations.md +++ b/docs/many-to-one-one-to-many-relations.md @@ -102,7 +102,7 @@ photo2.user = user; await connection.manager.save(photo2); ``` -With cascades enabled you can save this relation with only one `save` call. +With [cascades](https://github.com/typeorm/typeorm/blob/master/docs/relations.md#cascades) enabled you can save this relation with only one `save` call. To load a user with photos inside you must specify the relation in `FindOptions`: diff --git a/docs/one-to-one-relations.md b/docs/one-to-one-relations.md index acb87e0bf68..ee5c86774fe 100644 --- a/docs/one-to-one-relations.md +++ b/docs/one-to-one-relations.md @@ -82,7 +82,7 @@ user.profile = profile; await connection.manager.save(user); ``` -With cascades enabled you can save this relation with only one `save` call. +With [cascades](https://github.com/typeorm/typeorm/blob/master/docs/relations.md#cascades) enabled you can save this relation with only one `save` call. To load user with profile inside you must specify relation in `FindOptions`: From 874e5736776cb94635e4d6e2486aade4d797ed10 Mon Sep 17 00:00:00 2001 From: Gregory Date: Fri, 17 Jul 2020 04:32:21 +0300 Subject: [PATCH 004/212] fix: Query builder makes query with joins, without limit for inherited entities (#6402) Closes: #6399 Co-authored-by: Gregory Komagurov --- src/query-builder/QueryBuilder.ts | 26 +++++++++----- test/github-issues/6399/entities.ts | 52 +++++++++++++++++++++++++++ test/github-issues/6399/issue-6399.ts | 49 +++++++++++++++++++++++++ 3 files changed, 118 insertions(+), 9 deletions(-) create mode 100644 test/github-issues/6399/entities.ts create mode 100644 test/github-issues/6399/issue-6399.ts diff --git a/src/query-builder/QueryBuilder.ts b/src/query-builder/QueryBuilder.ts index f11ac46a98f..21ae390277e 100644 --- a/src/query-builder/QueryBuilder.ts +++ b/src/query-builder/QueryBuilder.ts @@ -598,7 +598,10 @@ export abstract class QueryBuilder { * Creates "WHERE" expression. */ protected createWhereExpression() { - let conditions = this.createWhereExpressionString(); + const conditionsArray = []; + + const whereExpression = this.createWhereExpressionString(); + whereExpression.trim() && conditionsArray.push(this.createWhereExpressionString()); if (this.expressionMap.mainAlias!.hasMetadata) { const metadata = this.expressionMap.mainAlias!.metadata; @@ -609,7 +612,7 @@ export abstract class QueryBuilder { : metadata.deleteDateColumn.propertyName; const condition = `${this.replacePropertyNames(column)} IS NULL`; - conditions = `${ conditions.length ? "(" + conditions + ") AND" : "" } ${condition}`; + conditionsArray.push(condition); } if (metadata.discriminatorColumn && metadata.parentEntityMetadata) { @@ -618,17 +621,22 @@ export abstract class QueryBuilder { : metadata.discriminatorColumn.databaseName; const condition = `${this.replacePropertyNames(column)} IN (:...discriminatorColumnValues)`; - return ` WHERE ${ conditions.length ? "(" + conditions + ") AND" : "" } ${condition}`; + conditionsArray.push(condition); } } - if (!conditions.length) // TODO copy in to discriminator condition - return this.expressionMap.extraAppendedAndWhereCondition ? " WHERE " + this.replacePropertyNames(this.expressionMap.extraAppendedAndWhereCondition) : ""; - - if (this.expressionMap.extraAppendedAndWhereCondition) - return " WHERE (" + conditions + ") AND " + this.replacePropertyNames(this.expressionMap.extraAppendedAndWhereCondition); + if (this.expressionMap.extraAppendedAndWhereCondition) { + const condition = this.replacePropertyNames(this.expressionMap.extraAppendedAndWhereCondition); + conditionsArray.push(condition); + } - return " WHERE " + conditions; + if (!conditionsArray.length) { + return " "; + } else if (conditionsArray.length === 1) { + return ` WHERE ${conditionsArray[0]}`; + } else { + return ` WHERE ( ${conditionsArray.join(" ) AND ( ")} )`; + } } /** diff --git a/test/github-issues/6399/entities.ts b/test/github-issues/6399/entities.ts new file mode 100644 index 00000000000..9629ee269ce --- /dev/null +++ b/test/github-issues/6399/entities.ts @@ -0,0 +1,52 @@ +import {Entity, OneToMany, ManyToOne} from "../../../src"; +import {Column} from "../../../src"; +import {PrimaryGeneratedColumn} from "../../../src"; +import { TableInheritance } from "../../../src"; +import {ChildEntity} from "../../../src"; +import {JoinColumn} from "../../../src"; + +@Entity() +export class Comment { + @PrimaryGeneratedColumn() + id: number; + + @Column() + text: string; + + @Column() + postId: number; + + @ManyToOne( + () => Post, + (entity) => entity.comments, + ) + @JoinColumn({ + name: "postId", + }) + post?: Post; + +} + +@Entity() +@TableInheritance({column: {type: "string", name: "postType"}}) +export class Post { + @PrimaryGeneratedColumn() + id: number; + + @Column() + title: string; + + @Column() + postType: string = "BasePost"; + + @OneToMany(() => Comment, (entity) => entity.post) + comments?: Comment[]; +} + +@ChildEntity("TargetPost") +export class TargetPost extends Post { + @Column() + postType: string = "TargetPost"; +} + + diff --git a/test/github-issues/6399/issue-6399.ts b/test/github-issues/6399/issue-6399.ts new file mode 100644 index 00000000000..a4f8f2d1b4c --- /dev/null +++ b/test/github-issues/6399/issue-6399.ts @@ -0,0 +1,49 @@ +import {Connection} from "../../../src"; +import {expect} from "chai"; +import {closeTestingConnections, createTestingConnections, reloadTestingDatabases} from "../../utils/test-utils"; +import {Post, TargetPost, Comment} from "./entities"; + +describe("github issues > #6399 Process extraAppendedAndWhereCondition for inherited entity", () => { + let connections: Connection[]; + + before(async () => { + return connections = await createTestingConnections({ + entities: [Post, TargetPost, Comment], + schemaCreate: true, + dropSchema: true, + enabledDrivers: ["mysql"] + }); + }); + beforeEach(() => reloadTestingDatabases(connections)); + after(() => closeTestingConnections(connections)); + + it("Query with join and limit for inhered entity", () => Promise.all(connections.map(async (connection) => { + const targetPostRepo = connection.getRepository(TargetPost); + + const posts: TargetPost[] = [ + { + id: 1, + title: "Post 1", + postType: "TargetPost", + }, + { id: 2, + title: "Post 2", + postType: "TargetPost", + }, + { + id: 3, + title: "Post 3", + postType: "TargetPost", + }, + ]; + + await targetPostRepo.save(posts); + + const result = await targetPostRepo.createQueryBuilder("targetPosts") + .leftJoinAndSelect("targetPosts.comments", "comments") + .take(2) + .getMany(); + + expect(result.length).eq(2); + }))); +}); From c23c88802cee33e377bc2ce85ed9aa2e6e1c14c8 Mon Sep 17 00:00:00 2001 From: SakirSoft Date: Fri, 17 Jul 2020 03:52:33 +0200 Subject: [PATCH 005/212] fix: decorators should implement the official TypeScript interface (#6398) Closes: #5922 --- src/decorator/Check.ts | 8 ++-- src/decorator/EntityRepository.ts | 2 +- src/decorator/Exclusion.ts | 8 ++-- src/decorator/Generated.ts | 2 +- src/decorator/Index.ts | 18 ++++----- src/decorator/Unique.ts | 37 +++++++++++++------ src/decorator/columns/Column.ts | 26 ++++++------- src/decorator/columns/CreateDateColumn.ts | 2 +- src/decorator/columns/DeleteDateColumn.ts | 2 +- src/decorator/columns/ObjectIdColumn.ts | 2 +- src/decorator/columns/PrimaryColumn.ts | 6 +-- .../columns/PrimaryGeneratedColumn.ts | 12 +++--- src/decorator/columns/UpdateDateColumn.ts | 2 +- src/decorator/columns/VersionColumn.ts | 2 +- src/decorator/columns/ViewColumn.ts | 2 +- src/decorator/entity-view/ViewEntity.ts | 6 +-- src/decorator/entity/ChildEntity.ts | 2 +- src/decorator/entity/TableInheritance.ts | 2 +- src/decorator/listeners/AfterInsert.ts | 2 +- src/decorator/listeners/AfterLoad.ts | 2 +- src/decorator/listeners/AfterRemove.ts | 2 +- src/decorator/listeners/AfterUpdate.ts | 2 +- src/decorator/listeners/BeforeInsert.ts | 2 +- src/decorator/listeners/BeforeRemove.ts | 2 +- src/decorator/listeners/BeforeUpdate.ts | 2 +- src/decorator/listeners/EventSubscriber.ts | 2 +- src/decorator/relations/JoinColumn.ts | 8 ++-- src/decorator/relations/JoinTable.ts | 8 ++-- src/decorator/relations/ManyToMany.ts | 6 +-- src/decorator/relations/ManyToOne.ts | 6 +-- src/decorator/relations/OneToMany.ts | 2 +- src/decorator/relations/OneToOne.ts | 6 +-- src/decorator/relations/RelationCount.ts | 2 +- src/decorator/relations/RelationId.ts | 2 +- .../transaction/TransactionManager.ts | 2 +- src/decorator/tree/Tree.ts | 2 +- src/decorator/tree/TreeChildren.ts | 2 +- src/decorator/tree/TreeLevelColumn.ts | 2 +- src/decorator/tree/TreeParent.ts | 2 +- 39 files changed, 111 insertions(+), 96 deletions(-) diff --git a/src/decorator/Check.ts b/src/decorator/Check.ts index 138eea1174a..305fd1e5b80 100644 --- a/src/decorator/Check.ts +++ b/src/decorator/Check.ts @@ -6,21 +6,21 @@ import {CheckMetadataArgs} from "../metadata-args/CheckMetadataArgs"; * Can be used on entity property or on entity. * Can create checks with composite columns when used on entity. */ -export function Check(expression: string): Function; +export function Check(expression: string): ClassDecorator & PropertyDecorator; /** * Creates a database check. * Can be used on entity property or on entity. * Can create checks with composite columns when used on entity. */ -export function Check(name: string, expression: string): Function; +export function Check(name: string, expression: string): ClassDecorator & PropertyDecorator; /** * Creates a database check. * Can be used on entity property or on entity. * Can create checks with composite columns when used on entity. */ -export function Check(nameOrExpression: string, maybeExpression?: string): Function { +export function Check(nameOrExpression: string, maybeExpression?: string): ClassDecorator & PropertyDecorator { const name = maybeExpression ? nameOrExpression : undefined; const expression = maybeExpression ? maybeExpression : nameOrExpression; @@ -28,7 +28,7 @@ export function Check(nameOrExpression: string, maybeExpression?: string): Funct if (!expression) throw new Error(`Check expression is required`); - return function (clsOrObject: Function|Object, propertyName?: string) { + return function (clsOrObject: Function|Object, propertyName?: string | symbol) { getMetadataArgsStorage().checks.push({ target: propertyName ? clsOrObject.constructor : clsOrObject as Function, diff --git a/src/decorator/EntityRepository.ts b/src/decorator/EntityRepository.ts index 996acb395ac..b97d58ce150 100644 --- a/src/decorator/EntityRepository.ts +++ b/src/decorator/EntityRepository.ts @@ -7,7 +7,7 @@ import { EntitySchema } from "../entity-schema/EntitySchema"; * Custom repository can manage some specific entity or just be generic. * Custom repository optionally can extend AbstractRepository, Repository or TreeRepository. */ -export function EntityRepository(entity?: Function | EntitySchema): Function { +export function EntityRepository(entity?: Function | EntitySchema): ClassDecorator { return function (target: Function) { getMetadataArgsStorage().entityRepositories.push({ diff --git a/src/decorator/Exclusion.ts b/src/decorator/Exclusion.ts index 75f3434a94a..d05394cab88 100644 --- a/src/decorator/Exclusion.ts +++ b/src/decorator/Exclusion.ts @@ -6,21 +6,21 @@ import {ExclusionMetadataArgs} from "../metadata-args/ExclusionMetadataArgs"; * Can be used on entity. * Can create exclusions with composite columns when used on entity. */ -export function Exclusion(expression: string): Function; +export function Exclusion(expression: string): ClassDecorator & PropertyDecorator; /** * Creates a database exclusion. * Can be used on entity. * Can create exclusions with composite columns when used on entity. */ -export function Exclusion(name: string, expression: string): Function; +export function Exclusion(name: string, expression: string): ClassDecorator & PropertyDecorator; /** * Creates a database exclusion. * Can be used on entity. * Can create exclusions with composite columns when used on entity. */ -export function Exclusion(nameOrExpression: string, maybeExpression?: string): Function { +export function Exclusion(nameOrExpression: string, maybeExpression?: string): ClassDecorator & PropertyDecorator { const name = maybeExpression ? nameOrExpression : undefined; const expression = maybeExpression ? maybeExpression : nameOrExpression; @@ -28,7 +28,7 @@ export function Exclusion(nameOrExpression: string, maybeExpression?: string): F if (!expression) throw new Error(`Exclusion expression is required`); - return function (clsOrObject: Function|Object, propertyName?: string) { + return function (clsOrObject: Function|Object, propertyName?: string | symbol) { getMetadataArgsStorage().exclusions.push({ target: propertyName ? clsOrObject.constructor : clsOrObject as Function, diff --git a/src/decorator/Generated.ts b/src/decorator/Generated.ts index 9857c95e497..934ccd4b6c4 100644 --- a/src/decorator/Generated.ts +++ b/src/decorator/Generated.ts @@ -10,7 +10,7 @@ import {GeneratedMetadataArgs} from "../metadata-args/GeneratedMetadataArgs"; * * Note, some databases do not support non-primary generation columns. */ -export function Generated(strategy: "increment"|"uuid"|"rowid" = "increment"): Function { +export function Generated(strategy: "increment"|"uuid"|"rowid" = "increment"): PropertyDecorator { return function (object: Object, propertyName: string) { getMetadataArgsStorage().generations.push({ diff --git a/src/decorator/Index.ts b/src/decorator/Index.ts index 17e57ea5c0a..2bc63d68269 100644 --- a/src/decorator/Index.ts +++ b/src/decorator/Index.ts @@ -6,49 +6,49 @@ import {IndexMetadataArgs} from "../metadata-args/IndexMetadataArgs"; * Can be used on entity property or on entity. * Can create indices with composite columns when used on entity. */ -export function Index(options?: IndexOptions): Function; +export function Index(options?: IndexOptions): ClassDecorator & PropertyDecorator; /** * Creates a database index. * Can be used on entity property or on entity. * Can create indices with composite columns when used on entity. */ -export function Index(name: string, options?: IndexOptions): Function; +export function Index(name: string, options?: IndexOptions): ClassDecorator & PropertyDecorator; /** * Creates a database index. * Can be used on entity property or on entity. * Can create indices with composite columns when used on entity. */ -export function Index(name: string, options: { synchronize: false }): Function; +export function Index(name: string, options: { synchronize: false }): ClassDecorator & PropertyDecorator; /** * Creates a database index. * Can be used on entity property or on entity. * Can create indices with composite columns when used on entity. */ -export function Index(name: string, fields: string[], options?: IndexOptions): Function; +export function Index(name: string, fields: string[], options?: IndexOptions): ClassDecorator & PropertyDecorator; /** * Creates a database index. * Can be used on entity property or on entity. * Can create indices with composite columns when used on entity. */ -export function Index(fields: string[], options?: IndexOptions): Function; +export function Index(fields: string[], options?: IndexOptions): ClassDecorator & PropertyDecorator; /** * Creates a database index. * Can be used on entity property or on entity. * Can create indices with composite columns when used on entity. */ -export function Index(fields: (object?: any) => (any[]|{ [key: string]: number }), options?: IndexOptions): Function; +export function Index(fields: (object?: any) => (any[]|{ [key: string]: number }), options?: IndexOptions): ClassDecorator & PropertyDecorator; /** * Creates a database index. * Can be used on entity property or on entity. * Can create indices with composite columns when used on entity. */ -export function Index(name: string, fields: (object?: any) => (any[]|{ [key: string]: number }), options?: IndexOptions): Function; +export function Index(name: string, fields: (object?: any) => (any[]|{ [key: string]: number }), options?: IndexOptions): ClassDecorator & PropertyDecorator; /** * Creates a database index. @@ -57,7 +57,7 @@ export function Index(name: string, fields: (object?: any) => (any[]|{ [key: str */ export function Index(nameOrFieldsOrOptions?: string|string[]|((object: any) => (any[]|{ [key: string]: number }))|IndexOptions, maybeFieldsOrOptions?: ((object?: any) => (any[]|{ [key: string]: number }))|IndexOptions|string[]|{ synchronize: false }, - maybeOptions?: IndexOptions): Function { + maybeOptions?: IndexOptions): ClassDecorator & PropertyDecorator { // normalize parameters const name = typeof nameOrFieldsOrOptions === "string" ? nameOrFieldsOrOptions : undefined; @@ -66,7 +66,7 @@ export function Index(nameOrFieldsOrOptions?: string|string[]|((object: any) => if (!options) options = (typeof maybeFieldsOrOptions === "object" && !Array.isArray(maybeFieldsOrOptions)) ? maybeFieldsOrOptions as IndexOptions : maybeOptions; - return function (clsOrObject: Function|Object, propertyName?: string) { + return function (clsOrObject: Function|Object, propertyName?: string | symbol) { getMetadataArgsStorage().indices.push({ target: propertyName ? clsOrObject.constructor : clsOrObject as Function, diff --git a/src/decorator/Unique.ts b/src/decorator/Unique.ts index 871e25c58a1..1923af52ad1 100644 --- a/src/decorator/Unique.ts +++ b/src/decorator/Unique.ts @@ -1,39 +1,54 @@ -import {getMetadataArgsStorage} from "../index"; -import {UniqueMetadataArgs} from "../metadata-args/UniqueMetadataArgs"; +import { getMetadataArgsStorage } from "../index"; +import { UniqueMetadataArgs } from "../metadata-args/UniqueMetadataArgs"; /** * Composite unique constraint must be set on entity classes and must specify entity's fields to be unique. */ -export function Unique(name: string, fields: string[]): Function; +export function Unique(name: string, fields: string[]): ClassDecorator & PropertyDecorator; /** * Composite unique constraint must be set on entity classes and must specify entity's fields to be unique. */ -export function Unique(fields: string[]): Function; +export function Unique(fields: string[]): ClassDecorator & PropertyDecorator; /** * Composite unique constraint must be set on entity classes and must specify entity's fields to be unique. */ -export function Unique(fields: (object?: any) => (any[]|{ [key: string]: number })): Function; +export function Unique(fields: (object?: any) => (any[] | { [key: string]: number })): ClassDecorator & PropertyDecorator; /** * Composite unique constraint must be set on entity classes and must specify entity's fields to be unique. */ -export function Unique(name: string, fields: (object?: any) => (any[]|{ [key: string]: number })): Function; +export function Unique(name: string, fields: (object?: any) => (any[] | { [key: string]: number })): ClassDecorator & PropertyDecorator; /** * Composite unique constraint must be set on entity classes and must specify entity's fields to be unique. */ -export function Unique(nameOrFields?: string|string[]|((object: any) => (any[]|{ [key: string]: number })), - maybeFields?: ((object?: any) => (any[]|{ [key: string]: number }))|string[]): Function { +export function Unique(nameOrFields?: string | string[] | ((object: any) => (any[] | { [key: string]: number })), + maybeFields?: ((object?: any) => (any[] | { [key: string]: number })) | string[]): ClassDecorator & PropertyDecorator { const name = typeof nameOrFields === "string" ? nameOrFields : undefined; - const fields = typeof nameOrFields === "string" ? <((object?: any) => (any[]|{ [key: string]: number }))|string[]> maybeFields : nameOrFields as string[]; + const fields = typeof nameOrFields === "string" ? <((object?: any) => (any[] | { [key: string]: number })) | string[]>maybeFields : nameOrFields as string[]; + + return function (clsOrObject: Function | Object, propertyName?: string | symbol) { + + let columns = fields; + + if (propertyName !== undefined) { + switch (typeof (propertyName)) { + case "string": + columns = [propertyName]; + break; + + case "symbol": + columns = [propertyName.toString()]; + break; + } + } - return function (clsOrObject: Function|Object, propertyName?: string) { const args: UniqueMetadataArgs = { target: propertyName ? clsOrObject.constructor : clsOrObject as Function, name: name, - columns: propertyName ? [propertyName] : fields + columns, }; getMetadataArgsStorage().uniques.push(args); }; diff --git a/src/decorator/columns/Column.ts b/src/decorator/columns/Column.ts index 834c33119ea..84e937a6dfd 100644 --- a/src/decorator/columns/Column.ts +++ b/src/decorator/columns/Column.ts @@ -20,67 +20,67 @@ import { GeneratedMetadataArgs } from "../../metadata-args/GeneratedMetadataArgs * Column decorator is used to mark a specific class property as a table column. Only properties decorated with this * decorator will be persisted to the database when entity be saved. */ -export function Column(): Function; +export function Column(): PropertyDecorator; /** * Column decorator is used to mark a specific class property as a table column. * Only properties decorated with this decorator will be persisted to the database when entity be saved. */ -export function Column(options: ColumnOptions): Function; +export function Column(options: ColumnOptions): PropertyDecorator; /** * Column decorator is used to mark a specific class property as a table column. * Only properties decorated with this decorator will be persisted to the database when entity be saved. */ -export function Column(type: SimpleColumnType, options?: ColumnCommonOptions): Function; +export function Column(type: SimpleColumnType, options?: ColumnCommonOptions): PropertyDecorator; /** * Column decorator is used to mark a specific class property as a table column. * Only properties decorated with this decorator will be persisted to the database when entity be saved. */ -export function Column(type: SpatialColumnType, options?: ColumnCommonOptions & SpatialColumnOptions): Function; +export function Column(type: SpatialColumnType, options?: ColumnCommonOptions & SpatialColumnOptions): PropertyDecorator; /** * Column decorator is used to mark a specific class property as a table column. * Only properties decorated with this decorator will be persisted to the database when entity be saved. */ -export function Column(type: WithLengthColumnType, options?: ColumnCommonOptions & ColumnWithLengthOptions): Function; +export function Column(type: WithLengthColumnType, options?: ColumnCommonOptions & ColumnWithLengthOptions): PropertyDecorator; /** * Column decorator is used to mark a specific class property as a table column. * Only properties decorated with this decorator will be persisted to the database when entity be saved. */ -export function Column(type: WithWidthColumnType, options?: ColumnCommonOptions & ColumnWithWidthOptions): Function; +export function Column(type: WithWidthColumnType, options?: ColumnCommonOptions & ColumnWithWidthOptions): PropertyDecorator; /** * Column decorator is used to mark a specific class property as a table column. * Only properties decorated with this decorator will be persisted to the database when entity be saved. */ -export function Column(type: WithPrecisionColumnType, options?: ColumnCommonOptions & ColumnNumericOptions): Function; +export function Column(type: WithPrecisionColumnType, options?: ColumnCommonOptions & ColumnNumericOptions): PropertyDecorator; /** * Column decorator is used to mark a specific class property as a table column. * Only properties decorated with this decorator will be persisted to the database when entity be saved. */ -export function Column(type: "enum", options?: ColumnCommonOptions & ColumnEnumOptions): Function; +export function Column(type: "enum", options?: ColumnCommonOptions & ColumnEnumOptions): PropertyDecorator; /** * Column decorator is used to mark a specific class property as a table column. * Only properties decorated with this decorator will be persisted to the database when entity be saved. */ -export function Column(type: "simple-enum", options?: ColumnCommonOptions & ColumnEnumOptions): Function; +export function Column(type: "simple-enum", options?: ColumnCommonOptions & ColumnEnumOptions): PropertyDecorator; /** * Column decorator is used to mark a specific class property as a table column. * Only properties decorated with this decorator will be persisted to the database when entity be saved. */ -export function Column(type: "set", options?: ColumnCommonOptions & ColumnEnumOptions): Function; +export function Column(type: "set", options?: ColumnCommonOptions & ColumnEnumOptions): PropertyDecorator; /** * Column decorator is used to mark a specific class property as a table column. * Only properties decorated with this decorator will be persisted to the database when entity be saved. */ -export function Column(type: "hstore", options?: ColumnCommonOptions & ColumnHstoreOptions): Function; +export function Column(type: "hstore", options?: ColumnCommonOptions & ColumnHstoreOptions): PropertyDecorator; /** * Column decorator is used to mark a specific class property as a table column. @@ -90,13 +90,13 @@ export function Column(type: "hstore", options?: ColumnCommonOptions & ColumnHst * single table of the entity where Embedded is used. And on hydration all columns which supposed to be in the * embedded will be mapped to it from the single table. */ -export function Column(type: (type?: any) => Function, options?: ColumnEmbeddedOptions): Function; +export function Column(type: (type?: any) => Function, options?: ColumnEmbeddedOptions): PropertyDecorator; /** * Column decorator is used to mark a specific class property as a table column. * Only properties decorated with this decorator will be persisted to the database when entity be saved. */ -export function Column(typeOrOptions?: ((type?: any) => Function)|ColumnType|(ColumnOptions&ColumnEmbeddedOptions), options?: (ColumnOptions&ColumnEmbeddedOptions)): Function { +export function Column(typeOrOptions?: ((type?: any) => Function)|ColumnType|(ColumnOptions&ColumnEmbeddedOptions), options?: (ColumnOptions&ColumnEmbeddedOptions)): PropertyDecorator { return function (object: Object, propertyName: string) { // normalize parameters diff --git a/src/decorator/columns/CreateDateColumn.ts b/src/decorator/columns/CreateDateColumn.ts index 6d9acd802d0..b14bf5c4f3a 100644 --- a/src/decorator/columns/CreateDateColumn.ts +++ b/src/decorator/columns/CreateDateColumn.ts @@ -6,7 +6,7 @@ import {ColumnMetadataArgs} from "../../metadata-args/ColumnMetadataArgs"; * Creation date is generated and inserted only once, * at the first time when you create an object, the value is inserted into the table, and is never touched again. */ -export function CreateDateColumn(options?: ColumnOptions): Function { +export function CreateDateColumn(options?: ColumnOptions): PropertyDecorator { return function (object: Object, propertyName: string) { getMetadataArgsStorage().columns.push({ target: object.constructor, diff --git a/src/decorator/columns/DeleteDateColumn.ts b/src/decorator/columns/DeleteDateColumn.ts index 35ea43b8480..deece8bba07 100644 --- a/src/decorator/columns/DeleteDateColumn.ts +++ b/src/decorator/columns/DeleteDateColumn.ts @@ -5,7 +5,7 @@ import { ColumnMetadataArgs } from "../../metadata-args/ColumnMetadataArgs"; * This column will store a delete date of the soft-deleted object. * This date is being updated each time you soft-delete the object. */ -export function DeleteDateColumn(options?: ColumnOptions): Function { +export function DeleteDateColumn(options?: ColumnOptions): PropertyDecorator { return function(object: Object, propertyName: string) { getMetadataArgsStorage().columns.push({ target: object.constructor, diff --git a/src/decorator/columns/ObjectIdColumn.ts b/src/decorator/columns/ObjectIdColumn.ts index 257aebf347e..5feeb201dec 100644 --- a/src/decorator/columns/ObjectIdColumn.ts +++ b/src/decorator/columns/ObjectIdColumn.ts @@ -5,7 +5,7 @@ import {ColumnMetadataArgs} from "../../metadata-args/ColumnMetadataArgs"; * Special type of column that is available only for MongoDB database. * Marks your entity's column to be an object id. */ -export function ObjectIdColumn(options?: ColumnOptions): Function { +export function ObjectIdColumn(options?: ColumnOptions): PropertyDecorator { return function (object: Object, propertyName: string) { // if column options are not given then create a new empty options diff --git a/src/decorator/columns/PrimaryColumn.ts b/src/decorator/columns/PrimaryColumn.ts index 9c56828bf6c..4ac950cc832 100644 --- a/src/decorator/columns/PrimaryColumn.ts +++ b/src/decorator/columns/PrimaryColumn.ts @@ -9,21 +9,21 @@ import { GeneratedMetadataArgs } from "../../metadata-args/GeneratedMetadataArgs * Only properties decorated with this decorator will be persisted to the database when entity be saved. * Primary columns also creates a PRIMARY KEY for this column in a db. */ -export function PrimaryColumn(options?: ColumnOptions): Function; +export function PrimaryColumn(options?: ColumnOptions): PropertyDecorator; /** * Column decorator is used to mark a specific class property as a table column. * Only properties decorated with this decorator will be persisted to the database when entity be saved. * Primary columns also creates a PRIMARY KEY for this column in a db. */ -export function PrimaryColumn(type?: ColumnType, options?: ColumnOptions): Function; +export function PrimaryColumn(type?: ColumnType, options?: ColumnOptions): PropertyDecorator; /** * Column decorator is used to mark a specific class property as a table column. * Only properties decorated with this decorator will be persisted to the database when entity be saved. * Primary columns also creates a PRIMARY KEY for this column in a db. */ -export function PrimaryColumn(typeOrOptions?: ColumnType|ColumnOptions, options?: ColumnOptions): Function { +export function PrimaryColumn(typeOrOptions?: ColumnType|ColumnOptions, options?: ColumnOptions): PropertyDecorator { return function (object: Object, propertyName: string) { // normalize parameters diff --git a/src/decorator/columns/PrimaryGeneratedColumn.ts b/src/decorator/columns/PrimaryGeneratedColumn.ts index afa6c81336e..14fbffa55a1 100644 --- a/src/decorator/columns/PrimaryGeneratedColumn.ts +++ b/src/decorator/columns/PrimaryGeneratedColumn.ts @@ -6,27 +6,27 @@ import {GeneratedMetadataArgs} from "../../metadata-args/GeneratedMetadataArgs"; /** * Column decorator is used to mark a specific class property as a table column. */ -export function PrimaryGeneratedColumn(): Function; +export function PrimaryGeneratedColumn(): PropertyDecorator; /** * Column decorator is used to mark a specific class property as a table column. */ -export function PrimaryGeneratedColumn(options: PrimaryGeneratedColumnNumericOptions): Function; +export function PrimaryGeneratedColumn(options: PrimaryGeneratedColumnNumericOptions): PropertyDecorator; /** * Column decorator is used to mark a specific class property as a table column. */ -export function PrimaryGeneratedColumn(strategy: "increment", options?: PrimaryGeneratedColumnNumericOptions): Function; +export function PrimaryGeneratedColumn(strategy: "increment", options?: PrimaryGeneratedColumnNumericOptions): PropertyDecorator; /** * Column decorator is used to mark a specific class property as a table column. */ -export function PrimaryGeneratedColumn(strategy: "uuid", options?: PrimaryGeneratedColumnUUIDOptions): Function; +export function PrimaryGeneratedColumn(strategy: "uuid", options?: PrimaryGeneratedColumnUUIDOptions): PropertyDecorator; /** * Column decorator is used to mark a specific class property as a table column. */ -export function PrimaryGeneratedColumn(strategy: "rowid", options?: PrimaryGeneratedColumnUUIDOptions): Function; +export function PrimaryGeneratedColumn(strategy: "rowid", options?: PrimaryGeneratedColumnUUIDOptions): PropertyDecorator; /** * Column decorator is used to mark a specific class property as a table column. @@ -34,7 +34,7 @@ export function PrimaryGeneratedColumn(strategy: "rowid", options?: PrimaryGener * This column creates an integer PRIMARY COLUMN with generated set to true. */ export function PrimaryGeneratedColumn(strategyOrOptions?: "increment"|"uuid"|"rowid"|PrimaryGeneratedColumnNumericOptions|PrimaryGeneratedColumnUUIDOptions, - maybeOptions?: PrimaryGeneratedColumnNumericOptions|PrimaryGeneratedColumnUUIDOptions): Function { + maybeOptions?: PrimaryGeneratedColumnNumericOptions|PrimaryGeneratedColumnUUIDOptions): PropertyDecorator { // normalize parameters const options: ColumnOptions = {}; diff --git a/src/decorator/columns/UpdateDateColumn.ts b/src/decorator/columns/UpdateDateColumn.ts index f4895e76b42..f4627a0df4c 100644 --- a/src/decorator/columns/UpdateDateColumn.ts +++ b/src/decorator/columns/UpdateDateColumn.ts @@ -5,7 +5,7 @@ import {ColumnMetadataArgs} from "../../metadata-args/ColumnMetadataArgs"; * This column will store an update date of the updated object. * This date is being updated each time you persist the object. */ -export function UpdateDateColumn(options?: ColumnOptions): Function { +export function UpdateDateColumn(options?: ColumnOptions): PropertyDecorator { return function (object: Object, propertyName: string) { getMetadataArgsStorage().columns.push({ diff --git a/src/decorator/columns/VersionColumn.ts b/src/decorator/columns/VersionColumn.ts index f1f14984a3b..17798697836 100644 --- a/src/decorator/columns/VersionColumn.ts +++ b/src/decorator/columns/VersionColumn.ts @@ -6,7 +6,7 @@ import {ColumnMetadataArgs} from "../../metadata-args/ColumnMetadataArgs"; * Every time your entity will be persisted, this number will be increased by one - * so you can organize visioning and update strategies of your entity. */ -export function VersionColumn(options?: ColumnOptions): Function { +export function VersionColumn(options?: ColumnOptions): PropertyDecorator { return function (object: Object, propertyName: string) { getMetadataArgsStorage().columns.push({ diff --git a/src/decorator/columns/ViewColumn.ts b/src/decorator/columns/ViewColumn.ts index e3df7bcd4d1..11356f66e3e 100644 --- a/src/decorator/columns/ViewColumn.ts +++ b/src/decorator/columns/ViewColumn.ts @@ -5,7 +5,7 @@ import { ViewColumnOptions } from "../options/ViewColumnOptions"; /** * ViewColumn decorator is used to mark a specific class property as a view column. */ -export function ViewColumn(options?: ViewColumnOptions): Function { +export function ViewColumn(options?: ViewColumnOptions): PropertyDecorator { return function (object: Object, propertyName: string) { getMetadataArgsStorage().columns.push({ target: object.constructor, diff --git a/src/decorator/entity-view/ViewEntity.ts b/src/decorator/entity-view/ViewEntity.ts index 50cb0f96a43..7223ed8ce58 100644 --- a/src/decorator/entity-view/ViewEntity.ts +++ b/src/decorator/entity-view/ViewEntity.ts @@ -6,19 +6,19 @@ import {ViewEntityOptions} from "../options/ViewEntityOptions"; * This decorator is used to mark classes that will be an entity view. * Database schema will be created for all classes decorated with it, and Repository can be retrieved and used for it. */ -export function ViewEntity(options?: ViewEntityOptions): Function; +export function ViewEntity(options?: ViewEntityOptions): ClassDecorator; /** * This decorator is used to mark classes that will be an entity view. * Database schema will be created for all classes decorated with it, and Repository can be retrieved and used for it. */ -export function ViewEntity(name?: string, options?: ViewEntityOptions): Function; +export function ViewEntity(name?: string, options?: ViewEntityOptions): ClassDecorator; /** * This decorator is used to mark classes that will be an entity view. * Database schema will be created for all classes decorated with it, and Repository can be retrieved and used for it. */ -export function ViewEntity(nameOrOptions?: string|ViewEntityOptions, maybeOptions?: ViewEntityOptions): Function { +export function ViewEntity(nameOrOptions?: string|ViewEntityOptions, maybeOptions?: ViewEntityOptions): ClassDecorator { const options = (typeof nameOrOptions === "object" ? nameOrOptions as ViewEntityOptions : maybeOptions) || {}; const name = typeof nameOrOptions === "string" ? nameOrOptions : options.name; diff --git a/src/decorator/entity/ChildEntity.ts b/src/decorator/entity/ChildEntity.ts index 644b7d5babb..aee1b9746a4 100644 --- a/src/decorator/entity/ChildEntity.ts +++ b/src/decorator/entity/ChildEntity.ts @@ -5,7 +5,7 @@ import {DiscriminatorValueMetadataArgs} from "../../metadata-args/DiscriminatorV /** * Special type of the table used in the single-table inherited tables. */ -export function ChildEntity(discriminatorValue?: any) { +export function ChildEntity(discriminatorValue?: any): ClassDecorator { return function (target: Function) { // register a table metadata diff --git a/src/decorator/entity/TableInheritance.ts b/src/decorator/entity/TableInheritance.ts index 264743713e5..f716b5c227b 100644 --- a/src/decorator/entity/TableInheritance.ts +++ b/src/decorator/entity/TableInheritance.ts @@ -4,7 +4,7 @@ import {InheritanceMetadataArgs} from "../../metadata-args/InheritanceMetadataAr /** * Sets for entity to use table inheritance pattern. */ -export function TableInheritance(options?: { pattern?: "STI"/*|"CTI"*/, column?: string|ColumnOptions }) { +export function TableInheritance(options?: { pattern?: "STI"/*|"CTI"*/, column?: string|ColumnOptions }): ClassDecorator { return function (target: Function) { getMetadataArgsStorage().inheritances.push({ diff --git a/src/decorator/listeners/AfterInsert.ts b/src/decorator/listeners/AfterInsert.ts index 68c2c1a11c2..48be17d67d1 100644 --- a/src/decorator/listeners/AfterInsert.ts +++ b/src/decorator/listeners/AfterInsert.ts @@ -5,7 +5,7 @@ import {EntityListenerMetadataArgs} from "../../metadata-args/EntityListenerMeta /** * Calls a method on which this decorator is applied after this entity insertion. */ -export function AfterInsert() { +export function AfterInsert(): PropertyDecorator { return function (object: Object, propertyName: string) { getMetadataArgsStorage().entityListeners.push({ diff --git a/src/decorator/listeners/AfterLoad.ts b/src/decorator/listeners/AfterLoad.ts index 8b810feed79..02e2fe81c67 100644 --- a/src/decorator/listeners/AfterLoad.ts +++ b/src/decorator/listeners/AfterLoad.ts @@ -5,7 +5,7 @@ import {EntityListenerMetadataArgs} from "../../metadata-args/EntityListenerMeta /** * Calls a method on which this decorator is applied after entity is loaded. */ -export function AfterLoad() { +export function AfterLoad(): PropertyDecorator { return function (object: Object, propertyName: string) { getMetadataArgsStorage().entityListeners.push({ diff --git a/src/decorator/listeners/AfterRemove.ts b/src/decorator/listeners/AfterRemove.ts index e9e7d2549cd..a2f00f63f4d 100644 --- a/src/decorator/listeners/AfterRemove.ts +++ b/src/decorator/listeners/AfterRemove.ts @@ -5,7 +5,7 @@ import {EntityListenerMetadataArgs} from "../../metadata-args/EntityListenerMeta /** * Calls a method on which this decorator is applied after this entity removal. */ -export function AfterRemove() { +export function AfterRemove(): PropertyDecorator { return function (object: Object, propertyName: string) { getMetadataArgsStorage().entityListeners.push({ diff --git a/src/decorator/listeners/AfterUpdate.ts b/src/decorator/listeners/AfterUpdate.ts index fadb31815f6..f77241e0954 100644 --- a/src/decorator/listeners/AfterUpdate.ts +++ b/src/decorator/listeners/AfterUpdate.ts @@ -5,7 +5,7 @@ import {EntityListenerMetadataArgs} from "../../metadata-args/EntityListenerMeta /** * Calls a method on which this decorator is applied after this entity update. */ -export function AfterUpdate() { +export function AfterUpdate(): PropertyDecorator { return function (object: Object, propertyName: string) { getMetadataArgsStorage().entityListeners.push({ diff --git a/src/decorator/listeners/BeforeInsert.ts b/src/decorator/listeners/BeforeInsert.ts index 10db63ad141..6f2d4c7d98a 100644 --- a/src/decorator/listeners/BeforeInsert.ts +++ b/src/decorator/listeners/BeforeInsert.ts @@ -5,7 +5,7 @@ import {EntityListenerMetadataArgs} from "../../metadata-args/EntityListenerMeta /** * Calls a method on which this decorator is applied before this entity insertion. */ -export function BeforeInsert() { +export function BeforeInsert(): PropertyDecorator { return function (object: Object, propertyName: string) { getMetadataArgsStorage().entityListeners.push({ diff --git a/src/decorator/listeners/BeforeRemove.ts b/src/decorator/listeners/BeforeRemove.ts index e108e2e9f66..0fcadd1fa4e 100644 --- a/src/decorator/listeners/BeforeRemove.ts +++ b/src/decorator/listeners/BeforeRemove.ts @@ -5,7 +5,7 @@ import {EntityListenerMetadataArgs} from "../../metadata-args/EntityListenerMeta /** * Calls a method on which this decorator is applied before this entity removal. */ -export function BeforeRemove() { +export function BeforeRemove(): PropertyDecorator { return function (object: Object, propertyName: string) { getMetadataArgsStorage().entityListeners.push({ diff --git a/src/decorator/listeners/BeforeUpdate.ts b/src/decorator/listeners/BeforeUpdate.ts index 753e3a15328..d4a15d36d2e 100644 --- a/src/decorator/listeners/BeforeUpdate.ts +++ b/src/decorator/listeners/BeforeUpdate.ts @@ -5,7 +5,7 @@ import {EntityListenerMetadataArgs} from "../../metadata-args/EntityListenerMeta /** * Calls a method on which this decorator is applied before this entity update. */ -export function BeforeUpdate() { +export function BeforeUpdate(): PropertyDecorator { return function (object: Object, propertyName: string) { getMetadataArgsStorage().entityListeners.push({ diff --git a/src/decorator/listeners/EventSubscriber.ts b/src/decorator/listeners/EventSubscriber.ts index 99741d0b9ad..ea13dc44a8a 100644 --- a/src/decorator/listeners/EventSubscriber.ts +++ b/src/decorator/listeners/EventSubscriber.ts @@ -5,7 +5,7 @@ import {EntitySubscriberMetadataArgs} from "../../metadata-args/EntitySubscriber * Classes decorated with this decorator will listen to ORM events and their methods will be triggered when event * occurs. Those classes must implement EventSubscriberInterface interface. */ -export function EventSubscriber() { +export function EventSubscriber(): ClassDecorator { return function (target: Function) { getMetadataArgsStorage().entitySubscribers.push({ diff --git a/src/decorator/relations/JoinColumn.ts b/src/decorator/relations/JoinColumn.ts index 3bded3a0800..f619e374ad4 100644 --- a/src/decorator/relations/JoinColumn.ts +++ b/src/decorator/relations/JoinColumn.ts @@ -6,28 +6,28 @@ import {JoinColumnMetadataArgs} from "../../metadata-args/JoinColumnMetadataArgs * It also can be used on both one-to-one and many-to-one relations to specify custom column name * or custom referenced column. */ -export function JoinColumn(): Function; +export function JoinColumn(): PropertyDecorator; /** * JoinColumn decorator used on one-to-one relations to specify owner side of relationship. * It also can be used on both one-to-one and many-to-one relations to specify custom column name * or custom referenced column. */ -export function JoinColumn(options: JoinColumnOptions): Function; +export function JoinColumn(options: JoinColumnOptions): PropertyDecorator; /** * JoinColumn decorator used on one-to-one relations to specify owner side of relationship. * It also can be used on both one-to-one and many-to-one relations to specify custom column name * or custom referenced column. */ -export function JoinColumn(options: JoinColumnOptions[]): Function; +export function JoinColumn(options: JoinColumnOptions[]): PropertyDecorator; /** * JoinColumn decorator used on one-to-one relations to specify owner side of relationship. * It also can be used on both one-to-one and many-to-one relations to specify custom column name * or custom referenced column. */ -export function JoinColumn(optionsOrOptionsArray?: JoinColumnOptions|JoinColumnOptions[]): Function { +export function JoinColumn(optionsOrOptionsArray?: JoinColumnOptions|JoinColumnOptions[]): PropertyDecorator { return function (object: Object, propertyName: string) { const options = Array.isArray(optionsOrOptionsArray) ? optionsOrOptionsArray : [optionsOrOptionsArray || {}]; options.forEach(options => { diff --git a/src/decorator/relations/JoinTable.ts b/src/decorator/relations/JoinTable.ts index ed7ddab587f..c9d95b09095 100644 --- a/src/decorator/relations/JoinTable.ts +++ b/src/decorator/relations/JoinTable.ts @@ -6,25 +6,25 @@ import {JoinTableMultipleColumnsOptions} from "../options/JoinTableMultipleColum * JoinTable decorator is used in many-to-many relationship to specify owner side of relationship. * Its also used to set a custom junction table's name, column names and referenced columns. */ -export function JoinTable(): Function; +export function JoinTable(): PropertyDecorator; /** * JoinTable decorator is used in many-to-many relationship to specify owner side of relationship. * Its also used to set a custom junction table's name, column names and referenced columns. */ -export function JoinTable(options: JoinTableOptions): Function; +export function JoinTable(options: JoinTableOptions): PropertyDecorator; /** * JoinTable decorator is used in many-to-many relationship to specify owner side of relationship. * Its also used to set a custom junction table's name, column names and referenced columns. */ -export function JoinTable(options: JoinTableMultipleColumnsOptions): Function; +export function JoinTable(options: JoinTableMultipleColumnsOptions): PropertyDecorator; /** * JoinTable decorator is used in many-to-many relationship to specify owner side of relationship. * Its also used to set a custom junction table's name, column names and referenced columns. */ -export function JoinTable(options?: JoinTableOptions|JoinTableMultipleColumnsOptions): Function { +export function JoinTable(options?: JoinTableOptions|JoinTableMultipleColumnsOptions): PropertyDecorator { return function (object: Object, propertyName: string) { options = options || {} as JoinTableOptions|JoinTableMultipleColumnsOptions; getMetadataArgsStorage().joinTables.push({ diff --git a/src/decorator/relations/ManyToMany.ts b/src/decorator/relations/ManyToMany.ts index f287b434f59..e07a124f04a 100644 --- a/src/decorator/relations/ManyToMany.ts +++ b/src/decorator/relations/ManyToMany.ts @@ -7,7 +7,7 @@ import {RelationMetadataArgs} from "../../metadata-args/RelationMetadataArgs"; * entity1 and entity2 ids. This is owner side of the relationship. */ export function ManyToMany(typeFunctionOrTarget: string|((type?: any) => ObjectType), - options?: RelationOptions): Function; + options?: RelationOptions): PropertyDecorator; /** * Many-to-many is a type of relationship when Entity1 can have multiple instances of Entity2, and Entity2 can have @@ -16,7 +16,7 @@ export function ManyToMany(typeFunctionOrTarget: string|((type?: any) => Obje */ export function ManyToMany(typeFunctionOrTarget: string|((type?: any) => ObjectType), inverseSide?: string|((object: T) => any), - options?: RelationOptions): Function; + options?: RelationOptions): PropertyDecorator; /** * Many-to-many is a type of relationship when Entity1 can have multiple instances of Entity2, and Entity2 can have @@ -25,7 +25,7 @@ export function ManyToMany(typeFunctionOrTarget: string|((type?: any) => Obje */ export function ManyToMany(typeFunctionOrTarget: string|((type?: any) => ObjectType), inverseSideOrOptions?: string|((object: T) => any)|RelationOptions, - options?: RelationOptions): Function { + options?: RelationOptions): PropertyDecorator { // normalize parameters let inverseSideProperty: string|((object: T) => any); diff --git a/src/decorator/relations/ManyToOne.ts b/src/decorator/relations/ManyToOne.ts index 7c0031e6c09..0c60ba0bf6a 100644 --- a/src/decorator/relations/ManyToOne.ts +++ b/src/decorator/relations/ManyToOne.ts @@ -6,7 +6,7 @@ import {RelationMetadataArgs} from "../../metadata-args/RelationMetadataArgs"; * Entity2 can have a multiple instances of Entity1. Entity1 is an owner of the relationship, and storages Entity2 id * on its own side. */ -export function ManyToOne(typeFunctionOrTarget: string|((type?: any) => ObjectType), options?: RelationOptions): Function; +export function ManyToOne(typeFunctionOrTarget: string|((type?: any) => ObjectType), options?: RelationOptions): PropertyDecorator; /** * Many-to-one relation allows to create type of relation when Entity1 can have single instance of Entity2, but @@ -15,7 +15,7 @@ export function ManyToOne(typeFunctionOrTarget: string|((type?: any) => Objec */ export function ManyToOne(typeFunctionOrTarget: string|((type?: any) => ObjectType), inverseSide?: string|((object: T) => any), - options?: RelationOptions): Function; + options?: RelationOptions): PropertyDecorator; /** * Many-to-one relation allows to create type of relation when Entity1 can have single instance of Entity2, but @@ -24,7 +24,7 @@ export function ManyToOne(typeFunctionOrTarget: string|((type?: any) => Objec */ export function ManyToOne(typeFunctionOrTarget: string|((type?: any) => ObjectType), inverseSideOrOptions?: string|((object: T) => any)|RelationOptions, - options?: RelationOptions): Function { + options?: RelationOptions): PropertyDecorator { // normalize parameters let inverseSideProperty: string|((object: T) => any); diff --git a/src/decorator/relations/OneToMany.ts b/src/decorator/relations/OneToMany.ts index 80e1f7175cf..802c754e263 100644 --- a/src/decorator/relations/OneToMany.ts +++ b/src/decorator/relations/OneToMany.ts @@ -5,7 +5,7 @@ import {RelationMetadataArgs} from "../../metadata-args/RelationMetadataArgs"; * One-to-many relation allows to create type of relation when Entity2 can have multiple instances of Entity1. * Entity1 have only one Entity2. Entity1 is an owner of the relationship, and storages Entity2 id on its own side. */ -export function OneToMany(typeFunctionOrTarget: string|((type?: any) => ObjectType), inverseSide: string|((object: T) => any), options?: RelationOptions): Function { +export function OneToMany(typeFunctionOrTarget: string|((type?: any) => ObjectType), inverseSide: string|((object: T) => any), options?: RelationOptions): PropertyDecorator { return function (object: Object, propertyName: string) { if (!options) options = {} as RelationOptions; diff --git a/src/decorator/relations/OneToOne.ts b/src/decorator/relations/OneToOne.ts index 85f196b2270..e1d8c04982d 100644 --- a/src/decorator/relations/OneToOne.ts +++ b/src/decorator/relations/OneToOne.ts @@ -6,7 +6,7 @@ import {RelationMetadataArgs} from "../../metadata-args/RelationMetadataArgs"; * Entity1 is an owner of the relationship, and storages Entity1 id on its own side. */ export function OneToOne(typeFunctionOrTarget: string|((type?: any) => ObjectType), - options?: RelationOptions): Function; + options?: RelationOptions): PropertyDecorator; /** * One-to-one relation allows to create direct relation between two entities. Entity1 have only one Entity2. @@ -14,7 +14,7 @@ export function OneToOne(typeFunctionOrTarget: string|((type?: any) => Object */ export function OneToOne(typeFunctionOrTarget: string|((type?: any) => ObjectType), inverseSide?: string|((object: T) => any), - options?: RelationOptions): Function; + options?: RelationOptions): PropertyDecorator; /** * One-to-one relation allows to create direct relation between two entities. Entity1 have only one Entity2. @@ -22,7 +22,7 @@ export function OneToOne(typeFunctionOrTarget: string|((type?: any) => Object */ export function OneToOne(typeFunctionOrTarget: string|((type?: any) => ObjectType), inverseSideOrOptions?: string|((object: T) => any)|RelationOptions, - options?: RelationOptions): Function { + options?: RelationOptions): PropertyDecorator { // normalize parameters let inverseSideProperty: string|((object: T) => any); diff --git a/src/decorator/relations/RelationCount.ts b/src/decorator/relations/RelationCount.ts index abfb76c2e46..9670c5c8953 100644 --- a/src/decorator/relations/RelationCount.ts +++ b/src/decorator/relations/RelationCount.ts @@ -6,7 +6,7 @@ import {RelationCountMetadataArgs} from "../../metadata-args/RelationCountMetada * * @deprecated Do not use this decorator, it may be removed in the future versions */ -export function RelationCount(relation: string|((object: T) => any), alias?: string, queryBuilderFactory?: (qb: SelectQueryBuilder) => SelectQueryBuilder): Function { +export function RelationCount(relation: string|((object: T) => any), alias?: string, queryBuilderFactory?: (qb: SelectQueryBuilder) => SelectQueryBuilder): PropertyDecorator { return function (object: Object, propertyName: string) { getMetadataArgsStorage().relationCounts.push({ diff --git a/src/decorator/relations/RelationId.ts b/src/decorator/relations/RelationId.ts index c7880e17a69..78855aeb4f0 100644 --- a/src/decorator/relations/RelationId.ts +++ b/src/decorator/relations/RelationId.ts @@ -6,7 +6,7 @@ import {RelationIdMetadataArgs} from "../../metadata-args/RelationIdMetadataArgs * * @experimental */ -export function RelationId(relation: string|((object: T) => any), alias?: string, queryBuilderFactory?: (qb: SelectQueryBuilder) => SelectQueryBuilder): Function { +export function RelationId(relation: string|((object: T) => any), alias?: string, queryBuilderFactory?: (qb: SelectQueryBuilder) => SelectQueryBuilder): PropertyDecorator { return function (object: Object, propertyName: string) { getMetadataArgsStorage().relationIds.push({ diff --git a/src/decorator/transaction/TransactionManager.ts b/src/decorator/transaction/TransactionManager.ts index 31addbcc769..083dd8d42d8 100644 --- a/src/decorator/transaction/TransactionManager.ts +++ b/src/decorator/transaction/TransactionManager.ts @@ -4,7 +4,7 @@ import {TransactionEntityMetadataArgs} from "../../metadata-args/TransactionEnti /** * Injects transaction's entity manager into the method wrapped with @Transaction decorator. */ -export function TransactionManager(): Function { +export function TransactionManager(): ParameterDecorator { return function (object: Object, methodName: string, index: number) { getMetadataArgsStorage().transactionEntityManagers.push({ diff --git a/src/decorator/tree/Tree.ts b/src/decorator/tree/Tree.ts index e93ab0be9cb..79da2fc96b2 100644 --- a/src/decorator/tree/Tree.ts +++ b/src/decorator/tree/Tree.ts @@ -8,7 +8,7 @@ import {TreeType} from "../../metadata/types/TreeTypes"; * @TreeParent decorator must be used in tree entities. * TreeRepository can be used to manipulate with tree entities. */ -export function Tree(type: TreeType): Function { +export function Tree(type: TreeType): ClassDecorator { return function (target: Function) { getMetadataArgsStorage().trees.push({ diff --git a/src/decorator/tree/TreeChildren.ts b/src/decorator/tree/TreeChildren.ts index 70de9e59956..2ef0935e0a2 100644 --- a/src/decorator/tree/TreeChildren.ts +++ b/src/decorator/tree/TreeChildren.ts @@ -5,7 +5,7 @@ import {RelationMetadataArgs} from "../../metadata-args/RelationMetadataArgs"; * Marks a entity property as a children of the tree. * "Tree children" will contain all children (bind) of this entity. */ -export function TreeChildren(options?: { cascade?: boolean|("insert"|"update"|"remove"|"soft-remove"|"recover")[] }): Function { +export function TreeChildren(options?: { cascade?: boolean|("insert"|"update"|"remove"|"soft-remove"|"recover")[] }): PropertyDecorator { return function (object: Object, propertyName: string) { if (!options) options = {} as RelationOptions; diff --git a/src/decorator/tree/TreeLevelColumn.ts b/src/decorator/tree/TreeLevelColumn.ts index f34a4173edd..24d9b5f2b16 100644 --- a/src/decorator/tree/TreeLevelColumn.ts +++ b/src/decorator/tree/TreeLevelColumn.ts @@ -4,7 +4,7 @@ import {ColumnMetadataArgs} from "../../metadata-args/ColumnMetadataArgs"; /** * Creates a "level"/"length" column to the table that holds a closure table. */ -export function TreeLevelColumn(): Function { +export function TreeLevelColumn(): PropertyDecorator { return function (object: Object, propertyName: string) { getMetadataArgsStorage().columns.push({ diff --git a/src/decorator/tree/TreeParent.ts b/src/decorator/tree/TreeParent.ts index 4b0d38b9ef8..931b78206e1 100644 --- a/src/decorator/tree/TreeParent.ts +++ b/src/decorator/tree/TreeParent.ts @@ -5,7 +5,7 @@ import {RelationMetadataArgs} from "../../metadata-args/RelationMetadataArgs"; * Marks a entity property as a parent of the tree. * "Tree parent" indicates who owns (is a parent) of this entity in tree structure. */ -export function TreeParent(): Function { +export function TreeParent(): PropertyDecorator { return function (object: Object, propertyName: string) { // now try to determine it its lazy relation From 911ac9361f25c390d0917ceff986f3575d58506a Mon Sep 17 00:00:00 2001 From: 0xflotus <0xflotus@gmail.com> Date: Fri, 17 Jul 2020 22:27:21 +0200 Subject: [PATCH 006/212] docs: fixed small typo error (#6418) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 71e8420f6d7..380eb853def 100644 --- a/README.md +++ b/README.md @@ -1035,7 +1035,7 @@ createConnection(options).then(async connection => { metadata.width = 480; metadata.compressed = true; metadata.comment = "cybershoot"; - metadata.orientation = "portait"; + metadata.orientation = "portrait"; photo.metadata = metadata; // this way we connect them From c6336aa4c3bbdc4c7907db605c5bd497c0eb42a3 Mon Sep 17 00:00:00 2001 From: "Saulo S. Toledo" Date: Fri, 17 Jul 2020 17:56:21 -0300 Subject: [PATCH 007/212] fix: exporting missing load event (#6396) --- src/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/index.ts b/src/index.ts index 1acbfe541c2..749d53390cc 100644 --- a/src/index.ts +++ b/src/index.ts @@ -151,6 +151,7 @@ export {MongoRepository} from "./repository/MongoRepository"; export {FindOneOptions} from "./find-options/FindOneOptions"; export {FindManyOptions} from "./find-options/FindManyOptions"; export {InsertEvent} from "./subscriber/event/InsertEvent"; +export {LoadEvent} from "./subscriber/event/LoadEvent"; export {UpdateEvent} from "./subscriber/event/UpdateEvent"; export {RemoveEvent} from "./subscriber/event/RemoveEvent"; export {EntitySubscriberInterface} from "./subscriber/EntitySubscriberInterface"; From 298a3b9c8b8cb793b4ceb7f101c8f6d8c7239a7c Mon Sep 17 00:00:00 2001 From: James Ward Date: Fri, 17 Jul 2020 17:13:49 -0400 Subject: [PATCH 008/212] fix: support multiple `JoinColumn`s in EntitySchema (#6397) update type definition and schema transformer so that - like the decorator - the EntitySchema can define composite `JoinColumn` definitions Closes: #5444 --- .../EntitySchemaRelationOptions.ts | 2 +- src/entity-schema/EntitySchemaTransformer.ts | 18 ++++--- test/github-issues/5444/entity/Author.ts | 41 ++++++++++++++ test/github-issues/5444/entity/Post.ts | 53 +++++++++++++++++++ test/github-issues/5444/issue-5444.ts | 40 ++++++++++++++ 5 files changed, 146 insertions(+), 8 deletions(-) create mode 100644 test/github-issues/5444/entity/Author.ts create mode 100644 test/github-issues/5444/entity/Post.ts create mode 100644 test/github-issues/5444/issue-5444.ts diff --git a/src/entity-schema/EntitySchemaRelationOptions.ts b/src/entity-schema/EntitySchemaRelationOptions.ts index 953caaccd6e..0502fc67e66 100644 --- a/src/entity-schema/EntitySchemaRelationOptions.ts +++ b/src/entity-schema/EntitySchemaRelationOptions.ts @@ -55,7 +55,7 @@ export interface EntitySchemaRelationOptions { /** * Join column options of this column. If set to true then it simply means that it has a join column. */ - joinColumn?: boolean|JoinColumnOptions; + joinColumn?: boolean|JoinColumnOptions|JoinColumnOptions[]; /** * Indicates if this is a parent (can be only many-to-one relation) relation in the tree tables. diff --git a/src/entity-schema/EntitySchemaTransformer.ts b/src/entity-schema/EntitySchemaTransformer.ts index 81808816139..e53eb2c981b 100644 --- a/src/entity-schema/EntitySchemaTransformer.ts +++ b/src/entity-schema/EntitySchemaTransformer.ts @@ -151,13 +151,17 @@ export class EntitySchemaTransformer { }; metadataArgsStorage.joinColumns.push(joinColumn); } else { - const joinColumn: JoinColumnMetadataArgs = { - target: options.target || options.name, - propertyName: relationName, - name: relationSchema.joinColumn.name, - referencedColumnName: relationSchema.joinColumn.referencedColumnName - }; - metadataArgsStorage.joinColumns.push(joinColumn); + const joinColumnsOptions = Array.isArray(relationSchema.joinColumn) ? relationSchema.joinColumn : [relationSchema.joinColumn]; + + for (const joinColumnOption of joinColumnsOptions) { + const joinColumn: JoinColumnMetadataArgs = { + target: options.target || options.name, + propertyName: relationName, + name: joinColumnOption.name, + referencedColumnName: joinColumnOption.referencedColumnName + }; + metadataArgsStorage.joinColumns.push(joinColumn); + } } } diff --git a/test/github-issues/5444/entity/Author.ts b/test/github-issues/5444/entity/Author.ts new file mode 100644 index 00000000000..20191b21c57 --- /dev/null +++ b/test/github-issues/5444/entity/Author.ts @@ -0,0 +1,41 @@ +import {EntitySchemaOptions} from "../../../../src/entity-schema/EntitySchemaOptions"; +import {Post} from "./Post"; + +export class Author { + id: number; + + publisherId: number; + + name: string; + + posts: Post[]; +} + +export const AuthorSchema: EntitySchemaOptions = { + name: "Author", + + target: Author, + + columns: { + id: { + primary: true, + type: Number + }, + + publisherId: { + primary: true, + type: Number + }, + + name: { + type: "varchar" + } + }, + + relations: { + posts: { + target: () => Post, + type: "one-to-many" + } + } +}; diff --git a/test/github-issues/5444/entity/Post.ts b/test/github-issues/5444/entity/Post.ts new file mode 100644 index 00000000000..eb5239960c7 --- /dev/null +++ b/test/github-issues/5444/entity/Post.ts @@ -0,0 +1,53 @@ +import {EntitySchemaOptions} from "../../../../src/entity-schema/EntitySchemaOptions"; +import {Author} from "./Author"; + +export class Post { + authorPublisherId: number; + + authorId: number; + + id: number; + + title: string; + + author: Author; +} + +export const PostSchema: EntitySchemaOptions = { + name: "Post", + + target: Post, + + columns: { + authorPublisherId: { + primary: true, + type: Number + }, + + authorId: { + primary: true, + type: Number + }, + + id: { + primary: true, + type: Number + }, + + title: { + type: "varchar" + } + }, + + relations: { + author: { + target: () => Author, + type: "many-to-one", + eager: true, + joinColumn: [ + { name: "authorPublisherId", referencedColumnName: "publisherId" }, + { name: "authorId", referencedColumnName: "id" }, + ] + } + } +}; diff --git a/test/github-issues/5444/issue-5444.ts b/test/github-issues/5444/issue-5444.ts new file mode 100644 index 00000000000..b25f47cd8d7 --- /dev/null +++ b/test/github-issues/5444/issue-5444.ts @@ -0,0 +1,40 @@ +import { EntitySchemaTransformer } from "../../../src/entity-schema/EntitySchemaTransformer"; + +import {expect} from "chai"; + +import { Post, PostSchema } from "./entity/Post"; +import { Author, AuthorSchema } from "./entity/Author"; +import {EntitySchema} from "../../../src"; + + +describe("github issues > #5444 EntitySchema missing support for multiple joinColumns in relations", () => { + it("Update query returns the number of affected rows", async () => { + const transformer = new EntitySchemaTransformer(); + + const actual = transformer.transform( + [ + new EntitySchema(AuthorSchema), + new EntitySchema(PostSchema) + ] + ); + + const joinColumns = actual.joinColumns; + + expect(joinColumns.length).to.eq(2); + expect(joinColumns).to.deep.eq([ + { + target: Post, + propertyName: "author", + name: "authorPublisherId", + referencedColumnName: "publisherId" + }, + { + target: Post, + propertyName: "author", + name: "authorId", + referencedColumnName: "id" + }, + + ]); + }); +}); From 54a3a15c4c1afc9a2cc42103d4498847f67820f9 Mon Sep 17 00:00:00 2001 From: Coroliov Oleg <1880059+ruscon@users.noreply.github.com> Date: Sat, 18 Jul 2020 00:17:39 +0300 Subject: [PATCH 009/212] fix: correctly parse connection URI with query params (#6390) ref #6389 Co-authored-by: Coroliov Oleg --- src/driver/DriverUtils.ts | 8 ++++++-- test/github-issues/6389/issue-6389.ts | 26 ++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) create mode 100644 test/github-issues/6389/issue-6389.ts diff --git a/src/driver/DriverUtils.ts b/src/driver/DriverUtils.ts index b7e00b6c2ae..c022e3c8453 100644 --- a/src/driver/DriverUtils.ts +++ b/src/driver/DriverUtils.ts @@ -35,7 +35,7 @@ export class DriverUtils { /** * Builds column alias from given alias name and column name. - * + * * If alias length is greater than the limit (if any) allowed by the current * driver, replaces it with a hashed string. * @@ -68,7 +68,11 @@ export class DriverUtils { const preBase = url.substr(firstSlashes + 2); const secondSlash = preBase.indexOf("/"); const base = (secondSlash !== -1) ? preBase.substr(0, secondSlash) : preBase; - const afterBase = (secondSlash !== -1) ? preBase.substr(secondSlash + 1) : undefined; + let afterBase = (secondSlash !== -1) ? preBase.substr(secondSlash + 1) : undefined; + // remove mongodb query params + if (afterBase && afterBase.indexOf("?") !== -1) { + afterBase = afterBase.substr(0, afterBase.indexOf("?")); + } const lastAtSign = base.lastIndexOf("@"); const usernameAndPassword = base.substr(0, lastAtSign); diff --git a/test/github-issues/6389/issue-6389.ts b/test/github-issues/6389/issue-6389.ts new file mode 100644 index 00000000000..a12e9adab16 --- /dev/null +++ b/test/github-issues/6389/issue-6389.ts @@ -0,0 +1,26 @@ +import { DriverUtils } from "../../../src/driver/DriverUtils"; +import { expect } from "chai"; + +describe("github issues > #6389 MongoDB URI Connection string with query params", () => { + it("should parse correctly mongodb URI", () => { + const obj: any = { + type: "mongodb", + username: "user", + password: "password", + host: "host", + database: "database", + port: 27017, + }; + + const url = `${obj.type}://${obj.username}:${obj.password}@${obj.host}:${obj.port}/${obj.database}?readPreference=primary`; + const options = DriverUtils.buildDriverOptions({url}); + + expect(options.type).to.eql(obj.type); + expect(options.username).to.eql(obj.username); + expect(options.username).to.eql(obj.username); + expect(options.password).to.eql(obj.password); + expect(options.host).to.eql(obj.host); + expect(options.port).to.eql(obj.port); + expect(options.database).to.eql(obj.database); + }); +}); From 7c0da1cbe5a5d4bb0aea0321cea6df7bfad9ef75 Mon Sep 17 00:00:00 2001 From: Akos Vandra Date: Sat, 18 Jul 2020 01:18:56 +0200 Subject: [PATCH 010/212] fix: getPendingMigrations isn't properly working (#6372) getPendingMigrations currently returns the executed migrations instead of the non-executed ones. --- src/migration/MigrationExecutor.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/migration/MigrationExecutor.ts b/src/migration/MigrationExecutor.ts index 2cc380c8251..efec992f614 100644 --- a/src/migration/MigrationExecutor.ts +++ b/src/migration/MigrationExecutor.ts @@ -90,7 +90,7 @@ export class MigrationExecutor { const executedMigrations = await this.getExecutedMigrations(); return allMigrations.filter(migration => - executedMigrations.find( + !executedMigrations.find( executedMigration => executedMigration.name === migration.name ) From 22414510f9c4f69cb0e48b8c2fce1b4910353d6b Mon Sep 17 00:00:00 2001 From: K024 <2382146546@qq.com> Date: Sat, 18 Jul 2020 07:32:16 +0800 Subject: [PATCH 011/212] feat: add better-sqlite3 driver (#6224) * feat: better-sqlite3 driver which is significantly faster than node-sqlite3 * test: added all tests for sqlite to better-sqlite3 * test: "query runner > drop column" modified compatible * docs: added better-sqlite3 related docs --- docs/connection-options.md | 11 +- docs/zh_CN/connection-options.md | 11 +- ormconfig.circleci-cockroach.json | 6 + ormconfig.circleci-common.json | 6 + ormconfig.circleci-oracle.json | 6 + ormconfig.json.dist | 7 + ormconfig.travis.json | 7 + package-lock.json | 238 ++++++++++++++++++ package.json | 1 + src/commands/InitCommand.ts | 10 + src/connection/ConnectionOptions.ts | 4 +- src/connection/ConnectionOptionsReader.ts | 2 +- src/driver/DriverFactory.ts | 3 + .../BetterSqlite3ConnectionOptions.ts | 60 +++++ .../better-sqlite3/BetterSqlite3Driver.ts | 141 +++++++++++ .../BetterSqlite3QueryRunner.ts | 106 ++++++++ src/driver/types/DatabaseType.ts | 3 +- src/error/MissingDriverError.ts | 2 +- src/query-builder/DeleteQueryBuilder.ts | 5 + src/query-builder/UpdateQueryBuilder.ts | 5 + .../configs/sqlite-memory.ts | 4 + .../sqlite/column-collation-sqlite.ts | 2 +- .../sqlite/column-length-sqlite..ts | 2 +- .../sqlite/column-types-sqlite.ts | 2 +- .../database-schema/simple-enums/enums.ts | 2 +- .../conditional-index/conditional-index.ts | 2 +- .../delete/query-builder-delete.ts | 1 + .../query-builder-insert-on-conflict.ts | 2 +- test/functional/query-runner/create-table.ts | 5 +- .../query-runner/create-unique-constraint.ts | 2 +- test/functional/query-runner/drop-column.ts | 5 + .../query-runner/drop-unique-constraint.ts | 2 +- .../basic-lazy-relations.ts | 4 +- .../basic-methods/repository-basic-methods.ts | 5 +- .../find-options/repository-find-options.ts | 2 +- .../database-option-inherited.ts | 2 +- .../sqlite-isolation.ts | 2 +- .../return-data-from-transaction.ts | 2 +- .../transaction-in-entity-manager.ts | 2 +- test/functional/uuid/sqlite/uuid-sqlite.ts | 2 +- .../view-entity/sqlite/view-entity-sqlite.ts | 2 +- test/github-issues/134/issue-134.ts | 2 +- test/github-issues/1465/save-relation.ts | 2 +- test/github-issues/1476/issue-1476.ts | 2 +- test/github-issues/1898/issue-1898.ts | 2 +- test/github-issues/190/issue-190.ts | 2 +- test/github-issues/1981/issue-1981.ts | 2 +- test/github-issues/2005/issue-2005.ts | 2 +- test/github-issues/2199/issue-2199.ts | 2 +- test/github-issues/2518/issue-2518.ts | 2 +- test/github-issues/2733/issue-2733.ts | 2 +- test/github-issues/3158/issue-3158.ts | 2 +- test/github-issues/3949/issue-3949.ts | 2 +- test/github-issues/4096/issue-4096.ts | 2 +- test/github-issues/4147/issue-4147.ts | 2 +- test/github-issues/513/issue-513.ts | 2 +- test/github-issues/798/issue-798.ts | 7 + test/github-issues/799/issue-799.ts | 10 + 58 files changed, 691 insertions(+), 44 deletions(-) create mode 100644 src/driver/better-sqlite3/BetterSqlite3ConnectionOptions.ts create mode 100644 src/driver/better-sqlite3/BetterSqlite3Driver.ts create mode 100644 src/driver/better-sqlite3/BetterSqlite3QueryRunner.ts diff --git a/docs/connection-options.md b/docs/connection-options.md index cd9915732f4..d52a64bc810 100644 --- a/docs/connection-options.md +++ b/docs/connection-options.md @@ -5,6 +5,7 @@ * [`mysql` / `mariadb` connection options](#mysql--mariadb-connection-options) * [`postgres` / `cockroachdb` connection options](#postgres--cockroachdb-connection-options) * [`sqlite` connection options](#sqlite-connection-options) +* [`better-sqlite3` connection options](#better-sqlite3-connection-options) * [`cordova` connection options](#cordova-connection-options) * [`react-native` connection options](#react-native-connection-options) * [`nativescript` connection options](#nativescript-connection-options) @@ -22,7 +23,7 @@ Connection options is a connection configuration you pass to `createConnection` ## Common connection options * `type` - Database type. You must specify what database engine you use. - Possible values are "mysql", "postgres", "cockroachdb", "mariadb", "sqlite", "cordova", "nativescript", + Possible values are "mysql", "postgres", "cockroachdb", "mariadb", "sqlite", "better-sqlite3", "cordova", "nativescript", "oracle", "mssql", "mongodb", "sqljs", "react-native". This option is **required**. @@ -185,6 +186,14 @@ See [SSL options](https://github.com/mysqljs/mysql#ssl-options). * `database` - Database path. For example "./mydb.sql" +## `better-sqlite3` connection options + +* `database` - Database path. For example "./mydb.sql" + +* `statementCacheSize` - Cache size of sqlite statement to speed up queries (default 100). + +* `prepareDatabase` - Function to run before a database is used in typeorm. You can access original better-sqlite3 Database object here. + ## `cordova` connection options * `database` - Database name diff --git a/docs/zh_CN/connection-options.md b/docs/zh_CN/connection-options.md index 3966d6c8e82..5523bc6afb6 100644 --- a/docs/zh_CN/connection-options.md +++ b/docs/zh_CN/connection-options.md @@ -5,6 +5,7 @@ - [`mysql`/`mariadb`](#mysql/mariadb) - [`postgres`/`cockroachdb`连接选项](#postgres/cockroachdb连接选项) - [`sqlite`](#sqlite) + - [`better-sqlite3`](#better-sqlite3) - [`cordova`](#cordova) - [`react-native`](#react-native) - [`nativescript`](#nativescript) @@ -20,7 +21,7 @@ ## 常用的连接选项 -- `type` - 数据库类型。你必须指定要使用的数据库引擎。该值可以是"mysql","postgres","mariadb","sqlite","cordova","nativescript","oracle","mssql","mongodb","sqljs","react-native"。此选项是**必需**的。 +- `type` - 数据库类型。你必须指定要使用的数据库引擎。该值可以是"mysql","postgres","mariadb","sqlite", "better-sqlite3","cordova","nativescript","oracle","mssql","mongodb","sqljs","react-native"。此选项是**必需**的。 - `name` - 连接名。 在使用 `getConnection(name: string)` 或 `ConnectionManager.get(name: string)`时候需要用到。不同连接的连接名称不能相同,它们都必须是唯一的。如果没有给出连接名称,那么它将被设置为"default"。 @@ -128,6 +129,14 @@ - `database` - 数据库路径。 例如 "./mydb.sql" +## `better-sqlite3` + +* `database` - 数据库路径。 例如 "./mydb.sql" + +* `statementCacheSize` - Sqlite 查询 Statement 缓存大小。默认100 + +* `prepareDatabase` - 在数据库投入使用前运行的函数。你可以在这里访问到better-sqlite3原始数据库对象。 + ## `cordova` - `database` - 数据库名 diff --git a/ormconfig.circleci-cockroach.json b/ormconfig.circleci-cockroach.json index b91014a7813..96049b3fbde 100644 --- a/ormconfig.circleci-cockroach.json +++ b/ormconfig.circleci-cockroach.json @@ -25,6 +25,12 @@ "type": "sqlite", "database": "temp/sqlitedb.db" }, + { + "skip": true, + "name": "better-sqlite3", + "type": "better-sqlite3", + "database": "temp/better-sqlite3db.db" + }, { "skip": true, "name": "postgres", diff --git a/ormconfig.circleci-common.json b/ormconfig.circleci-common.json index 286289f0f67..16a85b9e798 100644 --- a/ormconfig.circleci-common.json +++ b/ormconfig.circleci-common.json @@ -25,6 +25,12 @@ "type": "sqlite", "database": "temp/sqlitedb.db" }, + { + "skip": false, + "name": "better-sqlite3", + "type": "better-sqlite3", + "database": "temp/better-sqlite3db.db" + }, { "skip": false, "name": "postgres", diff --git a/ormconfig.circleci-oracle.json b/ormconfig.circleci-oracle.json index 83bc38febe7..aef977102f6 100644 --- a/ormconfig.circleci-oracle.json +++ b/ormconfig.circleci-oracle.json @@ -25,6 +25,12 @@ "type": "sqlite", "database": "temp/sqlitedb.db" }, + { + "skip": true, + "name": "better-sqlite3", + "type": "better-sqlite3", + "database": "temp/better-sqlite3db.db" + }, { "skip": true, "name": "postgres", diff --git a/ormconfig.json.dist b/ormconfig.json.dist index 4f456b7efee..f855baf460a 100644 --- a/ormconfig.json.dist +++ b/ormconfig.json.dist @@ -28,6 +28,13 @@ "database": "temp/sqlitedb.db", "logging": false }, + { + "skip": false, + "name": "better-sqlite3", + "type": "better-sqlite3", + "database": "temp/better-sqlite3db.db", + "logging": false + }, { "skip": false, "name": "postgres", diff --git a/ormconfig.travis.json b/ormconfig.travis.json index f6a76e4c9c0..ca9054416b0 100644 --- a/ormconfig.travis.json +++ b/ormconfig.travis.json @@ -25,6 +25,13 @@ "type": "sqlite", "database": "temp/sqlitedb.db" }, + { + "skip": false, + "name": "better-sqlite3", + "type": "better-sqlite3", + "database": "temp/better-sqlite3db.db", + "logging": false + }, { "skip": false, "name": "postgres", diff --git a/package-lock.json b/package-lock.json index 1cda64a9197..cd9bfb8a68f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -907,6 +907,17 @@ "tweetnacl": "^0.14.3" } }, + "better-sqlite3": { + "version": "7.0.1", + "resolved": "https://registry.npm.taobao.org/better-sqlite3/download/better-sqlite3-7.0.1.tgz", + "integrity": "sha1-fQhhMLQtfVydKEeJnFfuWe7Jy7M=", + "dev": true, + "requires": { + "bindings": "^1.5.0", + "prebuild-install": "^5.3.3", + "tar": "4.4.10" + } + }, "big-number": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/big-number/-/big-number-0.3.1.tgz", @@ -931,6 +942,15 @@ "integrity": "sha512-xVNN69YGDghOqCCtA6FI7avYrr02mTJjOgB0/f1VPD3pJC8QEvjTKWc4epDx8AqxxA75NI0QpVM2gPJXUbE4Tg==", "dev": true }, + "bindings": { + "version": "1.5.0", + "resolved": "https://registry.npm.taobao.org/bindings/download/bindings-1.5.0.tgz", + "integrity": "sha1-EDU8npRTNLwFEabZCzj7x8nFBN8=", + "dev": true, + "requires": { + "file-uri-to-path": "1.0.0" + } + }, "bl": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz", @@ -1931,6 +1951,15 @@ "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", "dev": true }, + "decompress-response": { + "version": "4.2.1", + "resolved": "https://registry.npm.taobao.org/decompress-response/download/decompress-response-4.2.1.tgz?cache=0&sync_timestamp=1589512178920&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdecompress-response%2Fdownload%2Fdecompress-response-4.2.1.tgz", + "integrity": "sha1-QUAjzHowLaJc4uyC0NUjjMr9iYY=", + "dev": true, + "requires": { + "mimic-response": "^2.0.0" + } + }, "dedent": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", @@ -2394,6 +2423,12 @@ } } }, + "expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npm.taobao.org/expand-template/download/expand-template-2.0.3.tgz", + "integrity": "sha1-bhSz/O4POmNA7LV9LokYaSBSpHw=", + "dev": true + }, "expand-tilde": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", @@ -2546,6 +2581,12 @@ "object-assign": "^4.1.0" } }, + "file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npm.taobao.org/file-uri-to-path/download/file-uri-to-path-1.0.0.tgz", + "integrity": "sha1-VTp7hEb/b2hDWcRF8eN6BdrMM90=", + "dev": true + }, "fill-range": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", @@ -2699,6 +2740,12 @@ "map-cache": "^0.2.2" } }, + "fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npm.taobao.org/fs-constants/download/fs-constants-1.0.0.tgz", + "integrity": "sha1-a+Dem+mYzhavivwkSXue6bfM2a0=", + "dev": true + }, "fs-minipass": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.5.tgz", @@ -3599,6 +3646,12 @@ "ini": "^1.3.2" } }, + "github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npm.taobao.org/github-from-package/download/github-from-package-0.0.0.tgz", + "integrity": "sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4=", + "dev": true + }, "glob": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", @@ -5752,6 +5805,12 @@ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==" }, + "mimic-response": { + "version": "2.1.0", + "resolved": "https://registry.npm.taobao.org/mimic-response/download/mimic-response-2.1.0.tgz", + "integrity": "sha1-0Tdj019hPQnsN+uzC6wEacDuj0M=", + "dev": true + }, "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", @@ -5829,6 +5888,12 @@ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.3.tgz", "integrity": "sha512-6uCP4Qc0sWsgMLy1EOqqS/3rjDHOEnsStVr/4vtAIK2Y5i2kA7lFFejYrpIyiN9w0pYf4ckeCYT9f1r1P9KX5g==" }, + "mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npm.taobao.org/mkdirp-classic/download/mkdirp-classic-0.5.3.tgz", + "integrity": "sha1-+hDJEVzG2IZb4iG6R+6b7XhgERM=", + "dev": true + }, "mocha": { "version": "6.1.4", "resolved": "https://registry.npmjs.org/mocha/-/mocha-6.1.4.tgz", @@ -6247,6 +6312,12 @@ "to-regex": "^3.0.1" } }, + "napi-build-utils": { + "version": "1.0.2", + "resolved": "https://registry.npm.taobao.org/napi-build-utils/download/napi-build-utils-1.0.2.tgz", + "integrity": "sha1-sf3cCyxG44Cgt6dvmE3UfEGhOAY=", + "dev": true + }, "native-duplexpair": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/native-duplexpair/-/native-duplexpair-1.0.0.tgz", @@ -6313,6 +6384,15 @@ } } }, + "node-abi": { + "version": "2.18.0", + "resolved": "https://registry.npm.taobao.org/node-abi/download/node-abi-2.18.0.tgz", + "integrity": "sha1-H1SGz9fTi9T1OS+kSkrU2aDf+/Q=", + "dev": true, + "requires": { + "semver": "^5.4.1" + } + }, "node-environment-flags": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.5.tgz", @@ -6376,6 +6456,12 @@ } } }, + "noop-logger": { + "version": "0.1.1", + "resolved": "https://registry.npm.taobao.org/noop-logger/download/noop-logger-0.1.1.tgz", + "integrity": "sha1-lKKxYzxPExdVMAfYlm/Q6EG2pMI=", + "dev": true + }, "nopt": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", @@ -7106,6 +7192,56 @@ "xtend": "^4.0.0" } }, + "prebuild-install": { + "version": "5.3.4", + "resolved": "https://registry.npm.taobao.org/prebuild-install/download/prebuild-install-5.3.4.tgz", + "integrity": "sha1-aYLRAIQmnTZMGFZVC30JDqMfopM=", + "dev": true, + "requires": { + "detect-libc": "^1.0.3", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.3", + "mkdirp": "^0.5.1", + "napi-build-utils": "^1.0.1", + "node-abi": "^2.7.0", + "noop-logger": "^0.1.1", + "npmlog": "^4.0.1", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^3.0.3", + "tar-fs": "^2.0.0", + "tunnel-agent": "^0.6.0", + "which-pm-runs": "^1.0.0" + }, + "dependencies": { + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npm.taobao.org/minimist/download/minimist-1.2.5.tgz", + "integrity": "sha1-Z9ZgFLZqaoqqDAg8X9WN9OTpdgI=", + "dev": true + }, + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npm.taobao.org/mkdirp/download/mkdirp-0.5.5.tgz?cache=0&sync_timestamp=1588819864223&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fmkdirp%2Fdownload%2Fmkdirp-0.5.5.tgz", + "integrity": "sha1-2Rzv1i0UNsoPQWIOJRKI1CAJne8=", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npm.taobao.org/pump/download/pump-3.0.0.tgz", + "integrity": "sha1-tKIRaBW94vTh6mAjVOjHVWUQemQ=", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + } + } + }, "prelude-ls": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", @@ -7717,6 +7853,23 @@ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" }, + "simple-concat": { + "version": "1.0.0", + "resolved": "https://registry.npm.taobao.org/simple-concat/download/simple-concat-1.0.0.tgz", + "integrity": "sha1-c0TLuLbib7J9ZrL8hvn21Zl1IcY=", + "dev": true + }, + "simple-get": { + "version": "3.1.0", + "resolved": "https://registry.npm.taobao.org/simple-get/download/simple-get-3.1.0.tgz", + "integrity": "sha1-tFvgYkNeUNFZVAtXYgLO7EC5xrM=", + "dev": true, + "requires": { + "decompress-response": "^4.2.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, "simple-git": { "version": "1.107.0", "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-1.107.0.tgz", @@ -8240,6 +8393,85 @@ } } }, + "tar-fs": { + "version": "2.1.0", + "resolved": "https://registry.npm.taobao.org/tar-fs/download/tar-fs-2.1.0.tgz", + "integrity": "sha1-0c3RIatGXuDrnM3i01BJ0/Pa8NU=", + "dev": true, + "requires": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.0.0" + }, + "dependencies": { + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npm.taobao.org/pump/download/pump-3.0.0.tgz", + "integrity": "sha1-tKIRaBW94vTh6mAjVOjHVWUQemQ=", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + } + } + }, + "tar-stream": { + "version": "2.1.2", + "resolved": "https://registry.npm.taobao.org/tar-stream/download/tar-stream-2.1.2.tgz", + "integrity": "sha1-bV7xp+V4OpX/cLabl0VaWWjcEyU=", + "dev": true, + "requires": { + "bl": "^4.0.1", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "dependencies": { + "bl": { + "version": "4.0.2", + "resolved": "https://registry.npm.taobao.org/bl/download/bl-4.0.2.tgz?cache=0&sync_timestamp=1584503592586&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fbl%2Fdownload%2Fbl-4.0.2.tgz", + "integrity": "sha1-UrcekIhRXQYG2d2cx6pI3B+Y5zo=", + "dev": true, + "requires": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + }, + "dependencies": { + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npm.taobao.org/inherits/download/inherits-2.0.4.tgz", + "integrity": "sha1-D6LGT5MpF8NDOg3tVTY6rjdBa3w=", + "dev": true + } + } + }, + "buffer": { + "version": "5.6.0", + "resolved": "https://registry.npm.taobao.org/buffer/download/buffer-5.6.0.tgz?cache=0&sync_timestamp=1588706716358&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fbuffer%2Fdownload%2Fbuffer-5.6.0.tgz", + "integrity": "sha1-oxdJ3H2B2E2wir+Te2uMQDP2J4Y=", + "dev": true, + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4" + } + }, + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npm.taobao.org/readable-stream/download/readable-stream-3.6.0.tgz", + "integrity": "sha1-M3u9o63AcGvT4CRCaihtS0sskZg=", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, "tedious": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/tedious/-/tedious-2.7.1.tgz", @@ -8845,6 +9077,12 @@ "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" }, + "which-pm-runs": { + "version": "1.0.0", + "resolved": "https://registry.npm.taobao.org/which-pm-runs/download/which-pm-runs-1.0.0.tgz", + "integrity": "sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs=", + "dev": true + }, "wide-align": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", diff --git a/package.json b/package.json index 0e6922ee8e3..a52319a5452 100644 --- a/package.json +++ b/package.json @@ -57,6 +57,7 @@ "@types/sinon": "^7.0.8", "@types/source-map-support": "^0.4.2", "@types/yargs": "^12.0.9", + "better-sqlite3": "^7.0.1", "chai": "^4.2.0", "chai-as-promised": "^7.1.1", "class-transformer": "^0.2.3", diff --git a/src/commands/InitCommand.ts b/src/commands/InitCommand.ts index b8e553ecb3f..c3638ffe662 100644 --- a/src/commands/InitCommand.ts +++ b/src/commands/InitCommand.ts @@ -113,6 +113,12 @@ export class InitCommand implements yargs.CommandModule { "database": "database.sqlite", }); break; + case "better-sqlite3": + Object.assign(options, { + type: "better-sqlite3", + "database": "database.sqlite", + }); + break; case "postgres": Object.assign(options, { "type": "postgres", @@ -457,6 +463,7 @@ services: `; case "sqlite": + case "better-sqlite3": return `version: '3' services: `; @@ -546,6 +553,9 @@ Steps to run this project: case "sqlite": packageJson.dependencies["sqlite3"] = "^4.0.3"; break; + case "better-sqlite3": + packageJson.dependencies["better-sqlite3"] = "^7.0.0"; + break; case "oracle": packageJson.dependencies["oracledb"] = "^1.13.1"; break; diff --git a/src/connection/ConnectionOptions.ts b/src/connection/ConnectionOptions.ts index 1c37c7ce843..40fd6080874 100644 --- a/src/connection/ConnectionOptions.ts +++ b/src/connection/ConnectionOptions.ts @@ -13,6 +13,7 @@ import {ExpoConnectionOptions} from "../driver/expo/ExpoConnectionOptions"; import {AuroraDataApiConnectionOptions} from "../driver/aurora-data-api/AuroraDataApiConnectionOptions"; import {SapConnectionOptions} from "../driver/sap/SapConnectionOptions"; import {AuroraDataApiPostgresConnectionOptions} from "../driver/aurora-data-api-pg/AuroraDataApiPostgresConnectionOptions"; +import {BetterSqlite3ConnectionOptions} from "../driver/better-sqlite3/BetterSqlite3ConnectionOptions"; /** @@ -35,4 +36,5 @@ export type ConnectionOptions = MongoConnectionOptions| AuroraDataApiConnectionOptions| AuroraDataApiPostgresConnectionOptions| - ExpoConnectionOptions; + ExpoConnectionOptions| + BetterSqlite3ConnectionOptions; diff --git a/src/connection/ConnectionOptionsReader.ts b/src/connection/ConnectionOptionsReader.ts index 03f00f99577..5e9ee045100 100644 --- a/src/connection/ConnectionOptionsReader.ts +++ b/src/connection/ConnectionOptionsReader.ts @@ -171,7 +171,7 @@ export class ConnectionOptionsReader { } // make database path file in sqlite relative to package.json - if (options.type === "sqlite") { + if (options.type === "sqlite" || options.type === "better-sqlite3") { if (typeof options.database === "string" && options.database.substr(0, 1) !== "/" && // unix absolute options.database.substr(1, 2) !== ":\\" && // windows absolute diff --git a/src/driver/DriverFactory.ts b/src/driver/DriverFactory.ts index 80f58df4efc..3d6456b3bc4 100644 --- a/src/driver/DriverFactory.ts +++ b/src/driver/DriverFactory.ts @@ -16,6 +16,7 @@ import {Driver} from "./Driver"; import {Connection} from "../connection/Connection"; import {SapDriver} from "./sap/SapDriver"; import {AuroraDataApiPostgresDriver} from "./postgres/PostgresDriver"; +import {BetterSqlite3Driver} from "./better-sqlite3/BetterSqlite3Driver"; /** * Helps to create drivers. @@ -40,6 +41,8 @@ export class DriverFactory { return new MysqlDriver(connection); case "sqlite": return new SqliteDriver(connection); + case "better-sqlite3": + return new BetterSqlite3Driver(connection); case "cordova": return new CordovaDriver(connection); case "nativescript": diff --git a/src/driver/better-sqlite3/BetterSqlite3ConnectionOptions.ts b/src/driver/better-sqlite3/BetterSqlite3ConnectionOptions.ts new file mode 100644 index 00000000000..09422cbfc00 --- /dev/null +++ b/src/driver/better-sqlite3/BetterSqlite3ConnectionOptions.ts @@ -0,0 +1,60 @@ +import {BaseConnectionOptions} from "../../connection/BaseConnectionOptions"; + +/** + * Sqlite-specific connection options. + */ +export interface BetterSqlite3ConnectionOptions extends BaseConnectionOptions { + + /** + * Database type. + */ + readonly type: "better-sqlite3"; + + /** + * Storage type or path to the storage. + */ + readonly database: string; + + /** + * Encryption key for for SQLCipher. + */ + readonly key?: string; + + /** + * Cache size of sqlite statement to speed up queries. + * Default: 100. + */ + readonly statementCacheSize?: number; + + /** + * Function to run before a database is used in typeorm. + * You can set pragmas, register plugins or register + * functions or aggregates in this function. + */ + readonly prepareDatabase?: (db: any) => void | Promise; + + /** + * Open the database connection in readonly mode. + * Default: false. + */ + readonly readonly?: boolean; + + /** + * If the database does not exist, an Error will be thrown instead of creating a new file. + * This option does not affect in-memory or readonly database connections. + * Default: false. + */ + readonly fileMustExist?: boolean; + + /** + * The number of milliseconds to wait when executing queries + * on a locked database, before throwing a SQLITE_BUSY error. + * Default: 5000. + */ + readonly timeout?: number; + + /** + * Provide a function that gets called with every SQL string executed by the database connection. + */ + readonly verbose?: Function; +} \ No newline at end of file diff --git a/src/driver/better-sqlite3/BetterSqlite3Driver.ts b/src/driver/better-sqlite3/BetterSqlite3Driver.ts new file mode 100644 index 00000000000..814b093d7ac --- /dev/null +++ b/src/driver/better-sqlite3/BetterSqlite3Driver.ts @@ -0,0 +1,141 @@ +import { DriverPackageNotInstalledError } from "../../error/DriverPackageNotInstalledError"; +import { DriverOptionNotSetError } from "../../error/DriverOptionNotSetError"; +import { PlatformTools } from "../../platform/PlatformTools"; +import { Connection } from "../../connection/Connection"; +import { ColumnType } from "../types/ColumnTypes"; +import { QueryRunner } from "../../query-runner/QueryRunner"; +import { AbstractSqliteDriver } from "../sqlite-abstract/AbstractSqliteDriver"; +import { BetterSqlite3ConnectionOptions } from "./BetterSqlite3ConnectionOptions"; +import { BetterSqlite3QueryRunner } from "./BetterSqlite3QueryRunner"; + +/** + * Organizes communication with sqlite DBMS. + */ +export class BetterSqlite3Driver extends AbstractSqliteDriver { + + // ------------------------------------------------------------------------- + // Public Implemented Properties + // ------------------------------------------------------------------------- + + /** + * Connection options. + */ + options: BetterSqlite3ConnectionOptions; + + /** + * SQLite underlying library. + */ + sqlite: any; + + // ------------------------------------------------------------------------- + // Constructor + // ------------------------------------------------------------------------- + + constructor(connection: Connection) { + super(connection); + + this.connection = connection; + this.options = connection.options as BetterSqlite3ConnectionOptions; + this.database = this.options.database; + + // validate options to make sure everything is set + if (!this.options.database) + throw new DriverOptionNotSetError("database"); + + // load sqlite package + this.loadDependencies(); + } + + // ------------------------------------------------------------------------- + // Public Methods + // ------------------------------------------------------------------------- + + /** + * Closes connection with database. + */ + async disconnect(): Promise { + this.queryRunner = undefined; + this.databaseConnection.close(); + } + + /** + * Creates a query runner used to execute database queries. + */ + createQueryRunner(mode: "master" | "slave" = "master"): QueryRunner { + if (!this.queryRunner) + this.queryRunner = new BetterSqlite3QueryRunner(this); + + return this.queryRunner; + } + + normalizeType(column: { type?: ColumnType, length?: number | string, precision?: number | null, scale?: number }): string { + if ((column.type as any) === Buffer) { + return "blob"; + } + + return super.normalizeType(column); + } + + // ------------------------------------------------------------------------- + // Protected Methods + // ------------------------------------------------------------------------- + + /** + * Creates connection with the database. + */ + protected async createDatabaseConnection() { + // not to create database directory if is in memory + if (this.options.database !== ":memory:") + await this.createDatabaseDirectory(this.options.database); + + const { + database, + readonly = false, + fileMustExist = false, + timeout = 5000, + verbose = null, + prepareDatabase + } = this.options; + const databaseConnection = this.sqlite(database, { readonly, fileMustExist, timeout, verbose }); + + // we need to enable foreign keys in sqlite to make sure all foreign key related features + // working properly. this also makes onDelete to work with sqlite. + databaseConnection.exec(`PRAGMA foreign_keys = ON`); + + // turn on WAL mode to enhance performance + databaseConnection.exec(`PRAGMA journal_mode = WAL`); + + // in the options, if encryption key for SQLCipher is setted. + if (this.options.key) { + databaseConnection.exec(`PRAGMA key = ${JSON.stringify(this.options.key)}`); + } + + if (typeof prepareDatabase === "function") { + prepareDatabase(databaseConnection); + } + + return databaseConnection; + } + + /** + * If driver dependency is not given explicitly, then try to load it via "require". + */ + protected loadDependencies(): void { + try { + this.sqlite = PlatformTools.load("better-sqlite3"); + + } catch (e) { + throw new DriverPackageNotInstalledError("SQLite", "better-sqlite3"); + } + } + + /** + * Auto creates database directory if it does not exist. + */ + protected createDatabaseDirectory(fullPath: string): Promise { + const mkdirp = PlatformTools.load("mkdirp"); + const path = PlatformTools.load("path"); + return mkdirp(path.dirname(fullPath)); + } + +} diff --git a/src/driver/better-sqlite3/BetterSqlite3QueryRunner.ts b/src/driver/better-sqlite3/BetterSqlite3QueryRunner.ts new file mode 100644 index 00000000000..b508fc6b71f --- /dev/null +++ b/src/driver/better-sqlite3/BetterSqlite3QueryRunner.ts @@ -0,0 +1,106 @@ +import { QueryRunnerAlreadyReleasedError } from "../../error/QueryRunnerAlreadyReleasedError"; +import { QueryFailedError } from "../../error/QueryFailedError"; +import { AbstractSqliteQueryRunner } from "../sqlite-abstract/AbstractSqliteQueryRunner"; +import { Broadcaster } from "../../subscriber/Broadcaster"; +import { BetterSqlite3Driver } from "./BetterSqlite3Driver"; + +/** + * Runs queries on a single sqlite database connection. + * + * Does not support compose primary keys with autoincrement field. + * todo: need to throw exception for this case. + */ +export class BetterSqlite3QueryRunner extends AbstractSqliteQueryRunner { + + /** + * Database driver used by connection. + */ + driver: BetterSqlite3Driver; + + // ------------------------------------------------------------------------- + // Constructor + // ------------------------------------------------------------------------- + + constructor(driver: BetterSqlite3Driver) { + super(); + this.driver = driver; + this.connection = driver.connection; + this.broadcaster = new Broadcaster(this); + if (typeof this.driver.options.statementCacheSize === "number") { + this.cacheSize = this.driver.options.statementCacheSize; + } else { + this.cacheSize = 100; + } + } + + private cacheSize: number; + private stmtCache = new Map(); + + private async getStmt(query: string) { + if (this.cacheSize > 0) { + let stmt = this.stmtCache.get(query); + if (!stmt) { + const databaseConnection = await this.connect(); + stmt = databaseConnection.prepare(query); + this.stmtCache.set(query, stmt); + while (this.stmtCache.size > this.cacheSize) { + // since es6 map keeps the insertion order, + // it comes to be FIFO cache + const key = this.stmtCache.keys().next().value; + this.stmtCache.delete(key); + } + } + return stmt; + } else { + const databaseConnection = await this.connect(); + return databaseConnection.prepare(query); + } + } + + /** + * Executes a given SQL query. + */ + async query(query: string, parameters?: any[]): Promise { + if (this.isReleased) + throw new QueryRunnerAlreadyReleasedError(); + + const connection = this.driver.connection; + + parameters = parameters || []; + for (let i = 0; i < parameters.length; i++) { + // in "where" clauses the parameters are not escaped by the driver + if (typeof parameters[i] === "boolean") + parameters[i] = +parameters[i]; + } + + this.driver.connection.logger.logQuery(query, parameters, this); + const queryStartTime = +new Date(); + + const stmt = await this.getStmt(query); + + try { + + let result: any; + if (stmt.reader) { + result = stmt.all.apply(stmt, parameters); + } else { + result = stmt.run.apply(stmt, parameters); + if (query.substr(0, 6) === "INSERT") { + result = result.lastInsertRowid; + } + } + + // log slow queries if maxQueryExecution time is set + const maxQueryExecutionTime = connection.options.maxQueryExecutionTime; + const queryEndTime = +new Date(); + const queryExecutionTime = queryEndTime - queryStartTime; + if (maxQueryExecutionTime && queryExecutionTime > maxQueryExecutionTime) + connection.logger.logQuerySlow(queryExecutionTime, query, parameters, this); + + return result; + } catch (err) { + connection.logger.logQueryError(err, query, parameters, this); + throw new QueryFailedError(query, parameters, err); + } + } +} \ No newline at end of file diff --git a/src/driver/types/DatabaseType.ts b/src/driver/types/DatabaseType.ts index 4426c9829da..5ceaece0ccc 100644 --- a/src/driver/types/DatabaseType.ts +++ b/src/driver/types/DatabaseType.ts @@ -17,4 +17,5 @@ export type DatabaseType = "mongodb"| "aurora-data-api"| "aurora-data-api-pg"| - "expo"; + "expo"| + "better-sqlite3"; diff --git a/src/error/MissingDriverError.ts b/src/error/MissingDriverError.ts index a5634f46791..5d2518fb553 100644 --- a/src/error/MissingDriverError.ts +++ b/src/error/MissingDriverError.ts @@ -7,7 +7,7 @@ export class MissingDriverError extends Error { constructor(driverType: string) { super(); Object.setPrototypeOf(this, MissingDriverError.prototype); - this.message = `Wrong driver: "${driverType}" given. Supported drivers are: "cordova", "expo", "mariadb", "mongodb", "mssql", "mysql", "oracle", "postgres", "sqlite", "sqljs", "react-native", "aurora-data-api", "aurora-data-api-pg".`; + this.message = `Wrong driver: "${driverType}" given. Supported drivers are: "cordova", "expo", "mariadb", "mongodb", "mssql", "mysql", "oracle", "postgres", "sqlite", "better-sqlite3", "sqljs", "react-native", "aurora-data-api", "aurora-data-api-pg".`; } } diff --git a/src/query-builder/DeleteQueryBuilder.ts b/src/query-builder/DeleteQueryBuilder.ts index 4be20ba3776..e6efd9d6971 100644 --- a/src/query-builder/DeleteQueryBuilder.ts +++ b/src/query-builder/DeleteQueryBuilder.ts @@ -16,6 +16,7 @@ import {MysqlDriver} from "../driver/mysql/MysqlDriver"; import {BroadcasterResult} from "../subscriber/BroadcasterResult"; import {EntitySchema} from "../index"; import {AuroraDataApiDriver} from "../driver/aurora-data-api/AuroraDataApiDriver"; +import {BetterSqlite3Driver} from "../driver/better-sqlite3/BetterSqlite3Driver"; /** * Allows to build complex sql queries in a fashion way and execute those queries. @@ -83,6 +84,10 @@ export class DeleteQueryBuilder extends QueryBuilder implements } else if (driver instanceof OracleDriver) { deleteResult.affected = result; + } else if (driver instanceof BetterSqlite3Driver) { // only works for better-sqlite3 + deleteResult.raw = result; + deleteResult.affected = result.changes; + } else { deleteResult.raw = result; } diff --git a/src/query-builder/UpdateQueryBuilder.ts b/src/query-builder/UpdateQueryBuilder.ts index 22ac5c5e127..2e0497f1f50 100644 --- a/src/query-builder/UpdateQueryBuilder.ts +++ b/src/query-builder/UpdateQueryBuilder.ts @@ -24,6 +24,7 @@ import {UpdateValuesMissingError} from "../error/UpdateValuesMissingError"; import {EntityColumnNotFound} from "../error/EntityColumnNotFound"; import {QueryDeepPartialEntity} from "./QueryPartialEntity"; import {AuroraDataApiDriver} from "../driver/aurora-data-api/AuroraDataApiDriver"; +import {BetterSqlite3Driver} from "../driver/better-sqlite3/BetterSqlite3Driver"; /** * Allows to build complex sql queries in a fashion way and execute those queries. @@ -108,6 +109,10 @@ export class UpdateQueryBuilder extends QueryBuilder implements updateResult.raw = result; updateResult.affected = result.affectedRows; } + else if (this.connection.driver instanceof BetterSqlite3Driver) { // only works for better-sqlite3 + updateResult.raw = result; + updateResult.affected = result.changes; + } else { updateResult.raw = result; } diff --git a/test/functional/connection-options-reader/configs/sqlite-memory.ts b/test/functional/connection-options-reader/configs/sqlite-memory.ts index 243dd45cef5..81907c198e6 100644 --- a/test/functional/connection-options-reader/configs/sqlite-memory.ts +++ b/test/functional/connection-options-reader/configs/sqlite-memory.ts @@ -6,4 +6,8 @@ module.exports = [{ type: "sqlite", name: "memory", database: ":memory:", +}, { + type: "better-sqlite3", + name: "memory2", + database: ":memory:", }]; \ No newline at end of file diff --git a/test/functional/database-schema/column-collation/sqlite/column-collation-sqlite.ts b/test/functional/database-schema/column-collation/sqlite/column-collation-sqlite.ts index cfd415258ec..869aa9785ed 100644 --- a/test/functional/database-schema/column-collation/sqlite/column-collation-sqlite.ts +++ b/test/functional/database-schema/column-collation/sqlite/column-collation-sqlite.ts @@ -10,7 +10,7 @@ describe.skip("database schema > column collation > sqlite", () => { before(async () => { connections = await createTestingConnections({ entities: [__dirname + "/entity/*{.js,.ts}"], - enabledDrivers: ["sqlite"], + enabledDrivers: ["sqlite", "better-sqlite3"], }); }); beforeEach(() => reloadTestingDatabases(connections)); diff --git a/test/functional/database-schema/column-length/sqlite/column-length-sqlite..ts b/test/functional/database-schema/column-length/sqlite/column-length-sqlite..ts index deffdbd3aa3..64a9d7f8fe5 100644 --- a/test/functional/database-schema/column-length/sqlite/column-length-sqlite..ts +++ b/test/functional/database-schema/column-length/sqlite/column-length-sqlite..ts @@ -10,7 +10,7 @@ describe("database schema > column length > sqlite", () => { before(async () => { connections = await createTestingConnections({ entities: [Post], - enabledDrivers: ["sqlite"], + enabledDrivers: ["sqlite", "better-sqlite3"], }); }); beforeEach(() => reloadTestingDatabases(connections)); diff --git a/test/functional/database-schema/column-types/sqlite/column-types-sqlite.ts b/test/functional/database-schema/column-types/sqlite/column-types-sqlite.ts index b76a3e5bcc6..64a2213f22e 100644 --- a/test/functional/database-schema/column-types/sqlite/column-types-sqlite.ts +++ b/test/functional/database-schema/column-types/sqlite/column-types-sqlite.ts @@ -11,7 +11,7 @@ describe("database schema > column types > sqlite", () => { before(async () => { connections = await createTestingConnections({ entities: [__dirname + "/entity/*{.js,.ts}"], - enabledDrivers: ["sqlite"], + enabledDrivers: ["sqlite", "better-sqlite3"], }); }); beforeEach(() => reloadTestingDatabases(connections)); diff --git a/test/functional/database-schema/simple-enums/enums.ts b/test/functional/database-schema/simple-enums/enums.ts index 61f84893428..dc355710420 100644 --- a/test/functional/database-schema/simple-enums/enums.ts +++ b/test/functional/database-schema/simple-enums/enums.ts @@ -9,7 +9,7 @@ describe("database schema > simple-enums", () => { before(async () => { connections = await createTestingConnections({ entities: [__dirname + "/entity/*{.js,.ts}"], - enabledDrivers: ["mysql", "mariadb", "postgres", "sqlite", "mssql"] + enabledDrivers: ["mysql", "mariadb", "postgres", "sqlite", "better-sqlite3", "mssql"] }); }); beforeEach(() => reloadTestingDatabases(connections)); diff --git a/test/functional/indices/conditional-index/conditional-index.ts b/test/functional/indices/conditional-index/conditional-index.ts index 67f6648c8c4..6b8ed7d5c9e 100644 --- a/test/functional/indices/conditional-index/conditional-index.ts +++ b/test/functional/indices/conditional-index/conditional-index.ts @@ -9,7 +9,7 @@ describe("indices > conditional index", () => { before(async () => { connections = await createTestingConnections({ entities: [__dirname + "/entity/*{.js,.ts}"], - enabledDrivers: ["mssql", "postgres", "sqlite"], // only these drivers supports conditional indices + enabledDrivers: ["mssql", "postgres", "sqlite", "better-sqlite3"], // only these drivers supports conditional indices schemaCreate: true, dropSchema: true, }); diff --git a/test/functional/query-builder/delete/query-builder-delete.ts b/test/functional/query-builder/delete/query-builder-delete.ts index 05d091dc46f..4c7be038831 100644 --- a/test/functional/query-builder/delete/query-builder-delete.ts +++ b/test/functional/query-builder/delete/query-builder-delete.ts @@ -96,6 +96,7 @@ describe("query builder > delete", () => { it("should return correct delete result", () => Promise.all(connections.map(async connection => { // don't run test for sqlite and sqljs as they don't return affected rows + // better-sqlite3 works correctly if (connection.name === "sqlite" || connection.name === "sqljs" || connection.name === "sap") return; diff --git a/test/functional/query-builder/insert-on-conflict/query-builder-insert-on-conflict.ts b/test/functional/query-builder/insert-on-conflict/query-builder-insert-on-conflict.ts index 03ee8e50bd4..67221d0f301 100644 --- a/test/functional/query-builder/insert-on-conflict/query-builder-insert-on-conflict.ts +++ b/test/functional/query-builder/insert-on-conflict/query-builder-insert-on-conflict.ts @@ -8,7 +8,7 @@ describe("query builder > insertion > on conflict", () => { let connections: Connection[]; before(async () => connections = await createTestingConnections({ entities: [__dirname + "/entity/*{.js,.ts}"], - enabledDrivers: ["postgres", "sqlite"] // since on conflict statement is only supported in postgres and sqlite >= 3.24.0 + enabledDrivers: ["postgres", "sqlite", "better-sqlite3"] // since on conflict statement is only supported in postgres and sqlite >= 3.24.0 })); beforeEach(() => reloadTestingDatabases(connections)); after(() => closeTestingConnections(connections)); diff --git a/test/functional/query-runner/create-table.ts b/test/functional/query-runner/create-table.ts index f940faf7ea5..3aa973fceac 100644 --- a/test/functional/query-runner/create-table.ts +++ b/test/functional/query-runner/create-table.ts @@ -12,7 +12,6 @@ import {AbstractSqliteDriver} from "../../../src/driver/sqlite-abstract/Abstract import {OracleDriver} from "../../../src/driver/oracle/OracleDriver"; import {Photo} from "./entity/Photo"; import {Book2, Book} from "./entity/Book"; -import {SqliteDriver} from "../../../src/driver/sqlite/SqliteDriver"; describe("query runner > create table", () => { @@ -332,7 +331,7 @@ describe("query runner > create table", () => { it("should correctly create table with different `withoutRowid` definitions", () => Promise.all(connections.map(async connection => { - if (connection.driver instanceof SqliteDriver) { + if (connection.driver instanceof AbstractSqliteDriver) { const queryRunner = connection.createQueryRunner(); // the table 'book' must contain a 'rowid' column @@ -358,7 +357,7 @@ describe("query runner > create table", () => { try { await connection.manager.query("SELECT rowid FROM book2"); } catch (e) { - expect(e.message).equal("SQLITE_ERROR: no such column: rowid"); + expect(e.message).contains("no such column: rowid"); } await queryRunner.dropTable("book2"); diff --git a/test/functional/query-runner/create-unique-constraint.ts b/test/functional/query-runner/create-unique-constraint.ts index ba39b2aa98e..b3022e0a367 100644 --- a/test/functional/query-runner/create-unique-constraint.ts +++ b/test/functional/query-runner/create-unique-constraint.ts @@ -10,7 +10,7 @@ describe("query runner > create unique constraint", () => { before(async () => { connections = await createTestingConnections({ entities: [__dirname + "/entity/*{.js,.ts}"], - enabledDrivers: ["mssql", "postgres", "sqlite", "oracle", "cockroachdb"], // mysql and sap does not supports unique constraints + enabledDrivers: ["mssql", "postgres", "sqlite", "better-sqlite3", "oracle", "cockroachdb"], // mysql and sap does not supports unique constraints schemaCreate: true, dropSchema: true, }); diff --git a/test/functional/query-runner/drop-column.ts b/test/functional/query-runner/drop-column.ts index 5e03628eee8..2c422c2e9d6 100644 --- a/test/functional/query-runner/drop-column.ts +++ b/test/functional/query-runner/drop-column.ts @@ -28,6 +28,11 @@ describe("query runner > drop column", () => { nameColumn!.should.be.exist; versionColumn!.should.be.exist; + // better-sqlite3 seems not able to create a check constraint on a non-existing column + if (connection.name === "better-sqlite3") { + await queryRunner.dropCheckConstraints(table!, table!.checks); + } + // In Sqlite 'dropColumns' method is more optimal than 'dropColumn', because it recreate table just once, // without all removed columns. In other drivers it's no difference between these methods, because 'dropColumns' // calls 'dropColumn' method for each removed column. diff --git a/test/functional/query-runner/drop-unique-constraint.ts b/test/functional/query-runner/drop-unique-constraint.ts index fd00a7952d2..d2b5d5bcb02 100644 --- a/test/functional/query-runner/drop-unique-constraint.ts +++ b/test/functional/query-runner/drop-unique-constraint.ts @@ -8,7 +8,7 @@ describe("query runner > drop unique constraint", () => { before(async () => { connections = await createTestingConnections({ entities: [__dirname + "/entity/*{.js,.ts}"], - enabledDrivers: ["mssql", "postgres", "sqlite", "oracle", "cockroachdb"], // mysql and sap does not supports unique constraints + enabledDrivers: ["mssql", "postgres", "sqlite", "better-sqlite3", "oracle", "cockroachdb"], // mysql and sap does not supports unique constraints schemaCreate: true, dropSchema: true, }); diff --git a/test/functional/relations/lazy-relations/basic-lazy-relation/basic-lazy-relations.ts b/test/functional/relations/lazy-relations/basic-lazy-relation/basic-lazy-relations.ts index 3c0d8fe7d1a..7c83e84e398 100644 --- a/test/functional/relations/lazy-relations/basic-lazy-relation/basic-lazy-relations.ts +++ b/test/functional/relations/lazy-relations/basic-lazy-relation/basic-lazy-relations.ts @@ -326,7 +326,7 @@ describe("basic-lazy-relations", () => { loadedPost.title.should.be.equal("post with great category"); }))); - it("should successfully load relations within a transaction", () => Promise.all(connections.filter((connection) => (new Set(["mysql", "sqlite", "postgres"])).has(connection.options.type)).map(async connection => { + it("should successfully load relations within a transaction", () => Promise.all(connections.filter((connection) => (new Set(["mysql", "sqlite", "better-sqlite3", "postgres"])).has(connection.options.type)).map(async connection => { await connection.manager.transaction(async (manager) => { const category = new Category(); category.name = "category of great post"; @@ -344,7 +344,7 @@ describe("basic-lazy-relations", () => { }); }))); - it("should successfully load relations outside a transaction with entity generated within a transaction", () => Promise.all(connections.filter((connection) => (new Set(["mysql", "sqlite", "postgres"])).has(connection.options.type)).map(async connection => { + it("should successfully load relations outside a transaction with entity generated within a transaction", () => Promise.all(connections.filter((connection) => (new Set(["mysql", "sqlite", "better-sqlite3", "postgres"])).has(connection.options.type)).map(async connection => { const loadedCategory = await connection.manager.transaction(async (manager) => { const category = new Category(); category.name = "category of great post"; diff --git a/test/functional/repository/basic-methods/repository-basic-methods.ts b/test/functional/repository/basic-methods/repository-basic-methods.ts index 677b5a4c607..cc50f66549c 100644 --- a/test/functional/repository/basic-methods/repository-basic-methods.ts +++ b/test/functional/repository/basic-methods/repository-basic-methods.ts @@ -324,8 +324,7 @@ describe("repository > basic methods", () => { }); describe("save", function () { - it("should update existing entity using transformers", async () => { - const connection = connections.find((c: Connection) => c.name === "sqlite"); + it("should update existing entity using transformers", () => Promise.all(connections.filter(c => c.name === "sqlite" || c.name === "better-sqlite3").map(async connection => { if (!connection || (connection.options as any).skip === true) { return; } @@ -354,7 +353,7 @@ describe("repository > basic methods", () => { saved.title.should.be.equal("New title"); saved.dateAdded.should.be.instanceof(Date); saved.dateAdded.getTime().should.be.equal(date.getTime()); - }); + }))); }); describe("preload also should also implement merge functionality", function() { diff --git a/test/functional/repository/find-options/repository-find-options.ts b/test/functional/repository/find-options/repository-find-options.ts index 42bffc16e11..e899d6158c3 100644 --- a/test/functional/repository/find-options/repository-find-options.ts +++ b/test/functional/repository/find-options/repository-find-options.ts @@ -12,7 +12,7 @@ describe("repository > find options", () => { let connections: Connection[]; before(async () => connections = await createTestingConnections({ entities: [__dirname + "/entity/*{.js,.ts}"], - enabledDrivers: ["sqlite"] + enabledDrivers: ["sqlite", "better-sqlite3"] })); beforeEach(() => reloadTestingDatabases(connections)); after(() => closeTestingConnections(connections)); diff --git a/test/functional/table-inheritance/single-table/database-option-inherited/database-option-inherited.ts b/test/functional/table-inheritance/single-table/database-option-inherited/database-option-inherited.ts index 18700f5e11c..66ba39cef9f 100644 --- a/test/functional/table-inheritance/single-table/database-option-inherited/database-option-inherited.ts +++ b/test/functional/table-inheritance/single-table/database-option-inherited/database-option-inherited.ts @@ -8,7 +8,7 @@ describe("table-inheritance > single-table > database-option-inherited", () => { before(async () => connections = await createTestingConnections({ entities: [__dirname + "/entity/*{.js,.ts}"], // creating more databases isn't always possible(e.g oracle official docker images) - enabledDrivers: ["postgres", "cockroachdb", "mariadb", "mssql", "mysql", "sqlite", "sqljs"] + enabledDrivers: ["postgres", "cockroachdb", "mariadb", "mssql", "mysql", "sqlite", "better-sqlite3", "sqljs"] })); beforeEach(() => reloadTestingDatabases(connections)); after(() => closeTestingConnections(connections)); diff --git a/test/functional/transaction/database-specific-isolation/sqlite-isolation.ts b/test/functional/transaction/database-specific-isolation/sqlite-isolation.ts index 907cb0da2d0..9915e444153 100644 --- a/test/functional/transaction/database-specific-isolation/sqlite-isolation.ts +++ b/test/functional/transaction/database-specific-isolation/sqlite-isolation.ts @@ -10,7 +10,7 @@ describe("transaction > transaction with sqlite connection partial isolation sup let connections: Connection[]; before(async () => connections = await createTestingConnections({ entities: [__dirname + "/entity/*{.js,.ts}"], - enabledDrivers: ["sqlite"] // todo: for some reasons mariadb tests are not passing here + enabledDrivers: ["sqlite", "better-sqlite3"] // todo: for some reasons mariadb tests are not passing here })); beforeEach(() => reloadTestingDatabases(connections)); after(() => closeTestingConnections(connections)); diff --git a/test/functional/transaction/return-data-from-transaction/return-data-from-transaction.ts b/test/functional/transaction/return-data-from-transaction/return-data-from-transaction.ts index db10856a45e..55db390eb58 100644 --- a/test/functional/transaction/return-data-from-transaction/return-data-from-transaction.ts +++ b/test/functional/transaction/return-data-from-transaction/return-data-from-transaction.ts @@ -10,7 +10,7 @@ describe("transaction > return data from transaction", () => { let connections: Connection[]; before(async () => connections = await createTestingConnections({ entities: [__dirname + "/entity/*{.js,.ts}"], - enabledDrivers: ["mysql", "sqlite", "postgres"] // todo: for some reasons mariadb tests are not passing here + enabledDrivers: ["mysql", "sqlite", "better-sqlite3", "postgres"] // todo: for some reasons mariadb tests are not passing here })); beforeEach(() => reloadTestingDatabases(connections)); after(() => closeTestingConnections(connections)); diff --git a/test/functional/transaction/transaction-in-entity-manager/transaction-in-entity-manager.ts b/test/functional/transaction/transaction-in-entity-manager/transaction-in-entity-manager.ts index 9b20840dc97..a47c9d7fbd8 100644 --- a/test/functional/transaction/transaction-in-entity-manager/transaction-in-entity-manager.ts +++ b/test/functional/transaction/transaction-in-entity-manager/transaction-in-entity-manager.ts @@ -10,7 +10,7 @@ describe("transaction > transaction with entity manager", () => { let connections: Connection[]; before(async () => connections = await createTestingConnections({ entities: [__dirname + "/entity/*{.js,.ts}"], - enabledDrivers: ["mysql", "sqlite", "postgres"] // todo: for some reasons mariadb tests are not passing here + enabledDrivers: ["mysql", "sqlite", "better-sqlite3", "postgres"] // todo: for some reasons mariadb tests are not passing here })); beforeEach(() => reloadTestingDatabases(connections)); after(() => closeTestingConnections(connections)); diff --git a/test/functional/uuid/sqlite/uuid-sqlite.ts b/test/functional/uuid/sqlite/uuid-sqlite.ts index f167faee6d1..ee03f28e3b6 100644 --- a/test/functional/uuid/sqlite/uuid-sqlite.ts +++ b/test/functional/uuid/sqlite/uuid-sqlite.ts @@ -11,7 +11,7 @@ describe("uuid-sqlite", () => { before(async () => { connections = await createTestingConnections({ entities: [__dirname + "/entity/*{.js,.ts}"], - enabledDrivers: ["sqlite"], + enabledDrivers: ["sqlite", "better-sqlite3"], }); }); beforeEach(() => reloadTestingDatabases(connections)); diff --git a/test/functional/view-entity/sqlite/view-entity-sqlite.ts b/test/functional/view-entity/sqlite/view-entity-sqlite.ts index cd1b0aef514..108c9bbea1a 100644 --- a/test/functional/view-entity/sqlite/view-entity-sqlite.ts +++ b/test/functional/view-entity/sqlite/view-entity-sqlite.ts @@ -12,7 +12,7 @@ describe("view entity > sqlite", () => { let connections: Connection[]; before(async () => connections = await createTestingConnections({ entities: [__dirname + "/entity/*{.js,.ts}"], - enabledDrivers: ["sqlite"] + enabledDrivers: ["sqlite", "better-sqlite3"] })); beforeEach(() => reloadTestingDatabases(connections)); after(() => closeTestingConnections(connections)); diff --git a/test/github-issues/134/issue-134.ts b/test/github-issues/134/issue-134.ts index 8a364197fc0..1b4b8e1e2c3 100644 --- a/test/github-issues/134/issue-134.ts +++ b/test/github-issues/134/issue-134.ts @@ -9,7 +9,7 @@ describe("github issues > #134 Error TIME is converted to 'HH-mm' instead of 'HH let connections: Connection[]; before(async () => connections = await createTestingConnections({ entities: [__dirname + "/entity/*{.js,.ts}"], - enabledDrivers: ["mysql", "mariadb", "sqlite", "mssql", "postgres"] // Oracle does not support TIME data type. + enabledDrivers: ["mysql", "mariadb", "sqlite", "better-sqlite3", "mssql", "postgres"] // Oracle does not support TIME data type. })); beforeEach(() => reloadTestingDatabases(connections)); after(() => closeTestingConnections(connections)); diff --git a/test/github-issues/1465/save-relation.ts b/test/github-issues/1465/save-relation.ts index bd5ef090670..e0ee4f0ce2d 100644 --- a/test/github-issues/1465/save-relation.ts +++ b/test/github-issues/1465/save-relation.ts @@ -10,7 +10,7 @@ describe("save child and parent entity", () => { let connections: Connection[] = []; before(async () => connections = await createTestingConnections({ entities: [__dirname + "/entity/*{.js,.ts}"], - enabledDrivers: ["mysql", "mariadb", "sqlite", "sqljs"] + enabledDrivers: ["mysql", "mariadb", "sqlite", "better-sqlite3", "sqljs"] })); beforeEach(() => reloadTestingDatabases(connections)); after(() => closeTestingConnections(connections)); diff --git a/test/github-issues/1476/issue-1476.ts b/test/github-issues/1476/issue-1476.ts index b886071a408..7b73d5b468d 100644 --- a/test/github-issues/1476/issue-1476.ts +++ b/test/github-issues/1476/issue-1476.ts @@ -12,7 +12,7 @@ describe("github issues > #1476 subqueries", () => { let connections: Connection[] = []; before(async () => connections = await createTestingConnections({ entities: [__dirname + "/entity/*{.js,.ts}"], - enabledDrivers: ["mysql", "mariadb", "sqlite", "sqljs"] + enabledDrivers: ["mysql", "mariadb", "sqlite", "better-sqlite3", "sqljs"] })); beforeEach(() => reloadTestingDatabases(connections)); after(() => closeTestingConnections(connections)); diff --git a/test/github-issues/1898/issue-1898.ts b/test/github-issues/1898/issue-1898.ts index a591d7c1ae2..3eac4149625 100644 --- a/test/github-issues/1898/issue-1898.ts +++ b/test/github-issues/1898/issue-1898.ts @@ -9,7 +9,7 @@ describe("github issues > #1898 Simple JSON breaking in @next", () => { before(async () => { connections = await createTestingConnections({ entities: [__dirname + "/entity/*{.js,.ts}"], - enabledDrivers: ["sqlite"], + enabledDrivers: ["sqlite", "better-sqlite3"], schemaCreate: true, dropSchema: true }); diff --git a/test/github-issues/190/issue-190.ts b/test/github-issues/190/issue-190.ts index 665b3ab5c83..ab7f3970275 100644 --- a/test/github-issues/190/issue-190.ts +++ b/test/github-issues/190/issue-190.ts @@ -8,7 +8,7 @@ describe("github issues > #190 too many SQL variables when using setMaxResults i let connections: Connection[]; before(async () => connections = await createTestingConnections({ entities: [__dirname + "/entity/*{.js,.ts}"], - enabledDrivers: ["sqlite"] // this issue only related to sqlite + enabledDrivers: ["sqlite", "better-sqlite3"] // this issue only related to sqlite })); beforeEach(() => reloadTestingDatabases(connections)); after(() => closeTestingConnections(connections)); diff --git a/test/github-issues/1981/issue-1981.ts b/test/github-issues/1981/issue-1981.ts index 1134f42d756..3e653ec0cf1 100644 --- a/test/github-issues/1981/issue-1981.ts +++ b/test/github-issues/1981/issue-1981.ts @@ -7,7 +7,7 @@ describe("github issues > #1981 Boolean values not casted properly when used in let connections: Connection[]; before(async () => connections = await createTestingConnections({ entities: [__dirname + "/entity/*{.js,.ts}"], - enabledDrivers: ["sqlite"], + enabledDrivers: ["sqlite", "better-sqlite3"], })); beforeEach(() => reloadTestingDatabases(connections)); after(() => closeTestingConnections(connections)); diff --git a/test/github-issues/2005/issue-2005.ts b/test/github-issues/2005/issue-2005.ts index 52aaf9eb3e8..bb714b3158f 100644 --- a/test/github-issues/2005/issue-2005.ts +++ b/test/github-issues/2005/issue-2005.ts @@ -7,7 +7,7 @@ describe("github issues > #2005", () => { let connections: Connection[]; before(async () => connections = await createTestingConnections({ entities: [__dirname + "/entity/*{.js,.ts}"], - enabledDrivers: ["sqlite"] + enabledDrivers: ["sqlite", "better-sqlite3"] })); beforeEach(() => reloadTestingDatabases(connections)); after(() => closeTestingConnections(connections)); diff --git a/test/github-issues/2199/issue-2199.ts b/test/github-issues/2199/issue-2199.ts index 3898c9f36fa..8a51691ac94 100644 --- a/test/github-issues/2199/issue-2199.ts +++ b/test/github-issues/2199/issue-2199.ts @@ -9,7 +9,7 @@ describe("github issues > #2199 - Inserting value for @PrimaryGeneratedColumn() let connections: Connection[]; before(async () => connections = await createTestingConnections({ entities: [__dirname + "/entity/*{.js,.ts}"], - enabledDrivers: ["mysql", "mariadb", "sqlite"], + enabledDrivers: ["mysql", "mariadb", "sqlite", "better-sqlite3"], schemaCreate: true, dropSchema: true })); diff --git a/test/github-issues/2518/issue-2518.ts b/test/github-issues/2518/issue-2518.ts index 538f1ee466f..8b451aba25f 100644 --- a/test/github-issues/2518/issue-2518.ts +++ b/test/github-issues/2518/issue-2518.ts @@ -12,7 +12,7 @@ describe("github issues > #2518 TreeRepository.findDescendantsTree does not load (connections = await createTestingConnections({ entities: [__dirname + "/entity/*{.js,.ts}"], // data type text isn't compatible with oracle - enabledDrivers: ["postgres", "cockroachdb", "mariadb", "mssql", "mysql", "sqlite", "sqljs"] + enabledDrivers: ["postgres", "cockroachdb", "mariadb", "mssql", "mysql", "sqlite", "better-sqlite3", "sqljs"] })) ); diff --git a/test/github-issues/2733/issue-2733.ts b/test/github-issues/2733/issue-2733.ts index 02ff1074bf0..bb4c1eb6cb6 100644 --- a/test/github-issues/2733/issue-2733.ts +++ b/test/github-issues/2733/issue-2733.ts @@ -12,7 +12,7 @@ describe("github issues > #2733 should correctly handle function calls with uper entities: [__dirname + "/entity/MSSQLDummy{.js,.ts}"], schemaCreate: true, dropSchema: true, - enabledDrivers: ["mssql", "sqljs", "sqlite"], + enabledDrivers: ["mssql", "sqljs", "sqlite", "better-sqlite3"], }); await reloadTestingDatabases(connections); await Promise.all(connections.map(async connection => { diff --git a/test/github-issues/3158/issue-3158.ts b/test/github-issues/3158/issue-3158.ts index d074678c769..7f26cc6da9e 100644 --- a/test/github-issues/3158/issue-3158.ts +++ b/test/github-issues/3158/issue-3158.ts @@ -8,7 +8,7 @@ it("github issues > #3158 Cannot run sync a second time", async () => { entities: [__dirname + "/entity/*{.js,.ts}"], schemaCreate: true, dropSchema: true, - enabledDrivers: ["mysql", "mariadb", "oracle", "mssql", "sqljs", "sqlite"], + enabledDrivers: ["mysql", "mariadb", "oracle", "mssql", "sqljs", "sqlite", "better-sqlite3"], // todo(AlexMesser): check why tests are failing under postgres driver }); await reloadTestingDatabases(connections); diff --git a/test/github-issues/3949/issue-3949.ts b/test/github-issues/3949/issue-3949.ts index 1e89826a45c..a2bf94e9171 100644 --- a/test/github-issues/3949/issue-3949.ts +++ b/test/github-issues/3949/issue-3949.ts @@ -11,7 +11,7 @@ describe("github issues > #3949 sqlite date hydration is susceptible to corrupti entities: [__dirname + "/entity/*{.js,.ts}"], schemaCreate: true, dropSchema: true, - enabledDrivers: ["sqlite", "sqljs"], + enabledDrivers: ["sqlite", "better-sqlite3", "sqljs"], }); }); beforeEach(() => reloadTestingDatabases(connections)); diff --git a/test/github-issues/4096/issue-4096.ts b/test/github-issues/4096/issue-4096.ts index 3685d0d17a3..40f200f209d 100644 --- a/test/github-issues/4096/issue-4096.ts +++ b/test/github-issues/4096/issue-4096.ts @@ -9,7 +9,7 @@ describe("github issues > #4096 SQLite support for orUpdate", () => { before(async () => connections = await createTestingConnections({ entities: [User], - enabledDrivers: ["sqlite"], + enabledDrivers: ["sqlite", "better-sqlite3"], schemaCreate: true, dropSchema: true, })); diff --git a/test/github-issues/4147/issue-4147.ts b/test/github-issues/4147/issue-4147.ts index d57a645e72a..43b52aa1527 100644 --- a/test/github-issues/4147/issue-4147.ts +++ b/test/github-issues/4147/issue-4147.ts @@ -14,7 +14,7 @@ describe("github issues > #4147 `SQLITE_ERROR: near \"-\": syntax error` when us (connections = await createTestingConnections({ entities: [new EntitySchema(PostSchema)], dropSchema: true, - enabledDrivers: ["sqlite"] + enabledDrivers: ["sqlite", "better-sqlite3"] })) ); beforeEach(() => reloadTestingDatabases(connections)); diff --git a/test/github-issues/513/issue-513.ts b/test/github-issues/513/issue-513.ts index be0cf0b754e..5d039ca8087 100644 --- a/test/github-issues/513/issue-513.ts +++ b/test/github-issues/513/issue-513.ts @@ -11,7 +11,7 @@ describe("github issues > #513 Incorrect time/datetime types for SQLite", () => let connections: Connection[]; before(async () => connections = await createTestingConnections({ entities: [__dirname + "/entity/*{.js,.ts}"], - enabledDrivers: ["sqlite"] + enabledDrivers: ["sqlite", "better-sqlite3"] })); beforeEach(() => reloadTestingDatabases(connections)); after(() => closeTestingConnections(connections)); diff --git a/test/github-issues/798/issue-798.ts b/test/github-issues/798/issue-798.ts index 445cbb31263..34a05c6775b 100644 --- a/test/github-issues/798/issue-798.ts +++ b/test/github-issues/798/issue-798.ts @@ -28,4 +28,11 @@ describe("github issues > #798 sqlite: 'database' path in ormconfig.json is not assert.strictEqual(connection.isConnected, true); }); + it("should find the sqlite database if the cwd is changed for better-sqlite3", async function () { + const options = await getConnectionOptions("better-sqlite3"); + connection = await createConnection(options); + + assert.strictEqual(connection.isConnected, true); + }); + }); \ No newline at end of file diff --git a/test/github-issues/799/issue-799.ts b/test/github-issues/799/issue-799.ts index 28152caff3b..d87a1c2ec4f 100644 --- a/test/github-issues/799/issue-799.ts +++ b/test/github-issues/799/issue-799.ts @@ -34,4 +34,14 @@ describe("github issues > #799 sqlite: 'database' path should be created", () => assert.strictEqual(connection.isConnected, true); }); + it("should create the whole path to database file for better-sqlite3", async function () { + connection = await createConnection({ + "name": "better-sqlite3", + "type": "better-sqlite3", + "database": path + }); + + assert.strictEqual(connection.isConnected, true); + }); + }); From c6ae601fcb459c9df2da7f093071fd44b530ebfd Mon Sep 17 00:00:00 2001 From: James Ward Date: Mon, 20 Jul 2020 22:26:22 -0400 Subject: [PATCH 012/212] style: use LF instead of CRLF in BetterSqlite3 modules (#6433) --- .../better-sqlite3/BetterSqlite3Driver.ts | 282 +++++++++--------- .../BetterSqlite3QueryRunner.ts | 210 ++++++------- 2 files changed, 246 insertions(+), 246 deletions(-) diff --git a/src/driver/better-sqlite3/BetterSqlite3Driver.ts b/src/driver/better-sqlite3/BetterSqlite3Driver.ts index 814b093d7ac..46531164535 100644 --- a/src/driver/better-sqlite3/BetterSqlite3Driver.ts +++ b/src/driver/better-sqlite3/BetterSqlite3Driver.ts @@ -1,141 +1,141 @@ -import { DriverPackageNotInstalledError } from "../../error/DriverPackageNotInstalledError"; -import { DriverOptionNotSetError } from "../../error/DriverOptionNotSetError"; -import { PlatformTools } from "../../platform/PlatformTools"; -import { Connection } from "../../connection/Connection"; -import { ColumnType } from "../types/ColumnTypes"; -import { QueryRunner } from "../../query-runner/QueryRunner"; -import { AbstractSqliteDriver } from "../sqlite-abstract/AbstractSqliteDriver"; -import { BetterSqlite3ConnectionOptions } from "./BetterSqlite3ConnectionOptions"; -import { BetterSqlite3QueryRunner } from "./BetterSqlite3QueryRunner"; - -/** - * Organizes communication with sqlite DBMS. - */ -export class BetterSqlite3Driver extends AbstractSqliteDriver { - - // ------------------------------------------------------------------------- - // Public Implemented Properties - // ------------------------------------------------------------------------- - - /** - * Connection options. - */ - options: BetterSqlite3ConnectionOptions; - - /** - * SQLite underlying library. - */ - sqlite: any; - - // ------------------------------------------------------------------------- - // Constructor - // ------------------------------------------------------------------------- - - constructor(connection: Connection) { - super(connection); - - this.connection = connection; - this.options = connection.options as BetterSqlite3ConnectionOptions; - this.database = this.options.database; - - // validate options to make sure everything is set - if (!this.options.database) - throw new DriverOptionNotSetError("database"); - - // load sqlite package - this.loadDependencies(); - } - - // ------------------------------------------------------------------------- - // Public Methods - // ------------------------------------------------------------------------- - - /** - * Closes connection with database. - */ - async disconnect(): Promise { - this.queryRunner = undefined; - this.databaseConnection.close(); - } - - /** - * Creates a query runner used to execute database queries. - */ - createQueryRunner(mode: "master" | "slave" = "master"): QueryRunner { - if (!this.queryRunner) - this.queryRunner = new BetterSqlite3QueryRunner(this); - - return this.queryRunner; - } - - normalizeType(column: { type?: ColumnType, length?: number | string, precision?: number | null, scale?: number }): string { - if ((column.type as any) === Buffer) { - return "blob"; - } - - return super.normalizeType(column); - } - - // ------------------------------------------------------------------------- - // Protected Methods - // ------------------------------------------------------------------------- - - /** - * Creates connection with the database. - */ - protected async createDatabaseConnection() { - // not to create database directory if is in memory - if (this.options.database !== ":memory:") - await this.createDatabaseDirectory(this.options.database); - - const { - database, - readonly = false, - fileMustExist = false, - timeout = 5000, - verbose = null, - prepareDatabase - } = this.options; - const databaseConnection = this.sqlite(database, { readonly, fileMustExist, timeout, verbose }); - - // we need to enable foreign keys in sqlite to make sure all foreign key related features - // working properly. this also makes onDelete to work with sqlite. - databaseConnection.exec(`PRAGMA foreign_keys = ON`); - - // turn on WAL mode to enhance performance - databaseConnection.exec(`PRAGMA journal_mode = WAL`); - - // in the options, if encryption key for SQLCipher is setted. - if (this.options.key) { - databaseConnection.exec(`PRAGMA key = ${JSON.stringify(this.options.key)}`); - } - - if (typeof prepareDatabase === "function") { - prepareDatabase(databaseConnection); - } - - return databaseConnection; - } - - /** - * If driver dependency is not given explicitly, then try to load it via "require". - */ - protected loadDependencies(): void { - try { - this.sqlite = PlatformTools.load("better-sqlite3"); - - } catch (e) { - throw new DriverPackageNotInstalledError("SQLite", "better-sqlite3"); - } - } - - /** - * Auto creates database directory if it does not exist. - */ - protected createDatabaseDirectory(fullPath: string): Promise { - const mkdirp = PlatformTools.load("mkdirp"); - const path = PlatformTools.load("path"); - return mkdirp(path.dirname(fullPath)); - } - -} +import { DriverPackageNotInstalledError } from "../../error/DriverPackageNotInstalledError"; +import { DriverOptionNotSetError } from "../../error/DriverOptionNotSetError"; +import { PlatformTools } from "../../platform/PlatformTools"; +import { Connection } from "../../connection/Connection"; +import { ColumnType } from "../types/ColumnTypes"; +import { QueryRunner } from "../../query-runner/QueryRunner"; +import { AbstractSqliteDriver } from "../sqlite-abstract/AbstractSqliteDriver"; +import { BetterSqlite3ConnectionOptions } from "./BetterSqlite3ConnectionOptions"; +import { BetterSqlite3QueryRunner } from "./BetterSqlite3QueryRunner"; + +/** + * Organizes communication with sqlite DBMS. + */ +export class BetterSqlite3Driver extends AbstractSqliteDriver { + + // ------------------------------------------------------------------------- + // Public Implemented Properties + // ------------------------------------------------------------------------- + + /** + * Connection options. + */ + options: BetterSqlite3ConnectionOptions; + + /** + * SQLite underlying library. + */ + sqlite: any; + + // ------------------------------------------------------------------------- + // Constructor + // ------------------------------------------------------------------------- + + constructor(connection: Connection) { + super(connection); + + this.connection = connection; + this.options = connection.options as BetterSqlite3ConnectionOptions; + this.database = this.options.database; + + // validate options to make sure everything is set + if (!this.options.database) + throw new DriverOptionNotSetError("database"); + + // load sqlite package + this.loadDependencies(); + } + + // ------------------------------------------------------------------------- + // Public Methods + // ------------------------------------------------------------------------- + + /** + * Closes connection with database. + */ + async disconnect(): Promise { + this.queryRunner = undefined; + this.databaseConnection.close(); + } + + /** + * Creates a query runner used to execute database queries. + */ + createQueryRunner(mode: "master" | "slave" = "master"): QueryRunner { + if (!this.queryRunner) + this.queryRunner = new BetterSqlite3QueryRunner(this); + + return this.queryRunner; + } + + normalizeType(column: { type?: ColumnType, length?: number | string, precision?: number | null, scale?: number }): string { + if ((column.type as any) === Buffer) { + return "blob"; + } + + return super.normalizeType(column); + } + + // ------------------------------------------------------------------------- + // Protected Methods + // ------------------------------------------------------------------------- + + /** + * Creates connection with the database. + */ + protected async createDatabaseConnection() { + // not to create database directory if is in memory + if (this.options.database !== ":memory:") + await this.createDatabaseDirectory(this.options.database); + + const { + database, + readonly = false, + fileMustExist = false, + timeout = 5000, + verbose = null, + prepareDatabase + } = this.options; + const databaseConnection = this.sqlite(database, { readonly, fileMustExist, timeout, verbose }); + + // we need to enable foreign keys in sqlite to make sure all foreign key related features + // working properly. this also makes onDelete to work with sqlite. + databaseConnection.exec(`PRAGMA foreign_keys = ON`); + + // turn on WAL mode to enhance performance + databaseConnection.exec(`PRAGMA journal_mode = WAL`); + + // in the options, if encryption key for SQLCipher is setted. + if (this.options.key) { + databaseConnection.exec(`PRAGMA key = ${JSON.stringify(this.options.key)}`); + } + + if (typeof prepareDatabase === "function") { + prepareDatabase(databaseConnection); + } + + return databaseConnection; + } + + /** + * If driver dependency is not given explicitly, then try to load it via "require". + */ + protected loadDependencies(): void { + try { + this.sqlite = PlatformTools.load("better-sqlite3"); + + } catch (e) { + throw new DriverPackageNotInstalledError("SQLite", "better-sqlite3"); + } + } + + /** + * Auto creates database directory if it does not exist. + */ + protected createDatabaseDirectory(fullPath: string): Promise { + const mkdirp = PlatformTools.load("mkdirp"); + const path = PlatformTools.load("path"); + return mkdirp(path.dirname(fullPath)); + } + +} diff --git a/src/driver/better-sqlite3/BetterSqlite3QueryRunner.ts b/src/driver/better-sqlite3/BetterSqlite3QueryRunner.ts index b508fc6b71f..7df796ade48 100644 --- a/src/driver/better-sqlite3/BetterSqlite3QueryRunner.ts +++ b/src/driver/better-sqlite3/BetterSqlite3QueryRunner.ts @@ -1,106 +1,106 @@ -import { QueryRunnerAlreadyReleasedError } from "../../error/QueryRunnerAlreadyReleasedError"; -import { QueryFailedError } from "../../error/QueryFailedError"; -import { AbstractSqliteQueryRunner } from "../sqlite-abstract/AbstractSqliteQueryRunner"; -import { Broadcaster } from "../../subscriber/Broadcaster"; -import { BetterSqlite3Driver } from "./BetterSqlite3Driver"; - -/** - * Runs queries on a single sqlite database connection. - * - * Does not support compose primary keys with autoincrement field. - * todo: need to throw exception for this case. - */ -export class BetterSqlite3QueryRunner extends AbstractSqliteQueryRunner { - - /** - * Database driver used by connection. - */ - driver: BetterSqlite3Driver; - - // ------------------------------------------------------------------------- - // Constructor - // ------------------------------------------------------------------------- - - constructor(driver: BetterSqlite3Driver) { - super(); - this.driver = driver; - this.connection = driver.connection; - this.broadcaster = new Broadcaster(this); - if (typeof this.driver.options.statementCacheSize === "number") { - this.cacheSize = this.driver.options.statementCacheSize; - } else { - this.cacheSize = 100; - } - } - - private cacheSize: number; - private stmtCache = new Map(); - - private async getStmt(query: string) { - if (this.cacheSize > 0) { - let stmt = this.stmtCache.get(query); - if (!stmt) { - const databaseConnection = await this.connect(); - stmt = databaseConnection.prepare(query); - this.stmtCache.set(query, stmt); - while (this.stmtCache.size > this.cacheSize) { - // since es6 map keeps the insertion order, - // it comes to be FIFO cache - const key = this.stmtCache.keys().next().value; - this.stmtCache.delete(key); - } - } - return stmt; - } else { - const databaseConnection = await this.connect(); - return databaseConnection.prepare(query); - } - } - - /** - * Executes a given SQL query. - */ - async query(query: string, parameters?: any[]): Promise { - if (this.isReleased) - throw new QueryRunnerAlreadyReleasedError(); - - const connection = this.driver.connection; - - parameters = parameters || []; - for (let i = 0; i < parameters.length; i++) { - // in "where" clauses the parameters are not escaped by the driver - if (typeof parameters[i] === "boolean") - parameters[i] = +parameters[i]; - } - - this.driver.connection.logger.logQuery(query, parameters, this); - const queryStartTime = +new Date(); - - const stmt = await this.getStmt(query); - - try { - - let result: any; - if (stmt.reader) { - result = stmt.all.apply(stmt, parameters); - } else { - result = stmt.run.apply(stmt, parameters); - if (query.substr(0, 6) === "INSERT") { - result = result.lastInsertRowid; - } - } - - // log slow queries if maxQueryExecution time is set - const maxQueryExecutionTime = connection.options.maxQueryExecutionTime; - const queryEndTime = +new Date(); - const queryExecutionTime = queryEndTime - queryStartTime; - if (maxQueryExecutionTime && queryExecutionTime > maxQueryExecutionTime) - connection.logger.logQuerySlow(queryExecutionTime, query, parameters, this); - - return result; - } catch (err) { - connection.logger.logQueryError(err, query, parameters, this); - throw new QueryFailedError(query, parameters, err); - } - } +import { QueryRunnerAlreadyReleasedError } from "../../error/QueryRunnerAlreadyReleasedError"; +import { QueryFailedError } from "../../error/QueryFailedError"; +import { AbstractSqliteQueryRunner } from "../sqlite-abstract/AbstractSqliteQueryRunner"; +import { Broadcaster } from "../../subscriber/Broadcaster"; +import { BetterSqlite3Driver } from "./BetterSqlite3Driver"; + +/** + * Runs queries on a single sqlite database connection. + * + * Does not support compose primary keys with autoincrement field. + * todo: need to throw exception for this case. + */ +export class BetterSqlite3QueryRunner extends AbstractSqliteQueryRunner { + + /** + * Database driver used by connection. + */ + driver: BetterSqlite3Driver; + + // ------------------------------------------------------------------------- + // Constructor + // ------------------------------------------------------------------------- + + constructor(driver: BetterSqlite3Driver) { + super(); + this.driver = driver; + this.connection = driver.connection; + this.broadcaster = new Broadcaster(this); + if (typeof this.driver.options.statementCacheSize === "number") { + this.cacheSize = this.driver.options.statementCacheSize; + } else { + this.cacheSize = 100; + } + } + + private cacheSize: number; + private stmtCache = new Map(); + + private async getStmt(query: string) { + if (this.cacheSize > 0) { + let stmt = this.stmtCache.get(query); + if (!stmt) { + const databaseConnection = await this.connect(); + stmt = databaseConnection.prepare(query); + this.stmtCache.set(query, stmt); + while (this.stmtCache.size > this.cacheSize) { + // since es6 map keeps the insertion order, + // it comes to be FIFO cache + const key = this.stmtCache.keys().next().value; + this.stmtCache.delete(key); + } + } + return stmt; + } else { + const databaseConnection = await this.connect(); + return databaseConnection.prepare(query); + } + } + + /** + * Executes a given SQL query. + */ + async query(query: string, parameters?: any[]): Promise { + if (this.isReleased) + throw new QueryRunnerAlreadyReleasedError(); + + const connection = this.driver.connection; + + parameters = parameters || []; + for (let i = 0; i < parameters.length; i++) { + // in "where" clauses the parameters are not escaped by the driver + if (typeof parameters[i] === "boolean") + parameters[i] = +parameters[i]; + } + + this.driver.connection.logger.logQuery(query, parameters, this); + const queryStartTime = +new Date(); + + const stmt = await this.getStmt(query); + + try { + + let result: any; + if (stmt.reader) { + result = stmt.all.apply(stmt, parameters); + } else { + result = stmt.run.apply(stmt, parameters); + if (query.substr(0, 6) === "INSERT") { + result = result.lastInsertRowid; + } + } + + // log slow queries if maxQueryExecution time is set + const maxQueryExecutionTime = connection.options.maxQueryExecutionTime; + const queryEndTime = +new Date(); + const queryExecutionTime = queryEndTime - queryStartTime; + if (maxQueryExecutionTime && queryExecutionTime > maxQueryExecutionTime) + connection.logger.logQuerySlow(queryExecutionTime, query, parameters, this); + + return result; + } catch (err) { + connection.logger.logQueryError(err, query, parameters, this); + throw new QueryFailedError(query, parameters, err); + } + } } \ No newline at end of file From 9abab82d51e3b76d717f2f473cbf3e4d96f51488 Mon Sep 17 00:00:00 2001 From: Arseny Yankovsky Date: Tue, 21 Jul 2020 04:49:35 +0200 Subject: [PATCH 013/212] fix: pass formatOptions to Data API Client, fix extensions (#6404) * fix(aurora): pass formatOptions to Data API Client, fix UUID type support and all other extensions * fix(aurora): refactored the code to avoid duplication (#1) * fix(aurora): refactored the code to avoid duplication --- src/driver/DriverFactory.ts | 3 +- .../AuroraDataApiPostgresConnectionOptions.ts | 2 + .../AuroraDataApiConnectionOptions.ts | 2 + .../aurora-data-api/AuroraDataApiDriver.ts | 3 +- src/driver/postgres/PostgresDriver.ts | 149 +++++++++++------- 5 files changed, 101 insertions(+), 58 deletions(-) diff --git a/src/driver/DriverFactory.ts b/src/driver/DriverFactory.ts index 3d6456b3bc4..e3eed40e59b 100644 --- a/src/driver/DriverFactory.ts +++ b/src/driver/DriverFactory.ts @@ -9,13 +9,12 @@ import {ReactNativeDriver} from "./react-native/ReactNativeDriver"; import {NativescriptDriver} from "./nativescript/NativescriptDriver"; import {SqljsDriver} from "./sqljs/SqljsDriver"; import {MysqlDriver} from "./mysql/MysqlDriver"; -import {PostgresDriver} from "./postgres/PostgresDriver"; +import {PostgresDriver, AuroraDataApiPostgresDriver} from "./postgres/PostgresDriver"; import {ExpoDriver} from "./expo/ExpoDriver"; import {AuroraDataApiDriver} from "./aurora-data-api/AuroraDataApiDriver"; import {Driver} from "./Driver"; import {Connection} from "../connection/Connection"; import {SapDriver} from "./sap/SapDriver"; -import {AuroraDataApiPostgresDriver} from "./postgres/PostgresDriver"; import {BetterSqlite3Driver} from "./better-sqlite3/BetterSqlite3Driver"; /** diff --git a/src/driver/aurora-data-api-pg/AuroraDataApiPostgresConnectionOptions.ts b/src/driver/aurora-data-api-pg/AuroraDataApiPostgresConnectionOptions.ts index f8d30d4f55a..18078aed828 100644 --- a/src/driver/aurora-data-api-pg/AuroraDataApiPostgresConnectionOptions.ts +++ b/src/driver/aurora-data-api-pg/AuroraDataApiPostgresConnectionOptions.ts @@ -33,4 +33,6 @@ export interface AuroraDataApiPostgresConnectionOptions extends BaseConnectionOp readonly poolErrorHandler?: (err: any) => any; readonly serviceConfigOptions?: { [key: string]: any }; + + readonly formatOptions?: { [key: string]: any }; } diff --git a/src/driver/aurora-data-api/AuroraDataApiConnectionOptions.ts b/src/driver/aurora-data-api/AuroraDataApiConnectionOptions.ts index d9468d1e366..5e5722c2272 100644 --- a/src/driver/aurora-data-api/AuroraDataApiConnectionOptions.ts +++ b/src/driver/aurora-data-api/AuroraDataApiConnectionOptions.ts @@ -23,6 +23,8 @@ export interface AuroraDataApiConnectionOptions extends BaseConnectionOptions, A readonly serviceConfigOptions?: { [key: string]: any }; // pass optional AWS.ConfigurationOptions here + readonly formatOptions?: { [key: string]: any }; + /** * Use spatial functions like GeomFromText and AsText which are removed in MySQL 8. * (Default: true) diff --git a/src/driver/aurora-data-api/AuroraDataApiDriver.ts b/src/driver/aurora-data-api/AuroraDataApiDriver.ts index 89b93ccc039..901ff224359 100644 --- a/src/driver/aurora-data-api/AuroraDataApiDriver.ts +++ b/src/driver/aurora-data-api/AuroraDataApiDriver.ts @@ -306,7 +306,8 @@ export class AuroraDataApiDriver implements Driver { this.options.resourceArn, this.options.database, (query: string, parameters?: any[]) => this.connection.logger.logQuery(query, parameters), - this.options.serviceConfigOptions + this.options.serviceConfigOptions, + this.options.formatOptions, ); // validate options to make sure everything is set diff --git a/src/driver/postgres/PostgresDriver.ts b/src/driver/postgres/PostgresDriver.ts index b45ac1c9355..5aa25b585db 100644 --- a/src/driver/postgres/PostgresDriver.ts +++ b/src/driver/postgres/PostgresDriver.ts @@ -301,6 +301,76 @@ export class PostgresDriver implements Driver { * Makes any action after connection (e.g. create extensions in Postgres driver). */ async afterConnect(): Promise { + const extensionsMetadata = await this.checkMetadataForExtensions(); + + if (extensionsMetadata.hasExtensions) { + await Promise.all([this.master, ...this.slaves].map(pool => { + return new Promise((ok, fail) => { + pool.connect(async (err: any, connection: any, release: Function) => { + await this.enableExtensions(extensionsMetadata, connection); + if (err) return fail(err); + release(); + ok(); + }); + }); + })); + } + + return Promise.resolve(); + } + + protected async enableExtensions(extensionsMetadata: any, connection: any) { + const { logger } = this.connection; + + const { + hasUuidColumns, + hasCitextColumns, + hasHstoreColumns, + hasCubeColumns, + hasGeometryColumns, + hasExclusionConstraints, + } = extensionsMetadata; + + if (hasUuidColumns) + try { + await this.executeQuery(connection, `CREATE EXTENSION IF NOT EXISTS "${this.options.uuidExtension || "uuid-ossp"}"`); + } catch (_) { + logger.log("warn", `At least one of the entities has uuid column, but the '${this.options.uuidExtension || "uuid-ossp"}' extension cannot be installed automatically. Please install it manually using superuser rights, or select another uuid extension.`); + } + if (hasCitextColumns) + try { + await this.executeQuery(connection, `CREATE EXTENSION IF NOT EXISTS "citext"`); + } catch (_) { + logger.log("warn", "At least one of the entities has citext column, but the 'citext' extension cannot be installed automatically. Please install it manually using superuser rights"); + } + if (hasHstoreColumns) + try { + await this.executeQuery(connection, `CREATE EXTENSION IF NOT EXISTS "hstore"`); + } catch (_) { + logger.log("warn", "At least one of the entities has hstore column, but the 'hstore' extension cannot be installed automatically. Please install it manually using superuser rights"); + } + if (hasGeometryColumns) + try { + await this.executeQuery(connection, `CREATE EXTENSION IF NOT EXISTS "postgis"`); + } catch (_) { + logger.log("warn", "At least one of the entities has a geometry column, but the 'postgis' extension cannot be installed automatically. Please install it manually using superuser rights"); + } + if (hasCubeColumns) + try { + await this.executeQuery(connection, `CREATE EXTENSION IF NOT EXISTS "cube"`); + } catch (_) { + logger.log("warn", "At least one of the entities has a cube column, but the 'cube' extension cannot be installed automatically. Please install it manually using superuser rights"); + } + if (hasExclusionConstraints) + try { + // The btree_gist extension provides operator support in PostgreSQL exclusion constraints + await this.executeQuery(connection, `CREATE EXTENSION IF NOT EXISTS "btree_gist"`); + } catch (_) { + logger.log("warn", "At least one of the entities has an exclusion constraint, but the 'btree_gist' extension cannot be installed automatically. Please install it manually using superuser rights"); + } + } + + protected async checkMetadataForExtensions() { const hasUuidColumns = this.connection.entityMetadatas.some(metadata => { return metadata.generatedColumns.filter(column => column.generationStrategy === "uuid").length > 0; }); @@ -319,57 +389,16 @@ export class PostgresDriver implements Driver { const hasExclusionConstraints = this.connection.entityMetadatas.some(metadata => { return metadata.exclusions.length > 0; }); - if (hasUuidColumns || hasCitextColumns || hasHstoreColumns || hasGeometryColumns || hasCubeColumns || hasExclusionConstraints) { - await Promise.all([this.master, ...this.slaves].map(pool => { - return new Promise((ok, fail) => { - pool.connect(async (err: any, connection: any, release: Function) => { - const { logger } = this.connection; - if (err) return fail(err); - if (hasUuidColumns) - try { - await this.executeQuery(connection, `CREATE EXTENSION IF NOT EXISTS "${this.options.uuidExtension || "uuid-ossp"}"`); - } catch (_) { - logger.log("warn", `At least one of the entities has uuid column, but the '${this.options.uuidExtension || "uuid-ossp"}' extension cannot be installed automatically. Please install it manually using superuser rights, or select another uuid extension.`); - } - if (hasCitextColumns) - try { - await this.executeQuery(connection, `CREATE EXTENSION IF NOT EXISTS "citext"`); - } catch (_) { - logger.log("warn", "At least one of the entities has citext column, but the 'citext' extension cannot be installed automatically. Please install it manually using superuser rights"); - } - if (hasHstoreColumns) - try { - await this.executeQuery(connection, `CREATE EXTENSION IF NOT EXISTS "hstore"`); - } catch (_) { - logger.log("warn", "At least one of the entities has hstore column, but the 'hstore' extension cannot be installed automatically. Please install it manually using superuser rights"); - } - if (hasGeometryColumns) - try { - await this.executeQuery(connection, `CREATE EXTENSION IF NOT EXISTS "postgis"`); - } catch (_) { - logger.log("warn", "At least one of the entities has a geometry column, but the 'postgis' extension cannot be installed automatically. Please install it manually using superuser rights"); - } - if (hasCubeColumns) - try { - await this.executeQuery(connection, `CREATE EXTENSION IF NOT EXISTS "cube"`); - } catch (_) { - logger.log("warn", "At least one of the entities has a cube column, but the 'cube' extension cannot be installed automatically. Please install it manually using superuser rights"); - } - if (hasExclusionConstraints) - try { - // The btree_gist extension provides operator support in PostgreSQL exclusion constraints - await this.executeQuery(connection, `CREATE EXTENSION IF NOT EXISTS "btree_gist"`); - } catch (_) { - logger.log("warn", "At least one of the entities has an exclusion constraint, but the 'btree_gist' extension cannot be installed automatically. Please install it manually using superuser rights"); - } - release(); - ok(); - }); - }); - })); - } - return Promise.resolve(); + return { + hasUuidColumns, + hasCitextColumns, + hasHstoreColumns, + hasCubeColumns, + hasGeometryColumns, + hasExclusionConstraints, + hasExtensions: hasUuidColumns || hasCitextColumns || hasHstoreColumns || hasGeometryColumns || hasCubeColumns || hasExclusionConstraints, + }; } /** @@ -395,7 +424,7 @@ export class PostgresDriver implements Driver { /** * Creates a query runner used to execute database queries. */ - createQueryRunner(mode: "master"|"slave" = "master") { + createQueryRunner(mode: "master"|"slave" = "master"): QueryRunner { return new PostgresQueryRunner(this, mode); } @@ -987,9 +1016,6 @@ abstract class PostgresWrapper extends PostgresDriver { abstract createQueryRunner(mode: "master"|"slave"): any; } -/** - * Organizes communication with PostgreSQL DBMS. - */ export class AuroraDataApiPostgresDriver extends PostgresWrapper { // ------------------------------------------------------------------------- @@ -1041,7 +1067,8 @@ export class AuroraDataApiPostgresDriver extends PostgresWrapper { this.options.resourceArn, this.options.database, (query: string, parameters?: any[]) => this.connection.logger.logQuery(query, parameters), - this.options.serviceConfigOptions + this.options.serviceConfigOptions, + this.options.formatOptions, ); } @@ -1090,4 +1117,16 @@ export class AuroraDataApiPostgresDriver extends PostgresWrapper { return this.client.query(query); } + /** + * Makes any action after connection (e.g. create extensions in Postgres driver). + */ + async afterConnect(): Promise { + const extensionsMetadata = await this.checkMetadataForExtensions(); + + if (extensionsMetadata.hasExtensions) { + await this.enableExtensions(extensionsMetadata, this.connection); + } + + return Promise.resolve(); + } } From 9d82a45fadc8d7e593afbe85212191dee7f22529 Mon Sep 17 00:00:00 2001 From: Umed Khudoiberdiev Date: Fri, 24 Jul 2020 12:10:33 +0300 Subject: [PATCH 014/212] added sponsors section --- README.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 380eb853def..73f8855d9bb 100644 --- a/README.md +++ b/README.md @@ -38,8 +38,13 @@ maintainable applications the most productive way. TypeORM is highly influenced by other ORMs, such as [Hibernate](http://hibernate.org/orm/), [Doctrine](http://www.doctrine-project.org/) and [Entity Framework](https://www.asp.net/entity-framework). + + ## TypeORM sponsors + +TypeORM is being sponsored by the following partner: + -Some TypeORM features: +## TypeORM features * supports both [DataMapper](./docs/active-record-data-mapper.md#what-is-the-data-mapper-pattern) and [ActiveRecord](./docs/active-record-data-mapper.md#what-is-the-active-record-pattern) (your choice) * entities and columns From 83eb25ef23b8579cb3b343ebca4db8f588886ac0 Mon Sep 17 00:00:00 2001 From: Umed Khudoiberdiev Date: Fri, 24 Jul 2020 14:19:57 +0300 Subject: [PATCH 015/212] updated sponsors section --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 73f8855d9bb..55d3bc8f59c 100644 --- a/README.md +++ b/README.md @@ -39,12 +39,12 @@ maintainable applications the most productive way. TypeORM is highly influenced by other ORMs, such as [Hibernate](http://hibernate.org/orm/), [Doctrine](http://www.doctrine-project.org/) and [Entity Framework](https://www.asp.net/entity-framework). - ## TypeORM sponsors + ## Sponsors TypeORM is being sponsored by the following partner: - + -## TypeORM features +## Features * supports both [DataMapper](./docs/active-record-data-mapper.md#what-is-the-data-mapper-pattern) and [ActiveRecord](./docs/active-record-data-mapper.md#what-is-the-active-record-pattern) (your choice) * entities and columns From feeb7d1cd7fdda75b0c5668b1907c57f86a446a2 Mon Sep 17 00:00:00 2001 From: Umed Khudoiberdiev Date: Fri, 24 Jul 2020 14:21:23 +0300 Subject: [PATCH 016/212] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 55d3bc8f59c..43ea513eee6 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ TypeORM is highly influenced by other ORMs, such as [Hibernate](http://hibernate ## Sponsors TypeORM is being sponsored by the following partner: - + GitAds ## Features From 5e47caf4bde05323c4dcf2267dd46c580e0d84a0 Mon Sep 17 00:00:00 2001 From: Umed Khudoiberdiev Date: Fri, 24 Jul 2020 19:22:25 +0300 Subject: [PATCH 017/212] ads styling fixes --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 43ea513eee6..d15d8cee8ca 100644 --- a/README.md +++ b/README.md @@ -39,10 +39,10 @@ maintainable applications the most productive way. TypeORM is highly influenced by other ORMs, such as [Hibernate](http://hibernate.org/orm/), [Doctrine](http://www.doctrine-project.org/) and [Entity Framework](https://www.asp.net/entity-framework). - ## Sponsors +## Sponsors TypeORM is being sponsored by the following partner: - GitAds + GitAds ## Features From cc23ba2dd9dba30fed82613dd4d9e3d10a2e1519 Mon Sep 17 00:00:00 2001 From: Nathan Lapierre Date: Fri, 24 Jul 2020 09:41:17 -0700 Subject: [PATCH 018/212] docs: fix grammatical error (#6458) --- docs/supported-platforms.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/supported-platforms.md b/docs/supported-platforms.md index ce2b1d50045..aac244adc49 100644 --- a/docs/supported-platforms.md +++ b/docs/supported-platforms.md @@ -61,7 +61,7 @@ You have the option to choose between module loaders just like in browser packag For an example how to use TypeORM in Cordova see [typeorm/cordova-example](https://github.com/typeorm/cordova-example) and for Ionic see [typeorm/ionic-example](https://github.com/typeorm/ionic-example). **Important**: For use with Ionic, a custom webpack config file is needed! Please checkout the example to see the needed changes. ## React Native -TypeORM is able to on React Native apps using the [react-native-sqlite-storage](https://github.com/andpor/react-native-sqlite-storage) plugin. For an example see [typeom/react-native-example](https://github.com/typeorm/react-native-example). +TypeORM is able to run on React Native apps using the [react-native-sqlite-storage](https://github.com/andpor/react-native-sqlite-storage) plugin. For an example see [typeom/react-native-example](https://github.com/typeorm/react-native-example). ## Expo From 259ad0ee18a4f1a27c311b7405ef0c12c09e096c Mon Sep 17 00:00:00 2001 From: James Ward Date: Fri, 24 Jul 2020 12:45:43 -0400 Subject: [PATCH 019/212] chore: use eslint instead of tslint (#6452) --- .eslintrc.js | 54 ++ gulpfile.ts | 17 +- package-lock.json | 1446 ++++++++++++++++++++++++++++++++++++++------- package.json | 10 +- tslint.json | 54 -- 5 files changed, 1298 insertions(+), 283 deletions(-) create mode 100644 .eslintrc.js delete mode 100644 tslint.json diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 00000000000..6abd1a7f021 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,54 @@ +module.exports = { + "env": { + "node": true + }, + "parser": "@typescript-eslint/parser", + "parserOptions": { + "project": "tsconfig.json", + "sourceType": "module" + }, + "plugins": [ + "@typescript-eslint" + ], + "rules": { + "@typescript-eslint/no-unused-vars": [ + "error", + { + "args": "none" + } + ], + "@typescript-eslint/prefer-namespace-keyword": "error", + "@typescript-eslint/quotes": [ + "error", + "double", + { + "avoidEscape": true, + "allowTemplateLiterals": true + } + ], + "@typescript-eslint/semi": [ + "error" + ], + "@typescript-eslint/type-annotation-spacing": "error", + "eqeqeq": [ + "error", + "smart" + ], + "id-blacklist": [ + "error", + "any", + "Number", + "number", + "String", + "string", + "Boolean", + "boolean", + "Undefined", + "undefined" + ], + "id-match": "error", + "no-eval": "error", + "no-redeclare": "error", + "no-var": "error" + } +}; diff --git a/gulpfile.ts b/gulpfile.ts index de3dfcf1776..a0ba65cc980 100644 --- a/gulpfile.ts +++ b/gulpfile.ts @@ -11,7 +11,7 @@ const replace = require("gulp-replace"); const rename = require("gulp-rename"); const mocha = require("gulp-mocha"); const chai = require("chai"); -const tslint = require("gulp-tslint"); +const eslint = require("gulp-eslint"); const sourcemaps = require("gulp-sourcemaps"); const istanbul = require("gulp-istanbul"); const remapIstanbul = require("remap-istanbul/lib/gulpRemapIstanbul"); @@ -269,18 +269,11 @@ export class Gulpfile { * Runs ts linting to validate source code. */ @Task() - tslint() { + eslint() { return gulp.src(["./src/**/*.ts", "./test/**/*.ts", "./sample/**/*.ts"]) - .pipe( - tslint({ - formatter: "stylish" - }) - ) - .pipe(tslint.report({ - emitError: true, - sort: true, - bell: true - })); + .pipe(eslint()) + .pipe(eslint.format('stylish')) + .pipe(eslint.failAfterError()) } /** diff --git a/package-lock.json b/package-lock.json index cd9bfb8a68f..1502530dc5e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,6 +4,40 @@ "lockfileVersion": 1, "requires": true, "dependencies": { + "@babel/code-frame": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", + "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", + "dev": true, + "requires": { + "@babel/highlight": "^7.10.4" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz", + "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==", + "dev": true + }, + "@babel/highlight": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", + "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "dependencies": { + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + } + } + }, "@babel/runtime": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.0.0.tgz", @@ -181,24 +215,30 @@ "@types/node": "*" } }, + "@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==", + "dev": true + }, "@types/debug": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.2.tgz", "integrity": "sha512-jkf6UiWUjcOqdQbatbvOm54/YbCdjt3JjiAzT/9KS2XtMmOkYHdKsI5u8fulhbuTUuiqNBfa6J5GSDiwjK+zLA==", "dev": true }, + "@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/events": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@types/events/-/events-1.2.0.tgz", "integrity": "sha512-KEIlhXnIutzKwRbQkGWb/I4HFqBuUykAdHgDED6xqwXJfONCjF5VoE0cXEiurh3XauygxzeDzgtXUqvLkxFzzA==", "dev": true }, - "@types/fancy-log": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@types/fancy-log/-/fancy-log-1.3.0.tgz", - "integrity": "sha512-mQjDxyOM1Cpocd+vm1kZBP7smwKZ4TNokFeds9LV7OZibmPJFEzY3+xZMrKfUdNT71lv8GoCPD6upKwHxubClw==", - "dev": true - }, "@types/glob": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.1.tgz", @@ -231,6 +271,12 @@ "@types/vinyl-fs": "*" } }, + "@types/json-schema": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.5.tgz", + "integrity": "sha512-7+2BITlgjgDhH0vvwZU/HZJVyk+2XUlvxXe8dFMedNX/aMkaOq++rMAFXc0tM7ij15QaWlbdQASBR9dihi+bDQ==", + "dev": true + }, "@types/merge2": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/@types/merge2/-/merge2-1.1.4.tgz", @@ -335,6 +381,134 @@ "integrity": "sha512-sCZy4SxP9rN2w30Hlmg5dtdRwgYQfYRiLo9usw8X9cxlf+H4FqM1xX7+sNH7NNKVdbXMJWqva7iyy+fxh/V7fA==", "dev": true }, + "@typescript-eslint/eslint-plugin": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-3.7.0.tgz", + "integrity": "sha512-4OEcPON3QIx0ntsuiuFP/TkldmBGXf0uKxPQlGtS/W2F3ndYm8Vgdpj/woPJkzUc65gd3iR+qi3K8SDQP/obFg==", + "dev": true, + "requires": { + "@typescript-eslint/experimental-utils": "3.7.0", + "debug": "^4.1.1", + "functional-red-black-tree": "^1.0.1", + "regexpp": "^3.0.0", + "semver": "^7.3.2", + "tsutils": "^3.17.1" + }, + "dependencies": { + "semver": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", + "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", + "dev": true + }, + "tsutils": { + "version": "3.17.1", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.17.1.tgz", + "integrity": "sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + } + } + } + }, + "@typescript-eslint/experimental-utils": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-3.7.0.tgz", + "integrity": "sha512-xpfXXAfZqhhqs5RPQBfAFrWDHoNxD5+sVB5A46TF58Bq1hRfVROrWHcQHHUM9aCBdy9+cwATcvCbRg8aIRbaHQ==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.3", + "@typescript-eslint/types": "3.7.0", + "@typescript-eslint/typescript-estree": "3.7.0", + "eslint-scope": "^5.0.0", + "eslint-utils": "^2.0.0" + } + }, + "@typescript-eslint/parser": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-3.7.0.tgz", + "integrity": "sha512-2LZauVUt7jAWkcIW7djUc3kyW+fSarNEuM3RF2JdLHR9BfX/nDEnyA4/uWz0wseoWVZbDXDF7iF9Jc342flNqQ==", + "dev": true, + "requires": { + "@types/eslint-visitor-keys": "^1.0.0", + "@typescript-eslint/experimental-utils": "3.7.0", + "@typescript-eslint/types": "3.7.0", + "@typescript-eslint/typescript-estree": "3.7.0", + "eslint-visitor-keys": "^1.1.0" + } + }, + "@typescript-eslint/types": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-3.7.0.tgz", + "integrity": "sha512-reCaK+hyKkKF+itoylAnLzFeNYAEktB0XVfSQvf0gcVgpz1l49Lt6Vo9x4MVCCxiDydA0iLAjTF/ODH0pbfnpg==", + "dev": true + }, + "@typescript-eslint/typescript-estree": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-3.7.0.tgz", + "integrity": "sha512-xr5oobkYRebejlACGr1TJ0Z/r0a2/HUf0SXqPvlgUMwiMqOCu/J+/Dr9U3T0IxpE5oLFSkqMx1FE/dKaZ8KsOQ==", + "dev": true, + "requires": { + "@typescript-eslint/types": "3.7.0", + "@typescript-eslint/visitor-keys": "3.7.0", + "debug": "^4.1.1", + "glob": "^7.1.6", + "is-glob": "^4.0.1", + "lodash": "^4.17.15", + "semver": "^7.3.2", + "tsutils": "^3.17.1" + }, + "dependencies": { + "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" + } + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "semver": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", + "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", + "dev": true + }, + "tsutils": { + "version": "3.17.1", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.17.1.tgz", + "integrity": "sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + } + } + } + }, + "@typescript-eslint/visitor-keys": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-3.7.0.tgz", + "integrity": "sha512-k5PiZdB4vklUpUX4NBncn5RBKty8G3ihTY+hqJsCdMuD0v4jofI5xuqwnVcWxfv6iTm2P/dfEa2wMUnsUY8ODw==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + } + }, "JSONStream": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", @@ -357,6 +531,12 @@ "integrity": "sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg==", "dev": true }, + "acorn-jsx": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.2.0.tgz", + "integrity": "sha512-HiUX/+K2YpkpJ+SzBffkM/AQ2YE03S0U1kjTLVpoJdhZMOWy8qvXVN9JdLqv2QsaQ6MPYQIuNmwD8zOiYUofLQ==", + "dev": true + }, "add-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/add-stream/-/add-stream-1.0.0.tgz", @@ -688,6 +868,12 @@ "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", "dev": true }, + "astral-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "dev": true + }, "async": { "version": "1.5.2", "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", @@ -745,59 +931,6 @@ "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==", "dev": true }, - "babel-code-frame": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", - "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", - "dev": true, - "requires": { - "chalk": "^1.1.3", - "esutils": "^2.0.2", - "js-tokens": "^3.0.2" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true - }, - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true - } - } - }, "babel-runtime": { "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", @@ -1140,6 +1273,12 @@ "supports-color": "^5.3.0" } }, + "chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true + }, "check-error": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", @@ -1330,6 +1469,12 @@ } } }, + "cli-width": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", + "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", + "dev": true + }, "cliui": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", @@ -2122,6 +2267,15 @@ "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", "dev": true }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, "dot-prop": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-3.0.0.tgz", @@ -2199,6 +2353,23 @@ "once": "^1.4.0" } }, + "enquirer": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", + "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "dev": true, + "requires": { + "ansi-colors": "^4.1.1" + }, + "dependencies": { + "ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true + } + } + }, "error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -2313,11 +2484,336 @@ } } }, + "eslint": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.5.0.tgz", + "integrity": "sha512-vlUP10xse9sWt9SGRtcr1LAC67BENcQMFeV+w5EvLEoFe3xJ8cF1Skd0msziRx/VMC+72B4DxreCE+OR12OA6Q==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "enquirer": "^2.3.5", + "eslint-scope": "^5.1.0", + "eslint-utils": "^2.1.0", + "eslint-visitor-keys": "^1.3.0", + "espree": "^7.2.0", + "esquery": "^1.2.0", + "esutils": "^2.0.2", + "file-entry-cache": "^5.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.0.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash": "^4.17.19", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "progress": "^2.0.0", + "regexpp": "^3.1.0", + "semver": "^7.2.1", + "strip-ansi": "^6.0.0", + "strip-json-comments": "^3.1.0", + "table": "^5.2.3", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "dev": true, + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.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==", + "dev": true, + "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==", + "dev": true + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "glob-parent": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", + "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + }, + "dependencies": { + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + } + } + }, + "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 + }, + "import-fresh": { + "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", + "resolve-from": "^4.0.0" + } + }, + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, + "optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "requires": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + } + }, + "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 + }, + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true + }, + "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==", + "dev": true + }, + "semver": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", + "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", + "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 + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "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" + } + }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1" + } + }, + "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" + } + } + } + }, + "eslint-scope": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.0.tgz", + "integrity": "sha512-iiGRvtxWqgtx5m8EyQUJihBloE4EnYeGE/bz1wSPwJE6tZuJUtHlhqDM4Xj2ukE8Dyy1+HCZ4hE0fzIVMzb58w==", + "dev": true, + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + }, + "dependencies": { + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + } + } + }, + "eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + } + }, + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + }, + "espree": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.2.0.tgz", + "integrity": "sha512-H+cQ3+3JYRMEIOl87e7QdHX70ocly5iW4+dttuR8iYSPr/hXKFb+7dBsZ7+u1adC4VrnPlTkv0+OwuPnDop19g==", + "dev": true, + "requires": { + "acorn": "^7.3.1", + "acorn-jsx": "^5.2.0", + "eslint-visitor-keys": "^1.3.0" + }, + "dependencies": { + "acorn": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.3.1.tgz", + "integrity": "sha512-tLc0wSnatxAQHVHUapaHdz72pi9KUyHjq5KyHjGg9Y8Ifdc79pTh2XvI6I1/chZbnM7QtNKzh66ooDogPZSleA==", + "dev": true + } + } + }, "esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" }, + "esquery": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.3.1.tgz", + "integrity": "sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ==", + "dev": true, + "requires": { + "estraverse": "^5.1.0" + }, + "dependencies": { + "estraverse": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.1.0.tgz", + "integrity": "sha512-FyohXK+R0vE+y1nHLoBM7ZTyqRpqAlhdZHCWIWEviFLiGB8b04H6bQs8G+XTthacvT8VuwvteiP7RJSxMs8UEw==", + "dev": true + } + } + }, + "esrecurse": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", + "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", + "dev": true, + "requires": { + "estraverse": "^4.1.0" + }, + "dependencies": { + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + } + } + }, "estraverse": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz", @@ -2465,6 +2961,17 @@ } } }, + "external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "requires": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + } + }, "extglob": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", @@ -2581,6 +3088,15 @@ "object-assign": "^4.1.0" } }, + "file-entry-cache": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", + "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", + "dev": true, + "requires": { + "flat-cache": "^2.0.1" + } + }, "file-uri-to-path": { "version": "1.0.0", "resolved": "https://registry.npm.taobao.org/file-uri-to-path/download/file-uri-to-path-1.0.0.tgz", @@ -2683,6 +3199,23 @@ } } }, + "flat-cache": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", + "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", + "dev": true, + "requires": { + "flatted": "^2.0.0", + "rimraf": "2.6.3", + "write": "1.0.3" + } + }, + "flatted": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", + "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", + "dev": true + }, "flush-write-stream": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.0.3.tgz", @@ -2783,28 +3316,28 @@ "dependencies": { "abbrev": { "version": "1.1.1", - "resolved": false, + "resolved": "", "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", "dev": true, "optional": true }, "ansi-regex": { "version": "2.1.1", - "resolved": false, + "resolved": "", "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", "dev": true, "optional": true }, "aproba": { "version": "1.2.0", - "resolved": false, + "resolved": "", "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", "dev": true, "optional": true }, "are-we-there-yet": { "version": "1.1.4", - "resolved": false, + "resolved": "", "integrity": "sha1-u13KOCu5TwXhUZQ3PRb9O6HKEQ0=", "dev": true, "optional": true, @@ -2815,14 +3348,14 @@ }, "balanced-match": { "version": "1.0.0", - "resolved": false, + "resolved": "", "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", "dev": true, "optional": true }, "brace-expansion": { "version": "1.1.11", - "resolved": false, + "resolved": "", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "optional": true, @@ -2833,35 +3366,35 @@ }, "code-point-at": { "version": "1.1.0", - "resolved": false, + "resolved": "", "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", "dev": true, "optional": true }, "concat-map": { "version": "0.0.1", - "resolved": false, + "resolved": "", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true, "optional": true }, "console-control-strings": { "version": "1.1.0", - "resolved": false, + "resolved": "", "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", "dev": true, "optional": true }, "core-util-is": { "version": "1.0.2", - "resolved": false, + "resolved": "", "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", "dev": true, "optional": true }, "debug": { "version": "2.6.9", - "resolved": false, + "resolved": "", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "optional": true, @@ -2871,35 +3404,35 @@ }, "deep-extend": { "version": "0.5.1", - "resolved": false, + "resolved": "", "integrity": "sha512-N8vBdOa+DF7zkRrDCsaOXoCs/E2fJfx9B9MrKnnSiHNh4ws7eSys6YQE4KvT1cecKmOASYQBhbKjeuDD9lT81w==", "dev": true, "optional": true }, "delegates": { "version": "1.0.0", - "resolved": false, + "resolved": "", "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", "dev": true, "optional": true }, "detect-libc": { "version": "1.0.3", - "resolved": false, + "resolved": "", "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", "dev": true, "optional": true }, "fs.realpath": { "version": "1.0.0", - "resolved": false, + "resolved": "", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true, "optional": true }, "gauge": { "version": "2.7.4", - "resolved": false, + "resolved": "", "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", "dev": true, "optional": true, @@ -2916,7 +3449,7 @@ }, "glob": { "version": "7.1.2", - "resolved": false, + "resolved": "", "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", "dev": true, "optional": true, @@ -2931,14 +3464,14 @@ }, "has-unicode": { "version": "2.0.1", - "resolved": false, + "resolved": "", "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", "dev": true, "optional": true }, "iconv-lite": { "version": "0.4.21", - "resolved": false, + "resolved": "", "integrity": "sha512-En5V9za5mBt2oUA03WGD3TwDv0MKAruqsuxstbMUZaj9W9k/m1CV/9py3l0L5kw9Bln8fdHQmzHSYtvpvTLpKw==", "dev": true, "optional": true, @@ -2948,7 +3481,7 @@ }, "ignore-walk": { "version": "3.0.1", - "resolved": false, + "resolved": "", "integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==", "dev": true, "optional": true, @@ -2958,7 +3491,7 @@ }, "inflight": { "version": "1.0.6", - "resolved": false, + "resolved": "", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dev": true, "optional": true, @@ -2969,21 +3502,21 @@ }, "inherits": { "version": "2.0.3", - "resolved": false, + "resolved": "", "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", "dev": true, "optional": true }, "ini": { "version": "1.3.5", - "resolved": false, + "resolved": "", "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", "dev": true, "optional": true }, "is-fullwidth-code-point": { "version": "1.0.0", - "resolved": false, + "resolved": "", "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "dev": true, "optional": true, @@ -2993,14 +3526,14 @@ }, "isarray": { "version": "1.0.0", - "resolved": false, + "resolved": "", "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", "dev": true, "optional": true }, "minimatch": { "version": "3.0.4", - "resolved": false, + "resolved": "", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, "optional": true, @@ -3010,14 +3543,14 @@ }, "minimist": { "version": "0.0.8", - "resolved": false, + "resolved": "", "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", "dev": true, "optional": true }, "mkdirp": { "version": "0.5.1", - "resolved": false, + "resolved": "", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "dev": true, "optional": true, @@ -3027,14 +3560,14 @@ }, "ms": { "version": "2.0.0", - "resolved": false, + "resolved": "", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true, "optional": true }, "needle": { "version": "2.2.0", - "resolved": false, + "resolved": "", "integrity": "sha512-eFagy6c+TYayorXw/qtAdSvaUpEbBsDwDyxYFgLZ0lTojfH7K+OdBqAF7TAFwDokJaGpubpSGG0wO3iC0XPi8w==", "dev": true, "optional": true, @@ -3046,7 +3579,7 @@ }, "node-pre-gyp": { "version": "0.10.0", - "resolved": false, + "resolved": "", "integrity": "sha512-G7kEonQLRbcA/mOoFoxvlMrw6Q6dPf92+t/l0DFSMuSlDoWaI9JWIyPwK0jyE1bph//CUEL65/Fz1m2vJbmjQQ==", "dev": true, "optional": true, @@ -3065,7 +3598,7 @@ }, "nopt": { "version": "4.0.1", - "resolved": false, + "resolved": "", "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", "dev": true, "optional": true, @@ -3076,14 +3609,14 @@ }, "npm-bundled": { "version": "1.0.3", - "resolved": false, + "resolved": "", "integrity": "sha512-ByQ3oJ/5ETLyglU2+8dBObvhfWXX8dtPZDMePCahptliFX2iIuhyEszyFk401PZUNQH20vvdW5MLjJxkwU80Ow==", "dev": true, "optional": true }, "npm-packlist": { "version": "1.1.10", - "resolved": false, + "resolved": "", "integrity": "sha512-AQC0Dyhzn4EiYEfIUjCdMl0JJ61I2ER9ukf/sLxJUcZHfo+VyEfz2rMJgLZSS1v30OxPQe1cN0LZA1xbcaVfWA==", "dev": true, "optional": true, @@ -3094,7 +3627,7 @@ }, "npmlog": { "version": "4.1.2", - "resolved": false, + "resolved": "", "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", "dev": true, "optional": true, @@ -3107,21 +3640,21 @@ }, "number-is-nan": { "version": "1.0.1", - "resolved": false, + "resolved": "", "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", "dev": true, "optional": true }, "object-assign": { "version": "4.1.1", - "resolved": false, + "resolved": "", "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", "dev": true, "optional": true }, "once": { "version": "1.4.0", - "resolved": false, + "resolved": "", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, "optional": true, @@ -3131,21 +3664,21 @@ }, "os-homedir": { "version": "1.0.2", - "resolved": false, + "resolved": "", "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", "dev": true, "optional": true }, "os-tmpdir": { "version": "1.0.2", - "resolved": false, + "resolved": "", "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", "dev": true, "optional": true }, "osenv": { "version": "0.1.5", - "resolved": false, + "resolved": "", "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", "dev": true, "optional": true, @@ -3156,21 +3689,21 @@ }, "path-is-absolute": { "version": "1.0.1", - "resolved": false, + "resolved": "", "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "dev": true, "optional": true }, "process-nextick-args": { "version": "2.0.0", - "resolved": false, + "resolved": "", "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", "dev": true, "optional": true }, "rc": { "version": "1.2.7", - "resolved": false, + "resolved": "", "integrity": "sha512-LdLD8xD4zzLsAT5xyushXDNscEjB7+2ulnl8+r1pnESlYtlJtVSoCMBGr30eDRJ3+2Gq89jK9P9e4tCEH1+ywA==", "dev": true, "optional": true, @@ -3183,7 +3716,7 @@ "dependencies": { "minimist": { "version": "1.2.0", - "resolved": false, + "resolved": "", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true, "optional": true @@ -3192,7 +3725,7 @@ }, "readable-stream": { "version": "2.3.6", - "resolved": false, + "resolved": "", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "optional": true, @@ -3208,7 +3741,7 @@ }, "rimraf": { "version": "2.6.2", - "resolved": false, + "resolved": "", "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", "dev": true, "optional": true, @@ -3218,49 +3751,49 @@ }, "safe-buffer": { "version": "5.1.1", - "resolved": false, + "resolved": "", "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", "dev": true, "optional": true }, "safer-buffer": { "version": "2.1.2", - "resolved": false, + "resolved": "", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true, "optional": true }, "sax": { "version": "1.2.4", - "resolved": false, + "resolved": "", "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", "dev": true, "optional": true }, "semver": { "version": "5.5.0", - "resolved": false, + "resolved": "", "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", "dev": true, "optional": true }, "set-blocking": { "version": "2.0.0", - "resolved": false, + "resolved": "", "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", "dev": true, "optional": true }, "signal-exit": { "version": "3.0.2", - "resolved": false, + "resolved": "", "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", "dev": true, "optional": true }, "string-width": { "version": "1.0.2", - "resolved": false, + "resolved": "", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, "optional": true, @@ -3272,7 +3805,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": false, + "resolved": "", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "optional": true, @@ -3282,7 +3815,7 @@ }, "strip-ansi": { "version": "3.0.1", - "resolved": false, + "resolved": "", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "optional": true, @@ -3292,7 +3825,7 @@ }, "strip-json-comments": { "version": "2.0.1", - "resolved": false, + "resolved": "", "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", "dev": true, "optional": true @@ -3324,14 +3857,14 @@ }, "util-deprecate": { "version": "1.0.2", - "resolved": false, + "resolved": "", "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", "dev": true, "optional": true }, "wide-align": { "version": "1.1.2", - "resolved": false, + "resolved": "", "integrity": "sha512-ijDLlyQ7s6x1JgCLur53osjm/UXUYD9+0PbYKrBsYisYXzCxN+HC3mYDNy/dWdmf3AwqwU3CXwDCvsNgGK1S0w==", "dev": true, "optional": true, @@ -3341,7 +3874,7 @@ }, "wrappy": { "version": "1.0.2", - "resolved": false, + "resolved": "", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true, "optional": true @@ -3361,6 +3894,12 @@ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", "dev": true }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, "g-status": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/g-status/-/g-status-2.0.2.tgz", @@ -3742,6 +4281,15 @@ "which": "^1.2.14" } }, + "globals": { + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", + "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "dev": true, + "requires": { + "type-fest": "^0.8.1" + } + }, "globby": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", @@ -3856,7 +4404,7 @@ }, "os-locale": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", + "resolved": "http://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", "dev": true, "requires": { @@ -3921,6 +4469,200 @@ } } }, + "gulp-eslint": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/gulp-eslint/-/gulp-eslint-6.0.0.tgz", + "integrity": "sha512-dCVPSh1sA+UVhn7JSQt7KEb4An2sQNbOdB3PA8UCfxsoPlAKjJHxYHGXdXC7eb+V1FAnilSFFqslPrq037l1ig==", + "dev": true, + "requires": { + "eslint": "^6.0.0", + "fancy-log": "^1.3.2", + "plugin-error": "^1.0.1" + }, + "dependencies": { + "acorn": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.3.1.tgz", + "integrity": "sha512-tLc0wSnatxAQHVHUapaHdz72pi9KUyHjq5KyHjGg9Y8Ifdc79pTh2XvI6I1/chZbnM7QtNKzh66ooDogPZSleA==", + "dev": true + }, + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "eslint": { + "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", + "ajv": "^6.10.0", + "chalk": "^2.1.0", + "cross-spawn": "^6.0.5", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "eslint-scope": "^5.0.0", + "eslint-utils": "^1.4.3", + "eslint-visitor-keys": "^1.1.0", + "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": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "inquirer": "^7.0.0", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.14", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "optionator": "^0.8.3", + "progress": "^2.0.0", + "regexpp": "^2.0.1", + "semver": "^6.1.2", + "strip-ansi": "^5.2.0", + "strip-json-comments": "^3.0.1", + "table": "^5.2.3", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + } + }, + "eslint-utils": { + "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.1.0" + } + }, + "espree": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-6.2.1.tgz", + "integrity": "sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw==", + "dev": true, + "requires": { + "acorn": "^7.1.1", + "acorn-jsx": "^5.2.0", + "eslint-visitor-keys": "^1.1.0" + } + }, + "glob-parent": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", + "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + }, + "dependencies": { + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + } + } + }, + "import-fresh": { + "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", + "resolve-from": "^4.0.0" + } + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + }, + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, + "optionator": { + "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.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + } + }, + "plugin-error": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-1.0.1.tgz", + "integrity": "sha512-L1zP0dk7vGweZME2i+EeakvUNqSrdiI3F91TwEoYiGrAfUXmVv6fJIq4g82PAXxNsWOp0J7ZqQy/3Szz0ajTxA==", + "dev": true, + "requires": { + "ansi-colors": "^1.0.1", + "arr-diff": "^4.0.0", + "arr-union": "^3.1.0", + "extend-shallow": "^3.0.2" + } + }, + "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 + }, + "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==", + "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 + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + } + } + }, "gulp-istanbul": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/gulp-istanbul/-/gulp-istanbul-1.1.3.tgz", @@ -4136,34 +4878,6 @@ } } }, - "gulp-tslint": { - "version": "8.1.4", - "resolved": "https://registry.npmjs.org/gulp-tslint/-/gulp-tslint-8.1.4.tgz", - "integrity": "sha512-wBoZIEMJRz9urHwolsvQpngA9l931p6g/Liwz1b/KrsVP6jEBFZv/o0NS1TFCQZi/l8mXxz8+v3twhf4HOXxPQ==", - "dev": true, - "requires": { - "@types/fancy-log": "1.3.0", - "ansi-colors": "^1.0.1", - "fancy-log": "1.3.3", - "map-stream": "~0.0.7", - "plugin-error": "1.0.1", - "through": "~2.3.8" - }, - "dependencies": { - "plugin-error": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-1.0.1.tgz", - "integrity": "sha512-L1zP0dk7vGweZME2i+EeakvUNqSrdiI3F91TwEoYiGrAfUXmVv6fJIq4g82PAXxNsWOp0J7ZqQy/3Szz0ajTxA==", - "dev": true, - "requires": { - "ansi-colors": "^1.0.1", - "arr-diff": "^4.0.0", - "arr-union": "^3.1.0", - "extend-shallow": "^3.0.2" - } - } - } - }, "gulp-typescript": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/gulp-typescript/-/gulp-typescript-5.0.0.tgz", @@ -4537,6 +5251,12 @@ "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.12.tgz", "integrity": "sha512-GguP+DRY+pJ3soyIiGPTvdiVXjZ+DbXOxGpXn3eMvNW4x4irjqXm4wHKscC+TfxSJ0yw/S1F24tqdMNsMZTiLA==" }, + "ignore": { + "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", @@ -4556,6 +5276,12 @@ "resolve-from": "^3.0.0" } }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, "indent-string": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", @@ -4582,6 +5308,184 @@ "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", "dev": true }, + "inquirer": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.3.2.tgz", + "integrity": "sha512-DF4osh1FM6l0RJc5YWYhSDB6TawiBRlbV9Cox8MWlidU218Tb7fm3lQTULyUJDfJ0tjbzl0W4q651mrCCEM55w==", + "dev": true, + "requires": { + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.16", + "mute-stream": "0.0.8", + "run-async": "^2.4.0", + "rxjs": "^6.6.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6" + }, + "dependencies": { + "ansi-escapes": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.1.tgz", + "integrity": "sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA==", + "dev": true, + "requires": { + "type-fest": "^0.11.0" + } + }, + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "dev": true, + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "requires": { + "restore-cursor": "^3.1.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==", + "dev": true, + "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==", + "dev": true + }, + "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==", + "dev": true + }, + "figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "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 + }, + "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==", + "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 + }, + "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" + } + }, + "restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "requires": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + } + }, + "rxjs": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.0.tgz", + "integrity": "sha512-3HMA8z/Oz61DUHe+SdOiQyzIf4tOx5oQHmMir7IZEu6TMqCLHT4LRcmNaUS0NwOz8VLvmmBduMsoaUvMaIiqzg==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "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==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "type-fest": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.11.0.tgz", + "integrity": "sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ==", + "dev": true + } + } + }, "interpret": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.1.0.tgz", @@ -4606,7 +5510,7 @@ }, "is-accessor-descriptor": { "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "resolved": "http://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", "dev": true, "requires": { @@ -4671,7 +5575,7 @@ }, "is-data-descriptor": { "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "resolved": "http://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", "dev": true, "requires": { @@ -5050,12 +5954,6 @@ "textextensions": "2" } }, - "js-tokens": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", - "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", - "dev": true - }, "js-yaml": { "version": "3.13.1", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", @@ -5414,7 +6312,7 @@ }, "load-json-file": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", "dev": true, "requires": { @@ -5427,7 +6325,7 @@ "dependencies": { "pify": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", "dev": true } @@ -5599,12 +6497,6 @@ "integrity": "sha1-plzSkIepJZi4eRJXpSPgISIqwfk=", "dev": true }, - "map-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.0.7.tgz", - "integrity": "sha1-ih8HiW2CsQkmvTdEokIACfiJdKg=", - "dev": true - }, "map-visit": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", @@ -6239,6 +7131,12 @@ "integrity": "sha512-kDcwXR4PS7caBpuRYYBUz9iVixUk3anO3f5OYFiIPwK/20vCzKCHyKoulbiDY1S53zD2bxUpxN/IJ+TnXjfvxg==", "dev": true }, + "mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true + }, "mysql": { "version": "2.16.0", "resolved": "https://registry.npmjs.org/mysql/-/mysql-2.16.0.tgz", @@ -6324,6 +7222,12 @@ "integrity": "sha1-eJkHjmS/PIo9cyYBs9QP8F21j6A=", "dev": true }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, "needle": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/needle/-/needle-2.4.0.tgz", @@ -6810,6 +7714,23 @@ "integrity": "sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==", "dev": true }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "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": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/parent-require/-/parent-require-1.0.0.tgz", @@ -6942,7 +7863,7 @@ "dependencies": { "pify": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", "dev": true } @@ -7260,6 +8181,12 @@ "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", "dev": true }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true + }, "property-expr": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/property-expr/-/property-expr-1.5.1.tgz", @@ -7482,6 +8409,12 @@ "safe-regex": "^1.1.0" } }, + "regexpp": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", + "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", + "dev": true + }, "remap-istanbul": { "version": "0.13.0", "resolved": "https://registry.npmjs.org/remap-istanbul/-/remap-istanbul-0.13.0.tgz", @@ -7722,6 +8655,12 @@ "glob": "^7.1.3" } }, + "run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", + "dev": true + }, "run-node": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/run-node/-/run-node-1.0.0.tgz", @@ -8355,6 +9294,75 @@ "integrity": "sha512-TyOuWLwkmtPL49LHCX1caIwHjRzcVd62+GF6h8W/jHOeZUFHpnd2XJDVuUlaTaLPH1nuu2M69mfHr5XbQJnf/g==", "dev": true }, + "table": { + "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", + "lodash": "^4.17.14", + "slice-ansi": "^2.1.0", + "string-width": "^3.0.0" + }, + "dependencies": { + "ajv": { + "version": "6.12.3", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.3.tgz", + "integrity": "sha512-4K0cK3L1hsqk9xIb2z9vs/XU+PGJZ9PNpJRDS9YLzmNdX6jmVPfamLvTJr0aDAusnHyCHO6MjzlkAsgtqp9teA==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "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", + "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" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, "tar": { "version": "4.4.10", "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.10.tgz", @@ -8521,6 +9529,12 @@ "integrity": "sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ==", "dev": true }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, "textextensions": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/textextensions/-/textextensions-2.4.0.tgz", @@ -8585,6 +9599,15 @@ "next-tick": "1" } }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.2" + } + }, "to-absolute-glob": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/to-absolute-glob/-/to-absolute-glob-2.0.2.tgz", @@ -8700,53 +9723,6 @@ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==" }, - "tslint": { - "version": "5.13.1", - "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.13.1.tgz", - "integrity": "sha512-fplQqb2miLbcPhyHoMV4FU9PtNRbgmm/zI5d3SZwwmJQM6V0eodju+hplpyfhLWpmwrDNfNYU57uYRb8s0zZoQ==", - "dev": true, - "requires": { - "babel-code-frame": "^6.22.0", - "builtin-modules": "^1.1.1", - "chalk": "^2.3.0", - "commander": "^2.12.1", - "diff": "^3.2.0", - "glob": "^7.1.1", - "js-yaml": "^3.7.0", - "minimatch": "^3.0.4", - "mkdirp": "^0.5.1", - "resolve": "^1.3.2", - "semver": "^5.3.0", - "tslib": "^1.8.0", - "tsutils": "^2.27.2" - }, - "dependencies": { - "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", - "dev": true - }, - "mkdirp": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.3.tgz", - "integrity": "sha512-P+2gwrFqx8lhew375MQHHeTlY8AuOJSrGf0R5ddkEndUkmwpgUob/vQuBD1V22/Cw1/lJr4x+EjllSezBThzBg==", - "dev": true, - "requires": { - "minimist": "^1.2.5" - } - } - } - }, - "tsutils": { - "version": "2.29.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", - "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", - "dev": true, - "requires": { - "tslib": "^1.8.1" - } - }, "tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", @@ -8777,6 +9753,12 @@ "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", "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 + }, "typedarray": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", @@ -8789,7 +9771,7 @@ "integrity": "sha512-9U5/zAcRgXixbMt4Hf6VkO94657WpR+Sq/SPKKEGDh+UxI1DHpkXLquvpOAdq76/LiMpmyAIRw51Yhjk8/lxpA==", "dev": true, "requires": { - "data-api-client": "github:ArsenyYankovsky/data-api-client#043f3320f8d665c21250d615101e7b3bc8f1d298" + "data-api-client": "github:ArsenyYankovsky/data-api-client#support-postgres" }, "dependencies": { "data-api-client": { @@ -8965,6 +9947,12 @@ "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", "dev": true }, + "v8-compile-cache": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.1.tgz", + "integrity": "sha512-8OQ9CL+VWyt3JStj7HX7/ciTL2V3Rl1Wf5OL+SNTm0yK1KvtReVulksyeRnCANHHuUxHlQig+JJDlUhBt1NQDQ==", + "dev": true + }, "v8flags": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.1.2.tgz", @@ -9092,6 +10080,12 @@ "string-width": "^1.0.2 || 2" } }, + "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": "1.0.0", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", @@ -9145,6 +10139,32 @@ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, + "write": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", + "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", + "dev": true, + "requires": { + "mkdirp": "^0.5.1" + }, + "dependencies": { + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + }, + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + } + } + }, "xml2js": { "version": "0.4.19", "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz", diff --git a/package.json b/package.json index a52319a5452..86d4ea61f95 100644 --- a/package.json +++ b/package.json @@ -57,6 +57,8 @@ "@types/sinon": "^7.0.8", "@types/source-map-support": "^0.4.2", "@types/yargs": "^12.0.9", + "@typescript-eslint/eslint-plugin": "^3.7.0", + "@typescript-eslint/parser": "^3.7.0", "better-sqlite3": "^7.0.1", "chai": "^4.2.0", "chai-as-promised": "^7.1.1", @@ -64,14 +66,15 @@ "conventional-changelog-angular": "^5.0.3", "conventional-changelog-cli": "^2.0.21", "del": "^3.0.0", + "eslint": "^7.5.0", "gulp": "^4.0.0", + "gulp-eslint": "^6.0.0", "gulp-istanbul": "^1.1.3", "gulp-mocha": "^6.0.0", "gulp-rename": "^1.2.2", "gulp-replace": "^1.0.0", "gulp-shell": "^0.6.5", "gulp-sourcemaps": "^2.6.5", - "gulp-tslint": "^8.1.4", "gulp-typescript": "^5.0.0", "gulpclass": "^0.2.0", "husky": "^1.3.1", @@ -91,7 +94,6 @@ "sql.js": "^1.0.0", "sqlite3": "^4.0.9", "ts-node": "^8.0.2", - "tslint": "^5.13.1", "typeorm-aurora-data-api-driver": "^1.3.0", "typescript": "^3.3.3333" }, @@ -114,7 +116,7 @@ }, "lint-staged": { "*.ts": [ - "tslint --fix", + "eslint --fix", "git add" ] }, @@ -125,7 +127,7 @@ "compile": "rimraf ./build && tsc", "watch": "./node_modules/.bin/tsc -w", "package": "gulp package", - "lint": "tslint -p .", + "lint": "eslint -c ./.eslintrc.js src/**/*.ts test/**/*.ts sample/**/*.ts", "changelog": "conventional-changelog -p angular -i CHANGELOG.md -s -r 2" }, "bin": { diff --git a/tslint.json b/tslint.json deleted file mode 100644 index 550a8cf6e29..00000000000 --- a/tslint.json +++ /dev/null @@ -1,54 +0,0 @@ -{ - "rules": { - "class-name": true, - "comment-format": [ - true, - "check-space" - ], - "indent": [ - true, - "spaces" - ], - "no-unused-variable": true, - "no-duplicate-variable": true, - "no-eval": true, - "no-internal-module": true, - "no-var-keyword": true, - "one-line": [ - true, - "check-open-brace", - "check-whitespace" - ], - "quotemark": [ - true, - "double" - ], - "semicolon": true, - "triple-equals": [ - true, - "allow-null-check" - ], - "typedef-whitespace": [ - true, - { - "call-signature": "nospace", - "index-signature": "nospace", - "parameter": "nospace", - "property-declaration": "nospace", - "variable-declaration": "nospace" - } - ], - "variable-name": [ - true, - "ban-keywords" - ], - "whitespace": [ - true, - "check-branch", - "check-decl", - "check-operator", - "check-separator", - "check-type" - ] - } -} \ No newline at end of file From f642a9efd53cbb1b7e49fa536d73b7b5619735cb Mon Sep 17 00:00:00 2001 From: Michael Date: Fri, 24 Jul 2020 11:55:47 -0500 Subject: [PATCH 020/212] fix: @JoinTable does not respect inverseJoinColumns referenced column width (#6444) * fix: provide width to ColumnMetadataArgs for JoinTable @JoinTable does not respect inverseJoinColumns referenced column width Closes: #6442 * fix: address linting errors, replaced single quotes * fix: add await so that promises are resolved * fix: add connection close for migration connection --- .../JunctionEntityMetadataBuilder.ts | 1 + test/github-issues/6642/entity/v1/entities.ts | 18 +++++ test/github-issues/6642/entity/v2/entities.ts | 34 ++++++++++ test/github-issues/6642/issue-6642.ts | 67 +++++++++++++++++++ 4 files changed, 120 insertions(+) create mode 100644 test/github-issues/6642/entity/v1/entities.ts create mode 100644 test/github-issues/6642/entity/v2/entities.ts create mode 100644 test/github-issues/6642/issue-6642.ts diff --git a/src/metadata-builder/JunctionEntityMetadataBuilder.ts b/src/metadata-builder/JunctionEntityMetadataBuilder.ts index e5464329075..9fbb1ed7338 100644 --- a/src/metadata-builder/JunctionEntityMetadataBuilder.ts +++ b/src/metadata-builder/JunctionEntityMetadataBuilder.ts @@ -113,6 +113,7 @@ export class JunctionEntityMetadataBuilder { && (inverseReferencedColumn.generationStrategy === "uuid" || inverseReferencedColumn.type === "uuid") ? "36" : inverseReferencedColumn.length, // fix https://github.com/typeorm/typeorm/issues/3604 + width: inverseReferencedColumn.width, // fix https://github.com/typeorm/typeorm/issues/6442 type: inverseReferencedColumn.type, precision: inverseReferencedColumn.precision, scale: inverseReferencedColumn.scale, diff --git a/test/github-issues/6642/entity/v1/entities.ts b/test/github-issues/6642/entity/v1/entities.ts new file mode 100644 index 00000000000..f8df17ccd27 --- /dev/null +++ b/test/github-issues/6642/entity/v1/entities.ts @@ -0,0 +1,18 @@ +import { PrimaryColumn, Generated, Column, Entity } from "../../../../../src"; + +@Entity() +export class FooEntity { + @PrimaryColumn({ type: "int", width: 10, unsigned: true, nullable: false }) + @Generated() + public id: number; +} + +@Entity() +export class BarEntity { + @PrimaryColumn({ type: "int", width: 10, unsigned: true }) + @Generated() + public id: number; + + @Column("varchar", { nullable: false, length: 50 }) + public code: string; +} diff --git a/test/github-issues/6642/entity/v2/entities.ts b/test/github-issues/6642/entity/v2/entities.ts new file mode 100644 index 00000000000..fcf2d1a14b4 --- /dev/null +++ b/test/github-issues/6642/entity/v2/entities.ts @@ -0,0 +1,34 @@ +import { PrimaryColumn, Generated, ManyToMany, Entity, Column, JoinTable } from "../../../../../src"; + +@Entity() +export class FooEntity { + @PrimaryColumn({ type: "int", width: 10, unsigned: true, nullable: false }) + @Generated() + public id: number; + + @ManyToMany(() => BarEntity) + @JoinTable({ + name: "foo_bars", + joinColumns: [ + { + name: "foo_id", + } + ], + inverseJoinColumns: [ + { + name: "bar_id", + } + ] + }) + public fooBars: BarEntity[]; +} + +@Entity() +export class BarEntity { + @PrimaryColumn({ type: "int", width: 10, unsigned: true }) + @Generated() + public id: number; + + @Column("varchar", { nullable: false, length: 50 }) + public code: string; +} diff --git a/test/github-issues/6642/issue-6642.ts b/test/github-issues/6642/issue-6642.ts new file mode 100644 index 00000000000..b8ba4f7d058 --- /dev/null +++ b/test/github-issues/6642/issue-6642.ts @@ -0,0 +1,67 @@ +import "reflect-metadata"; +import { + closeTestingConnections, + createTestingConnections, + reloadTestingDatabases, + setupSingleTestingConnection +} from "../../utils/test-utils"; +import { Connection, createConnection } from "../../../src"; +import { fail } from "assert"; +import { Query } from "../../../src/driver/Query"; +import { MysqlConnectionOptions } from "../../../src/driver/mysql/MysqlConnectionOptions"; + +describe("github issues > #6642 JoinTable does not respect inverseJoinColumns referenced column width", () => { + let connections: Connection[]; + + before(async () => { + return connections = await createTestingConnections({ + entities: [__dirname + "/entity/v1/*{.js,.ts}"], + schemaCreate: true, + dropSchema: true, + enabledDrivers: ["mysql"] + }); + }); + beforeEach(async () => await reloadTestingDatabases(connections)); + after(async () => await closeTestingConnections(connections)); + + it("should generate column widths equal to the referenced column widths", async () => { + + await Promise.all(connections.map(async (connection) => { + const options = setupSingleTestingConnection( + connection.options.type, + { + name: `${connection.name}-v2`, + entities: [__dirname + "/entity/v2/*{.js,.ts}"], + dropSchema: false, + schemaCreate: false + } + ) as MysqlConnectionOptions; + + if (!options) { + await connection.close(); + fail(); + } + + const migrationConnection = await createConnection(options); + try { + const sqlInMemory = await migrationConnection.driver + .createSchemaBuilder() + .log(); + + const upQueries = sqlInMemory.upQueries.map( + (query: Query) => query.query + ); + + upQueries.should.eql([ + "CREATE TABLE `foo_bars` (`foo_id` int(10) UNSIGNED NOT NULL, `bar_id` int(10) UNSIGNED NOT NULL, INDEX `IDX_319290776f044043e3ef3ba5a8` (`foo_id`), INDEX `IDX_b7fd4be386fa7cdb87ef8b12b6` (`bar_id`), PRIMARY KEY (`foo_id`, `bar_id`)) ENGINE=InnoDB", + "ALTER TABLE `foo_bars` ADD CONSTRAINT `FK_319290776f044043e3ef3ba5a8d` FOREIGN KEY (`foo_id`) REFERENCES `foo_entity`(`id`) ON DELETE CASCADE ON UPDATE NO ACTION", + "ALTER TABLE `foo_bars` ADD CONSTRAINT `FK_b7fd4be386fa7cdb87ef8b12b69` FOREIGN KEY (`bar_id`) REFERENCES `bar_entity`(`id`) ON DELETE CASCADE ON UPDATE NO ACTION" + ]); + + } finally { + await connection.close(); + await migrationConnection.close(); + } + })); + }); +}); From 1c52ccf15062d84f100f099a874a70dab7a9bd8e Mon Sep 17 00:00:00 2001 From: James Ward Date: Fri, 24 Jul 2020 13:08:25 -0400 Subject: [PATCH 021/212] chore: update slack invite link (#6447) --- CONTRIBUTING.md | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3c619c186f2..e92a577913e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -14,7 +14,7 @@ As a contributor, here are the guidelines we would like you to follow: There are several ways how you can ask your question: * You can create a question on [StackOverflow](https://stackoverflow.com/questions/tagged/typeorm) where the questions should be tagged with tag `typeorm`. -* You can ask on [Slack](https://join.slack.com/t/typeorm/shared_invite/enQtNDQ1MzA3MDA5MTExLTUxNTZhM2Q4NDNhMjMzNjQ2NGM1ZjI1ZGRkNjJjYzI4OTZjMGYyYTc0MzAxYTdjMWE3ZDIxOWUzZTdlM2QxNTY) +* You can ask on [Slack](https://join.slack.com/t/typeorm/shared_invite/zt-gej3gc00-hR~L~DqGUJ7qOpGy4SSq3g) * You can create issue on [github](https://github.com/typeorm/typeorm/issues) * If you have a Skype then try to find me there (`Umed Khudoiberdiev`) diff --git a/README.md b/README.md index d15d8cee8ca..ad512ec46e8 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ Codecov - +
From 275061bb2c74ab7831899ce60a8d258e854dcbee Mon Sep 17 00:00:00 2001 From: James Ward Date: Sun, 26 Jul 2020 06:26:40 -0400 Subject: [PATCH 022/212] chore: update pg to 8.3.0 (#6462) update pg to the currently latest version which has support for node 14 --- package-lock.json | 45 ++++++++++++++++++++++++++------------------- package.json | 2 +- 2 files changed, 27 insertions(+), 20 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1502530dc5e..a25b244d674 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7882,16 +7882,17 @@ "dev": true }, "pg": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/pg/-/pg-7.8.1.tgz", - "integrity": "sha512-m9aIrOV4mgfo+1Ze+eNoJwaWZDvpeBz8Kzwi0zzqLC+tQBsQgIuu+FGPqzyRv9HFlS7tHO1I33LKp9gP5g7U4Q==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.3.0.tgz", + "integrity": "sha512-jQPKWHWxbI09s/Z9aUvoTbvGgoj98AU7FDCcQ7kdejupn/TcNpx56v2gaOTzXkzOajmOEJEdi9eTh9cA2RVAjQ==", "dev": true, "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-connection-string": "^2.3.0", + "pg-pool": "^3.2.1", + "pg-protocol": "^1.2.5", + "pg-types": "^2.1.0", "pgpass": "1.x", "semver": "4.3.2" }, @@ -7905,9 +7906,9 @@ } }, "pg-connection-string": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-0.1.3.tgz", - "integrity": "sha1-2hhHsglA5C7hSSvq9l1J2RskXfc=", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.3.0.tgz", + "integrity": "sha512-ukMTJXLI7/hZIwTW7hGMZJ0Lj0S2XQBCJ4Shv4y1zgQ/vqVea+FLhzywvPj0ujSuofu+yA4MYHGZPTsgjBgJ+w==", "dev": true }, "pg-int8": { @@ -7917,21 +7918,27 @@ "dev": true }, "pg-pool": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-2.0.6.tgz", - "integrity": "sha512-hod2zYQxM8Gt482q+qONGTYcg/qVcV32VHVPtktbBJs0us3Dj7xibISw0BAAXVMCzt8A/jhfJvpZaxUlqtqs0g==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.2.1.tgz", + "integrity": "sha512-BQDPWUeKenVrMMDN9opfns/kZo4lxmSWhIqo+cSAF7+lfi9ZclQbr9vfnlNaPr8wYF3UYjm5X0yPAhbcgqNOdA==", + "dev": true + }, + "pg-protocol": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.2.5.tgz", + "integrity": "sha512-1uYCckkuTfzz/FCefvavRywkowa6M5FohNMF5OjKrqo9PSR8gYc8poVmwwYQaBxhmQdBjhtP514eXy9/Us2xKg==", "dev": true }, "pg-types": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.0.0.tgz", - "integrity": "sha512-THUD7gQll5tys+5eQ8Rvs7DjHiIC3bLqixk3gMN9Hu8UrCBAOjf35FoI39rTGGc3lM2HU/R+Knpxvd11mCwOMA==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", + "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", "dev": true, "requires": { "pg-int8": "1.0.1", "postgres-array": "~2.0.0", "postgres-bytea": "~1.0.0", - "postgres-date": "~1.0.0", + "postgres-date": "~1.0.4", "postgres-interval": "^1.1.0" } }, @@ -8099,9 +8106,9 @@ "dev": true }, "postgres-date": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.3.tgz", - "integrity": "sha1-4tiXAu/bJY/52c7g/pG9BpdSV6g=", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.5.tgz", + "integrity": "sha512-pdau6GRPERdAYUQwkBnGKxEfPyhVZXG/JiS44iZWiNdSOWE09N2lUgN6yshuq6fVSon4Pm0VMXd1srUUkLe9iA==", "dev": true }, "postgres-interval": { diff --git a/package.json b/package.json index 86d4ea61f95..065b53c0fc7 100644 --- a/package.json +++ b/package.json @@ -84,7 +84,7 @@ "mssql": "^4.3.2", "mysql": "^2.15.0", "mysql2": "^1.6.5", - "pg": "^7.8.1", + "pg": "^8.3.0", "redis": "^2.8.0", "remap-istanbul": "^0.13.0", "rimraf": "^2.6.3", From 906d97fc8dbf1dba8f4e579a4f5bfead83af36ab Mon Sep 17 00:00:00 2001 From: Carlos Date: Sun, 26 Jul 2020 18:30:49 +0800 Subject: [PATCH 023/212] fix: mysql migration: make sure the indices sql which left-join be the same database (#6426) --- src/driver/mysql/MysqlQueryRunner.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/driver/mysql/MysqlQueryRunner.ts b/src/driver/mysql/MysqlQueryRunner.ts index f501c899d8e..0a2b439f2d4 100644 --- a/src/driver/mysql/MysqlQueryRunner.ts +++ b/src/driver/mysql/MysqlQueryRunner.ts @@ -1218,7 +1218,7 @@ export class MysqlQueryRunner extends BaseQueryRunner implements QueryRunner { return `(\`s\`.\`TABLE_SCHEMA\` = '${database}' AND \`s\`.\`TABLE_NAME\` = '${name}')`; }).join(" OR "); const indicesSql = `SELECT \`s\`.* FROM \`INFORMATION_SCHEMA\`.\`STATISTICS\` \`s\` ` + - `LEFT JOIN \`INFORMATION_SCHEMA\`.\`REFERENTIAL_CONSTRAINTS\` \`rc\` ON \`s\`.\`INDEX_NAME\` = \`rc\`.\`CONSTRAINT_NAME\` ` + + `LEFT JOIN \`INFORMATION_SCHEMA\`.\`REFERENTIAL_CONSTRAINTS\` \`rc\` ON \`s\`.\`INDEX_NAME\` = \`rc\`.\`CONSTRAINT_NAME\` AND \`s\`.\`TABLE_SCHEMA\` = \`rc\`.\`CONSTRAINT_SCHEMA\`` + `WHERE (${indicesCondition}) AND \`s\`.\`INDEX_NAME\` != 'PRIMARY' AND \`rc\`.\`CONSTRAINT_NAME\` IS NULL`; const foreignKeysCondition = tableNames.map(tableName => { From 86a31a804cf2204a549cf2c8b99e058eb0ea9717 Mon Sep 17 00:00:00 2001 From: James Ward Date: Sun, 2 Aug 2020 10:32:05 -0400 Subject: [PATCH 024/212] chore: use circleci for all builds (#6460) drop travis-ci from the builds by using the matrix functionality in circleci to run multiple node versions plus refactor the way builds work to allow splitting and joining builds together more easily --- .circleci/config.yml | 215 ++++++++++++++++++------------ .travis.yml | 21 --- ormconfig.circleci-cockroach.json | 98 -------------- ormconfig.circleci-common.json | 15 ++- ormconfig.circleci-oracle.json | 98 -------------- ormconfig.travis.json | 100 -------------- 6 files changed, 136 insertions(+), 411 deletions(-) delete mode 100644 .travis.yml delete mode 100644 ormconfig.circleci-cockroach.json delete mode 100644 ormconfig.circleci-oracle.json delete mode 100644 ormconfig.travis.json diff --git a/.circleci/config.yml b/.circleci/config.yml index bc4b58c6312..522f720b766 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,11 +1,93 @@ -# Javascript Node CircleCI 2.0 configuration file -# Check https://circleci.com/docs/2.0/language-javascript/ for more details -version: 2 +version: 2.1 + +orbs: + codecov: codecov/codecov@1.1.1 + +commands: + create-typeorm-config: + parameters: + databases: + type: string + default: "" + steps: + - when: + condition: + equal: [ << parameters.databases >>, "" ] + steps: + - run: + name: "Enabling Databases in ORM config" + command: cp ormconfig.circleci-common.json ./ormconfig.json + - unless: + condition: + equal: [ << parameters.databases >>, "" ] + steps: + - run: + name: "Enabling Databases in ORM config" + command: > + cat ormconfig.circleci-common.json \ + | jq 'map(.skip = if (.name | IN($ARGS.positional[])) then false else true end)' --args << parameters.databases >> \ + > ormconfig.json + - run: + name: Check ORMConfig + command: cat ormconfig.json + + install-packages: + parameters: + cache-key: + type: string + default: "" + steps: + - restore_cache: + name: Restore node_modules cache + key: node_modules-<< parameters.cache-key >>-{{ checksum "package-lock.json" }} + - run: + name: Install Node Packages + command: | + if [ ! -d node_modules ]; then + npm ci + fi + - save_cache: + name: Save node_modules cache + key: node_modules-{{ checksum "package-lock.json" }} + paths: + - node_modules + jobs: - common: + lint: + working_directory: ~/typeorm + docker: + - image: circleci/node:12 + steps: + - checkout + - install-packages: + cache-key: node12 + - run: npm run lint + + build: + working_directory: ~/typeorm + docker: + - image: circleci/node:12 + steps: + - checkout + - install-packages: + cache-key: node12 + - run: npm run compile + - persist_to_workspace: + root: ~/typeorm + paths: + - build/ + + test: + parameters: + databases: + type: string + default: "" + node-version: + type: string + default: "10" working_directory: ~/typeorm docker: - - image: circleci/node:10.16.0 + - image: circleci/node:<< parameters.node-version >> - image: mysql:5.7.24 environment: MYSQL_ROOT_PASSWORD: "admin" @@ -16,99 +98,58 @@ jobs: MYSQL_ROOT_PASSWORD: "admin" MYSQL_DATABASE: "test" - image: circleci/postgres:9.6.11-postgis + name: postgres environment: POSTGRES_USER: "test" POSTGRES_PASSWORD: "test" POSTGRES_DB: "test" + - image: cockroachdb/cockroach:latest + name: cockroachdb + command: start --insecure - image: circleci/mongo:3.4.18 - # - image: mcr.microsoft.com/mssql/server:2017-latest-ubuntu - # environment: - # SA_PASSWORD: "Admin12345" - # ACCEPT_EULA: "Y" + name: mongodb + - image: mcr.microsoft.com/mssql/server:2017-latest + name: mssql + environment: + SA_PASSWORD: "Admin123" + ACCEPT_EULA: "Y" steps: - checkout - - run: cp ormconfig.circleci-common.json ormconfig.json + - attach_workspace: + at: ~/typeorm + - create-typeorm-config: + databases: << parameters.databases >> # Download and cache dependencies - - restore_cache: - keys: - - v1-dependencies-{{ checksum "package.json" }} - # fallback to using the latest cache if no exact match is found - - v1-dependencies- - - run: npm install - - save_cache: - paths: - - node_modules - key: v1-dependencies-{{ checksum "package.json" }} - - run: npm run lint - - run: npm test + - install-packages: + cache-key: node<< parameters.node-version >> + - run: npx nyc npm run test-fast + - store_artifacts: + path: coverage + - codecov/upload - cockroachdb: - working_directory: ~/typeorm - docker: - - image: circleci/node:10.15.0 - - image: cockroachdb/cockroach:latest - command: start --insecure - steps: - - checkout - - run: cp ormconfig.circleci-cockroach.json ormconfig.json - # Download and cache dependencies - - restore_cache: - keys: - - v1-dependencies-{{ checksum "package.json" }} - # fallback to using the latest cache if no exact match is found - - v1-dependencies- - - run: npm install - - save_cache: - paths: - - node_modules - key: v1-dependencies-{{ checksum "package.json" }} - - run: npm run lint - - run: - npm test - oracle: - working_directory: ~/typeorm - docker: - - image: circleci/node:10.16.0 - - image: "store/oracle/database-enterprise:12.2.0.1-slim" - auth: - username: $DOCKER_USER - password: $DOCKER_PASSWORD - environment: - DB_SID: "sys" - SYS_PASSWORD: "ORCLCDB" - steps: - - run: if [ -z "$DOCKER_USER" ]; then echo "DOCKER_USER is unset"; circleci step halt; fi - - checkout - - run: sudo npm install -g npm@latest - - run: cp ormconfig.circleci-oracle.json ormconfig.json - # Download and cache dependencies - - restore_cache: - keys: - - v1-dependencies-{{ checksum "package.json" }} - # fallback to using the latest cache if no exact match is found - - v1-dependencies- - - run: npm install - - save_cache: - paths: - - node_modules - key: v1-dependencies-{{ checksum "package.json" }} - - run: wget https://download.oracle.com/otn_software/linux/instantclient/195000/instantclient-basiclite-linux.x64-19.5.0.0.0dbru.zip - - run: unzip instantclient-basiclite-linux.x64-19.5.0.0.0dbru.zip -d /tmp/oracle - - run: wget https://download.oracle.com/otn_software/linux/instantclient/195000/instantclient-sqlplus-linux.x64-19.5.0.0.0dbru.zip - - run: unzip instantclient-sqlplus-linux.x64-19.5.0.0.0dbru.zip -d /tmp/oracle - - run: echo "export LD_LIBRARY_PATH=/tmp/oracle/instantclient_19_5" >> $BASH_ENV - - run: sudo sh -c "echo /tmp/oracle/instantclient_19_5 > /etc/ld.so.conf.d/oracle-instantclient.conf";sudo ldconfig - - run: sh -c 'echo WHENEVER SQLERROR EXIT FAILURE > /tmp/user.sql; echo CREATE USER typeorm IDENTIFIED BY Passw0rd\; >> /tmp/user.sql; echo GRANT CONNECT TO typeorm\; >> /tmp/user.sql; echo GRANT UNLIMITED TABLESPACE TO typeorm\; >> /tmp/user.sql; echo exit >> /tmp/user.sql' - - run: sudo apt install libaio1 - - run: until /tmp/oracle/instantclient_19_5/sqlplus -L -S sys/Oradoc_db1@//localhost:1521/orclpdb1.localdomain as sysdba @/tmp/user.sql ; do echo waiting for oracle; sleep 10; done; - - run: npm install oracledb --no-save - - run: npm run lint - - run: npm test workflows: version: 2 test: jobs: - - common - - cockroachdb - # - oracle + - lint + - build + - test: + name: test (mysql mariadb sqlite better-sqlite3 postgres sqljs mssql mongodb) - Node v<< matrix.node-version >> + requires: + - lint + - build + matrix: + databases: "mysql mariadb sqlite better-sqlite3 postgres sqljs mssql mongodb" + parameters: + node-version: + - "10" + - "12" + - "13" + - test: + name: test (cockroachdb) - Node v12 + requires: + - lint + - build + databases: "cockroachdb" + node-version: "12" diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 3fa8b1987be..00000000000 --- a/.travis.yml +++ /dev/null @@ -1,21 +0,0 @@ -language: node_js -node_js: - - 13 - - 12 - - 10 - -services: - - docker - -before_script: - - sudo service mysql stop - - sudo service postgresql stop - - docker-compose up -d - - cp ormconfig.travis.json ormconfig.json - -script: - - npm run lint - - npx nyc npm test - -after_success: - - bash <(curl -s https://codecov.io/bash) diff --git a/ormconfig.circleci-cockroach.json b/ormconfig.circleci-cockroach.json deleted file mode 100644 index 96049b3fbde..00000000000 --- a/ormconfig.circleci-cockroach.json +++ /dev/null @@ -1,98 +0,0 @@ -[ - { - "skip": true, - "name": "mysql", - "type": "mysql", - "host": "localhost", - "port": 3306, - "username": "root", - "password": "admin", - "database": "test" - }, - { - "skip": true, - "name": "mariadb", - "type": "mariadb", - "host": "mariadb", - "port": 3306, - "username": "root", - "password": "admin", - "database": "test" - }, - { - "skip": true, - "name": "sqlite", - "type": "sqlite", - "database": "temp/sqlitedb.db" - }, - { - "skip": true, - "name": "better-sqlite3", - "type": "better-sqlite3", - "database": "temp/better-sqlite3db.db" - }, - { - "skip": true, - "name": "postgres", - "type": "postgres", - "host": "localhost", - "port": 5432, - "username": "test", - "password": "test", - "database": "test" - }, - { - "skip": true, - "name": "sqljs", - "type": "sqljs" - }, - { - "skip": true, - "name": "mssql", - "type": "mssql", - "host": "localhost", - "username": "sa", - "password": "Admin12345", - "database": "tempdb" - }, - { - "skip": true, - "name": "sap", - "type": "sap", - "host": "localhost", - "port": 39015, - "username": "SYSTEM", - "password": "HXEHana1", - "database": "HXE", - "logging": false - }, - { - "skip": true, - "disabledIfNotEnabledImplicitly": true, - "name": "mongodb", - "type": "mongodb", - "database": "test", - "useNewUrlParser": true, - "useUnifiedTopology": true - }, - { - "skip": false, - "name": "cockroachdb", - "type": "cockroachdb", - "host": "localhost", - "port": 26257, - "username": "root", - "password": "", - "database": "defaultdb" - }, - { - "skip": true, - "name": "oracle", - "type": "oracle", - "host": "localhost", - "username": "typeorm", - "password": "Passw0rd", - "port": 1521, - "sid": "orclpdb1.localdomain" - } -] diff --git a/ormconfig.circleci-common.json b/ormconfig.circleci-common.json index 16a85b9e798..da367ab4f41 100644 --- a/ormconfig.circleci-common.json +++ b/ormconfig.circleci-common.json @@ -35,7 +35,7 @@ "skip": false, "name": "postgres", "type": "postgres", - "host": "localhost", + "host": "postgres", "port": 5432, "username": "test", "password": "test", @@ -47,19 +47,19 @@ "type": "sqljs" }, { - "skip": true, + "skip": false, "name": "mssql", "type": "mssql", - "host": "localhost", + "host": "mssql", "username": "sa", - "password": "Admin12345", + "password": "Admin123", "database": "tempdb" }, { "skip": true, "name": "sap", "type": "sap", - "host": "localhost", + "host": "sap", "port": 39015, "username": "SYSTEM", "password": "HXEHana1", @@ -71,6 +71,7 @@ "disabledIfNotEnabledImplicitly": true, "name": "mongodb", "type": "mongodb", + "host": "mongodb", "database": "test", "useNewUrlParser": true, "useUnifiedTopology": true @@ -79,7 +80,7 @@ "skip": true, "name": "cockroachdb", "type": "cockroachdb", - "host": "localhost", + "host": "cockroachdb", "port": 26257, "username": "root", "password": "", @@ -89,7 +90,7 @@ "skip": true, "name": "oracle", "type": "oracle", - "host": "localhost", + "host": "oracle", "username": "typeorm", "password": "Passw0rd", "port": 1521, diff --git a/ormconfig.circleci-oracle.json b/ormconfig.circleci-oracle.json deleted file mode 100644 index aef977102f6..00000000000 --- a/ormconfig.circleci-oracle.json +++ /dev/null @@ -1,98 +0,0 @@ -[ - { - "skip": true, - "name": "mysql", - "type": "mysql", - "host": "localhost", - "port": 3306, - "username": "root", - "password": "admin", - "database": "test" - }, - { - "skip": true, - "name": "mariadb", - "type": "mariadb", - "host": "mariadb", - "port": 3306, - "username": "root", - "password": "admin", - "database": "test" - }, - { - "skip": true, - "name": "sqlite", - "type": "sqlite", - "database": "temp/sqlitedb.db" - }, - { - "skip": true, - "name": "better-sqlite3", - "type": "better-sqlite3", - "database": "temp/better-sqlite3db.db" - }, - { - "skip": true, - "name": "postgres", - "type": "postgres", - "host": "localhost", - "port": 5432, - "username": "test", - "password": "test", - "database": "test" - }, - { - "skip": true, - "name": "sqljs", - "type": "sqljs" - }, - { - "skip": true, - "name": "mssql", - "type": "mssql", - "host": "localhost", - "username": "sa", - "password": "Admin12345", - "database": "tempdb" - }, - { - "skip": true, - "name": "sap", - "type": "sap", - "host": "localhost", - "port": 39015, - "username": "SYSTEM", - "password": "HXEHana1", - "database": "HXE", - "logging": false - }, - { - "skip": true, - "disabledIfNotEnabledImplicitly": true, - "name": "mongodb", - "type": "mongodb", - "database": "test", - "useNewUrlParser": true, - "useUnifiedTopology": true - }, - { - "skip": true, - "name": "cockroachdb", - "type": "cockroachdb", - "host": "localhost", - "port": 26257, - "username": "root", - "password": "", - "database": "defaultdb" - }, - { - "skip": false, - "name": "oracle", - "type": "oracle", - "host": "localhost", - "username": "typeorm", - "password": "Passw0rd", - "port": 1521, - "sid": "orclpdb1.localdomain" - } -] diff --git a/ormconfig.travis.json b/ormconfig.travis.json deleted file mode 100644 index ca9054416b0..00000000000 --- a/ormconfig.travis.json +++ /dev/null @@ -1,100 +0,0 @@ -[ - { - "skip": false, - "name": "mysql", - "type": "mysql", - "host": "localhost", - "port": 3306, - "username": "root", - "password": "admin", - "database": "test" - }, - { - "skip": false, - "name": "mariadb", - "type": "mariadb", - "host": "localhost", - "port": 3307, - "username": "root", - "password": "admin", - "database": "test" - }, - { - "skip": false, - "name": "sqlite", - "type": "sqlite", - "database": "temp/sqlitedb.db" - }, - { - "skip": false, - "name": "better-sqlite3", - "type": "better-sqlite3", - "database": "temp/better-sqlite3db.db", - "logging": false - }, - { - "skip": false, - "name": "postgres", - "type": "postgres", - "host": "localhost", - "port": 5432, - "username": "test", - "password": "test", - "database": "test", - "logging": false - }, - { - "skip": false, - "name": "sqljs", - "type": "sqljs" - }, - { - "skip": false, - "name": "mssql", - "type": "mssql", - "host": "localhost", - "username": "sa", - "password": "Admin12345", - "database": "tempdb" - }, - { - "skip": true, - "name": "oracle", - "type": "oracle", - "host": "localhost", - "username": "system", - "password": "oracle", - "port": 1521, - "sid": "xe.oracle.docker" - }, - { - "skip": false, - "name": "cockroachdb", - "type": "cockroachdb", - "host": "localhost", - "port": 26257, - "username": "root", - "password": "", - "database": "defaultdb" - }, - { - "skip": true, - "name": "sap", - "type": "sap", - "host": "localhost", - "port": 39015, - "username": "SYSTEM", - "password": "HXEHana1", - "database": "HXE", - "logging": false - }, - { - "skip": false, - "disabledIfNotEnabledImplicitly": true, - "name": "mongodb", - "type": "mongodb", - "database": "test", - "useNewUrlParser": true, - "useUnifiedTopology": true - } -] From 0d6191b17739c3a1479954b04989872f435d01ee Mon Sep 17 00:00:00 2001 From: Alcides Augusto Date: Sun, 2 Aug 2020 11:32:46 -0300 Subject: [PATCH 025/212] doc: change @types/node install to install in dev dependencies (#6485) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ad512ec46e8..2d4569693c2 100644 --- a/README.md +++ b/README.md @@ -182,7 +182,7 @@ await timber.remove(); 3. You may need to install node typings: - `npm install @types/node --save` + `npm install @types/node --save-dev` 4. Install a database driver: From 43a7386719280a11cfd0495748189799bc51b7d6 Mon Sep 17 00:00:00 2001 From: Thomas Sawkins Date: Mon, 3 Aug 2020 00:34:01 +1000 Subject: [PATCH 026/212] feat: implement postgres ltree (#6480) This new feature implements support for the postgres extension ltree Closes: #4193 --- docs/entities.md | 2 +- src/driver/postgres/PostgresDriver.ts | 18 ++- src/driver/types/ColumnTypes.ts | 3 +- test/functional/ltree/postgres/entity/Post.ts | 14 ++ .../ltree/postgres/ltree-postgres.ts | 136 ++++++++++++++++++ 5 files changed, 169 insertions(+), 4 deletions(-) create mode 100644 test/functional/ltree/postgres/entity/Post.ts create mode 100644 test/functional/ltree/postgres/ltree-postgres.ts diff --git a/docs/entities.md b/docs/entities.md index a5893b54acc..9b562454ce6 100644 --- a/docs/entities.md +++ b/docs/entities.md @@ -311,7 +311,7 @@ or `date`, `time`, `time without time zone`, `time with time zone`, `interval`, `bool`, `boolean`, `enum`, `point`, `line`, `lseg`, `box`, `path`, `polygon`, `circle`, `cidr`, `inet`, `macaddr`, `tsvector`, `tsquery`, `uuid`, `xml`, `json`, `jsonb`, `int4range`, `int8range`, `numrange`, -`tsrange`, `tstzrange`, `daterange`, `geometry`, `geography`, `cube` +`tsrange`, `tstzrange`, `daterange`, `geometry`, `geography`, `cube`, `ltree` ### Column types for `cockroachdb` diff --git a/src/driver/postgres/PostgresDriver.ts b/src/driver/postgres/PostgresDriver.ts index 5aa25b585db..e9eae242c6a 100644 --- a/src/driver/postgres/PostgresDriver.ts +++ b/src/driver/postgres/PostgresDriver.ts @@ -151,7 +151,8 @@ export class PostgresDriver implements Driver { "daterange", "geometry", "geography", - "cube" + "cube", + "ltree" ]; /** @@ -328,6 +329,7 @@ export class PostgresDriver implements Driver { hasHstoreColumns, hasCubeColumns, hasGeometryColumns, + hasLtreeColumns, hasExclusionConstraints, } = extensionsMetadata; @@ -361,6 +363,12 @@ export class PostgresDriver implements Driver { } catch (_) { logger.log("warn", "At least one of the entities has a cube column, but the 'cube' extension cannot be installed automatically. Please install it manually using superuser rights"); } + if (hasLtreeColumns) + try { + await this.executeQuery(connection, `CREATE EXTENSION IF NOT EXISTS "ltree"`); + } catch (_) { + logger.log("warn", "At least one of the entities has a cube column, but the 'ltree' extension cannot be installed automatically. Please install it manually using superuser rights"); + } if (hasExclusionConstraints) try { // The btree_gist extension provides operator support in PostgreSQL exclusion constraints @@ -386,6 +394,9 @@ export class PostgresDriver implements Driver { const hasGeometryColumns = this.connection.entityMetadatas.some(metadata => { return metadata.columns.filter(column => this.spatialTypes.indexOf(column.type) >= 0).length > 0; }); + const hasLtreeColumns = this.connection.entityMetadatas.some(metadata => { + return metadata.columns.filter(column => column.type === 'ltree').length > 0; + }); const hasExclusionConstraints = this.connection.entityMetadatas.some(metadata => { return metadata.exclusions.length > 0; }); @@ -396,8 +407,9 @@ export class PostgresDriver implements Driver { hasHstoreColumns, hasCubeColumns, hasGeometryColumns, + hasLtreeColumns, hasExclusionConstraints, - hasExtensions: hasUuidColumns || hasCitextColumns || hasHstoreColumns || hasGeometryColumns || hasCubeColumns || hasExclusionConstraints, + hasExtensions: hasUuidColumns || hasCitextColumns || hasHstoreColumns || hasGeometryColumns || hasCubeColumns || hasLtreeColumns || hasExclusionConstraints, }; } @@ -487,6 +499,8 @@ export class PostgresDriver implements Driver { } return `(${value.join(",")})`; + } else if (columnMetadata.type === "ltree") { + return value.split(".").filter(Boolean).join('.').replace(/[\s]+/g, "_"); } else if ( ( columnMetadata.type === "enum" diff --git a/src/driver/types/ColumnTypes.ts b/src/driver/types/ColumnTypes.ts index 3569bedda3c..44c3ab2b852 100644 --- a/src/driver/types/ColumnTypes.ts +++ b/src/driver/types/ColumnTypes.ts @@ -193,7 +193,8 @@ export type SimpleColumnType = |"uniqueidentifier" // mssql |"rowversion" // mssql |"array" // cockroachdb, sap - |"cube"; // postgres + |"cube" // postgres + |"ltree"; // postgres /** * Any column type column can be. diff --git a/test/functional/ltree/postgres/entity/Post.ts b/test/functional/ltree/postgres/entity/Post.ts new file mode 100644 index 00000000000..8abbf39803f --- /dev/null +++ b/test/functional/ltree/postgres/entity/Post.ts @@ -0,0 +1,14 @@ +import {PrimaryGeneratedColumn} from "../../../../../src/decorator/columns/PrimaryGeneratedColumn"; +import {Entity} from "../../../../../src/decorator/entity/Entity"; +import {Column} from "../../../../../src/decorator/columns/Column"; + +@Entity() +export class Post { + @PrimaryGeneratedColumn() + id: number; + + @Column("ltree", { + nullable: false + }) + path: string; +} diff --git a/test/functional/ltree/postgres/ltree-postgres.ts b/test/functional/ltree/postgres/ltree-postgres.ts new file mode 100644 index 00000000000..7e19718d84a --- /dev/null +++ b/test/functional/ltree/postgres/ltree-postgres.ts @@ -0,0 +1,136 @@ +import "reflect-metadata"; +import { expect } from "chai"; +import { Connection } from "../../../../src/connection/Connection"; +import { + closeTestingConnections, + createTestingConnections, + reloadTestingDatabases +} from "../../../utils/test-utils"; +import { Post } from "./entity/Post"; + +describe("ltree-postgres", () => { + let connections: Connection[]; + before(async () => { + connections = await createTestingConnections({ + entities: [__dirname + "/entity/*{.js,.ts}"], + enabledDrivers: ["postgres"] + }); + }); + beforeEach(() => reloadTestingDatabases(connections)); + after(() => closeTestingConnections(connections)); + + it("should create correct schema with Postgres' ltree type", () => + Promise.all( + connections.map(async connection => { + const queryRunner = connection.createQueryRunner(); + const schema = await queryRunner.getTable("post"); + await queryRunner.release(); + expect(schema).not.to.be.undefined; + const ltreeColumn = schema!.columns.find( + tableColumn => + tableColumn.name === "path" && + tableColumn.type === "ltree" && + !tableColumn.isArray + ); + expect(ltreeColumn).to.not.be.undefined; + }) + )); + + it("should persist ltree correctly", () => + Promise.all( + connections.map(async connection => { + const path = 'News.Featured.Opinion'; + const postRepo = connection.getRepository(Post); + const post = new Post(); + post.path = path; + const persistedPost = await postRepo.save(post); + const foundPost = await postRepo.findOne(persistedPost.id); + expect(foundPost).to.exist; + expect(foundPost!.path).to.deep.equal(path); + }) + )); + + it("should update ltree correctly", () => + Promise.all( + connections.map(async connection => { + const path = 'News.Featured.Opinion'; + const path2 = 'News.Featured.Gossip'; + const postRepo = connection.getRepository(Post); + const post = new Post(); + post.path = path; + const persistedPost = await postRepo.save(post); + + await postRepo.update( + { id: persistedPost.id }, + { path: path2 } + ); + + const foundPost = await postRepo.findOne(persistedPost.id); + expect(foundPost).to.exist; + expect(foundPost!.path).to.deep.equal(path2); + }) + )); + + it("should re-save ltree correctly", () => + Promise.all( + connections.map(async connection => { + const path = 'News.Featured.Opinion'; + const path2 = 'News.Featured.Gossip'; + const postRepo = connection.getRepository(Post); + const post = new Post(); + post.path = path; + const persistedPost = await postRepo.save(post); + + persistedPost.path = path2; + await postRepo.save(persistedPost); + + const foundPost = await postRepo.findOne(persistedPost.id); + expect(foundPost).to.exist; + expect(foundPost!.path).to.deep.equal(path2); + }) + )); + + it("should persist ltree correctly with trailing '.'", () => + Promise.all( + connections.map(async connection => { + const path = 'News.Featured.Opinion.'; + const postRepo = connection.getRepository(Post); + const post = new Post(); + post.path = path; + const persistedPost = await postRepo.save(post); + const foundPost = await postRepo.findOne(persistedPost.id); + expect(foundPost).to.exist; + expect(foundPost!.path).to.deep.equal('News.Featured.Opinion'); + }) + )); + + it("should persist ltree correctly when containing spaces", () => + Promise.all( + connections.map(async connection => { + const path = 'News.Featured Story.Opinion'; + const postRepo = connection.getRepository(Post); + const post = new Post(); + post.path = path; + const persistedPost = await postRepo.save(post); + const foundPost = await postRepo.findOne(persistedPost.id); + expect(foundPost).to.exist; + expect(foundPost!.path).to.deep.equal('News.Featured_Story.Opinion'); + }) + )); + + it("should be able to query ltree correctly", () => + Promise.all( + connections.map(async connection => { + const path = 'News.Featured.Opinion'; + const postRepo = connection.getRepository(Post); + const post = new Post(); + post.path = path; + await postRepo.save(post); + const foundPost = await postRepo.createQueryBuilder().where(`path ~ 'news@.*'`).getOne() + expect(foundPost).to.exist; + expect(foundPost!.path).to.deep.equal(path); + }) + )); +}); + + From f270c0bbafa3628b5ba8cfa54bc9f8f216279255 Mon Sep 17 00:00:00 2001 From: Izzuddin Ahsanujunda Date: Sun, 2 Aug 2020 21:35:35 +0700 Subject: [PATCH 027/212] docs: remove out-of-place 'example:' (#6468) * modify docs/relational-query-builder.md --- docs/relational-query-builder.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/relational-query-builder.md b/docs/relational-query-builder.md index 247c41a576b..0e2e69a98b5 100644 --- a/docs/relational-query-builder.md +++ b/docs/relational-query-builder.md @@ -3,7 +3,6 @@ `RelationQueryBuilder` is a special type of `QueryBuilder` which allows you to work with your relations. Using it, you can bind entities to each other in the database without the need to load any entities, or you can load related entities easily. -Examples: For example, we have a `Post` entity and it has a many-to-many relation to `Category` called `categories`. Let's add a new category to this many-to-many relation: From 33041ccde5e46b95e1d10b1a15ad798b3a972651 Mon Sep 17 00:00:00 2001 From: James Ward Date: Sun, 2 Aug 2020 10:36:32 -0400 Subject: [PATCH 028/212] test: remove hardcoded test from github issue tst 2096 (#6463) the test had assumed the username, password, host, and port of the mysql server this update changes that so the test instead uses the config properly while still checking that the test works as expected --- test/github-issues/114/issue-114.ts | 2 +- test/github-issues/2096/issue-2096.ts | 17 +++++++++++++++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/test/github-issues/114/issue-114.ts b/test/github-issues/114/issue-114.ts index 0bf45946e2b..f3a322fb5c8 100644 --- a/test/github-issues/114/issue-114.ts +++ b/test/github-issues/114/issue-114.ts @@ -7,7 +7,7 @@ describe.skip("github issues > #114 Can not be parsed correctly the URL of pg.", let connection: Connection; before(() => { - connection = new Connection({ + connection = new Connection({ // Dummy Connection, won't be established type: "postgres", url: "postgres://test:test@localhost:5432/test", }); diff --git a/test/github-issues/2096/issue-2096.ts b/test/github-issues/2096/issue-2096.ts index 05cbfc11bb0..768f48b17be 100644 --- a/test/github-issues/2096/issue-2096.ts +++ b/test/github-issues/2096/issue-2096.ts @@ -2,6 +2,7 @@ import "reflect-metadata"; import { expect } from "chai"; import { createConnection } from "../../../src"; import { getTypeOrmConfig } from "../../utils/test-utils"; +import {MysqlConnectionOptions} from "../../../src/driver/mysql/MysqlConnectionOptions"; describe("github issues > #2096 [mysql] Database name isn't read from url", () => { it("should be possible to define a database by connection url for mysql", async () => { @@ -9,10 +10,22 @@ describe("github issues > #2096 [mysql] Database name isn't read from url", () = // it is important to synchronize here, to trigger EntityMetadataValidator.validate // that previously threw the error where the database on the driver object was undefined - if (config.find(c => c.name === "mysql" && !c.skip)) { + const mysqlConfig: MysqlConnectionOptions = config.find(c => c.name === "mysql" && !c.skip) as MysqlConnectionOptions; + + if (mysqlConfig) { + const { + username, + password, + host, + port, + database + } = mysqlConfig; + + const url = `mysql://${username}:${password}@${host}:${port}/${database}` + const connection = await createConnection({ name: "#2096", - url: "mysql://root:admin@localhost:3306/test", + url, entities: [__dirname + "/entity/*{.js,.ts}"], synchronize: true, type: "mysql" From 9750e3842cd28081ff16faf24e83fc9cccb10ccd Mon Sep 17 00:00:00 2001 From: James Ward Date: Fri, 7 Aug 2020 04:55:13 -0400 Subject: [PATCH 029/212] doc: use CircleCI for CI badge (#6516) * use CircleCI for CI badge Updates the badge to point at CircleCI for the passing / failing status * doc: use circleci badge in README (zh_CN) * doc: use circleci badge in readme in docs (zh_CN) * doc: use circleci badge under index in docs (zh_CN) --- README-zh_CN.md | 4 ++-- README.md | 4 ++-- docs/zh_CN/README.md | 4 ++-- docs/zh_CN/index.md | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/README-zh_CN.md b/README-zh_CN.md index 2c6f2e28066..e9e91bfc56f 100644 --- a/README-zh_CN.md +++ b/README-zh_CN.md @@ -4,8 +4,8 @@

- - + + diff --git a/README.md b/README.md index 2d4569693c2..2b59bb5733d 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,8 @@

- - + + diff --git a/docs/zh_CN/README.md b/docs/zh_CN/README.md index 348588f0a3d..c8e24aeee85 100644 --- a/docs/zh_CN/README.md +++ b/docs/zh_CN/README.md @@ -4,8 +4,8 @@

- - + + diff --git a/docs/zh_CN/index.md b/docs/zh_CN/index.md index ea48fa264c9..6d6893d0d47 100644 --- a/docs/zh_CN/index.md +++ b/docs/zh_CN/index.md @@ -4,8 +4,8 @@

- - + + From 21b51f3f0159c333c55bc2bb6e7b508d29182885 Mon Sep 17 00:00:00 2001 From: James Ward Date: Fri, 7 Aug 2020 04:55:36 -0400 Subject: [PATCH 030/212] docs: Update slack invite link for typeorm.io support page (#6524) closes #6523 --- docs/support.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/support.md b/docs/support.md index d69707290ac..62d2fdd4b88 100644 --- a/docs/support.md +++ b/docs/support.md @@ -10,7 +10,7 @@ If you have a question, you can ask it on [StackOverflow](https://stackoverflow. ### Want community support? -If you want community support, or simply want to chat with friendly TypeORM enthusiasts and users, you can do it on [Slack](https://join.slack.com/t/typeorm/shared_invite/enQtNDQ1MzA3MDA5MTExLTFiNDEyOGUxZGQyYWIwOTA0NDQxODdkOGQ0OTUxNzFjYjUwY2E0ZmFlODc5OTYyYzAzNGM3MGZjYzhjYTBiZTY). +If you want community support, or simply want to chat with friendly TypeORM enthusiasts and users, you can do it on [Slack](https://join.slack.com/t/typeorm/shared_invite/zt-gej3gc00-hR~L~DqGUJ7qOpGy4SSq3g). ### Want professional commercial support? From 6b795a8b997801d5f9c01cd9a33747262da40a15 Mon Sep 17 00:00:00 2001 From: Ilan <36084092+ilanolkies@users.noreply.github.com> Date: Sun, 16 Aug 2020 07:46:43 -0300 Subject: [PATCH 031/212] docs: update supported-platforms.md (#6545) --- docs/supported-platforms.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/supported-platforms.md b/docs/supported-platforms.md index aac244adc49..ec817e6e843 100644 --- a/docs/supported-platforms.md +++ b/docs/supported-platforms.md @@ -61,7 +61,7 @@ You have the option to choose between module loaders just like in browser packag For an example how to use TypeORM in Cordova see [typeorm/cordova-example](https://github.com/typeorm/cordova-example) and for Ionic see [typeorm/ionic-example](https://github.com/typeorm/ionic-example). **Important**: For use with Ionic, a custom webpack config file is needed! Please checkout the example to see the needed changes. ## React Native -TypeORM is able to run on React Native apps using the [react-native-sqlite-storage](https://github.com/andpor/react-native-sqlite-storage) plugin. For an example see [typeom/react-native-example](https://github.com/typeorm/react-native-example). +TypeORM is able to run on React Native apps using the [react-native-sqlite-storage](https://github.com/andpor/react-native-sqlite-storage) plugin. For an example see [typeorm/react-native-example](https://github.com/typeorm/react-native-example). ## Expo From 92f2554f098eed50a39b977bc96dedff059be09a Mon Sep 17 00:00:00 2001 From: Ashwin Ramaswami Date: Sun, 16 Aug 2020 06:47:18 -0400 Subject: [PATCH 032/212] docs: fix typos (#6538) --- src/error/FindRelationsNotFoundError.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/error/FindRelationsNotFoundError.ts b/src/error/FindRelationsNotFoundError.ts index 8b44bfc620f..99a9e509f91 100644 --- a/src/error/FindRelationsNotFoundError.ts +++ b/src/error/FindRelationsNotFoundError.ts @@ -7,10 +7,10 @@ export class FindRelationsNotFoundError extends Error { super(); Object.setPrototypeOf(this, FindRelationsNotFoundError.prototype); if (notFoundRelations.length === 1) { - this.message = `Relation "${notFoundRelations[0]}" was not found, please check if it is correct and really exist in your entity.`; + this.message = `Relation "${notFoundRelations[0]}" was not found; please check if it is correct and really exists in your entity.`; } else { - this.message = `Relations ${notFoundRelations.map(relation => `"${relation}"`).join(", ")} were not found, please check if relations are correct and they exist in your entities.`; + this.message = `Relations ${notFoundRelations.map(relation => `"${relation}"`).join(", ")} were not found; please check if relations are correct and they exist in your entities.`; } } -} \ No newline at end of file +} From 15afef3c9e41e93b42644d577161453fe4e6cd65 Mon Sep 17 00:00:00 2001 From: James Ward Date: Sun, 16 Aug 2020 07:15:14 -0400 Subject: [PATCH 033/212] chore: discourage questions as issues (#6535) --- ISSUE_TEMPLATE.md | 8 +++++++- docs/support.md | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md index 8e96c64ffa5..7dc654f6150 100644 --- a/ISSUE_TEMPLATE.md +++ b/ISSUE_TEMPLATE.md @@ -1,6 +1,12 @@ **Issue type:** -[ ] question + + [ ] bug report [ ] feature request [ ] documentation issue diff --git a/docs/support.md b/docs/support.md index 62d2fdd4b88..aaf7229434a 100644 --- a/docs/support.md +++ b/docs/support.md @@ -6,7 +6,7 @@ If you found a bug, issue, or you just want to propose a new feature, create [an ### Have a question? -If you have a question, you can ask it on [StackOverflow](https://stackoverflow.com/questions/tagged/typeorm). +If you have a question, you can ask it on [StackOverflow](https://stackoverflow.com/questions/tagged/typeorm) or other community support channels. ### Want community support? From 31029bdfd4164b4056f48c4905a8aa64e60b6a98 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 16 Aug 2020 16:21:06 +0500 Subject: [PATCH 034/212] chore(deps-dev): bump class-transformer from 0.2.3 to 0.3.1 (#6532) Bumps [class-transformer](https://github.com/typestack/class-transformer) from 0.2.3 to 0.3.1. - [Release notes](https://github.com/typestack/class-transformer/releases) - [Changelog](https://github.com/typestack/class-transformer/blob/develop/CHANGELOG.md) - [Commits](https://github.com/typestack/class-transformer/compare/v0.2.3...v0.3.1) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 138 +++++++++++++++++++++++----------------------- package.json | 2 +- 2 files changed, 70 insertions(+), 70 deletions(-) diff --git a/package-lock.json b/package-lock.json index a25b244d674..bc7c689f524 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1319,9 +1319,9 @@ "dev": true }, "class-transformer": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.2.3.tgz", - "integrity": "sha512-qsP+0xoavpOlJHuYsQJsN58HXSl8Jvveo+T37rEvCEeRfMWoytAyR0Ua/YsFgpM6AZYZ/og2PJwArwzJl1aXtQ==", + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.3.1.tgz", + "integrity": "sha512-cKFwohpJbuMovS8xVLmn8N2AUbAuc8pVo4zEfsUVo8qgECOogns1WVk/FkOZoxhOPTyTYFckuoH+13FO+MQ8GA==", "dev": true }, "class-utils": { @@ -3316,28 +3316,28 @@ "dependencies": { "abbrev": { "version": "1.1.1", - "resolved": "", + "resolved": false, "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", "dev": true, "optional": true }, "ansi-regex": { "version": "2.1.1", - "resolved": "", + "resolved": false, "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", "dev": true, "optional": true }, "aproba": { "version": "1.2.0", - "resolved": "", + "resolved": false, "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", "dev": true, "optional": true }, "are-we-there-yet": { "version": "1.1.4", - "resolved": "", + "resolved": false, "integrity": "sha1-u13KOCu5TwXhUZQ3PRb9O6HKEQ0=", "dev": true, "optional": true, @@ -3348,14 +3348,14 @@ }, "balanced-match": { "version": "1.0.0", - "resolved": "", + "resolved": false, "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", "dev": true, "optional": true }, "brace-expansion": { "version": "1.1.11", - "resolved": "", + "resolved": false, "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "optional": true, @@ -3366,35 +3366,35 @@ }, "code-point-at": { "version": "1.1.0", - "resolved": "", + "resolved": false, "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", "dev": true, "optional": true }, "concat-map": { "version": "0.0.1", - "resolved": "", + "resolved": false, "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true, "optional": true }, "console-control-strings": { "version": "1.1.0", - "resolved": "", + "resolved": false, "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", "dev": true, "optional": true }, "core-util-is": { "version": "1.0.2", - "resolved": "", + "resolved": false, "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", "dev": true, "optional": true }, "debug": { "version": "2.6.9", - "resolved": "", + "resolved": false, "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "optional": true, @@ -3404,35 +3404,35 @@ }, "deep-extend": { "version": "0.5.1", - "resolved": "", + "resolved": false, "integrity": "sha512-N8vBdOa+DF7zkRrDCsaOXoCs/E2fJfx9B9MrKnnSiHNh4ws7eSys6YQE4KvT1cecKmOASYQBhbKjeuDD9lT81w==", "dev": true, "optional": true }, "delegates": { "version": "1.0.0", - "resolved": "", + "resolved": false, "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", "dev": true, "optional": true }, "detect-libc": { "version": "1.0.3", - "resolved": "", + "resolved": false, "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", "dev": true, "optional": true }, "fs.realpath": { "version": "1.0.0", - "resolved": "", + "resolved": false, "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true, "optional": true }, "gauge": { "version": "2.7.4", - "resolved": "", + "resolved": false, "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", "dev": true, "optional": true, @@ -3449,7 +3449,7 @@ }, "glob": { "version": "7.1.2", - "resolved": "", + "resolved": false, "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", "dev": true, "optional": true, @@ -3464,14 +3464,14 @@ }, "has-unicode": { "version": "2.0.1", - "resolved": "", + "resolved": false, "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", "dev": true, "optional": true }, "iconv-lite": { "version": "0.4.21", - "resolved": "", + "resolved": false, "integrity": "sha512-En5V9za5mBt2oUA03WGD3TwDv0MKAruqsuxstbMUZaj9W9k/m1CV/9py3l0L5kw9Bln8fdHQmzHSYtvpvTLpKw==", "dev": true, "optional": true, @@ -3481,7 +3481,7 @@ }, "ignore-walk": { "version": "3.0.1", - "resolved": "", + "resolved": false, "integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==", "dev": true, "optional": true, @@ -3491,7 +3491,7 @@ }, "inflight": { "version": "1.0.6", - "resolved": "", + "resolved": false, "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dev": true, "optional": true, @@ -3502,21 +3502,21 @@ }, "inherits": { "version": "2.0.3", - "resolved": "", + "resolved": false, "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", "dev": true, "optional": true }, "ini": { "version": "1.3.5", - "resolved": "", + "resolved": false, "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", "dev": true, "optional": true }, "is-fullwidth-code-point": { "version": "1.0.0", - "resolved": "", + "resolved": false, "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "dev": true, "optional": true, @@ -3526,14 +3526,14 @@ }, "isarray": { "version": "1.0.0", - "resolved": "", + "resolved": false, "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", "dev": true, "optional": true }, "minimatch": { "version": "3.0.4", - "resolved": "", + "resolved": false, "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, "optional": true, @@ -3543,14 +3543,14 @@ }, "minimist": { "version": "0.0.8", - "resolved": "", + "resolved": false, "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", "dev": true, "optional": true }, "mkdirp": { "version": "0.5.1", - "resolved": "", + "resolved": false, "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "dev": true, "optional": true, @@ -3560,14 +3560,14 @@ }, "ms": { "version": "2.0.0", - "resolved": "", + "resolved": false, "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true, "optional": true }, "needle": { "version": "2.2.0", - "resolved": "", + "resolved": false, "integrity": "sha512-eFagy6c+TYayorXw/qtAdSvaUpEbBsDwDyxYFgLZ0lTojfH7K+OdBqAF7TAFwDokJaGpubpSGG0wO3iC0XPi8w==", "dev": true, "optional": true, @@ -3579,7 +3579,7 @@ }, "node-pre-gyp": { "version": "0.10.0", - "resolved": "", + "resolved": false, "integrity": "sha512-G7kEonQLRbcA/mOoFoxvlMrw6Q6dPf92+t/l0DFSMuSlDoWaI9JWIyPwK0jyE1bph//CUEL65/Fz1m2vJbmjQQ==", "dev": true, "optional": true, @@ -3598,7 +3598,7 @@ }, "nopt": { "version": "4.0.1", - "resolved": "", + "resolved": false, "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", "dev": true, "optional": true, @@ -3609,14 +3609,14 @@ }, "npm-bundled": { "version": "1.0.3", - "resolved": "", + "resolved": false, "integrity": "sha512-ByQ3oJ/5ETLyglU2+8dBObvhfWXX8dtPZDMePCahptliFX2iIuhyEszyFk401PZUNQH20vvdW5MLjJxkwU80Ow==", "dev": true, "optional": true }, "npm-packlist": { "version": "1.1.10", - "resolved": "", + "resolved": false, "integrity": "sha512-AQC0Dyhzn4EiYEfIUjCdMl0JJ61I2ER9ukf/sLxJUcZHfo+VyEfz2rMJgLZSS1v30OxPQe1cN0LZA1xbcaVfWA==", "dev": true, "optional": true, @@ -3627,7 +3627,7 @@ }, "npmlog": { "version": "4.1.2", - "resolved": "", + "resolved": false, "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", "dev": true, "optional": true, @@ -3640,21 +3640,21 @@ }, "number-is-nan": { "version": "1.0.1", - "resolved": "", + "resolved": false, "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", "dev": true, "optional": true }, "object-assign": { "version": "4.1.1", - "resolved": "", + "resolved": false, "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", "dev": true, "optional": true }, "once": { "version": "1.4.0", - "resolved": "", + "resolved": false, "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, "optional": true, @@ -3664,21 +3664,21 @@ }, "os-homedir": { "version": "1.0.2", - "resolved": "", + "resolved": false, "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", "dev": true, "optional": true }, "os-tmpdir": { "version": "1.0.2", - "resolved": "", + "resolved": false, "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", "dev": true, "optional": true }, "osenv": { "version": "0.1.5", - "resolved": "", + "resolved": false, "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", "dev": true, "optional": true, @@ -3689,21 +3689,21 @@ }, "path-is-absolute": { "version": "1.0.1", - "resolved": "", + "resolved": false, "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "dev": true, "optional": true }, "process-nextick-args": { "version": "2.0.0", - "resolved": "", + "resolved": false, "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", "dev": true, "optional": true }, "rc": { "version": "1.2.7", - "resolved": "", + "resolved": false, "integrity": "sha512-LdLD8xD4zzLsAT5xyushXDNscEjB7+2ulnl8+r1pnESlYtlJtVSoCMBGr30eDRJ3+2Gq89jK9P9e4tCEH1+ywA==", "dev": true, "optional": true, @@ -3716,7 +3716,7 @@ "dependencies": { "minimist": { "version": "1.2.0", - "resolved": "", + "resolved": false, "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true, "optional": true @@ -3725,7 +3725,7 @@ }, "readable-stream": { "version": "2.3.6", - "resolved": "", + "resolved": false, "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "optional": true, @@ -3741,7 +3741,7 @@ }, "rimraf": { "version": "2.6.2", - "resolved": "", + "resolved": false, "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", "dev": true, "optional": true, @@ -3751,49 +3751,49 @@ }, "safe-buffer": { "version": "5.1.1", - "resolved": "", + "resolved": false, "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", "dev": true, "optional": true }, "safer-buffer": { "version": "2.1.2", - "resolved": "", + "resolved": false, "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true, "optional": true }, "sax": { "version": "1.2.4", - "resolved": "", + "resolved": false, "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", "dev": true, "optional": true }, "semver": { "version": "5.5.0", - "resolved": "", + "resolved": false, "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", "dev": true, "optional": true }, "set-blocking": { "version": "2.0.0", - "resolved": "", + "resolved": false, "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", "dev": true, "optional": true }, "signal-exit": { "version": "3.0.2", - "resolved": "", + "resolved": false, "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", "dev": true, "optional": true }, "string-width": { "version": "1.0.2", - "resolved": "", + "resolved": false, "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, "optional": true, @@ -3805,7 +3805,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "", + "resolved": false, "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "optional": true, @@ -3815,7 +3815,7 @@ }, "strip-ansi": { "version": "3.0.1", - "resolved": "", + "resolved": false, "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "optional": true, @@ -3825,7 +3825,7 @@ }, "strip-json-comments": { "version": "2.0.1", - "resolved": "", + "resolved": false, "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", "dev": true, "optional": true @@ -3857,14 +3857,14 @@ }, "util-deprecate": { "version": "1.0.2", - "resolved": "", + "resolved": false, "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", "dev": true, "optional": true }, "wide-align": { "version": "1.1.2", - "resolved": "", + "resolved": false, "integrity": "sha512-ijDLlyQ7s6x1JgCLur53osjm/UXUYD9+0PbYKrBsYisYXzCxN+HC3mYDNy/dWdmf3AwqwU3CXwDCvsNgGK1S0w==", "dev": true, "optional": true, @@ -3874,7 +3874,7 @@ }, "wrappy": { "version": "1.0.2", - "resolved": "", + "resolved": false, "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true, "optional": true @@ -4404,7 +4404,7 @@ }, "os-locale": { "version": "1.4.0", - "resolved": "http://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", "dev": true, "requires": { @@ -5510,7 +5510,7 @@ }, "is-accessor-descriptor": { "version": "0.1.6", - "resolved": "http://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", "dev": true, "requires": { @@ -5575,7 +5575,7 @@ }, "is-data-descriptor": { "version": "0.1.4", - "resolved": "http://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", "dev": true, "requires": { @@ -6312,7 +6312,7 @@ }, "load-json-file": { "version": "1.1.0", - "resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", "dev": true, "requires": { @@ -6325,7 +6325,7 @@ "dependencies": { "pify": { "version": "2.3.0", - "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", "dev": true } @@ -7863,7 +7863,7 @@ "dependencies": { "pify": { "version": "2.3.0", - "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", "dev": true } diff --git a/package.json b/package.json index 065b53c0fc7..0491d0c5903 100644 --- a/package.json +++ b/package.json @@ -62,7 +62,7 @@ "better-sqlite3": "^7.0.1", "chai": "^4.2.0", "chai-as-promised": "^7.1.1", - "class-transformer": "^0.2.3", + "class-transformer": "^0.3.1", "conventional-changelog-angular": "^5.0.3", "conventional-changelog-cli": "^2.0.21", "del": "^3.0.0", From c96ab43f3cef0d38f4107401e040c355c5df7d95 Mon Sep 17 00:00:00 2001 From: James Ward Date: Mon, 17 Aug 2020 15:21:13 -0400 Subject: [PATCH 035/212] build: use `npm install` to work around npm/cli#558 (#6571) the lockfile we use was generated on a mac & includes `fsevents` as a dependency. while this is optional for OSX it's not available for linux & this causes problems with the `npm ci` command. npm v7 will correct this but until we're using that we should switch to using npm install --- .circleci/config.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 522f720b766..2e889df0d10 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -41,10 +41,15 @@ commands: name: Restore node_modules cache key: node_modules-<< parameters.cache-key >>-{{ checksum "package-lock.json" }} - run: + name: Verify `package.json` and `package-lock.json` are in sync + command: npx lock-verify + - run: + # This uses `npm install` instead of `npm ci` + # because of https://github.com/npm/cli/issues/558 name: Install Node Packages command: | if [ ! -d node_modules ]; then - npm ci + npm install fi - save_cache: name: Save node_modules cache From 10d0aea9c0cbfec99088ed6fa392fa15b8e57961 Mon Sep 17 00:00:00 2001 From: James Ward Date: Wed, 19 Aug 2020 13:15:18 -0400 Subject: [PATCH 036/212] chore: pin version of cockroach to a known good version (#6585) --- .circleci/config.yml | 2 +- docker-compose.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 2e889df0d10..a025996aa66 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -108,7 +108,7 @@ jobs: POSTGRES_USER: "test" POSTGRES_PASSWORD: "test" POSTGRES_DB: "test" - - image: cockroachdb/cockroach:latest + - image: cockroachdb/cockroach:v19.2.9 name: cockroachdb command: start --insecure - image: circleci/mongo:3.4.18 diff --git a/docker-compose.yml b/docker-compose.yml index 81a000efc5f..0ee126dc3f0 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -62,7 +62,7 @@ services: # cockroachdb cockroachdb: - image: "cockroachdb/cockroach-unstable:v19.1.0-rc.2" + image: "cockroachdb/cockroach:v19.2.9" container_name: "typeorm-cockroachdb" command: start --insecure ports: From 5a9150e65e413cd1f5fd50788efe233ae9f09e0b Mon Sep 17 00:00:00 2001 From: James Ward Date: Wed, 19 Aug 2020 15:04:19 -0400 Subject: [PATCH 037/212] chore: remove uneccessary cockroachdriver calls in view-entity tests (#6587) this is a backport of changes from the `next` branch --- test/functional/view-entity/mssql/view-entity-mssql.ts | 7 ++----- test/functional/view-entity/mysql/view-entity-mysql.ts | 7 ++----- test/functional/view-entity/oracle/view-entity-oracle.ts | 7 ++----- .../view-entity/postgres/view-entity-postgres.ts | 7 ++----- test/functional/view-entity/sqlite/view-entity-sqlite.ts | 7 ++----- 5 files changed, 10 insertions(+), 25 deletions(-) diff --git a/test/functional/view-entity/mssql/view-entity-mssql.ts b/test/functional/view-entity/mssql/view-entity-mssql.ts index 274f6d34a8e..451d8aeff72 100644 --- a/test/functional/view-entity/mssql/view-entity-mssql.ts +++ b/test/functional/view-entity/mssql/view-entity-mssql.ts @@ -1,6 +1,5 @@ import {expect} from "chai"; import "reflect-metadata"; -import {CockroachDriver} from "../../../../src/driver/cockroachdb/CockroachDriver"; import {Category} from "./entity/Category"; import {Connection} from "../../../../src"; import {closeTestingConnections, createTestingConnections, reloadTestingDatabases} from "../../../utils/test-utils"; @@ -49,13 +48,11 @@ describe("view entity > mssql", () => { const postCategories = await connection.manager.find(PostCategory); postCategories.length.should.be.equal(2); - const postId1 = connection.driver instanceof CockroachDriver ? "1" : 1; - postCategories[0].id.should.be.equal(postId1); + postCategories[0].id.should.be.equal(1); postCategories[0].postName.should.be.equal("About BMW"); postCategories[0].categoryName.should.be.equal("Cars"); - const postId2 = connection.driver instanceof CockroachDriver ? "2" : 2; - postCategories[1].id.should.be.equal(postId2); + postCategories[1].id.should.be.equal(2); postCategories[1].postName.should.be.equal("About Boeing"); postCategories[1].categoryName.should.be.equal("Airplanes"); diff --git a/test/functional/view-entity/mysql/view-entity-mysql.ts b/test/functional/view-entity/mysql/view-entity-mysql.ts index 4ff2e3c84d5..0e8ca35a752 100644 --- a/test/functional/view-entity/mysql/view-entity-mysql.ts +++ b/test/functional/view-entity/mysql/view-entity-mysql.ts @@ -1,6 +1,5 @@ import {expect} from "chai"; import "reflect-metadata"; -import {CockroachDriver} from "../../../../src/driver/cockroachdb/CockroachDriver"; import {Category} from "./entity/Category"; import {Connection} from "../../../../src"; import {closeTestingConnections, createTestingConnections, reloadTestingDatabases} from "../../../utils/test-utils"; @@ -49,13 +48,11 @@ describe("view entity > mysql", () => { const postCategories = await connection.manager.find(PostCategory); postCategories.length.should.be.equal(2); - const postId1 = connection.driver instanceof CockroachDriver ? "1" : 1; - postCategories[0].id.should.be.equal(postId1); + postCategories[0].id.should.be.equal(1); postCategories[0].postName.should.be.equal("About BMW"); postCategories[0].categoryName.should.be.equal("Cars"); - const postId2 = connection.driver instanceof CockroachDriver ? "2" : 2; - postCategories[1].id.should.be.equal(postId2); + postCategories[1].id.should.be.equal(2); postCategories[1].postName.should.be.equal("About Boeing"); postCategories[1].categoryName.should.be.equal("Airplanes"); diff --git a/test/functional/view-entity/oracle/view-entity-oracle.ts b/test/functional/view-entity/oracle/view-entity-oracle.ts index 61cbc0f8173..620cd11e008 100644 --- a/test/functional/view-entity/oracle/view-entity-oracle.ts +++ b/test/functional/view-entity/oracle/view-entity-oracle.ts @@ -1,6 +1,5 @@ import {expect} from "chai"; import "reflect-metadata"; -import {CockroachDriver} from "../../../../src/driver/cockroachdb/CockroachDriver"; import {Category} from "./entity/Category"; import {Connection} from "../../../../src"; import {closeTestingConnections, createTestingConnections, reloadTestingDatabases} from "../../../utils/test-utils"; @@ -49,13 +48,11 @@ describe("view entity > oracle", () => { const postCategories = await connection.manager.find(PostCategory); postCategories.length.should.be.equal(2); - const postId1 = connection.driver instanceof CockroachDriver ? "1" : 1; - postCategories[0].id.should.be.equal(postId1); + postCategories[0].id.should.be.equal(1); postCategories[0].postName.should.be.equal("About BMW"); postCategories[0].categoryName.should.be.equal("Cars"); - const postId2 = connection.driver instanceof CockroachDriver ? "2" : 2; - postCategories[1].id.should.be.equal(postId2); + postCategories[1].id.should.be.equal(2); postCategories[1].postName.should.be.equal("About Boeing"); postCategories[1].categoryName.should.be.equal("Airplanes"); diff --git a/test/functional/view-entity/postgres/view-entity-postgres.ts b/test/functional/view-entity/postgres/view-entity-postgres.ts index c034a4d7465..eb56de2e710 100644 --- a/test/functional/view-entity/postgres/view-entity-postgres.ts +++ b/test/functional/view-entity/postgres/view-entity-postgres.ts @@ -1,6 +1,5 @@ import {expect} from "chai"; import "reflect-metadata"; -import {CockroachDriver} from "../../../../src/driver/cockroachdb/CockroachDriver"; import {Category} from "./entity/Category"; import {Connection} from "../../../../src"; import {closeTestingConnections, createTestingConnections, reloadTestingDatabases} from "../../../utils/test-utils"; @@ -75,13 +74,11 @@ describe("view entity > postgres", () => { const postCategories = await connection.manager.find(PostCategory); postCategories.length.should.be.equal(2); - const postId1 = connection.driver instanceof CockroachDriver ? "1" : 1; - postCategories[0].id.should.be.equal(postId1); + postCategories[0].id.should.be.equal(1); postCategories[0].postName.should.be.equal("About BMW"); postCategories[0].categoryName.should.be.equal("Cars"); - const postId2 = connection.driver instanceof CockroachDriver ? "2" : 2; - postCategories[1].id.should.be.equal(postId2); + postCategories[1].id.should.be.equal(2); postCategories[1].postName.should.be.equal("About Boeing"); postCategories[1].categoryName.should.be.equal("Airplanes"); diff --git a/test/functional/view-entity/sqlite/view-entity-sqlite.ts b/test/functional/view-entity/sqlite/view-entity-sqlite.ts index 108c9bbea1a..3fe63aa72ef 100644 --- a/test/functional/view-entity/sqlite/view-entity-sqlite.ts +++ b/test/functional/view-entity/sqlite/view-entity-sqlite.ts @@ -1,6 +1,5 @@ import {expect} from "chai"; import "reflect-metadata"; -import {CockroachDriver} from "../../../../src/driver/cockroachdb/CockroachDriver"; import {Category} from "./entity/Category"; import {Connection} from "../../../../src"; import {closeTestingConnections, createTestingConnections, reloadTestingDatabases} from "../../../utils/test-utils"; @@ -49,13 +48,11 @@ describe("view entity > sqlite", () => { const postCategories = await connection.manager.find(PostCategory); postCategories.length.should.be.equal(2); - const postId1 = connection.driver instanceof CockroachDriver ? "1" : 1; - postCategories[0].id.should.be.equal(postId1); + postCategories[0].id.should.be.equal(1); postCategories[0].postName.should.be.equal("About BMW"); postCategories[0].categoryName.should.be.equal("Cars"); - const postId2 = connection.driver instanceof CockroachDriver ? "2" : 2; - postCategories[1].id.should.be.equal(postId2); + postCategories[1].id.should.be.equal(2); postCategories[1].postName.should.be.equal("About Boeing"); postCategories[1].categoryName.should.be.equal("Airplanes"); From 9d2df28b4c8c22024566a86a231db64ae2c09161 Mon Sep 17 00:00:00 2001 From: Lachlan McCarty Date: Sun, 23 Aug 2020 04:29:30 -0400 Subject: [PATCH 038/212] fix: change InsertQueryBuilder.values() with an empty array into a no-op (#6584) Change InsertQueryBuilder.values() with an empty array into a no-op instead of the current behavior of inserting a row of DEFAULT values. Closes: #3111 --- src/entity-manager/EntityManager.ts | 11 --------- src/query-builder/InsertQueryBuilder.ts | 19 ++++++++++++---- test/github-issues/3111/entity/Test.ts | 14 ++++++++++++ test/github-issues/3111/issue-3111.ts | 30 +++++++++++++++++++++++++ 4 files changed, 59 insertions(+), 15 deletions(-) create mode 100644 test/github-issues/3111/entity/Test.ts create mode 100644 test/github-issues/3111/issue-3111.ts diff --git a/src/entity-manager/EntityManager.ts b/src/entity-manager/EntityManager.ts index bb9979fa7b6..5ed47b36902 100644 --- a/src/entity-manager/EntityManager.ts +++ b/src/entity-manager/EntityManager.ts @@ -581,17 +581,6 @@ export class EntityManager { * You can execute bulk inserts using this method. */ async insert(target: ObjectType|EntitySchema|string, entity: QueryDeepPartialEntity|(QueryDeepPartialEntity[])): Promise { - - // If user passed empty array of entities then we don't need to do - // anything. - // - // Fixes GitHub issue #5734. If we were to let this through we would - // run into problems downstream, like subscribers getting invoked with - // the empty array where they expect an entity, and SQL queries with an - // empty VALUES clause. - if (Array.isArray(entity) && entity.length === 0) - return Promise.resolve(new InsertResult()); - // TODO: Oracle does not support multiple values. Need to create another nice solution. if (this.connection.driver instanceof OracleDriver && Array.isArray(entity)) { const results = await Promise.all(entity.map(entity => this.insert(target, entity))); diff --git a/src/query-builder/InsertQueryBuilder.ts b/src/query-builder/InsertQueryBuilder.ts index 480a93ac044..106cd41494b 100644 --- a/src/query-builder/InsertQueryBuilder.ts +++ b/src/query-builder/InsertQueryBuilder.ts @@ -41,6 +41,20 @@ export class InsertQueryBuilder extends QueryBuilder { * Executes sql generated by query builder and returns raw database results. */ async execute(): Promise { + // console.time(".value sets"); + const valueSets: ObjectLiteral[] = this.getValueSets(); + // console.timeEnd(".value sets"); + + // If user passed empty array of entities then we don't need to do + // anything. + // + // Fixes GitHub issues #3111 and #5734. If we were to let this through + // we would run into problems downstream, like subscribers getting + // invoked with the empty array where they expect an entity, and SQL + // queries with an empty VALUES clause. + if (valueSets.length === 0) + return new InsertResult(); + // console.time("QueryBuilder.execute"); // console.time(".database stuff"); const queryRunner = this.obtainQueryRunner(); @@ -55,9 +69,6 @@ export class InsertQueryBuilder extends QueryBuilder { } // console.timeEnd(".database stuff"); - // console.time(".value sets"); - const valueSets: ObjectLiteral[] = this.getValueSets(); - // console.timeEnd(".value sets"); // call before insertion methods in listeners and subscribers if (this.expressionMap.callListeners === true && this.expressionMap.mainAlias!.hasMetadata) { @@ -579,7 +590,7 @@ export class InsertQueryBuilder extends QueryBuilder { * Gets array of values need to be inserted into the target table. */ protected getValueSets(): ObjectLiteral[] { - if (Array.isArray(this.expressionMap.valuesSet) && this.expressionMap.valuesSet.length > 0) + if (Array.isArray(this.expressionMap.valuesSet)) return this.expressionMap.valuesSet; if (this.expressionMap.valuesSet instanceof Object) diff --git a/test/github-issues/3111/entity/Test.ts b/test/github-issues/3111/entity/Test.ts new file mode 100644 index 00000000000..dfcf3d22775 --- /dev/null +++ b/test/github-issues/3111/entity/Test.ts @@ -0,0 +1,14 @@ +import {Column} from "../../../../src/decorator/columns/Column"; +import {Entity} from "../../../../src/decorator/entity/Entity"; +import {PrimaryGeneratedColumn} from "../../../../src/decorator/columns/PrimaryGeneratedColumn"; + +export const DEFAULT_VALUE = "default-value"; + +@Entity() +export class Test { + @PrimaryGeneratedColumn() + id: number; + + @Column({default: DEFAULT_VALUE}) + value: string; +} diff --git a/test/github-issues/3111/issue-3111.ts b/test/github-issues/3111/issue-3111.ts new file mode 100644 index 00000000000..614525200f6 --- /dev/null +++ b/test/github-issues/3111/issue-3111.ts @@ -0,0 +1,30 @@ +import "reflect-metadata"; +import {createTestingConnections, closeTestingConnections, reloadTestingDatabases} from "../../utils/test-utils"; +import {Connection} from "../../../src/connection/Connection"; +import {expect} from "chai"; +import {InsertValuesMissingError} from "../../../src/error/InsertValuesMissingError"; +import {Test, DEFAULT_VALUE} from "./entity/Test"; + +describe("github issues > #3111 Inserting with query builder attempts to insert a default row when values is empty array", () => { + + let connections: Connection[]; + before(async () => connections = await createTestingConnections({ + entities: [__dirname + "/entity/*{.js,.ts}"], + schemaCreate: true, + dropSchema: true, + })); + beforeEach(() => reloadTestingDatabases(connections)); + after(() => closeTestingConnections(connections)); + + it("should not insert with default values on .values([])", () => Promise.all(connections.map(async connection => { + const repo = connection.getRepository(Test); + await repo.createQueryBuilder().insert().values([]).execute(); + const rowsWithDefaultValue = await repo.find({ where: {value: DEFAULT_VALUE}}); + expect(rowsWithDefaultValue).to.have.lengthOf(0); + }))); + + it("should still error on missing .values()", () => Promise.all(connections.map(async connection => { + const repo = connection.getRepository(Test); + await repo.createQueryBuilder().insert().execute().should.be.rejectedWith(InsertValuesMissingError); + }))); +}); From 8d90d403627f949dc8bf1bf32dc33c918b55f6eb Mon Sep 17 00:00:00 2001 From: Matthias Kunnen Date: Sun, 23 Aug 2020 10:35:16 +0200 Subject: [PATCH 039/212] fix: DeepPartial with any and {[k: string]: any} (#6581) * test: Test DeepPartial with any and {[k: string]: any} This tests #6580. * fix: DeepPartial with any and {[k: string]: any} Fixes #6580. --- src/common/DeepPartial.ts | 2 +- test/github-issues/6580/entity/Comment.ts | 4 ++++ test/github-issues/6580/issue-6580.ts | 24 +++++++++++++++++++++++ 3 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 test/github-issues/6580/entity/Comment.ts create mode 100644 test/github-issues/6580/issue-6580.ts diff --git a/src/common/DeepPartial.ts b/src/common/DeepPartial.ts index c318088d541..370c1f5f2d9 100644 --- a/src/common/DeepPartial.ts +++ b/src/common/DeepPartial.ts @@ -5,5 +5,5 @@ export type DeepPartial = { [P in keyof T]?: T[P] extends Array ? Array> : T[P] extends ReadonlyArray ? ReadonlyArray> : - DeepPartial + DeepPartial | T[P] }; diff --git a/test/github-issues/6580/entity/Comment.ts b/test/github-issues/6580/entity/Comment.ts new file mode 100644 index 00000000000..1ef8a1139b2 --- /dev/null +++ b/test/github-issues/6580/entity/Comment.ts @@ -0,0 +1,4 @@ +export class Comment { + any: any; + object: {[k: string]: any}; +} diff --git a/test/github-issues/6580/issue-6580.ts b/test/github-issues/6580/issue-6580.ts new file mode 100644 index 00000000000..d309ad411e9 --- /dev/null +++ b/test/github-issues/6580/issue-6580.ts @@ -0,0 +1,24 @@ +import {DeepPartial} from "../../../src"; +import {Comment} from "./entity/Comment"; + +describe("github issues > #6580 DeepPartial does not handle `any` and `{[k: string]}`", () => { + + function attemptDeepPartial(entityLike: DeepPartial): void { + } + + it("DeepPartial should correctly handle any", () => { + attemptDeepPartial({ + any: { + foo: 'bar', + } + }) + }); + + it("DeepPartial should correctly handle {[k: string]: any}", () => { + attemptDeepPartial({ + object: { + foo: 'bar' + }, + }) + }); +}); From d1ed5723bb55d4124be13b21e57d9f729d0bae1a Mon Sep 17 00:00:00 2001 From: James Ward Date: Mon, 24 Aug 2020 04:12:03 -0400 Subject: [PATCH 040/212] build: use docker-compose for database services (#6602) --- .circleci/config.yml | 92 ++++++++++++++++++++++------------ ormconfig.circleci-common.json | 66 ++++++++++++++---------- 2 files changed, 100 insertions(+), 58 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index a025996aa66..9c4526781ef 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -93,42 +93,72 @@ jobs: working_directory: ~/typeorm docker: - image: circleci/node:<< parameters.node-version >> - - image: mysql:5.7.24 - environment: - MYSQL_ROOT_PASSWORD: "admin" - MYSQL_DATABASE: "test" - - image: mariadb:10.1.37 - name: mariadb - environment: - MYSQL_ROOT_PASSWORD: "admin" - MYSQL_DATABASE: "test" - - image: circleci/postgres:9.6.11-postgis - name: postgres - environment: - POSTGRES_USER: "test" - POSTGRES_PASSWORD: "test" - POSTGRES_DB: "test" - - image: cockroachdb/cockroach:v19.2.9 - name: cockroachdb - command: start --insecure - - image: circleci/mongo:3.4.18 - name: mongodb - - image: mcr.microsoft.com/mssql/server:2017-latest - name: mssql - environment: - SA_PASSWORD: "Admin123" - ACCEPT_EULA: "Y" - steps: - checkout + - setup_remote_docker - attach_workspace: at: ~/typeorm - create-typeorm-config: databases: << parameters.databases >> - # Download and cache dependencies + - run: + name: Start all Relevant Services + command: | + SERVICES=$( + npx js-yaml ./docker-compose.yml \ + | jq -r '.services | keys | map(select(. | IN($ARGS.positional[]))) | join(" ")' --args << parameters.databases >> + ) + + docker-compose --project-name typeorm --no-ansi up --detach $SERVICES - install-packages: - cache-key: node<< parameters.node-version >> - - run: npx nyc npm run test-fast + cache-key: node<< parameters.node-version >> + - run: + name: Set up TypeORM Test Runner + command: | + docker run \ + --volume /typeorm \ + --name typeorm-code \ + --workdir /typeorm \ + circleci/node:<< parameters.node-version >> \ + /bin/bash -c "sudo chmod 777 /typeorm && sudo chown circleci /typeorm" + docker cp ./ typeorm-code:/typeorm + - run: + name: Wait for Services to be Available + command: | + COMMANDS=$( + cat ormconfig.json \ + | jq -r ' + map(select(.skip == false) + | select(.host) + | select(.port) + | "nc -z " + .host + " " + (.port|tostring) + " && echo " + .host + " " + (.port|tostring) + " is up") + | join(" && ") + ' + ) + echo "Running '$COMMANDS'" + + docker run \ + --network typeorm_default \ + --tty \ + ubuntu:trusty \ + timeout 60 sh -c "until ($COMMANDS); do echo \"Waiting for Services to be Available ...\"; sleep 5; done" + # Download and cache dependencies + - run: + name: "Run Tests with Coverage" + command: | + docker run \ + --env LD_LIBRARY_PATH='/typeorm/node_modules/oracledb/instantclient_19_8/:$LD_LIBRARY_PATH' \ + --volumes-from typeorm-code \ + --network typeorm_default \ + --tty \ + --workdir /typeorm \ + --name typeorm-testrunner \ + circleci/node:<< parameters.node-version >> \ + npx nyc npm run test-fast + + docker cp typeorm-testrunner:/typeorm/coverage/ ./ + - run: + name: Stop all Relevant Services + command: docker-compose down - store_artifacts: path: coverage - codecov/upload @@ -140,12 +170,12 @@ workflows: - lint - build - test: - name: test (mysql mariadb sqlite better-sqlite3 postgres sqljs mssql mongodb) - Node v<< matrix.node-version >> + name: test (mysql mariadb postgres mssql mongodb sqlite better-sqlite3 sqljs) - Node v<< matrix.node-version >> requires: - lint - build + databases: "mysql mariadb postgres mssql mongodb sqlite better-sqlite3 sqljs" matrix: - databases: "mysql mariadb sqlite better-sqlite3 postgres sqljs mssql mongodb" parameters: node-version: - "10" diff --git a/ormconfig.circleci-common.json b/ormconfig.circleci-common.json index da367ab4f41..ef62fa1ac43 100644 --- a/ormconfig.circleci-common.json +++ b/ormconfig.circleci-common.json @@ -1,78 +1,89 @@ [ { - "skip": false, + "skip": true, "name": "mysql", "type": "mysql", - "host": "localhost", + "host": "typeorm-mysql", "port": 3306, "username": "root", "password": "admin", - "database": "test" + "database": "test", + "logging": false }, { - "skip": false, + "skip": true, "name": "mariadb", "type": "mariadb", - "host": "mariadb", + "host": "typeorm-mariadb", "port": 3306, "username": "root", "password": "admin", - "database": "test" + "database": "test", + "logging": false }, { - "skip": false, + "skip": true, "name": "sqlite", "type": "sqlite", - "database": "temp/sqlitedb.db" + "database": "temp/sqlitedb.db", + "logging": false }, { - "skip": false, + "skip": true, "name": "better-sqlite3", "type": "better-sqlite3", - "database": "temp/better-sqlite3db.db" + "database": "temp/better-sqlite3db.db", + "logging": false }, { - "skip": false, + "skip": true, "name": "postgres", "type": "postgres", - "host": "postgres", + "host": "typeorm-postgres", "port": 5432, "username": "test", "password": "test", - "database": "test" + "database": "test", + "logging": false }, { "skip": false, "name": "sqljs", - "type": "sqljs" + "type": "sqljs", + "logging": false }, + { - "skip": false, + "skip": true, "name": "mssql", "type": "mssql", - "host": "mssql", + "host": "typeorm-mssql", + "port": 1433, "username": "sa", - "password": "Admin123", - "database": "tempdb" + "password": "Admin12345", + "database": "tempdb", + "logging": false }, { "skip": true, "name": "sap", "type": "sap", - "host": "sap", + "host": "typeorm-hana", "port": 39015, "username": "SYSTEM", - "password": "HXEHana1", + "password": "MySuperHanaPwd123!", "database": "HXE", "logging": false }, { - "skip": false, + "skip": true, "disabledIfNotEnabledImplicitly": true, "name": "mongodb", "type": "mongodb", - "host": "mongodb", + "host": "typeorm-mongodb", + "port": 27017, "database": "test", + "logging": false, "useNewUrlParser": true, "useUnifiedTopology": true }, @@ -80,7 +91,7 @@ "skip": true, "name": "cockroachdb", "type": "cockroachdb", - "host": "cockroachdb", + "host": "typeorm-cockroachdb", "port": 26257, "username": "root", "password": "", @@ -90,10 +101,11 @@ "skip": true, "name": "oracle", "type": "oracle", - "host": "oracle", - "username": "typeorm", - "password": "Passw0rd", + "host": "typeorm-oracle", "port": 1521, - "sid": "orclpdb1.localdomain" + "sid": "xe", + "username": "system", + "password": "oracle", + "logging": false } ] From 10b05a9210e085e5e3634e740ab7975925bf962c Mon Sep 17 00:00:00 2001 From: Umed Khudoiberdiev Date: Wed, 2 Sep 2020 12:15:27 +0500 Subject: [PATCH 041/212] removing gitads --- README.md | 5 ----- 1 file changed, 5 deletions(-) diff --git a/README.md b/README.md index 2b59bb5733d..72f9b72e452 100644 --- a/README.md +++ b/README.md @@ -39,11 +39,6 @@ maintainable applications the most productive way. TypeORM is highly influenced by other ORMs, such as [Hibernate](http://hibernate.org/orm/), [Doctrine](http://www.doctrine-project.org/) and [Entity Framework](https://www.asp.net/entity-framework). -## Sponsors - -TypeORM is being sponsored by the following partner: - GitAds - ## Features * supports both [DataMapper](./docs/active-record-data-mapper.md#what-is-the-data-mapper-pattern) and [ActiveRecord](./docs/active-record-data-mapper.md#what-is-the-active-record-pattern) (your choice) From 85c07fda2fe79a3556b9c06e014bbaea5f74cf3b Mon Sep 17 00:00:00 2001 From: xgqfrms Date: Wed, 2 Sep 2020 21:49:00 +0800 Subject: [PATCH 042/212] docs: update zh_CN link path (#6652) * update zh_CN link path * Update README-zh_CN.md --- README-zh_CN.md | 92 ++++++++++++++++++++++++------------------------- 1 file changed, 46 insertions(+), 46 deletions(-) diff --git a/README-zh_CN.md b/README-zh_CN.md index e9e91bfc56f..4b7dc796d99 100644 --- a/README-zh_CN.md +++ b/README-zh_CN.md @@ -22,13 +22,13 @@ TypeORM 是一个 [ORM](https://en.wikipedia.org/wiki/Object-relational_mapping) 框架,它可以运行在 NodeJS、Browser、Cordova、PhoneGap、Ionic、React Native、Expo 和 Electron 平台上,可以与 TypeScript 和 JavaScript (ES5,ES6,ES7,ES8)一起使用。 它的目标是始终支持最新的 JavaScript 特性并提供额外的特性以帮助你开发任何使用数据库的(不管是只有几张表的小型应用还是拥有多数据库的大型企业应用)应用程序。 -不同于现有的所有其他 JavaScript ORM 框架,TypeORM 支持 [Active Record](./docs/active-record-data-mapper.md#what-is-the-active-record-pattern) 和 [Data Mapper](./docs/active-record-data-mapper.md#what-is-the-data-mapper-pattern) 模式,这意味着你可以以最高效的方式编写高质量的、松耦合的、可扩展的、可维护的应用程序。 +不同于现有的所有其他 JavaScript ORM 框架,TypeORM 支持 [Data Mapper](./docs/zh_CN/active-record-data-mapper.md#什么是data-mapper模式) 和 [Active Record](./docs/zh_CN/active-record-data-mapper.md#什么是active-record模式) 模式,这意味着你可以以最高效的方式编写高质量的、松耦合的、可扩展的、可维护的应用程序。 TypeORM 参考了很多其他优秀 ORM 的实现, 比如 [Hibernate](http://hibernate.org/orm/), [Doctrine](http://www.doctrine-project.org/) 和 [Entity Framework](https://www.asp.net/entity-framework)。 TypeORM 的一些特性: -- 同时支持 [DataMapper](./docs/active-record-data-mapper.md#what-is-the-data-mapper-pattern) 和 [ActiveRecord](./docs/active-record-data-mapper.md#what-is-the-active-record-pattern) (随你选择) +- 同时支持 [DataMapper](./docs/zh_CN/active-record-data-mapper.md#什么是data-mapper模式) 和 [ActiveRecord](./docs/zh_CN/active-record-data-mapper.md#什么是active-record模式) (随你选择) - 实体和列 - 数据库特性列类型 - 实体管理 @@ -69,7 +69,7 @@ TypeORM 的一些特性: 通过使用 `TypeORM` 你的 `models` 看起来如下: -```typescript +```ts import { Entity, PrimaryGeneratedColumn, Column } from "typeorm"; @Entity() @@ -90,7 +90,7 @@ export class User { 逻辑操作如下: -```typescript +```ts const user = new User(); user.firstName = "Timber"; user.lastName = "Saw"; @@ -106,7 +106,7 @@ await repository.remove(timber); 或者,如果你更喜欢使用 `ActiveRecord` 模式,也可以这样用: -```typescript +```ts import { Entity, PrimaryGeneratedColumn, Column, BaseEntity } from "typeorm"; @Entity() @@ -127,7 +127,7 @@ export class User extends BaseEntity { 逻辑操作如下所示: -```typescript +```ts const user = new User(); user.firstName = "Timber"; user.lastName = "Saw"; @@ -241,7 +241,7 @@ typeorm init --name MyProject --database mysql 此命令将在 `MyProject` 目录中生成一个包含以下文件的新项目: -``` +```sh MyProject ├── src // TypeScript 代码 │ ├── entity // 存储实体(数据库模型)的位置 @@ -259,9 +259,9 @@ MyProject 接下来安装项目依赖项: -``` -cd MyProject -npm install +```sh +$ cd MyProject +$ npm install ``` 在安装过程中,编辑 `ormconfig.json` 文件并在其中编辑自己的数据库连接配置选项: @@ -286,8 +286,8 @@ npm install 完成配置并安装所有 node modules 后,即可运行应用程序: -``` -npm start +```sh +$ npm start ``` 至此你的应用程序应该成功运行并将新用户插入数据库。你可以继续使用此项目并集成所需的其他模块并创建更多实体。 @@ -305,7 +305,7 @@ npm start 举个例子, 你有一个 `Photo` 模型: -```typescript +```ts export class Photo { id: number; name: string; @@ -323,7 +323,7 @@ export class Photo { 让我们将 `Photo` 模型作为一个实体 -```typescript +```ts import { Entity } from "typeorm"; @Entity() @@ -344,7 +344,7 @@ export class Photo { 要添加数据库列,你只需要将要生成的实体属性加上 `@Column` 装饰器。 -```typescript +```ts import { Entity, Column } from "typeorm"; @Entity() @@ -378,7 +378,7 @@ export class Photo { 每个**必须**至少有一个主键列。这是必须的,你无法避免。要使列成为主键,你需要使用 `@PrimaryColumn` 装饰器。 -```typescript +```ts import { Entity, Column, PrimaryColumn } from "typeorm"; @Entity() @@ -407,7 +407,7 @@ export class Photo { 假设你希望 id 列自动生成(这称为 auto-increment/sequence/serial/generated identity column)。为此你需要将`@PrimaryColumn` 装饰器更改为 `@PrimaryGeneratedColumn` 装饰器: -```typescript +```ts import { Entity, Column, PrimaryGeneratedColumn } from "typeorm"; @Entity() @@ -437,7 +437,7 @@ export class Photo { 接下来,让我们修改数据类型。默认情况下,字符串被映射到一个 varchar(255) 类型(取决于数据库类型)。 数字被映射到一个类似 integer 类型(取决于数据库类型)。但是我们不希望所有的列都是有限的 varchars 或 integer,让我们修改下代码以设置想要的数据类型: -```typescript +```ts import { Entity, Column, PrimaryGeneratedColumn } from "typeorm"; @Entity() @@ -464,13 +464,13 @@ export class Photo { } ``` -列类型是特定于数据库的。你可以设置数据库支持的任何列类型。有关支持的列类型的更多信息,请参见[此处](./docs/entities.md#column-types)。 +列类型是特定于数据库的。你可以设置数据库支持的任何列类型。有关支持的列类型的更多信息,请参见[此处](./docs/zh_CN/entities.md#列类型)。 ### 创建数据库的连接 当实体被创建后,让我们创建一个`index.ts`(或`app.ts`,无论你怎么命名)文件,并配置数据库连接:: -```typescript +```ts import "reflect-metadata"; import { createConnection } from "typeorm"; import { Photo } from "./entity/Photo"; @@ -502,7 +502,7 @@ createConnection({ 之后当我们创建更多实体时,都需要一一将它们添加到配置中的实体中,但是这不是很方便,所以我们可以设置加载整个目录,从中连接所有实体并使用: -```typescript +```ts import { createConnection } from "typeorm"; createConnection({ @@ -547,7 +547,7 @@ createConnection({ 现在创建一个新的 photo 存到数据库: -```typescript +```ts import { createConnection } from "typeorm"; import { Photo } from "./entity/Photo"; @@ -573,7 +573,7 @@ createConnection(/*...*/) 我们可以使用ES8(ES2017)的新特性,并使用 async/await 语法代替: -```typescript +```ts import { createConnection } from "typeorm"; import { Photo } from "./entity/Photo"; @@ -598,7 +598,7 @@ createConnection(/*...*/) 例如,加载已经保存的实体: -```typescript +```ts import { createConnection } from "typeorm"; import { Photo } from "./entity/Photo"; @@ -613,13 +613,13 @@ createConnection(/*...*/) `savedPhotos` 是一个 Photo 对象数组,其中包含从数据库加载的数据。 -了解更多有关 [EntityManager](./docs/working-with-entity-manager.md) 的信息。 +了解更多有关 [EntityManager](./docs/zh_CN/working-with-entity-manager.md) 的信息。 ### 使用 Repositories 现在让我们重构之前的代码,并使用 `Repository` 替代 `EntityManager`。每个实体都有自己的repository,可以处理其实体的所有操作。当你经常处理实体时,Repositories 比 EntityManagers 更方便使用: -```typescript +```ts import { createConnection } from "typeorm"; import { Photo } from "./entity/Photo"; @@ -643,13 +643,13 @@ createConnection(/*...*/) .catch(error => console.log(error)); ``` -了解更多有关 [Repository](./docs/working-with-repository.md) 的信息。 +了解更多有关 [Repository](./docs/zh_CN/working-with-repository.md) 的信息。 ### 从数据库加载 让我们使用 Repository 尝试更多的加载操作: -```typescript +```ts import { createConnection } from "typeorm"; import { Photo } from "./entity/Photo"; @@ -682,7 +682,7 @@ createConnection(/*...*/) 让我们从数据库加载出 photo,更新并保存到数据库: -```typescript +```ts import { createConnection } from "typeorm"; import { Photo } from "./entity/Photo"; @@ -702,7 +702,7 @@ createConnection(/*...*/) 让我们从数据库中删除 Photo: -```typescript +```ts import { createConnection } from "typeorm"; import { Photo } from "./entity/Photo"; @@ -721,7 +721,7 @@ createConnection(/*...*/) 要与另一个类创建一对一的关系。先在 `PhotoMetadata.ts` 中创建一个新类。此 PhotoMetadata 类应包含 photo 的其他元信息: -```typescript +```ts import { Entity, Column, PrimaryGeneratedColumn, OneToOne, JoinColumn } from "typeorm"; import { Photo } from "./Photo"; @@ -777,7 +777,7 @@ export class PhotoMetadata { 现在让我们来创建一个 photo,它的元信息将它们互相连接起来。 -```typescript +```ts import { createConnection } from "typeorm"; import { Photo } from "./entity/Photo"; import { PhotoMetadata } from "./entity/PhotoMetadata"; @@ -820,7 +820,7 @@ createConnection(/*...*/) 关系可以是单向的或双向的。目前 PhotoMetadata 和 Photo 之间的关系是单向的。关系的所有者是 PhotoMetadata,而 Photo 对 PhotoMetadata 一无所知。这使得从 Photo 中访问 PhotoMetadata 变得很复杂。要解决这个问题,我们应该在 PhotoMetadata 和 Photo 之间建立双向关系。让我们来修改一下实体: -```typescript +```ts import { Entity, Column, PrimaryGeneratedColumn, OneToOne, JoinColumn } from "typeorm"; import { Photo } from "./Photo"; @@ -855,7 +855,7 @@ export class Photo { 在一个查询中加载 photo 及 photo metadata 有两种方法。使用 `find *` 或使用 `QueryBuilder`。我们先使用 `find *` 方法。 `find *` 方法允许你使用 `FindOneOptions` / `FindManyOptions` 接口指定对象。 -```typescript +```ts import { createConnection } from "typeorm"; import { Photo } from "./entity/Photo"; import { PhotoMetadata } from "./entity/PhotoMetadata"; @@ -869,11 +869,11 @@ createConnection(/*...*/) .catch(error => console.log(error)); ``` -photos 包含来自数据库的 photos 数组,每个 photo 包含其 photo metadata。详细了解本文档中的[Find 选项](./docs/find-options.md)。 +photos 包含来自数据库的 photos 数组,每个 photo 包含其 photo metadata。详细了解本文档中的[Find 选项](./docs/zh_CN/find-options.md)。 使用find选项很简单,但是如果你需要更复杂的查询,则应该使用 `QueryBuilder`。 `QueryBuilder` 使用更优雅的方式执行更复杂的查询: -```typescript +```ts import { createConnection } from "typeorm"; import { Photo } from "./entity/Photo"; import { PhotoMetadata } from "./entity/PhotoMetadata"; @@ -896,7 +896,7 @@ createConnection(/*...*/) 我们可以在关系中设置 `cascade` 选项,这时就可以在保存其他对象的同时保存相关对象。让我们更改一下的 photo 的 `@OneToOne` 装饰器: -```typescript +```ts export class Photo { /// ... 其他列 @@ -909,7 +909,7 @@ export class Photo { 使用 `cascade` 允许就不需要边存 photo 边存元数据对象。我们可以简单地保存一个 photo 对象,由于使用了 cascade,metadata 也将自动保存。 -```typescript +```ts createConnection(options) .then(async connection => { // 创建 photo 对象 @@ -966,7 +966,7 @@ export class Author { 现在让我们将关系的所有者方添加到 Photo 实体中: -```typescript +```ts import { Entity, Column, PrimaryGeneratedColumn, ManyToOne } from "typeorm"; import { PhotoMetadata } from "./PhotoMetadata"; import { Author } from "./Author"; @@ -1011,7 +1011,7 @@ export class Photo { 假设一个 photo 可以放在多个 albums 中,每个 albums 可以包含多个 photo。让我们创建一个`Album`类: -```typescript +```ts import { Entity, PrimaryGeneratedColumn, Column, ManyToMany, JoinTable } from "typeorm"; @Entity() @@ -1032,7 +1032,7 @@ export class Album { 现在添加反向关系到`Photo`类: -```typescript +```ts export class Photo { /// ... 其他列 @@ -1054,7 +1054,7 @@ export class Photo { 记得在 ORM 中使用 ConnectionOptions 注册`Album`类: -```typescript +```ts const options: ConnectionOptions = { // ... 其他选项 entities: [Photo, PhotoMetadata, Author, Album] @@ -1063,7 +1063,7 @@ const options: ConnectionOptions = { 现在让我们将 albums 和 photos 插入我们的数据库: -```typescript +```ts let connection = await createConnection(options); // 创建一些 albums @@ -1090,7 +1090,7 @@ const loadedPhoto = await connection.getRepository(Photo).findOne(1, { relations `loadedPhoto` 如下所示: -```typescript +```ts { id: 1, name: "Me and Bears", @@ -1110,7 +1110,7 @@ const loadedPhoto = await connection.getRepository(Photo).findOne(1, { relations 你可以使用 QueryBuilder 构建几乎任何复杂性的 SQL 查询。例如,可以这样做: -```typescript +```ts let photos = await connection .getRepository(Photo) .createQueryBuilder("photo") // 第一个参数是别名。即photos。 该参数必须指定。 @@ -1128,7 +1128,7 @@ let photos = await connection 此查询选择所有 published 的 name 等于"My"或"Mishka"的 photos。它将从结果中的第 5 个(分页偏移)开始,并且仅选择 10 个结果(分页限制)。得到的结果将按 ID 降序排序。photo 的 albums 将被 left-joined,其元数据将被 inner joined。 由于 QueryBuilder 的自由度更高,因此在项目中可能会大量的使用它。 -更多关于 QueryBuilder 的信息,[可查看](./docs/select-query-builder.md)。 +更多关于 QueryBuilder 的信息,[可查看](./docs/zh_CN/select-query-builder.md)。 ## 示例 From c99ba4052d71637c0b0a1982541acdd4b5e74a7f Mon Sep 17 00:00:00 2001 From: Arty <26905074+artysidorenko@users.noreply.github.com> Date: Wed, 2 Sep 2020 15:41:55 +0100 Subject: [PATCH 043/212] feat: FileLogger accepts custom file path (#6642) This allows users to override default log filepath and save typeorm logs in a custom location Closes: #4410 --- src/logger/FileLogger.ts | 15 ++-- src/logger/LoggerOptions.ts | 10 +++ test/github-issues/4410/entity/Username.ts | 12 ++++ test/github-issues/4410/issue-4410.ts | 81 ++++++++++++++++++++++ 4 files changed, 114 insertions(+), 4 deletions(-) create mode 100644 test/github-issues/4410/entity/Username.ts create mode 100644 test/github-issues/4410/issue-4410.ts diff --git a/src/logger/FileLogger.ts b/src/logger/FileLogger.ts index 3bdccda7bdd..f50d65283d7 100644 --- a/src/logger/FileLogger.ts +++ b/src/logger/FileLogger.ts @@ -1,4 +1,4 @@ -import {LoggerOptions} from "./LoggerOptions"; +import {LoggerOptions, FileLoggerOptions} from "./LoggerOptions"; import {QueryRunner} from "../query-runner/QueryRunner"; import {Logger} from "./Logger"; import {PlatformTools} from "../platform/PlatformTools"; @@ -13,7 +13,10 @@ export class FileLogger implements Logger { // Constructor // ------------------------------------------------------------------------- - constructor(private options?: LoggerOptions) { + constructor( + private options?: LoggerOptions, + private fileLoggerOptions?: FileLoggerOptions, + ) { } // ------------------------------------------------------------------------- @@ -97,9 +100,13 @@ export class FileLogger implements Logger { */ protected write(strings: string|string[]) { strings = Array.isArray(strings) ? strings : [strings]; - const basePath = PlatformTools.load("app-root-path").path; + const basePath = PlatformTools.load("app-root-path").path + "/"; + let logPath = "ormlogs.log"; + if (this.fileLoggerOptions && this.fileLoggerOptions.logPath) { + logPath = PlatformTools.pathNormalize(this.fileLoggerOptions.logPath); + } strings = (strings as string[]).map(str => "[" + new Date().toISOString() + "]" + str); - PlatformTools.appendFileSync(basePath + "/ormlogs.log", strings.join("\r\n") + "\r\n"); // todo: use async or implement promises? + PlatformTools.appendFileSync(basePath + logPath, strings.join("\r\n") + "\r\n"); // todo: use async or implement promises? } /** diff --git a/src/logger/LoggerOptions.ts b/src/logger/LoggerOptions.ts index 67049d5a4f5..adfff93488b 100644 --- a/src/logger/LoggerOptions.ts +++ b/src/logger/LoggerOptions.ts @@ -2,3 +2,13 @@ * Logging options. */ export type LoggerOptions = boolean|"all"|("query"|"schema"|"error"|"warn"|"info"|"log"|"migration")[]; + +/** + * File logging option. + */ +export type FileLoggerOptions = { + /** + * Specify custom path for log file, relative to application root + */ + logPath: string; +}; diff --git a/test/github-issues/4410/entity/Username.ts b/test/github-issues/4410/entity/Username.ts new file mode 100644 index 00000000000..ad0ee27175c --- /dev/null +++ b/test/github-issues/4410/entity/Username.ts @@ -0,0 +1,12 @@ +import { Column } from "../../../../src/decorator/columns/Column"; +import { PrimaryColumn } from "../../../../src/decorator/columns/PrimaryColumn"; +import { Entity } from "../../../../src/decorator/entity/Entity"; + +@Entity() +export class Username { + @PrimaryColumn() + username: string; + + @Column() + email: string; +} diff --git a/test/github-issues/4410/issue-4410.ts b/test/github-issues/4410/issue-4410.ts new file mode 100644 index 00000000000..52dfceab534 --- /dev/null +++ b/test/github-issues/4410/issue-4410.ts @@ -0,0 +1,81 @@ +import sinon from "sinon"; +import { Connection, FileLogger } from "../../../src"; +import { createTestingConnections, reloadTestingDatabases, closeTestingConnections, TestingOptions } from "../../utils/test-utils"; +import { Username } from "./entity/Username"; +import { PlatformTools } from "../../../src/platform/PlatformTools"; + +describe("github issues > #4410 allow custom filepath for FileLogger", () => { + let connections: Connection[]; + let stub: sinon.SinonStub; + + const testingOptions: TestingOptions = { + entities: [Username], + schemaCreate: true, + dropSchema: true, + }; + const testQuery = "SELECT COUNT(*) from username;"; + + before(() => stub = sinon.stub(PlatformTools, "appendFileSync")); + beforeEach(() => reloadTestingDatabases(connections)); + afterEach(async () => { + stub.resetHistory(); await closeTestingConnections(connections); + }); + + describe("when no option is passed", () => { + before(async () => { + connections = await createTestingConnections({ + ...testingOptions, + createLogger: () => new FileLogger("all"), + }); + }); + it("writes to the base path", async () => + Promise.all(connections.map(async (connection) => { + await connection.query(testQuery); + sinon.assert.calledWith( + stub, + PlatformTools.load("app-root-path").path + "/ormlogs.log", + sinon.match(testQuery) + ); + }))); + }); + + describe("when logPath option is passed as a file", () => { + before(async () => { + connections = await createTestingConnections({ + ...testingOptions, + createLogger: () => new FileLogger("all", { + logPath: "test.log" + }), + }); + }); + it("writes to the given filename", async () => + Promise.all(connections.map(async (connection) => { + await connection.query(testQuery); + sinon.assert.calledWith( + stub, + PlatformTools.load("app-root-path").path + "/test.log", + sinon.match(testQuery) + ); + }))); + }); + + describe("when logPath option is passed as a nested path", () => { + before(async () => { + connections = await createTestingConnections({ + ...testingOptions, + createLogger: () => new FileLogger("all", { + logPath: "./test/test.log" + }), + }); + }); + it("writes to the given path", () => + Promise.all(connections.map(async (connection) => { + await connection.query(testQuery); + sinon.assert.calledWith( + stub, + PlatformTools.load("app-root-path").path + "/test/test.log", + sinon.match(testQuery) + ); + }))); + }); +}); From 4f7481b55af021f5ffe12ff3d5d4d0ea6cb13f1c Mon Sep 17 00:00:00 2001 From: James Ward Date: Wed, 2 Sep 2020 10:47:36 -0400 Subject: [PATCH 044/212] chore: instead of require, import chalk from chalk (#6637) --- src/commands/CacheClearCommand.ts | 2 +- src/commands/EntityCreateCommand.ts | 2 +- src/commands/InitCommand.ts | 2 +- src/commands/MigrationCreateCommand.ts | 2 +- src/commands/MigrationGenerateCommand.ts | 2 +- src/commands/MigrationRevertCommand.ts | 2 +- src/commands/MigrationRunCommand.ts | 2 +- src/commands/MigrationShowCommand.ts | 2 +- src/commands/QueryCommand.ts | 2 +- src/commands/SchemaDropCommand.ts | 2 +- src/commands/SchemaLogCommand.ts | 5 ++--- src/commands/SchemaSyncCommand.ts | 2 +- src/commands/SubscriberCreateCommand.ts | 2 +- src/commands/VersionCommand.ts | 2 +- src/platform/PlatformTools.ts | 3 +-- 15 files changed, 16 insertions(+), 18 deletions(-) diff --git a/src/commands/CacheClearCommand.ts b/src/commands/CacheClearCommand.ts index 7c635611c81..79dba0e87a1 100644 --- a/src/commands/CacheClearCommand.ts +++ b/src/commands/CacheClearCommand.ts @@ -2,7 +2,7 @@ import {createConnection} from "../index"; import {ConnectionOptionsReader} from "../connection/ConnectionOptionsReader"; import {Connection} from "../connection/Connection"; import * as yargs from "yargs"; -const chalk = require("chalk"); +import chalk from "chalk"; /** * Clear cache command. diff --git a/src/commands/EntityCreateCommand.ts b/src/commands/EntityCreateCommand.ts index 024aecb2ddc..314fa203d1d 100644 --- a/src/commands/EntityCreateCommand.ts +++ b/src/commands/EntityCreateCommand.ts @@ -1,7 +1,7 @@ import {ConnectionOptionsReader} from "../connection/ConnectionOptionsReader"; import {CommandUtils} from "./CommandUtils"; import * as yargs from "yargs"; -const chalk = require("chalk"); +import chalk from "chalk"; /** * Generates a new entity. diff --git a/src/commands/InitCommand.ts b/src/commands/InitCommand.ts index c3638ffe662..3dbe7f2c51f 100644 --- a/src/commands/InitCommand.ts +++ b/src/commands/InitCommand.ts @@ -2,7 +2,7 @@ import {CommandUtils} from "./CommandUtils"; import {ObjectLiteral} from "../common/ObjectLiteral"; import * as path from "path"; import * as yargs from "yargs"; -const chalk = require("chalk"); +import chalk from "chalk"; /** * Generates a new project with TypeORM. diff --git a/src/commands/MigrationCreateCommand.ts b/src/commands/MigrationCreateCommand.ts index 8e56855c821..9d39b06174c 100644 --- a/src/commands/MigrationCreateCommand.ts +++ b/src/commands/MigrationCreateCommand.ts @@ -2,7 +2,7 @@ import {ConnectionOptionsReader} from "../connection/ConnectionOptionsReader"; import {CommandUtils} from "./CommandUtils"; import {camelCase} from "../util/StringUtils"; import * as yargs from "yargs"; -const chalk = require("chalk"); +import chalk from "chalk"; /** * Creates a new migration file. diff --git a/src/commands/MigrationGenerateCommand.ts b/src/commands/MigrationGenerateCommand.ts index faf6edd382c..f036fd67fc8 100644 --- a/src/commands/MigrationGenerateCommand.ts +++ b/src/commands/MigrationGenerateCommand.ts @@ -6,7 +6,7 @@ import {MysqlDriver} from "../driver/mysql/MysqlDriver"; import {camelCase} from "../util/StringUtils"; import * as yargs from "yargs"; import {AuroraDataApiDriver} from "../driver/aurora-data-api/AuroraDataApiDriver"; -const chalk = require("chalk"); +import chalk from "chalk"; /** * Generates a new migration file with sql needs to be executed to update schema. diff --git a/src/commands/MigrationRevertCommand.ts b/src/commands/MigrationRevertCommand.ts index 5a7605ac188..1d70326c939 100644 --- a/src/commands/MigrationRevertCommand.ts +++ b/src/commands/MigrationRevertCommand.ts @@ -2,7 +2,7 @@ import {createConnection} from "../index"; import {ConnectionOptionsReader} from "../connection/ConnectionOptionsReader"; import {Connection} from "../connection/Connection"; import * as yargs from "yargs"; -const chalk = require("chalk"); +import chalk from "chalk"; /** * Reverts last migration command. diff --git a/src/commands/MigrationRunCommand.ts b/src/commands/MigrationRunCommand.ts index e27915fe179..f953d5b551d 100644 --- a/src/commands/MigrationRunCommand.ts +++ b/src/commands/MigrationRunCommand.ts @@ -3,7 +3,7 @@ import {ConnectionOptionsReader} from "../connection/ConnectionOptionsReader"; import {Connection} from "../connection/Connection"; import * as process from "process"; import * as yargs from "yargs"; -const chalk = require("chalk"); +import chalk from "chalk"; /** * Runs migration command. diff --git a/src/commands/MigrationShowCommand.ts b/src/commands/MigrationShowCommand.ts index d72b62c9ae3..8995faa6b0f 100644 --- a/src/commands/MigrationShowCommand.ts +++ b/src/commands/MigrationShowCommand.ts @@ -3,7 +3,7 @@ import {ConnectionOptionsReader} from "../connection/ConnectionOptionsReader"; import {Connection} from "../connection/Connection"; import * as process from "process"; import * as yargs from "yargs"; -const chalk = require("chalk"); +import chalk from "chalk"; /** * Runs migration command. diff --git a/src/commands/QueryCommand.ts b/src/commands/QueryCommand.ts index 49bf0078e31..c7a62129f2f 100644 --- a/src/commands/QueryCommand.ts +++ b/src/commands/QueryCommand.ts @@ -4,7 +4,7 @@ import {ConnectionOptionsReader} from "../connection/ConnectionOptionsReader"; import {Connection} from "../connection/Connection"; import {PlatformTools} from "../platform/PlatformTools"; import * as yargs from "yargs"; -const chalk = require("chalk"); +import chalk from "chalk"; /** * Executes an sql query on the given connection. diff --git a/src/commands/SchemaDropCommand.ts b/src/commands/SchemaDropCommand.ts index 2ce3caafd06..fcabb029c41 100644 --- a/src/commands/SchemaDropCommand.ts +++ b/src/commands/SchemaDropCommand.ts @@ -2,7 +2,7 @@ import {createConnection} from "../index"; import {Connection} from "../connection/Connection"; import {ConnectionOptionsReader} from "../connection/ConnectionOptionsReader"; import * as yargs from "yargs"; -const chalk = require("chalk"); +import chalk from "chalk"; /** * Drops all tables of the database from the given connection. diff --git a/src/commands/SchemaLogCommand.ts b/src/commands/SchemaLogCommand.ts index 86d99a0aac0..73c1320934f 100644 --- a/src/commands/SchemaLogCommand.ts +++ b/src/commands/SchemaLogCommand.ts @@ -3,8 +3,7 @@ import {Connection} from "../connection/Connection"; import {ConnectionOptionsReader} from "../connection/ConnectionOptionsReader"; import {highlight} from "cli-highlight"; import * as yargs from "yargs"; - -const chalk = require("chalk"); +import chalk from "chalk"; /** * Shows sql to be executed by schema:sync command. @@ -53,7 +52,7 @@ export class SchemaLogCommand implements yargs.CommandModule { } else { const lengthSeparators = String(sqlInMemory.upQueries.length).split("").map(char => "-").join(""); console.log(chalk.yellow("---------------------------------------------------------------" + lengthSeparators)); - console.log(chalk.yellow.bold(`-- Schema syncronization will execute following sql queries (${chalk.white(sqlInMemory.upQueries.length)}):`)); + console.log(chalk.yellow.bold(`-- Schema syncronization will execute following sql queries (${chalk.white(sqlInMemory.upQueries.length.toString())}):`)); console.log(chalk.yellow("---------------------------------------------------------------" + lengthSeparators)); sqlInMemory.upQueries.forEach(upQuery => { diff --git a/src/commands/SchemaSyncCommand.ts b/src/commands/SchemaSyncCommand.ts index 5ac12aab7df..3a1653344b4 100644 --- a/src/commands/SchemaSyncCommand.ts +++ b/src/commands/SchemaSyncCommand.ts @@ -2,7 +2,7 @@ import {createConnection} from "../index"; import {Connection} from "../connection/Connection"; import {ConnectionOptionsReader} from "../connection/ConnectionOptionsReader"; import * as yargs from "yargs"; -const chalk = require("chalk"); +import chalk from "chalk"; /** * Synchronizes database schema with entities. diff --git a/src/commands/SubscriberCreateCommand.ts b/src/commands/SubscriberCreateCommand.ts index b91f40d0141..65d908843d5 100644 --- a/src/commands/SubscriberCreateCommand.ts +++ b/src/commands/SubscriberCreateCommand.ts @@ -1,7 +1,7 @@ import {ConnectionOptionsReader} from "../connection/ConnectionOptionsReader"; import {CommandUtils} from "./CommandUtils"; import * as yargs from "yargs"; -const chalk = require("chalk"); +import chalk from "chalk"; /** * Generates a new subscriber. diff --git a/src/commands/VersionCommand.ts b/src/commands/VersionCommand.ts index 3f2daaebaa9..09361ea831e 100644 --- a/src/commands/VersionCommand.ts +++ b/src/commands/VersionCommand.ts @@ -1,5 +1,5 @@ import * as yargs from "yargs"; -const exec = require("child_process").exec; +import {exec} from "child_process"; /** * Shows typeorm version. diff --git a/src/platform/PlatformTools.ts b/src/platform/PlatformTools.ts index 5af551057cf..98e9d066895 100644 --- a/src/platform/PlatformTools.ts +++ b/src/platform/PlatformTools.ts @@ -1,12 +1,11 @@ import * as path from "path"; import * as fs from "fs"; +import chalk from "chalk"; import {highlight, Theme} from "cli-highlight"; export {ReadStream} from "fs"; export {EventEmitter} from "events"; export {Readable, Writable} from "stream"; -const chalk = require("chalk"); - /** * Platform-specific tools. */ From cf3ad6211af988822e9f6328fb6933ce4b4b887c Mon Sep 17 00:00:00 2001 From: James Ward Date: Wed, 2 Sep 2020 11:46:14 -0400 Subject: [PATCH 045/212] fix: pass `ids_` to alias builder to prevent length overflow (#6624) --- src/query-builder/SelectQueryBuilder.ts | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/query-builder/SelectQueryBuilder.ts b/src/query-builder/SelectQueryBuilder.ts index c1de0e2f25a..9a87ac832a6 100644 --- a/src/query-builder/SelectQueryBuilder.ts +++ b/src/query-builder/SelectQueryBuilder.ts @@ -1861,7 +1861,14 @@ export class SelectQueryBuilder extends QueryBuilder implements const columnAlias = this.escape(DriverUtils.buildColumnAlias(this.connection.driver, mainAliasName, primaryColumn.databaseName)); if (!orderBys[columnAlias]) // make sure we aren't overriding user-defined order in inverse direction orderBys[columnAlias] = "ASC"; - return `${distinctAlias}.${columnAlias} as "ids_${DriverUtils.buildColumnAlias(this.connection.driver, mainAliasName, primaryColumn.databaseName)}"`; + + const alias = DriverUtils.buildColumnAlias( + this.connection.driver, + "ids_" + mainAliasName, + primaryColumn.databaseName + ); + + return `${distinctAlias}.${columnAlias} as "${alias}"`; }); rawResults = await new SelectQueryBuilder(this.connection, queryRunner) @@ -1888,7 +1895,13 @@ export class SelectQueryBuilder extends QueryBuilder implements }).join(" AND "); }).join(" OR "); } else { - const ids = rawResults.map(result => result["ids_" + DriverUtils.buildColumnAlias(this.connection.driver, mainAliasName, metadata.primaryColumns[0].databaseName)]); + const alias = DriverUtils.buildColumnAlias( + this.connection.driver, + "ids_" + mainAliasName, + metadata.primaryColumns[0].databaseName + ); + + const ids = rawResults.map(result => result[alias]); const areAllNumbers = ids.every((id: any) => typeof id === "number"); if (areAllNumbers) { // fixes #190. if all numbers then its safe to perform query without parameter From 2b5f139cea281aa9752ccc0898ddf7664a87ce9a Mon Sep 17 00:00:00 2001 From: Tomas Reimers Date: Thu, 3 Sep 2020 03:50:37 -0400 Subject: [PATCH 046/212] feat: support absolute paths in migrationsDir for the CLI (#6660) Right now the CLI will ALWAYS prepend the CWD to `options.cli.migrationsDir`. This prevents us from using absolute paths there. How would we feel about changing that to support absolute paths (by only prepending CLI if the path DOES NOT start with "/")? If we're open to it, I'm happy to make the change for the other CLI commands as well. --- src/commands/MigrationCreateCommand.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/MigrationCreateCommand.ts b/src/commands/MigrationCreateCommand.ts index 9d39b06174c..383e30c680c 100644 --- a/src/commands/MigrationCreateCommand.ts +++ b/src/commands/MigrationCreateCommand.ts @@ -59,7 +59,7 @@ export class MigrationCreateCommand implements yargs.CommandModule { } catch (err) { } } - const path = process.cwd() + "/" + (directory ? (directory + "/") : "") + filename; + const path = (directory.startsWith("/") ? "" : process.cwd() + "/") + (directory ? (directory + "/") : "") + filename; await CommandUtils.createFile(path, fileContent); console.log(`Migration ${chalk.blue(path)} has been generated successfully.`); From 490ad0d424e674de5be38b0c3bc83b9a14a383a5 Mon Sep 17 00:00:00 2001 From: James Ward Date: Thu, 3 Sep 2020 04:07:49 -0400 Subject: [PATCH 047/212] refactor: only use PlatformTools.load for optional dependencies (#6630) --- package-lock.json | 53 +++++++++++++--- package.json | 9 ++- src/cache/RedisQueryResultCache.ts | 7 ++- src/commands/CommandUtils.ts | 2 +- src/connection/ConnectionOptionsReader.ts | 12 ++-- .../ConnectionOptionsXmlReader.ts | 4 +- .../ConnectionOptionsYmlReader.ts | 14 ++++- .../better-sqlite3/BetterSqlite3Driver.ts | 10 +-- src/driver/react-native/ReactNativeDriver.ts | 3 +- src/driver/sqlite/SqliteDriver.ts | 8 +-- src/logger/DebugLogger.ts | 31 +++++----- src/logger/FileLogger.ts | 3 +- src/platform/PlatformTools.ts | 61 ++++++++----------- src/util/DirectoryExportedClassesLoader.ts | 9 +-- test/github-issues/4410/issue-4410.ts | 11 ++-- 15 files changed, 142 insertions(+), 95 deletions(-) diff --git a/package-lock.json b/package-lock.json index bc7c689f524..e100be4b4fb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -190,6 +190,12 @@ "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==", "dev": true }, + "@types/app-root-path": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@types/app-root-path/-/app-root-path-1.2.4.tgz", + "integrity": "sha1-p4twMoKzKsVN52j1US7MNWmRncc=", + "dev": true + }, "@types/chai": { "version": "4.1.7", "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.1.7.tgz", @@ -227,6 +233,15 @@ "integrity": "sha512-jkf6UiWUjcOqdQbatbvOm54/YbCdjt3JjiAzT/9KS2XtMmOkYHdKsI5u8fulhbuTUuiqNBfa6J5GSDiwjK+zLA==", "dev": true }, + "@types/dotenv": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@types/dotenv/-/dotenv-8.2.0.tgz", + "integrity": "sha512-ylSC9GhfRH7m1EUXBXofhgx4lUWmFeQDINW5oLuS+gxWdfUeW4zJdeVTYVkexEW+e2VUvlZR2kGnGGipAWR7kw==", + "dev": true, + "requires": { + "dotenv": "*" + } + }, "@types/eslint-visitor-keys": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", @@ -271,6 +286,12 @@ "@types/vinyl-fs": "*" } }, + "@types/js-yaml": { + "version": "3.12.5", + "resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-3.12.5.tgz", + "integrity": "sha512-JCcp6J0GV66Y4ZMDAQCXot4xprYB+Zfd3meK9+INSJeVZwJmHAW30BBEEkPzXswMXuiyReUGOP3GxrADc9wPww==", + "dev": true + }, "@types/json-schema": { "version": "7.0.5", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.5.tgz", @@ -292,6 +313,15 @@ "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", "dev": true }, + "@types/mkdirp": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@types/mkdirp/-/mkdirp-1.0.1.tgz", + "integrity": "sha512-HkGSK7CGAXncr8Qn/0VqNtExEE+PHMWb+qlR1faHMao7ng6P3tAaoWWBMdva0gL5h4zprjIO89GJOLXsMcDm1Q==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/mocha": { "version": "5.2.6", "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.6.tgz", @@ -375,6 +405,15 @@ "@types/vinyl": "*" } }, + "@types/xml2js": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/@types/xml2js/-/xml2js-0.4.5.tgz", + "integrity": "sha512-yohU3zMn0fkhlape1nxXG2bLEGZRc1FeqF80RoHaYXJN7uibaauXfhzhOJr1Xh36sn+/tx21QAOf07b/xYVk1w==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/yargs": { "version": "12.0.9", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-12.0.9.tgz", @@ -2286,9 +2325,9 @@ } }, "dotenv": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-6.2.0.tgz", - "integrity": "sha512-HygQCKUBSFl8wKQZBSemMywRWcEDNidvNbjGVyZu3nbZ8qq9ubiPoGLMdRDpfSrpkkm9BXYFkpKxxFX38o/76w==" + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz", + "integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==" }, "double-ended-queue": { "version": "2.1.0-0", @@ -4187,7 +4226,7 @@ }, "github-from-package": { "version": "0.0.0", - "resolved": "https://registry.npm.taobao.org/github-from-package/download/github-from-package-0.0.0.tgz", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", "integrity": "sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4=", "dev": true }, @@ -7362,7 +7401,7 @@ }, "noop-logger": { "version": "0.1.1", - "resolved": "https://registry.npm.taobao.org/noop-logger/download/noop-logger-0.1.1.tgz", + "resolved": "https://registry.npmjs.org/noop-logger/-/noop-logger-0.1.1.tgz", "integrity": "sha1-lKKxYzxPExdVMAfYlm/Q6EG2pMI=", "dev": true }, @@ -9213,7 +9252,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { @@ -10074,7 +10113,7 @@ }, "which-pm-runs": { "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/which-pm-runs/download/which-pm-runs-1.0.0.tgz", + "resolved": "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.0.0.tgz", "integrity": "sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs=", "dev": true }, diff --git a/package.json b/package.json index 0491d0c5903..7890bcf589d 100644 --- a/package.json +++ b/package.json @@ -47,15 +47,20 @@ "oracle-orm" ], "devDependencies": { + "@types/app-root-path": "^1.2.4", "@types/chai": "^4.1.2", "@types/chai-as-promised": "7.1.0", - "@types/debug": "4.1.2", + "@types/debug": "^4.1.2", + "@types/dotenv": "^8.2.0", + "@types/js-yaml": "^3.12.5", + "@types/mkdirp": "^1.0.1", "@types/mocha": "^5.2.6", "@types/node": "^9.6.0", "@types/rimraf": "^2.0.2", "@types/sha.js": "^2.4.0", "@types/sinon": "^7.0.8", "@types/source-map-support": "^0.4.2", + "@types/xml2js": "^0.4.5", "@types/yargs": "^12.0.9", "@typescript-eslint/eslint-plugin": "^3.7.0", "@typescript-eslint/parser": "^3.7.0", @@ -103,7 +108,7 @@ "chalk": "^2.4.2", "cli-highlight": "^2.0.0", "debug": "^4.1.1", - "dotenv": "^6.2.0", + "dotenv": "^8.2.0", "glob": "^7.1.2", "js-yaml": "^3.13.1", "mkdirp": "^1.0.3", diff --git a/src/cache/RedisQueryResultCache.ts b/src/cache/RedisQueryResultCache.ts index 735a4279800..afda734a262 100644 --- a/src/cache/RedisQueryResultCache.ts +++ b/src/cache/RedisQueryResultCache.ts @@ -185,8 +185,11 @@ export class RedisQueryResultCache implements QueryResultCache { */ protected loadRedis(): any { try { - return PlatformTools.load(this.clientType); - + if (this.clientType === "ioredis/cluster") { + return PlatformTools.load("ioredis"); + } else { + return PlatformTools.load(this.clientType); + } } catch (e) { throw new Error(`Cannot use cache because ${this.clientType} is not installed. Please run "npm i ${this.clientType} --save".`); } diff --git a/src/commands/CommandUtils.ts b/src/commands/CommandUtils.ts index 75f43b41aeb..bd42c4ba5c8 100644 --- a/src/commands/CommandUtils.ts +++ b/src/commands/CommandUtils.ts @@ -1,6 +1,6 @@ import * as fs from "fs"; import * as path from "path"; -const mkdirp = require("mkdirp"); +import mkdirp from "mkdirp"; /** * Command line utils functions. diff --git a/src/connection/ConnectionOptionsReader.ts b/src/connection/ConnectionOptionsReader.ts index 5e9ee045100..b995eba5653 100644 --- a/src/connection/ConnectionOptionsReader.ts +++ b/src/connection/ConnectionOptionsReader.ts @@ -1,3 +1,5 @@ +import dotenv from "dotenv"; +import appRootPath from "app-root-path"; import {ConnectionOptions} from "./ConnectionOptions"; import {PlatformTools} from "../platform/PlatformTools"; import {ConnectionOptionsEnvReader} from "./options-reader/ConnectionOptionsEnvReader"; @@ -93,10 +95,8 @@ export class ConnectionOptionsReader { // if .env file found then load all its variables into process.env using dotenv package if (foundFileFormat === "env") { - const dotenv = PlatformTools.load("dotenv"); dotenv.config({ path: this.baseFilePath }); } else if (PlatformTools.fileExist(".env")) { - const dotenv = PlatformTools.load("dotenv"); dotenv.config({ path: ".env" }); } @@ -108,13 +108,13 @@ export class ConnectionOptionsReader { connectionOptions = new ConnectionOptionsEnvReader().read(); } else if (foundFileFormat === "js" || foundFileFormat === "cjs") { - connectionOptions = await PlatformTools.load(configFile); + connectionOptions = await require(configFile); } else if (foundFileFormat === "ts") { - connectionOptions = await PlatformTools.load(configFile); + connectionOptions = await require(configFile); } else if (foundFileFormat === "json") { - connectionOptions = PlatformTools.load(configFile); + connectionOptions = require(configFile); } else if (foundFileFormat === "yml") { connectionOptions = new ConnectionOptionsYmlReader().read(configFile); @@ -200,7 +200,7 @@ export class ConnectionOptionsReader { if (this.options && this.options.root) return this.options.root; - return PlatformTools.load("app-root-path").path; + return appRootPath.path; } /** diff --git a/src/connection/options-reader/ConnectionOptionsXmlReader.ts b/src/connection/options-reader/ConnectionOptionsXmlReader.ts index d43e9e76443..17f5cf347ef 100644 --- a/src/connection/options-reader/ConnectionOptionsXmlReader.ts +++ b/src/connection/options-reader/ConnectionOptionsXmlReader.ts @@ -1,3 +1,4 @@ +import {parseString as xmlParser} from 'xml2js'; import {PlatformTools} from "../../platform/PlatformTools"; import {ConnectionOptions} from "../ConnectionOptions"; @@ -43,11 +44,10 @@ export class ConnectionOptionsXmlReader { * Reads xml file contents and returns them in a promise. */ protected readXml(path: string): Promise { - const xmlParser = PlatformTools.load("xml2js").parseString; const xmlOptions = { trim: true, explicitRoot: false }; return new Promise((ok, fail) => { xmlParser(PlatformTools.readFileSync(path), xmlOptions, (err: any, result: any) => err ? fail(err) : ok(result)); }); } -} \ No newline at end of file +} diff --git a/src/connection/options-reader/ConnectionOptionsYmlReader.ts b/src/connection/options-reader/ConnectionOptionsYmlReader.ts index 8d90e6a519f..7c14a4d28f9 100644 --- a/src/connection/options-reader/ConnectionOptionsYmlReader.ts +++ b/src/connection/options-reader/ConnectionOptionsYmlReader.ts @@ -1,3 +1,4 @@ +import ymlParser from 'js-yaml'; import {PlatformTools} from "../../platform/PlatformTools"; import {ConnectionOptions} from "../ConnectionOptions"; @@ -14,11 +15,18 @@ export class ConnectionOptionsYmlReader { * Reads connection options from given yml file. */ read(path: string): ConnectionOptions[] { - const ymlParser = PlatformTools.load("js-yaml"); - const config = ymlParser.safeLoad(PlatformTools.readFileSync(path)); + const contentsBuffer = PlatformTools.readFileSync(path); + const contents = contentsBuffer.toString(); + + const config: undefined | string | {[key: string]: any} = ymlParser.safeLoad(contents); + + if (typeof config !== 'object') { + return []; + } + return Object.keys(config).map(connectionName => { return Object.assign({ name: connectionName }, config[connectionName]); }); } -} \ No newline at end of file +} diff --git a/src/driver/better-sqlite3/BetterSqlite3Driver.ts b/src/driver/better-sqlite3/BetterSqlite3Driver.ts index 46531164535..77864accf25 100644 --- a/src/driver/better-sqlite3/BetterSqlite3Driver.ts +++ b/src/driver/better-sqlite3/BetterSqlite3Driver.ts @@ -1,3 +1,5 @@ +import mkdirp from 'mkdirp'; +import path from 'path'; import { DriverPackageNotInstalledError } from "../../error/DriverPackageNotInstalledError"; import { DriverOptionNotSetError } from "../../error/DriverOptionNotSetError"; import { PlatformTools } from "../../platform/PlatformTools"; @@ -88,7 +90,7 @@ export class BetterSqlite3Driver extends AbstractSqliteDriver { if (this.options.database !== ":memory:") await this.createDatabaseDirectory(this.options.database); - const { + const { database, readonly = false, fileMustExist = false, @@ -132,10 +134,8 @@ export class BetterSqlite3Driver extends AbstractSqliteDriver { /** * Auto creates database directory if it does not exist. */ - protected createDatabaseDirectory(fullPath: string): Promise { - const mkdirp = PlatformTools.load("mkdirp"); - const path = PlatformTools.load("path"); - return mkdirp(path.dirname(fullPath)); + protected async createDatabaseDirectory(fullPath: string): Promise { + await mkdirp(path.dirname(fullPath)); } } diff --git a/src/driver/react-native/ReactNativeDriver.ts b/src/driver/react-native/ReactNativeDriver.ts index 803ac93b794..8aca0aca75f 100644 --- a/src/driver/react-native/ReactNativeDriver.ts +++ b/src/driver/react-native/ReactNativeDriver.ts @@ -5,6 +5,7 @@ import {QueryRunner} from "../../query-runner/QueryRunner"; import {Connection} from "../../connection/Connection"; import {DriverOptionNotSetError} from "../../error/DriverOptionNotSetError"; import {DriverPackageNotInstalledError} from "../../error/DriverPackageNotInstalledError"; +import {PlatformTools} from "../../platform/PlatformTools"; export class ReactNativeDriver extends AbstractSqliteDriver { options: ReactNativeConnectionOptions; @@ -89,7 +90,7 @@ export class ReactNativeDriver extends AbstractSqliteDriver { */ protected loadDependencies(): void { try { - this.sqlite = require("react-native-sqlite-storage"); + this.sqlite = PlatformTools.load("react-native-sqlite-storage"); } catch (e) { throw new DriverPackageNotInstalledError("React-Native", "react-native-sqlite-storage"); diff --git a/src/driver/sqlite/SqliteDriver.ts b/src/driver/sqlite/SqliteDriver.ts index cdd62261279..fd271d72f2c 100644 --- a/src/driver/sqlite/SqliteDriver.ts +++ b/src/driver/sqlite/SqliteDriver.ts @@ -1,3 +1,5 @@ +import mkdirp from 'mkdirp'; +import path from 'path'; import { DriverPackageNotInstalledError } from "../../error/DriverPackageNotInstalledError"; import { SqliteQueryRunner } from "./SqliteQueryRunner"; import { DriverOptionNotSetError } from "../../error/DriverOptionNotSetError"; @@ -132,10 +134,8 @@ export class SqliteDriver extends AbstractSqliteDriver { /** * Auto creates database directory if it does not exist. */ - protected createDatabaseDirectory(fullPath: string): Promise { - const mkdirp = PlatformTools.load("mkdirp"); - const path = PlatformTools.load("path"); - return mkdirp(path.dirname(fullPath)); + protected async createDatabaseDirectory(fullPath: string): Promise { + await mkdirp(path.dirname(fullPath)); } } diff --git a/src/logger/DebugLogger.ts b/src/logger/DebugLogger.ts index 8943a4523b4..36e901187a9 100644 --- a/src/logger/DebugLogger.ts +++ b/src/logger/DebugLogger.ts @@ -1,3 +1,4 @@ +import debug from "debug"; import {Logger} from "./Logger"; import {QueryRunner} from "../"; import {PlatformTools} from "../platform/PlatformTools"; @@ -6,18 +7,16 @@ import {PlatformTools} from "../platform/PlatformTools"; * Performs logging of the events in TypeORM via debug library. */ export class DebugLogger implements Logger { - private debug = PlatformTools.load("debug"); + private debugQueryLog = debug("typeorm:query:log"); + private debugQueryError = debug("typeorm:query:error"); + private debugQuerySlow = debug("typeorm:query:slow"); + private debugSchemaBuild = debug("typeorm:schema"); + private debugMigration = debug("typeorm:migration"); + + private debugLog = debug("typeorm:log"); + private debugInfo = debug("typeorm:info"); + private debugWarn = debug("typeorm:warn"); - private debugQueryLog = this.debug("typeorm:query:log"); - private debugQueryError = this.debug("typeorm:query:error"); - private debugQuerySlow = this.debug("typeorm:query:slow"); - private debugSchemaBuild = this.debug("typeorm:schema"); - private debugMigration = this.debug("typeorm:migration"); - - private debugLog = this.debug("typeorm:log"); - private debugInfo = this.debug("typeorm:info"); - private debugWarn = this.debug("typeorm:warn"); - /** * Logs query and parameters used in it. */ @@ -29,7 +28,7 @@ export class DebugLogger implements Logger { } } } - + /** * Logs query that failed. */ @@ -42,7 +41,7 @@ export class DebugLogger implements Logger { this.debugQueryError("error: ", error); } } - + /** * Logs query that is slow. */ @@ -55,7 +54,7 @@ export class DebugLogger implements Logger { this.debugQuerySlow("execution time:", time); } } - + /** * Logs events from the schema build process. */ @@ -64,7 +63,7 @@ export class DebugLogger implements Logger { this.debugSchemaBuild(message); } } - + /** * Logs events from the migration run process. */ @@ -73,7 +72,7 @@ export class DebugLogger implements Logger { this.debugMigration(message); } } - + /** * Perform logging using given logger. * Log has its own level and message. diff --git a/src/logger/FileLogger.ts b/src/logger/FileLogger.ts index f50d65283d7..e96d142ad2c 100644 --- a/src/logger/FileLogger.ts +++ b/src/logger/FileLogger.ts @@ -1,4 +1,5 @@ import {LoggerOptions, FileLoggerOptions} from "./LoggerOptions"; +import appRootPath from "app-root-path"; import {QueryRunner} from "../query-runner/QueryRunner"; import {Logger} from "./Logger"; import {PlatformTools} from "../platform/PlatformTools"; @@ -100,7 +101,7 @@ export class FileLogger implements Logger { */ protected write(strings: string|string[]) { strings = Array.isArray(strings) ? strings : [strings]; - const basePath = PlatformTools.load("app-root-path").path + "/"; + const basePath = appRootPath.path + "/"; let logPath = "ormlogs.log"; if (this.fileLoggerOptions && this.fileLoggerOptions.logPath) { logPath = PlatformTools.pathNormalize(this.fileLoggerOptions.logPath); diff --git a/src/platform/PlatformTools.ts b/src/platform/PlatformTools.ts index 98e9d066895..0821a63c7d4 100644 --- a/src/platform/PlatformTools.ts +++ b/src/platform/PlatformTools.ts @@ -48,8 +48,11 @@ export class PlatformTools { /** * hana */ - case "@sap/hdbext": - return require("@sap/hdbext"); + case "@sap/hana-client": + return require("@sap/hana-client"); + + case "@sap/hdb-pool": + return require("hdb-pool"); /** * mysql @@ -78,19 +81,24 @@ export class PlatformTools { case "pg-query-stream": return require("pg-query-stream"); + case "typeorm-aurora-data-api-driver": + return require("typeorm-aurora-data-api-driver"); + /** * redis */ case "redis": return require("redis"); - /** - * ioredis - */ case "ioredis": - case "ioredis/cluster": return require("ioredis"); + /** + * better-sqlite3 + */ + case "better-sqlite3": + return require("better-sqlite3"); + /** * sqlite */ @@ -110,40 +118,21 @@ export class PlatformTools { return require("mssql"); /** - * other modules - */ - case "mkdirp": - return require("mkdirp"); - - case "path": - return require("path"); - - case "debug": - return require("debug"); - - case "app-root-path": - return require("app-root-path"); - - case "glob": - return require("glob"); - - case "typeorm-aurora-data-api-driver": - return require("typeorm-aurora-data-api-driver"); - /** - * default - */ - default: - return require(name); - + * react-native-sqlite + */ + case "react-native-sqlite-storage": + return require("react-native-sqlite-storage"); } } catch (err) { - if (!path.isAbsolute(name) && name.substr(0, 2) !== "./" && name.substr(0, 3) !== "../") { - return require(path.resolve(process.cwd() + "/node_modules/" + name)); - } - - throw err; + return require(path.resolve(process.cwd() + "/node_modules/" + name)); } + + // If nothing above matched and we get here, the package was not listed within PlatformTools + // and is an Invalid Package. To make it explicit that this is NOT the intended use case for + // PlatformTools.load - it's not just a way to replace `require` all willy-nilly - let's throw + // an error. + throw new TypeError(`Invalid Package for PlatformTools.load: ${name}`); } /** diff --git a/src/util/DirectoryExportedClassesLoader.ts b/src/util/DirectoryExportedClassesLoader.ts index 321937a1985..3e64efe1f55 100644 --- a/src/util/DirectoryExportedClassesLoader.ts +++ b/src/util/DirectoryExportedClassesLoader.ts @@ -1,3 +1,4 @@ +import glob from "glob"; import {PlatformTools} from "../platform/PlatformTools"; import {EntitySchema} from "../index"; import {Logger} from "../logger/Logger"; @@ -24,7 +25,7 @@ export function importClassesFromDirectories(logger: Logger, directories: string } const allFiles = directories.reduce((allDirs, dir) => { - return allDirs.concat(PlatformTools.load("glob").sync(PlatformTools.pathNormalize(dir))); + return allDirs.concat(glob.sync(PlatformTools.pathNormalize(dir))); }, [] as string[]); if (directories.length > 0 && allFiles.length === 0) { @@ -37,7 +38,7 @@ export function importClassesFromDirectories(logger: Logger, directories: string const dtsExtension = file.substring(file.length - 5, file.length); return formats.indexOf(PlatformTools.pathExtname(file)) !== -1 && dtsExtension !== ".d.ts"; }) - .map(file => PlatformTools.load(PlatformTools.pathResolve(file))); + .map(file => require(PlatformTools.pathResolve(file))); return loadFileClasses(dirs, []); } @@ -48,10 +49,10 @@ export function importClassesFromDirectories(logger: Logger, directories: string export function importJsonsFromDirectories(directories: string[], format = ".json"): any[] { const allFiles = directories.reduce((allDirs, dir) => { - return allDirs.concat(PlatformTools.load("glob").sync(PlatformTools.pathNormalize(dir))); + return allDirs.concat(glob.sync(PlatformTools.pathNormalize(dir))); }, [] as string[]); return allFiles .filter(file => PlatformTools.pathExtname(file) === format) - .map(file => PlatformTools.load(PlatformTools.pathResolve(file))); + .map(file => require(PlatformTools.pathResolve(file))); } diff --git a/test/github-issues/4410/issue-4410.ts b/test/github-issues/4410/issue-4410.ts index 52dfceab534..86ff3de1d73 100644 --- a/test/github-issues/4410/issue-4410.ts +++ b/test/github-issues/4410/issue-4410.ts @@ -1,3 +1,4 @@ +import appRootPath from "app-root-path"; import sinon from "sinon"; import { Connection, FileLogger } from "../../../src"; import { createTestingConnections, reloadTestingDatabases, closeTestingConnections, TestingOptions } from "../../utils/test-utils"; @@ -33,7 +34,7 @@ describe("github issues > #4410 allow custom filepath for FileLogger", () => { await connection.query(testQuery); sinon.assert.calledWith( stub, - PlatformTools.load("app-root-path").path + "/ormlogs.log", + appRootPath.path + "/ormlogs.log", sinon.match(testQuery) ); }))); @@ -48,12 +49,12 @@ describe("github issues > #4410 allow custom filepath for FileLogger", () => { }), }); }); - it("writes to the given filename", async () => + it("writes to the given filename", async () => Promise.all(connections.map(async (connection) => { await connection.query(testQuery); sinon.assert.calledWith( stub, - PlatformTools.load("app-root-path").path + "/test.log", + appRootPath.path + "/test.log", sinon.match(testQuery) ); }))); @@ -68,12 +69,12 @@ describe("github issues > #4410 allow custom filepath for FileLogger", () => { }), }); }); - it("writes to the given path", () => + it("writes to the given path", () => Promise.all(connections.map(async (connection) => { await connection.query(testQuery); sinon.assert.calledWith( stub, - PlatformTools.load("app-root-path").path + "/test/test.log", + appRootPath.path + "/test/test.log", sinon.match(testQuery) ); }))); From 0397e44817c4cc6ad5b9f284e861ff85ccb90530 Mon Sep 17 00:00:00 2001 From: Michael Bromley Date: Thu, 3 Sep 2020 14:47:16 +0200 Subject: [PATCH 048/212] fix: Migration issues with scale & precision in sqlite/sql.js (#6638) * fix: Migration issues with scale & precision in sqlite/sql.js Specifying precision or scale properties on columns with SQLite/sql.js would result in migrations being generated even on an unchanged schema. This was due to the precision and scale arguments not correctly being inferred when reading the table. This change handles scale and precision in the same way that "length" was already being correctly handled. Fixes #6636 * awaited the test * fix missing async Co-authored-by: Umed Khudoiberdiev --- .../sqlite-abstract/AbstractSqliteDriver.ts | 23 +++++++++++++++-- .../AbstractSqliteQueryRunner.ts | 20 ++++++++++++--- test/github-issues/6636/entity/Test.ts | 15 +++++++++++ test/github-issues/6636/issue-6636.ts | 25 +++++++++++++++++++ 4 files changed, 78 insertions(+), 5 deletions(-) create mode 100644 test/github-issues/6636/entity/Test.ts create mode 100644 test/github-issues/6636/issue-6636.ts diff --git a/src/driver/sqlite-abstract/AbstractSqliteDriver.ts b/src/driver/sqlite-abstract/AbstractSqliteDriver.ts index 09cb044e178..dc406c7bb76 100644 --- a/src/driver/sqlite-abstract/AbstractSqliteDriver.ts +++ b/src/driver/sqlite-abstract/AbstractSqliteDriver.ts @@ -130,12 +130,31 @@ export abstract class AbstractSqliteDriver implements Driver { /** * Gets list of column data types that support precision by a driver. */ - withPrecisionColumnTypes: ColumnType[] = []; + withPrecisionColumnTypes: ColumnType[] = [ + "real", + "double", + "double precision", + "float", + "real", + "numeric", + "decimal", + "date", + "time", + "datetime" + ]; /** * Gets list of column data types that support scale by a driver. */ - withScaleColumnTypes: ColumnType[] = []; + withScaleColumnTypes: ColumnType[] = [ + "real", + "double", + "double precision", + "float", + "real", + "numeric", + "decimal", + ]; /** * Orm has special columns and we need to know what database column types should be for those types. diff --git a/src/driver/sqlite-abstract/AbstractSqliteQueryRunner.ts b/src/driver/sqlite-abstract/AbstractSqliteQueryRunner.ts index c361695c2cf..995b22d785b 100644 --- a/src/driver/sqlite-abstract/AbstractSqliteQueryRunner.ts +++ b/src/driver/sqlite-abstract/AbstractSqliteQueryRunner.ts @@ -825,17 +825,31 @@ export abstract class AbstractSqliteQueryRunner extends BaseQueryRunner implemen } } - // parse datatype and attempt to retrieve length + // parse datatype and attempt to retrieve length, precision and scale let pos = tableColumn.type.indexOf("("); if (pos !== -1) { - let dataType = tableColumn.type.substr(0, pos); + const fullType = tableColumn.type; + let dataType = fullType.substr(0, pos); if (!!this.driver.withLengthColumnTypes.find(col => col === dataType)) { - let len = parseInt(tableColumn.type.substring(pos + 1, tableColumn.type.length - 1)); + let len = parseInt(fullType.substring(pos + 1, fullType.length - 1)); if (len) { tableColumn.length = len.toString(); tableColumn.type = dataType; // remove the length part from the datatype } } + if (!!this.driver.withPrecisionColumnTypes.find(col => col === dataType)) { + const re = new RegExp(`^${dataType}\\((\\d+),?\\s?(\\d+)?\\)`); + const matches = fullType.match(re); + if (matches && matches[1]) { + tableColumn.precision = +matches[1]; + } + if (!!this.driver.withScaleColumnTypes.find(col => col === dataType)) { + if (matches && matches[2]) { + tableColumn.scale = +matches[2]; + } + } + tableColumn.type = dataType; // remove the precision/scale part from the datatype + } } return tableColumn; diff --git a/test/github-issues/6636/entity/Test.ts b/test/github-issues/6636/entity/Test.ts new file mode 100644 index 00000000000..086363bbbc3 --- /dev/null +++ b/test/github-issues/6636/entity/Test.ts @@ -0,0 +1,15 @@ +import { Column, Entity, PrimaryColumn } from "../../../../src"; + +@Entity() +export class Test { + + @PrimaryColumn() + id: number; + + @Column({ nullable: true, precision: 6 }) + startedAt?: Date; + + @Column({ type: 'decimal', precision: 5, scale: 2 }) + value: number; + +} diff --git a/test/github-issues/6636/issue-6636.ts b/test/github-issues/6636/issue-6636.ts new file mode 100644 index 00000000000..841f7c4a5af --- /dev/null +++ b/test/github-issues/6636/issue-6636.ts @@ -0,0 +1,25 @@ +import { Connection } from "../../../src"; +import { closeTestingConnections, createTestingConnections, reloadTestingDatabases } from "../../utils/test-utils"; +import { Test } from "./entity/Test"; +import { expect } from "chai"; + +describe("github issues > #6636 migration issues with scale & precision", () => { + + let connections: Connection[]; + before(async () => connections = await createTestingConnections({ + entities: [Test], + enabledDrivers: ["sqljs", "sqlite", "better-sqlite3"], + })); + beforeEach(() => reloadTestingDatabases(connections)); + after(() => closeTestingConnections(connections)); + + it("should not create migrations columns with precision", async () => { + await Promise.all(connections.map(async (connection) => { + const sqlInMemory = await connection.driver.createSchemaBuilder().log(); + expect(sqlInMemory.upQueries).to.eql([]); + expect(sqlInMemory.downQueries).to.eql([]); + } + )) + }); + +}); From a50e09ab66ac828fe3e8348a814f0e1a46d9aca0 Mon Sep 17 00:00:00 2001 From: Umed Khudoiberdiev Date: Fri, 4 Sep 2020 13:07:02 +0500 Subject: [PATCH 049/212] added directory typing --- src/commands/MigrationCreateCommand.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/MigrationCreateCommand.ts b/src/commands/MigrationCreateCommand.ts index 383e30c680c..ba81b1e8b7b 100644 --- a/src/commands/MigrationCreateCommand.ts +++ b/src/commands/MigrationCreateCommand.ts @@ -45,7 +45,7 @@ export class MigrationCreateCommand implements yargs.CommandModule { const timestamp = new Date().getTime(); const fileContent = MigrationCreateCommand.getTemplate(args.name as any, timestamp); const filename = timestamp + "-" + args.name + ".ts"; - let directory = args.dir; + let directory: string = args.dir; // if directory is not set then try to open tsconfig and find default path there if (!directory) { From df70dc39b5ab018a5ababb1df157205b8f88231e Mon Sep 17 00:00:00 2001 From: Umed Khudoiberdiev Date: Fri, 4 Sep 2020 13:20:43 +0500 Subject: [PATCH 050/212] added directory typing --- src/commands/MigrationCreateCommand.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/commands/MigrationCreateCommand.ts b/src/commands/MigrationCreateCommand.ts index ba81b1e8b7b..a39247e919c 100644 --- a/src/commands/MigrationCreateCommand.ts +++ b/src/commands/MigrationCreateCommand.ts @@ -45,7 +45,7 @@ export class MigrationCreateCommand implements yargs.CommandModule { const timestamp = new Date().getTime(); const fileContent = MigrationCreateCommand.getTemplate(args.name as any, timestamp); const filename = timestamp + "-" + args.name + ".ts"; - let directory: string = args.dir; + let directory = args.dir as string; // if directory is not set then try to open tsconfig and find default path there if (!directory) { @@ -55,7 +55,7 @@ export class MigrationCreateCommand implements yargs.CommandModule { configName: args.config as any }); const connectionOptions = await connectionOptionsReader.get(args.connection as any); - directory = connectionOptions.cli ? connectionOptions.cli.migrationsDir : undefined; + directory = connectionOptions.cli ? (connectionOptions.cli.migrationsDir || "") : ""; } catch (err) { } } From c81b405a365067e9ab8854317a659f99df9830b4 Mon Sep 17 00:00:00 2001 From: Michael Bromley Date: Fri, 4 Sep 2020 12:37:04 +0200 Subject: [PATCH 051/212] fix: Unnecessary migrations for fulltext indices (#6634) * fix: Unnecessary migrations for fulltext indices Fixes #6633 (see issue for root cause explanation) * test: Enable all tests * refactor: Add `isFullTextColumnTypeSupported()` method to Driver interface * fix: Include isFullTextColumnTypeSupported method in SqlServerDriver --- src/driver/Driver.ts | 5 ++++ .../aurora-data-api/AuroraDataApiDriver.ts | 7 +++++ src/driver/cockroachdb/CockroachDriver.ts | 7 +++++ src/driver/mongodb/MongoDriver.ts | 7 +++++ src/driver/mysql/MysqlDriver.ts | 7 +++++ src/driver/oracle/OracleDriver.ts | 7 +++++ src/driver/postgres/PostgresDriver.ts | 7 +++++ src/driver/sap/SapDriver.ts | 7 +++++ .../sqlite-abstract/AbstractSqliteDriver.ts | 7 +++++ src/driver/sqlserver/SqlServerDriver.ts | 7 +++++ src/schema-builder/RdbmsSchemaBuilder.ts | 2 +- .../options/TableIndexOptions.ts | 6 ++-- test/github-issues/6633/entity/Test.ts | 11 +++++++ test/github-issues/6633/issue-6633.ts | 29 +++++++++++++++++++ 14 files changed, 112 insertions(+), 4 deletions(-) create mode 100644 test/github-issues/6633/entity/Test.ts create mode 100644 test/github-issues/6633/issue-6633.ts diff --git a/src/driver/Driver.ts b/src/driver/Driver.ts index 4041f586932..3027e4afaf8 100644 --- a/src/driver/Driver.ts +++ b/src/driver/Driver.ts @@ -193,6 +193,11 @@ export interface Driver { */ isUUIDGenerationSupported(): boolean; + /** + * Returns true if driver supports fulltext indices. + */ + isFullTextColumnTypeSupported(): boolean; + /** * Creates an escaped parameter. */ diff --git a/src/driver/aurora-data-api/AuroraDataApiDriver.ts b/src/driver/aurora-data-api/AuroraDataApiDriver.ts index 901ff224359..e85e545aa20 100644 --- a/src/driver/aurora-data-api/AuroraDataApiDriver.ts +++ b/src/driver/aurora-data-api/AuroraDataApiDriver.ts @@ -750,6 +750,13 @@ export class AuroraDataApiDriver implements Driver { return false; } + /** + * Returns true if driver supports fulltext indices. + */ + isFullTextColumnTypeSupported(): boolean { + return true; + } + /** * Creates an escaped parameter. */ diff --git a/src/driver/cockroachdb/CockroachDriver.ts b/src/driver/cockroachdb/CockroachDriver.ts index 33472503616..8cacf571187 100644 --- a/src/driver/cockroachdb/CockroachDriver.ts +++ b/src/driver/cockroachdb/CockroachDriver.ts @@ -649,6 +649,13 @@ export class CockroachDriver implements Driver { return true; } + /** + * Returns true if driver supports fulltext indices. + */ + isFullTextColumnTypeSupported(): boolean { + return false; + } + /** * Creates an escaped parameter. */ diff --git a/src/driver/mongodb/MongoDriver.ts b/src/driver/mongodb/MongoDriver.ts index 71065324678..f1d1b190e2b 100644 --- a/src/driver/mongodb/MongoDriver.ts +++ b/src/driver/mongodb/MongoDriver.ts @@ -389,6 +389,13 @@ export class MongoDriver implements Driver { return false; } + /** + * Returns true if driver supports fulltext indices. + */ + isFullTextColumnTypeSupported(): boolean { + return false; + } + /** * Creates an escaped parameter. */ diff --git a/src/driver/mysql/MysqlDriver.ts b/src/driver/mysql/MysqlDriver.ts index 291beaa68fc..d55a960ef41 100644 --- a/src/driver/mysql/MysqlDriver.ts +++ b/src/driver/mysql/MysqlDriver.ts @@ -798,6 +798,13 @@ export class MysqlDriver implements Driver { return false; } + /** + * Returns true if driver supports fulltext indices. + */ + isFullTextColumnTypeSupported(): boolean { + return true; + } + /** * Creates an escaped parameter. */ diff --git a/src/driver/oracle/OracleDriver.ts b/src/driver/oracle/OracleDriver.ts index 134ed6bba7e..42575f61080 100644 --- a/src/driver/oracle/OracleDriver.ts +++ b/src/driver/oracle/OracleDriver.ts @@ -623,6 +623,13 @@ export class OracleDriver implements Driver { return false; } + /** + * Returns true if driver supports fulltext indices. + */ + isFullTextColumnTypeSupported(): boolean { + return false; + } + /** * Creates an escaped parameter. */ diff --git a/src/driver/postgres/PostgresDriver.ts b/src/driver/postgres/PostgresDriver.ts index e9eae242c6a..59684c74bfd 100644 --- a/src/driver/postgres/PostgresDriver.ts +++ b/src/driver/postgres/PostgresDriver.ts @@ -912,6 +912,13 @@ export class PostgresDriver implements Driver { return true; } + /** + * Returns true if driver supports fulltext indices. + */ + isFullTextColumnTypeSupported(): boolean { + return false; + } + get uuidGenerator(): string { return this.options.uuidExtension === "pgcrypto" ? "gen_random_uuid()" : "uuid_generate_v4()"; } diff --git a/src/driver/sap/SapDriver.ts b/src/driver/sap/SapDriver.ts index 9479277503d..85b6a7f2f2e 100644 --- a/src/driver/sap/SapDriver.ts +++ b/src/driver/sap/SapDriver.ts @@ -624,6 +624,13 @@ export class SapDriver implements Driver { return false; } + /** + * Returns true if driver supports fulltext indices. + */ + isFullTextColumnTypeSupported(): boolean { + return true; + } + /** * Creates an escaped parameter. */ diff --git a/src/driver/sqlite-abstract/AbstractSqliteDriver.ts b/src/driver/sqlite-abstract/AbstractSqliteDriver.ts index dc406c7bb76..79fd5ef7f85 100644 --- a/src/driver/sqlite-abstract/AbstractSqliteDriver.ts +++ b/src/driver/sqlite-abstract/AbstractSqliteDriver.ts @@ -594,6 +594,13 @@ export abstract class AbstractSqliteDriver implements Driver { return false; } + /** + * Returns true if driver supports fulltext indices. + */ + isFullTextColumnTypeSupported(): boolean { + return false; + } + /** * Creates an escaped parameter. */ diff --git a/src/driver/sqlserver/SqlServerDriver.ts b/src/driver/sqlserver/SqlServerDriver.ts index 20e7f9e11d3..5954431de09 100644 --- a/src/driver/sqlserver/SqlServerDriver.ts +++ b/src/driver/sqlserver/SqlServerDriver.ts @@ -640,6 +640,13 @@ export class SqlServerDriver implements Driver { return true; } + /** + * Returns true if driver supports fulltext indices. + */ + isFullTextColumnTypeSupported(): boolean { + return false; + } + /** * Creates an escaped parameter. */ diff --git a/src/schema-builder/RdbmsSchemaBuilder.ts b/src/schema-builder/RdbmsSchemaBuilder.ts index 2c625c9a6e7..d5bd9f2aa0f 100644 --- a/src/schema-builder/RdbmsSchemaBuilder.ts +++ b/src/schema-builder/RdbmsSchemaBuilder.ts @@ -277,7 +277,7 @@ export class RdbmsSchemaBuilder implements SchemaBuilder { if (indexMetadata.isSpatial !== tableIndex.isSpatial) return true; - if (indexMetadata.isFulltext !== tableIndex.isFulltext) + if (this.connection.driver.isFullTextColumnTypeSupported() && indexMetadata.isFulltext !== tableIndex.isFulltext) return true; if (indexMetadata.columns.length !== tableIndex.columnNames.length) diff --git a/src/schema-builder/options/TableIndexOptions.ts b/src/schema-builder/options/TableIndexOptions.ts index c75228e2fd3..b37be3d790d 100644 --- a/src/schema-builder/options/TableIndexOptions.ts +++ b/src/schema-builder/options/TableIndexOptions.ts @@ -30,10 +30,10 @@ export interface TableIndexOptions { /** * The FULLTEXT modifier indexes the entire column and does not allow prefixing. - * Works only in MySQL. + * Supported only in MySQL & SAP HANA. */ isFulltext?: boolean; - + /** * Fulltext parser. * Works only in MySQL. @@ -45,4 +45,4 @@ export interface TableIndexOptions { */ where?: string; -} \ No newline at end of file +} diff --git a/test/github-issues/6633/entity/Test.ts b/test/github-issues/6633/entity/Test.ts new file mode 100644 index 00000000000..61443c6dcda --- /dev/null +++ b/test/github-issues/6633/entity/Test.ts @@ -0,0 +1,11 @@ +import { Entity, PrimaryColumn, Index, Column } from "../../../../src"; + +@Entity() +export class Test { + @PrimaryColumn() + id: number; + + @Index("description_index", { fulltext: true }) + @Column() + description: string; +} diff --git a/test/github-issues/6633/issue-6633.ts b/test/github-issues/6633/issue-6633.ts new file mode 100644 index 00000000000..31df86b5b8a --- /dev/null +++ b/test/github-issues/6633/issue-6633.ts @@ -0,0 +1,29 @@ +import "reflect-metadata"; +import { expect } from "chai"; +import { Connection } from "../../../src"; +import { closeTestingConnections, createTestingConnections, reloadTestingDatabases } from "../../utils/test-utils"; +import { Post } from "../4440/entity/Post"; + +describe("github issues > #6633 Fulltext indices continually dropped & re-created", () => { + + let connections: Connection[]; + before(async () => { + connections = await createTestingConnections({ + entities: [Post], + schemaCreate: true, + dropSchema: true + }); + }); + beforeEach(() => reloadTestingDatabases(connections)); + after(() => closeTestingConnections(connections)); + + it("should not create migrations for fulltext indices", () => + Promise.all(connections.map(async (connection) => { + const sqlInMemory = await connection.driver.createSchemaBuilder().log(); + + expect(sqlInMemory.upQueries).to.eql([]); + expect(sqlInMemory.downQueries).to.eql([]); + } + )) + ); +}); From ef2011d7e98abf59767bb0315ccf6acdc9e23c2d Mon Sep 17 00:00:00 2001 From: Json Choi <1890mah@gmail.com> Date: Fri, 4 Sep 2020 19:37:41 +0900 Subject: [PATCH 052/212] fix: get correct insert ids for multiple entities inserted (#6668) * fix: (sqlite) get correct increment primary key for mutiple entities inserted Closes: #2131 * fix: (mysql) get correct increment primary key for mutiple entities inserted Closes: #5973 * test: add test case for fix of #2131 * docs: update note about sqlite lastID --- src/driver/Driver.ts | 2 +- src/driver/mysql/MysqlDriver.ts | 6 ++- .../sqlite-abstract/AbstractSqliteDriver.ts | 6 ++- .../ReturningResultsEntityUpdator.ts | 2 +- test/github-issues/2131/entity/Post.ts | 12 +++++ test/github-issues/2131/issue-2131.ts | 53 +++++++++++++++++++ 6 files changed, 75 insertions(+), 6 deletions(-) create mode 100644 test/github-issues/2131/entity/Post.ts create mode 100644 test/github-issues/2131/issue-2131.ts diff --git a/src/driver/Driver.ts b/src/driver/Driver.ts index 3027e4afaf8..70dc4c0ee5c 100644 --- a/src/driver/Driver.ts +++ b/src/driver/Driver.ts @@ -175,7 +175,7 @@ export interface Driver { /** * Creates generated map of values generated or returned by database after INSERT query. */ - createGeneratedMap(metadata: EntityMetadata, insertResult: any): ObjectLiteral|undefined; + createGeneratedMap(metadata: EntityMetadata, insertResult: any, entityIndex?: number, entityNum?: number): ObjectLiteral|undefined; /** * Differentiate columns of this table and columns from the given column metadatas columns diff --git a/src/driver/mysql/MysqlDriver.ts b/src/driver/mysql/MysqlDriver.ts index d55a960ef41..d65b5d6a5f6 100644 --- a/src/driver/mysql/MysqlDriver.ts +++ b/src/driver/mysql/MysqlDriver.ts @@ -709,11 +709,13 @@ export class MysqlDriver implements Driver { /** * Creates generated map of values generated or returned by database after INSERT query. */ - createGeneratedMap(metadata: EntityMetadata, insertResult: any) { + createGeneratedMap(metadata: EntityMetadata, insertResult: any, entityIndex: number) { const generatedMap = metadata.generatedColumns.reduce((map, generatedColumn) => { let value: any; if (generatedColumn.generationStrategy === "increment" && insertResult.insertId) { - value = insertResult.insertId; + // NOTE: When multiple rows is inserted by a single INSERT statement, + // `insertId` is the value generated for the first inserted row only. + value = insertResult.insertId + entityIndex; // } else if (generatedColumn.generationStrategy === "uuid") { // console.log("getting db value:", generatedColumn.databaseName); // value = generatedColumn.getEntityValue(uuidMap); diff --git a/src/driver/sqlite-abstract/AbstractSqliteDriver.ts b/src/driver/sqlite-abstract/AbstractSqliteDriver.ts index 79fd5ef7f85..308f0c1a9f6 100644 --- a/src/driver/sqlite-abstract/AbstractSqliteDriver.ts +++ b/src/driver/sqlite-abstract/AbstractSqliteDriver.ts @@ -526,11 +526,13 @@ export abstract class AbstractSqliteDriver implements Driver { /** * Creates generated map of values generated or returned by database after INSERT query. */ - createGeneratedMap(metadata: EntityMetadata, insertResult: any) { + createGeneratedMap(metadata: EntityMetadata, insertResult: any, entityIndex: number, entityNum: number) { const generatedMap = metadata.generatedColumns.reduce((map, generatedColumn) => { let value: any; if (generatedColumn.generationStrategy === "increment" && insertResult) { - value = insertResult; + // NOTE: When INSERT statement is successfully completed, the last inserted row ID is returned. + // see also: SqliteQueryRunner.query() + value = insertResult - entityNum + entityIndex + 1; // } else if (generatedColumn.generationStrategy === "uuid") { // value = insertValue[generatedColumn.databaseName]; } diff --git a/src/query-builder/ReturningResultsEntityUpdator.ts b/src/query-builder/ReturningResultsEntityUpdator.ts index 7dcd9f100da..c12e4794b51 100644 --- a/src/query-builder/ReturningResultsEntityUpdator.ts +++ b/src/query-builder/ReturningResultsEntityUpdator.ts @@ -93,7 +93,7 @@ export class ReturningResultsEntityUpdator { } // get all values generated by a database for us const result = Array.isArray(insertResult.raw) ? insertResult.raw[entityIndex] : insertResult.raw; - const generatedMap = this.queryRunner.connection.driver.createGeneratedMap(metadata, result) || {}; + const generatedMap = this.queryRunner.connection.driver.createGeneratedMap(metadata, result, entityIndex, entities.length) || {}; // if database does not support uuid generation we need to get uuid values // generated by orm and set them to the generatedMap diff --git a/test/github-issues/2131/entity/Post.ts b/test/github-issues/2131/entity/Post.ts new file mode 100644 index 00000000000..2004a609664 --- /dev/null +++ b/test/github-issues/2131/entity/Post.ts @@ -0,0 +1,12 @@ +import { PrimaryGeneratedColumn, Entity, Column } from "../../../../src"; + +@Entity() +export class Post { + + @PrimaryGeneratedColumn() + id: number | null; + + @Column() + title: string; + +} diff --git a/test/github-issues/2131/issue-2131.ts b/test/github-issues/2131/issue-2131.ts new file mode 100644 index 00000000000..6d67a4aaf81 --- /dev/null +++ b/test/github-issues/2131/issue-2131.ts @@ -0,0 +1,53 @@ +import "reflect-metadata"; +import { + closeTestingConnections, + createTestingConnections, + reloadTestingDatabases, +} from "../../utils/test-utils"; +import { Connection } from "../../../src/connection/Connection"; +import { expect } from "chai"; +import { Post } from "./entity/Post"; + +describe("github issues > #2131 InsertResult return the same primary key", () => { + let connections: Connection[]; + const posts: Post[] = [{ + id: null, + title: "Post 1", + }, { + id: null, + title: "Post 2", + }, { + id: null, + title: "Post 3", + }, { + id: null, + title: "Post 4", + }]; + + before( + async () => + (connections = await createTestingConnections({ + entities: [__dirname + "/entity/*{.js,.ts}"], + enabledDrivers: ["sqlite", "mysql"], + })) + ); + beforeEach(() => reloadTestingDatabases(connections)); + after(() => closeTestingConnections(connections)); + + it("should get correct insert ids for multiple entities inserted", () => + Promise.all( + connections.map(async (connection) => { + await connection + .createQueryBuilder() + .insert() + .into(Post) + .values(posts) + .execute(); + + expect(posts[0].id).to.equal(1); + expect(posts[1].id).to.equal(2); + expect(posts[2].id).to.equal(3); + expect(posts[3].id).to.equal(4); + }) + )); +}); From 4fc4a1b4eb4e7d54d52e8559b9f04a94cd3ad154 Mon Sep 17 00:00:00 2001 From: Json Choi <1890mah@gmail.com> Date: Fri, 4 Sep 2020 19:56:46 +0900 Subject: [PATCH 053/212] fix: make only a single SELECT to get inserted default and generated values of multiple entities (#6669) * fix: re-select inserted default and generated values with a single SELECT closes #6266 * test: add test case for fix of #6266 * fix lint error --- .../ReturningResultsEntityUpdator.ts | 41 +++++++------ test/github-issues/6266/entity/Post.ts | 14 +++++ test/github-issues/6266/issue-6266.ts | 60 +++++++++++++++++++ 3 files changed, 96 insertions(+), 19 deletions(-) create mode 100644 test/github-issues/6266/entity/Post.ts create mode 100644 test/github-issues/6266/issue-6266.ts diff --git a/src/query-builder/ReturningResultsEntityUpdator.ts b/src/query-builder/ReturningResultsEntityUpdator.ts index c12e4794b51..6e9b41207ab 100644 --- a/src/query-builder/ReturningResultsEntityUpdator.ts +++ b/src/query-builder/ReturningResultsEntityUpdator.ts @@ -117,26 +117,29 @@ export class ReturningResultsEntityUpdator { // for postgres and mssql we use returning/output statement to get values of inserted default and generated values // for other drivers we have to re-select this data from the database if (this.queryRunner.connection.driver.isReturningSqlSupported() === false && insertionColumns.length > 0) { - await Promise.all(entities.map(async (entity, entityIndex) => { + const entityIds = entities.map((entity) => { const entityId = metadata.getEntityIdMap(entity)!; - - // to select just inserted entity we need a criteria to select by. - // for newly inserted entities in drivers which do not support returning statement - // row identifier can only be an increment column - // (since its the only thing that can be generated by those databases) - // or (and) other primary key which is defined by a user and inserted value has it - - const returningResult: any = await this.queryRunner.manager - .createQueryBuilder() - .select(metadata.primaryColumns.map(column => metadata.targetName + "." + column.propertyPath)) - .addSelect(insertionColumns.map(column => metadata.targetName + "." + column.propertyPath)) - .from(metadata.target, metadata.targetName) - .where(entityId) - .setOption("create-pojo") // use POJO because created object can contain default values, e.g. property = null and those properties maight be overridden by merge process - .getOne(); - - this.queryRunner.manager.merge(metadata.target as any, generatedMaps[entityIndex], returningResult); - })); + return entityId; + }); + + // to select just inserted entities we need a criteria to select by. + // for newly inserted entities in drivers which do not support returning statement + // row identifier can only be an increment column + // (since its the only thing that can be generated by those databases) + // or (and) other primary key which is defined by a user and inserted value has it + + const returningResult: any = await this.queryRunner.manager + .createQueryBuilder() + .select(metadata.primaryColumns.map(column => metadata.targetName + "." + column.propertyPath)) + .addSelect(insertionColumns.map(column => metadata.targetName + "." + column.propertyPath)) + .from(metadata.target, metadata.targetName) + .where(entityIds) + .setOption("create-pojo") // use POJO because created object can contain default values, e.g. property = null and those properties maight be overridden by merge process + .getMany(); + + entities.forEach((entity, entityIndex) => { + this.queryRunner.manager.merge(metadata.target as any, generatedMaps[entityIndex], returningResult[entityIndex]); + }); } entities.forEach((entity, entityIndex) => { diff --git a/test/github-issues/6266/entity/Post.ts b/test/github-issues/6266/entity/Post.ts new file mode 100644 index 00000000000..94e6f92ea52 --- /dev/null +++ b/test/github-issues/6266/entity/Post.ts @@ -0,0 +1,14 @@ +import { PrimaryGeneratedColumn, Entity, Column, CreateDateColumn } from "../../../../src"; + +@Entity() +export class Post { + + @PrimaryGeneratedColumn() + id?: number; + + @Column() + title: string; + + @CreateDateColumn() + readonly createdAt?: Date; +} diff --git a/test/github-issues/6266/issue-6266.ts b/test/github-issues/6266/issue-6266.ts new file mode 100644 index 00000000000..8e8a79e9c0e --- /dev/null +++ b/test/github-issues/6266/issue-6266.ts @@ -0,0 +1,60 @@ +import "reflect-metadata"; +import { + closeTestingConnections, + createTestingConnections, + reloadTestingDatabases, +} from "../../utils/test-utils"; +import { Connection } from "../../../src/connection/Connection"; +import { Post } from "./entity/Post"; +import sinon from "sinon"; +import { SelectQueryBuilder } from "../../../src"; +import { assert } from "chai"; + +describe("github issues > #6266 Many identical selects after insert bunch of items", () => { + let connections: Connection[]; + const posts: Post[] = [ + { + title: "Post 1", + }, + { + title: "Post 2", + }, + { + title: "Post 3", + }, + { + title: "Post 4", + }, + ]; + + before( + async () => + (connections = await createTestingConnections({ + entities: [__dirname + "/entity/*{.js,.ts}"], + enabledDrivers: ["mysql"], + })) + ); + beforeEach(() => reloadTestingDatabases(connections)); + after(() => closeTestingConnections(connections)); + + it("should execute a single SELECT to get inserted default and generated values of multiple entities", () => + Promise.all( + connections.map(async (connection) => { + const selectSpy = sinon.spy( + SelectQueryBuilder.prototype, + "select" + ); + + await connection + .createQueryBuilder() + .insert() + .into(Post) + .values(posts) + .execute(); + + assert.strictEqual(selectSpy.calledOnce, true); + + selectSpy.restore(); + }) + )); +}); From 16a2d8023d3ab3682a5f9b777e5723daea7b917c Mon Sep 17 00:00:00 2001 From: ZBAGI Date: Fri, 4 Sep 2020 18:39:00 +0200 Subject: [PATCH 054/212] fix: Child entities not being saved correctly with cascade actions (#6219) * fix: Child entities not being saved correctly with cascade actions * fixes tslint complains --- src/metadata/EntityMetadata.ts | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/metadata/EntityMetadata.ts b/src/metadata/EntityMetadata.ts index 20cb81ad807..3c4a66ae5c3 100644 --- a/src/metadata/EntityMetadata.ts +++ b/src/metadata/EntityMetadata.ts @@ -700,14 +700,21 @@ export class EntityMetadata { relations.forEach(relation => { const value = relation.getEntityValue(entity); if (Array.isArray(value)) { - value.forEach(subValue => relationsAndValues.push([relation, subValue, relation.inverseEntityMetadata])); + value.forEach(subValue => relationsAndValues.push([relation, subValue, this.getInverseEntityMetadata(subValue, relation)])); } else if (value) { - relationsAndValues.push([relation, value, relation.inverseEntityMetadata]); + relationsAndValues.push([relation, value, this.getInverseEntityMetadata(value, relation)]); } }); return relationsAndValues; } + private getInverseEntityMetadata(value: any, relation: RelationMetadata): EntityMetadata { + const childEntityMetadata = relation.inverseEntityMetadata.childEntityMetadatas.find(metadata => + metadata.target === value.constructor + ); + return childEntityMetadata ? childEntityMetadata : relation.inverseEntityMetadata; + } + // ------------------------------------------------------------------------- // Public Static Methods // ------------------------------------------------------------------------- From 23110d164620dd0ee0bd3a63a6a5ba9720ee9d52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Domaga=C5=82a?= Date: Fri, 4 Sep 2020 19:25:01 +0200 Subject: [PATCH 055/212] fix: update query deep partial TypeScript definition (#6085) User should be able to pass function if field is an array --- src/query-builder/QueryPartialEntity.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/query-builder/QueryPartialEntity.ts b/src/query-builder/QueryPartialEntity.ts index 1e6ccfa3017..6889c547e02 100644 --- a/src/query-builder/QueryPartialEntity.ts +++ b/src/query-builder/QueryPartialEntity.ts @@ -11,7 +11,9 @@ export type QueryPartialEntity = { */ export type QueryDeepPartialEntity = { [P in keyof T]?: - T[P] extends Array ? Array> : - T[P] extends ReadonlyArray ? ReadonlyArray> : - QueryDeepPartialEntity | (() => string); + ( + T[P] extends Array ? Array> : + T[P] extends ReadonlyArray ? ReadonlyArray> : + QueryDeepPartialEntity + ) | (() => string); }; From fa21f874a5aed50e9722dfc74ae47e7043ca1d05 Mon Sep 17 00:00:00 2001 From: James Ward Date: Fri, 4 Sep 2020 19:20:54 -0400 Subject: [PATCH 056/212] build: add oracle to CI (#6623) * build: add oracle to build database services * only enable test 1972 for MySQL * disable github issue 3118 for oracle --- .circleci/config.yml | 25 +++++++++++++++++++++++++ docker-compose.yml | 6 ++++++ ormconfig.circleci-common.json | 7 +++++-- package-lock.json | 6 ++++++ package.json | 1 + test/github-issues/1972/issue-1972.ts | 1 + test/github-issues/3118/issue-3118.ts | 1 + 7 files changed, 45 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 9c4526781ef..58256e0dd97 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -51,6 +51,24 @@ commands: if [ ! -d node_modules ]; then npm install fi + - run: + # This is pretty terrible but OracleDB requires you to grab the binaries OOB + # from the normal installation, place them in the LD Path + # also - not super well documented - grab `libaio` as well + # Because this is technically the same image as the runner we'll snag + # the libaio1 and place them in the same instantclient directory. + name: Download Required OracleDB Binaries + command: | + if [ ! -d node_modules/oracledb/instantclient_19_8 ]; then + curl -sf -o node_modules/oracledb/instantclient.zip $BLOB_URL + unzip -qqo node_modules/oracledb/instantclient.zip -d node_modules/oracledb/ + rm node_modules/oracledb/instantclient.zip + + DEBIAN_FRONTEND=noninteractive sudo apt-get -qq -y install libaio1 + cp /lib/*/libaio.so.* node_modules/oracledb/instantclient_19_8/ + fi + environment: + BLOB_URL: https://download.oracle.com/otn_software/linux/instantclient/19800/instantclient-basiclite-linux.x64-19.8.0.0.0dbru.zip - save_cache: name: Save node_modules cache key: node_modules-{{ checksum "package-lock.json" }} @@ -188,3 +206,10 @@ workflows: - build databases: "cockroachdb" node-version: "12" + - test: + name: test (oracle) - Node v12 + requires: + - lint + - build + databases: "oracle" + node-version: "12" diff --git a/docker-compose.yml b/docker-compose.yml index 0ee126dc3f0..47415bce4e6 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -68,6 +68,12 @@ services: ports: - "26257:26257" + oracle: + image: imnotjames/oracle-xe:18 + container_name: "typeorm-oracle" + ports: + - "1521:1521" + # sap hana (works only on linux) # hanaexpress: # image: "store/saplabs/hanaexpress:2.00.040.00.20190729.1" diff --git a/ormconfig.circleci-common.json b/ormconfig.circleci-common.json index ef62fa1ac43..d9f558a78a0 100644 --- a/ormconfig.circleci-common.json +++ b/ormconfig.circleci-common.json @@ -103,9 +103,12 @@ "type": "oracle", "host": "typeorm-oracle", "port": 1521, - "sid": "xe", + "sid": "XE", "username": "system", "password": "oracle", - "logging": false + "logging": false, + "extra": { + "connectString": "typeorm-oracle:1521/XE" + } } ] diff --git a/package-lock.json b/package-lock.json index e100be4b4fb..319bc470aa9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7674,6 +7674,12 @@ "wordwrap": "~1.0.0" } }, + "oracledb": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/oracledb/-/oracledb-5.0.0.tgz", + "integrity": "sha512-NLE3t6KiAkpBHA1/zgjNiKaa9Z4Nnp4PuB3d0b3Kz4C8klrIrMKfHIGUySlwqgDW588m7/2hnPxU7PH6wjBd6g==", + "dev": true + }, "ordered-read-streams": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-1.0.1.tgz", diff --git a/package.json b/package.json index 7890bcf589d..a0c3fbd2a9c 100644 --- a/package.json +++ b/package.json @@ -89,6 +89,7 @@ "mssql": "^4.3.2", "mysql": "^2.15.0", "mysql2": "^1.6.5", + "oracledb": "^5.0.0", "pg": "^8.3.0", "redis": "^2.8.0", "remap-istanbul": "^0.13.0", diff --git a/test/github-issues/1972/issue-1972.ts b/test/github-issues/1972/issue-1972.ts index 0b957b9732d..df65ea747f1 100644 --- a/test/github-issues/1972/issue-1972.ts +++ b/test/github-issues/1972/issue-1972.ts @@ -10,6 +10,7 @@ describe("github issues > #1972 STI problem - empty columns", () => { before(async () => connections = await createTestingConnections({ entities: [__dirname + "/entity/*{.js,.ts}"], + enabledDrivers: ['mysql'] })); beforeEach(() => reloadTestingDatabases(connections)); diff --git a/test/github-issues/3118/issue-3118.ts b/test/github-issues/3118/issue-3118.ts index 001e358e691..de30cc7aa9e 100644 --- a/test/github-issues/3118/issue-3118.ts +++ b/test/github-issues/3118/issue-3118.ts @@ -18,6 +18,7 @@ describe("github issues > #3118 shorten alias names (for RDBMS with a limit) whe let connections: Connection[]; before(async () => connections = await createTestingConnections({ entities: [__dirname + "/entity/*{.js,.ts}"], + enabledDrivers: ["mysql", "postgres", "cockroachdb", "sap", "mariadb", "mssql"] })); beforeEach(() => reloadTestingDatabases(connections)); after(() => closeTestingConnections(connections)); From 802e0f6e8ac1466fea4fb9cbb85ba361c677532c Mon Sep 17 00:00:00 2001 From: James Ward Date: Sat, 5 Sep 2020 10:25:40 -0400 Subject: [PATCH 057/212] test: escape table name for Github #4410 (#6672) --- test/github-issues/4410/issue-4410.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/test/github-issues/4410/issue-4410.ts b/test/github-issues/4410/issue-4410.ts index 86ff3de1d73..cf23b9856ff 100644 --- a/test/github-issues/4410/issue-4410.ts +++ b/test/github-issues/4410/issue-4410.ts @@ -14,7 +14,6 @@ describe("github issues > #4410 allow custom filepath for FileLogger", () => { schemaCreate: true, dropSchema: true, }; - const testQuery = "SELECT COUNT(*) from username;"; before(() => stub = sinon.stub(PlatformTools, "appendFileSync")); beforeEach(() => reloadTestingDatabases(connections)); @@ -29,8 +28,10 @@ describe("github issues > #4410 allow custom filepath for FileLogger", () => { createLogger: () => new FileLogger("all"), }); }); - it("writes to the base path", async () => + it("writes to the base path", async () => Promise.all(connections.map(async (connection) => { + const testQuery = `SELECT COUNT(*) FROM ${connection.driver.escape('username')}`; + await connection.query(testQuery); sinon.assert.calledWith( stub, @@ -51,6 +52,8 @@ describe("github issues > #4410 allow custom filepath for FileLogger", () => { }); it("writes to the given filename", async () => Promise.all(connections.map(async (connection) => { + const testQuery = `SELECT COUNT(*) FROM ${connection.driver.escape('username')}`; + await connection.query(testQuery); sinon.assert.calledWith( stub, @@ -71,6 +74,8 @@ describe("github issues > #4410 allow custom filepath for FileLogger", () => { }); it("writes to the given path", () => Promise.all(connections.map(async (connection) => { + const testQuery = `SELECT COUNT(*) FROM ${connection.driver.escape('username')}`; + await connection.query(testQuery); sinon.assert.calledWith( stub, From 8b8bc353d0ffb38bcf8a2658f64be170f759833c Mon Sep 17 00:00:00 2001 From: Michael Date: Sun, 6 Sep 2020 15:38:35 +0100 Subject: [PATCH 058/212] fix: add missing schema for OracleDriver (#6673) --- src/metadata/EntityMetadata.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/metadata/EntityMetadata.ts b/src/metadata/EntityMetadata.ts index 3c4a66ae5c3..6975928d3e5 100644 --- a/src/metadata/EntityMetadata.ts +++ b/src/metadata/EntityMetadata.ts @@ -6,6 +6,7 @@ import {PostgresDriver} from "../driver/postgres/PostgresDriver"; import {SapDriver} from "../driver/sap/SapDriver"; import {SqlServerConnectionOptions} from "../driver/sqlserver/SqlServerConnectionOptions"; import {SqlServerDriver} from "../driver/sqlserver/SqlServerDriver"; +import {OracleDriver} from "../driver/oracle/OracleDriver"; import {CannotCreateEntityIdMapError} from "../error/CannotCreateEntityIdMapError"; import {OrderByCondition} from "../find-options/OrderByCondition"; import {TableMetadataArgs} from "../metadata-args/TableMetadataArgs"; @@ -709,7 +710,7 @@ export class EntityMetadata { } private getInverseEntityMetadata(value: any, relation: RelationMetadata): EntityMetadata { - const childEntityMetadata = relation.inverseEntityMetadata.childEntityMetadatas.find(metadata => + const childEntityMetadata = relation.inverseEntityMetadata.childEntityMetadatas.find(metadata => metadata.target === value.constructor ); return childEntityMetadata ? childEntityMetadata : relation.inverseEntityMetadata; @@ -848,7 +849,7 @@ export class EntityMetadata { */ protected buildTablePath(): string { let tablePath = this.tableName; - if (this.schema && ((this.connection.driver instanceof PostgresDriver) || (this.connection.driver instanceof SqlServerDriver) || (this.connection.driver instanceof SapDriver))) { + if (this.schema && ((this.connection.driver instanceof OracleDriver) || (this.connection.driver instanceof PostgresDriver) || (this.connection.driver instanceof SqlServerDriver) || (this.connection.driver instanceof SapDriver))) { tablePath = this.schema + "." + tablePath; } From a8b2845d08ff1c896c1124f18d45a52958d98e29 Mon Sep 17 00:00:00 2001 From: Tulio Molina Date: Tue, 8 Sep 2020 09:37:13 -0400 Subject: [PATCH 059/212] docs: update select-query-builder.md (#6681) Found a typo on the "Adding WHERE expression" section: user.firstName is used in the SQL snippet where you actually meant user.id --- docs/select-query-builder.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/select-query-builder.md b/docs/select-query-builder.md index 7e2ca9ad991..ba590c2d398 100644 --- a/docs/select-query-builder.md +++ b/docs/select-query-builder.md @@ -342,7 +342,7 @@ createQueryBuilder("user") Which will produce the following SQL query: ```sql -SELECT ... FROM users user WHERE user.firstName IN (1, 2, 3, 4) +SELECT ... FROM users user WHERE user.id IN (1, 2, 3, 4) ``` From 620a2432ba0deb4e0935604bea1322f847b73ade Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cristian=20Magalh=C3=A3es?= Date: Tue, 8 Sep 2020 10:38:55 -0300 Subject: [PATCH 060/212] docs: update query runner examples (#6680) * refactor: add two examples to use timesteamp when create migration using js/ts * refactor: add two examples to use timesteamp when create migration using js/ts --- docs/migrations.md | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/docs/migrations.md b/docs/migrations.md index 3cbd03f8ecd..7c903aa6dc2 100644 --- a/docs/migrations.md +++ b/docs/migrations.md @@ -87,7 +87,7 @@ typeorm migration:create -n PostRefactoring ``` Here, `PostRefactoring` is the name of the migration - you can specify any name you want. -After you run the command you can see a new file generated in the "migration" directory +After you run the command you can see a new file generated in the "migration" directory named `{TIMESTAMP}-PostRefactoring.ts` where `{TIMESTAMP}` is the current timestamp when the migration was generated. Now you can open the file and add your migration sql queries there. @@ -144,7 +144,7 @@ Once you have a migration to run on production, you can run them using a CLI com typeorm migration:run ``` -**`typeorm migration:create` and `typeorm migration:generate` will create `.ts` files. The `migration:run` and `migration:revert` commands only work on `.js` files. Thus the typescript files need to be compiled before running the commands.** Alternatively you can use `ts-node` in conjunction with `typeorm` to run `.ts` migration files. +**`typeorm migration:create` and `typeorm migration:generate` will create `.ts` files. The `migration:run` and `migration:revert` commands only work on `.js` files. Thus the typescript files need to be compiled before running the commands.** Alternatively you can use `ts-node` in conjunction with `typeorm` to run `.ts` migration files. Example with `ts-node`: ``` @@ -161,8 +161,8 @@ If for some reason you want to revert the changes, you can run: typeorm migration:revert ``` -This command will execute `down` in the latest executed migration. -If you need to revert multiple migrations you must call this command multiple times. +This command will execute `down` in the latest executed migration. +If you need to revert multiple migrations you must call this command multiple times. ## Generating migrations @@ -246,6 +246,11 @@ export class QuestionRefactoringTIMESTAMP implements MigrationInterface { { name: "name", type: "varchar", + }, + { + name: 'created_at', + type: 'timestamp', + default: 'now()' } ] }), true); @@ -383,7 +388,7 @@ Drops database. createSchema(schemaPath: string, ifNotExist?: boolean): Promise ``` -- `schemaPath` - schema name. For SqlServer can accept schema path (e.g. 'dbName.schemaName') as parameter. +- `schemaPath` - schema name. For SqlServer can accept schema path (e.g. 'dbName.schemaName') as parameter. If schema path passed, it will create schema in specified database - `ifNotExist` - skips creation if `true`, otherwise throws error if schema already exist @@ -395,7 +400,7 @@ Creates a new table schema. dropSchema(schemaPath: string, ifExist?: boolean, isCascade?: boolean): Promise ``` -- `schemaPath` - schema name. For SqlServer can accept schema path (e.g. 'dbName.schemaName') as parameter. +- `schemaPath` - schema name. For SqlServer can accept schema path (e.g. 'dbName.schemaName') as parameter. If schema path passed, it will drop schema in specified database - `ifExist` - skips deletion if `true`, otherwise throws error if schema was not found - `isCascade` - If `true`, automatically drop objects (tables, functions, etc.) that are contained in the schema. From 2d4a8d7f48c98bc59ef00b6e4984d35434141182 Mon Sep 17 00:00:00 2001 From: Gareth Parker Date: Tue, 8 Sep 2020 14:39:33 +0100 Subject: [PATCH 061/212] test: Testing that the discriminatorValue gets saved for ChildEntity when saved by cascade (#6671) * test: Testing that the discriminatorValue gets saved for ChildEntity when saved by cascade * test: Update assertions to not be specific to retrieval order Co-authored-by: Gareth Parker --- .../entity/Faculty.ts | 19 +++++++++ .../entity/Professor.ts | 15 +++++++ .../entity/Researcher.ts | 15 +++++++ .../one-to-many-casecade-save/entity/Staff.ts | 17 ++++++++ .../one-to-many-cascade-save.ts | 42 +++++++++++++++++++ 5 files changed, 108 insertions(+) create mode 100644 test/functional/table-inheritance/single-table/relations/one-to-many-casecade-save/entity/Faculty.ts create mode 100644 test/functional/table-inheritance/single-table/relations/one-to-many-casecade-save/entity/Professor.ts create mode 100644 test/functional/table-inheritance/single-table/relations/one-to-many-casecade-save/entity/Researcher.ts create mode 100644 test/functional/table-inheritance/single-table/relations/one-to-many-casecade-save/entity/Staff.ts create mode 100644 test/functional/table-inheritance/single-table/relations/one-to-many-casecade-save/one-to-many-cascade-save.ts diff --git a/test/functional/table-inheritance/single-table/relations/one-to-many-casecade-save/entity/Faculty.ts b/test/functional/table-inheritance/single-table/relations/one-to-many-casecade-save/entity/Faculty.ts new file mode 100644 index 00000000000..2a85a9ef8e5 --- /dev/null +++ b/test/functional/table-inheritance/single-table/relations/one-to-many-casecade-save/entity/Faculty.ts @@ -0,0 +1,19 @@ +import {Column} from "../../../../../../../src/decorator/columns/Column"; +import {Entity} from "../../../../../../../src/decorator/entity/Entity"; +import {PrimaryGeneratedColumn} from "../../../../../../../src/decorator/columns/PrimaryGeneratedColumn"; +import {Staff} from "./Staff"; +import {OneToMany} from "../../../../../../../src"; + +@Entity() +export class Faculty { + + @PrimaryGeneratedColumn() + id: number; + + @Column() + name: string; + + @OneToMany(type => Staff, staff => staff.faculty, { cascade: true, eager: true }) + staff: Staff[]; + +} diff --git a/test/functional/table-inheritance/single-table/relations/one-to-many-casecade-save/entity/Professor.ts b/test/functional/table-inheritance/single-table/relations/one-to-many-casecade-save/entity/Professor.ts new file mode 100644 index 00000000000..82c742be89f --- /dev/null +++ b/test/functional/table-inheritance/single-table/relations/one-to-many-casecade-save/entity/Professor.ts @@ -0,0 +1,15 @@ +import {ChildEntity} from "../../../../../../../src/decorator/entity/ChildEntity"; +import {Staff} from "./Staff"; +import {Column} from "../../../../../../../src"; + +@ChildEntity("PROFESSOR") +export class Professor extends Staff { + + constructor(className: string) { + super(); + this.className = className; + } + + @Column() + className: string; +} diff --git a/test/functional/table-inheritance/single-table/relations/one-to-many-casecade-save/entity/Researcher.ts b/test/functional/table-inheritance/single-table/relations/one-to-many-casecade-save/entity/Researcher.ts new file mode 100644 index 00000000000..c85ff87a3ff --- /dev/null +++ b/test/functional/table-inheritance/single-table/relations/one-to-many-casecade-save/entity/Researcher.ts @@ -0,0 +1,15 @@ +import {ChildEntity} from "../../../../../../../src/decorator/entity/ChildEntity"; +import {Staff} from "./Staff"; +import {Column} from "../../../../../../../src"; + +@ChildEntity("RESEARCHER") +export class Researcher extends Staff { + + constructor(areaOfStudy: string) { + super(); + this.areaOfStudy = areaOfStudy; + } + + @Column() + areaOfStudy: string; +} diff --git a/test/functional/table-inheritance/single-table/relations/one-to-many-casecade-save/entity/Staff.ts b/test/functional/table-inheritance/single-table/relations/one-to-many-casecade-save/entity/Staff.ts new file mode 100644 index 00000000000..191e8ab950b --- /dev/null +++ b/test/functional/table-inheritance/single-table/relations/one-to-many-casecade-save/entity/Staff.ts @@ -0,0 +1,17 @@ +import {Column, Entity, ManyToOne, PrimaryGeneratedColumn, TableInheritance} from "../../../../../../../src"; +import {Faculty} from "./Faculty"; + +@Entity() +@TableInheritance({ column: { name: "type", type: "varchar" } }) +export class Staff { + + @PrimaryGeneratedColumn() + id: number; + + @ManyToOne(type => Faculty, faculty => faculty.staff) + faculty: Faculty; + + @Column() + type: string; + +} diff --git a/test/functional/table-inheritance/single-table/relations/one-to-many-casecade-save/one-to-many-cascade-save.ts b/test/functional/table-inheritance/single-table/relations/one-to-many-casecade-save/one-to-many-cascade-save.ts new file mode 100644 index 00000000000..42d5c8631bc --- /dev/null +++ b/test/functional/table-inheritance/single-table/relations/one-to-many-casecade-save/one-to-many-cascade-save.ts @@ -0,0 +1,42 @@ +import "reflect-metadata"; +import { + closeTestingConnections, + createTestingConnections, + reloadTestingDatabases +} from "../../../../../utils/test-utils"; +import {expect} from "chai"; +import {Connection} from "../../../../../../src/connection/Connection"; +import {Faculty} from "./entity/Faculty"; +import {Professor} from "./entity/Professor"; +import {Researcher} from "./entity/Researcher"; + +describe("table-inheritance > single-table > relations > one-to-many-cascade-save", () => { + + let connections: Connection[]; + before(async () => connections = await createTestingConnections({ + entities: [__dirname + "/entity/*{.js,.ts}"] + })); + beforeEach(() => reloadTestingDatabases(connections)); + after(() => closeTestingConnections(connections)); + + it("should work correctly with OneToMany relations", () => Promise.all(connections.map(async connection => { + + // ------------------------------------------------------------------------- + // Create + // ------------------------------------------------------------------------- + + const researcher = new Researcher("Economics"); + await connection.getRepository(Researcher).save(researcher); + + const faculty1 = new Faculty(); + faculty1.name = "Economics"; + faculty1.staff = [ new Professor("Economics 101"), researcher ]; + await connection.getRepository(Faculty).save(faculty1); + + const loadedFaculty = await connection.getRepository(Faculty).findOne() as Faculty; + + expect(loadedFaculty.staff.find(staff => staff.type === "PROFESSOR")).to.not.be.undefined; + expect(loadedFaculty.staff.find(staff => staff.type === "RESEARCHER")).to.not.be.undefined; + }))); + +}); From ae3cf0efb1bd05418a7c3f0a8249a867d1e19a93 Mon Sep 17 00:00:00 2001 From: Jaan Oras Date: Tue, 8 Sep 2020 17:31:12 +0300 Subject: [PATCH 062/212] fix: handle 'error' events from pool connection (#6262) --- src/driver/postgres/PostgresQueryRunner.ts | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/driver/postgres/PostgresQueryRunner.ts b/src/driver/postgres/PostgresQueryRunner.ts index e4ce86a8b2e..e0ff11ebb5a 100644 --- a/src/driver/postgres/PostgresQueryRunner.ts +++ b/src/driver/postgres/PostgresQueryRunner.ts @@ -102,10 +102,14 @@ export class PostgresQueryRunner extends BaseQueryRunner implements QueryRunner * Releases used database connection. * You cannot use query runner methods once its released. */ - release(): Promise { + release(err?: any): Promise { + if (this.isReleased) { + return Promise.resolve(); + } + this.isReleased = true; if (this.releaseCallback) - this.releaseCallback(); + this.releaseCallback(err); const index = this.driver.connectedQueryRunners.indexOf(this); if (index !== -1) this.driver.connectedQueryRunners.splice(index); @@ -164,7 +168,13 @@ export class PostgresQueryRunner extends BaseQueryRunner implements QueryRunner this.driver.connection.logger.logQuery(query, parameters, this); const queryStartTime = +new Date(); + const onError = (err: any) => { + this.release(err); + }; + databaseConnection.once("error", onError); + databaseConnection.query(query, parameters, (err: any, result: any) => { + databaseConnection.removeListener("error", onError); // log slow queries if maxQueryExecution time is set const maxQueryExecutionTime = this.driver.connection.options.maxQueryExecutionTime; From 7ddaf23e4794f463e67691cd30bde10b963f8d7c Mon Sep 17 00:00:00 2001 From: Michael Bromley Date: Thu, 10 Sep 2020 09:21:19 +0200 Subject: [PATCH 063/212] fix: unnecessary migrations for unsigned numeric types (#6632) * fix: Unnecessary migrations for unsigned numeric types In MariaDB, unsigned numeric types (``int`) without an explicit `width` property set would generate migrations on every run. This is due to an error in setting the default width for unsigned types. Fixes #2943 * test: Enable all tests * refactor: Move isDefaultColumnWidth() method out of BaseQueryRunner See https://github.com/typeorm/typeorm/pull/6632#pullrequestreview-480932808 for discussion as to why. * fix: Correct unsigned int behaviour for MySQL 5.7 * fix: Correct position of zerofill check Plus stylistic change based on code review --- .../AuroraDataApiQueryRunner.ts | 22 ++++++++++++ src/driver/mysql/MysqlQueryRunner.ts | 35 +++++++++++++++++-- src/query-runner/BaseQueryRunner.ts | 21 ----------- test/github-issues/2943/entity/Test.ts | 22 ++++++++++++ test/github-issues/2943/issue-2943.ts | 29 +++++++++++++++ 5 files changed, 106 insertions(+), 23 deletions(-) create mode 100644 test/github-issues/2943/entity/Test.ts create mode 100644 test/github-issues/2943/issue-2943.ts diff --git a/src/driver/aurora-data-api/AuroraDataApiQueryRunner.ts b/src/driver/aurora-data-api/AuroraDataApiQueryRunner.ts index a9df895eba7..14d3d68bab0 100644 --- a/src/driver/aurora-data-api/AuroraDataApiQueryRunner.ts +++ b/src/driver/aurora-data-api/AuroraDataApiQueryRunner.ts @@ -1623,4 +1623,26 @@ export class AuroraDataApiQueryRunner extends BaseQueryRunner implements QueryRu return c; } + /** + * Checks if column display width is by default. + */ + protected isDefaultColumnWidth(table: Table, column: TableColumn, width: number): boolean { + // if table have metadata, we check if length is specified in column metadata + if (this.connection.hasMetadata(table.name)) { + const metadata = this.connection.getMetadata(table.name); + const columnMetadata = metadata.findColumnWithDatabaseName(column.name); + if (columnMetadata && columnMetadata.width) + return false; + } + + const defaultWidthForType = this.connection.driver.dataTypeDefaults + && this.connection.driver.dataTypeDefaults[column.type] + && this.connection.driver.dataTypeDefaults[column.type].width; + + if (defaultWidthForType) { + return defaultWidthForType === width; + } + return false; + } + } diff --git a/src/driver/mysql/MysqlQueryRunner.ts b/src/driver/mysql/MysqlQueryRunner.ts index 0a2b439f2d4..4eff8332fac 100644 --- a/src/driver/mysql/MysqlQueryRunner.ts +++ b/src/driver/mysql/MysqlQueryRunner.ts @@ -1296,6 +1296,8 @@ export class MysqlQueryRunner extends BaseQueryRunner implements QueryRunner { tableColumn.name = dbColumn["COLUMN_NAME"]; tableColumn.type = dbColumn["DATA_TYPE"].toLowerCase(); + tableColumn.zerofill = dbColumn["COLUMN_TYPE"].indexOf("zerofill") !== -1; + tableColumn.unsigned = tableColumn.zerofill ? true : dbColumn["COLUMN_TYPE"].indexOf("unsigned") !== -1; if (this.driver.withWidthColumnTypes.indexOf(tableColumn.type as ColumnType) !== -1) { const width = dbColumn["COLUMN_TYPE"].substring(dbColumn["COLUMN_TYPE"].indexOf("(") + 1, dbColumn["COLUMN_TYPE"].indexOf(")")); tableColumn.width = width && !this.isDefaultColumnWidth(table, tableColumn, parseInt(width)) ? parseInt(width) : undefined; @@ -1332,8 +1334,6 @@ export class MysqlQueryRunner extends BaseQueryRunner implements QueryRunner { tableColumn.isPrimary = dbPrimaryKeys.some(dbPrimaryKey => { return this.driver.buildTableName(dbPrimaryKey["TABLE_NAME"], undefined, dbPrimaryKey["TABLE_SCHEMA"]) === tableFullName && dbPrimaryKey["COLUMN_NAME"] === tableColumn.name; }); - tableColumn.zerofill = dbColumn["COLUMN_TYPE"].indexOf("zerofill") !== -1; - tableColumn.unsigned = tableColumn.zerofill ? true : dbColumn["COLUMN_TYPE"].indexOf("unsigned") !== -1; tableColumn.isGenerated = dbColumn["EXTRA"].indexOf("auto_increment") !== -1; if (tableColumn.isGenerated) tableColumn.generationStrategy = "increment"; @@ -1694,4 +1694,35 @@ export class MysqlQueryRunner extends BaseQueryRunner implements QueryRunner { return result[0]["version"]; } + /** + * Checks if column display width is by default. + */ + protected isDefaultColumnWidth(table: Table, column: TableColumn, width: number): boolean { + // if table have metadata, we check if length is specified in column metadata + if (this.connection.hasMetadata(table.name)) { + const metadata = this.connection.getMetadata(table.name); + const columnMetadata = metadata.findColumnWithDatabaseName(column.name); + if (columnMetadata && columnMetadata.width) + return false; + } + + const defaultWidthForType = this.connection.driver.dataTypeDefaults + && this.connection.driver.dataTypeDefaults[column.type] + && this.connection.driver.dataTypeDefaults[column.type].width; + + if (defaultWidthForType) { + // In MariaDB & MySQL 5.7, the default widths of certain numeric types are 1 less than + // the usual defaults when the column is unsigned. + const typesWithReducedUnsignedDefault = ["int", "tinyint", "smallint", "mediumint"]; + const needsAdjustment = typesWithReducedUnsignedDefault.indexOf(column.type) !== -1; + if (column.unsigned && needsAdjustment) { + return (defaultWidthForType - 1) === width; + } else { + return defaultWidthForType === width; + } + } + + return false; + } + } diff --git a/src/query-runner/BaseQueryRunner.ts b/src/query-runner/BaseQueryRunner.ts index fefb2e05a2e..7ab8ebf1feb 100644 --- a/src/query-runner/BaseQueryRunner.ts +++ b/src/query-runner/BaseQueryRunner.ts @@ -312,27 +312,6 @@ export abstract class BaseQueryRunner { return false; } - /** - * Checks if column display width is by default. Used only for MySQL. - */ - protected isDefaultColumnWidth(table: Table, column: TableColumn, width: number): boolean { - // if table have metadata, we check if length is specified in column metadata - if (this.connection.hasMetadata(table.name)) { - const metadata = this.connection.getMetadata(table.name); - const columnMetadata = metadata.findColumnWithDatabaseName(column.name); - if (columnMetadata && columnMetadata.width) - return false; - } - - if (this.connection.driver.dataTypeDefaults - && this.connection.driver.dataTypeDefaults[column.type] - && this.connection.driver.dataTypeDefaults[column.type].width) { - return this.connection.driver.dataTypeDefaults[column.type].width === width; - } - - return false; - } - /** * Checks if column precision is by default. */ diff --git a/test/github-issues/2943/entity/Test.ts b/test/github-issues/2943/entity/Test.ts new file mode 100644 index 00000000000..9055aa93b11 --- /dev/null +++ b/test/github-issues/2943/entity/Test.ts @@ -0,0 +1,22 @@ +import { Column, Entity, PrimaryColumn } from "../../../../src"; + +@Entity() +export class Test { + @PrimaryColumn() + id: number; + + @Column({ type: 'int', unsigned: true}) + uInt: number; + + @Column({ type: 'tinyint', unsigned: true}) + uTinyInt: number; + + @Column({ type: 'smallint', unsigned: true}) + uSmallInt: number; + + @Column({ type: 'mediumint', unsigned: true}) + uMediumInt: number; + + @Column({ type: 'bigint', unsigned: true}) + uBigInt: number; +} diff --git a/test/github-issues/2943/issue-2943.ts b/test/github-issues/2943/issue-2943.ts new file mode 100644 index 00000000000..5fee6e77542 --- /dev/null +++ b/test/github-issues/2943/issue-2943.ts @@ -0,0 +1,29 @@ +import "reflect-metadata"; +import { expect } from "chai"; +import { Connection } from "../../../src"; +import { closeTestingConnections, createTestingConnections, reloadTestingDatabases } from "../../utils/test-utils"; +import { Test } from "./entity/Test"; + +describe("github issues > #2943 Inappropriate migration generated", () => { + + let connections: Connection[]; + + before(async () => { + connections = await createTestingConnections({ + enabledDrivers: ['mariadb', 'mysql'], + entities: [Test], + schemaCreate: true, + dropSchema: true + }); + }); + beforeEach(() => reloadTestingDatabases(connections)); + after(() => closeTestingConnections(connections)); + + it("should not create migrations for unsigned numeric types with no specified width", () => + Promise.all(connections.map(async (connection) => { + const sqlInMemory = await connection.driver.createSchemaBuilder().log(); + + expect(sqlInMemory.upQueries).to.eql([]); + expect(sqlInMemory.downQueries).to.eql([]); + }))); +}); From 716790322908cb377c1eb552ed2604cc84c4afe0 Mon Sep 17 00:00:00 2001 From: Umed Khudoiberdiev Date: Thu, 10 Sep 2020 12:30:30 +0500 Subject: [PATCH 064/212] version bump --- CHANGELOG.md | 41 +++++++++++++++++++++++++++++++++++++++++ package-lock.json | 16 ++++++++-------- package.json | 2 +- 3 files changed, 50 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ba22f7e6801..676a6c4ec15 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,44 @@ +## [0.2.26](https://github.com/typeorm/typeorm/compare/0.2.25...0.2.26) (2020-09-10) + +### Bug Fixes + +* @JoinTable does not respect inverseJoinColumns referenced column width ([#6444](https://github.com/typeorm/typeorm/issues/6444)) ([f642a9e](https://github.com/typeorm/typeorm/commit/f642a9e)), closes [#6442](https://github.com/typeorm/typeorm/issues/6442) +* add missing schema for OracleDriver ([#6673](https://github.com/typeorm/typeorm/issues/6673)) ([8b8bc35](https://github.com/typeorm/typeorm/commit/8b8bc35)) +* change InsertQueryBuilder.values() with an empty array into a no-op ([#6584](https://github.com/typeorm/typeorm/issues/6584)) ([9d2df28](https://github.com/typeorm/typeorm/commit/9d2df28)), closes [#3111](https://github.com/typeorm/typeorm/issues/3111) +* Child entities not being saved correctly with cascade actions ([#6219](https://github.com/typeorm/typeorm/issues/6219)) ([16a2d80](https://github.com/typeorm/typeorm/commit/16a2d80)) +* correctly parse connection URI with query params ([#6390](https://github.com/typeorm/typeorm/issues/6390)) ([54a3a15](https://github.com/typeorm/typeorm/commit/54a3a15)), closes [#6389](https://github.com/typeorm/typeorm/issues/6389) +* decorators should implement the official TypeScript interface ([#6398](https://github.com/typeorm/typeorm/issues/6398)) ([c23c888](https://github.com/typeorm/typeorm/commit/c23c888)), closes [#5922](https://github.com/typeorm/typeorm/issues/5922) +* DeepPartial with any and {[k: string]: any} ([#6581](https://github.com/typeorm/typeorm/issues/6581)) ([8d90d40](https://github.com/typeorm/typeorm/commit/8d90d40)), closes [#6580](https://github.com/typeorm/typeorm/issues/6580) [#6580](https://github.com/typeorm/typeorm/issues/6580) +* exporting missing load event ([#6396](https://github.com/typeorm/typeorm/issues/6396)) ([c6336aa](https://github.com/typeorm/typeorm/commit/c6336aa)) +* get correct insert ids for multiple entities inserted ([#6668](https://github.com/typeorm/typeorm/issues/6668)) ([ef2011d](https://github.com/typeorm/typeorm/commit/ef2011d)), closes [#2131](https://github.com/typeorm/typeorm/issues/2131) [#5973](https://github.com/typeorm/typeorm/issues/5973) [#2131](https://github.com/typeorm/typeorm/issues/2131) +* getPendingMigrations isn't properly working ([#6372](https://github.com/typeorm/typeorm/issues/6372)) ([7c0da1c](https://github.com/typeorm/typeorm/commit/7c0da1c)) +* handle 'error' events from pool connection ([#6262](https://github.com/typeorm/typeorm/issues/6262)) ([ae3cf0e](https://github.com/typeorm/typeorm/commit/ae3cf0e)) +* insert IN(null) instead of IN() when In([]) empty array for mysqlDriver ([#6237](https://github.com/typeorm/typeorm/issues/6237)) ([6f6bdbd](https://github.com/typeorm/typeorm/commit/6f6bdbd)) +* make only a single SELECT to get inserted default and generated values of multiple entities ([#6669](https://github.com/typeorm/typeorm/issues/6669)) ([4fc4a1b](https://github.com/typeorm/typeorm/commit/4fc4a1b)), closes [#6266](https://github.com/typeorm/typeorm/issues/6266) [#6266](https://github.com/typeorm/typeorm/issues/6266) +* Migration issues with scale & precision in sqlite/sql.js ([#6638](https://github.com/typeorm/typeorm/issues/6638)) ([0397e44](https://github.com/typeorm/typeorm/commit/0397e44)), closes [#6636](https://github.com/typeorm/typeorm/issues/6636) +* mysql migration: make sure the indices sql which left-join be the same database ([#6426](https://github.com/typeorm/typeorm/issues/6426)) ([906d97f](https://github.com/typeorm/typeorm/commit/906d97f)) +* pass `ids_` to alias builder to prevent length overflow ([#6624](https://github.com/typeorm/typeorm/issues/6624)) ([cf3ad62](https://github.com/typeorm/typeorm/commit/cf3ad62)) +* pass formatOptions to Data API Client, fix extensions ([#6404](https://github.com/typeorm/typeorm/issues/6404)) ([9abab82](https://github.com/typeorm/typeorm/commit/9abab82)), closes [#1](https://github.com/typeorm/typeorm/issues/1) +* Query builder makes query with joins, without limit for inherited entities ([#6402](https://github.com/typeorm/typeorm/issues/6402)) ([874e573](https://github.com/typeorm/typeorm/commit/874e573)), closes [#6399](https://github.com/typeorm/typeorm/issues/6399) +* remove unnecessary optionality from Raw operator's columnAlias argument ([#6321](https://github.com/typeorm/typeorm/issues/6321)) ([0d99b46](https://github.com/typeorm/typeorm/commit/0d99b46)) +* resolve missing decorators on shim ([#6354](https://github.com/typeorm/typeorm/issues/6354)) ([8e2d97d](https://github.com/typeorm/typeorm/commit/8e2d97d)), closes [#6093](https://github.com/typeorm/typeorm/issues/6093) +* revert fix handle URL objects as column field values ([#6145](https://github.com/typeorm/typeorm/issues/6145)) ([e073e02](https://github.com/typeorm/typeorm/commit/e073e02)) +* SqlQueryRunner.hasColumn was not working ([#6146](https://github.com/typeorm/typeorm/issues/6146)) ([a595fed](https://github.com/typeorm/typeorm/commit/a595fed)), closes [#5718](https://github.com/typeorm/typeorm/issues/5718) +* support multiple `JoinColumn`s in EntitySchema ([#6397](https://github.com/typeorm/typeorm/issues/6397)) ([298a3b9](https://github.com/typeorm/typeorm/commit/298a3b9)), closes [#5444](https://github.com/typeorm/typeorm/issues/5444) +* Unnecessary migrations for fulltext indices ([#6634](https://github.com/typeorm/typeorm/issues/6634)) ([c81b405](https://github.com/typeorm/typeorm/commit/c81b405)), closes [#6633](https://github.com/typeorm/typeorm/issues/6633) +* unnecessary migrations for unsigned numeric types ([#6632](https://github.com/typeorm/typeorm/issues/6632)) ([7ddaf23](https://github.com/typeorm/typeorm/commit/7ddaf23)), closes [#2943](https://github.com/typeorm/typeorm/issues/2943) [/github.com/typeorm/typeorm/pull/6632#pullrequestreview-480932808](https://github.com//github.com/typeorm/typeorm/pull/6632/issues/pullrequestreview-480932808) +* update query deep partial TypeScript definition ([#6085](https://github.com/typeorm/typeorm/issues/6085)) ([23110d1](https://github.com/typeorm/typeorm/commit/23110d1)) + +### Features + +* add AWS configurationOptions to aurora-data-api-pg connector ([#6106](https://github.com/typeorm/typeorm/issues/6106)) ([203f51d](https://github.com/typeorm/typeorm/commit/203f51d)) +* add better-sqlite3 driver ([#6224](https://github.com/typeorm/typeorm/issues/6224)) ([2241451](https://github.com/typeorm/typeorm/commit/2241451)) +* add postgres connection timeout option ([#6160](https://github.com/typeorm/typeorm/issues/6160)) ([0072149](https://github.com/typeorm/typeorm/commit/0072149)) +* FileLogger accepts custom file path ([#6642](https://github.com/typeorm/typeorm/issues/6642)) ([c99ba40](https://github.com/typeorm/typeorm/commit/c99ba40)), closes [#4410](https://github.com/typeorm/typeorm/issues/4410) +* implement postgres ltree ([#6480](https://github.com/typeorm/typeorm/issues/6480)) ([43a7386](https://github.com/typeorm/typeorm/commit/43a7386)), closes [#4193](https://github.com/typeorm/typeorm/issues/4193) +* support absolute paths in migrationsDir for the CLI ([#6660](https://github.com/typeorm/typeorm/issues/6660)) ([2b5f139](https://github.com/typeorm/typeorm/commit/2b5f139)) +* support cjs extension for ormconfig ([#6285](https://github.com/typeorm/typeorm/issues/6285)) ([6eeb03a](https://github.com/typeorm/typeorm/commit/6eeb03a)) + ## [0.2.25](https://github.com/typeorm/typeorm/compare/0.2.24...0.2.25) (2020-05-19) ### Bug Fixes diff --git a/package-lock.json b/package-lock.json index 319bc470aa9..7284fa67be7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "typeorm", - "version": "0.2.25", + "version": "0.2.26", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -4443,7 +4443,7 @@ }, "os-locale": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", + "resolved": "http://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", "dev": true, "requires": { @@ -5549,7 +5549,7 @@ }, "is-accessor-descriptor": { "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "resolved": "http://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", "dev": true, "requires": { @@ -5614,7 +5614,7 @@ }, "is-data-descriptor": { "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "resolved": "http://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", "dev": true, "requires": { @@ -6351,7 +6351,7 @@ }, "load-json-file": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", "dev": true, "requires": { @@ -6364,7 +6364,7 @@ "dependencies": { "pify": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", "dev": true } @@ -7908,7 +7908,7 @@ "dependencies": { "pify": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", "dev": true } @@ -9258,7 +9258,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { diff --git a/package.json b/package.json index a0c3fbd2a9c..a09c349c663 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "typeorm", "private": true, - "version": "0.2.25", + "version": "0.2.26", "description": "Data-Mapper ORM for TypeScript, ES7, ES6, ES5. Supports MySQL, PostgreSQL, MariaDB, SQLite, MS SQL Server, Oracle, MongoDB databases.", "license": "MIT", "readmeFilename": "README.md", From ea59b8d46b2a36ac251f43c8a8fb98ff15ab4e2d Mon Sep 17 00:00:00 2001 From: James Ward Date: Fri, 11 Sep 2020 09:34:58 -0400 Subject: [PATCH 065/212] fix: sql.js v1.2+ don't support undefined parameters (#6698) before sql.js 1.2 it seems undefined were treated as if they were null, but as of 1.2 they cause a query error & fail to execute this change swaps out any undefined parameters with `null`s closes #5720 --- package-lock.json | 6 +++--- package.json | 2 +- src/driver/sqljs/SqljsQueryRunner.ts | 2 ++ 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7284fa67be7..d0a7186083e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9149,9 +9149,9 @@ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" }, "sql.js": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/sql.js/-/sql.js-1.0.0.tgz", - "integrity": "sha512-fl/cQu8hDbu9bXNXTrmwwtS2wvHttWrXS9fzINVtedOBOJJWMjwSADR1aQ+DKmCdGNF4jrg/15AedJ5kcrWRJA==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/sql.js/-/sql.js-1.3.0.tgz", + "integrity": "sha512-bxrJ/9rqJ2SA6hpHnSodRjKBugZHewRvNTITTt74W1VZWmzODjdS68yQW0/J9oC0NWKylHEtV1ptkoTyOYO4Tw==", "dev": true }, "sqlite3": { diff --git a/package.json b/package.json index a09c349c663..aa38595f43b 100644 --- a/package.json +++ b/package.json @@ -97,7 +97,7 @@ "sinon": "^7.2.5", "sinon-chai": "^3.3.0", "source-map-support": "^0.5.10", - "sql.js": "^1.0.0", + "sql.js": "^1.3.0", "sqlite3": "^4.0.9", "ts-node": "^8.0.2", "typeorm-aurora-data-api-driver": "^1.3.0", diff --git a/src/driver/sqljs/SqljsQueryRunner.ts b/src/driver/sqljs/SqljsQueryRunner.ts index 51a38ea0dcb..69a6349c476 100644 --- a/src/driver/sqljs/SqljsQueryRunner.ts +++ b/src/driver/sqljs/SqljsQueryRunner.ts @@ -53,6 +53,8 @@ export class SqljsQueryRunner extends AbstractSqliteQueryRunner { try { statement = databaseConnection.prepare(query); if (parameters) { + parameters = parameters.map(p => typeof p !== 'undefined' ? p : null); + statement.bind(parameters); } From 9583430e8282d1ad758724957971a5d5d9664f63 Mon Sep 17 00:00:00 2001 From: James Ward Date: Fri, 11 Sep 2020 09:36:57 -0400 Subject: [PATCH 066/212] fix: hdb-pool is not namespaced under @sap (#6700) closes #6697 --- src/platform/PlatformTools.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/platform/PlatformTools.ts b/src/platform/PlatformTools.ts index 0821a63c7d4..1adb9042993 100644 --- a/src/platform/PlatformTools.ts +++ b/src/platform/PlatformTools.ts @@ -51,7 +51,7 @@ export class PlatformTools { case "@sap/hana-client": return require("@sap/hana-client"); - case "@sap/hdb-pool": + case "hdb-pool": return require("hdb-pool"); /** From 8b68f40a01b6cdc0e8d21492d988fe21cbef64de Mon Sep 17 00:00:00 2001 From: James Ward Date: Fri, 11 Sep 2020 09:39:37 -0400 Subject: [PATCH 067/212] feat: create EntityTarget and use instead of EntitySchema / ObjectType / etc (#6701) --- src/common/EntityTarget.ts | 11 + src/connection/Connection.ts | 21 +- src/entity-manager/EntityManager.ts | 392 +++--------------- src/entity-manager/MongoEntityManager.ts | 92 ++-- src/error/EntityMetadataNotFoundError.ts | 7 +- src/error/EntityNotFoundError.ts | 6 +- src/error/RepositoryNotFoundError.ts | 7 +- src/error/RepositoryNotTreeError.ts | 17 +- src/index.ts | 11 +- .../EntityRepositoryMetadataArgs.ts | 4 +- src/query-builder/DeleteQueryBuilder.ts | 4 +- src/query-builder/InsertQueryBuilder.ts | 4 +- src/query-builder/QueryBuilder.ts | 52 +-- src/query-builder/SelectQueryBuilder.ts | 10 +- src/query-builder/SoftDeleteQueryBuilder.ts | 4 +- src/repository/AbstractRepository.ts | 6 +- src/repository/Repository.ts | 6 +- 17 files changed, 199 insertions(+), 455 deletions(-) create mode 100644 src/common/EntityTarget.ts diff --git a/src/common/EntityTarget.ts b/src/common/EntityTarget.ts new file mode 100644 index 00000000000..6ee00dd1be0 --- /dev/null +++ b/src/common/EntityTarget.ts @@ -0,0 +1,11 @@ +import {ObjectType} from "./ObjectType"; +import {EntitySchema} from ".."; + +/** + * Entity target. + */ +export type EntityTarget = + | ObjectType + | EntitySchema + | string + | { type: Entity, name: string }; diff --git a/src/connection/Connection.ts b/src/connection/Connection.ts index 1ddb8ff7b58..3f7ba32706d 100644 --- a/src/connection/Connection.ts +++ b/src/connection/Connection.ts @@ -1,6 +1,7 @@ import {Driver} from "../driver/Driver"; import {Repository} from "../repository/Repository"; import {EntitySubscriberInterface} from "../subscriber/EntitySubscriberInterface"; +import {EntityTarget} from "../common/EntityTarget"; import {ObjectType} from "../common/ObjectType"; import {EntityManager} from "../entity-manager/EntityManager"; import {DefaultNamingStrategy} from "../naming-strategy/DefaultNamingStrategy"; @@ -320,14 +321,14 @@ export class Connection { /** * Checks if entity metadata exist for the given entity class, target name or table name. */ - hasMetadata(target: Function|EntitySchema|string): boolean { + hasMetadata(target: EntityTarget): boolean { return !!this.findMetadata(target); } /** * Gets entity metadata for the given entity class or schema name. */ - getMetadata(target: Function|EntitySchema|string): EntityMetadata { + getMetadata(target: EntityTarget): EntityMetadata { const metadata = this.findMetadata(target); if (!metadata) throw new EntityMetadataNotFoundError(target); @@ -338,7 +339,7 @@ export class Connection { /** * Gets repository for the given entity. */ - getRepository(target: ObjectType|EntitySchema|string): Repository { + getRepository(target: EntityTarget): Repository { return this.manager.getRepository(target); } @@ -346,7 +347,7 @@ export class Connection { * Gets tree repository for the given entity class or name. * Only tree-type entities can have a TreeRepository, like ones decorated with @Tree decorator. */ - getTreeRepository(target: ObjectType|EntitySchema|string): TreeRepository { + getTreeRepository(target: EntityTarget): TreeRepository { return this.manager.getTreeRepository(target); } @@ -354,7 +355,7 @@ export class Connection { * Gets mongodb-specific repository for the given entity class or name. * Works only if connection is mongodb-specific. */ - getMongoRepository(target: ObjectType|EntitySchema|string): MongoRepository { + getMongoRepository(target: EntityTarget): MongoRepository { if (!(this.driver instanceof MongoDriver)) throw new Error(`You can use getMongoRepository only for MongoDB connections.`); @@ -408,7 +409,7 @@ export class Connection { /** * Creates a new query builder that can be used to build a sql query. */ - createQueryBuilder(entityClass: ObjectType|EntitySchema|Function|string, alias: string, queryRunner?: QueryRunner): SelectQueryBuilder; + createQueryBuilder(entityClass: EntityTarget, alias: string, queryRunner?: QueryRunner): SelectQueryBuilder; /** * Creates a new query builder that can be used to build a sql query. @@ -418,12 +419,12 @@ export class Connection { /** * Creates a new query builder that can be used to build a sql query. */ - createQueryBuilder(entityOrRunner?: ObjectType|EntitySchema|Function|string|QueryRunner, alias?: string, queryRunner?: QueryRunner): SelectQueryBuilder { + createQueryBuilder(entityOrRunner?: EntityTarget|QueryRunner, alias?: string, queryRunner?: QueryRunner): SelectQueryBuilder { if (this instanceof MongoEntityManager) throw new Error(`Query Builder is not supported by MongoDB.`); if (alias) { - const metadata = this.getMetadata(entityOrRunner as Function|EntitySchema|string); + const metadata = this.getMetadata(entityOrRunner as EntityTarget); return new SelectQueryBuilder(this, queryRunner) .select(alias) .from(metadata.target, alias); @@ -453,7 +454,7 @@ export class Connection { /** * Gets entity metadata of the junction table (many-to-many table). */ - getManyToManyMetadata(entityTarget: Function|string, relationPropertyPath: string) { + getManyToManyMetadata(entityTarget: EntityTarget, relationPropertyPath: string) { const relationMetadata = this.getMetadata(entityTarget).findRelationWithPropertyPath(relationPropertyPath); if (!relationMetadata) throw new Error(`Relation "${relationPropertyPath}" was not found in ${entityTarget} entity.`); @@ -478,7 +479,7 @@ export class Connection { /** * Finds exist entity metadata by the given entity class, target name or table name. */ - protected findMetadata(target: Function|EntitySchema|string): EntityMetadata|undefined { + protected findMetadata(target: EntityTarget): EntityMetadata|undefined { return this.entityMetadatas.find(metadata => { if (metadata.target === target) return true; diff --git a/src/entity-manager/EntityManager.ts b/src/entity-manager/EntityManager.ts index 5ed47b36902..1d214757ecc 100644 --- a/src/entity-manager/EntityManager.ts +++ b/src/entity-manager/EntityManager.ts @@ -1,5 +1,6 @@ import {Connection} from "../connection/Connection"; import {FindManyOptions} from "../find-options/FindManyOptions"; +import {EntityTarget} from "../common/EntityTarget"; import {ObjectType} from "../common/ObjectType"; import {EntityNotFoundError} from "../error/EntityNotFoundError"; import {QueryRunnerProviderAlreadyReleasedError} from "../error/QueryRunnerProviderAlreadyReleasedError"; @@ -161,17 +162,7 @@ export class EntityManager { /** * Creates a new query builder that can be used to build a sql query. */ - createQueryBuilder(entityClass: ObjectType, alias: string, queryRunner?: QueryRunner): SelectQueryBuilder; - - /** - * Creates a new query builder that can be used to build a sql query. - */ - createQueryBuilder(entityClass: EntitySchema, alias: string, queryRunner?: QueryRunner): SelectQueryBuilder; - - /** - * Creates a new query builder that can be used to build a sql query. - */ - createQueryBuilder(entityName: string, alias: string, queryRunner?: QueryRunner): SelectQueryBuilder; + createQueryBuilder(entityClass: EntityTarget, alias: string, queryRunner?: QueryRunner): SelectQueryBuilder; /** * Creates a new query builder that can be used to build a sql query. @@ -181,9 +172,9 @@ export class EntityManager { /** * Creates a new query builder that can be used to build a sql query. */ - createQueryBuilder(entityClass?: ObjectType|EntitySchema|string|QueryRunner, alias?: string, queryRunner?: QueryRunner): SelectQueryBuilder { + createQueryBuilder(entityClass?: EntityTarget|QueryRunner, alias?: string, queryRunner?: QueryRunner): SelectQueryBuilder { if (alias) { - return this.connection.createQueryBuilder(entityClass as EntitySchema|string, alias, queryRunner || this.queryRunner); + return this.connection.createQueryBuilder(entityClass as EntityTarget, alias, queryRunner || this.queryRunner); } else { return this.connection.createQueryBuilder(entityClass as QueryRunner|undefined || queryRunner || this.queryRunner); @@ -218,12 +209,12 @@ export class EntityManager { /** * Gets entity mixed id. */ - getId(target: Function|string, entity: any): any; + getId(target: EntityTarget, entity: any): any; /** * Gets entity mixed id. */ - getId(targetOrEntity: any|Function|string, maybeEntity?: any): any { + getId(targetOrEntity: any|EntityTarget, maybeEntity?: any): any { const target = arguments.length === 2 ? targetOrEntity : targetOrEntity.constructor; const entity = arguments.length === 2 ? maybeEntity : targetOrEntity; const metadata = this.connection.getMetadata(target); @@ -234,43 +225,19 @@ export class EntityManager { * Creates a new entity instance and copies all entity properties from this object into a new entity. * Note that it copies only properties that present in entity schema. */ - create(entityClass: ObjectType, plainObject?: DeepPartial): Entity; + create(entityClass: EntityTarget, plainObject?: DeepPartial): Entity; /** * Creates a new entities and copies all entity properties from given objects into their new entities. * Note that it copies only properties that present in entity schema. */ - create(entityClass: ObjectType, plainObjects?: DeepPartial[]): Entity[]; - - /** - * Creates a new entity instance and copies all entity properties from this object into a new entity. - * Note that it copies only properties that present in entity schema. - */ - create(entitySchema: EntitySchema, plainObject?: DeepPartial): Entity; - - /** - * Creates a new entities and copies all entity properties from given objects into their new entities. - * Note that it copies only properties that present in entity schema. - */ - create(entitySchema: EntitySchema, plainObjects?: DeepPartial[]): Entity[]; - - /** - * Creates a new entity instance and copies all entity properties from this object into a new entity. - * Note that it copies only properties that present in entity schema. - */ - create(entityName: string, plainObject?: DeepPartial): Entity; - - /** - * Creates a new entities and copies all entity properties from given objects into their new entities. - * Note that it copies only properties that present in entity schema. - */ - create(entityName: string, plainObjects?: DeepPartial[]): Entity[]; + create(entityClass: EntityTarget, plainObjects?: DeepPartial[]): Entity[]; /** * Creates a new entity instance or instances. * Can copy properties from the given object into new entities. */ - create(entityClass: ObjectType|EntitySchema|string, plainObjectOrObjects?: DeepPartial|DeepPartial[]): Entity|Entity[] { + create(entityClass: EntityTarget, plainObjectOrObjects?: DeepPartial|DeepPartial[]): Entity|Entity[] { const metadata = this.connection.getMetadata(entityClass); if (!plainObjectOrObjects) @@ -287,22 +254,7 @@ export class EntityManager { /** * Merges two entities into one new entity. */ - merge(entityClass: ObjectType, mergeIntoEntity: Entity, ...entityLikes: DeepPartial[]): Entity; - - /** - * Merges two entities into one new entity. - */ - merge(entitySchema: EntitySchema, mergeIntoEntity: Entity, ...entityLikes: DeepPartial[]): Entity; - - /** - * Merges two entities into one new entity. - */ - merge(entityName: string, mergeIntoEntity: Entity, ...entityLikes: DeepPartial[]): Entity; - - /** - * Merges two entities into one new entity. - */ - merge(entityClass: ObjectType|EntitySchema|string, mergeIntoEntity: Entity, ...entityLikes: DeepPartial[]): Entity { // todo: throw exception if entity manager is released + merge(entityClass: EntityTarget, mergeIntoEntity: Entity, ...entityLikes: DeepPartial[]): Entity { // todo: throw exception if entity manager is released const metadata = this.connection.getMetadata(entityClass); entityLikes.forEach(object => this.plainObjectToEntityTransformer.transform(mergeIntoEntity, object, metadata)); return mergeIntoEntity; @@ -314,31 +266,7 @@ export class EntityManager { * and returns this new entity. This new entity is actually a loaded from the db entity with all properties * replaced from the new object. */ - preload(entityClass: ObjectType, entityLike: DeepPartial): Promise; - - /** - * Creates a new entity from the given plain javascript object. If entity already exist in the database, then - * it loads it (and everything related to it), replaces all values with the new ones from the given object - * and returns this new entity. This new entity is actually a loaded from the db entity with all properties - * replaced from the new object. - */ - preload(entitySchema: EntitySchema, entityLike: DeepPartial): Promise; - - /** - * Creates a new entity from the given plain javascript object. If entity already exist in the database, then - * it loads it (and everything related to it), replaces all values with the new ones from the given object - * and returns this new entity. This new entity is actually a loaded from the db entity with all properties - * replaced from the new object. - */ - preload(entityName: string, entityLike: DeepPartial): Promise; - - /** - * Creates a new entity from the given plain javascript object. If entity already exist in the database, then - * it loads it (and everything related to it), replaces all values with the new ones from the given object - * and returns this new entity. This new entity is actually a loaded from the db entity with all properties - * replaced from the new object. - */ - async preload(entityClass: ObjectType|EntitySchema|string, entityLike: DeepPartial): Promise { + async preload(entityClass: EntityTarget, entityLike: DeepPartial): Promise { const metadata = this.connection.getMetadata(entityClass); const plainObjectToDatabaseEntityTransformer = new PlainObjectToDatabaseEntityTransformer(this.connection.manager); const transformedEntity = await plainObjectToDatabaseEntityTransformer.transform(entityLike, metadata); @@ -364,30 +292,18 @@ export class EntityManager { * Saves all given entities in the database. * If entities do not exist in the database then inserts, otherwise updates. */ - save>(targetOrEntity: ObjectType|EntitySchema, entities: T[], options?: SaveOptions): Promise; - - /** - * Saves all given entities in the database. - * If entities do not exist in the database then inserts, otherwise updates. - */ - save>(targetOrEntity: ObjectType|EntitySchema, entity: T, options?: SaveOptions): Promise; + save>(targetOrEntity: EntityTarget, entities: T[], options?: SaveOptions): Promise; /** * Saves all given entities in the database. * If entities do not exist in the database then inserts, otherwise updates. */ - save(targetOrEntity: string, entities: T[], options?: SaveOptions): Promise; - - /** - * Saves all given entities in the database. - * If entities do not exist in the database then inserts, otherwise updates. - */ - save(targetOrEntity: string, entity: T, options?: SaveOptions): Promise; + save>(targetOrEntity: EntityTarget, entity: T, options?: SaveOptions): Promise; /** * Saves a given entity in the database. */ - save>(targetOrEntity: (T|T[])|ObjectType|EntitySchema|string, maybeEntityOrOptions?: T|T[], maybeOptions?: SaveOptions): Promise { + save>(targetOrEntity: (T|T[])|EntityTarget, maybeEntityOrOptions?: T|T[], maybeOptions?: SaveOptions): Promise { // normalize mixed parameters let target = (arguments.length > 1 && (targetOrEntity instanceof Function || targetOrEntity instanceof EntitySchema || typeof targetOrEntity === "string")) ? targetOrEntity as Function|string : undefined; @@ -415,17 +331,7 @@ export class EntityManager { /** * Removes a given entity from the database. */ - remove(targetOrEntity: ObjectType, entity: Entity, options?: RemoveOptions): Promise; - - /** - * Removes a given entity from the database. - */ - remove(targetOrEntity: EntitySchema, entity: Entity, options?: RemoveOptions): Promise; - - /** - * Removes a given entity from the database. - */ - remove(targetOrEntity: string, entity: Entity, options?: RemoveOptions): Promise; + remove(targetOrEntity: EntityTarget, entity: Entity, options?: RemoveOptions): Promise; /** * Removes a given entity from the database. @@ -435,22 +341,12 @@ export class EntityManager { /** * Removes a given entity from the database. */ - remove(targetOrEntity: ObjectType, entity: Entity[], options?: RemoveOptions): Promise; - - /** - * Removes a given entity from the database. - */ - remove(targetOrEntity: EntitySchema, entity: Entity[], options?: RemoveOptions): Promise; - - /** - * Removes a given entity from the database. - */ - remove(targetOrEntity: string, entity: Entity[], options?: RemoveOptions): Promise; + remove(targetOrEntity: EntityTarget, entity: Entity[], options?: RemoveOptions): Promise; /** * Removes a given entity from the database. */ - remove(targetOrEntity: (Entity|Entity[])|Function|string, maybeEntityOrOptions?: Entity|Entity[], maybeOptions?: RemoveOptions): Promise { + remove(targetOrEntity: (Entity|Entity[])|EntityTarget, maybeEntityOrOptions?: Entity|Entity[], maybeOptions?: RemoveOptions): Promise { // normalize mixed parameters const target = (arguments.length > 1 && (targetOrEntity instanceof Function || typeof targetOrEntity === "string")) ? targetOrEntity as Function|string : undefined; @@ -480,27 +376,17 @@ export class EntityManager { /** * Records the delete date of all given entities. */ - softRemove>(targetOrEntity: ObjectType|EntitySchema, entities: T[], options?: SaveOptions): Promise; + softRemove>(targetOrEntity: EntityTarget, entities: T[], options?: SaveOptions): Promise; /** * Records the delete date of a given entity. */ - softRemove>(targetOrEntity: ObjectType|EntitySchema, entity: T, options?: SaveOptions): Promise; - - /** - * Records the delete date of all given entities. - */ - softRemove(targetOrEntity: string, entities: T[], options?: SaveOptions): Promise; - - /** - * Records the delete date of a given entity. - */ - softRemove(targetOrEntity: string, entity: T, options?: SaveOptions): Promise; + softRemove>(targetOrEntity: EntityTarget, entity: T, options?: SaveOptions): Promise; /** * Records the delete date of one or many given entities. */ - softRemove>(targetOrEntity: (T|T[])|ObjectType|EntitySchema|string, maybeEntityOrOptions?: T|T[], maybeOptions?: SaveOptions): Promise { + softRemove>(targetOrEntity: (T|T[])|EntityTarget, maybeEntityOrOptions?: T|T[], maybeOptions?: SaveOptions): Promise { // normalize mixed parameters let target = (arguments.length > 1 && (targetOrEntity instanceof Function || targetOrEntity instanceof EntitySchema || typeof targetOrEntity === "string")) ? targetOrEntity as Function|string : undefined; @@ -533,27 +419,17 @@ export class EntityManager { /** * Recovers all given entities. */ - recover>(targetOrEntity: ObjectType|EntitySchema, entities: T[], options?: SaveOptions): Promise; + recover>(targetOrEntity: EntityTarget, entities: T[], options?: SaveOptions): Promise; /** * Recovers a given entity. */ - recover>(targetOrEntity: ObjectType|EntitySchema, entity: T, options?: SaveOptions): Promise; - - /** - * Recovers all given entities. - */ - recover(targetOrEntity: string, entities: T[], options?: SaveOptions): Promise; - - /** - * Recovers a given entity. - */ - recover(targetOrEntity: string, entity: T, options?: SaveOptions): Promise; + recover>(targetOrEntity: EntityTarget, entity: T, options?: SaveOptions): Promise; /** * Recovers one or many given entities. */ - recover>(targetOrEntity: (T|T[])|ObjectType|EntitySchema|string, maybeEntityOrOptions?: T|T[], maybeOptions?: SaveOptions): Promise { + recover>(targetOrEntity: (T|T[])|EntityTarget, maybeEntityOrOptions?: T|T[], maybeOptions?: SaveOptions): Promise { // normalize mixed parameters let target = (arguments.length > 1 && (targetOrEntity instanceof Function || targetOrEntity instanceof EntitySchema || typeof targetOrEntity === "string")) ? targetOrEntity as Function|string : undefined; @@ -580,7 +456,7 @@ export class EntityManager { * Does not check if entity exist in the database, so query will fail if duplicate entity is being inserted. * You can execute bulk inserts using this method. */ - async insert(target: ObjectType|EntitySchema|string, entity: QueryDeepPartialEntity|(QueryDeepPartialEntity[])): Promise { + async insert(target: EntityTarget, entity: QueryDeepPartialEntity|(QueryDeepPartialEntity[])): Promise { // TODO: Oracle does not support multiple values. Need to create another nice solution. if (this.connection.driver instanceof OracleDriver && Array.isArray(entity)) { const results = await Promise.all(entity.map(entity => this.insert(target, entity))); @@ -600,7 +476,7 @@ export class EntityManager { * Does not check if entity exist in the database. * Condition(s) cannot be empty. */ - update(target: ObjectType|EntitySchema|string, criteria: string|string[]|number|number[]|Date|Date[]|ObjectID|ObjectID[]|any, partialEntity: QueryDeepPartialEntity): Promise { + update(target: EntityTarget, criteria: string|string[]|number|number[]|Date|Date[]|ObjectID|ObjectID[]|any, partialEntity: QueryDeepPartialEntity): Promise { // if user passed empty criteria or empty list of criterias, then throw an error if (criteria === undefined || @@ -638,7 +514,7 @@ export class EntityManager { * Does not check if entity exist in the database. * Condition(s) cannot be empty. */ - delete(targetOrEntity: ObjectType|EntitySchema|string, criteria: string|string[]|number|number[]|Date|Date[]|ObjectID|ObjectID[]|any): Promise { + delete(targetOrEntity: EntityTarget, criteria: string|string[]|number|number[]|Date|Date[]|ObjectID|ObjectID[]|any): Promise { // if user passed empty criteria or empty list of criterias, then throw an error if (criteria === undefined || @@ -676,7 +552,7 @@ export class EntityManager { * Does not check if entity exist in the database. * Condition(s) cannot be empty. */ - softDelete(targetOrEntity: ObjectType|EntitySchema|string, criteria: string|string[]|number|number[]|Date|Date[]|ObjectID|ObjectID[]|any): Promise { + softDelete(targetOrEntity: EntityTarget, criteria: string|string[]|number|number[]|Date|Date[]|ObjectID|ObjectID[]|any): Promise { // if user passed empty criteria or empty list of criterias, then throw an error if (criteria === undefined || @@ -714,7 +590,7 @@ export class EntityManager { * Does not check if entity exist in the database. * Condition(s) cannot be empty. */ - restore(targetOrEntity: ObjectType|EntitySchema|string, criteria: string|string[]|number|number[]|Date|Date[]|ObjectID|ObjectID[]|any): Promise { + restore(targetOrEntity: EntityTarget, criteria: string|string[]|number|number[]|Date|Date[]|ObjectID|ObjectID[]|any): Promise { // if user passed empty criteria or empty list of criterias, then throw an error if (criteria === undefined || @@ -746,85 +622,47 @@ export class EntityManager { } /** - * Counts entities that match given options. + * Counts entities that match given conditions. * Useful for pagination. */ - count(entityClass: ObjectType, options?: FindOneOptions): Promise; + count(entityClass: EntityTarget, conditions?: FindConditions): Promise; /** * Counts entities that match given options. * Useful for pagination. */ - count(entityClass: EntitySchema, options?: FindOneOptions): Promise; + count(entityClass: EntityTarget, options?: FindOneOptions): Promise; /** * Counts entities that match given options. * Useful for pagination. */ - count(entityClass: string, options?: FindOneOptions): Promise; - - /** - * Counts entities that match given conditions. - * Useful for pagination. - */ - count(entityClass: ObjectType, conditions?: FindConditions): Promise; - - /** - * Counts entities that match given conditions. - * Useful for pagination. - */ - count(entityClass: EntitySchema, conditions?: FindConditions): Promise; - - /** - * Counts entities that match given conditions. - * Useful for pagination. - */ - count(entityClass: string, conditions?: FindConditions): Promise; + count(entityClass: EntityTarget, options?: FindManyOptions): Promise; /** * Counts entities that match given find options or conditions. * Useful for pagination. */ - async count(entityClass: ObjectType|EntitySchema|string, optionsOrConditions?: FindManyOptions|any): Promise { + async count(entityClass: EntityTarget, optionsOrConditions?: FindConditions|FindOneOptions|FindManyOptions): Promise { const metadata = this.connection.getMetadata(entityClass); - const qb = this.createQueryBuilder(entityClass as any, FindOptionsUtils.extractFindManyOptionsAlias(optionsOrConditions) || metadata.name); + const qb = this.createQueryBuilder(entityClass, FindOptionsUtils.extractFindManyOptionsAlias(optionsOrConditions) || metadata.name); return FindOptionsUtils.applyFindManyOptionsOrConditionsToQueryBuilder(qb, optionsOrConditions).getCount(); } - /** - * Finds entities that match given options. - */ - find(entityClass: ObjectType, options?: FindManyOptions): Promise; - /** * Finds entities that match given conditions. */ - find(entityClass: ObjectType, conditions?: FindConditions): Promise; + find(entityClass: EntityTarget, conditions?: FindConditions): Promise; /** * Finds entities that match given options. */ - find(entitySchema: EntitySchema, options?: FindManyOptions): Promise; - - /** - * Finds entities that match given conditions. - */ - find(entitySchema: EntitySchema, conditions?: FindConditions): Promise; - - /** - * Finds entities that match given conditions. - */ - find(entityClass: string, options?: FindManyOptions): Promise; - - /** - * Finds entities that match given conditions. - */ - find(entityClass: string, conditions?: FindConditions): Promise; + find(entityClass: EntityTarget, options?: FindManyOptions): Promise; /** * Finds entities that match given find options or conditions. */ - async find(entityClass: ObjectType|EntitySchema|string, optionsOrConditions?: FindManyOptions|any): Promise { + async find(entityClass: EntityTarget, optionsOrConditions?: FindManyOptions|FindConditions): Promise { const metadata = this.connection.getMetadata(entityClass); const qb = this.createQueryBuilder(entityClass as any, FindOptionsUtils.extractFindManyOptionsAlias(optionsOrConditions) || metadata.name); @@ -834,54 +672,26 @@ export class EntityManager { return FindOptionsUtils.applyFindManyOptionsOrConditionsToQueryBuilder(qb, optionsOrConditions).getMany(); } - /** - * Finds entities that match given find options. - * Also counts all entities that match given conditions, - * but ignores pagination settings (from and take options). - */ - findAndCount(entityClass: ObjectType, options?: FindManyOptions): Promise<[Entity[], number]>; - - /** - * Finds entities that match given find options. - * Also counts all entities that match given conditions, - * but ignores pagination settings (from and take options). - */ - findAndCount(entityClass: EntitySchema, options?: FindManyOptions): Promise<[Entity[], number]>; - - /** - * Finds entities that match given find options. - * Also counts all entities that match given conditions, - * but ignores pagination settings (from and take options). - */ - findAndCount(entityClass: string, options?: FindManyOptions): Promise<[Entity[], number]>; - - /** - * Finds entities that match given conditions. - * Also counts all entities that match given conditions, - * but ignores pagination settings (from and take options). - */ - findAndCount(entityClass: ObjectType, conditions?: FindConditions): Promise<[Entity[], number]>; - /** * Finds entities that match given conditions. * Also counts all entities that match given conditions, * but ignores pagination settings (from and take options). */ - findAndCount(entityClass: EntitySchema, conditions?: FindConditions): Promise<[Entity[], number]>; + findAndCount(entityClass: EntityTarget, conditions?: FindConditions): Promise<[Entity[], number]>; /** - * Finds entities that match given conditions. + * Finds entities that match given find options. * Also counts all entities that match given conditions, * but ignores pagination settings (from and take options). */ - findAndCount(entityClass: string, conditions?: FindConditions): Promise<[Entity[], number]>; + findAndCount(entityClass: EntityTarget, options?: FindManyOptions): Promise<[Entity[], number]>; /** * Finds entities that match given find options and conditions. * Also counts all entities that match given conditions, * but ignores pagination settings (from and take options). */ - async findAndCount(entityClass: ObjectType|EntitySchema|string, optionsOrConditions?: FindManyOptions|any): Promise<[Entity[], number]> { + async findAndCount(entityClass: EntityTarget, optionsOrConditions?: FindConditions|FindManyOptions): Promise<[Entity[], number]> { const metadata = this.connection.getMetadata(entityClass); const qb = this.createQueryBuilder(entityClass as any, FindOptionsUtils.extractFindManyOptionsAlias(optionsOrConditions) || metadata.name); @@ -891,47 +701,23 @@ export class EntityManager { return FindOptionsUtils.applyFindManyOptionsOrConditionsToQueryBuilder(qb, optionsOrConditions).getManyAndCount(); } - /** - * Finds entities with ids. - * Optionally find options can be applied. - */ - findByIds(entityClass: ObjectType, ids: any[], options?: FindManyOptions): Promise; - - /** - * Finds entities with ids. - * Optionally find options can be applied. - */ - findByIds(entityClass: EntitySchema, ids: any[], options?: FindManyOptions): Promise; - - /** - * Finds entities with ids. - * Optionally find options can be applied. - */ - findByIds(entityClass: string, ids: any[], options?: FindManyOptions): Promise; - - /** - * Finds entities with ids. - * Optionally conditions can be applied. - */ - findByIds(entityClass: ObjectType, ids: any[], conditions?: FindConditions): Promise; - /** * Finds entities with ids. * Optionally conditions can be applied. */ - findByIds(entityClass: EntitySchema, ids: any[], conditions?: FindConditions): Promise; + findByIds(entityClass: EntityTarget, ids: any[], conditions?: FindConditions): Promise; /** * Finds entities with ids. - * Optionally conditions can be applied. + * Optionally find options can be applied. */ - findByIds(entityClass: string, ids: any[], conditions?: FindConditions): Promise; + findByIds(entityClass: EntityTarget, ids: any[], options?: FindManyOptions): Promise; /** * Finds entities with ids. * Optionally find options or conditions can be applied. */ - async findByIds(entityClass: ObjectType|EntitySchema|string, ids: any[], optionsOrConditions?: FindManyOptions|any): Promise { + async findByIds(entityClass: EntityTarget, ids: any[], optionsOrConditions?: FindConditions|FindManyOptions): Promise { // if no ids passed, no need to execute a query - just return an empty array of values if (!ids.length) @@ -949,52 +735,22 @@ export class EntityManager { /** * Finds first entity that matches given find options. */ - findOne(entityClass: ObjectType, id?: string|number|Date|ObjectID, options?: FindOneOptions): Promise; + findOne(entityClass: EntityTarget, id?: string|number|Date|ObjectID, options?: FindOneOptions): Promise; /** * Finds first entity that matches given find options. */ - findOne(entityClass: EntitySchema, id?: string|number|Date|ObjectID, options?: FindOneOptions): Promise; - - /** - * Finds first entity that matches given find options. - */ - findOne(entityClass: string, id?: string|number|Date|ObjectID, options?: FindOneOptions): Promise; - - /** - * Finds first entity that matches given find options. - */ - findOne(entityClass: ObjectType, options?: FindOneOptions): Promise; - - /** - * Finds first entity that matches given find options. - */ - findOne(entityClass: EntitySchema, options?: FindOneOptions): Promise; - - /** - * Finds first entity that matches given find options. - */ - findOne(entityClass: string, options?: FindOneOptions): Promise; - - /** - * Finds first entity that matches given conditions. - */ - findOne(entityClass: ObjectType, conditions?: FindConditions, options?: FindOneOptions): Promise; - - /** - * Finds first entity that matches given conditions. - */ - findOne(entityClass: EntitySchema, conditions?: FindConditions, options?: FindOneOptions): Promise; + findOne(entityClass: EntityTarget, options?: FindOneOptions): Promise; /** * Finds first entity that matches given conditions. */ - findOne(entityClass: string, conditions?: FindConditions, options?: FindOneOptions): Promise; + findOne(entityClass: EntityTarget, conditions?: FindConditions, options?: FindOneOptions): Promise; /** * Finds first entity that matches given conditions. */ - async findOne(entityClass: ObjectType|EntitySchema|string, idOrOptionsOrConditions?: string|string[]|number|number[]|Date|Date[]|ObjectID|ObjectID[]|FindOneOptions|any, maybeOptions?: FindOneOptions): Promise { + async findOne(entityClass: EntityTarget, idOrOptionsOrConditions?: string|string[]|number|number[]|Date|Date[]|ObjectID|ObjectID[]|FindOneOptions|FindConditions, maybeOptions?: FindOneOptions): Promise { let findOptions: FindManyOptions|FindOneOptions|undefined = undefined; if (FindOptionsUtils.isFindOneOptions(idOrOptionsOrConditions)) { @@ -1044,52 +800,22 @@ export class EntityManager { /** * Finds first entity that matches given find options or rejects the returned promise on error. */ - findOneOrFail(entityClass: ObjectType, id?: string|number|Date|ObjectID, options?: FindOneOptions): Promise; + findOneOrFail(entityClass: EntityTarget, id?: string|number|Date|ObjectID, options?: FindOneOptions): Promise; /** * Finds first entity that matches given find options or rejects the returned promise on error. */ - findOneOrFail(entityClass: EntitySchema, id?: string|number|Date|ObjectID, options?: FindOneOptions): Promise; - - /** - * Finds first entity that matches given find options or rejects the returned promise on error. - */ - findOneOrFail(entityClass: string, id?: string|number|Date|ObjectID, options?: FindOneOptions): Promise; - - /** - * Finds first entity that matches given find options or rejects the returned promise on error. - */ - findOneOrFail(entityClass: ObjectType, options?: FindOneOptions): Promise; - - /** - * Finds first entity that matches given find options or rejects the returned promise on error. - */ - findOneOrFail(entityClass: EntitySchema, options?: FindOneOptions): Promise; - - /** - * Finds first entity that matches given find options or rejects the returned promise on error. - */ - findOneOrFail(entityClass: string, options?: FindOneOptions): Promise; - - /** - * Finds first entity that matches given conditions or rejects the returned promise on error. - */ - findOneOrFail(entityClass: ObjectType, conditions?: FindConditions, options?: FindOneOptions): Promise; - - /** - * Finds first entity that matches given conditions or rejects the returned promise on error. - */ - findOneOrFail(entityClass: EntitySchema, conditions?: FindConditions, options?: FindOneOptions): Promise; + findOneOrFail(entityClass: EntityTarget, options?: FindOneOptions): Promise; /** * Finds first entity that matches given conditions or rejects the returned promise on error. */ - findOneOrFail(entityClass: string, conditions?: FindConditions, options?: FindOneOptions): Promise; + findOneOrFail(entityClass: EntityTarget, conditions?: FindConditions, options?: FindOneOptions): Promise; /** * Finds first entity that matches given conditions or rejects the returned promise on error. */ - async findOneOrFail(entityClass: ObjectType|EntitySchema|string, idOrOptionsOrConditions?: string|string[]|number|number[]|Date|Date[]|ObjectID|ObjectID[]|FindOneOptions|any, maybeOptions?: FindOneOptions): Promise { + async findOneOrFail(entityClass: EntityTarget, idOrOptionsOrConditions?: string|string[]|number|number[]|Date|Date[]|ObjectID|ObjectID[]|FindOneOptions|FindConditions, maybeOptions?: FindOneOptions): Promise { return this.findOne(entityClass as any, idOrOptionsOrConditions as any, maybeOptions).then((value) => { if (value === undefined) { return Promise.reject(new EntityNotFoundError(entityClass, idOrOptionsOrConditions)); @@ -1104,7 +830,7 @@ export class EntityManager { * Note: this method uses TRUNCATE and may not work as you expect in transactions on some platforms. * @see https://stackoverflow.com/a/5972738/925151 */ - async clear(entityClass: ObjectType|EntitySchema|string): Promise { + async clear(entityClass: EntityTarget): Promise { const metadata = this.connection.getMetadata(entityClass); const queryRunner = this.queryRunner || this.connection.createQueryRunner("master"); try { @@ -1119,7 +845,7 @@ export class EntityManager { /** * Increments some column by provided value of the entities matched given conditions. */ - async increment(entityClass: ObjectType|EntitySchema|string, + async increment(entityClass: EntityTarget, conditions: any, propertyPath: string, value: number | string): Promise { @@ -1151,7 +877,7 @@ export class EntityManager { /** * Decrements some column by provided value of the entities matched given conditions. */ - async decrement(entityClass: ObjectType|EntitySchema|string, + async decrement(entityClass: EntityTarget, conditions: any, propertyPath: string, value: number | string): Promise { @@ -1186,7 +912,7 @@ export class EntityManager { * repository aggregator, where each repository is individually created for this entity manager. * When single database connection is not used, repository is being obtained from the connection. */ - getRepository(target: ObjectType|EntitySchema|string): Repository { + getRepository(target: EntityTarget): Repository { // throw exception if there is no repository with this target registered if (!this.connection.hasMetadata(target)) @@ -1210,7 +936,7 @@ export class EntityManager { * repository aggregator, where each repository is individually created for this entity manager. * When single database connection is not used, repository is being obtained from the connection. */ - getTreeRepository(target: ObjectType|EntitySchema|string): TreeRepository { + getTreeRepository(target: EntityTarget): TreeRepository { // tree tables aren't supported by some drivers (mongodb) if (this.connection.driver.treeSupport === false) @@ -1227,7 +953,7 @@ export class EntityManager { /** * Gets mongodb repository for the given entity class. */ - getMongoRepository(target: ObjectType|EntitySchema|string): MongoRepository { + getMongoRepository(target: EntityTarget): MongoRepository { return this.connection.getMongoRepository(target); } diff --git a/src/entity-manager/MongoEntityManager.ts b/src/entity-manager/MongoEntityManager.ts index 346cf1eee42..1a5ce451993 100644 --- a/src/entity-manager/MongoEntityManager.ts +++ b/src/entity-manager/MongoEntityManager.ts @@ -1,6 +1,6 @@ import { Connection } from "../connection/Connection"; import { EntityManager } from "./EntityManager"; -import { ObjectType } from "../common/ObjectType"; +import { EntityTarget } from "../common/EntityTarget"; import { AggregationCursor, BulkWriteOpResultObject, @@ -51,7 +51,7 @@ import { InsertResult } from "../query-builder/result/InsertResult"; import { UpdateResult } from "../query-builder/result/UpdateResult"; import { DeleteResult } from "../query-builder/result/DeleteResult"; import { EntityMetadata } from "../metadata/EntityMetadata"; -import { EntitySchema, FindConditions } from "../index"; +import { FindConditions } from "../index"; import { BroadcasterResult } from "../subscriber/BroadcasterResult"; /** @@ -88,7 +88,7 @@ export class MongoEntityManager extends EntityManager { /** * Finds entities that match given find options or conditions. */ - async find(entityClassOrName: ObjectType | EntitySchema | string, optionsOrConditions?: FindManyOptions | Partial): Promise { + async find(entityClassOrName: EntityTarget, optionsOrConditions?: FindManyOptions | Partial): Promise { const query = this.convertFindManyOptionsOrConditionsToMongodbQuery(optionsOrConditions); const cursor = await this.createEntityCursor(entityClassOrName, query); if (FindOptionsUtils.isFindManyOptions(optionsOrConditions)) { @@ -109,7 +109,7 @@ export class MongoEntityManager extends EntityManager { * Also counts all entities that match given conditions, * but ignores pagination settings (from and take options). */ - async findAndCount(entityClassOrName: ObjectType | EntitySchema | string, optionsOrConditions?: FindManyOptions | Partial): Promise<[Entity[], number]> { + async findAndCount(entityClassOrName: EntityTarget, optionsOrConditions?: FindManyOptions | Partial): Promise<[Entity[], number]> { const query = this.convertFindManyOptionsOrConditionsToMongodbQuery(optionsOrConditions); const cursor = await this.createEntityCursor(entityClassOrName, query); if (FindOptionsUtils.isFindManyOptions(optionsOrConditions)) { @@ -134,7 +134,7 @@ export class MongoEntityManager extends EntityManager { * Finds entities by ids. * Optionally find options can be applied. */ - async findByIds(entityClassOrName: ObjectType | EntitySchema | string, ids: any[], optionsOrConditions?: FindManyOptions | Partial): Promise { + async findByIds(entityClassOrName: EntityTarget, ids: any[], optionsOrConditions?: FindManyOptions | Partial): Promise { const metadata = this.connection.getMetadata(entityClassOrName); const query = this.convertFindManyOptionsOrConditionsToMongodbQuery(optionsOrConditions) || {}; const objectIdInstance = PlatformTools.load("mongodb").ObjectID; @@ -164,7 +164,7 @@ export class MongoEntityManager extends EntityManager { /** * Finds first entity that matches given conditions and/or find options. */ - async findOne(entityClassOrName: ObjectType | EntitySchema | string, + async findOne(entityClassOrName: EntityTarget, optionsOrConditions?: string | string[] | number | number[] | Date | Date[] | ObjectID | ObjectID[] | FindOneOptions | DeepPartial, maybeOptions?: FindOneOptions): Promise { const objectIdInstance = PlatformTools.load("mongodb").ObjectID; @@ -194,7 +194,7 @@ export class MongoEntityManager extends EntityManager { * Does not check if entity exist in the database, so query will fail if duplicate entity is being inserted. * You can execute bulk inserts using this method. */ - async insert(target: ObjectType | EntitySchema | string, entity: QueryDeepPartialEntity | QueryDeepPartialEntity[]): Promise { + async insert(target: EntityTarget, entity: QueryDeepPartialEntity | QueryDeepPartialEntity[]): Promise { // todo: convert entity to its database name const result = new InsertResult(); if (Array.isArray(entity)) { @@ -220,7 +220,7 @@ export class MongoEntityManager extends EntityManager { * Executes fast and efficient UPDATE query. * Does not check if entity exist in the database. */ - async update(target: ObjectType | EntitySchema | string, criteria: string | string[] | number | number[] | Date | Date[] | ObjectID | ObjectID[] | FindConditions, partialEntity: QueryDeepPartialEntity): Promise { + async update(target: EntityTarget, criteria: string | string[] | number | number[] | Date | Date[] | ObjectID | ObjectID[] | FindConditions, partialEntity: QueryDeepPartialEntity): Promise { if (Array.isArray(criteria)) { await Promise.all((criteria as any[]).map(criteriaItem => { return this.update(target, criteriaItem, partialEntity); @@ -240,7 +240,7 @@ export class MongoEntityManager extends EntityManager { * Executes fast and efficient DELETE query. * Does not check if entity exist in the database. */ - async delete(target: ObjectType | EntitySchema | string, criteria: string | string[] | number | number[] | Date | Date[] | ObjectID | ObjectID[] | FindConditions): Promise { + async delete(target: EntityTarget, criteria: string | string[] | number | number[] | Date | Date[] | ObjectID | ObjectID[] | FindConditions): Promise { if (Array.isArray(criteria)) { await Promise.all((criteria as any[]).map(criteriaItem => { return this.delete(target, criteriaItem); @@ -260,7 +260,7 @@ export class MongoEntityManager extends EntityManager { /** * Creates a cursor for a query that can be used to iterate over results from MongoDB. */ - createCursor(entityClassOrName: ObjectType | EntitySchema | string, query?: ObjectLiteral): Cursor { + createCursor(entityClassOrName: EntityTarget, query?: ObjectLiteral): Cursor { const metadata = this.connection.getMetadata(entityClassOrName); return this.queryRunner.cursor(metadata.tableName, query); } @@ -269,7 +269,7 @@ export class MongoEntityManager extends EntityManager { * Creates a cursor for a query that can be used to iterate over results from MongoDB. * This returns modified version of cursor that transforms each result into Entity model. */ - createEntityCursor(entityClassOrName: ObjectType | EntitySchema | string, query?: ObjectLiteral): Cursor { + createEntityCursor(entityClassOrName: EntityTarget, query?: ObjectLiteral): Cursor { const metadata = this.connection.getMetadata(entityClassOrName); const cursor = this.createCursor(entityClassOrName, query); this.applyEntityTransformationToCursor(metadata, cursor); @@ -279,7 +279,7 @@ export class MongoEntityManager extends EntityManager { /** * Execute an aggregation framework pipeline against the collection. */ - aggregate(entityClassOrName: ObjectType | EntitySchema | string, pipeline: ObjectLiteral[], options?: CollectionAggregationOptions): AggregationCursor { + aggregate(entityClassOrName: EntityTarget, pipeline: ObjectLiteral[], options?: CollectionAggregationOptions): AggregationCursor { const metadata = this.connection.getMetadata(entityClassOrName); return this.queryRunner.aggregate(metadata.tableName, pipeline, options); } @@ -288,7 +288,7 @@ export class MongoEntityManager extends EntityManager { * Execute an aggregation framework pipeline against the collection. * This returns modified version of cursor that transforms each result into Entity model. */ - aggregateEntity(entityClassOrName: ObjectType | EntitySchema | string, pipeline: ObjectLiteral[], options?: CollectionAggregationOptions): AggregationCursor { + aggregateEntity(entityClassOrName: EntityTarget, pipeline: ObjectLiteral[], options?: CollectionAggregationOptions): AggregationCursor { const metadata = this.connection.getMetadata(entityClassOrName); const cursor = this.queryRunner.aggregate(metadata.tableName, pipeline, options); this.applyEntityTransformationToCursor(metadata, cursor); @@ -298,7 +298,7 @@ export class MongoEntityManager extends EntityManager { /** * Perform a bulkWrite operation without a fluent API. */ - bulkWrite(entityClassOrName: ObjectType | EntitySchema | string, operations: ObjectLiteral[], options?: CollectionBulkWriteOptions): Promise { + bulkWrite(entityClassOrName: EntityTarget, operations: ObjectLiteral[], options?: CollectionBulkWriteOptions): Promise { const metadata = this.connection.getMetadata(entityClassOrName); return this.queryRunner.bulkWrite(metadata.tableName, operations, options); } @@ -306,7 +306,7 @@ export class MongoEntityManager extends EntityManager { /** * Count number of matching documents in the db to a query. */ - count(entityClassOrName: ObjectType | EntitySchema | string, query?: ObjectLiteral, options?: MongoCountPreferences): Promise { + count(entityClassOrName: EntityTarget, query?: ObjectLiteral, options?: MongoCountPreferences): Promise { const metadata = this.connection.getMetadata(entityClassOrName); return this.queryRunner.count(metadata.tableName, query, options); } @@ -314,7 +314,7 @@ export class MongoEntityManager extends EntityManager { /** * Creates an index on the db and collection. */ - createCollectionIndex(entityClassOrName: ObjectType | EntitySchema | string, fieldOrSpec: string | any, options?: MongodbIndexOptions): Promise { + createCollectionIndex(entityClassOrName: EntityTarget, fieldOrSpec: string | any, options?: MongodbIndexOptions): Promise { const metadata = this.connection.getMetadata(entityClassOrName); return this.queryRunner.createCollectionIndex(metadata.tableName, fieldOrSpec, options); } @@ -324,7 +324,7 @@ export class MongoEntityManager extends EntityManager { * Earlier version of MongoDB will throw a command not supported error. * Index specifications are defined at http://docs.mongodb.org/manual/reference/command/createIndexes/. */ - createCollectionIndexes(entityClassOrName: ObjectType | EntitySchema | string, indexSpecs: ObjectLiteral[]): Promise { + createCollectionIndexes(entityClassOrName: EntityTarget, indexSpecs: ObjectLiteral[]): Promise { const metadata = this.connection.getMetadata(entityClassOrName); return this.queryRunner.createCollectionIndexes(metadata.tableName, indexSpecs); } @@ -332,7 +332,7 @@ export class MongoEntityManager extends EntityManager { /** * Delete multiple documents on MongoDB. */ - deleteMany(entityClassOrName: ObjectType | EntitySchema | string, query: ObjectLiteral, options?: CollectionOptions): Promise { + deleteMany(entityClassOrName: EntityTarget, query: ObjectLiteral, options?: CollectionOptions): Promise { const metadata = this.connection.getMetadata(entityClassOrName); return this.queryRunner.deleteMany(metadata.tableName, query, options); } @@ -340,7 +340,7 @@ export class MongoEntityManager extends EntityManager { /** * Delete a document on MongoDB. */ - deleteOne(entityClassOrName: ObjectType | EntitySchema | string, query: ObjectLiteral, options?: CollectionOptions): Promise { + deleteOne(entityClassOrName: EntityTarget, query: ObjectLiteral, options?: CollectionOptions): Promise { const metadata = this.connection.getMetadata(entityClassOrName); return this.queryRunner.deleteOne(metadata.tableName, query, options); } @@ -348,7 +348,7 @@ export class MongoEntityManager extends EntityManager { /** * The distinct command returns returns a list of distinct values for the given key across a collection. */ - distinct(entityClassOrName: ObjectType | EntitySchema | string, key: string, query: ObjectLiteral, options?: { readPreference?: ReadPreference | string }): Promise { + distinct(entityClassOrName: EntityTarget, key: string, query: ObjectLiteral, options?: { readPreference?: ReadPreference | string }): Promise { const metadata = this.connection.getMetadata(entityClassOrName); return this.queryRunner.distinct(metadata.tableName, key, query, options); } @@ -356,7 +356,7 @@ export class MongoEntityManager extends EntityManager { /** * Drops an index from this collection. */ - dropCollectionIndex(entityClassOrName: ObjectType | EntitySchema | string, indexName: string, options?: CollectionOptions): Promise { + dropCollectionIndex(entityClassOrName: EntityTarget, indexName: string, options?: CollectionOptions): Promise { const metadata = this.connection.getMetadata(entityClassOrName); return this.queryRunner.dropCollectionIndex(metadata.tableName, indexName, options); } @@ -364,7 +364,7 @@ export class MongoEntityManager extends EntityManager { /** * Drops all indexes from the collection. */ - dropCollectionIndexes(entityClassOrName: ObjectType | EntitySchema | string): Promise { + dropCollectionIndexes(entityClassOrName: EntityTarget): Promise { const metadata = this.connection.getMetadata(entityClassOrName); return this.queryRunner.dropCollectionIndexes(metadata.tableName); } @@ -372,7 +372,7 @@ export class MongoEntityManager extends EntityManager { /** * Find a document and delete it in one atomic operation, requires a write lock for the duration of the operation. */ - findOneAndDelete(entityClassOrName: ObjectType | EntitySchema | string, query: ObjectLiteral, options?: { projection?: Object, sort?: Object, maxTimeMS?: number }): Promise { + findOneAndDelete(entityClassOrName: EntityTarget, query: ObjectLiteral, options?: { projection?: Object, sort?: Object, maxTimeMS?: number }): Promise { const metadata = this.connection.getMetadata(entityClassOrName); return this.queryRunner.findOneAndDelete(metadata.tableName, query, options); } @@ -380,7 +380,7 @@ export class MongoEntityManager extends EntityManager { /** * Find a document and replace it in one atomic operation, requires a write lock for the duration of the operation. */ - findOneAndReplace(entityClassOrName: ObjectType | EntitySchema | string, query: ObjectLiteral, replacement: Object, options?: FindOneAndReplaceOption): Promise { + findOneAndReplace(entityClassOrName: EntityTarget, query: ObjectLiteral, replacement: Object, options?: FindOneAndReplaceOption): Promise { const metadata = this.connection.getMetadata(entityClassOrName); return this.queryRunner.findOneAndReplace(metadata.tableName, query, replacement, options); } @@ -388,7 +388,7 @@ export class MongoEntityManager extends EntityManager { /** * Find a document and update it in one atomic operation, requires a write lock for the duration of the operation. */ - findOneAndUpdate(entityClassOrName: ObjectType | EntitySchema | string, query: ObjectLiteral, update: Object, options?: FindOneAndReplaceOption): Promise { + findOneAndUpdate(entityClassOrName: EntityTarget, query: ObjectLiteral, update: Object, options?: FindOneAndReplaceOption): Promise { const metadata = this.connection.getMetadata(entityClassOrName); return this.queryRunner.findOneAndUpdate(metadata.tableName, query, update, options); } @@ -396,7 +396,7 @@ export class MongoEntityManager extends EntityManager { /** * Execute a geo search using a geo haystack index on a collection. */ - geoHaystackSearch(entityClassOrName: ObjectType | EntitySchema | string, x: number, y: number, options?: GeoHaystackSearchOptions): Promise { + geoHaystackSearch(entityClassOrName: EntityTarget, x: number, y: number, options?: GeoHaystackSearchOptions): Promise { const metadata = this.connection.getMetadata(entityClassOrName); return this.queryRunner.geoHaystackSearch(metadata.tableName, x, y, options); } @@ -404,7 +404,7 @@ export class MongoEntityManager extends EntityManager { /** * Execute the geoNear command to search for items in the collection. */ - geoNear(entityClassOrName: ObjectType | EntitySchema | string, x: number, y: number, options?: GeoNearOptions): Promise { + geoNear(entityClassOrName: EntityTarget, x: number, y: number, options?: GeoNearOptions): Promise { const metadata = this.connection.getMetadata(entityClassOrName); return this.queryRunner.geoNear(metadata.tableName, x, y, options); } @@ -412,7 +412,7 @@ export class MongoEntityManager extends EntityManager { /** * Run a group command across a collection. */ - group(entityClassOrName: ObjectType | EntitySchema | string, keys: Object | Array | Function | Code, condition: Object, initial: Object, reduce: Function | Code, finalize: Function | Code, command: boolean, options?: { readPreference?: ReadPreference | string }): Promise { + group(entityClassOrName: EntityTarget, keys: Object | Array | Function | Code, condition: Object, initial: Object, reduce: Function | Code, finalize: Function | Code, command: boolean, options?: { readPreference?: ReadPreference | string }): Promise { const metadata = this.connection.getMetadata(entityClassOrName); return this.queryRunner.group(metadata.tableName, keys, condition, initial, reduce, finalize, command, options); } @@ -420,7 +420,7 @@ export class MongoEntityManager extends EntityManager { /** * Retrieve all the indexes on the collection. */ - collectionIndexes(entityClassOrName: ObjectType | EntitySchema | string): Promise { + collectionIndexes(entityClassOrName: EntityTarget): Promise { const metadata = this.connection.getMetadata(entityClassOrName); return this.queryRunner.collectionIndexes(metadata.tableName); } @@ -428,7 +428,7 @@ export class MongoEntityManager extends EntityManager { /** * Retrieve all the indexes on the collection. */ - collectionIndexExists(entityClassOrName: ObjectType | EntitySchema | string, indexes: string | string[]): Promise { + collectionIndexExists(entityClassOrName: EntityTarget, indexes: string | string[]): Promise { const metadata = this.connection.getMetadata(entityClassOrName); return this.queryRunner.collectionIndexExists(metadata.tableName, indexes); } @@ -436,7 +436,7 @@ export class MongoEntityManager extends EntityManager { /** * Retrieves this collections index info. */ - collectionIndexInformation(entityClassOrName: ObjectType | EntitySchema | string, options?: { full: boolean }): Promise { + collectionIndexInformation(entityClassOrName: EntityTarget, options?: { full: boolean }): Promise { const metadata = this.connection.getMetadata(entityClassOrName); return this.queryRunner.collectionIndexInformation(metadata.tableName, options); } @@ -444,7 +444,7 @@ export class MongoEntityManager extends EntityManager { /** * Initiate an In order bulk write operation, operations will be serially executed in the order they are added, creating a new operation for each switch in types. */ - initializeOrderedBulkOp(entityClassOrName: ObjectType | EntitySchema | string, options?: CollectionOptions): OrderedBulkOperation { + initializeOrderedBulkOp(entityClassOrName: EntityTarget, options?: CollectionOptions): OrderedBulkOperation { const metadata = this.connection.getMetadata(entityClassOrName); return this.queryRunner.initializeOrderedBulkOp(metadata.tableName, options); } @@ -452,7 +452,7 @@ export class MongoEntityManager extends EntityManager { /** * Initiate a Out of order batch write operation. All operations will be buffered into insert/update/remove commands executed out of order. */ - initializeUnorderedBulkOp(entityClassOrName: ObjectType | EntitySchema | string, options?: CollectionOptions): UnorderedBulkOperation { + initializeUnorderedBulkOp(entityClassOrName: EntityTarget, options?: CollectionOptions): UnorderedBulkOperation { const metadata = this.connection.getMetadata(entityClassOrName); return this.queryRunner.initializeUnorderedBulkOp(metadata.tableName, options); } @@ -460,7 +460,7 @@ export class MongoEntityManager extends EntityManager { /** * Inserts an array of documents into MongoDB. */ - insertMany(entityClassOrName: ObjectType | EntitySchema | string, docs: ObjectLiteral[], options?: CollectionInsertManyOptions): Promise { + insertMany(entityClassOrName: EntityTarget, docs: ObjectLiteral[], options?: CollectionInsertManyOptions): Promise { const metadata = this.connection.getMetadata(entityClassOrName); return this.queryRunner.insertMany(metadata.tableName, docs, options); } @@ -468,7 +468,7 @@ export class MongoEntityManager extends EntityManager { /** * Inserts a single document into MongoDB. */ - insertOne(entityClassOrName: ObjectType | EntitySchema | string, doc: ObjectLiteral, options?: CollectionInsertOneOptions): Promise { + insertOne(entityClassOrName: EntityTarget, doc: ObjectLiteral, options?: CollectionInsertOneOptions): Promise { const metadata = this.connection.getMetadata(entityClassOrName); return this.queryRunner.insertOne(metadata.tableName, doc, options); } @@ -476,7 +476,7 @@ export class MongoEntityManager extends EntityManager { /** * Returns if the collection is a capped collection. */ - isCapped(entityClassOrName: ObjectType | EntitySchema | string): Promise { + isCapped(entityClassOrName: EntityTarget): Promise { const metadata = this.connection.getMetadata(entityClassOrName); return this.queryRunner.isCapped(metadata.tableName); } @@ -484,7 +484,7 @@ export class MongoEntityManager extends EntityManager { /** * Get the list of all indexes information for the collection. */ - listCollectionIndexes(entityClassOrName: ObjectType | EntitySchema | string, options?: { batchSize?: number, readPreference?: ReadPreference | string }): CommandCursor { + listCollectionIndexes(entityClassOrName: EntityTarget, options?: { batchSize?: number, readPreference?: ReadPreference | string }): CommandCursor { const metadata = this.connection.getMetadata(entityClassOrName); return this.queryRunner.listCollectionIndexes(metadata.tableName, options); } @@ -492,7 +492,7 @@ export class MongoEntityManager extends EntityManager { /** * Run Map Reduce across a collection. Be aware that the inline option for out will return an array of results not a collection. */ - mapReduce(entityClassOrName: ObjectType | EntitySchema | string, map: Function | string, reduce: Function | string, options?: MapReduceOptions): Promise { + mapReduce(entityClassOrName: EntityTarget, map: Function | string, reduce: Function | string, options?: MapReduceOptions): Promise { const metadata = this.connection.getMetadata(entityClassOrName); return this.queryRunner.mapReduce(metadata.tableName, map, reduce, options); } @@ -501,7 +501,7 @@ export class MongoEntityManager extends EntityManager { * Return N number of parallel cursors for a collection allowing parallel reading of entire collection. * There are no ordering guarantees for returned results. */ - parallelCollectionScan(entityClassOrName: ObjectType | EntitySchema | string, options?: ParallelCollectionScanOptions): Promise[]> { + parallelCollectionScan(entityClassOrName: EntityTarget, options?: ParallelCollectionScanOptions): Promise[]> { const metadata = this.connection.getMetadata(entityClassOrName); return this.queryRunner.parallelCollectionScan(metadata.tableName, options); } @@ -509,7 +509,7 @@ export class MongoEntityManager extends EntityManager { /** * Reindex all indexes on the collection Warning: reIndex is a blocking operation (indexes are rebuilt in the foreground) and will be slow for large collections. */ - reIndex(entityClassOrName: ObjectType | EntitySchema | string): Promise { + reIndex(entityClassOrName: EntityTarget): Promise { const metadata = this.connection.getMetadata(entityClassOrName); return this.queryRunner.reIndex(metadata.tableName); } @@ -517,7 +517,7 @@ export class MongoEntityManager extends EntityManager { /** * Reindex all indexes on the collection Warning: reIndex is a blocking operation (indexes are rebuilt in the foreground) and will be slow for large collections. */ - rename(entityClassOrName: ObjectType | EntitySchema | string, newName: string, options?: { dropTarget?: boolean }): Promise> { + rename(entityClassOrName: EntityTarget, newName: string, options?: { dropTarget?: boolean }): Promise> { const metadata = this.connection.getMetadata(entityClassOrName); return this.queryRunner.rename(metadata.tableName, newName, options); } @@ -525,7 +525,7 @@ export class MongoEntityManager extends EntityManager { /** * Replace a document on MongoDB. */ - replaceOne(entityClassOrName: ObjectType | EntitySchema | string, query: ObjectLiteral, doc: ObjectLiteral, options?: ReplaceOneOptions): Promise { + replaceOne(entityClassOrName: EntityTarget, query: ObjectLiteral, doc: ObjectLiteral, options?: ReplaceOneOptions): Promise { const metadata = this.connection.getMetadata(entityClassOrName); return this.queryRunner.replaceOne(metadata.tableName, query, doc, options); } @@ -533,12 +533,12 @@ export class MongoEntityManager extends EntityManager { /** * Get all the collection statistics. */ - stats(entityClassOrName: ObjectType | EntitySchema | string, options?: { scale: number }): Promise { + stats(entityClassOrName: EntityTarget, options?: { scale: number }): Promise { const metadata = this.connection.getMetadata(entityClassOrName); return this.queryRunner.stats(metadata.tableName, options); } - watch(entityClassOrName: ObjectType | EntitySchema | string, pipeline?: Object[], options?: ChangeStreamOptions): ChangeStream { + watch(entityClassOrName: EntityTarget, pipeline?: Object[], options?: ChangeStreamOptions): ChangeStream { const metadata = this.connection.getMetadata(entityClassOrName); return this.queryRunner.watch(metadata.tableName, pipeline, options); } @@ -546,7 +546,7 @@ export class MongoEntityManager extends EntityManager { /** * Update multiple documents on MongoDB. */ - updateMany(entityClassOrName: ObjectType | EntitySchema | string, query: ObjectLiteral, update: ObjectLiteral, options?: { upsert?: boolean, w?: any, wtimeout?: number, j?: boolean }): Promise { + updateMany(entityClassOrName: EntityTarget, query: ObjectLiteral, update: ObjectLiteral, options?: { upsert?: boolean, w?: any, wtimeout?: number, j?: boolean }): Promise { const metadata = this.connection.getMetadata(entityClassOrName); return this.queryRunner.updateMany(metadata.tableName, query, update, options); } @@ -554,7 +554,7 @@ export class MongoEntityManager extends EntityManager { /** * Update a single document on MongoDB. */ - updateOne(entityClassOrName: ObjectType | EntitySchema | string, query: ObjectLiteral, update: ObjectLiteral, options?: ReplaceOneOptions): Promise { + updateOne(entityClassOrName: EntityTarget, query: ObjectLiteral, update: ObjectLiteral, options?: ReplaceOneOptions): Promise { const metadata = this.connection.getMetadata(entityClassOrName); return this.queryRunner.updateOne(metadata.tableName, query, update, options); } diff --git a/src/error/EntityMetadataNotFoundError.ts b/src/error/EntityMetadataNotFoundError.ts index 3365617f86f..ecb43fd7cf7 100644 --- a/src/error/EntityMetadataNotFoundError.ts +++ b/src/error/EntityMetadataNotFoundError.ts @@ -1,3 +1,4 @@ +import {EntityTarget} from "../common/EntityTarget"; import {EntitySchema} from "../index"; /** @@ -5,7 +6,7 @@ import {EntitySchema} from "../index"; export class EntityMetadataNotFoundError extends Error { name = "EntityMetadataNotFound"; - constructor(target: Function|EntitySchema|string) { + constructor(target: EntityTarget) { super(); Object.setPrototypeOf(this, EntityMetadataNotFoundError.prototype); let targetName: string; @@ -13,10 +14,12 @@ export class EntityMetadataNotFoundError extends Error { targetName = target.options.name; } else if (typeof target === "function") { targetName = target.name; + } else if (typeof target === "object" && "name" in target) { + targetName = target.name; } else { targetName = target; } this.message = `No metadata for "${targetName}" was found.`; } -} \ No newline at end of file +} diff --git a/src/error/EntityNotFoundError.ts b/src/error/EntityNotFoundError.ts index df6d21404ff..446b79aaabe 100644 --- a/src/error/EntityNotFoundError.ts +++ b/src/error/EntityNotFoundError.ts @@ -1,4 +1,4 @@ -import {ObjectType} from "../common/ObjectType"; +import {EntityTarget} from "../common/EntityTarget"; import {EntitySchema} from "../index"; /** @@ -7,7 +7,7 @@ import {EntitySchema} from "../index"; export class EntityNotFoundError extends Error { name = "EntityNotFound"; - constructor(entityClass: ObjectType|EntitySchema|string, criteria: any) { + constructor(entityClass: EntityTarget, criteria: any) { super(); Object.setPrototypeOf(this, EntityNotFoundError.prototype); let targetName: string; @@ -15,6 +15,8 @@ export class EntityNotFoundError extends Error { targetName = entityClass.options.name; } else if (typeof entityClass === "function") { targetName = entityClass.name; + } else if (typeof entityClass === "object" && "name" in entityClass) { + targetName = entityClass.name; } else { targetName = entityClass; } diff --git a/src/error/RepositoryNotFoundError.ts b/src/error/RepositoryNotFoundError.ts index 620078e751d..1a53bc06206 100644 --- a/src/error/RepositoryNotFoundError.ts +++ b/src/error/RepositoryNotFoundError.ts @@ -1,3 +1,4 @@ +import {EntityTarget} from "../common/EntityTarget"; import {EntitySchema} from "../index"; /** @@ -6,7 +7,7 @@ import {EntitySchema} from "../index"; export class RepositoryNotFoundError extends Error { name = "RepositoryNotFoundError"; - constructor(connectionName: string, entityClass: Function|EntitySchema|string) { + constructor(connectionName: string, entityClass: EntityTarget) { super(); Object.setPrototypeOf(this, RepositoryNotFoundError.prototype); let targetName: string; @@ -14,6 +15,8 @@ export class RepositoryNotFoundError extends Error { targetName = entityClass.options.name; } else if (typeof entityClass === "function") { targetName = entityClass.name; + } else if (typeof entityClass === "object" && "name" in entityClass) { + targetName = entityClass.name; } else { targetName = entityClass; } @@ -21,4 +24,4 @@ export class RepositoryNotFoundError extends Error { `current "${connectionName}" connection?`; } -} \ No newline at end of file +} diff --git a/src/error/RepositoryNotTreeError.ts b/src/error/RepositoryNotTreeError.ts index c1533ece2e6..082f01c7f34 100644 --- a/src/error/RepositoryNotTreeError.ts +++ b/src/error/RepositoryNotTreeError.ts @@ -1,3 +1,4 @@ +import {EntityTarget} from "../common/EntityTarget"; import {EntitySchema} from "../index"; /** @@ -6,18 +7,20 @@ import {EntitySchema} from "../index"; export class RepositoryNotTreeError extends Error { name = "RepositoryNotTreeError"; - constructor(target: Function|EntitySchema|string) { + constructor(entityClass: EntityTarget) { super(); Object.setPrototypeOf(this, RepositoryNotTreeError.prototype); let targetName: string; - if (target instanceof EntitySchema) { - targetName = target.options.name; - } else if (typeof target === "function") { - targetName = target.name; + if (entityClass instanceof EntitySchema) { + targetName = entityClass.options.name; + } else if (typeof entityClass === "function") { + targetName = entityClass.name; + } else if (typeof entityClass === "object" && "name" in entityClass) { + targetName = entityClass.name; } else { - targetName = target; + targetName = entityClass; } this.message = `Repository of the "${targetName}" class is not a TreeRepository. Try to apply @Tree decorator on your entity.`; } -} \ No newline at end of file +} diff --git a/src/index.ts b/src/index.ts index 749d53390cc..5407300bb22 100644 --- a/src/index.ts +++ b/src/index.ts @@ -17,13 +17,14 @@ import {PromiseUtils} from "./util/PromiseUtils"; import {MongoEntityManager} from "./entity-manager/MongoEntityManager"; import {SqljsEntityManager} from "./entity-manager/SqljsEntityManager"; import {SelectQueryBuilder} from "./query-builder/SelectQueryBuilder"; -import {EntitySchema} from "./entity-schema/EntitySchema"; +import {EntityTarget} from "./common/EntityTarget"; // ------------------------------------------------------------------------- // Commonly Used exports // ------------------------------------------------------------------------- export * from "./container"; +export * from "./common/EntityTarget"; export * from "./common/ObjectType"; export * from "./common/ObjectLiteral"; export * from "./common/DeepPartial"; @@ -283,14 +284,14 @@ export function getSqljsManager(connectionName: string = "default"): SqljsEntity /** * Gets repository for the given entity class. */ -export function getRepository(entityClass: ObjectType|EntitySchema|string, connectionName: string = "default"): Repository { +export function getRepository(entityClass: EntityTarget, connectionName: string = "default"): Repository { return getConnectionManager().get(connectionName).getRepository(entityClass); } /** * Gets tree repository for the given entity class. */ -export function getTreeRepository(entityClass: ObjectType|string, connectionName: string = "default"): TreeRepository { +export function getTreeRepository(entityClass: EntityTarget, connectionName: string = "default"): TreeRepository { return getConnectionManager().get(connectionName).getTreeRepository(entityClass); } @@ -304,14 +305,14 @@ export function getCustomRepository(customRepository: ObjectType, connecti /** * Gets mongodb repository for the given entity class or name. */ -export function getMongoRepository(entityClass: ObjectType|string, connectionName: string = "default"): MongoRepository { +export function getMongoRepository(entityClass: EntityTarget, connectionName: string = "default"): MongoRepository { return getConnectionManager().get(connectionName).getMongoRepository(entityClass); } /** * Creates a new query builder. */ -export function createQueryBuilder(entityClass?: ObjectType|string, alias?: string, connectionName: string = "default"): SelectQueryBuilder { +export function createQueryBuilder(entityClass?: EntityTarget, alias?: string, connectionName: string = "default"): SelectQueryBuilder { if (entityClass) { return getRepository(entityClass, connectionName).createQueryBuilder(alias); } diff --git a/src/metadata-args/EntityRepositoryMetadataArgs.ts b/src/metadata-args/EntityRepositoryMetadataArgs.ts index 1b7e3e0dbb3..fd55676630a 100644 --- a/src/metadata-args/EntityRepositoryMetadataArgs.ts +++ b/src/metadata-args/EntityRepositoryMetadataArgs.ts @@ -1,4 +1,4 @@ -import { EntitySchema } from "../entity-schema/EntitySchema"; +import { EntityTarget } from "../common/EntityTarget"; /** * Arguments for EntityRepositoryMetadata class, helps to construct an EntityRepositoryMetadata object. @@ -13,6 +13,6 @@ export interface EntityRepositoryMetadataArgs { /** * Entity managed by this custom repository. */ - readonly entity?: Function|string|EntitySchema; + readonly entity?: EntityTarget; } diff --git a/src/query-builder/DeleteQueryBuilder.ts b/src/query-builder/DeleteQueryBuilder.ts index e6efd9d6971..c4c1358d163 100644 --- a/src/query-builder/DeleteQueryBuilder.ts +++ b/src/query-builder/DeleteQueryBuilder.ts @@ -2,7 +2,7 @@ import {CockroachDriver} from "../driver/cockroachdb/CockroachDriver"; import {OracleDriver} from "../driver/oracle/OracleDriver"; import {QueryBuilder} from "./QueryBuilder"; import {ObjectLiteral} from "../common/ObjectLiteral"; -import {ObjectType} from "../common/ObjectType"; +import {EntityTarget} from "../common/EntityTarget"; import {Connection} from "../connection/Connection"; import {QueryRunner} from "../query-runner/QueryRunner"; import {SqlServerDriver} from "../driver/sqlserver/SqlServerDriver"; @@ -133,7 +133,7 @@ export class DeleteQueryBuilder extends QueryBuilder implements * Specifies FROM which entity's table select/update/delete will be executed. * Also sets a main string alias of the selection data. */ - from(entityTarget: ObjectType|EntitySchema|string, aliasName?: string): DeleteQueryBuilder { + from(entityTarget: EntityTarget, aliasName?: string): DeleteQueryBuilder { entityTarget = entityTarget instanceof EntitySchema ? entityTarget.options.name : entityTarget; const mainAlias = this.createFromAlias(entityTarget, aliasName); this.expressionMap.setMainAlias(mainAlias); diff --git a/src/query-builder/InsertQueryBuilder.ts b/src/query-builder/InsertQueryBuilder.ts index 106cd41494b..8192293f627 100644 --- a/src/query-builder/InsertQueryBuilder.ts +++ b/src/query-builder/InsertQueryBuilder.ts @@ -2,7 +2,7 @@ import {CockroachDriver} from "../driver/cockroachdb/CockroachDriver"; import {SapDriver} from "../driver/sap/SapDriver"; import {QueryBuilder} from "./QueryBuilder"; import {ObjectLiteral} from "../common/ObjectLiteral"; -import {ObjectType} from "../common/ObjectType"; +import {EntityTarget} from "../common/EntityTarget"; import {QueryDeepPartialEntity} from "./QueryPartialEntity"; import {SqlServerDriver} from "../driver/sqlserver/SqlServerDriver"; import {PostgresDriver} from "../driver/postgres/PostgresDriver"; @@ -164,7 +164,7 @@ export class InsertQueryBuilder extends QueryBuilder { /** * Specifies INTO which entity's table insertion will be executed. */ - into(entityTarget: ObjectType|EntitySchema|string, columns?: string[]): InsertQueryBuilder { + into(entityTarget: EntityTarget, columns?: string[]): InsertQueryBuilder { entityTarget = entityTarget instanceof EntitySchema ? entityTarget.options.name : entityTarget; const mainAlias = this.createFromAlias(entityTarget); this.expressionMap.setMainAlias(mainAlias); diff --git a/src/query-builder/QueryBuilder.ts b/src/query-builder/QueryBuilder.ts index 21ae390277e..c883b5ad074 100644 --- a/src/query-builder/QueryBuilder.ts +++ b/src/query-builder/QueryBuilder.ts @@ -8,7 +8,7 @@ import {DeleteQueryBuilder} from "./DeleteQueryBuilder"; import {SoftDeleteQueryBuilder} from "./SoftDeleteQueryBuilder"; import {InsertQueryBuilder} from "./InsertQueryBuilder"; import {RelationQueryBuilder} from "./RelationQueryBuilder"; -import {ObjectType} from "../common/ObjectType"; +import {EntityTarget} from "../common/EntityTarget"; import {Alias} from "./Alias"; import {Brackets} from "./Brackets"; import {QueryDeepPartialEntity} from "./QueryPartialEntity"; @@ -187,17 +187,7 @@ export abstract class QueryBuilder { /** * Creates UPDATE query for the given entity and applies given update values. */ - update(entity: ObjectType, updateSet?: QueryDeepPartialEntity): UpdateQueryBuilder; - - /** - * Creates UPDATE query for the given entity and applies given update values. - */ - update(entity: EntitySchema, updateSet?: QueryDeepPartialEntity): UpdateQueryBuilder; - - /** - * Creates UPDATE query for the given entity and applies given update values. - */ - update(entity: Function|EntitySchema|string, updateSet?: QueryDeepPartialEntity): UpdateQueryBuilder; + update(entity: EntityTarget, updateSet?: QueryDeepPartialEntity): UpdateQueryBuilder; /** * Creates UPDATE query for the given table name and applies given update values. @@ -207,7 +197,7 @@ export abstract class QueryBuilder { /** * Creates UPDATE query and applies given update values. */ - update(entityOrTableNameUpdateSet?: string|Function|EntitySchema|ObjectLiteral, maybeUpdateSet?: ObjectLiteral): UpdateQueryBuilder { + update(entityOrTableNameUpdateSet?: EntityTarget|ObjectLiteral, maybeUpdateSet?: ObjectLiteral): UpdateQueryBuilder { const updateSet = maybeUpdateSet ? maybeUpdateSet : entityOrTableNameUpdateSet as ObjectLiteral|undefined; entityOrTableNameUpdateSet = entityOrTableNameUpdateSet instanceof EntitySchema ? entityOrTableNameUpdateSet.options.name : entityOrTableNameUpdateSet; @@ -271,7 +261,7 @@ export abstract class QueryBuilder { /** * Sets entity's relation with which this query builder gonna work. */ - relation(entityTarget: ObjectType|string, propertyPath: string): RelationQueryBuilder; + relation(entityTarget: EntityTarget, propertyPath: string): RelationQueryBuilder; /** * Sets entity's relation with which this query builder gonna work. @@ -303,7 +293,7 @@ export abstract class QueryBuilder { * * todo: move this method to manager? or create a shortcut? */ - hasRelation(target: ObjectType|string, relation: string): boolean; + hasRelation(target: EntityTarget, relation: string): boolean; /** * Checks if given relations exist in the entity. @@ -311,7 +301,7 @@ export abstract class QueryBuilder { * * todo: move this method to manager? or create a shortcut? */ - hasRelation(target: ObjectType|string, relation: string[]): boolean; + hasRelation(target: EntityTarget, relation: string[]): boolean; /** * Checks if given relation or relations exist in the entity. @@ -319,7 +309,7 @@ export abstract class QueryBuilder { * * todo: move this method to manager? or create a shortcut? */ - hasRelation(target: ObjectType|string, relation: string|string[]): boolean { + hasRelation(target: EntityTarget, relation: string|string[]): boolean { const entityMetadata = this.connection.getMetadata(target); const relations = Array.isArray(relation) ? relation : [relation]; return relations.every(relation => { @@ -532,7 +522,7 @@ export abstract class QueryBuilder { * Specifies FROM which entity's table select/update/delete will be executed. * Also sets a main string alias of the selection data. */ - protected createFromAlias(entityTarget: Function|string|((qb: SelectQueryBuilder) => SelectQueryBuilder), aliasName?: string): Alias { + protected createFromAlias(entityTarget: EntityTarget|((qb: SelectQueryBuilder) => SelectQueryBuilder), aliasName?: string): Alias { // if table has a metadata then find it to properly escape its properties // const metadata = this.connection.entityMetadatas.find(metadata => metadata.tableName === tableName); @@ -547,21 +537,25 @@ export abstract class QueryBuilder { }); } else { - let subQuery: string = ""; - if (entityTarget instanceof Function) { - const subQueryBuilder: SelectQueryBuilder = (entityTarget as any)(((this as any) as SelectQueryBuilder).subQuery()); - this.setParameters(subQueryBuilder.getParameters()); - subQuery = subQueryBuilder.getQuery(); - - } else { - subQuery = entityTarget; + if (typeof entityTarget === "string") { + const isSubquery = entityTarget.substr(0, 1) === "(" && entityTarget.substr(-1) === ")"; + + return this.expressionMap.createAlias({ + type: "from", + name: aliasName, + tablePath: !isSubquery ? entityTarget as string : undefined, + subQuery: isSubquery ? entityTarget : undefined, + }); } - const isSubQuery = entityTarget instanceof Function || entityTarget.substr(0, 1) === "(" && entityTarget.substr(-1) === ")"; + + const subQueryBuilder: SelectQueryBuilder = (entityTarget as any)(((this as any) as SelectQueryBuilder).subQuery()); + this.setParameters(subQueryBuilder.getParameters()); + const subquery = subQueryBuilder.getQuery(); + return this.expressionMap.createAlias({ type: "from", name: aliasName, - tablePath: isSubQuery === false ? entityTarget as string : undefined, - subQuery: isSubQuery === true ? subQuery : undefined, + subQuery: subquery }); } } diff --git a/src/query-builder/SelectQueryBuilder.ts b/src/query-builder/SelectQueryBuilder.ts index 9a87ac832a6..821be3186c3 100644 --- a/src/query-builder/SelectQueryBuilder.ts +++ b/src/query-builder/SelectQueryBuilder.ts @@ -24,7 +24,7 @@ import {EntityMetadata} from "../metadata/EntityMetadata"; import {ColumnMetadata} from "../metadata/ColumnMetadata"; import {OrderByCondition} from "../find-options/OrderByCondition"; import {QueryExpressionMap} from "./QueryExpressionMap"; -import {ObjectType} from "../common/ObjectType"; +import {EntityTarget} from "../common/EntityTarget"; import {QueryRunner} from "../query-runner/QueryRunner"; import {WhereExpression} from "./WhereExpression"; import {Brackets} from "./Brackets"; @@ -188,14 +188,14 @@ export class SelectQueryBuilder extends QueryBuilder implements * Also sets a main string alias of the selection data. * Removes all previously set from-s. */ - from(entityTarget: ObjectType|string, aliasName: string): SelectQueryBuilder; + from(entityTarget: EntityTarget, aliasName: string): SelectQueryBuilder; /** * Specifies FROM which entity's table select/update/delete will be executed. * Also sets a main string alias of the selection data. * Removes all previously set from-s. */ - from(entityTarget: ObjectType|string|((qb: SelectQueryBuilder) => SelectQueryBuilder), aliasName: string): SelectQueryBuilder { + from(entityTarget: EntityTarget|((qb: SelectQueryBuilder) => SelectQueryBuilder), aliasName: string): SelectQueryBuilder { const mainAlias = this.createFromAlias(entityTarget, aliasName); this.expressionMap.setMainAlias(mainAlias); return (this as any) as SelectQueryBuilder; @@ -211,13 +211,13 @@ export class SelectQueryBuilder extends QueryBuilder implements * Specifies FROM which entity's table select/update/delete will be executed. * Also sets a main string alias of the selection data. */ - addFrom(entityTarget: ObjectType|string, aliasName: string): SelectQueryBuilder; + addFrom(entityTarget: EntityTarget, aliasName: string): SelectQueryBuilder; /** * Specifies FROM which entity's table select/update/delete will be executed. * Also sets a main string alias of the selection data. */ - addFrom(entityTarget: ObjectType|string|((qb: SelectQueryBuilder) => SelectQueryBuilder), aliasName: string): SelectQueryBuilder { + addFrom(entityTarget: EntityTarget|((qb: SelectQueryBuilder) => SelectQueryBuilder), aliasName: string): SelectQueryBuilder { const alias = this.createFromAlias(entityTarget, aliasName); if (!this.expressionMap.mainAlias) this.expressionMap.setMainAlias(alias); diff --git a/src/query-builder/SoftDeleteQueryBuilder.ts b/src/query-builder/SoftDeleteQueryBuilder.ts index 3f5b903f486..f4e54395cfa 100644 --- a/src/query-builder/SoftDeleteQueryBuilder.ts +++ b/src/query-builder/SoftDeleteQueryBuilder.ts @@ -1,7 +1,7 @@ import {CockroachDriver} from "../driver/cockroachdb/CockroachDriver"; import {QueryBuilder} from "./QueryBuilder"; import {ObjectLiteral} from "../common/ObjectLiteral"; -import {ObjectType} from "../common/ObjectType"; +import {EntityTarget} from "../common/EntityTarget"; import {Connection} from "../connection/Connection"; import {QueryRunner} from "../query-runner/QueryRunner"; import {SqlServerDriver} from "../driver/sqlserver/SqlServerDriver"; @@ -142,7 +142,7 @@ export class SoftDeleteQueryBuilder extends QueryBuilder impleme * Specifies FROM which entity's table select/update/delete/soft-delete will be executed. * Also sets a main string alias of the selection data. */ - from(entityTarget: ObjectType|EntitySchema|string, aliasName?: string): SoftDeleteQueryBuilder { + from(entityTarget: EntityTarget, aliasName?: string): SoftDeleteQueryBuilder { entityTarget = entityTarget instanceof EntitySchema ? entityTarget.options.name : entityTarget; const mainAlias = this.createFromAlias(entityTarget, aliasName); this.expressionMap.setMainAlias(mainAlias); diff --git a/src/repository/AbstractRepository.ts b/src/repository/AbstractRepository.ts index 87005cb0a93..789368f2b9b 100644 --- a/src/repository/AbstractRepository.ts +++ b/src/repository/AbstractRepository.ts @@ -2,12 +2,12 @@ import {ObjectLiteral} from "../common/ObjectLiteral"; import {EntityManager} from "../entity-manager/EntityManager"; import {Repository} from "./Repository"; import {TreeRepository} from "./TreeRepository"; +import {EntityTarget} from "../common/EntityTarget"; import {ObjectType} from "../common/ObjectType"; import {CustomRepositoryDoesNotHaveEntityError} from "../error/CustomRepositoryDoesNotHaveEntityError"; import {getMetadataArgsStorage} from "../index"; import {CustomRepositoryNotFoundError} from "../error/CustomRepositoryNotFoundError"; import {SelectQueryBuilder} from "../query-builder/SelectQueryBuilder"; -import { EntitySchema } from "../entity-schema/EntitySchema"; /** * Provides abstract class for custom repositories that do not inherit from original orm Repository. @@ -100,7 +100,7 @@ export class AbstractRepository { * Gets custom repository's managed entity. * If given custom repository does not manage any entity then undefined will be returned. */ - private getCustomRepositoryTarget(customRepository: any): Function|string|EntitySchema|undefined { + private getCustomRepositoryTarget(customRepository: any): EntityTarget|undefined { const entityRepositoryMetadataArgs = getMetadataArgsStorage().entityRepositories.find(repository => { return repository.target === (customRepository instanceof Function ? customRepository : (customRepository as any).constructor); }); @@ -110,4 +110,4 @@ export class AbstractRepository { return entityRepositoryMetadataArgs.entity; } -} \ No newline at end of file +} diff --git a/src/repository/Repository.ts b/src/repository/Repository.ts index b8ad4390b25..96c9223fa73 100644 --- a/src/repository/Repository.ts +++ b/src/repository/Repository.ts @@ -147,7 +147,7 @@ export class Repository { * Saves one or many given entities. */ save>(entityOrEntities: T|T[], options?: SaveOptions): Promise { - return this.manager.save(this.metadata.target as any, entityOrEntities as any, options); + return this.manager.save(this.metadata.target as any, entityOrEntities as any, options); } /** @@ -191,7 +191,7 @@ export class Repository { * Records the delete date of one or many given entities. */ softRemove>(entityOrEntities: T|T[], options?: SaveOptions): Promise { - return this.manager.softRemove(this.metadata.target as any, entityOrEntities as any, options); + return this.manager.softRemove(this.metadata.target as any, entityOrEntities as any, options); } /** @@ -218,7 +218,7 @@ export class Repository { * Recovers one or many given entities. */ recover>(entityOrEntities: T|T[], options?: SaveOptions): Promise { - return this.manager.recover(this.metadata.target as any, entityOrEntities as any, options); + return this.manager.recover(this.metadata.target as any, entityOrEntities as any, options); } /** From 330262d9a4a8a5e261885ec546bd3976d78bb9d9 Mon Sep 17 00:00:00 2001 From: James Ward Date: Sat, 12 Sep 2020 16:31:26 -0400 Subject: [PATCH 068/212] chore: bump all package versions except typescript (#6696) also updates some tests to support typing changes --- .eslintrc.js | 2 +- package-lock.json | 7565 ++++++++++------- package.json | 90 +- src/index.ts | 5 - .../ReturningResultsEntityUpdator.ts | 2 +- .../basic-methods/repository-basic-methods.ts | 4 +- test/github-issues/1014/issue-1014.ts | 4 +- test/github-issues/1123/issue-1123.ts | 2 +- test/github-issues/4156/issue-4156.ts | 4 +- 9 files changed, 4618 insertions(+), 3060 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 6abd1a7f021..06473d20bf9 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -30,6 +30,7 @@ module.exports = { "error" ], "@typescript-eslint/type-annotation-spacing": "error", + "@typescript-eslint/no-redeclare": "error", "eqeqeq": [ "error", "smart" @@ -48,7 +49,6 @@ module.exports = { ], "id-match": "error", "no-eval": "error", - "no-redeclare": "error", "no-var": "error" } }; diff --git a/package-lock.json b/package-lock.json index d0a7186083e..e81e794aded 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,6 +4,47 @@ "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==", + "dev": true + }, + "@azure/ms-rest-js": { + "version": "1.8.15", + "resolved": "https://registry.npmjs.org/@azure/ms-rest-js/-/ms-rest-js-1.8.15.tgz", + "integrity": "sha512-kIB71V3DcrA4iysBbOsYcxd4WWlOE7OFtCUYNfflPODM0lbIR23A236QeTn5iAeYwcHmMjR/TAKp5KQQh/WqoQ==", + "dev": true, + "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" + }, + "dependencies": { + "tslib": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz", + "integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==", + "dev": true + } + } + }, + "@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==", + "dev": true, + "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.10.4", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", @@ -30,21 +71,82 @@ "js-tokens": "^4.0.0" }, "dependencies": { + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } } } }, - "@babel/runtime": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.0.0.tgz", - "integrity": "sha512-7hGhzlcmg01CvH1EHdSPVXYX1aJ8KCEyz6I9xYIi/asDtzBPMyMhVibhM/K6g/5qnKBwjZtp10bNZIEFTRW1MA==", + "@eslint/eslintrc": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.1.3.tgz", + "integrity": "sha512-4YVwPkANLeNtRjMekzux1ci8hIaH5eGKktGqR0d3LWsKNn5B2X/1Z6Trxy7jQXl9EBGE6Yj02O+t09FMeRllaA==", "dev": true, "requires": { - "regenerator-runtime": "^0.12.0" + "ajv": "^6.12.4", + "debug": "^4.1.1", + "espree": "^7.3.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.2.1", + "js-yaml": "^3.13.1", + "lodash": "^4.17.19", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + }, + "dependencies": { + "ajv": { + "version": "6.12.4", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.4.tgz", + "integrity": "sha512-eienB2c9qVQs2KWexhkrdMLVDoIQCz5KSeLxwg9Lzk4DOfBtIK9PQwwufcsn1jjGuf9WZmqPMbGxOzfcuphJCQ==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + } } }, "@gulp-sourcemaps/identity-map": { @@ -78,110 +180,69 @@ "through2": "^2.0.3" } }, - "@iamstarkov/listr-update-renderer": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@iamstarkov/listr-update-renderer/-/listr-update-renderer-0.4.1.tgz", - "integrity": "sha512-IJyxQWsYDEkf8C8QthBn5N8tIUR9V9je6j3sMIpAkonaadjbvxmRC6RAhpa3RKxndhNnU2M6iNbtJwd7usQYIA==", + "@nodelib/fs.scandir": { + "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": { - "chalk": "^1.1.3", - "cli-truncate": "^0.2.1", - "elegant-spinner": "^1.0.1", - "figures": "^1.7.0", - "indent-string": "^3.0.0", - "log-symbols": "^1.0.2", - "log-update": "^2.3.0", - "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 - }, - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "log-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-1.0.2.tgz", - "integrity": "sha1-N2/3tY6jCGoPCfrMdGF+ylAeGhg=", - "dev": true, - "requires": { - "chalk": "^1.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" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true - } + "@nodelib/fs.stat": "2.0.3", + "run-parallel": "^1.1.9" } }, - "@samverschueren/stream-to-observable": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@samverschueren/stream-to-observable/-/stream-to-observable-0.3.0.tgz", - "integrity": "sha512-MI4Xx6LHs4Webyvi6EbspgyAb4D2Q2VtnCQ1blOJcoLS6mVa8lNN2rkIy1CVxfTUpoyIbCTkXES1rLXztFD1lg==", + "@nodelib/fs.stat": { + "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.4", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz", + "integrity": "sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ==", "dev": true, "requires": { - "any-observable": "^0.3.0" + "@nodelib/fs.scandir": "2.1.3", + "fastq": "^1.6.0" } }, "@sinonjs/commons": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.3.1.tgz", - "integrity": "sha512-rgmZk5CrBGAMATk0HlHOFvo8V44/r+On6cKS80tqid0Eljd+fFBWBOXZp9H2/EB3faxdNdzXTx6QZIKLkbJ7mA==", + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.1.tgz", + "integrity": "sha512-892K+kWUUi3cl+LlqEWIDrhvLgdL79tECi8JZUyq6IviKy/DNhuzCRlbHUjxK89f4ypPMMaFnFuR9Ie6DoIMsw==", "dev": true, "requires": { "type-detect": "4.0.8" } }, + "@sinonjs/fake-timers": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz", + "integrity": "sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.7.0" + } + }, "@sinonjs/formatio": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-3.2.0.tgz", - "integrity": "sha512-hskkZG4qB0HgsxrPUlnk2EiIyBwntM+ETIxCha/gidl172MCfdosNezB5706ciS5P2VhueM7MoACWwMc4A4gMQ==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-5.0.1.tgz", + "integrity": "sha512-KaiQ5pBf1MpS09MuA0kp6KBQt2JUOQycqVG1NZXvzeaXe5LGFqAKueIS0bw4w0P9r7KuBSVdUk5QjXsUdu2CxQ==", "dev": true, "requires": { "@sinonjs/commons": "^1", - "@sinonjs/samsam": "^3.1.0" + "@sinonjs/samsam": "^5.0.2" } }, "@sinonjs/samsam": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-3.2.0.tgz", - "integrity": "sha512-j5F1rScewLtx6pbTK0UAjA3jJj4RYiSKOix53YWv+Jzy/AZ69qHxUpU8fwVLjyKbEEud9QrLpv6Ggs7WqTimYw==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-5.1.0.tgz", + "integrity": "sha512-42nyaQOVunX5Pm6GRJobmzbS7iLI+fhERITnETXzzwDZh+TtDr/Au3yAvXVjFmZ4wEUaE4Y3NFZfKv0bV0cbtg==", "dev": true, "requires": { - "@sinonjs/commons": "^1.0.2", - "array-from": "^2.1.1", - "lodash": "^4.17.11" + "@sinonjs/commons": "^1.6.0", + "lodash.get": "^4.4.2", + "type-detect": "^4.0.8" } }, "@sinonjs/text-encoding": { @@ -197,15 +258,15 @@ "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.12", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.2.12.tgz", + "integrity": "sha512-aN5IAC8QNtSUdQzxu7lGBgYAOuU1tmRU4c9dIq5OKGf/SBVjXo+ffM2wEjudAWbgpOhy60nLoAGH1xm8fpCKFQ==", "dev": true }, "@types/chai-as-promised": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@types/chai-as-promised/-/chai-as-promised-7.1.0.tgz", - "integrity": "sha512-MFiW54UOSt+f2bRw8J7LgQeIvE/9b4oGvwU7XW30S9QGAiHGnU/fmiOprsyMkdmH2rl8xSPc0/yrQw8juXU6bQ==", + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/@types/chai-as-promised/-/chai-as-promised-7.1.3.tgz", + "integrity": "sha512-FQnh1ohPXJELpKhzjuDkPLR2BZCAqed+a6xV4MI/T3XzHfd2FlarfUGUdZYgqYe8oxkYn0fchHEeHfHqdZ96sg==", "dev": true, "requires": { "@types/chai": "*" @@ -224,13 +285,12 @@ "@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==", - "dev": true + "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==" }, "@types/debug": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.2.tgz", - "integrity": "sha512-jkf6UiWUjcOqdQbatbvOm54/YbCdjt3JjiAzT/9KS2XtMmOkYHdKsI5u8fulhbuTUuiqNBfa6J5GSDiwjK+zLA==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.5.tgz", + "integrity": "sha512-Q1y515GcOdTHgagaVFhHnIFQ38ygs/kmxdNpvpou+raI9UO3YZcHDngBSYKQklcKlvA7iuQlmIKbzvmxcOE9CQ==", "dev": true }, "@types/dotenv": { @@ -242,12 +302,6 @@ "dotenv": "*" } }, - "@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/events": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@types/events/-/events-1.2.0.tgz", @@ -293,9 +347,9 @@ "dev": true }, "@types/json-schema": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.5.tgz", - "integrity": "sha512-7+2BITlgjgDhH0vvwZU/HZJVyk+2XUlvxXe8dFMedNX/aMkaOq++rMAFXc0tM7ij15QaWlbdQASBR9dihi+bDQ==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.6.tgz", + "integrity": "sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw==", "dev": true }, "@types/merge2": { @@ -313,6 +367,12 @@ "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", "dev": true }, + "@types/minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-aaI6OtKcrwCX8G7aWbNh7i8GOfY=", + "dev": true + }, "@types/mkdirp": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@types/mkdirp/-/mkdirp-1.0.1.tgz", @@ -323,21 +383,43 @@ } }, "@types/mocha": { - "version": "5.2.6", - "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.6.tgz", - "integrity": "sha512-1axi39YdtBI7z957vdqXI4Ac25e7YihYQtJa+Clnxg1zTJEaIRbndt71O3sP4GAMgiAm0pY26/b9BrY4MR/PMw==", + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-8.0.3.tgz", + "integrity": "sha512-vyxR57nv8NfcU0GZu8EUXZLTbCMupIUwy95LJ6lllN+JRPG25CwMHoB1q5xKh8YKhQnHYRAn4yW2yuHbf/5xgg==", "dev": true }, "@types/node": { - "version": "9.6.42", - "resolved": "https://registry.npmjs.org/@types/node/-/node-9.6.42.tgz", - "integrity": "sha512-SpeVQJFekfnEaZZO1yl4je/36upII36L7gOT4DBx51B1GeAB45mmDb3a5OBQB+ZeFxVVOP37r8Owsl940G/fBg==", + "version": "14.6.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.6.4.tgz", + "integrity": "sha512-Wk7nG1JSaMfMpoMJDKUsWYugliB2Vy55pdjLpmLixeyMi7HizW2I/9QoxsPCkXl3dO+ZOVqPumKaDUv5zJu2uQ==", + "dev": true + }, + "@types/normalize-package-data": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz", + "integrity": "sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==", + "dev": true + }, + "@types/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", "dev": true }, + "@types/readable-stream": { + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/@types/readable-stream/-/readable-stream-2.3.9.tgz", + "integrity": "sha512-sqsgQqFT7HmQz/V5jH1O0fvQQnXAJO46Gg9LRO/JPfjmVmGUlcx831TZZO3Y3HtWhIkzf3kTsNT0Z0kzIhIvZw==", + "dev": true, + "requires": { + "@types/node": "*", + "safe-buffer": "*" + } + }, "@types/rimraf": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@types/rimraf/-/rimraf-2.0.2.tgz", - "integrity": "sha512-Hm/bnWq0TCy7jmjeN5bKYij9vw5GrDFWME4IuxV08278NtU/VdGbzsBohcCUJ7+QMqmUq5hpRKB39HeQWJjztQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/rimraf/-/rimraf-3.0.0.tgz", + "integrity": "sha512-7WhJ0MdpFgYQPXlF4Dx+DhgvlPCfz/x5mHaeDQAKhcenvQP1KCpLQ18JklAqeGMYSAT2PxLpzd0g2/HE7fj7hQ==", "dev": true, "requires": { "@types/glob": "*", @@ -354,15 +436,41 @@ } }, "@types/sinon": { - "version": "7.0.8", - "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-7.0.8.tgz", - "integrity": "sha512-v8HKmpYANbS3y0cWji16uk/CV9v2CqpI+wxeW7WVZPU2E8MAcvBYbCBpeukhaWPRHbTO3tu8m6vb2IXWCbEUOQ==", + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-9.0.5.tgz", + "integrity": "sha512-4CnkGdM/5/FXDGqL32JQ1ttVrGvhOoesLLF7VnTh4KdjK5N5VQOtxaylFqqTjnHx55MnD9O02Nbk5c1ELC8wlQ==", + "dev": true, + "requires": { + "@types/sinonjs__fake-timers": "*" + } + }, + "@types/sinonjs__fake-timers": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-6.0.1.tgz", + "integrity": "sha512-yYezQwGWty8ziyYLdZjwxyMb0CZR49h8JALHGrxjQHWlqGgc8kLdHEgWrgL0uZ29DMvEVBDnHU2Wg36zKSIUtA==", "dev": true }, "@types/source-map-support": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/@types/source-map-support/-/source-map-support-0.4.2.tgz", - "integrity": "sha512-GbGWx39O8NdUHSChdrU0XeigBAgu1Teg3llwE0slSVcH2qISaQT70ftAiH+h4HIt3VIObFU34PSpXIKJuXCybQ==", + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/@types/source-map-support/-/source-map-support-0.5.3.tgz", + "integrity": "sha512-fvjMjVH8Rmokw2dWh1dkj90iX5R8FPjeZzjNH+6eFXReh0QnHFf1YBl3B0CF0RohIAA3SDRJsGeeUWKl6d7HqA==", + "dev": true, + "requires": { + "source-map": "^0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "@types/tunnel": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/@types/tunnel/-/tunnel-0.0.0.tgz", + "integrity": "sha512-FGDp0iBRiBdPjOgjJmn1NH0KDLN+Z8fRmo+9J7XGBhubq1DPrGrbmG4UTlGzrpbCpesMqD0sWkzi27EYkOMHyg==", "dev": true, "requires": { "@types/node": "*" @@ -415,18 +523,28 @@ } }, "@types/yargs": { - "version": "12.0.9", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-12.0.9.tgz", - "integrity": "sha512-sCZy4SxP9rN2w30Hlmg5dtdRwgYQfYRiLo9usw8X9cxlf+H4FqM1xX7+sNH7NNKVdbXMJWqva7iyy+fxh/V7fA==", + "version": "15.0.5", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.5.tgz", + "integrity": "sha512-Dk/IDOPtOgubt/IaevIUbTgV7doaKkoorvOyYM2CMwuDyP89bekI7H4xLIwunNYiK9jhCkmc6pUrJk3cj2AB9w==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "@types/yargs-parser": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-15.0.0.tgz", + "integrity": "sha512-FA/BWv8t8ZWJ+gEOnLLd8ygxH/2UFbAvgEonyfN6yWGLKc7zVjbpl2Y4CTjid9h2RfgPP6SEt6uHwEOply00yw==", "dev": true }, "@typescript-eslint/eslint-plugin": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-3.7.0.tgz", - "integrity": "sha512-4OEcPON3QIx0ntsuiuFP/TkldmBGXf0uKxPQlGtS/W2F3ndYm8Vgdpj/woPJkzUc65gd3iR+qi3K8SDQP/obFg==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.1.0.tgz", + "integrity": "sha512-U+nRJx8XDUqJxYF0FCXbpmD9nWt/xHDDG0zsw1vrVYAmEAuD/r49iowfurjSL2uTA2JsgtpsyG7mjO7PHf2dYw==", "dev": true, "requires": { - "@typescript-eslint/experimental-utils": "3.7.0", + "@typescript-eslint/experimental-utils": "4.1.0", + "@typescript-eslint/scope-manager": "4.1.0", "debug": "^4.1.1", "functional-red-black-tree": "^1.0.1", "regexpp": "^3.0.0", @@ -439,80 +557,87 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", "dev": true - }, - "tsutils": { - "version": "3.17.1", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.17.1.tgz", - "integrity": "sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g==", - "dev": true, - "requires": { - "tslib": "^1.8.1" - } } } }, "@typescript-eslint/experimental-utils": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-3.7.0.tgz", - "integrity": "sha512-xpfXXAfZqhhqs5RPQBfAFrWDHoNxD5+sVB5A46TF58Bq1hRfVROrWHcQHHUM9aCBdy9+cwATcvCbRg8aIRbaHQ==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.1.0.tgz", + "integrity": "sha512-paEYLA37iqRIDPeQwAmoYSiZ3PiHsaAc3igFeBTeqRHgPnHjHLJ9OGdmP6nwAkF65p2QzEsEBtpjNUBWByNWzA==", "dev": true, "requires": { "@types/json-schema": "^7.0.3", - "@typescript-eslint/types": "3.7.0", - "@typescript-eslint/typescript-estree": "3.7.0", + "@typescript-eslint/scope-manager": "4.1.0", + "@typescript-eslint/types": "4.1.0", + "@typescript-eslint/typescript-estree": "4.1.0", "eslint-scope": "^5.0.0", "eslint-utils": "^2.0.0" } }, "@typescript-eslint/parser": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-3.7.0.tgz", - "integrity": "sha512-2LZauVUt7jAWkcIW7djUc3kyW+fSarNEuM3RF2JdLHR9BfX/nDEnyA4/uWz0wseoWVZbDXDF7iF9Jc342flNqQ==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.1.0.tgz", + "integrity": "sha512-hM/WNCQTzDHgS0Ke3cR9zPndL3OTKr9OoN9CL3UqulsAjYDrglSwIIgswSmHBcSbOzLmgaMARwrQEbIumIglvQ==", "dev": true, "requires": { - "@types/eslint-visitor-keys": "^1.0.0", - "@typescript-eslint/experimental-utils": "3.7.0", - "@typescript-eslint/types": "3.7.0", - "@typescript-eslint/typescript-estree": "3.7.0", - "eslint-visitor-keys": "^1.1.0" + "@typescript-eslint/scope-manager": "4.1.0", + "@typescript-eslint/types": "4.1.0", + "@typescript-eslint/typescript-estree": "4.1.0", + "debug": "^4.1.1" + } + }, + "@typescript-eslint/scope-manager": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.1.0.tgz", + "integrity": "sha512-HD1/u8vFNnxwiHqlWKC/Pigdn0Mvxi84Y6GzbZ5f5sbLrFKu0al02573Er+D63Sw67IffVUXR0uR8rpdfdk+vA==", + "dev": true, + "requires": { + "@typescript-eslint/types": "4.1.0", + "@typescript-eslint/visitor-keys": "4.1.0" } }, "@typescript-eslint/types": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-3.7.0.tgz", - "integrity": "sha512-reCaK+hyKkKF+itoylAnLzFeNYAEktB0XVfSQvf0gcVgpz1l49Lt6Vo9x4MVCCxiDydA0iLAjTF/ODH0pbfnpg==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.1.0.tgz", + "integrity": "sha512-rkBqWsO7m01XckP9R2YHVN8mySOKKY2cophGM8K5uDK89ArCgahItQYdbg/3n8xMxzu2elss+an1TphlUpDuJw==", "dev": true }, "@typescript-eslint/typescript-estree": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-3.7.0.tgz", - "integrity": "sha512-xr5oobkYRebejlACGr1TJ0Z/r0a2/HUf0SXqPvlgUMwiMqOCu/J+/Dr9U3T0IxpE5oLFSkqMx1FE/dKaZ8KsOQ==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.1.0.tgz", + "integrity": "sha512-r6et57qqKAWU173nWyw31x7OfgmKfMEcjJl9vlJEzS+kf9uKNRr4AVTRXfTCwebr7bdiVEkfRY5xGnpPaNPe4Q==", "dev": true, "requires": { - "@typescript-eslint/types": "3.7.0", - "@typescript-eslint/visitor-keys": "3.7.0", + "@typescript-eslint/types": "4.1.0", + "@typescript-eslint/visitor-keys": "4.1.0", "debug": "^4.1.1", - "glob": "^7.1.6", + "globby": "^11.0.1", "is-glob": "^4.0.1", "lodash": "^4.17.15", "semver": "^7.3.2", "tsutils": "^3.17.1" }, "dependencies": { - "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "globby": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.1.tgz", + "integrity": "sha512-iH9RmgwCmUJHi2z5o2l3eTtGBtXek1OYlHrbcxOYugyHLmAsZrPj43OtHThd62Buh/Vv6VyCBD2bdyWcGNQqoQ==", "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" + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.1.1", + "ignore": "^5.1.4", + "merge2": "^1.3.0", + "slash": "^3.0.0" } }, + "ignore": { + "version": "5.1.8", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", + "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", + "dev": true + }, "is-glob": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", @@ -522,30 +647,36 @@ "is-extglob": "^2.1.1" } }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true + }, "semver": { "version": "7.3.2", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", "dev": true - }, - "tsutils": { - "version": "3.17.1", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.17.1.tgz", - "integrity": "sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g==", - "dev": true, - "requires": { - "tslib": "^1.8.1" - } } } }, "@typescript-eslint/visitor-keys": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-3.7.0.tgz", - "integrity": "sha512-k5PiZdB4vklUpUX4NBncn5RBKty8G3ihTY+hqJsCdMuD0v4jofI5xuqwnVcWxfv6iTm2P/dfEa2wMUnsUY8ODw==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.1.0.tgz", + "integrity": "sha512-+taO0IZGCtCEsuNTTF2Q/5o8+fHrlml8i9YsZt2AiDCdYEJzYlsmRY991l/6f3jNXFyAWepdQj7n8Na6URiDRQ==", "dev": true, "requires": { - "eslint-visitor-keys": "^1.1.0" + "@typescript-eslint/types": "4.1.0", + "eslint-visitor-keys": "^2.0.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz", + "integrity": "sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==", + "dev": true + } } }, "JSONStream": { @@ -576,12 +707,55 @@ "integrity": "sha512-HiUX/+K2YpkpJ+SzBffkM/AQ2YE03S0U1kjTLVpoJdhZMOWy8qvXVN9JdLqv2QsaQ6MPYQIuNmwD8zOiYUofLQ==", "dev": true }, + "adal-node": { + "version": "0.1.28", + "resolved": "https://registry.npmjs.org/adal-node/-/adal-node-0.1.28.tgz", + "integrity": "sha1-RoxLs+u9lrEnBmn0ucuk4AZepIU=", + "dev": true, + "requires": { + "@types/node": "^8.0.47", + "async": ">=0.6.0", + "date-utils": "*", + "jws": "3.x.x", + "request": ">= 2.52.0", + "underscore": ">= 1.3.1", + "uuid": "^3.1.0", + "xmldom": ">= 0.1.x", + "xpath.js": "~1.1.0" + }, + "dependencies": { + "@types/node": { + "version": "8.10.63", + "resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.63.tgz", + "integrity": "sha512-g+nSkeHFDd2WOQChfmy9SAXLywT47WZBrGS/NC5ym5PJ8c8RC6l4pbGaUW/X0+eZJnXw6/AVNEouXWhV4iz72Q==", + "dev": true + } + } + }, "add-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/add-stream/-/add-stream-1.0.0.tgz", "integrity": "sha1-anmQQ3ynNtXhKI25K9MmbV9csqo=", "dev": true }, + "aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "requires": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "dependencies": { + "indent-string": { + "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 + } + } + }, "ajv": { "version": "6.10.0", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.0.tgz", @@ -620,10 +794,21 @@ } }, "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==", - "dev": true + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.1.tgz", + "integrity": "sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA==", + "dev": true, + "requires": { + "type-fest": "^0.11.0" + }, + "dependencies": { + "type-fest": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.11.0.tgz", + "integrity": "sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ==", + "dev": true + } + } }, "ansi-gray": { "version": "0.1.1", @@ -646,12 +831,14 @@ "ansi-regex": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true }, "ansi-styles": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, "requires": { "color-convert": "^1.9.0" } @@ -662,10 +849,10 @@ "integrity": "sha1-qCJQ3bABXponyoLoLqYDu/pF768=", "dev": true }, - "any-observable": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/any-observable/-/any-observable-0.3.0.tgz", - "integrity": "sha512-/FQM1EDkTsf63Ub2C6O7GuYFDsSXUwsaZDurV0np41ocwq0jthUAYCmhBX9f+KwlaCgIuWyr/4WlUQUBfKfZog==", + "ansicolors": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/ansicolors/-/ansicolors-0.3.2.tgz", + "integrity": "sha1-ZlWX3oap/+Oqm/vmyuXG6kJrSXk=", "dev": true }, "any-promise": { @@ -681,14 +868,119 @@ "requires": { "micromatch": "^3.1.4", "normalize-path": "^2.1.1" - } - }, - "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-buffer": { + }, + "dependencies": { + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + } + } + }, + "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-buffer": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/append-buffer/-/append-buffer-1.0.2.tgz", "integrity": "sha1-2CIM9GYIFSXv6lBhTz3mUU36WPE=", @@ -720,9 +1012,9 @@ } }, "arg": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.0.tgz", - "integrity": "sha512-ZWc51jO3qegGkVh8Hwpv636EkbesNV5ZNQPCtRa+0qytRYPEs9IYT9qITY9buezqUH5uqyzlWLcufrzU2rffdg==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", "dev": true }, "argparse": { @@ -781,12 +1073,6 @@ "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=", "dev": true }, - "array-from": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/array-from/-/array-from-2.1.1.tgz", - "integrity": "sha1-z+nYwmYoudxa7MYqn12PHzUsEZU=", - "dev": true - }, "array-ify": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/array-ify/-/array-ify-1.0.0.tgz", @@ -854,18 +1140,9 @@ } }, "array-union": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", - "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", - "dev": true, - "requires": { - "array-uniq": "^1.0.1" - } - }, - "array-uniq": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", - "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", "dev": true }, "array-unique": { @@ -874,6 +1151,18 @@ "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", "dev": true }, + "array.prototype.map": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array.prototype.map/-/array.prototype.map-1.0.2.tgz", + "integrity": "sha512-Az3OYxgsa1g7xDYp86l0nnN4bcmuEITGe1rbdEBVkrqkzMgDcbdQ2R7r41pNzti+4NMces3H8gMmuioZUilLgw==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1", + "es-array-method-boxes-properly": "^1.0.0", + "is-string": "^1.0.4" + } + }, "arrify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", @@ -920,21 +1209,21 @@ "dev": true }, "async-done": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/async-done/-/async-done-1.3.1.tgz", - "integrity": "sha512-R1BaUeJ4PMoLNJuk+0tLJgjmEqVsdN118+Z8O+alhnQDQgy0kmD5Mqi0DNEmMx2LM0Ed5yekKu+ZXYvIHceicg==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/async-done/-/async-done-1.3.2.tgz", + "integrity": "sha512-uYkTP8dw2og1tu1nmza1n1CMW0qb8gWWlwqMmLb7MhBVs4BXrFziT6HXUd+/RlRA/i4H9AkofYloUbs1fwMqlw==", "dev": true, "requires": { "end-of-stream": "^1.1.0", "once": "^1.3.2", - "process-nextick-args": "^1.0.7", + "process-nextick-args": "^2.0.0", "stream-exhaust": "^1.0.1" } }, "async-each": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz", - "integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0=", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", + "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", "dev": true }, "async-settle": { @@ -965,27 +1254,18 @@ "dev": true }, "aws4": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", - "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==", + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.10.1.tgz", + "integrity": "sha512-zg7Hz2k5lI8kb7U32998pRRFin7zJlkfezGJjUc2heaD4Pw2wObakCDVzkKztTm/Ln7eiVvYsjqak0Ed4LkMDA==", "dev": true }, - "babel-runtime": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", - "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", + "axios": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.19.2.tgz", + "integrity": "sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==", "dev": true, "requires": { - "core-js": "^2.4.0", - "regenerator-runtime": "^0.11.0" - }, - "dependencies": { - "regenerator-runtime": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", - "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", - "dev": true - } + "follow-redirects": "1.5.10" } }, "bach": { @@ -1080,9 +1360,9 @@ } }, "better-sqlite3": { - "version": "7.0.1", - "resolved": "https://registry.npm.taobao.org/better-sqlite3/download/better-sqlite3-7.0.1.tgz", - "integrity": "sha1-fQhhMLQtfVydKEeJnFfuWe7Jy7M=", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-7.1.0.tgz", + "integrity": "sha512-FV/snQ8F/kyqhdxsevzbojVtMowDWOfe1A5N3lYu1KJwoho2t7JgITmdlSc7DkOh3Zq65I+ZyeNWXQrkLEDFTg==", "dev": true, "requires": { "bindings": "^1.5.0", @@ -1090,22 +1370,16 @@ "tar": "4.4.10" } }, - "big-number": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/big-number/-/big-number-0.3.1.tgz", - "integrity": "sha1-rHMCDApZu3nrF8LOLbd/d9l04BM=", - "dev": true - }, "bignumber.js": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-4.1.0.tgz", - "integrity": "sha512-eJzYkFYy9L4JzXsbymsFn3p54D+llV27oTQ+ziJG7WFRheJcNZilgVXMG0LoZtlQSKBsJdWtLFqOD0u+U0jZKA==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz", + "integrity": "sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A==", "dev": true }, "binary-extensions": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.12.0.tgz", - "integrity": "sha512-DYWGk01lDcxeS/K9IHPGWfT8PsJmbXRtRd2Sx72Tnb8pcYZQFF1oSDb8hJtS1vhp212q1Rzi5dUf9+nq0o9UIg==", + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", "dev": true }, "binaryextensions": { @@ -1124,15 +1398,25 @@ } }, "bl": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz", - "integrity": "sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/bl/-/bl-2.2.1.tgz", + "integrity": "sha512-6Pesp1w0DEX1N550i/uGV/TqucVL4AM/pgThFSN/Qq9si1/DF9aIHs1BxD8V/QU0HoeHO6cQRTAuYnLPKq1e4g==", "dev": true, "requires": { "readable-stream": "^2.3.5", "safe-buffer": "^5.1.1" } }, + "block-stream": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz", + "integrity": "sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=", + "dev": true, + "optional": true, + "requires": { + "inherits": "~2.0.0" + } + }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -1143,32 +1427,12 @@ } }, "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", "dev": true, "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } + "fill-range": "^7.0.1" } }, "browser-stdout": { @@ -1178,15 +1442,15 @@ "dev": true }, "bson": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/bson/-/bson-1.1.0.tgz", - "integrity": "sha512-9Aeai9TacfNtWXOYarkFJRW2CWo+dRon+fuLZYJmvLV3+MiUp0bEI6IAZfXEIg7/Pl/7IWlLaDnhzTsD81etQA==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/bson/-/bson-1.1.5.tgz", + "integrity": "sha512-kDuEzldR21lHciPQAIulLs1LZlCXdLziXI6Mb/TDkwXhb//UORJNPXgcRs2CuO4H0DcMkpfT3/ySsP3unoZjBg==", "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.6.0", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz", + "integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==", "requires": { "base64-js": "^1.0.2", "ieee754": "^1.1.4" @@ -1198,6 +1462,12 @@ "integrity": "sha1-WWFrSYME1Var1GaWayLu2j7KX74=", "dev": true }, + "buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=", + "dev": true + }, "buffer-from": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", @@ -1233,44 +1503,31 @@ "unset-value": "^1.0.0" } }, - "caller-callsite": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", - "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=", - "dev": true, - "requires": { - "callsites": "^2.0.0" - } + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true }, - "caller-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", - "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=", + "camelcase-keys": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz", + "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==", "dev": true, "requires": { - "caller-callsite": "^2.0.0" + "camelcase": "^5.3.1", + "map-obj": "^4.0.0", + "quick-lru": "^4.0.1" } }, - "callsites": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", - "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=", - "dev": true - }, - "camelcase": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", - "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=" - }, - "camelcase-keys": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-4.2.0.tgz", - "integrity": "sha1-oqpfsa9oh1glnDLBQUJteJI7m3c=", + "cardinal": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/cardinal/-/cardinal-2.1.1.tgz", + "integrity": "sha1-fMEFXYItISlU0HsIXeolHMe8VQU=", "dev": true, "requires": { - "camelcase": "^4.1.0", - "map-obj": "^2.0.0", - "quick-lru": "^1.0.0" + "ansicolors": "~0.3.2", + "redeyed": "~2.1.0" } }, "caseless": { @@ -1303,13 +1560,36 @@ } }, "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "ansi-styles": { + "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" + } + }, + "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==" + } } }, "chardet": { @@ -1325,24 +1605,98 @@ "dev": true }, "chokidar": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.0.4.tgz", - "integrity": "sha512-z9n7yt9rOvIJrMhvDtDictKrkFHeihkNl6uWMmZlmL6tJtX9Cs+87oK+teBx+JIgzvbX3yZHT3eF8vpbDxHJXQ==", + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", "dev": true, "requires": { "anymatch": "^2.0.0", - "async-each": "^1.0.0", - "braces": "^2.3.0", - "fsevents": "^1.2.2", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "fsevents": "^1.2.7", "glob-parent": "^3.1.0", - "inherits": "^2.0.1", + "inherits": "^2.0.3", "is-binary-path": "^1.0.0", "is-glob": "^4.0.0", - "lodash.debounce": "^4.0.8", - "normalize-path": "^2.1.1", + "normalize-path": "^3.0.0", "path-is-absolute": "^1.0.0", - "readdirp": "^2.0.0", - "upath": "^1.0.5" + "readdirp": "^2.2.1", + "upath": "^1.1.1" + }, + "dependencies": { + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + }, + "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 + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + } } }, "chownr": { @@ -1386,124 +1740,179 @@ } } }, + "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=", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", "dev": true, "requires": { - "restore-cursor": "^2.0.0" + "restore-cursor": "^3.1.0" } }, "cli-highlight": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/cli-highlight/-/cli-highlight-2.0.0.tgz", - "integrity": "sha512-cW9HBA7Z7YETTwncdScUBUUDj8AnBU4rq6qQt6NbSXG2sFLcQ1LHEAGadRWydVtNXnH6StuN4GDCX5yddJDgew==", + "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": "^11.0.0" + "parse5": "^5.1.1", + "parse5-htmlparser2-tree-adapter": "^5.1.1", + "yargs": "^15.0.0" }, "dependencies": { - "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==" + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==" }, - "lcid": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", - "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", "requires": { - "invert-kv": "^2.0.0" + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" } }, - "yargs": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-11.1.1.tgz", - "integrity": "sha512-PRU7gJrJaXv3q3yQZ/+/X6KBswZiaQ+zOmdprZcouPYtQgvNU35i+68M4b1ZHLZtYFT5QObFLV+ZkmJYcwKdiw==", + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", "requires": { - "cliui": "^4.0.0", - "decamelize": "^1.1.1", - "find-up": "^2.1.0", - "get-caller-file": "^1.0.1", - "os-locale": "^3.1.0", - "require-directory": "^2.1.1", - "require-main-filename": "^1.0.1", - "set-blocking": "^2.0.0", - "string-width": "^2.0.0", - "which-module": "^2.0.0", - "y18n": "^3.2.1", - "yargs-parser": "^9.0.2" - }, - "dependencies": { - "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==", - "requires": { - "execa": "^1.0.0", - "lcid": "^2.0.0", - "mem": "^4.0.0" - } - }, - "yargs-parser": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-9.0.2.tgz", - "integrity": "sha1-nM9qQ0YP5O1Aqbto9I1DuKaMwHc=", - "requires": { - "camelcase": "^4.1.0" - } - } + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" } - } - } - }, - "cli-truncate": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-0.2.1.tgz", - "integrity": "sha1-nxXPuwcFAFNpIWxiasfQWrkN1XQ=", - "dev": true, - "requires": { - "slice-ansi": "0.0.4", - "string-width": "^1.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 }, - "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, + "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": { - "number-is-nan": "^1.0.0" + "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==" + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" + }, + "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==" + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" + }, "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "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" + } + }, + "y18n": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", + "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==" + }, + "yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "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": "^18.1.2" + } + } + } + }, + "cli-truncate": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz", + "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==", + "dev": true, + "requires": { + "slice-ansi": "^3.0.0", + "string-width": "^4.2.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==", + "dev": true + }, + "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==", + "dev": true + }, + "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==", + "dev": true + }, + "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==", "dev": true, "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.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=", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", "dev": true, "requires": { - "ansi-regex": "^2.0.0" + "ansi-regex": "^5.0.0" } } } @@ -1515,13 +1924,80 @@ "dev": true }, "cliui": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", - "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", "requires": { - "string-width": "^2.1.1", - "strip-ansi": "^4.0.0", - "wrap-ansi": "^2.0.0" + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.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.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" + } + }, + "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==" + }, + "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==" + }, + "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" + } + } } }, "clone": { @@ -1564,7 +2040,8 @@ "code-point-at": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "dev": true }, "collection-map": { "version": "1.0.0", @@ -1591,6 +2068,7 @@ "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, "requires": { "color-name": "1.1.3" } @@ -1598,7 +2076,8 @@ "color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true }, "color-support": { "version": "1.1.3", @@ -1616,25 +2095,31 @@ } }, "commander": { - "version": "2.17.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz", - "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-6.1.0.tgz", + "integrity": "sha512-wl7PNrYWd2y5mp1OK/LhTlv8Ff4kQJQRXXAvF+uU/TPNiVJUxZLRYGj/B0y/lPGAVcSbJqH2Za/cvHmrPMC8mA==", "dev": true }, "compare-func": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/compare-func/-/compare-func-1.3.2.tgz", - "integrity": "sha1-md0LpFfh+bxyKxLAjsM+6rMfpkg=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/compare-func/-/compare-func-2.0.0.tgz", + "integrity": "sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==", "dev": true, "requires": { "array-ify": "^1.0.0", - "dot-prop": "^3.0.0" + "dot-prop": "^5.1.0" } }, + "compare-versions": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-3.6.0.tgz", + "integrity": "sha512-W6Af2Iw1z4CB7q4uU4hv646dW9GQuBM+YpC0UvUCWSD8w90SJjp+ujJuXaEMtAXBtSqGfMPuFOVn4/+FlaqfBA==", + "dev": true + }, "component-emitter": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", - "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", "dev": true }, "concat-map": { @@ -1661,96 +2146,114 @@ "dev": true }, "conventional-changelog": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/conventional-changelog/-/conventional-changelog-3.1.8.tgz", - "integrity": "sha512-fb3/DOLLrQdNqN0yYn/lT6HcNsAa9A+VTDBqlZBMQcEPPIeJIMI+DBs3yu+eiYOLi22w9oShq3nn/zN6qm1Hmw==", + "version": "3.1.23", + "resolved": "https://registry.npmjs.org/conventional-changelog/-/conventional-changelog-3.1.23.tgz", + "integrity": "sha512-sScUu2NHusjRC1dPc5p8/b3kT78OYr95/Bx7Vl8CPB8tF2mG1xei5iylDTRjONV5hTlzt+Cn/tBWrKdd299b7A==", "dev": true, "requires": { - "conventional-changelog-angular": "^5.0.3", - "conventional-changelog-atom": "^2.0.1", - "conventional-changelog-codemirror": "^2.0.1", - "conventional-changelog-conventionalcommits": "^3.0.2", - "conventional-changelog-core": "^3.2.2", - "conventional-changelog-ember": "^2.0.2", - "conventional-changelog-eslint": "^3.0.2", - "conventional-changelog-express": "^2.0.1", - "conventional-changelog-jquery": "^3.0.4", - "conventional-changelog-jshint": "^2.0.1", - "conventional-changelog-preset-loader": "^2.1.1" + "conventional-changelog-angular": "^5.0.11", + "conventional-changelog-atom": "^2.0.7", + "conventional-changelog-codemirror": "^2.0.7", + "conventional-changelog-conventionalcommits": "^4.4.0", + "conventional-changelog-core": "^4.2.0", + "conventional-changelog-ember": "^2.0.8", + "conventional-changelog-eslint": "^3.0.8", + "conventional-changelog-express": "^2.0.5", + "conventional-changelog-jquery": "^3.0.10", + "conventional-changelog-jshint": "^2.0.8", + "conventional-changelog-preset-loader": "^2.3.4" } }, "conventional-changelog-angular": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-5.0.3.tgz", - "integrity": "sha512-YD1xzH7r9yXQte/HF9JBuEDfvjxxwDGGwZU1+ndanbY0oFgA+Po1T9JDSpPLdP0pZT6MhCAsdvFKC4TJ4MTJTA==", + "version": "5.0.11", + "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-5.0.11.tgz", + "integrity": "sha512-nSLypht/1yEflhuTogC03i7DX7sOrXGsRn14g131Potqi6cbGbGEE9PSDEHKldabB6N76HiSyw9Ph+kLmC04Qw==", "dev": true, "requires": { - "compare-func": "^1.3.1", + "compare-func": "^2.0.0", "q": "^1.5.1" } }, "conventional-changelog-atom": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/conventional-changelog-atom/-/conventional-changelog-atom-2.0.1.tgz", - "integrity": "sha512-9BniJa4gLwL20Sm7HWSNXd0gd9c5qo49gCi8nylLFpqAHhkFTj7NQfROq3f1VpffRtzfTQp4VKU5nxbe2v+eZQ==", + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/conventional-changelog-atom/-/conventional-changelog-atom-2.0.7.tgz", + "integrity": "sha512-7dOREZwzB+tCEMjRTDfen0OHwd7vPUdmU0llTy1eloZgtOP4iSLVzYIQqfmdRZEty+3w5Jz+AbhfTJKoKw1JeQ==", "dev": true, "requires": { "q": "^1.5.1" } }, "conventional-changelog-cli": { - "version": "2.0.21", - "resolved": "https://registry.npmjs.org/conventional-changelog-cli/-/conventional-changelog-cli-2.0.21.tgz", - "integrity": "sha512-gMT1XvSVmo9Np1WUXz8Mvt3K+OtzR+Xu13z0jq/3qsXBbLuYc2/oaUXVr68r3fYOL8E9dN2uvX7Hc7RkeWvRVA==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/conventional-changelog-cli/-/conventional-changelog-cli-2.1.0.tgz", + "integrity": "sha512-hZ8EcpxV4LcGOZwH+U5LJQDnyA4o/uyUdmIGzmFZMB4caujavvDBo/iTgVihk0m1QKkEhJgulagrILSm1JCakA==", "dev": true, "requires": { "add-stream": "^1.0.0", - "conventional-changelog": "^3.1.8", - "lodash": "^4.2.1", - "meow": "^4.0.0", - "tempfile": "^1.1.1" + "conventional-changelog": "^3.1.23", + "lodash": "^4.17.15", + "meow": "^7.0.0", + "tempfile": "^3.0.0" } }, "conventional-changelog-codemirror": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/conventional-changelog-codemirror/-/conventional-changelog-codemirror-2.0.1.tgz", - "integrity": "sha512-23kT5IZWa+oNoUaDUzVXMYn60MCdOygTA2I+UjnOMiYVhZgmVwNd6ri/yDlmQGXHqbKhNR5NoXdBzSOSGxsgIQ==", + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/conventional-changelog-codemirror/-/conventional-changelog-codemirror-2.0.7.tgz", + "integrity": "sha512-Oralk1kiagn3Gb5cR5BffenWjVu59t/viE6UMD/mQa1hISMPkMYhJIqX+CMeA1zXgVBO+YHQhhokEj99GP5xcg==", "dev": true, "requires": { "q": "^1.5.1" } }, "conventional-changelog-conventionalcommits": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-3.0.2.tgz", - "integrity": "sha512-w1+fQSDnm/7+sPKIYC5nfRVYDszt+6HdWizrigSqWFVIiiBVzkHGeqDLMSHc+Qq9qssHVAxAak5206epZyK87A==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-4.4.0.tgz", + "integrity": "sha512-ybvx76jTh08tpaYrYn/yd0uJNLt5yMrb1BphDe4WBredMlvPisvMghfpnJb6RmRNcqXeuhR6LfGZGewbkRm9yA==", "dev": true, "requires": { - "compare-func": "^1.3.1", + "compare-func": "^2.0.0", + "lodash": "^4.17.15", "q": "^1.5.1" } }, "conventional-changelog-core": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/conventional-changelog-core/-/conventional-changelog-core-3.2.2.tgz", - "integrity": "sha512-cssjAKajxaOX5LNAJLB+UOcoWjAIBvXtDMedv/58G+YEmAXMNfC16mmPl0JDOuVJVfIqM0nqQiZ8UCm8IXbE0g==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/conventional-changelog-core/-/conventional-changelog-core-4.2.0.tgz", + "integrity": "sha512-8+xMvN6JvdDtPbGBqA7oRNyZD4od1h/SIzrWqHcKZjitbVXrFpozEeyn4iI4af1UwdrabQpiZMaV07fPUTGd4w==", "dev": true, "requires": { - "conventional-changelog-writer": "^4.0.5", - "conventional-commits-parser": "^3.0.2", + "add-stream": "^1.0.0", + "conventional-changelog-writer": "^4.0.17", + "conventional-commits-parser": "^3.1.0", "dateformat": "^3.0.0", "get-pkg-repo": "^1.0.0", "git-raw-commits": "2.0.0", "git-remote-origin-url": "^2.0.0", - "git-semver-tags": "^2.0.2", - "lodash": "^4.2.1", + "git-semver-tags": "^4.1.0", + "lodash": "^4.17.15", "normalize-package-data": "^2.3.5", "q": "^1.5.1", "read-pkg": "^3.0.0", "read-pkg-up": "^3.0.0", + "shelljs": "^0.8.3", "through2": "^3.0.0" }, "dependencies": { + "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" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, "load-json-file": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", @@ -1763,6 +2266,40 @@ "strip-bom": "^3.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" + } + }, + "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 + }, "parse-json": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", @@ -1810,128 +2347,174 @@ "dev": true }, "through2": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.1.tgz", - "integrity": "sha512-M96dvTalPT3YbYLaKaCuwu+j06D/8Jfib0o/PxbVt6Amhv3dUAtW6rTV1jPgJSBG83I/e04Y6xkVdVhSRhi0ww==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.2.tgz", + "integrity": "sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ==", "dev": true, "requires": { + "inherits": "^2.0.4", "readable-stream": "2 || 3" } } } }, "conventional-changelog-ember": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/conventional-changelog-ember/-/conventional-changelog-ember-2.0.2.tgz", - "integrity": "sha512-qtZbA3XefO/n6DDmkYywDYi6wDKNNc98MMl2F9PKSaheJ25Trpi3336W8fDlBhq0X+EJRuseceAdKLEMmuX2tg==", + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/conventional-changelog-ember/-/conventional-changelog-ember-2.0.8.tgz", + "integrity": "sha512-JEMEcUAMg4Q9yxD341OgWlESQ4gLqMWMXIWWUqoQU8yvTJlKnrvcui3wk9JvnZQyONwM2g1MKRZuAjKxr8hAXA==", "dev": true, "requires": { "q": "^1.5.1" } }, "conventional-changelog-eslint": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/conventional-changelog-eslint/-/conventional-changelog-eslint-3.0.2.tgz", - "integrity": "sha512-Yi7tOnxjZLXlCYBHArbIAm8vZ68QUSygFS7PgumPRiEk+9NPUeucy5Wg9AAyKoBprSV3o6P7Oghh4IZSLtKCvQ==", + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/conventional-changelog-eslint/-/conventional-changelog-eslint-3.0.8.tgz", + "integrity": "sha512-5rTRltgWG7TpU1PqgKHMA/2ivjhrB+E+S7OCTvj0zM/QGg4vmnVH67Vq/EzvSNYtejhWC+OwzvDrLk3tqPry8A==", "dev": true, "requires": { "q": "^1.5.1" } }, "conventional-changelog-express": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/conventional-changelog-express/-/conventional-changelog-express-2.0.1.tgz", - "integrity": "sha512-G6uCuCaQhLxdb4eEfAIHpcfcJ2+ao3hJkbLrw/jSK/eROeNfnxCJasaWdDAfFkxsbpzvQT4W01iSynU3OoPLIw==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/conventional-changelog-express/-/conventional-changelog-express-2.0.5.tgz", + "integrity": "sha512-pW2hsjKG+xNx/Qjof8wYlAX/P61hT5gQ/2rZ2NsTpG+PgV7Rc8RCfITvC/zN9K8fj0QmV6dWmUefCteD9baEAw==", "dev": true, "requires": { "q": "^1.5.1" } }, "conventional-changelog-jquery": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/conventional-changelog-jquery/-/conventional-changelog-jquery-3.0.4.tgz", - "integrity": "sha512-IVJGI3MseYoY6eybknnTf9WzeQIKZv7aNTm2KQsiFVJH21bfP2q7XVjfoMibdCg95GmgeFlaygMdeoDDa+ZbEQ==", + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/conventional-changelog-jquery/-/conventional-changelog-jquery-3.0.10.tgz", + "integrity": "sha512-QCW6wF8QgPkq2ruPaxc83jZxoWQxLkt/pNxIDn/oYjMiVgrtqNdd7lWe3vsl0hw5ENHNf/ejXuzDHk6suKsRpg==", "dev": true, "requires": { "q": "^1.5.1" } }, "conventional-changelog-jshint": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/conventional-changelog-jshint/-/conventional-changelog-jshint-2.0.1.tgz", - "integrity": "sha512-kRFJsCOZzPFm2tzRHULWP4tauGMvccOlXYf3zGeuSW4U0mZhk5NsjnRZ7xFWrTFPlCLV+PNmHMuXp5atdoZmEg==", + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/conventional-changelog-jshint/-/conventional-changelog-jshint-2.0.8.tgz", + "integrity": "sha512-hB/iI0IiZwnZ+seYI+qEQ4b+EMQSEC8jGIvhO2Vpz1E5p8FgLz75OX8oB1xJWl+s4xBMB6f8zJr0tC/BL7YOjw==", "dev": true, "requires": { - "compare-func": "^1.3.1", + "compare-func": "^2.0.0", "q": "^1.5.1" } }, "conventional-changelog-preset-loader": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/conventional-changelog-preset-loader/-/conventional-changelog-preset-loader-2.1.1.tgz", - "integrity": "sha512-K4avzGMLm5Xw0Ek/6eE3vdOXkqnpf9ydb68XYmCc16cJ99XMMbc2oaNMuPwAsxVK6CC1yA4/I90EhmWNj0Q6HA==", + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/conventional-changelog-preset-loader/-/conventional-changelog-preset-loader-2.3.4.tgz", + "integrity": "sha512-GEKRWkrSAZeTq5+YjUZOYxdHq+ci4dNwHvpaBC3+ENalzFWuCWa9EZXSuZBpkr72sMdKB+1fyDV4takK1Lf58g==", "dev": true }, "conventional-changelog-writer": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-4.0.5.tgz", - "integrity": "sha512-g/Myp4MaJ1A+f7Ai+SnVhkcWtaHk6flw0SYN7A+vQ+MTu0+gSovQWs4Pg4NtcNUcIztYQ9YHsoxHP+GGQplI7Q==", + "version": "4.0.17", + "resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-4.0.17.tgz", + "integrity": "sha512-IKQuK3bib/n032KWaSb8YlBFds+aLmzENtnKtxJy3+HqDq5kohu3g/UdNbIHeJWygfnEbZjnCKFxAW0y7ArZAw==", "dev": true, "requires": { - "compare-func": "^1.3.1", - "conventional-commits-filter": "^2.0.2", + "compare-func": "^2.0.0", + "conventional-commits-filter": "^2.0.6", "dateformat": "^3.0.0", - "handlebars": "^4.1.0", + "handlebars": "^4.7.6", "json-stringify-safe": "^5.0.1", - "lodash": "^4.2.1", - "meow": "^4.0.0", - "semver": "^5.5.0", + "lodash": "^4.17.15", + "meow": "^7.0.0", + "semver": "^6.0.0", "split": "^1.0.0", "through2": "^3.0.0" }, "dependencies": { - "through2": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.1.tgz", - "integrity": "sha512-M96dvTalPT3YbYLaKaCuwu+j06D/8Jfib0o/PxbVt6Amhv3dUAtW6rTV1jPgJSBG83I/e04Y6xkVdVhSRhi0ww==", + "handlebars": { + "version": "4.7.6", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.6.tgz", + "integrity": "sha512-1f2BACcBfiwAfStCKZNrUCgqNZkGsAT7UM3kkYtXuLo0KnaVfjKOyf7PRzB6++aK9STyT1Pd2ZCPe3EGOXleXA==", "dev": true, "requires": { - "readable-stream": "2 || 3" + "minimist": "^1.2.5", + "neo-async": "^2.6.0", + "source-map": "^0.6.1", + "uglify-js": "^3.1.4", + "wordwrap": "^1.0.0" } - } - } - }, - "conventional-commits-filter": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/conventional-commits-filter/-/conventional-commits-filter-2.0.2.tgz", - "integrity": "sha512-WpGKsMeXfs21m1zIw4s9H5sys2+9JccTzpN6toXtxhpw2VNF2JUXwIakthKBy+LN4DvJm+TzWhxOMWOs1OFCFQ==", - "dev": true, - "requires": { - "lodash.ismatch": "^4.4.0", - "modify-values": "^1.0.0" - } - }, - "conventional-commits-parser": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-3.0.2.tgz", - "integrity": "sha512-y5eqgaKR0F6xsBNVSQ/5cI5qIF3MojddSUi1vKIggRkqUTbkqFKH9P5YX/AT1BVZp9DtSzBTIkvjyVLotLsVog==", - "dev": true, + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "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 + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "through2": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.2.tgz", + "integrity": "sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ==", + "dev": true, + "requires": { + "inherits": "^2.0.4", + "readable-stream": "2 || 3" + } + } + } + }, + "conventional-commits-filter": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/conventional-commits-filter/-/conventional-commits-filter-2.0.6.tgz", + "integrity": "sha512-4g+sw8+KA50/Qwzfr0hL5k5NWxqtrOVw4DDk3/h6L85a9Gz0/Eqp3oP+CWCNfesBvZZZEFHF7OTEbRe+yYSyKw==", + "dev": true, + "requires": { + "lodash.ismatch": "^4.4.0", + "modify-values": "^1.0.0" + } + }, + "conventional-commits-parser": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-3.1.0.tgz", + "integrity": "sha512-RSo5S0WIwXZiRxUGTPuYFbqvrR4vpJ1BDdTlthFgvHt5kEdnd1+pdvwWphWn57/oIl4V72NMmOocFqqJ8mFFhA==", + "dev": true, "requires": { "JSONStream": "^1.0.4", - "is-text-path": "^1.0.0", - "lodash": "^4.2.1", - "meow": "^4.0.0", + "is-text-path": "^1.0.1", + "lodash": "^4.17.15", + "meow": "^7.0.0", "split2": "^2.0.0", "through2": "^3.0.0", "trim-off-newlines": "^1.0.0" }, "dependencies": { + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, "through2": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.1.tgz", - "integrity": "sha512-M96dvTalPT3YbYLaKaCuwu+j06D/8Jfib0o/PxbVt6Amhv3dUAtW6rTV1jPgJSBG83I/e04Y6xkVdVhSRhi0ww==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.2.tgz", + "integrity": "sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ==", "dev": true, "requires": { + "inherits": "^2.0.4", "readable-stream": "2 || 3" } } @@ -1962,12 +2545,6 @@ "is-plain-object": "^2.0.1" } }, - "core-js": { - "version": "2.6.5", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.5.tgz", - "integrity": "sha512-klh/kDpwX8hryYL14M9w/xei6vrv6sE8gTHDG7/T/+SEovB/G4ejwcfE/CBzO6Edsu+OETZMZ3wcX/EjUkrl5A==", - "dev": true - }, "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", @@ -1975,27 +2552,35 @@ "dev": true }, "cosmiconfig": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.1.0.tgz", - "integrity": "sha512-kCNPvthka8gvLtzAxQXvWo4FxqRB+ftRZyPZNuab5ngvM9Y7yw7hbEysglptLgpkGX9nAOKTBVkHUAe8xtYR6Q==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.0.tgz", + "integrity": "sha512-pondGvTuVYDk++upghXJabWzL6Kxu6f26ljFw64Swq9v6sQPUL3EUlVDV56diOjpCayKihL6hVe8exIACU4XcA==", "dev": true, "requires": { - "import-fresh": "^2.0.0", - "is-directory": "^0.3.1", - "js-yaml": "^3.9.0", - "lodash.get": "^4.4.2", - "parse-json": "^4.0.0" + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" }, "dependencies": { "parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.1.0.tgz", + "integrity": "sha512-+mi/lmVVNKFNVyLXV31ERiy2CY5E1/F6QtJFEzoChPRwwngMNXRDQ9GJ5WdE2Z2P4AujsOi0/+2qHID68KwfIQ==", "dev": true, "requires": { + "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" } + }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true } } }, @@ -2003,6 +2588,7 @@ "version": "6.0.5", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, "requires": { "nice-try": "^1.0.4", "path-key": "^2.0.1", @@ -2050,9 +2636,9 @@ } }, "dargs": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/dargs/-/dargs-5.1.0.tgz", - "integrity": "sha1-7H6lDHhWTNNsnV7Bj2Yyn63ieCk=", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/dargs/-/dargs-7.0.0.tgz", + "integrity": "sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg==", "dev": true }, "dashdash": { @@ -2064,10 +2650,19 @@ "assert-plus": "^1.0.0" } }, - "date-fns": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-1.30.1.tgz", - "integrity": "sha512-hBSVCvSmWC+QypYObzwGOd9wqdDpOt+0wl0KbU+R+uuZBS1jN8VsD1ss3irQDknRj5NvxiTF6oj/nDRnN/UQNw==", + "data-api-client": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/data-api-client/-/data-api-client-1.1.0.tgz", + "integrity": "sha512-ZO6i4g55afRYbDwpVuF3pa6KI0pNee5VcAGAIQRHhCFAJytFCwazzSQ3iwZU8ONcRumXoHDKTp/dyIQOub1ysg==", + "dev": true, + "requires": { + "sqlstring": "^2.3.1" + } + }, + "date-utils": { + "version": "1.2.21", + "resolved": "https://registry.npmjs.org/date-utils/-/date-utils-1.2.21.tgz", + "integrity": "sha1-YfsWzcEnSzyayq/+n8ad+HIKK2Q=", "dev": true }, "dateformat": { @@ -2137,8 +2732,8 @@ }, "decompress-response": { "version": "4.2.1", - "resolved": "https://registry.npm.taobao.org/decompress-response/download/decompress-response-4.2.1.tgz?cache=0&sync_timestamp=1589512178920&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdecompress-response%2Fdownload%2Fdecompress-response-4.2.1.tgz", - "integrity": "sha1-QUAjzHowLaJc4uyC0NUjjMr9iYY=", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz", + "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==", "dev": true, "requires": { "mimic-response": "^2.0.0" @@ -2245,17 +2840,36 @@ } }, "del": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/del/-/del-3.0.0.tgz", - "integrity": "sha1-U+z2mf/LyzljdpGrE7rxYIGXZuU=", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/del/-/del-5.1.0.tgz", + "integrity": "sha512-wH9xOVHnczo9jN2IW68BabcecVPxacIA3g/7z6vhSU/4stOKQzeCRK0yD0A24WiAAUJmmVpWqrERcTxnLo3AnA==", "dev": true, "requires": { - "globby": "^6.1.0", - "is-path-cwd": "^1.0.0", - "is-path-in-cwd": "^1.0.0", - "p-map": "^1.1.1", - "pify": "^3.0.0", - "rimraf": "^2.2.8" + "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.4", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", + "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", + "dev": true + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + } } }, "delayed-stream": { @@ -2271,15 +2885,15 @@ "dev": true }, "denque": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/denque/-/denque-1.4.0.tgz", - "integrity": "sha512-gh513ac7aiKrAgjiIBWZG0EASyDF9p4JMWwKA8YU5s9figrL5SRNEMT6FDynsegakuhWd1wVqTvqvqAoDxw7wQ==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/denque/-/denque-1.4.1.tgz", + "integrity": "sha512-OfzPuSZKGcgr96rf1oODnfjqBFmr1DVoc/TrItj3Ohe0Ah1C5WX5Baquw/9U9KovnQ88EqmJbD66rKYUQYN1tQ==", "dev": true }, "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==", "dev": true }, "detect-file": { @@ -2306,6 +2920,23 @@ "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", "dev": true }, + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "requires": { + "path-type": "^4.0.0" + }, + "dependencies": { + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true + } + } + }, "doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", @@ -2316,12 +2947,20 @@ } }, "dot-prop": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-3.0.0.tgz", - "integrity": "sha1-G3CK8JSknJoOfbyteQq6U52sEXc=", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", "dev": true, "requires": { - "is-obj": "^1.0.0" + "is-obj": "^2.0.0" + }, + "dependencies": { + "is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "dev": true + } } }, "dotenv": { @@ -2329,12 +2968,6 @@ "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz", "integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==" }, - "double-ended-queue": { - "version": "2.1.0-0", - "resolved": "https://registry.npmjs.org/double-ended-queue/-/double-ended-queue-2.1.0-0.tgz", - "integrity": "sha1-ED01J/0xUo9AGIEwyEHv3XgmTlw=", - "dev": true - }, "duplexify": { "version": "3.6.1", "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.6.1.tgz", @@ -2367,27 +3000,32 @@ "safer-buffer": "^2.1.0" } }, + "ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.0.1" + } + }, "editions": { "version": "1.3.4", "resolved": "https://registry.npmjs.org/editions/-/editions-1.3.4.tgz", "integrity": "sha512-gzao+mxnYDzIysXKMQi/+M1mjy/rjestjg6OPoYTtI+3Izp23oiGZitsl9lPDPiTGXbcSIk1iJWhliSaglxnUg==", "dev": true }, - "elegant-spinner": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/elegant-spinner/-/elegant-spinner-1.0.1.tgz", - "integrity": "sha1-2wQ1IcldfjA/2PNFvtwzSc+wcp4=", - "dev": true - }, "emoji-regex": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true }, "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==", + "dev": true, "requires": { "once": "^1.4.0" } @@ -2419,23 +3057,77 @@ } }, "es-abstract": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.13.0.tgz", - "integrity": "sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg==", + "version": "1.17.6", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", + "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", "dev": true, "requires": { - "es-to-primitive": "^1.2.0", + "es-to-primitive": "^1.2.1", "function-bind": "^1.1.1", "has": "^1.0.3", - "is-callable": "^1.1.4", - "is-regex": "^1.0.4", - "object-keys": "^1.0.12" + "has-symbols": "^1.0.1", + "is-callable": "^1.2.0", + "is-regex": "^1.1.0", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + }, + "dependencies": { + "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 + }, + "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 + } + } + }, + "es-array-method-boxes-properly": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz", + "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==", + "dev": true + }, + "es-get-iterator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.0.tgz", + "integrity": "sha512-UfrmHuWQlNMTs35e1ypnvikg6jCz3SK8v8ImvmDsh36fCVUR1MqoFDiyn0/k52C8NqO3YsO8Oe0azeesNuqSsQ==", + "dev": true, + "requires": { + "es-abstract": "^1.17.4", + "has-symbols": "^1.0.1", + "is-arguments": "^1.0.4", + "is-map": "^2.0.1", + "is-set": "^2.0.1", + "is-string": "^1.0.5", + "isarray": "^2.0.5" + }, + "dependencies": { + "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 + }, + "isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + } } }, "es-to-primitive": { - "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==", + "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", @@ -2487,6 +3179,11 @@ "es6-symbol": "^3.1.1" } }, + "escalade": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.0.2.tgz", + "integrity": "sha512-gPYAU37hYCUhW5euPeR+Y74F7BL+IBsV93j5cvGriSaD1aG6MGsqsV1yamRdrWrb2j3aiZvb0X+UBOWpx3JWtQ==" + }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", @@ -2524,12 +3221,13 @@ } }, "eslint": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.5.0.tgz", - "integrity": "sha512-vlUP10xse9sWt9SGRtcr1LAC67BENcQMFeV+w5EvLEoFe3xJ8cF1Skd0msziRx/VMC+72B4DxreCE+OR12OA6Q==", + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.8.1.tgz", + "integrity": "sha512-/2rX2pfhyUG0y+A123d0ccXtMm7DV7sH1m3lk9nk2DZ2LReq39FXHueR9xZwshE5MdfSf0xunSaMWRqyIA6M1w==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", + "@eslint/eslintrc": "^0.1.3", "ajv": "^6.10.0", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", @@ -2539,7 +3237,7 @@ "eslint-scope": "^5.1.0", "eslint-utils": "^2.1.0", "eslint-visitor-keys": "^1.3.0", - "espree": "^7.2.0", + "espree": "^7.3.0", "esquery": "^1.2.0", "esutils": "^2.0.2", "file-entry-cache": "^5.0.1", @@ -2639,22 +3337,6 @@ } } }, - "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 - }, - "import-fresh": { - "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", - "resolve-from": "^4.0.0" - } - }, "levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -2691,12 +3373,6 @@ "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true }, - "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==", - "dev": true - }, "semver": { "version": "7.3.2", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", @@ -2733,15 +3409,6 @@ "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "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" - } - }, "type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -2796,20 +3463,20 @@ "dev": true }, "espree": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-7.2.0.tgz", - "integrity": "sha512-H+cQ3+3JYRMEIOl87e7QdHX70ocly5iW4+dttuR8iYSPr/hXKFb+7dBsZ7+u1adC4VrnPlTkv0+OwuPnDop19g==", + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.0.tgz", + "integrity": "sha512-dksIWsvKCixn1yrEXO8UosNSxaDoSYpq9reEjZSbHLpT5hpaCAKTLBwq0RHtLrIr+c0ByiYzWT8KTMRzoRCNlw==", "dev": true, "requires": { - "acorn": "^7.3.1", + "acorn": "^7.4.0", "acorn-jsx": "^5.2.0", "eslint-visitor-keys": "^1.3.0" }, "dependencies": { "acorn": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.3.1.tgz", - "integrity": "sha512-tLc0wSnatxAQHVHUapaHdz72pi9KUyHjq5KyHjGg9Y8Ifdc79pTh2XvI6I1/chZbnM7QtNKzh66ooDogPZSleA==", + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.0.tgz", + "integrity": "sha512-+G7P8jJmCHr+S+cLfQxygbWhXy+8YTVGzAkpEbcLo2mLoL7tij/VG41QSHACSf5QgYRhMZYHuNc6drJaO0Da+w==", "dev": true } } @@ -2876,34 +3543,61 @@ } }, "execa": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", - "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", - "requires": { - "cross-spawn": "^6.0.0", - "get-stream": "^4.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" + "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": "^7.0.0", + "get-stream": "^5.0.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^3.0.0", + "onetime": "^5.1.0", + "p-finally": "^2.0.0", + "signal-exit": "^3.0.2", + "strip-final-newline": "^2.0.0" }, "dependencies": { - "get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, "requires": { - "pump": "^3.0.0" + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" } }, - "pump": { + "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/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "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": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" + "isexe": "^2.0.0" } } } @@ -2960,8 +3654,8 @@ }, "expand-template": { "version": "2.0.3", - "resolved": "https://registry.npm.taobao.org/expand-template/download/expand-template-2.0.3.tgz", - "integrity": "sha1-bhSz/O4POmNA7LV9LokYaSBSpHw=", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", "dev": true }, "expand-tilde": { @@ -3100,34 +3794,82 @@ "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", "dev": true }, - "fast-json-stable-stringify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", - "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", - "dev": true - }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true - }, - "figlet": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/figlet/-/figlet-1.2.1.tgz", - "integrity": "sha512-qc8gycfnnfOmfvPl7Fi3JeTbcvdmbZkckyUVGGAM02je7Ookvu+bBfKy1I4FKqTsQHCs3ARJ76ip/k98r+OQuQ==" - }, - "figures": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", - "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", + "fast-glob": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.4.tgz", + "integrity": "sha512-kr/Oo6PX51265qeuCYsyGypiO5uJFgBS0jksyG7FUeCyQzNwYnzrNIMR1NXfkZXsMYXYLRAHgISHBz8gQcxKHQ==", "dev": true, "requires": { - "escape-string-regexp": "^1.0.5", - "object-assign": "^4.1.0" - } - }, - "file-entry-cache": { + "@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", + "picomatch": "^2.2.1" + }, + "dependencies": { + "glob-parent": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", + "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true + } + } + }, + "fast-json-stable-stringify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "fastq": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.8.0.tgz", + "integrity": "sha512-SMIZoZdLh/fgofivvIkmknUXyPnvxRE3DhtZ5Me3Mrsk5gyPL42F0xr51TdRXskBxHfMp+07bcYzfsYEsSQA9Q==", + "dev": true, + "requires": { + "reusify": "^1.0.4" + } + }, + "figlet": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/figlet/-/figlet-1.2.1.tgz", + "integrity": "sha512-qc8gycfnnfOmfvPl7Fi3JeTbcvdmbZkckyUVGGAM02je7Ookvu+bBfKy1I4FKqTsQHCs3ARJ76ip/k98r+OQuQ==" + }, + "figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "file-entry-cache": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", @@ -3143,69 +3885,160 @@ "dev": true }, "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", "dev": true, "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" + "to-regex-range": "^5.0.1" + } + }, + "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" }, "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.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==" } } }, - "find-parent-dir": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/find-parent-dir/-/find-parent-dir-0.3.0.tgz", - "integrity": "sha1-M8RLQpqysvBkYpnF+fcY83b/jVQ=", - "dev": true - }, - "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "find-versions": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/find-versions/-/find-versions-3.2.0.tgz", + "integrity": "sha512-P8WRou2S+oe222TOCHitLy8zj+SIsVJh52VP4lvXkaFVnOFFdoWv1H1Jjvel1aI6NCFOAaeAVm8qrI0odiLcww==", + "dev": true, "requires": { - "locate-path": "^2.0.0" + "semver-regex": "^2.0.0" } }, "findup-sync": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-2.0.0.tgz", - "integrity": "sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-3.0.0.tgz", + "integrity": "sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg==", "dev": true, "requires": { "detect-file": "^1.0.0", - "is-glob": "^3.1.0", + "is-glob": "^4.0.0", "micromatch": "^3.0.4", "resolve-dir": "^1.0.1" }, "dependencies": { - "is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", "dev": true, "requires": { - "is-extglob": "^2.1.0" + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" } } } }, "fined": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/fined/-/fined-1.1.1.tgz", - "integrity": "sha512-jQp949ZmEbiYHk3gkbdtpJ0G1+kgtLQBNdP5edFP7Fh+WAYceLQz6yO1SBj72Xkg8GVyTB3bBzAYrHJVh5Xd5g==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fined/-/fined-1.2.0.tgz", + "integrity": "sha512-ZYDqPLGxDkDhDZBjZBb+oD1+j0rA4E0pXY50eplAAOPg2N/gUBSSk5IM1/QhPfyVo19lJ+CvXpqfvk+b2p/8Ng==", "dev": true, "requires": { "expand-tilde": "^2.0.2", @@ -3231,9 +4064,9 @@ }, "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==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz", + "integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==", "dev": true } } @@ -3247,6 +4080,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": { @@ -3265,11 +4109,31 @@ "readable-stream": "^2.0.4" } }, - "fn-name": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fn-name/-/fn-name-2.0.1.tgz", - "integrity": "sha1-UhTXU3pNBqSjAcDMJi/rhBiAAuc=", - "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==", + "dev": true, + "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==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } }, "for-in": { "version": "1.0.2", @@ -3293,9 +4157,9 @@ "dev": true }, "form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz", + "integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==", "dev": true, "requires": { "asynckit": "^0.4.0", @@ -3314,8 +4178,8 @@ }, "fs-constants": { "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/fs-constants/download/fs-constants-1.0.0.tgz", - "integrity": "sha1-a+Dem+mYzhavivwkSXue6bfM2a0=", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", "dev": true }, "fs-minipass": { @@ -3343,587 +4207,55 @@ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, "fsevents": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.4.tgz", - "integrity": "sha512-z8H8/diyk76B7q5wg+Ud0+CqzcAF3mBBI/bA5ne5zrRUUIvNkJY//D3BqyH571KuAC4Nr7Rw7CjWX4r0y9DvNg==", + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", + "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", "dev": true, "optional": true, "requires": { - "nan": "^2.9.2", - "node-pre-gyp": "^0.10.0" - }, - "dependencies": { - "abbrev": { - "version": "1.1.1", - "resolved": false, - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "dev": true, - "optional": true - }, - "ansi-regex": { - "version": "2.1.1", - "resolved": false, - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true, - "optional": true - }, - "aproba": { - "version": "1.2.0", - "resolved": false, - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", - "dev": true, - "optional": true - }, - "are-we-there-yet": { - "version": "1.1.4", - "resolved": false, - "integrity": "sha1-u13KOCu5TwXhUZQ3PRb9O6HKEQ0=", - "dev": true, - "optional": true, - "requires": { - "delegates": "^1.0.0", - "readable-stream": "^2.0.6" - } - }, - "balanced-match": { - "version": "1.0.0", - "resolved": false, - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true, - "optional": true - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": false, - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "optional": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "code-point-at": { - "version": "1.1.0", - "resolved": false, - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "dev": true, - "optional": true - }, - "concat-map": { - "version": "0.0.1", - "resolved": false, - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true, - "optional": true - }, - "console-control-strings": { - "version": "1.1.0", - "resolved": false, - "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", - "dev": true, - "optional": true - }, - "core-util-is": { - "version": "1.0.2", - "resolved": false, - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", - "dev": true, - "optional": true - }, - "debug": { - "version": "2.6.9", - "resolved": false, - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "optional": true, - "requires": { - "ms": "2.0.0" - } - }, - "deep-extend": { - "version": "0.5.1", - "resolved": false, - "integrity": "sha512-N8vBdOa+DF7zkRrDCsaOXoCs/E2fJfx9B9MrKnnSiHNh4ws7eSys6YQE4KvT1cecKmOASYQBhbKjeuDD9lT81w==", - "dev": true, - "optional": true - }, - "delegates": { - "version": "1.0.0", - "resolved": false, - "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", - "dev": true, - "optional": true - }, - "detect-libc": { - "version": "1.0.3", - "resolved": false, - "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", - "dev": true, - "optional": true - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": false, - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true, - "optional": true - }, - "gauge": { - "version": "2.7.4", - "resolved": false, - "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", - "dev": true, - "optional": true, - "requires": { - "aproba": "^1.0.3", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", - "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" - } - }, - "glob": { - "version": "7.1.2", - "resolved": false, - "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", - "dev": true, - "optional": 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" - } - }, - "has-unicode": { - "version": "2.0.1", - "resolved": false, - "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", - "dev": true, - "optional": true - }, - "iconv-lite": { - "version": "0.4.21", - "resolved": false, - "integrity": "sha512-En5V9za5mBt2oUA03WGD3TwDv0MKAruqsuxstbMUZaj9W9k/m1CV/9py3l0L5kw9Bln8fdHQmzHSYtvpvTLpKw==", - "dev": true, - "optional": true, - "requires": { - "safer-buffer": "^2.1.0" - } - }, - "ignore-walk": { - "version": "3.0.1", - "resolved": false, - "integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==", - "dev": true, - "optional": true, - "requires": { - "minimatch": "^3.0.4" - } - }, - "inflight": { - "version": "1.0.6", - "resolved": false, - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "optional": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.3", - "resolved": false, - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true, - "optional": true - }, - "ini": { - "version": "1.3.5", - "resolved": false, - "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", - "dev": true, - "optional": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": false, - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "dev": true, - "optional": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "isarray": { - "version": "1.0.0", - "resolved": false, - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true, - "optional": true - }, - "minimatch": { - "version": "3.0.4", - "resolved": false, - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, - "optional": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "0.0.8", - "resolved": false, - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", - "dev": true, - "optional": true - }, - "mkdirp": { - "version": "0.5.1", - "resolved": false, - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "dev": true, - "optional": true, - "requires": { - "minimist": "0.0.8" - } - }, - "ms": { - "version": "2.0.0", - "resolved": false, - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true, - "optional": true - }, - "needle": { - "version": "2.2.0", - "resolved": false, - "integrity": "sha512-eFagy6c+TYayorXw/qtAdSvaUpEbBsDwDyxYFgLZ0lTojfH7K+OdBqAF7TAFwDokJaGpubpSGG0wO3iC0XPi8w==", - "dev": true, - "optional": true, - "requires": { - "debug": "^2.1.2", - "iconv-lite": "^0.4.4", - "sax": "^1.2.4" - } - }, - "node-pre-gyp": { - "version": "0.10.0", - "resolved": false, - "integrity": "sha512-G7kEonQLRbcA/mOoFoxvlMrw6Q6dPf92+t/l0DFSMuSlDoWaI9JWIyPwK0jyE1bph//CUEL65/Fz1m2vJbmjQQ==", - "dev": true, - "optional": true, - "requires": { - "detect-libc": "^1.0.2", - "mkdirp": "^0.5.1", - "needle": "^2.2.0", - "nopt": "^4.0.1", - "npm-packlist": "^1.1.6", - "npmlog": "^4.0.2", - "rc": "^1.1.7", - "rimraf": "^2.6.1", - "semver": "^5.3.0", - "tar": "^4" - } - }, - "nopt": { - "version": "4.0.1", - "resolved": false, - "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", - "dev": true, - "optional": true, - "requires": { - "abbrev": "1", - "osenv": "^0.1.4" - } - }, - "npm-bundled": { - "version": "1.0.3", - "resolved": false, - "integrity": "sha512-ByQ3oJ/5ETLyglU2+8dBObvhfWXX8dtPZDMePCahptliFX2iIuhyEszyFk401PZUNQH20vvdW5MLjJxkwU80Ow==", - "dev": true, - "optional": true - }, - "npm-packlist": { - "version": "1.1.10", - "resolved": false, - "integrity": "sha512-AQC0Dyhzn4EiYEfIUjCdMl0JJ61I2ER9ukf/sLxJUcZHfo+VyEfz2rMJgLZSS1v30OxPQe1cN0LZA1xbcaVfWA==", - "dev": true, - "optional": true, - "requires": { - "ignore-walk": "^3.0.1", - "npm-bundled": "^1.0.1" - } - }, - "npmlog": { - "version": "4.1.2", - "resolved": false, - "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", - "dev": true, - "optional": true, - "requires": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" - } - }, - "number-is-nan": { - "version": "1.0.1", - "resolved": false, - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "dev": true, - "optional": true - }, - "object-assign": { - "version": "4.1.1", - "resolved": false, - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "dev": true, - "optional": true - }, - "once": { - "version": "1.4.0", - "resolved": false, - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "optional": true, - "requires": { - "wrappy": "1" - } - }, - "os-homedir": { - "version": "1.0.2", - "resolved": false, - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", - "dev": true, - "optional": true - }, - "os-tmpdir": { - "version": "1.0.2", - "resolved": false, - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", - "dev": true, - "optional": true - }, - "osenv": { - "version": "0.1.5", - "resolved": false, - "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", - "dev": true, - "optional": true, - "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": false, - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true, - "optional": true - }, - "process-nextick-args": { - "version": "2.0.0", - "resolved": false, - "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", - "dev": true, - "optional": true - }, - "rc": { - "version": "1.2.7", - "resolved": false, - "integrity": "sha512-LdLD8xD4zzLsAT5xyushXDNscEjB7+2ulnl8+r1pnESlYtlJtVSoCMBGr30eDRJ3+2Gq89jK9P9e4tCEH1+ywA==", - "dev": true, - "optional": true, - "requires": { - "deep-extend": "^0.5.1", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "resolved": false, - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true, - "optional": true - } - } - }, - "readable-stream": { - "version": "2.3.6", - "resolved": false, - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", - "dev": true, - "optional": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "rimraf": { - "version": "2.6.2", - "resolved": false, - "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", - "dev": true, - "optional": true, - "requires": { - "glob": "^7.0.5" - } - }, - "safe-buffer": { - "version": "5.1.1", - "resolved": false, - "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", - "dev": true, - "optional": true - }, - "safer-buffer": { - "version": "2.1.2", - "resolved": false, - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true, - "optional": true - }, - "sax": { - "version": "1.2.4", - "resolved": false, - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", - "dev": true, - "optional": true - }, - "semver": { - "version": "5.5.0", - "resolved": false, - "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", - "dev": true, - "optional": true - }, - "set-blocking": { - "version": "2.0.0", - "resolved": false, - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", - "dev": true, - "optional": true - }, - "signal-exit": { - "version": "3.0.2", - "resolved": false, - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", - "dev": true, - "optional": true - }, - "string-width": { - "version": "1.0.2", - "resolved": false, - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dev": true, - "optional": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": false, - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "optional": true, - "requires": { - "safe-buffer": "~5.1.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": false, - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "optional": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "strip-json-comments": { - "version": "2.0.1", - "resolved": false, - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "bindings": "^1.5.0", + "nan": "^2.12.1" + } + }, + "fstream": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz", + "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==", + "dev": true, + "optional": true, + "requires": { + "graceful-fs": "^4.1.2", + "inherits": "~2.0.0", + "mkdirp": ">=0.5 0", + "rimraf": "2" + }, + "dependencies": { + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", "dev": true, "optional": true }, - "tar": { - "version": "4.4.8", - "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.8.tgz", - "integrity": "sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ==", + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", "dev": true, "optional": true, "requires": { - "chownr": "^1.1.1", - "fs-minipass": "^1.2.5", - "minipass": "^2.3.4", - "minizlib": "^1.1.1", - "mkdirp": "^0.5.0", - "safe-buffer": "^5.1.2", - "yallist": "^3.0.2" - }, - "dependencies": { - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "optional": true - } + "minimist": "^1.2.5" } }, - "util-deprecate": { - "version": "1.0.2", - "resolved": false, - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "dev": true, - "optional": true - }, - "wide-align": { - "version": "1.1.2", - "resolved": false, - "integrity": "sha512-ijDLlyQ7s6x1JgCLur53osjm/UXUYD9+0PbYKrBsYisYXzCxN+HC3mYDNy/dWdmf3AwqwU3CXwDCvsNgGK1S0w==", + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", "dev": true, "optional": true, "requires": { - "string-width": "^1.0.2" + "glob": "^7.1.3" } - }, - "wrappy": { - "version": "1.0.2", - "resolved": false, - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true, - "optional": true - }, - "yallist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz", - "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==", - "dev": true, - "optional": true } } }, @@ -3939,17 +4271,6 @@ "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", "dev": true }, - "g-status": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/g-status/-/g-status-2.0.2.tgz", - "integrity": "sha512-kQoE9qH+T1AHKgSSD0Hkv98bobE90ILQcXAF4wvGgsr7uFqNvwmh8j+Lq3l0RVt3E3HjSbv2B9biEGcEtpHLCA==", - "dev": true, - "requires": { - "arrify": "^1.0.1", - "matcher": "^1.0.0", - "simple-git": "^1.85.0" - } - }, "gauge": { "version": "2.7.4", "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", @@ -4012,16 +4333,11 @@ "is-property": "^1.0.2" } }, - "generic-pool": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.6.1.tgz", - "integrity": "sha512-iMmD/pY4q0+V+f8o4twE9JPeqfNuX+gJAaIPB3B0W1lFkBOtTxBo6B0HxHPgGhzQA8jego7EWopcYq/UDJO2KA==", - "dev": true - }, "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==" + "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", + "dev": true }, "get-func-name": { "version": "2.0.0", @@ -4030,9 +4346,9 @@ "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.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-pkg-repo": { @@ -4064,12 +4380,6 @@ "map-obj": "^1.0.0" } }, - "get-stdin": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", - "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=", - "dev": true - }, "indent-string": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", @@ -4104,9 +4414,9 @@ } }, "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", "dev": true }, "redent": { @@ -4137,16 +4447,31 @@ } }, "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==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", + "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=", "dev": true }, "get-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", - "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", - "dev": true + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "requires": { + "pump": "^3.0.0" + }, + "dependencies": { + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + } + } }, "get-value": { "version": "2.0.6", @@ -4176,6 +4501,23 @@ "through2": "^2.0.0" }, "dependencies": { + "camelcase": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", + "dev": true + }, + "camelcase-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-4.2.0.tgz", + "integrity": "sha1-oqpfsa9oh1glnDLBQUJteJI7m3c=", + "dev": true, + "requires": { + "camelcase": "^4.1.0", + "map-obj": "^2.0.0", + "quick-lru": "^1.0.0" + } + }, "dargs": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/dargs/-/dargs-4.1.0.tgz", @@ -4184,6 +4526,180 @@ "requires": { "number-is-nan": "^1.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" + } + }, + "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 + }, + "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": "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" + } + }, + "map-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-2.0.0.tgz", + "integrity": "sha1-plzSkIepJZi4eRJXpSPgISIqwfk=", + "dev": true + }, + "meow": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/meow/-/meow-4.0.1.tgz", + "integrity": "sha512-xcSBHD5Z86zaOc+781KrupuHAzeGXSLtiAOmBsiLDiPSaYSB6hdew2ng9EBAnZ62jagG9MHAOdxpDi/lWBFJ/A==", + "dev": true, + "requires": { + "camelcase-keys": "^4.0.0", + "decamelize-keys": "^1.0.0", + "loud-rejection": "^1.0.0", + "minimist": "^1.1.3", + "minimist-options": "^3.0.1", + "normalize-package-data": "^2.3.4", + "read-pkg-up": "^3.0.0", + "redent": "^2.0.0", + "trim-newlines": "^2.0.0" + } + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + }, + "minimist-options": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-3.0.2.tgz", + "integrity": "sha512-FyBrT/d0d4+uiZRbqznPXqw3IpZZG3gl3wKWiX784FycUKVwBt0uLBFkQrtE4tZOrgo78nZp2jnKz3L65T5LdQ==", + "dev": true, + "requires": { + "arrify": "^1.0.1", + "is-plain-obj": "^1.1.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": "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 + }, + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + }, + "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" + } + }, + "quick-lru": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-1.1.0.tgz", + "integrity": "sha1-Q2CxfGETatOAeDl/8RQW4Ybc+7g=", + "dev": true + }, + "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" + } + }, + "read-pkg-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz", + "integrity": "sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc=", + "dev": true, + "requires": { + "find-up": "^2.0.0", + "read-pkg": "^3.0.0" + } + }, + "redent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-2.0.0.tgz", + "integrity": "sha1-wbIAe0LVfrE4kHmzyDM2OdXhzKo=", + "dev": true, + "requires": { + "indent-string": "^3.0.0", + "strip-indent": "^2.0.0" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + }, + "strip-indent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-2.0.0.tgz", + "integrity": "sha1-XvjbKV0B5u1sv3qrlpmNeCJSe2g=", + "dev": true + }, + "trim-newlines": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-2.0.0.tgz", + "integrity": "sha1-tAPQuRvlDDMd/EuC7s6yLD3hbSA=", + "dev": true } } }, @@ -4206,13 +4722,21 @@ } }, "git-semver-tags": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/git-semver-tags/-/git-semver-tags-2.0.2.tgz", - "integrity": "sha512-34lMF7Yo1xEmsK2EkbArdoU79umpvm0MfzaDkSNYSJqtM5QLAVTPWgpiXSVI5o/O9EvZPSrP4Zvnec/CqhSd5w==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/git-semver-tags/-/git-semver-tags-4.1.0.tgz", + "integrity": "sha512-TcxAGeo03HdErzKzi4fDD+xEL7gi8r2Y5YSxH6N2XYdVSV5UkBwfrt7Gqo1b+uSHCjy/sa9Y6BBBxxFLxfbhTg==", "dev": true, "requires": { - "meow": "^4.0.0", - "semver": "^5.5.0" + "meow": "^7.0.0", + "semver": "^6.0.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 + } } }, "gitconfiglocal": { @@ -4231,9 +4755,9 @@ "dev": true }, "glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -4283,9 +4807,9 @@ } }, "glob-watcher": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/glob-watcher/-/glob-watcher-5.0.3.tgz", - "integrity": "sha512-8tWsULNEPHKQ2MR4zXuzSmqbdyV5PtwwCaWSGQ1WwHsJ07ilNeN1JB8ntxhckbnpSHaf9dXFUHzIWvm1I13dsg==", + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/glob-watcher/-/glob-watcher-5.0.5.tgz", + "integrity": "sha512-zOZgGGEHPklZNjZQaZ9f41i7F2YwE+tS5ZHrDhbBCk3stwahn5vQxnFmBJZHoYdusR6R1bLSXeGUy/BhctwKzw==", "dev": true, "requires": { "anymatch": "^2.0.0", @@ -4293,7 +4817,16 @@ "chokidar": "^2.0.0", "is-negated-glob": "^1.0.0", "just-debounce": "^1.0.0", + "normalize-path": "^3.0.0", "object.defaults": "^1.1.0" + }, + "dependencies": { + "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 + } } }, "global-modules": { @@ -4330,22 +4863,25 @@ } }, "globby": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", - "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", - "dev": true, - "requires": { - "array-union": "^1.0.1", - "glob": "^7.0.3", - "object-assign": "^4.0.1", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-10.0.2.tgz", + "integrity": "sha512-7dUi7RvCoT/xast/o/dLN53oqND4yk0nsHkhRgn9w65C4PofCLOoJ39iSOg+qVDdWQPIEj+eszMHQ+aLVwwQSg==", + "dev": true, + "requires": { + "@types/glob": "^7.1.1", + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.0.3", + "glob": "^7.1.3", + "ignore": "^5.1.1", + "merge2": "^1.2.3", + "slash": "^3.0.0" }, "dependencies": { - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "ignore": { + "version": "5.1.8", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", + "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", "dev": true } } @@ -4372,14 +4908,14 @@ "dev": true }, "gulp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/gulp/-/gulp-4.0.0.tgz", - "integrity": "sha1-lXZsYB2t5Kd+0+eyttwDiBtZY2Y=", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/gulp/-/gulp-4.0.2.tgz", + "integrity": "sha512-dvEs27SCZt2ibF29xYgmnwwCYZxdxhQ/+LFWlbAW8y7jt68L/65402Lz3+CKy0Ov4rOs+NERmDq7YlZaDqUIfA==", "dev": true, "requires": { - "glob-watcher": "^5.0.0", - "gulp-cli": "^2.0.0", - "undertaker": "^1.0.0", + "glob-watcher": "^5.0.3", + "gulp-cli": "^2.2.0", + "undertaker": "^1.2.1", "vinyl-fs": "^3.0.0" }, "dependencies": { @@ -4407,9 +4943,9 @@ } }, "gulp-cli": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/gulp-cli/-/gulp-cli-2.0.1.tgz", - "integrity": "sha512-RxujJJdN8/O6IW2nPugl7YazhmrIEjmiVfPKrWt68r71UCaLKS71Hp0gpKT+F6qOUFtr7KqtifDKaAJPRVvMYQ==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/gulp-cli/-/gulp-cli-2.3.0.tgz", + "integrity": "sha512-zzGBl5fHo0EKSXsHzjspp3y5CONegCm8ErO5Qh0UzFzk2y4tMvzLWhoDokADbarfZRL2pGpRp7yt6gfJX4ph7A==", "dev": true, "requires": { "ansi-colors": "^1.0.1", @@ -4420,15 +4956,15 @@ "copy-props": "^2.0.1", "fancy-log": "^1.3.2", "gulplog": "^1.0.0", - "interpret": "^1.1.0", + "interpret": "^1.4.0", "isobject": "^3.0.1", - "liftoff": "^2.5.0", + "liftoff": "^3.1.0", "matchdep": "^2.0.0", "mute-stdout": "^1.0.0", "pretty-hrtime": "^1.0.0", "replace-homedir": "^1.0.0", "semver-greatest-satisfied-range": "^1.1.0", - "v8flags": "^3.0.1", + "v8flags": "^3.2.0", "yargs": "^7.1.0" } }, @@ -4438,16 +4974,7 @@ "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "dev": true, "requires": { - "number-is-nan": "^1.0.0" - } - }, - "os-locale": { - "version": "1.4.0", - "resolved": "http://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", - "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", - "dev": true, - "requires": { - "lcid": "^1.0.0" + "number-is-nan": "^1.0.0" } }, "string-width": { @@ -4477,9 +5004,9 @@ "dev": true }, "yargs": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.0.tgz", - "integrity": "sha1-a6MY6xaWFyf10oT46gA+jWFU0Mg=", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.1.tgz", + "integrity": "sha512-huO4Fr1f9PmiJJdll5kwoS2e4GqzGSsMT3PPMpOwoVkOK8ckqAewMTZyA6LXVQWflleb/Z8oPBEvNsMft0XE+g==", "dev": true, "requires": { "camelcase": "^3.0.0", @@ -4494,16 +5021,17 @@ "string-width": "^1.0.2", "which-module": "^1.0.0", "y18n": "^3.2.1", - "yargs-parser": "^5.0.0" + "yargs-parser": "5.0.0-security.0" } }, "yargs-parser": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.0.tgz", - "integrity": "sha1-J17PDX/+Bcd+ZOfIbkzZS/DhIoo=", + "version": "5.0.0-security.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.0-security.0.tgz", + "integrity": "sha512-T69y4Ps64LNesYxeYGYPvfoMTt/7y1XtfpIslUeK4um+9Hu7hlGoRtaDLvdXb7+/tfq4opVa2HRY5xGip022rQ==", "dev": true, "requires": { - "camelcase": "^3.0.0" + "camelcase": "^3.0.0", + "object.assign": "^4.1.0" } } } @@ -4574,6 +5102,19 @@ "table": "^5.2.3", "text-table": "^0.2.0", "v8-compile-cache": "^2.0.3" + }, + "dependencies": { + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + } } }, "eslint-utils": { @@ -4616,6 +5157,12 @@ } } }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, "import-fresh": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz", @@ -4699,6 +5246,15 @@ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } } } }, @@ -4717,67 +5273,76 @@ } }, "gulp-mocha": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/gulp-mocha/-/gulp-mocha-6.0.0.tgz", - "integrity": "sha512-FfBldW5ttnDpKf4Sg6/BLOOKCCbr5mbixDGK1t02/8oSrTCwNhgN/mdszG3cuQuYNzuouUdw4EH/mlYtgUscPg==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/gulp-mocha/-/gulp-mocha-7.0.2.tgz", + "integrity": "sha512-ZXBGN60TXYnFhttr19mfZBOtlHYGx9SvCSc+Kr/m2cMIGloUe176HBPwvPqlakPuQgeTGVRS47NmcdZUereKMQ==", "dev": true, "requires": { - "dargs": "^5.1.0", - "execa": "^0.10.0", - "mocha": "^5.2.0", - "npm-run-path": "^2.0.2", + "dargs": "^7.0.0", + "execa": "^2.0.4", + "mocha": "^6.2.0", "plugin-error": "^1.0.1", - "supports-color": "^5.4.0", - "through2": "^2.0.3" + "supports-color": "^7.0.0", + "through2": "^3.0.1" }, "dependencies": { - "commander": { - "version": "2.15.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", - "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==", + "ansi-colors": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz", + "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==", "dev": true }, - "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", "dev": true, "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" } }, "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", "dev": true, "requires": { - "ms": "2.0.0" + "ms": "^2.1.1" } }, - "execa": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-0.10.0.tgz", - "integrity": "sha512-7XOMnz8Ynx1gGo/3hyV9loYNPWM94jG3+3T3Y8tsfSstFmETmENCMU/A/zj8Lyaj1lkgEepKepvd6240tBRvlw==", + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", "dev": true, "requires": { - "cross-spawn": "^6.0.0", - "get-stream": "^3.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" + "locate-path": "^3.0.0" } }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, "glob": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", "dev": true, "requires": { "fs.realpath": "^1.0.0", @@ -4788,38 +5353,82 @@ "path-is-absolute": "^1.0.0" } }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + }, + "mkdirp": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.4.tgz", + "integrity": "sha512-iG9AK/dJLtJ0XNgTuDbSyNS3zECqDlAhnQW4CsNxBG3LQJBbHmRX1egw39DmtOdCAqY+dKXV+sgPgilNWUKMVw==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, "mocha": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-5.2.0.tgz", - "integrity": "sha512-2IUgKDhc3J7Uug+FxMXuqIyYzH7gJjXECKe/w43IGgQHTSj3InJi+yAA7T24L9bQMRKiUEHxEX37G5JpVUGLcQ==", + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-6.2.3.tgz", + "integrity": "sha512-0R/3FvjIGH3eEuG17ccFPk117XL2rWxatr81a57D+r/x2uTYZRbdZ4oVidEUMh2W2TJDa7MdAb12Lm2/qrKajg==", "dev": true, "requires": { + "ansi-colors": "3.2.3", "browser-stdout": "1.3.1", - "commander": "2.15.1", - "debug": "3.1.0", + "debug": "3.2.6", "diff": "3.5.0", "escape-string-regexp": "1.0.5", - "glob": "7.1.2", + "find-up": "3.0.0", + "glob": "7.1.3", "growl": "1.10.5", - "he": "1.1.1", + "he": "1.2.0", + "js-yaml": "3.13.1", + "log-symbols": "2.2.0", "minimatch": "3.0.4", - "mkdirp": "0.5.1", - "supports-color": "5.4.0" + "mkdirp": "0.5.4", + "ms": "2.1.1", + "node-environment-flags": "1.0.5", + "object.assign": "4.1.0", + "strip-json-comments": "2.0.1", + "supports-color": "6.0.0", + "which": "1.3.1", + "wide-align": "1.1.3", + "yargs": "13.3.2", + "yargs-parser": "13.1.2", + "yargs-unparser": "1.6.0" }, "dependencies": { - "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "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": { - "minimist": "0.0.8" + "argparse": "^1.0.7", + "esprima": "^4.0.0" } }, "supports-color": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", - "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", + "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", "dev": true, "requires": { "has-flag": "^3.0.0" @@ -4827,10 +5436,214 @@ } } }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "plugin-error": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-1.0.1.tgz", + "integrity": "sha512-L1zP0dk7vGweZME2i+EeakvUNqSrdiI3F91TwEoYiGrAfUXmVv6fJIq4g82PAXxNsWOp0J7ZqQy/3Szz0ajTxA==", + "dev": true, + "requires": { + "ansi-colors": "^1.0.1", + "arr-diff": "^4.0.0", + "arr-union": "^3.1.0", + "extend-shallow": "^3.0.2" + }, + "dependencies": { + "ansi-colors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz", + "integrity": "sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==", + "dev": true, + "requires": { + "ansi-wrap": "^0.1.0" + } + } + } + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "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" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "through2": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.2.tgz", + "integrity": "sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ==", + "dev": true, + "requires": { + "inherits": "^2.0.4", + "readable-stream": "2 || 3" + }, + "dependencies": { + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + } + } + }, + "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==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + } + }, + "y18n": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", + "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", + "dev": true + }, + "yargs": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "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.2" + } + }, + "yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } + }, + "gulp-rename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/gulp-rename/-/gulp-rename-2.0.0.tgz", + "integrity": "sha512-97Vba4KBzbYmR5VBs9mWmK+HwIf5mj+/zioxfZhOKeXtx5ZjBk57KFlePf5nxq9QsTtFl0ejnHE3zTC9MHXqyQ==", + "dev": true + }, + "gulp-replace": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/gulp-replace/-/gulp-replace-1.0.0.tgz", + "integrity": "sha512-lgdmrFSI1SdhNMXZQbrC75MOl1UjYWlOWNbNRnz+F/KHmgxt3l6XstBoAYIdadwETFyG/6i+vWUSCawdC3pqOw==", + "dev": true, + "requires": { + "istextorbinary": "2.2.1", + "readable-stream": "^2.0.1", + "replacestream": "^4.0.0" + } + }, + "gulp-shell": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/gulp-shell/-/gulp-shell-0.8.0.tgz", + "integrity": "sha512-wHNCgmqbWkk1c6Gc2dOL5SprcoeujQdeepICwfQRo91DIylTE7a794VEE+leq3cE2YDoiS5ulvRfKVIEMazcTQ==", + "dev": true, + "requires": { + "chalk": "^3.0.0", + "fancy-log": "^1.3.3", + "lodash.template": "^4.5.0", + "plugin-error": "^1.0.1", + "through2": "^3.0.1", + "tslib": "^1.10.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "dev": true, + "requires": { + "@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==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.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==", + "dev": true, + "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==", + "dev": true + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, "plugin-error": { @@ -4844,49 +5657,22 @@ "arr-union": "^3.1.0", "extend-shallow": "^3.0.2" } - } - } - }, - "gulp-rename": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/gulp-rename/-/gulp-rename-1.4.0.tgz", - "integrity": "sha512-swzbIGb/arEoFK89tPY58vg3Ok1bw+d35PfUNwWqdo7KM4jkmuGA78JiDNqR+JeZFaeeHnRg9N7aihX3YPmsyg==", - "dev": true - }, - "gulp-replace": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/gulp-replace/-/gulp-replace-1.0.0.tgz", - "integrity": "sha512-lgdmrFSI1SdhNMXZQbrC75MOl1UjYWlOWNbNRnz+F/KHmgxt3l6XstBoAYIdadwETFyG/6i+vWUSCawdC3pqOw==", - "dev": true, - "requires": { - "istextorbinary": "2.2.1", - "readable-stream": "^2.0.1", - "replacestream": "^4.0.0" - } - }, - "gulp-shell": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/gulp-shell/-/gulp-shell-0.6.5.tgz", - "integrity": "sha512-f3m1WcS0o2B72/PGj1Jbv9zYR9rynBh/EQJv64n01xQUo7j7anols0eww9GG/WtDTzGVQLrupVDYkifRFnj5Zg==", - "dev": true, - "requires": { - "async": "^2.1.5", - "chalk": "^2.3.0", - "fancy-log": "^1.3.2", - "lodash": "^4.17.4", - "lodash.template": "^4.4.0", - "plugin-error": "^0.1.2", - "through2": "^2.0.3" - }, - "dependencies": { - "async": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.1.tgz", - "integrity": "sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==", + }, + "through2": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.2.tgz", + "integrity": "sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ==", "dev": true, "requires": { - "lodash": "^4.17.10" + "inherits": "^2.0.4", + "readable-stream": "2 || 3" } + }, + "tslib": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz", + "integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==", + "dev": true } } }, @@ -4918,23 +5704,29 @@ } }, "gulp-typescript": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/gulp-typescript/-/gulp-typescript-5.0.0.tgz", - "integrity": "sha512-lMj2U+Ni6HyFaY2nr1sSQ6D014eHil5L1i52XWBaAQUR9UAUUp9btnm4yRBT2Jb8xhrwqmhMssZf/g2B7cinCA==", + "version": "6.0.0-alpha.1", + "resolved": "https://registry.npmjs.org/gulp-typescript/-/gulp-typescript-6.0.0-alpha.1.tgz", + "integrity": "sha512-KoT0TTfjfT7w3JItHkgFH1T/zK4oXWC+a8xxKfniRfVcA0Fa1bKrIhztYelYmb+95RB80OLMBreknYkdwzdi2Q==", "dev": true, "requires": { - "ansi-colors": "^3.0.5", + "ansi-colors": "^4.1.1", "plugin-error": "^1.0.1", "source-map": "^0.7.3", - "through2": "^3.0.0", - "vinyl": "^2.1.0", + "through2": "^3.0.1", + "vinyl": "^2.2.0", "vinyl-fs": "^3.0.3" }, "dependencies": { "ansi-colors": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz", - "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, "plugin-error": { @@ -4967,11 +5759,12 @@ "dev": true }, "through2": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.1.tgz", - "integrity": "sha512-M96dvTalPT3YbYLaKaCuwu+j06D/8Jfib0o/PxbVt6Amhv3dUAtW6rTV1jPgJSBG83I/e04Y6xkVdVhSRhi0ww==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.2.tgz", + "integrity": "sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ==", "dev": true, "requires": { + "inherits": "^2.0.4", "readable-stream": "2 || 3" } } @@ -5026,15 +5819,41 @@ "dev": true }, "har-validator": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", - "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", "dev": true, "requires": { - "ajv": "^6.5.5", + "ajv": "^6.12.3", "har-schema": "^2.0.0" + }, + "dependencies": { + "ajv": { + "version": "6.12.4", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.4.tgz", + "integrity": "sha512-eienB2c9qVQs2KWexhkrdMLVDoIQCz5KSeLxwg9Lzk4DOfBtIK9PQwwufcsn1jjGuf9WZmqPMbGxOzfcuphJCQ==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + } } }, + "hard-rejection": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", + "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==", + "dev": true + }, "has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", @@ -5060,9 +5879,9 @@ } }, "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" }, "has-symbols": { "version": "1.0.0", @@ -5097,6 +5916,26 @@ "kind-of": "^4.0.0" }, "dependencies": { + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, "kind-of": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", @@ -5109,20 +5948,20 @@ } }, "he": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", - "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", "dev": true }, "highlight.js": { - "version": "9.15.6", - "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.15.6.tgz", - "integrity": "sha512-zozTAWM1D6sozHo8kqhfYgsac+B+q0PmsjXeyDrYIHHcBN0zTVT66+s2GW1GZv7DbyaROdLXKdabwS/WqPyIdQ==" + "version": "9.18.3", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.18.3.tgz", + "integrity": "sha512-zBZAmhSupHIl5sITeMqIJnYCDfAEc3Gdkqj65wC1lpI468MMQeeQkhcIAvk+RylAkxrCcI9xy9piHiXeQ1BdzQ==" }, "homedir-polyfill": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz", - "integrity": "sha1-TCu8inWJmP7r9e1oWA921GdotLw=", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", + "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", "dev": true, "requires": { "parse-passwd": "^1.0.0" @@ -5145,134 +5984,64 @@ "sshpk": "^1.7.0" } }, + "human-signals": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", + "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", + "dev": true + }, "husky": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/husky/-/husky-1.3.1.tgz", - "integrity": "sha512-86U6sVVVf4b5NYSZ0yvv88dRgBSSXXmHaiq5pP4KDj5JVzdwKgBjEtUPOm8hcoytezFwbU+7gotXNhpHdystlg==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/husky/-/husky-4.3.0.tgz", + "integrity": "sha512-tTMeLCLqSBqnflBZnlVDhpaIMucSGaYyX6855jM4AguGeWCeSzNdb1mfyWduTZ3pe3SJVvVWGL0jO1iKZVPfTA==", "dev": true, "requires": { - "cosmiconfig": "^5.0.7", - "execa": "^1.0.0", - "find-up": "^3.0.0", - "get-stdin": "^6.0.0", - "is-ci": "^2.0.0", - "pkg-dir": "^3.0.0", - "please-upgrade-node": "^3.1.1", - "read-pkg": "^4.0.1", - "run-node": "^1.0.0", - "slash": "^2.0.0" + "chalk": "^4.0.0", + "ci-info": "^2.0.0", + "compare-versions": "^3.6.0", + "cosmiconfig": "^7.0.0", + "find-versions": "^3.2.0", + "opencollective-postinstall": "^2.0.2", + "pkg-dir": "^4.2.0", + "please-upgrade-node": "^3.2.0", + "slash": "^3.0.0", + "which-pm-runs": "^1.0.0" }, "dependencies": { - "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "dev": true, - "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, - "execa": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", - "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", - "dev": true, - "requires": { - "cross-spawn": "^6.0.0", - "get-stream": "^4.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - } - }, - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", "dev": true, "requires": { - "locate-path": "^3.0.0" + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" } }, - "get-stream": { + "chalk": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } - }, - "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, - "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - } - }, - "p-limit": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.1.0.tgz", - "integrity": "sha512-NhURkNcrVB+8hNfLuysU8enY5xn2KXphsHBaC2YmRNTZRc7RWusw6apSpdEj3jo4CMb6W9nrF6tTnsJsJeyu6g==", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", "dev": true, "requires": { - "p-try": "^2.0.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" } }, - "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "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==", "dev": true, "requires": { - "p-limit": "^2.0.0" + "color-name": "~1.1.4" } }, - "p-try": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.0.0.tgz", - "integrity": "sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ==", + "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==", "dev": true - }, - "parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", - "dev": true, - "requires": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - } - }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "read-pkg": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-4.0.1.tgz", - "integrity": "sha1-ljYlN48+HE1IyFhytabsfV0JMjc=", - "dev": true, - "requires": { - "normalize-package-data": "^2.3.2", - "parse-json": "^4.0.0", - "pify": "^3.0.0" - } } } }, @@ -5297,22 +6066,22 @@ "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==", "dev": true, "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.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": { - "caller-path": "^2.0.0", - "resolve-from": "^3.0.0" + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" } }, "imurmurhash": { @@ -5322,9 +6091,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": { @@ -5486,6 +6255,14 @@ "dev": true, "requires": { "tslib": "^1.9.0" + }, + "dependencies": { + "tslib": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz", + "integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==", + "dev": true + } } }, "string-width": { @@ -5526,9 +6303,9 @@ } }, "interpret": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.1.0.tgz", - "integrity": "sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ=", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", "dev": true }, "invert-kv": { @@ -5549,7 +6326,7 @@ }, "is-accessor-descriptor": { "version": "0.1.6", - "resolved": "http://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", "dev": true, "requires": { @@ -5567,6 +6344,12 @@ } } }, + "is-arguments": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.0.4.tgz", + "integrity": "sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA==", + "dev": true + }, "is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", @@ -5598,23 +6381,14 @@ } }, "is-callable": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", - "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.1.tgz", + "integrity": "sha512-wliAfSzx6V+6WfMOmus1xy0XvSgf/dlStkvTfq7F0g4bOIW0PSUbnyse3NhDwdyYS1ozfUtAAySqTws3z9Eqgg==", "dev": true }, - "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-data-descriptor": { "version": "0.1.4", - "resolved": "http://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", "dev": true, "requires": { @@ -5633,9 +6407,9 @@ } }, "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=", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", + "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", "dev": true }, "is-descriptor": { @@ -5657,12 +6431,6 @@ } } }, - "is-directory": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", - "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=", - "dev": true - }, "is-extendable": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", @@ -5676,18 +6444,16 @@ "dev": true }, "is-finite": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", - "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", - "dev": true, - "requires": { - "number-is-nan": "^1.0.0" - } + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.1.0.tgz", + "integrity": "sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w==", + "dev": true }, "is-fullwidth-code-point": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true }, "is-glob": { "version": "4.0.0", @@ -5695,73 +6461,44 @@ "integrity": "sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A=", "dev": true, "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-negated-glob": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-negated-glob/-/is-negated-glob-1.0.0.tgz", - "integrity": "sha1-aRC8pdqMleeEtXUbl2z1oQ/uNtI=", - "dev": true - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } + "is-extglob": "^2.1.1" } }, + "is-map": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.1.tgz", + "integrity": "sha512-T/S49scO8plUiAOA2DBTBG3JHpn1yiw0kRp6dgiZ0v2/6twi5eiB0rHtHFH9ZIrvlWc6+4O+m4zg5+Z833aXgw==", + "dev": true + }, + "is-negated-glob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-negated-glob/-/is-negated-glob-1.0.0.tgz", + "integrity": "sha1-aRC8pdqMleeEtXUbl2z1oQ/uNtI=", + "dev": true + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, "is-obj": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", "dev": true }, - "is-observable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-observable/-/is-observable-1.1.0.tgz", - "integrity": "sha512-NqCa4Sa2d+u7BWc6CukaObG3Fh+CU9bvixbpcXYhy2VvYS7vVGIdAgnIS5Ks3A/cqk4rebLJ9s8zBstT2aKnIA==", - "dev": true, - "requires": { - "symbol-observable": "^1.1.0" - } - }, "is-path-cwd": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", - "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", + "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", "dev": true }, - "is-path-in-cwd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz", - "integrity": "sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==", - "dev": true, - "requires": { - "is-path-inside": "^1.0.0" - } - }, "is-path-inside": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", - "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", - "dev": true, - "requires": { - "path-is-inside": "^1.0.1" - } + "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-plain-obj": { "version": "1.1.0", @@ -5791,12 +6528,20 @@ "dev": true }, "is-regex": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", - "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz", + "integrity": "sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==", "dev": true, "requires": { - "has": "^1.0.1" + "has-symbols": "^1.0.1" + }, + "dependencies": { + "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 + } } }, "is-regexp": { @@ -5814,18 +6559,39 @@ "is-unc-path": "^1.0.0" } }, + "is-set": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.1.tgz", + "integrity": "sha512-eJEzOtVyenDs1TMzSQ3kU3K+E0GUS9sno+F0OBT97xsgcJsF9nXMBtkT9/kut5JEpM7oL7X/0qxR17K3mcwIAA==", + "dev": true + }, "is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" + "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 + }, + "is-string": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", + "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==", + "dev": true }, "is-symbol": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", - "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", + "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", "dev": true, "requires": { - "has-symbols": "^1.0.0" + "has-symbols": "^1.0.1" + }, + "dependencies": { + "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 + } } }, "is-text-path": { @@ -5879,7 +6645,8 @@ "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true }, "isobject": { "version": "3.0.1", @@ -5993,15 +6760,37 @@ "textextensions": "2" } }, + "iterate-iterator": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/iterate-iterator/-/iterate-iterator-1.0.1.tgz", + "integrity": "sha512-3Q6tudGN05kbkDQDI4CqjaBf4qf85w6W6GnuZDtUVYwKgtC1q8yxYX7CZed7N+tLzQqS6roujWvszf13T+n9aw==", + "dev": true + }, + "iterate-value": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/iterate-value/-/iterate-value-1.0.2.tgz", + "integrity": "sha512-A6fMAio4D2ot2r/TYzr4yUWrmwNdsN5xL7+HUiyACE4DXm+q8HtPcnFTp+NnW3k4N05tZ7FVYFFb2CR13NxyHQ==", + "dev": true, + "requires": { + "es-get-iterator": "^1.0.2", + "iterate-iterator": "^1.0.1" + } + }, "js-yaml": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", - "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", + "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", "requires": { "argparse": "^1.0.7", "esprima": "^4.0.0" } }, + "jsbi": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/jsbi/-/jsbi-3.1.4.tgz", + "integrity": "sha512-52QRRFSsi9impURE8ZUbzAMCLjPm4THO7H2fcuIvaaeFTbSysvkodbQQXIVsNgq/ypDbq6dJiuGKL0vZ/i9hUg==", + "dev": true + }, "jsbn": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", @@ -6014,6 +6803,12 @@ "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", "dev": true }, + "json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, "json-schema": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", @@ -6063,15 +6858,36 @@ "dev": true }, "just-extend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.0.2.tgz", - "integrity": "sha512-FrLwOgm+iXrPV+5zDU6Jqu4gCRXbWEQg2O3SKONsWE4w7AXFRkryS53bpWdaL9cNol+AmR3AEYz6kn+o0fCPnw==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.1.0.tgz", + "integrity": "sha512-ApcjaOdVTJ7y4r08xI5wIqpvwS48Q0PBG4DJROcEkH1f8MdAiNFyFxz3xoL0LWAVwjrwPYZdVHHxhRHcx/uGLA==", "dev": true }, + "jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "dev": true, + "requires": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "dev": true, + "requires": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", "dev": true }, "last-run": { @@ -6122,13 +6938,13 @@ } }, "liftoff": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/liftoff/-/liftoff-2.5.0.tgz", - "integrity": "sha1-IAkpG7Mc6oYbvxCnwVooyvdcMew=", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/liftoff/-/liftoff-3.1.0.tgz", + "integrity": "sha512-DlIPlJUkCV0Ips2zf2pJP0unEoT1kwYhiiPUGF3s/jtxTCjziNLoiVVh+jqWOWeFi6mmwQ5fNxvAUyPad4Dfog==", "dev": true, "requires": { "extend": "^3.0.0", - "findup-sync": "^2.0.0", + "findup-sync": "^3.0.0", "fined": "^1.0.1", "flagged-respawn": "^1.0.0", "is-plain-object": "^2.0.4", @@ -6137,221 +6953,225 @@ "resolve": "^1.1.7" } }, + "lines-and-columns": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz", + "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=", + "dev": true + }, "lint-staged": { - "version": "8.1.4", - "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-8.1.4.tgz", - "integrity": "sha512-oFbbhB/VzN8B3i/sIdb9gMfngGArI6jIfxSn+WPdQb2Ni3GJeS6T4j5VriSbQfxfMuYoQlMHOoFt+lfcWV0HfA==", + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-10.3.0.tgz", + "integrity": "sha512-an3VgjHqmJk0TORB/sdQl0CTkRg4E5ybYCXTTCSJ5h9jFwZbcgKIx5oVma5e7wp/uKt17s1QYFmYqT9MGVosGw==", "dev": true, "requires": { - "@iamstarkov/listr-update-renderer": "0.4.1", - "chalk": "^2.3.1", - "commander": "^2.14.1", - "cosmiconfig": "^5.0.2", - "debug": "^3.1.0", + "chalk": "^4.1.0", + "cli-truncate": "^2.1.0", + "commander": "^6.0.0", + "cosmiconfig": "^7.0.0", + "debug": "^4.1.1", "dedent": "^0.7.0", - "del": "^3.0.0", - "execa": "^1.0.0", - "find-parent-dir": "^0.3.0", - "g-status": "^2.0.2", - "is-glob": "^4.0.0", - "is-windows": "^1.0.2", - "listr": "^0.14.2", - "lodash": "^4.17.11", - "log-symbols": "^2.2.0", - "micromatch": "^3.1.8", - "npm-which": "^3.0.1", - "p-map": "^1.1.1", - "path-is-inside": "^1.0.2", - "pify": "^3.0.0", - "please-upgrade-node": "^3.0.2", - "staged-git-files": "1.1.2", - "string-argv": "^0.0.2", - "stringify-object": "^3.2.2", - "yup": "^0.26.10" + "enquirer": "^2.3.6", + "execa": "^4.0.3", + "listr2": "^2.6.0", + "log-symbols": "^4.0.0", + "micromatch": "^4.0.2", + "normalize-path": "^3.0.0", + "please-upgrade-node": "^3.2.0", + "string-argv": "0.3.1", + "stringify-object": "^3.3.0" }, "dependencies": { - "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", "dev": true, "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" } }, - "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", "dev": true, "requires": { - "ms": "^2.1.1" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.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==", + "dev": true, + "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==", + "dev": true + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" } }, "execa": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", - "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/execa/-/execa-4.0.3.tgz", + "integrity": "sha512-WFDXGHckXPWZX19t1kCsXzOpqX9LWYNqn4C+HqZlk/V0imTkzJZqf87ZBhvpHaftERYknpk0fjSylnXVlVgI0A==", "dev": true, "requires": { - "cross-spawn": "^6.0.0", - "get-stream": "^4.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" + "cross-spawn": "^7.0.0", + "get-stream": "^5.0.0", + "human-signals": "^1.1.1", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.0", + "onetime": "^5.1.0", + "signal-exit": "^3.0.2", + "strip-final-newline": "^2.0.0" } }, - "get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "log-symbols": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.0.0.tgz", + "integrity": "sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA==", "dev": true, "requires": { - "pump": "^3.0.0" + "chalk": "^4.0.0" } }, - "pump": { + "normalize-path": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", "dev": true, "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" + "path-key": "^3.0.0" } - } - } - }, - "listr": { - "version": "0.14.3", - "resolved": "https://registry.npmjs.org/listr/-/listr-0.14.3.tgz", - "integrity": "sha512-RmAl7su35BFd/xoMamRjpIE4j3v+L28o8CT5YhAXQJm1fD+1l9ngXY8JAQRJ+tFK2i5njvi0iRUKV09vPwA0iA==", - "dev": true, - "requires": { - "@samverschueren/stream-to-observable": "^0.3.0", - "is-observable": "^1.1.0", - "is-promise": "^2.1.0", - "is-stream": "^1.1.0", - "listr-silent-renderer": "^1.1.1", - "listr-update-renderer": "^0.5.0", - "listr-verbose-renderer": "^0.5.0", - "p-map": "^2.0.0", - "rxjs": "^6.3.3" - }, - "dependencies": { - "p-map": { + }, + "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/p-map/-/p-map-2.0.0.tgz", - "integrity": "sha512-GO107XdrSUmtHxVoi60qc9tUl/KkNKm+X2CF4P9amalpGxv5YqVPJNfSb0wcA+syCopkZvYYIzW8OVTQW59x/w==", + "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" + } } } }, - "listr-silent-renderer": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/listr-silent-renderer/-/listr-silent-renderer-1.1.1.tgz", - "integrity": "sha1-kktaN1cVN3C/Go4/v3S4u/P5JC4=", - "dev": true - }, - "listr-update-renderer": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/listr-update-renderer/-/listr-update-renderer-0.5.0.tgz", - "integrity": "sha512-tKRsZpKz8GSGqoI/+caPmfrypiaq+OQCbd+CovEC24uk1h952lVj5sC7SqyFUm+OaJ5HN/a1YLt5cit2FMNsFA==", + "listr2": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-2.6.2.tgz", + "integrity": "sha512-6x6pKEMs8DSIpA/tixiYY2m/GcbgMplMVmhQAaLFxEtNSKLeWTGjtmU57xvv6QCm2XcqzyNXL/cTSVf4IChCRA==", "dev": true, "requires": { - "chalk": "^1.1.3", - "cli-truncate": "^0.2.1", - "elegant-spinner": "^1.0.1", - "figures": "^1.7.0", - "indent-string": "^3.0.0", - "log-symbols": "^1.0.2", - "log-update": "^2.3.0", - "strip-ansi": "^3.0.1" + "chalk": "^4.1.0", + "cli-truncate": "^2.1.0", + "figures": "^3.2.0", + "indent-string": "^4.0.0", + "log-update": "^4.0.0", + "p-map": "^4.0.0", + "rxjs": "^6.6.2", + "through": "^2.3.8" }, "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true - }, "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", "dev": true, "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" } }, - "log-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-1.0.2.tgz", - "integrity": "sha1-N2/3tY6jCGoPCfrMdGF+ylAeGhg=", + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", "dev": true, "requires": { - "chalk": "^1.0.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" } }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "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==", "dev": true, "requires": { - "ansi-regex": "^2.0.0" + "color-name": "~1.1.4" } }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "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==", "dev": true - } - } - }, - "listr-verbose-renderer": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/listr-verbose-renderer/-/listr-verbose-renderer-0.5.0.tgz", - "integrity": "sha512-04PDPqSlsqIOaaaGZ+41vq5FejI9auqTInicFRndCBgE3bXG8D6W1I+mWhk+1nqbHmyhla/6BUrd5OSiHwKRXw==", - "dev": true, - "requires": { - "chalk": "^2.4.1", - "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=", + }, + "indent-string": { + "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 + }, + "p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", "dev": true, "requires": { - "escape-string-regexp": "^1.0.5" + "aggregate-error": "^3.0.0" } } } }, "load-json-file": { "version": "1.1.0", - "resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", "dev": true, "requires": { @@ -6364,19 +7184,18 @@ "dependencies": { "pify": { "version": "2.3.0", - "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", "dev": true } } }, "locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "requires": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" + "p-locate": "^4.1.0" } }, "lodash": { @@ -6391,12 +7210,6 @@ "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=", "dev": true }, - "lodash.debounce": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=", - "dev": true - }, "lodash.get": { "version": "4.4.2", "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", @@ -6435,37 +7248,141 @@ "dev": true, "requires": { "chalk": "^2.0.1" + }, + "dependencies": { + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } } }, "log-update": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/log-update/-/log-update-2.3.0.tgz", - "integrity": "sha1-iDKP19HOeTiykoN0bwsbwSayRwg=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-4.0.0.tgz", + "integrity": "sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==", "dev": true, "requires": { - "ansi-escapes": "^3.0.0", - "cli-cursor": "^2.0.0", - "wrap-ansi": "^3.0.1" + "ansi-escapes": "^4.3.0", + "cli-cursor": "^3.1.0", + "slice-ansi": "^4.0.0", + "wrap-ansi": "^6.2.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==", + "dev": true + }, + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "dev": true, + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true + }, + "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==", + "dev": true, + "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==", + "dev": true + }, + "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==", + "dev": true + }, + "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==", + "dev": true + }, + "slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + } + }, + "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==", + "dev": true, + "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==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + }, "wrap-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-3.0.1.tgz", - "integrity": "sha1-KIoE2H7aXChuBg3+jxNc6NAH+Lo=", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", "dev": true, "requires": { - "string-width": "^2.1.1", - "strip-ansi": "^4.0.0" + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" } } } }, - "lolex": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/lolex/-/lolex-3.1.0.tgz", - "integrity": "sha512-zFo5MgCJ0rZ7gQg69S4pqBsLURbFw11X68C18OcJjJQbqaXm2NoTrGl1IMM3TIz0/BnN1tIs2tzmmqvCsOMMjw==", - "dev": true - }, "long": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", @@ -6483,13 +7400,12 @@ } }, "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==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", "dev": true, "requires": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" + "yallist": "^3.0.2" } }, "lru-queue": { @@ -6502,9 +7418,9 @@ } }, "make-error": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.5.tgz", - "integrity": "sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g==", + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", "dev": true }, "make-iterator": { @@ -6516,14 +7432,6 @@ "kind-of": "^6.0.2" } }, - "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==", - "requires": { - "p-defer": "^1.0.0" - } - }, "map-cache": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", @@ -6531,9 +7439,9 @@ "dev": true }, "map-obj": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-2.0.0.tgz", - "integrity": "sha1-plzSkIepJZi4eRJXpSPgISIqwfk=", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.1.0.tgz", + "integrity": "sha512-glc9y00wgtwcDmp7GaE/0b0OnxpNJsVf3ael/An6Fe2Q51LLwN1er6sdomLRzz5h0+yMpiYLhWYF5R7HeqVd4g==", "dev": true }, "map-visit": { @@ -6555,31 +7463,131 @@ "micromatch": "^3.0.4", "resolve": "^1.4.0", "stack-trace": "0.0.10" - } - }, - "matcher": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/matcher/-/matcher-1.1.1.tgz", - "integrity": "sha512-+BmqxWIubKTRKNWx/ahnCkk3mG8m7OturVlqq6HiojGJTd5hVYbgZm6WzcYPCoB+KBT4Vd6R7WSRG2OADNaCjg==", - "dev": true, - "requires": { - "escape-string-regexp": "^1.0.4" - } - }, - "mem": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz", - "integrity": "sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==", - "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==" + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "findup-sync": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-2.0.0.tgz", + "integrity": "sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw=", + "dev": true, + "requires": { + "detect-file": "^1.0.0", + "is-glob": "^3.1.0", + "micromatch": "^3.0.4", + "resolve-dir": "^1.0.1" + } + }, + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, + "requires": { + "is-extglob": "^2.1.0" + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } } } }, @@ -6607,139 +7615,148 @@ "optional": true }, "meow": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/meow/-/meow-4.0.1.tgz", - "integrity": "sha512-xcSBHD5Z86zaOc+781KrupuHAzeGXSLtiAOmBsiLDiPSaYSB6hdew2ng9EBAnZ62jagG9MHAOdxpDi/lWBFJ/A==", - "dev": true, - "requires": { - "camelcase-keys": "^4.0.0", - "decamelize-keys": "^1.0.0", - "loud-rejection": "^1.0.0", - "minimist": "^1.1.3", - "minimist-options": "^3.0.1", - "normalize-package-data": "^2.3.4", - "read-pkg-up": "^3.0.0", - "redent": "^2.0.0", - "trim-newlines": "^2.0.0" + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/meow/-/meow-7.1.1.tgz", + "integrity": "sha512-GWHvA5QOcS412WCo8vwKDlTelGLsCGBVevQB5Kva961rmNfun0PCbv5+xta2kUMFJyR8/oWnn7ddeKdosbAPbA==", + "dev": true, + "requires": { + "@types/minimist": "^1.2.0", + "camelcase-keys": "^6.2.2", + "decamelize-keys": "^1.1.0", + "hard-rejection": "^2.1.0", + "minimist-options": "4.1.0", + "normalize-package-data": "^2.5.0", + "read-pkg-up": "^7.0.1", + "redent": "^3.0.0", + "trim-newlines": "^3.0.0", + "type-fest": "^0.13.1", + "yargs-parser": "^18.1.3" }, "dependencies": { - "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=", + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", "dev": true, "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^4.0.0", - "pify": "^3.0.0", - "strip-bom": "^3.0.0" + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" } }, - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - }, "parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.1.0.tgz", + "integrity": "sha512-+mi/lmVVNKFNVyLXV31ERiy2CY5E1/F6QtJFEzoChPRwwngMNXRDQ9GJ5WdE2Z2P4AujsOi0/+2qHID68KwfIQ==", "dev": true, "requires": { + "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - } - }, - "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" + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" } }, "read-pkg": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", - "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", "dev": true, "requires": { - "load-json-file": "^4.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^3.0.0" + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, + "dependencies": { + "type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "dev": true + } } }, "read-pkg-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz", - "integrity": "sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc=", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", "dev": true, "requires": { - "find-up": "^2.0.0", - "read-pkg": "^3.0.0" + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" + }, + "dependencies": { + "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 + } } }, - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "type-fest": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz", + "integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==", "dev": true } } }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, "merge2": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.2.3.tgz", "integrity": "sha512-gdUU1Fwj5ep4kplwcmftruWofEFt6lfpkkr3h860CXbAB9c3hGb55EOL2ali0Td5oebvW0E1+3Sr+Ur7XfKpRA==", - "dev": true - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" + "dev": true + }, + "micromatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", + "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", + "dev": true, + "requires": { + "braces": "^3.0.1", + "picomatch": "^2.0.5" } }, "mime-db": { - "version": "1.40.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz", - "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==", + "version": "1.44.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz", + "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==", "dev": true }, "mime-types": { - "version": "2.1.24", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz", - "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==", + "version": "2.1.27", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz", + "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==", "dev": true, "requires": { - "mime-db": "1.40.0" + "mime-db": "1.44.0" } }, "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 }, "mimic-response": { "version": "2.1.0", - "resolved": "https://registry.npm.taobao.org/mimic-response/download/mimic-response-2.1.0.tgz", - "integrity": "sha1-0Tdj019hPQnsN+uzC6wEacDuj0M=", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", + "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==", + "dev": true + }, + "min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", "dev": true }, "minimatch": { @@ -6757,13 +7774,14 @@ "dev": true }, "minimist-options": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-3.0.2.tgz", - "integrity": "sha512-FyBrT/d0d4+uiZRbqznPXqw3IpZZG3gl3wKWiX784FycUKVwBt0uLBFkQrtE4tZOrgo78nZp2jnKz3L65T5LdQ==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz", + "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==", "dev": true, "requires": { "arrify": "^1.0.1", - "is-plain-obj": "^1.1.0" + "is-plain-obj": "^1.1.0", + "kind-of": "^6.0.3" } }, "minipass": { @@ -6815,51 +7833,53 @@ } }, "mkdirp": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.3.tgz", - "integrity": "sha512-6uCP4Qc0sWsgMLy1EOqqS/3rjDHOEnsStVr/4vtAIK2Y5i2kA7lFFejYrpIyiN9w0pYf4ckeCYT9f1r1P9KX5g==" + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" }, "mkdirp-classic": { "version": "0.5.3", - "resolved": "https://registry.npm.taobao.org/mkdirp-classic/download/mkdirp-classic-0.5.3.tgz", - "integrity": "sha1-+hDJEVzG2IZb4iG6R+6b7XhgERM=", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", "dev": true }, "mocha": { - "version": "6.1.4", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-6.1.4.tgz", - "integrity": "sha512-PN8CIy4RXsIoxoFJzS4QNnCH4psUCPWc4/rPrst/ecSJJbLBkubMiyGCP2Kj/9YnWbotFqAoeXyXMucj7gwCFg==", + "version": "8.1.3", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-8.1.3.tgz", + "integrity": "sha512-ZbaYib4hT4PpF4bdSO2DohooKXIn4lDeiYqB+vTmCdr6l2woW0b6H3pf5x4sM5nwQMru9RvjjHYWVGltR50ZBw==", "dev": true, "requires": { - "ansi-colors": "3.2.3", + "ansi-colors": "4.1.1", "browser-stdout": "1.3.1", - "debug": "3.2.6", - "diff": "3.5.0", - "escape-string-regexp": "1.0.5", - "find-up": "3.0.0", - "glob": "7.1.3", + "chokidar": "3.4.2", + "debug": "4.1.1", + "diff": "4.0.2", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.1.6", "growl": "1.10.5", "he": "1.2.0", - "js-yaml": "3.13.1", - "log-symbols": "2.2.0", + "js-yaml": "3.14.0", + "log-symbols": "4.0.0", "minimatch": "3.0.4", - "mkdirp": "0.5.1", - "ms": "2.1.1", - "node-environment-flags": "1.0.5", + "ms": "2.1.2", "object.assign": "4.1.0", - "strip-json-comments": "2.0.1", - "supports-color": "6.0.0", - "which": "1.3.1", + "promise.allsettled": "1.0.2", + "serialize-javascript": "4.0.0", + "strip-json-comments": "3.0.1", + "supports-color": "7.1.0", + "which": "2.0.2", "wide-align": "1.1.3", - "yargs": "13.2.2", - "yargs-parser": "13.0.0", - "yargs-unparser": "1.5.0" + "workerpool": "6.0.0", + "yargs": "13.3.2", + "yargs-parser": "13.1.2", + "yargs-unparser": "1.6.1" }, "dependencies": { "ansi-colors": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz", - "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", "dev": true }, "ansi-regex": { @@ -6868,173 +7888,209 @@ "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", "dev": true }, - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "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" + } + }, + "binary-extensions": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz", + "integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==", "dev": true }, - "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "chokidar": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.2.tgz", + "integrity": "sha512-IZHaDeBeI+sZJRX7lGcXsdzgvZqKv6sECqsbErJA4mHWfpRrD8B97kSFN4cQz6nGBGiuFia1MKR4d6c1o8Cv7A==", "dev": true, "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "fsevents": "~2.1.2", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.4.0" } }, - "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", "dev": true, "requires": { - "ms": "^2.1.1" + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" } }, - "execa": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", - "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "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==", "dev": true, "requires": { - "cross-spawn": "^6.0.0", - "get-stream": "^4.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" + "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==", + "dev": true + }, + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + }, "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, "requires": { - "locate-path": "^3.0.0" + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" } }, + "fsevents": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", + "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", + "dev": true, + "optional": true + }, "get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "dev": true }, - "get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "glob-parent": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", + "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", "dev": true, "requires": { - "pump": "^3.0.0" + "is-glob": "^4.0.1" } }, - "he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true - }, - "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 - }, - "lcid": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", - "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", + "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": { - "invert-kv": "^2.0.0" + "binary-extensions": "^2.0.0" } }, - "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", "dev": true, "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" + "is-extglob": "^2.1.1" } }, - "mem": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz", - "integrity": "sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==", + "locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, "requires": { - "map-age-cleaner": "^0.1.1", - "mimic-fn": "^2.0.0", - "p-is-promise": "^2.0.0" + "p-locate": "^5.0.0" } }, - "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 - }, - "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "log-symbols": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.0.0.tgz", + "integrity": "sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA==", "dev": true, "requires": { - "minimist": "0.0.8" + "chalk": "^4.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "dev": true, + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + } } }, - "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" - } + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "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 }, "p-limit": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz", - "integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.0.2.tgz", + "integrity": "sha512-iwqZSOoWIW+Ew4kAGUlN16J4M7OB3ysMLSZtnhmqx7njIHFPlxWBX8xo3lVTyFVq6mI/lL9qt2IsN1sHwaxJkg==", "dev": true, "requires": { "p-try": "^2.0.0" } }, "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, "requires": { - "p-limit": "^2.0.0" + "p-limit": "^3.0.2" } }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "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 }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "readdirp": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.4.0.tgz", + "integrity": "sha512-0xe001vZBnJEK+uKcj8qOhyAKPzIT+gStxWr3LCB0DwcXR5NZJ3IaC+yGnHCYzB/S7ov3m3EEbZI2zeNvX+hGQ==", "dev": true, "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" + "picomatch": "^2.2.1" } }, "require-main-filename": { @@ -7063,13 +8119,39 @@ "ansi-regex": "^4.1.0" } }, + "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 + }, "supports-color": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", - "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", + "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": "^3.0.0" + "has-flag": "^4.0.0" + } + }, + "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" + } + }, + "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==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" } }, "y18n": { @@ -7079,33 +8161,164 @@ "dev": true }, "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.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", "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.2" + }, + "dependencies": { + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + } } }, "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==", + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", "dev": true, "requires": { "camelcase": "^5.0.0", "decamelize": "^1.2.0" } + }, + "yargs-unparser": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.6.1.tgz", + "integrity": "sha512-qZV14lK9MWsGCmcr7u5oXGH0dbGqZAIxTDrWXZDo5zUr6b6iUmelNKO6x6R1dQT24AH3LgRxJpr8meWy2unolA==", + "dev": true, + "requires": { + "camelcase": "^5.3.1", + "decamelize": "^1.2.0", + "flat": "^4.1.0", + "is-plain-obj": "^1.1.0", + "yargs": "^14.2.3" + }, + "dependencies": { + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, + "yargs": { + "version": "14.2.3", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-14.2.3.tgz", + "integrity": "sha512-ZbotRWhF+lkjijC/VhmOT9wSgyBQ7+zr13+YLkhfsSiTriYsMzkTUFP18pFhWwBeMa5gUc1MzbhrO6/VB7c9Xg==", + "dev": true, + "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", + "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": "^15.0.1" + } + }, + "yargs-parser": { + "version": "15.0.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-15.0.1.tgz", + "integrity": "sha512-0OAMV2mAZQrs3FkNpDQcBk1x5HXb8X4twADss4S0Iuk+2dGnLOE/fRHrsYm542GduMveyA77OF4wrNJuanRCWw==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } } } }, @@ -7116,22 +8329,14 @@ "dev": true }, "mongodb": { - "version": "3.1.13", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.1.13.tgz", - "integrity": "sha512-sz2dhvBZQWf3LRNDhbd30KHVzdjZx9IKC0L+kSZ/gzYquCF5zPOgGqRz6sSCqYZtKP2ekB4nfLxhGtzGHnIKxA==", - "dev": true, - "requires": { - "mongodb-core": "3.1.11", - "safe-buffer": "^5.1.2" - } - }, - "mongodb-core": { - "version": "3.1.11", - "resolved": "https://registry.npmjs.org/mongodb-core/-/mongodb-core-3.1.11.tgz", - "integrity": "sha512-rD2US2s5qk/ckbiiGFHeu+yKYDXdJ1G87F6CG3YdaZpzdOm5zpoAZd/EKbPmFO6cQZ+XVXBXBJ660sSI0gc6qg==", + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.6.1.tgz", + "integrity": "sha512-uH76Zzr5wPptnjEKJRQnwTsomtFOU/kQEU8a9hKHr2M7y9qVk7Q4Pkv0EQVp88742z9+RwvsdTw6dRjDZCNu1g==", "dev": true, "requires": { - "bson": "^1.1.0", + "bl": "^2.2.0", + "bson": "^1.1.4", + "denque": "^1.4.1", "require_optional": "^1.0.1", "safe-buffer": "^5.1.2", "saslprep": "^1.0.0" @@ -7143,25 +8348,14 @@ "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" }, "mssql": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/mssql/-/mssql-4.3.2.tgz", - "integrity": "sha512-FMC/nvEjR+yMkkyPsHCiswckT7EExoKuTj9uC1yohtJuySgodzPqkJX7q+tsZsZyK8mFYo7JfX+li6/Xf+Irbg==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/mssql/-/mssql-6.2.1.tgz", + "integrity": "sha512-erINJ9EUPvPuWXifZfhum0CVEVrdvnFYlpgU6WKkQW69W4W7DWqJS2FHdedHnuJWlJ8x1WW1NcD8GFfF15O2aA==", "dev": true, "requires": { - "debug": "^3.2.6", - "generic-pool": "^3.6", - "tedious": "^2.7.1" - }, - "dependencies": { - "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - } + "debug": "^4", + "tarn": "^1.1.5", + "tedious": "^6.6.2" } }, "mute-stdout": { @@ -7177,31 +8371,60 @@ "dev": true }, "mysql": { - "version": "2.16.0", - "resolved": "https://registry.npmjs.org/mysql/-/mysql-2.16.0.tgz", - "integrity": "sha512-dPbN2LHonQp7D5ja5DJXNbCLe/HRdu+f3v61aguzNRQIrmZLOeRoymBYyeThrR6ug+FqzDL95Gc9maqZUJS+Gw==", + "version": "2.18.1", + "resolved": "https://registry.npmjs.org/mysql/-/mysql-2.18.1.tgz", + "integrity": "sha512-Bca+gk2YWmqp2Uf6k5NFEurwY/0td0cpebAucFpY/3jhrwrVGuxU2uQFCHjU19SJfje0yQvi+rVWdq78hR5lig==", "dev": true, "requires": { - "bignumber.js": "4.1.0", - "readable-stream": "2.3.6", + "bignumber.js": "9.0.0", + "readable-stream": "2.3.7", "safe-buffer": "5.1.2", "sqlstring": "2.3.1" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + } } }, "mysql2": { - "version": "1.6.5", - "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-1.6.5.tgz", - "integrity": "sha512-zedaOOyb3msuuZcJJnxIX/EGOpmljDG7B+UevRH5lqcv+yhy9eCwkArBz8/AO+/rlY3/oCsOdG8R5oD6k0hNfg==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-2.1.0.tgz", + "integrity": "sha512-9kGVyi930rG2KaHrz3sHwtc6K+GY9d8wWk1XRSYxQiunvGcn4DwuZxOwmK11ftuhhwrYDwGx9Ta4VBwznJn36A==", "dev": true, "requires": { - "denque": "^1.4.0", + "cardinal": "^2.1.1", + "denque": "^1.4.1", "generate-function": "^2.3.1", - "iconv-lite": "^0.4.24", + "iconv-lite": "^0.5.0", "long": "^4.0.0", - "lru-cache": "^4.1.3", + "lru-cache": "^5.1.1", "named-placeholders": "^1.1.2", "seq-queue": "^0.0.5", "sqlstring": "^2.3.1" + }, + "dependencies": { + "iconv-lite": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.5.2.tgz", + "integrity": "sha512-kERHXvpSaB4aU3eANwidg79K8FlrN77m8G9V+0vOR3HYaRifrlwMEpT7ZBJqLSEIHnEgJTHcWK82wwLwwKwtag==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + } } }, "mz": { @@ -7221,12 +8444,30 @@ "dev": true, "requires": { "lru-cache": "^4.1.3" + }, + "dependencies": { + "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" + } + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true + } } }, "nan": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.12.0.tgz", - "integrity": "sha512-zT5nC0JhbljmyEf+Z456nvm7iO7XgRV2hYxoBtPpnyp+0Q4aCoP6uWNn76v/I6k2kCYNLWqWbwBWQcjsNI/bjw==", + "version": "2.14.1", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.1.tgz", + "integrity": "sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw==", "dev": true, "optional": true }, @@ -7251,8 +8492,8 @@ }, "napi-build-utils": { "version": "1.0.2", - "resolved": "https://registry.npm.taobao.org/napi-build-utils/download/napi-build-utils-1.0.2.tgz", - "integrity": "sha1-sf3cCyxG44Cgt6dvmE3UfEGhOAY=", + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", + "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==", "dev": true }, "native-duplexpair": { @@ -7268,9 +8509,9 @@ "dev": true }, "needle": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/needle/-/needle-2.4.0.tgz", - "integrity": "sha512-4Hnwzr3mi5L97hMYeNl8wRW/Onhy4nUKR/lVemJ8gJedxxUyBLm9kkrDColJvoSfwi0jCNhD+xCdOtiGDQiRZg==", + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/needle/-/needle-2.5.2.tgz", + "integrity": "sha512-LbRIwS9BfkPvNwNHlsA41Q29kL2L/6VaOJ0qisM5lLWsTV3nP15abO5ITL6L81zqFhzjRKDAYjpcBcwM0AVvLQ==", "dev": true, "requires": { "debug": "^3.2.6", @@ -7304,38 +8545,37 @@ "nice-try": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==" + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true }, "nise": { - "version": "1.4.10", - "resolved": "https://registry.npmjs.org/nise/-/nise-1.4.10.tgz", - "integrity": "sha512-sa0RRbj53dovjc7wombHmVli9ZihXbXCQ2uH3TNm03DyvOSIQbxg+pbqDKrk2oxMK1rtLGVlKxcB9rrc6X5YjA==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/nise/-/nise-4.0.4.tgz", + "integrity": "sha512-bTTRUNlemx6deJa+ZyoCUTRvH3liK5+N6VQZ4NIw90AgDXY6iPnsqplNFf6STcj+ePk0H/xqxnP75Lr0J0Fq3A==", "dev": true, "requires": { - "@sinonjs/formatio": "^3.1.0", + "@sinonjs/commons": "^1.7.0", + "@sinonjs/fake-timers": "^6.0.0", "@sinonjs/text-encoding": "^0.7.1", "just-extend": "^4.0.2", - "lolex": "^2.3.2", "path-to-regexp": "^1.7.0" - }, - "dependencies": { - "lolex": { - "version": "2.7.5", - "resolved": "https://registry.npmjs.org/lolex/-/lolex-2.7.5.tgz", - "integrity": "sha512-l9x0+1offnKKIzYVjyXU2SiwhXDLekRzKyhnbyldPHvC7BvLPVpdNUNR2KeMAiCN2D/kLNttZgQD5WjSxuBx3Q==", - "dev": true - } } }, "node-abi": { - "version": "2.18.0", - "resolved": "https://registry.npm.taobao.org/node-abi/download/node-abi-2.18.0.tgz", - "integrity": "sha1-H1SGz9fTi9T1OS+kSkrU2aDf+/Q=", + "version": "2.19.1", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.19.1.tgz", + "integrity": "sha512-HbtmIuByq44yhAzK7b9j/FelKlHYISKQn0mtvcBrU5QBkhoCMp5bu8Hv5AI34DcKfOAcJBcOEMwLlwO62FFu9A==", "dev": true, "requires": { "semver": "^5.4.1" } }, + "node-addon-api": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.0.tgz", + "integrity": "sha512-ASCL5U13as7HhOExbT6OlWJJUV/lLzL2voOSP1UVehpRD8FbSrSDjfScK/KwAvVTI5AS6r4VwbOMlIqtvRidnA==", + "dev": true + }, "node-environment-flags": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.5.tgz", @@ -7347,13 +8587,82 @@ }, "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 } } }, + "node-gyp": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-3.8.0.tgz", + "integrity": "sha512-3g8lYefrRRzvGeSowdJKAKyks8oUpLEd/DyPV4eMhVlhJ0aNaZqIrNUIPuEWWTAoPqyFkfGrM67MC69baqn6vA==", + "dev": true, + "optional": true, + "requires": { + "fstream": "^1.0.0", + "glob": "^7.0.3", + "graceful-fs": "^4.1.2", + "mkdirp": "^0.5.0", + "nopt": "2 || 3", + "npmlog": "0 || 1 || 2 || 3 || 4", + "osenv": "0", + "request": "^2.87.0", + "rimraf": "2", + "semver": "~5.3.0", + "tar": "^2.0.0", + "which": "1" + }, + "dependencies": { + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true, + "optional": true + }, + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, + "optional": true, + "requires": { + "minimist": "^1.2.5" + } + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "optional": true, + "requires": { + "glob": "^7.1.3" + } + }, + "semver": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", + "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=", + "dev": true, + "optional": true + }, + "tar": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.2.tgz", + "integrity": "sha512-FCEhQ/4rE1zYv9rYXJw/msRqsnmlje5jHP6huWeBZ704jUTy02c5AZyWujpMR1ax6mVw9NyJMfuK2CMDWVIfgA==", + "dev": true, + "optional": true, + "requires": { + "block-stream": "*", + "fstream": "^1.0.12", + "inherits": "2" + } + } + } + }, "node-pre-gyp": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.11.0.tgz", @@ -7379,23 +8688,32 @@ "dev": true }, "mkdirp": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.3.tgz", - "integrity": "sha512-P+2gwrFqx8lhew375MQHHeTlY8AuOJSrGf0R5ddkEndUkmwpgUob/vQuBD1V22/Cw1/lJr4x+EjllSezBThzBg==", + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", "dev": true, "requires": { "minimist": "^1.2.5" } }, "nopt": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz", - "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz", + "integrity": "sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg==", "dev": true, "requires": { "abbrev": "1", "osenv": "^0.1.4" } + }, + "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" + } } } }, @@ -7445,47 +8763,46 @@ } }, "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==", - "dev": true - }, - "npm-packlist": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.1.tgz", - "integrity": "sha512-+TcdO7HJJ8peiiYhvPxsEDhF3PJFGUGRcFsGve3vxvxdcpO2Z4Z7rkosRM0kWj6LfbK/P0gu3dzk5RU1ffvFcw==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.1.tgz", + "integrity": "sha512-gqkfgGePhTpAEgUsGEgcq1rqPXA+tv/aVBlgEzfXwA1yiUJF7xtEt3CtVwOjNYQOVknDk0F20w58Fnm3EtG0fA==", "dev": true, "requires": { - "ignore-walk": "^3.0.1", - "npm-bundled": "^1.0.1" + "npm-normalize-package-bin": "^1.0.1" } }, - "npm-path": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/npm-path/-/npm-path-2.0.4.tgz", - "integrity": "sha512-IFsj0R9C7ZdR5cP+ET342q77uSRdtWOlWpih5eC+lu29tIDbNEgDbzgVJ5UFvYHWhxDZ5TFkJafFioO0pPQjCw==", + "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==", + "dev": true + }, + "npm-packlist": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.8.tgz", + "integrity": "sha512-5+AZgwru5IevF5ZdnFglB5wNlHG1AOOuw28WhUq8/8emhBmLv6jX5by4WJCh7lW0uSYZYS6DXqIsyZVIXRZU9A==", "dev": true, "requires": { - "which": "^1.2.10" + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1", + "npm-normalize-package-bin": "^1.0.1" } }, "npm-run-path": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", - "requires": { - "path-key": "^2.0.0" - } - }, - "npm-which": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/npm-which/-/npm-which-3.0.1.tgz", - "integrity": "sha1-kiXybsOihcIJyuZ8OxGmtKtxQKo=", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-3.1.0.tgz", + "integrity": "sha512-Dbl4A/VfiVGLgQv29URL9xshU8XDY1GeLy+fsaZ1AA8JDSfjvr5P5+pzRbWqRSBxk6/DW7MIh8lTM/PaGnP2kg==", "dev": true, "requires": { - "commander": "^2.9.0", - "npm-path": "^2.0.2", - "which": "^1.2.10" + "path-key": "^3.0.0" + }, + "dependencies": { + "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 + } } }, "npmlog": { @@ -7503,7 +8820,8 @@ "number-is-nan": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "dev": true }, "oauth-sign": { "version": "0.9.0", @@ -7547,6 +8865,12 @@ } } }, + "object-inspect": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.8.0.tgz", + "integrity": "sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==", + "dev": true + }, "object-keys": { "version": "1.0.12", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.12.tgz", @@ -7587,13 +8911,13 @@ } }, "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==", "dev": true, "requires": { - "define-properties": "^1.1.2", - "es-abstract": "^1.5.1" + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1" } }, "object.map": { @@ -7634,14 +8958,20 @@ } }, "onetime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", - "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", "dev": true, "requires": { - "mimic-fn": "^1.0.0" + "mimic-fn": "^2.1.0" } }, + "opencollective-postinstall": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz", + "integrity": "sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q==", + "dev": true + }, "optimist": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", @@ -7695,6 +9025,15 @@ "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", "dev": true }, + "os-locale": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", + "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", + "dev": true, + "requires": { + "lcid": "^1.0.0" + } + }, "os-tmpdir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", @@ -7711,47 +9050,41 @@ "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=" - }, "p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=" - }, - "p-is-promise": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.0.0.tgz", - "integrity": "sha512-pzQPhYMCAgLAKPWD2jC3Se9fEfrD9npNos0y150EeqZll7akhEgGhTW/slB6lHku8AvYGiJ+YJ5hfHKePPgFWg==" + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-2.0.1.tgz", + "integrity": "sha512-vpm09aKwq6H9phqRQzecoDpD8TmVyGw70qmWlyq5onxY7tqyTTFVvxMykxQSQKILBSFlbXpypIw2T1Ml7+DDtw==", + "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==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "requires": { - "p-try": "^1.0.0" + "p-try": "^2.0.0" } }, "p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "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": "^1.1.0" + "p-limit": "^2.2.0" } }, "p-map": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-1.2.0.tgz", - "integrity": "sha512-r6zKACMNhjPJMTl8KcFH4li//gkrXWfbD6feV8l6doRHlzljFWGJ2AP6iKaCJXyZmAUMOPtvbW7EXkbWO/pLEA==", - "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": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=" + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" }, "packet-reader": { "version": "1.0.0", @@ -7820,9 +9153,17 @@ "dev": true }, "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" + } }, "pascalcase": { "version": "0.1.1", @@ -7839,23 +9180,19 @@ "path-exists": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true }, "path-is-absolute": { "version": "1.0.1", "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", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=" + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true }, "path-parse": { "version": "1.0.6", @@ -7879,9 +9216,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" @@ -7908,7 +9245,7 @@ "dependencies": { "pify": { "version": "2.3.0", - "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", "dev": true } @@ -7927,9 +9264,9 @@ "dev": true }, "pg": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/pg/-/pg-8.3.0.tgz", - "integrity": "sha512-jQPKWHWxbI09s/Z9aUvoTbvGgoj98AU7FDCcQ7kdejupn/TcNpx56v2gaOTzXkzOajmOEJEdi9eTh9cA2RVAjQ==", + "version": "8.3.3", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.3.3.tgz", + "integrity": "sha512-wmUyoQM/Xzmo62wgOdQAn5tl7u+IA1ZYK7qbuppi+3E+Gj4hlUxVHjInulieWrd0SfHi/ADriTb5ILJ/lsJrSg==", "dev": true, "requires": { "buffer-writer": "2.0.0", @@ -7996,6 +9333,12 @@ "split": "^1.0.0" } }, + "picomatch": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", + "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", + "dev": true + }, "pify": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", @@ -8018,63 +9361,69 @@ } }, "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==", + "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": "^3.0.0" + "find-up": "^4.0.0" }, "dependencies": { "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "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": "^3.0.0" + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" } }, "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "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": "^3.0.0", - "path-exists": "^3.0.0" + "p-locate": "^4.1.0" } }, "p-limit": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.1.0.tgz", - "integrity": "sha512-NhURkNcrVB+8hNfLuysU8enY5xn2KXphsHBaC2YmRNTZRc7RWusw6apSpdEj3jo4CMb6W9nrF6tTnsJsJeyu6g==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, "requires": { "p-try": "^2.0.0" } }, "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "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.0.0" + "p-limit": "^2.2.0" } }, "p-try": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.0.0.tgz", - "integrity": "sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "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 } } }, "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" @@ -8151,9 +9500,9 @@ "dev": true }, "postgres-date": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.5.tgz", - "integrity": "sha512-pdau6GRPERdAYUQwkBnGKxEfPyhVZXG/JiS44iZWiNdSOWE09N2lUgN6yshuq6fVSon4Pm0VMXd1srUUkLe9iA==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", + "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==", "dev": true }, "postgres-interval": { @@ -8166,9 +9515,9 @@ } }, "prebuild-install": { - "version": "5.3.4", - "resolved": "https://registry.npm.taobao.org/prebuild-install/download/prebuild-install-5.3.4.tgz", - "integrity": "sha1-aYLRAIQmnTZMGFZVC30JDqMfopM=", + "version": "5.3.5", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-5.3.5.tgz", + "integrity": "sha512-YmMO7dph9CYKi5IR/BzjOJlRzpxGGVo1EsLSUZ0mt/Mq0HWZIHOKHHcHdT69yG54C9m6i45GpItwRHpk0Py7Uw==", "dev": true, "requires": { "detect-libc": "^1.0.3", @@ -8190,14 +9539,14 @@ "dependencies": { "minimist": { "version": "1.2.5", - "resolved": "https://registry.npm.taobao.org/minimist/download/minimist-1.2.5.tgz", - "integrity": "sha1-Z9ZgFLZqaoqqDAg8X9WN9OTpdgI=", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", "dev": true }, "mkdirp": { "version": "0.5.5", - "resolved": "https://registry.npm.taobao.org/mkdirp/download/mkdirp-0.5.5.tgz?cache=0&sync_timestamp=1588819864223&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fmkdirp%2Fdownload%2Fmkdirp-0.5.5.tgz", - "integrity": "sha1-2Rzv1i0UNsoPQWIOJRKI1CAJne8=", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", "dev": true, "requires": { "minimist": "^1.2.5" @@ -8205,8 +9554,8 @@ }, "pump": { "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/pump/download/pump-3.0.0.tgz", - "integrity": "sha1-tKIRaBW94vTh6mAjVOjHVWUQemQ=", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", "dev": true, "requires": { "end-of-stream": "^1.1.0", @@ -8228,9 +9577,9 @@ "dev": true }, "process-nextick-args": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", - "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "dev": true }, "progress": { @@ -8239,11 +9588,18 @@ "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", "dev": true }, - "property-expr": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/property-expr/-/property-expr-1.5.1.tgz", - "integrity": "sha512-CGuc0VUTGthpJXL36ydB6jnbyOf/rAHFvmVrJlH+Rg0DqqLFQGAP6hIaxD/G0OAmBJPhXDHuEJigrp0e0wFV6g==", - "dev": true + "promise.allsettled": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/promise.allsettled/-/promise.allsettled-1.0.2.tgz", + "integrity": "sha512-UpcYW5S1RaNKT6pd+s9jp9K9rlQge1UXKskec0j6Mmuq7UJCvlS2J2/s/yuPN8ehftf9HXMxWlKiPbGGUzpoRg==", + "dev": true, + "requires": { + "array.prototype.map": "^1.0.1", + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1", + "function-bind": "^1.1.1", + "iterate-value": "^1.0.0" + } }, "pseudomap": { "version": "1.0.2", @@ -8252,9 +9608,9 @@ "dev": true }, "psl": { - "version": "1.1.32", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.32.tgz", - "integrity": "sha512-MHACAkHpihU/REGGPLj4sEfc/XKW2bheigvHO1dUqjaKigMp1C8+WLQYRGgeKFMsw5PMfegZcaN8IDXK/cD0+g==", + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", + "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", "dev": true }, "pump": { @@ -8297,11 +9653,20 @@ "dev": true }, "quick-lru": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-1.1.0.tgz", - "integrity": "sha1-Q2CxfGETatOAeDl/8RQW4Ybc+7g=", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", + "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==", "dev": true }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, "rc": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", @@ -8396,6 +9761,111 @@ "graceful-fs": "^4.1.11", "micromatch": "^3.1.10", "readable-stream": "^2.0.2" + }, + "dependencies": { + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + } } }, "rechoir": { @@ -8408,49 +9878,62 @@ } }, "redent": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/redent/-/redent-2.0.0.tgz", - "integrity": "sha1-wbIAe0LVfrE4kHmzyDM2OdXhzKo=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "dev": true, + "requires": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + } + }, + "redeyed": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/redeyed/-/redeyed-2.1.1.tgz", + "integrity": "sha1-iYS1gV2ZyyIEacme7v/jiRPmzAs=", "dev": true, "requires": { - "indent-string": "^3.0.0", - "strip-indent": "^2.0.0" + "esprima": "~4.0.0" } }, "redis": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/redis/-/redis-2.8.0.tgz", - "integrity": "sha512-M1OkonEQwtRmZv4tEWF2VgpG0JWJ8Fv1PhlgT5+B+uNq2cA3Rt1Yt/ryoR+vQNOQcIEgdCdfH0jr3bDpihAw1A==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/redis/-/redis-3.0.2.tgz", + "integrity": "sha512-PNhLCrjU6vKVuMOyFu7oSP296mwBkcE6lrAjruBYG5LgdSqtRBoVQIylrMyVZD/lkF24RSNNatzvYag6HRBHjQ==", "dev": true, "requires": { - "double-ended-queue": "^2.1.0-0", - "redis-commands": "^1.2.0", - "redis-parser": "^2.6.0" + "denque": "^1.4.1", + "redis-commands": "^1.5.0", + "redis-errors": "^1.2.0", + "redis-parser": "^3.0.0" } }, "redis-commands": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/redis-commands/-/redis-commands-1.4.0.tgz", - "integrity": "sha512-cu8EF+MtkwI4DLIT0x9P8qNTLFhQD4jLfxLR0cCNkeGzs87FN6879JOJwNQR/1zD7aSYNbU0hgsV9zGY71Itvw==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/redis-commands/-/redis-commands-1.6.0.tgz", + "integrity": "sha512-2jnZ0IkjZxvguITjFTrGiLyzQZcTvaw8DAaCXxZq/dsHXz7KfMQ3OUJy7Tz9vnRtZRVz6VRCPDvruvU8Ts44wQ==", "dev": true }, - "redis-parser": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-2.6.0.tgz", - "integrity": "sha1-Uu0J2srBCPGmMcB+m2mUHnoZUEs=", + "redis-errors": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz", + "integrity": "sha1-62LSrbFeTq9GEMBK/hUpOEJQq60=", "dev": true }, + "redis-parser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz", + "integrity": "sha1-tm2CjNyv5rS4pCin3vTGvKwxyLQ=", + "dev": true, + "requires": { + "redis-errors": "^1.0.0" + } + }, "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==" }, - "regenerator-runtime": { - "version": "0.12.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz", - "integrity": "sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg==", - "dev": true - }, "regex-not": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", @@ -8587,9 +10070,9 @@ } }, "request": { - "version": "2.88.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", - "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", "dev": true, "requires": { "aws-sign2": "~0.7.0", @@ -8599,7 +10082,7 @@ "extend": "~3.0.2", "forever-agent": "~0.6.1", "form-data": "~2.3.2", - "har-validator": "~5.1.0", + "har-validator": "~5.1.3", "http-signature": "~1.2.0", "is-typedarray": "~1.0.0", "isstream": "~0.1.2", @@ -8609,9 +10092,22 @@ "performance-now": "^2.1.0", "qs": "~6.5.2", "safe-buffer": "^5.1.2", - "tough-cookie": "~2.4.3", + "tough-cookie": "~2.5.0", "tunnel-agent": "^0.6.0", "uuid": "^3.3.2" + }, + "dependencies": { + "form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + } } }, "require-directory": { @@ -8622,7 +10118,8 @@ "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=" + "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", + "dev": true }, "require_optional": { "version": "1.0.1", @@ -8643,9 +10140,9 @@ } }, "resolve": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.9.0.tgz", - "integrity": "sha512-TZNye00tI67lwYvzxCxHGjwTNlUV70io54/Ed4j6PscB8xVfuBJpRenI/o6dVk0cY0PYTY27AgCoGGxRnYuItQ==", + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", + "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", "dev": true, "requires": { "path-parse": "^1.0.6" @@ -8662,9 +10159,9 @@ } }, "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 }, "resolve-options": { @@ -8683,12 +10180,12 @@ "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=", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", "dev": true, "requires": { - "onetime": "^2.0.0", + "onetime": "^5.1.0", "signal-exit": "^3.0.2" } }, @@ -8698,10 +10195,16 @@ "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", "dev": true }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "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.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", "dev": true, "requires": { "glob": "^7.1.3" @@ -8713,19 +10216,27 @@ "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", "dev": true }, - "run-node": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/run-node/-/run-node-1.0.0.tgz", - "integrity": "sha512-kc120TBlQ3mih1LSzdAJXo4xn/GWS2ec0l3S+syHDXP9uRr0JAT8Qd3mdMuyjqCzeZktgP3try92cEgf9Nks8A==", + "run-parallel": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.9.tgz", + "integrity": "sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==", "dev": true }, "rxjs": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.4.0.tgz", - "integrity": "sha512-Z9Yfa11F6B9Sg/BK9MnqnQ+aQYicPLtilXBp2yUtDt2JRCE0h26d33EnfO3ZxoNxG0T92OUucP3Ct7cpfkdFfw==", + "version": "6.6.3", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.3.tgz", + "integrity": "sha512-trsQc+xYYXZ3urjOiJOuCOa5N3jAZ3eiSpQB5hIT8zGlL2QfnHLJ2r7GMkBGuIausdJN1OneaI6gQlsqNHHmZQ==", "dev": true, "requires": { "tslib": "^1.9.0" + }, + "dependencies": { + "tslib": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz", + "integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==", + "dev": true + } } }, "safe-buffer": { @@ -8749,9 +10260,9 @@ "dev": true }, "saslprep": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/saslprep/-/saslprep-1.0.2.tgz", - "integrity": "sha512-4cDsYuAjXssUSjxHKRe4DTZC0agDwsCqcMqtJAQPzC74nJ7LfAJflAtC1Zed5hMzEQKj82d3tuzqdGNRsLJ4Gw==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/saslprep/-/saslprep-1.0.3.tgz", + "integrity": "sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag==", "dev": true, "optional": true, "requires": { @@ -8766,7 +10277,8 @@ "semver": { "version": "5.6.0", "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", - "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==" + "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==", + "dev": true }, "semver-compare": { "version": "1.0.0", @@ -8783,12 +10295,27 @@ "sver-compat": "^1.5.0" } }, + "semver-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/semver-regex/-/semver-regex-2.0.0.tgz", + "integrity": "sha512-mUdIBBvdn0PLOeP3TEkMH7HHeUP3GjsXCwKarjv/kGmUFOYg1VqEemKhoQpWMu6X2I8kHeuVdGibLGkVK+/5Qw==", + "dev": true + }, "seq-queue": { "version": "0.0.5", "resolved": "https://registry.npmjs.org/seq-queue/-/seq-queue-0.0.5.tgz", "integrity": "sha1-1WgS4cAXpuTnw+Ojeh2m143TyT4=", "dev": true }, + "serialize-javascript": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", + "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", + "dev": true, + "requires": { + "randombytes": "^2.1.0" + } + }, "set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", @@ -8830,6 +10357,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, "requires": { "shebang-regex": "^1.0.0" } @@ -8837,23 +10365,36 @@ "shebang-regex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=" + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true + }, + "shelljs": { + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.4.tgz", + "integrity": "sha512-7gk3UZ9kOfPLIAbslLzyWeGiEqx9e3rxwZM0KE6EL8GlGwjym9Mrlx5/p33bWTu9YG6vcS4MBxYZDHYr5lr8BQ==", + "dev": true, + "requires": { + "glob": "^7.0.0", + "interpret": "^1.0.0", + "rechoir": "^0.6.2" + } }, "signal-exit": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", + "dev": true }, "simple-concat": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/simple-concat/download/simple-concat-1.0.0.tgz", - "integrity": "sha1-c0TLuLbib7J9ZrL8hvn21Zl1IcY=", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", "dev": true }, "simple-get": { "version": "3.1.0", - "resolved": "https://registry.npm.taobao.org/simple-get/download/simple-get-3.1.0.tgz", - "integrity": "sha1-tFvgYkNeUNFZVAtXYgLO7EC5xrM=", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.0.tgz", + "integrity": "sha512-bCR6cP+aTdScaQCnQKbPKtJOKDp/hj9EDLJo3Nw4y1QksqaovlW/bnptB6/c1e+qmNIDHRK+oXFDdEqBT8WzUA==", "dev": true, "requires": { "decompress-response": "^4.2.0", @@ -8861,47 +10402,90 @@ "simple-concat": "^1.0.0" } }, - "simple-git": { - "version": "1.107.0", - "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-1.107.0.tgz", - "integrity": "sha512-t4OK1JRlp4ayKRfcW6owrWcRVLyHRUlhGd0uN6ZZTqfDq8a5XpcUdOKiGRNobHEuMtNqzp0vcJNvhYWwh5PsQA==", - "dev": true, - "requires": { - "debug": "^4.0.1" - } - }, "sinon": { - "version": "7.2.5", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-7.2.5.tgz", - "integrity": "sha512-1c2KK6g5NQr9XNYCEcUbeFtBpKZD1FXEw0VX7gNhWUBtkchguT2lNdS7XmS7y64OpQWfSNeeV/f8py3NNcQ63Q==", - "dev": true, - "requires": { - "@sinonjs/commons": "^1.3.0", - "@sinonjs/formatio": "^3.1.0", - "@sinonjs/samsam": "^3.2.0", - "diff": "^3.5.0", - "lolex": "^3.1.0", - "nise": "^1.4.10", - "supports-color": "^5.5.0" + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-9.0.3.tgz", + "integrity": "sha512-IKo9MIM111+smz9JGwLmw5U1075n1YXeAq8YeSFlndCLhAL5KGn6bLgu7b/4AYHTV/LcEMcRm2wU2YiL55/6Pg==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.7.2", + "@sinonjs/fake-timers": "^6.0.1", + "@sinonjs/formatio": "^5.0.1", + "@sinonjs/samsam": "^5.1.0", + "diff": "^4.0.2", + "nise": "^4.0.4", + "supports-color": "^7.1.0" + }, + "dependencies": { + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true + } } }, "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.5.0", + "resolved": "https://registry.npmjs.org/sinon-chai/-/sinon-chai-3.5.0.tgz", + "integrity": "sha512-IifbusYiQBpUxxFJkR3wTU68xzBN0+bxCScEaKMjBvAQERg6FnTTc1F17rseLb1tjmkJ23730AXpFI0c47FgAg==", "dev": true }, "slash": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", - "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "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": "3.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz", + "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "dev": true, + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true + }, + "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==", + "dev": true, + "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==", + "dev": true + }, + "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==", + "dev": true + } + } }, "snapdragon": { "version": "0.8.2", @@ -9045,9 +10629,9 @@ } }, "source-map-support": { - "version": "0.5.10", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.10.tgz", - "integrity": "sha512-YfQ3tQFTK/yzlGJuX8pTwa4tifQj4QS2Mj7UegOu8jAz59MqIiMGPXxQhVQiIMNzayuUSF/jEuVnfFF5JqybmQ==", + "version": "0.5.19", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", + "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", "dev": true, "requires": { "buffer-from": "^1.0.0", @@ -9155,22 +10739,14 @@ "dev": true }, "sqlite3": { - "version": "4.0.9", - "resolved": "https://registry.npmjs.org/sqlite3/-/sqlite3-4.0.9.tgz", - "integrity": "sha512-IkvzjmsWQl9BuBiM4xKpl5X8WCR4w0AeJHRdobCdXZ8dT/lNc1XS6WqvY35N6+YzIIgzSBeY5prdFObID9F9tA==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/sqlite3/-/sqlite3-5.0.0.tgz", + "integrity": "sha512-rjvqHFUaSGnzxDy2AHCwhHy6Zp6MNJzCPGYju4kD8yi6bze4d1/zMTg6C7JI49b7/EM7jKMTvyfN/4ylBKdwfw==", "dev": true, "requires": { - "nan": "^2.12.1", - "node-pre-gyp": "^0.11.0", - "request": "^2.87.0" - }, - "dependencies": { - "nan": { - "version": "2.14.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", - "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==", - "dev": true - } + "node-addon-api": "2.0.0", + "node-gyp": "3.x", + "node-pre-gyp": "^0.11.0" } }, "sqlstring": { @@ -9202,12 +10778,6 @@ "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=", "dev": true }, - "staged-git-files": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/staged-git-files/-/staged-git-files-1.1.2.tgz", - "integrity": "sha512-0Eyrk6uXW6tg9PYkhi/V/J4zHp33aNyi2hOCmhFLqLTIhbgqWn5jlSzI+IU0VqrZq6+DbHcabQl/WP6P3BG0QA==", - "dev": true - }, "static-extend": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", @@ -9242,23 +10812,44 @@ "dev": true }, "string-argv": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.0.2.tgz", - "integrity": "sha1-2sMECGkMIfPDYwo/86BYd73L1zY=", + "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": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, "requires": { "is-fullwidth-code-point": "^2.0.0", "strip-ansi": "^4.0.0" } }, + "string.prototype.trimend": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz", + "integrity": "sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "string.prototype.trimstart": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz", + "integrity": "sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, "string_decoder": { "version": "1.1.1", - "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { @@ -9280,6 +10871,7 @@ "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" } @@ -9299,17 +10891,21 @@ "integrity": "sha1-5SEekiQ2n7uB1jOi8ABE3IztrZI=", "dev": true }, - "strip-eof": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", - "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=" - }, - "strip-indent": { + "strip-final-newline": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-2.0.0.tgz", - "integrity": "sha1-XvjbKV0B5u1sv3qrlpmNeCJSe2g=", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", "dev": true }, + "strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "requires": { + "min-indent": "^1.0.0" + } + }, "strip-json-comments": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", @@ -9317,11 +10913,11 @@ "dev": true }, "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "^4.0.0" } }, "sver-compat": { @@ -9334,18 +10930,6 @@ "es6-symbol": "^3.1.1" } }, - "symbol-observable": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", - "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==", - "dev": true - }, - "synchronous-promise": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/synchronous-promise/-/synchronous-promise-2.0.6.tgz", - "integrity": "sha512-TyOuWLwkmtPL49LHCX1caIwHjRzcVd62+GF6h8W/jHOeZUFHpnd2XJDVuUlaTaLPH1nuu2M69mfHr5XbQJnf/g==", - "dev": true - }, "table": { "version": "5.4.6", "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", @@ -9455,8 +11039,8 @@ }, "tar-fs": { "version": "2.1.0", - "resolved": "https://registry.npm.taobao.org/tar-fs/download/tar-fs-2.1.0.tgz", - "integrity": "sha1-0c3RIatGXuDrnM3i01BJ0/Pa8NU=", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.0.tgz", + "integrity": "sha512-9uW5iDvrIMCVpvasdFHW0wJPez0K4JnMZtsuIeDI7HyMGJNxmDZDOCQROr7lXyS+iL/QMpj07qcjGYTSdRFXUg==", "dev": true, "requires": { "chownr": "^1.1.1", @@ -9467,8 +11051,8 @@ "dependencies": { "pump": { "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/pump/download/pump-3.0.0.tgz", - "integrity": "sha1-tKIRaBW94vTh6mAjVOjHVWUQemQ=", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", "dev": true, "requires": { "end-of-stream": "^1.1.0", @@ -9478,12 +11062,12 @@ } }, "tar-stream": { - "version": "2.1.2", - "resolved": "https://registry.npm.taobao.org/tar-stream/download/tar-stream-2.1.2.tgz", - "integrity": "sha1-bV7xp+V4OpX/cLabl0VaWWjcEyU=", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.1.4.tgz", + "integrity": "sha512-o3pS2zlG4gxr67GmFYBLlq+dM8gyRGUOvsrHclSkvtVtQbjV0s/+ZE8OpICbaj8clrX3tjeHngYGP7rweaBnuw==", "dev": true, "requires": { - "bl": "^4.0.1", + "bl": "^4.0.3", "end-of-stream": "^1.4.1", "fs-constants": "^1.0.0", "inherits": "^2.0.3", @@ -9491,9 +11075,9 @@ }, "dependencies": { "bl": { - "version": "4.0.2", - "resolved": "https://registry.npm.taobao.org/bl/download/bl-4.0.2.tgz?cache=0&sync_timestamp=1584503592586&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fbl%2Fdownload%2Fbl-4.0.2.tgz", - "integrity": "sha1-UrcekIhRXQYG2d2cx6pI3B+Y5zo=", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.0.3.tgz", + "integrity": "sha512-fs4G6/Hu4/EE+F75J8DuN/0IpQqNjAdC7aEQv7Qt8MHGUH7Ckv2MwTEEeN9QehD0pfIDkMI1bkHYkKy7xHyKIg==", "dev": true, "requires": { "buffer": "^5.5.0", @@ -9503,26 +11087,16 @@ "dependencies": { "inherits": { "version": "2.0.4", - "resolved": "https://registry.npm.taobao.org/inherits/download/inherits-2.0.4.tgz", - "integrity": "sha1-D6LGT5MpF8NDOg3tVTY6rjdBa3w=", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true } } }, - "buffer": { - "version": "5.6.0", - "resolved": "https://registry.npm.taobao.org/buffer/download/buffer-5.6.0.tgz?cache=0&sync_timestamp=1588706716358&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fbuffer%2Fdownload%2Fbuffer-5.6.0.tgz", - "integrity": "sha1-oxdJ3H2B2E2wir+Te2uMQDP2J4Y=", - "dev": true, - "requires": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4" - } - }, "readable-stream": { "version": "3.6.0", - "resolved": "https://registry.npm.taobao.org/readable-stream/download/readable-stream-3.6.0.tgz", - "integrity": "sha1-M3u9o63AcGvT4CRCaihtS0sskZg=", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", "dev": true, "requires": { "inherits": "^2.0.3", @@ -9532,23 +11106,66 @@ } } }, + "tarn": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/tarn/-/tarn-1.1.5.tgz", + "integrity": "sha512-PMtJ3HCLAZeedWjJPgGnCvcphbCOMbtZpjKgLq3qM5Qq9aQud+XHrL0WlrlgnTyS8U+jrjGbEXprFcQrxPy52g==", + "dev": true + }, "tedious": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/tedious/-/tedious-2.7.1.tgz", - "integrity": "sha512-u3ciATGm5byim91b3+c3MVTvY1zKjDmhUhnBQZXKymT2Vb9w322dziPQY6MhBNyBEcNONPsAMR+7/Uub7NYABQ==", - "dev": true, - "requires": { - "babel-runtime": "^6.26.0", - "big-number": "0.3.1", - "bl": "^1.2.2", - "depd": "^1.1.2", - "iconv-lite": "^0.4.23", + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/tedious/-/tedious-6.7.0.tgz", + "integrity": "sha512-8qr7+sB0h4SZVQBRWUgHmYuOEflAOl2eihvxk0fVNvpvGJV4V5UC/YmSvebyfgyfwWcPO22/AnSbYVZZqf9wuQ==", + "dev": true, + "requires": { + "@azure/ms-rest-nodeauth": "2.0.2", + "@types/node": "^12.12.17", + "@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": "^2.3.6", - "sprintf-js": "^1.1.1" + "readable-stream": "^3.4.0", + "sprintf-js": "^1.1.2" }, "dependencies": { + "@types/node": { + "version": "12.12.56", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.56.tgz", + "integrity": "sha512-8OdIupOIZtmObR13fvGyTvpcuzKmMugkATeVcfNwCjGtHxhjEKmOvLqXwR8U9VOtNnZ4EXaSfNiLVsPinaCXkQ==", + "dev": true + }, + "bl": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/bl/-/bl-3.0.1.tgz", + "integrity": "sha512-jrCW5ZhfQ/Vt07WX1Ngs+yn9BDqPL/gw28S7s9H6QK/gupnizNzJAss5akW20ISgOrbLTlXOOCTJeNUQqruAWQ==", + "dev": true, + "requires": { + "readable-stream": "^3.0.1" + } + }, + "iconv-lite": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.5.2.tgz", + "integrity": "sha512-kERHXvpSaB4aU3eANwidg79K8FlrN77m8G9V+0vOR3HYaRifrlwMEpT7ZBJqLSEIHnEgJTHcWK82wwLwwKwtag==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, "sprintf-js": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz", @@ -9557,22 +11174,20 @@ } } }, + "temp-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-2.0.0.tgz", + "integrity": "sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==", + "dev": true + }, "tempfile": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/tempfile/-/tempfile-1.1.1.tgz", - "integrity": "sha1-W8xOrsxKsscH2LwR2ZzMmiyyh/I=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/tempfile/-/tempfile-3.0.0.tgz", + "integrity": "sha512-uNFCg478XovRi85iD42egu+eSFUmmka750Jy7L5tfHI5hQKKtbPnxaSaXAbBqCDYrw3wx4tXjKwci4/QmsZJxw==", "dev": true, "requires": { - "os-tmpdir": "^1.0.0", - "uuid": "^2.0.1" - }, - "dependencies": { - "uuid": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.3.tgz", - "integrity": "sha1-Z+LoY3lyFVMN/zGOW/nc6/1Hsho=", - "dev": true - } + "temp-dir": "^2.0.0", + "uuid": "^3.3.2" } }, "text-extensions": { @@ -9594,9 +11209,9 @@ "dev": true }, "thenify": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.0.tgz", - "integrity": "sha1-5p44obq+lpsBCCB5eLn2K4hgSDk=", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", "requires": { "any-promise": "^1.0.0" } @@ -9703,13 +11318,12 @@ } }, "to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" + "is-number": "^7.0.0" } }, "to-through": { @@ -9721,34 +11335,20 @@ "through2": "^2.0.3" } }, - "toposort": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz", - "integrity": "sha1-riF2gXXRVZ1IvvNUILL0li8JwzA=", - "dev": true - }, "tough-cookie": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", - "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", "dev": true, "requires": { - "psl": "^1.1.24", - "punycode": "^1.4.1" - }, - "dependencies": { - "punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", - "dev": true - } + "psl": "^1.1.28", + "punycode": "^2.1.1" } }, "trim-newlines": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-2.0.0.tgz", - "integrity": "sha1-tAPQuRvlDDMd/EuC7s6yLD3hbSA=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.0.tgz", + "integrity": "sha512-C4+gOpvmxaSMKuEf9Qc134F1ZuOHVXKRbtEflf4NTtuuJDEIJ9p5PXsalL8SkeRw+qit1Mo+yuvMPAKwWg/1hA==", "dev": true }, "trim-off-newlines": { @@ -9758,22 +11358,53 @@ "dev": true }, "ts-node": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.0.2.tgz", - "integrity": "sha512-MosTrinKmaAcWgO8tqMjMJB22h+sp3Rd1i4fdoWY4mhBDekOwIAKI/bzmRi7IcbCmjquccYg2gcF6NBkLgr0Tw==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-9.0.0.tgz", + "integrity": "sha512-/TqB4SnererCDR/vb4S/QvSZvzQMJN8daAslg7MeaiHvD8rDZsSfXmNeNumyZZzMned72Xoq/isQljYSt8Ynfg==", "dev": true, "requires": { "arg": "^4.1.0", - "diff": "^3.1.0", + "diff": "^4.0.1", "make-error": "^1.1.1", - "source-map-support": "^0.5.6", - "yn": "^3.0.0" + "source-map-support": "^0.5.17", + "yn": "3.1.1" + }, + "dependencies": { + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true + } } }, "tslib": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", - "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==" + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz", + "integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==" + }, + "tsutils": { + "version": "3.17.1", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.17.1.tgz", + "integrity": "sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + }, + "dependencies": { + "tslib": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz", + "integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==", + "dev": true + } + } + }, + "tunnel": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", + "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", + "dev": true }, "tunnel-agent": { "version": "0.6.0", @@ -9818,28 +11449,18 @@ "dev": true }, "typeorm-aurora-data-api-driver": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/typeorm-aurora-data-api-driver/-/typeorm-aurora-data-api-driver-1.3.0.tgz", - "integrity": "sha512-9U5/zAcRgXixbMt4Hf6VkO94657WpR+Sq/SPKKEGDh+UxI1DHpkXLquvpOAdq76/LiMpmyAIRw51Yhjk8/lxpA==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/typeorm-aurora-data-api-driver/-/typeorm-aurora-data-api-driver-1.4.0.tgz", + "integrity": "sha512-uGoVZvuStFknrhQuSzpdhdm7TG3XcOWrkHH47oMY8qNcNrYGEGkiK5Msqpoqu9nfEEY+HG6sDSx0ssmfmkF31g==", "dev": true, "requires": { - "data-api-client": "github:ArsenyYankovsky/data-api-client#support-postgres" - }, - "dependencies": { - "data-api-client": { - "version": "github:ArsenyYankovsky/data-api-client#043f3320f8d665c21250d615101e7b3bc8f1d298", - "from": "github:ArsenyYankovsky/data-api-client#support-postgres", - "dev": true, - "requires": { - "sqlstring": "^2.3.1" - } - } + "data-api-client": "^1.1.0" } }, "typescript": { - "version": "3.3.3333", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.3.3333.tgz", - "integrity": "sha512-JjSKsAfuHBE/fB2oZ8NxtRTk5iGcg6hkYXMnZ3Wc+b2RSqejEqTaem11mHASMnFilHrax3sLK0GDzcJrekZYLw==", + "version": "3.9.7", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.7.tgz", + "integrity": "sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw==", "dev": true }, "uglify-js": { @@ -9875,10 +11496,16 @@ "integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo=", "dev": true }, + "underscore": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.11.0.tgz", + "integrity": "sha512-xY96SsN3NA461qIRKZ/+qox37YXPtSBswMGfiNptr+wrt6ds4HaMw23TP612fEyGekRE6LNRiLYr/aqbHXNedw==", + "dev": true + }, "undertaker": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/undertaker/-/undertaker-1.2.0.tgz", - "integrity": "sha1-M52kZGJS0ILcN45wgGcpl1DhG0k=", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/undertaker/-/undertaker-1.3.0.tgz", + "integrity": "sha512-/RXwi5m/Mu3H6IHQGww3GNt1PNXlbeCuclF2QYR14L/2CHPz3DFZkvB5hZ0N/QUkiXWCACML2jXViIQEQc2MLg==", "dev": true, "requires": { "arr-flatten": "^1.0.1", @@ -9886,10 +11513,19 @@ "bach": "^1.0.0", "collection-map": "^1.0.0", "es6-weak-map": "^2.0.1", + "fast-levenshtein": "^1.0.0", "last-run": "^1.1.0", "object.defaults": "^1.0.0", "object.reduce": "^1.0.0", "undertaker-registry": "^1.0.0" + }, + "dependencies": { + "fast-levenshtein": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-1.1.4.tgz", + "integrity": "sha1-5qdUzI8V5YmHqpy9J69m/W9OWvk=", + "dev": true + } } }, "undertaker-registry": { @@ -9961,9 +11597,9 @@ } }, "upath": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/upath/-/upath-1.1.0.tgz", - "integrity": "sha512-bzpH/oBhoS/QI/YtbkqCg6VEiPYjSZtrHQM6/QnJS6OL9pKUFLqb3aFh4Scvwm45+7iAgiMkLhSbaZxUqmrprw==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", + "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", "dev": true }, "uri-js": { @@ -10006,9 +11642,9 @@ "dev": true }, "v8flags": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.1.2.tgz", - "integrity": "sha512-MtivA7GF24yMPte9Rp/BWGCYQNaUj86zeYxV/x2RRJMKagImbbv3u8iJC57lNhWLPcGLJmHcHmFWkNsplbbLWw==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.2.0.tgz", + "integrity": "sha512-mH8etigqMfiGWdeXpaaqGfs6BndypxusHHcv2qSHyZkGEznCd/qAXCWWRzeowtL54147cktFOC4P5y+kl8d8Jg==", "dev": true, "requires": { "homedir-polyfill": "^1.0.1" @@ -10108,6 +11744,7 @@ "version": "1.3.1", "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, "requires": { "isexe": "^2.0.0" } @@ -10144,10 +11781,17 @@ "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", "dev": true }, + "workerpool": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.0.0.tgz", + "integrity": "sha512-fU2OcNA/GVAJLLyKUoHkAgIhKb0JoCpSjLC/G2vYKxUjVmQwGbRVeoPJ1a8U4pnVofz4AQV5Y/NEw8oKqxEBtA==", + "dev": true + }, "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, "requires": { "string-width": "^1.0.1", "strip-ansi": "^3.0.1" @@ -10156,12 +11800,14 @@ "ansi-regex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true }, "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, "requires": { "number-is-nan": "^1.0.0" } @@ -10170,6 +11816,7 @@ "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", @@ -10180,6 +11827,7 @@ "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" } @@ -10218,18 +11866,30 @@ } }, "xml2js": { - "version": "0.4.19", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz", - "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==", + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", + "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", "requires": { "sax": ">=0.6.0", - "xmlbuilder": "~9.0.1" + "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.3.0", + "resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.3.0.tgz", + "integrity": "sha512-z9s6k3wxE+aZHgXYxSTpGDo7BYOUfJsIRyoZiX6HTjwpwfS2wpQBQKa2fD+ShLyPkqDYo5ud7KitmLZ2Cd6r0g==", + "dev": true + }, + "xpath.js": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/xpath.js/-/xpath.js-1.1.0.tgz", + "integrity": "sha512-jg+qkfS4K8E7965sqaUl8mRngXiKb3WZGfONgE18pr03FUQiuSV6G+Ej4tS55B+rIQSFEIw3phdVAQ4pPqNWfQ==", + "dev": true }, "xtend": { "version": "4.0.1", @@ -10240,12 +11900,19 @@ "y18n": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", - "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=" + "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=", + "dev": true }, "yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "yaml": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.0.tgz", + "integrity": "sha512-yr2icI4glYaNG+KWONODapy2/jDdMSDnrONSjblABjD9B4Z5LgiircSt8m8sRZFNi08kG9Sm0uSHtEmP3zaEGg==", "dev": true }, "yargonaut": { @@ -10296,234 +11963,159 @@ } }, "yargs": { - "version": "13.2.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.2.1.tgz", - "integrity": "sha512-HgY0xHGmPPakg6kEDufqxZuXVtvPZcipORC8O7S44iEnwsUmP+qnhReHc6d1dyeIZkrPmYFblh45Z2oeDn++fQ==", - "requires": { - "cliui": "^4.0.0", - "find-up": "^3.0.0", - "get-caller-file": "^2.0.1", - "os-locale": "^3.1.0", + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.0.3.tgz", + "integrity": "sha512-6+nLw8xa9uK1BOEOykaiYAJVh6/CjxWXK/q9b5FpRgNslt8s22F2xMBqVIKgCRjNgGvGPBy8Vog7WN7yh4amtA==", + "requires": { + "cliui": "^7.0.0", + "escalade": "^3.0.2", + "get-caller-file": "^2.0.5", "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" + "string-width": "^4.2.0", + "y18n": "^5.0.1", + "yargs-parser": "^20.0.0" }, "dependencies": { "ansi-regex": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.0.0.tgz", - "integrity": "sha512-iB5Dda8t/UqpPI/IjsejXu5jOGDrzn41wJyljwPH65VCIbk6+1BzFIMJGFwTNrYXT1CrD+B4l19U7awiQ8rk7w==" - }, - "camelcase": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.0.0.tgz", - "integrity": "sha512-faqwZqnWxbxn+F1d399ygeamQNy3lPp/H9H6rNrqYh4FSVCtcY+3cub1MxA8o9mDd55mM8Aghuu/kuyYA6VTsA==" - }, - "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==" }, - "execa": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", - "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", "requires": { - "cross-spawn": "^6.0.0", - "get-stream": "^4.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" } }, - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "cliui": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.1.tgz", + "integrity": "sha512-rcvHOWyGyid6I1WjT/3NatKj2kDt9OdSHSXpyLXaMWFbKpGACNW8pRhhdPUq9MWUOdwn8Rz9AVETjF4105rZZQ==", "requires": { - "locate-path": "^3.0.0" + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" } }, - "get-caller-file": { + "color-convert": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.1.tgz", - "integrity": "sha512-SpOZHfz845AH0wJYVuZk2jWDqFmu7Xubsx+ldIpwzy5pDUpu7OJHK7QYNSA2NPlDSKQwM1GFaAkciOWjjW92Sg==" - }, - "get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "requires": { - "pump": "^3.0.0" - } - }, - "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==" - }, - "lcid": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", - "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", - "requires": { - "invert-kv": "^2.0.0" - } - }, - "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" + "color-name": "~1.1.4" } }, - "mem": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/mem/-/mem-4.1.0.tgz", - "integrity": "sha512-I5u6Q1x7wxO0kdOpYBB28xueHADYps5uty/zg936CiG8NTe5sJL8EjrCuLneuDW3PlMdZBGDIn8BirEVdovZvg==", - "requires": { - "map-age-cleaner": "^0.1.1", - "mimic-fn": "^1.0.0", - "p-is-promise": "^2.0.0" - } + "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==" }, - "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==", - "requires": { - "execa": "^1.0.0", - "lcid": "^2.0.0", - "mem": "^4.0.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==" }, - "p-limit": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.1.0.tgz", - "integrity": "sha512-NhURkNcrVB+8hNfLuysU8enY5xn2KXphsHBaC2YmRNTZRc7RWusw6apSpdEj3jo4CMb6W9nrF6tTnsJsJeyu6g==", - "requires": { - "p-try": "^2.0.0" - } + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" }, - "p-locate": { + "is-fullwidth-code-point": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "requires": { - "p-limit": "^2.0.0" - } - }, - "p-try": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.0.0.tgz", - "integrity": "sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ==" + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "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": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" } }, - "require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" - }, - "string-width": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.0.0.tgz", - "integrity": "sha512-rr8CUxBbvOZDUvc5lNIJ+OC1nPVpz+Siw9VBtUjB9b6jZehZLFt0JMCZzShFHIsI8cbhm0EsNIfWJMFV3cu3Ew==", + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.0.0" + "ansi-regex": "^5.0.0" } }, - "strip-ansi": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.0.0.tgz", - "integrity": "sha512-Uu7gQyZI7J7gn5qLn1Np3G9vcYGTVqB+lFTytnDJv83dd8T22aGH451P3jueT2/QemInJDfxHB5Tde5OzgG1Ow==", + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "requires": { - "ansi-regex": "^4.0.0" + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" } }, "y18n": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", - "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==" + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.1.tgz", + "integrity": "sha512-/jJ831jEs4vGDbYPQp4yGKDYPSCCEQ45uZWJHE1AoYBzqdZi8+LDWas0z4HrmJXmKdpFsTiowSHXdxyFhpmdMg==" }, "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==", - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } + "version": "20.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.0.0.tgz", + "integrity": "sha512-8eblPHTL7ZWRkyjIZJjnGf+TijiKJSwA24svzLRVvtgoi/RZiKa9fFQTrlx0OKLnyHSdt/enrdadji6WFfESVA==" + } + } + }, + "yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, + "dependencies": { + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" } } }, "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": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, "camelcase": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "dev": true }, - "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "dev": true, - "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, - "execa": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", - "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", "dev": true, "requires": { - "cross-spawn": "^6.0.0", - "get-stream": "^4.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" } }, "find-up": { @@ -10535,30 +12127,12 @@ "locate-path": "^3.0.0" } }, - "get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } - }, - "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==", + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "dev": true }, - "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" - } - }, "locate-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", @@ -10569,38 +12143,10 @@ "path-exists": "^3.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" - } - }, - "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 - }, - "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" - } - }, "p-limit": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz", - "integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, "requires": { "p-try": "^2.0.0" @@ -10621,40 +12167,71 @@ "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "dev": true }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "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": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.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==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" } }, + "y18n": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", + "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", + "dev": true + }, "yargs": { - "version": "12.0.5", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz", - "integrity": "sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==", + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", "dev": true, "requires": { - "cliui": "^4.0.0", - "decamelize": "^1.2.0", + "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.2" } }, "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.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", "dev": true, "requires": { "camelcase": "^5.0.0", @@ -10664,24 +12241,10 @@ } }, "yn": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.0.0.tgz", - "integrity": "sha512-+Wo/p5VRfxUgBUGy2j/6KX2mj9AYJWOHuhMjMcbBFc3y54o9/4buK1ksBvuiK01C3kby8DH9lSmJdSxw+4G/2Q==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", "dev": true - }, - "yup": { - "version": "0.26.10", - "resolved": "https://registry.npmjs.org/yup/-/yup-0.26.10.tgz", - "integrity": "sha512-keuNEbNSnsOTOuGCt3UJW69jDE3O4P+UHAakO7vSeFMnjaitcmlbij/a3oNb9g1Y1KvSKH/7O1R2PQ4m4TRylw==", - "dev": true, - "requires": { - "@babel/runtime": "7.0.0", - "fn-name": "~2.0.1", - "lodash": "^4.17.10", - "property-expr": "^1.5.0", - "synchronous-promise": "^2.0.5", - "toposort": "^2.0.2" - } } } } diff --git a/package.json b/package.json index aa38595f43b..7432d5c900b 100644 --- a/package.json +++ b/package.json @@ -48,77 +48,77 @@ ], "devDependencies": { "@types/app-root-path": "^1.2.4", - "@types/chai": "^4.1.2", - "@types/chai-as-promised": "7.1.0", - "@types/debug": "^4.1.2", + "@types/chai": "^4.2.0", + "@types/chai-as-promised": "^7.1.3", + "@types/debug": "^4.1.5", "@types/dotenv": "^8.2.0", "@types/js-yaml": "^3.12.5", "@types/mkdirp": "^1.0.1", - "@types/mocha": "^5.2.6", - "@types/node": "^9.6.0", - "@types/rimraf": "^2.0.2", + "@types/mocha": "^8.0.3", + "@types/node": "^14.6.4", + "@types/rimraf": "^3.0.0", "@types/sha.js": "^2.4.0", - "@types/sinon": "^7.0.8", - "@types/source-map-support": "^0.4.2", + "@types/sinon": "^9.0.5", + "@types/source-map-support": "^0.5.1", "@types/xml2js": "^0.4.5", - "@types/yargs": "^12.0.9", - "@typescript-eslint/eslint-plugin": "^3.7.0", - "@typescript-eslint/parser": "^3.7.0", - "better-sqlite3": "^7.0.1", + "@types/yargs": "^15.0.4", + "@typescript-eslint/eslint-plugin": "^4.1.0", + "@typescript-eslint/parser": "^4.1.0", + "better-sqlite3": "^7.1.0", "chai": "^4.2.0", "chai-as-promised": "^7.1.1", "class-transformer": "^0.3.1", - "conventional-changelog-angular": "^5.0.3", - "conventional-changelog-cli": "^2.0.21", - "del": "^3.0.0", - "eslint": "^7.5.0", - "gulp": "^4.0.0", + "conventional-changelog-angular": "^5.0.11", + "conventional-changelog-cli": "^2.1.0", + "del": "^5.1.0", + "eslint": "^7.8.1", + "gulp": "^4.0.2", "gulp-eslint": "^6.0.0", "gulp-istanbul": "^1.1.3", - "gulp-mocha": "^6.0.0", - "gulp-rename": "^1.2.2", + "gulp-mocha": "^7.0.2", + "gulp-rename": "^2.0.0", "gulp-replace": "^1.0.0", - "gulp-shell": "^0.6.5", + "gulp-shell": "^0.8.0", "gulp-sourcemaps": "^2.6.5", - "gulp-typescript": "^5.0.0", + "gulp-typescript": "^6.0.0-alpha.1", "gulpclass": "^0.2.0", - "husky": "^1.3.1", - "lint-staged": "^8.1.4", - "mocha": "^6.1.4", - "mongodb": "^3.1.13", - "mssql": "^4.3.2", - "mysql": "^2.15.0", - "mysql2": "^1.6.5", + "husky": "^4.2.3", + "lint-staged": "^10.0.8", + "mocha": "^8.1.3", + "mongodb": "^3.5.4", + "mssql": "^6.1.0", + "mysql": "^2.18.1", + "mysql2": "^2.1.0", "oracledb": "^5.0.0", "pg": "^8.3.0", - "redis": "^2.8.0", + "redis": "^3.0.2", "remap-istanbul": "^0.13.0", - "rimraf": "^2.6.3", - "sinon": "^7.2.5", - "sinon-chai": "^3.3.0", - "source-map-support": "^0.5.10", + "rimraf": "^3.0.2", + "sinon": "^9.0.0", + "sinon-chai": "^3.5.0", + "source-map-support": "^0.5.16", "sql.js": "^1.3.0", - "sqlite3": "^4.0.9", - "ts-node": "^8.0.2", - "typeorm-aurora-data-api-driver": "^1.3.0", + "sqlite3": "^5.0.0", + "ts-node": "^9.0.0", + "typeorm-aurora-data-api-driver": "^1.4.0", "typescript": "^3.3.3333" }, "dependencies": { "app-root-path": "^3.0.0", - "buffer": "^5.1.0", - "chalk": "^2.4.2", - "cli-highlight": "^2.0.0", + "buffer": "^5.5.0", + "chalk": "^4.1.0", + "cli-highlight": "^2.1.4", "debug": "^4.1.1", "dotenv": "^8.2.0", - "glob": "^7.1.2", - "js-yaml": "^3.13.1", - "mkdirp": "^1.0.3", + "glob": "^7.1.6", + "js-yaml": "^3.14.0", + "mkdirp": "^1.0.4", "reflect-metadata": "^0.1.13", "sha.js": "^2.4.11", - "tslib": "^1.9.0", - "xml2js": "^0.4.17", + "tslib": "^1.13.0", + "xml2js": "^0.4.23", "yargonaut": "^1.1.2", - "yargs": "^13.2.1" + "yargs": "^16.0.3" }, "lint-staged": { "*.ts": [ diff --git a/src/index.ts b/src/index.ts index 5407300bb22..422440c8319 100644 --- a/src/index.ts +++ b/src/index.ts @@ -139,16 +139,12 @@ export {InsertResult} from "./query-builder/result/InsertResult"; export {UpdateResult} from "./query-builder/result/UpdateResult"; export {DeleteResult} from "./query-builder/result/DeleteResult"; export {QueryRunner} from "./query-runner/QueryRunner"; -export {EntityManager} from "./entity-manager/EntityManager"; export {MongoEntityManager} from "./entity-manager/MongoEntityManager"; export {Migration} from "./migration/Migration"; export {MigrationExecutor} from "./migration/MigrationExecutor"; export {MigrationInterface} from "./migration/MigrationInterface"; export {DefaultNamingStrategy} from "./naming-strategy/DefaultNamingStrategy"; export {NamingStrategyInterface} from "./naming-strategy/NamingStrategyInterface"; -export {Repository} from "./repository/Repository"; -export {TreeRepository} from "./repository/TreeRepository"; -export {MongoRepository} from "./repository/MongoRepository"; export {FindOneOptions} from "./find-options/FindOneOptions"; export {FindManyOptions} from "./find-options/FindManyOptions"; export {InsertEvent} from "./subscriber/event/InsertEvent"; @@ -156,7 +152,6 @@ export {LoadEvent} from "./subscriber/event/LoadEvent"; export {UpdateEvent} from "./subscriber/event/UpdateEvent"; export {RemoveEvent} from "./subscriber/event/RemoveEvent"; export {EntitySubscriberInterface} from "./subscriber/EntitySubscriberInterface"; -export {BaseEntity} from "./repository/BaseEntity"; export {EntitySchema} from "./entity-schema/EntitySchema"; export {EntitySchemaColumnOptions} from "./entity-schema/EntitySchemaColumnOptions"; export {EntitySchemaIndexOptions} from "./entity-schema/EntitySchemaIndexOptions"; diff --git a/src/query-builder/ReturningResultsEntityUpdator.ts b/src/query-builder/ReturningResultsEntityUpdator.ts index 6e9b41207ab..2080dcf366b 100644 --- a/src/query-builder/ReturningResultsEntityUpdator.ts +++ b/src/query-builder/ReturningResultsEntityUpdator.ts @@ -66,7 +66,7 @@ export class ReturningResultsEntityUpdator { .from(metadata.target, metadata.targetName) .where(entityId) .setOption("create-pojo") // use POJO because created object can contain default values, e.g. property = null and those properties maight be overridden by merge process - .getOne(); + .getOne() as any; if (loadedReturningColumns) { this.queryRunner.manager.merge(metadata.target as any, entity, loadedReturningColumns); diff --git a/test/functional/repository/basic-methods/repository-basic-methods.ts b/test/functional/repository/basic-methods/repository-basic-methods.ts index cc50f66549c..7b5ba000245 100644 --- a/test/functional/repository/basic-methods/repository-basic-methods.ts +++ b/test/functional/repository/basic-methods/repository-basic-methods.ts @@ -9,7 +9,7 @@ import {Question} from "./model/Question"; import {Blog} from "./entity/Blog"; import {Category} from "./entity/Category"; import {DeepPartial} from "../../../../src/common/DeepPartial"; -import {EntitySchema} from "../../../../src"; +import {EntitySchema, Repository} from "../../../../src"; describe("repository > basic methods", () => { @@ -152,7 +152,7 @@ describe("repository > basic methods", () => { })); it("should create a new empty object if entity schema is used", () => connections.forEach(connection => { - const repository = connection.getRepository("User"); + const repository = connection.getRepository("User") as Repository; repository.create().should.be.eql({}); })); diff --git a/test/github-issues/1014/issue-1014.ts b/test/github-issues/1014/issue-1014.ts index a94ea3999b2..943171764a4 100644 --- a/test/github-issues/1014/issue-1014.ts +++ b/test/github-issues/1014/issue-1014.ts @@ -18,13 +18,13 @@ describe("github issues > #1014 Transaction doesn't rollback", () => { const testEntity = new TestEntity(); testEntity.name = "Hello Test"; - await connection.manager.save(testEntity); + await connection.manager.save(testEntity, { reload: true }); let error: any; try { await connection.transaction(manager => { return PromiseUtils.settle([ - manager.remove(TestEntity, { id: 1 }), + manager.remove(testEntity), Promise.reject(new Error()), new Promise((resolve, reject) => reject(new Error())), ]); diff --git a/test/github-issues/1123/issue-1123.ts b/test/github-issues/1123/issue-1123.ts index da7ccabb4cb..a7aec5aad5b 100644 --- a/test/github-issues/1123/issue-1123.ts +++ b/test/github-issues/1123/issue-1123.ts @@ -54,7 +54,7 @@ describe("github issues > #1123 load relation eagerly by setting isEager propert const loadedPost = await connection.manager .createQueryBuilder("Post", "post") .where("post.id = :id", { id: 1 }) - .getOne(); + .getOne() as Post; loadedPost!.should.be.eql({ id: 1, diff --git a/test/github-issues/4156/issue-4156.ts b/test/github-issues/4156/issue-4156.ts index e6ada524eca..26aa21815e8 100644 --- a/test/github-issues/4156/issue-4156.ts +++ b/test/github-issues/4156/issue-4156.ts @@ -41,7 +41,7 @@ describe("github issues > #4156 QueryExpressionMap doesn't clone all values corr const [loadedPost1, loadedPost2] = await Promise.all([ qb.clone().where({ id: 1 }).getOne(), qb.clone().where({ id: In([1]) }).getOne(), - ]); + ]) as Post[]; loadedPost1!.should.be.eql({ id: 1, @@ -67,7 +67,7 @@ describe("github issues > #4156 QueryExpressionMap doesn't clone all values corr const [loadedPost1, loadedPost2] = await Promise.all([ qb.clone().getOne(), qb.clone().getOne(), - ]); + ]) as Post[]; loadedPost1!.should.be.eql({ id: 1, From 370442c27a0aecd67eeb44f6077922dda16bcef8 Mon Sep 17 00:00:00 2001 From: Arty <26905074+artysidorenko@users.noreply.github.com> Date: Sat, 12 Sep 2020 21:36:05 +0100 Subject: [PATCH 069/212] feat: Beautify generated SQL for migrations (#6685) * feat: Beautify generated SQL for migrations Allows user to pass an optional flag to beautify generated SQL for migrations Closes: #4415 * fixed formatter version Co-authored-by: Umed Khudoiberdiev --- docs/migrations.md | 2 +- package-lock.json | 6 + package.json | 1 + src/commands/MigrationGenerateCommand.ts | 24 +++ test/github-issues/4415/entity/Post.ts | 14 ++ test/github-issues/4415/entity/Username.ts | 15 ++ test/github-issues/4415/issue-4415.ts | 108 +++++++++++++ test/github-issues/4415/results-templates.ts | 157 +++++++++++++++++++ 8 files changed, 326 insertions(+), 1 deletion(-) create mode 100644 test/github-issues/4415/entity/Post.ts create mode 100644 test/github-issues/4415/entity/Username.ts create mode 100644 test/github-issues/4415/issue-4415.ts create mode 100644 test/github-issues/4415/results-templates.ts diff --git a/docs/migrations.md b/docs/migrations.md index 7c903aa6dc2..3e4799d2059 100644 --- a/docs/migrations.md +++ b/docs/migrations.md @@ -195,7 +195,7 @@ export class PostRefactoringTIMESTAMP implements MigrationInterface { ``` See, you don't need to write the queries on your own. -The rule of thumb for generating migrations is that you generate them after "each" change you made to your models. +The rule of thumb for generating migrations is that you generate them after "each" change you made to your models. To apply multi-line formatting to your generated migration queries, use the `p` (alias for `--pretty`) flag. ## Connection option If you need to run/revert your migrations for another connection rather than the default, use the `-c` (alias for `--connection`) and pass the config name as an argument diff --git a/package-lock.json b/package-lock.json index e81e794aded..edd53ab49d7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -251,6 +251,12 @@ "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==", "dev": true }, + "@sqltools/formatter": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@sqltools/formatter/-/formatter-1.2.2.tgz", + "integrity": "sha512-/5O7Fq6Vnv8L6ucmPjaWbVG1XkP4FO+w5glqfkIsq3Xw4oyNAdJddbnYodNDAfjVUvo/rrSCTom4kAND7T1o5Q==", + "dev": true + }, "@types/app-root-path": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/@types/app-root-path/-/app-root-path-1.2.4.tgz", diff --git a/package.json b/package.json index 7432d5c900b..6e22c75a480 100644 --- a/package.json +++ b/package.json @@ -104,6 +104,7 @@ "typescript": "^3.3.3333" }, "dependencies": { + "@sqltools/formatter": "1.2.2", "app-root-path": "^3.0.0", "buffer": "^5.5.0", "chalk": "^4.1.0", diff --git a/src/commands/MigrationGenerateCommand.ts b/src/commands/MigrationGenerateCommand.ts index f036fd67fc8..5fb779b7cc9 100644 --- a/src/commands/MigrationGenerateCommand.ts +++ b/src/commands/MigrationGenerateCommand.ts @@ -7,6 +7,7 @@ import {camelCase} from "../util/StringUtils"; import * as yargs from "yargs"; import {AuroraDataApiDriver} from "../driver/aurora-data-api/AuroraDataApiDriver"; import chalk from "chalk"; +import { format } from "@sqltools/formatter/lib/sqlFormatter"; /** * Generates a new migration file with sql needs to be executed to update schema. @@ -33,6 +34,12 @@ export class MigrationGenerateCommand implements yargs.CommandModule { alias: "dir", describe: "Directory where migration should be created." }) + .option("p", { + alias: "pretty", + type: "boolean", + default: false, + describe: "Pretty-print generated SQL", + }) .option("f", { alias: "config", default: "ormconfig", @@ -76,6 +83,16 @@ export class MigrationGenerateCommand implements yargs.CommandModule { }); connection = await createConnection(connectionOptions); const sqlInMemory = await connection.driver.createSchemaBuilder().log(); + + if (args.pretty) { + sqlInMemory.upQueries.forEach(upQuery => { + upQuery.query = MigrationGenerateCommand.prettifyQuery(upQuery.query); + }); + sqlInMemory.downQueries.forEach(downQuery => { + downQuery.query = MigrationGenerateCommand.prettifyQuery(downQuery.query); + }); + } + const upSqls: string[] = [], downSqls: string[] = []; // mysql is exceptional here because it uses ` character in to escape names in queries, that's why for mysql @@ -160,4 +177,11 @@ ${downSqls.join(` `; } + /** + * + */ + protected static prettifyQuery(query: string) { + const formattedQuery = format(query, { indent: " " }); + return "\n" + formattedQuery.replace(/^/gm, " ") + "\n "; + } } diff --git a/test/github-issues/4415/entity/Post.ts b/test/github-issues/4415/entity/Post.ts new file mode 100644 index 00000000000..94e6f92ea52 --- /dev/null +++ b/test/github-issues/4415/entity/Post.ts @@ -0,0 +1,14 @@ +import { PrimaryGeneratedColumn, Entity, Column, CreateDateColumn } from "../../../../src"; + +@Entity() +export class Post { + + @PrimaryGeneratedColumn() + id?: number; + + @Column() + title: string; + + @CreateDateColumn() + readonly createdAt?: Date; +} diff --git a/test/github-issues/4415/entity/Username.ts b/test/github-issues/4415/entity/Username.ts new file mode 100644 index 00000000000..b1f7b555527 --- /dev/null +++ b/test/github-issues/4415/entity/Username.ts @@ -0,0 +1,15 @@ +import { Column } from "../../../../src/decorator/columns/Column"; +import { PrimaryColumn } from "../../../../src/decorator/columns/PrimaryColumn"; +import { Entity } from "../../../../src/decorator/entity/Entity"; + +@Entity() +export class Username { + @PrimaryColumn() + username: string; + + @Column() + email: string; + + @Column() + something: string; +} diff --git a/test/github-issues/4415/issue-4415.ts b/test/github-issues/4415/issue-4415.ts new file mode 100644 index 00000000000..5f0a08af579 --- /dev/null +++ b/test/github-issues/4415/issue-4415.ts @@ -0,0 +1,108 @@ +import sinon from "sinon"; +import { ConnectionOptions, ConnectionOptionsReader, DatabaseType } from "../../../src"; +import { setupTestingConnections, createTestingConnections, closeTestingConnections, reloadTestingDatabases } from "../../utils/test-utils"; +import { Username } from "./entity/Username"; +import { CommandUtils } from "../../../src/commands/CommandUtils"; +import { MigrationGenerateCommand } from "../../../src/commands/MigrationGenerateCommand"; +import { Post } from "./entity/Post"; +import { resultsTemplates } from "./results-templates"; + +describe("github issues > #4415 allow beautify generated migrations", () => { + let connectionOptions: ConnectionOptions[]; + let createFileStub: sinon.SinonStub; + let getConnectionOptionsStub: sinon.SinonStub; + let migrationGenerateCommand: MigrationGenerateCommand; + let connectionOptionsReader: ConnectionOptionsReader; + let baseConnectionOptions: ConnectionOptions; + + const enabledDrivers = [ + "postgres", + "mssql", + "mysql", + "mariadb", + "sqlite", + "better-sqlite3", + "oracle", + "cockroachdb" + ] as DatabaseType[]; + + // simulate args: `npm run typeorm migration:run -- -n test-migration -d test-directory` + const testHandlerArgs = (options: Record) => ({ + "$0": "test", + "_": ["test"], + "name": "test-migration", + "dir": "test-directory", + ...options + }); + + before(async () => { + // clean out db from any prior tests in case previous state impacts the generated migrations + const connections = await createTestingConnections({ + entities: [], + enabledDrivers + }); + await reloadTestingDatabases(connections); + await closeTestingConnections(connections); + + connectionOptions = await setupTestingConnections({ + entities: [Username, Post], + enabledDrivers + }); + connectionOptionsReader = new ConnectionOptionsReader(); + migrationGenerateCommand = new MigrationGenerateCommand(); + createFileStub = sinon.stub(CommandUtils, "createFile"); + }); + after(() => createFileStub.restore()); + + it("writes regular migration file when no option is passed", async () => { + for (const connectionOption of connectionOptions) { + createFileStub.resetHistory(); + baseConnectionOptions = await connectionOptionsReader.get(connectionOption.name as string); + getConnectionOptionsStub = sinon.stub(ConnectionOptionsReader.prototype, "get").resolves({ + ...baseConnectionOptions, + entities: [Username, Post] + }); + + await migrationGenerateCommand.handler(testHandlerArgs({ + "connection": connectionOption.name + })); + + // compare against control test strings in results-templates.ts + for (const control of resultsTemplates[connectionOption.type as string].control) { + sinon.assert.calledWith( + createFileStub, + sinon.match(/test-directory.*test-migration.ts/), + sinon.match(control) + ); + } + + getConnectionOptionsStub.restore(); + } + }); + + it("writes pretty printed file when pretty option is passed", async () => { + for (const connectionOption of connectionOptions) { + createFileStub.resetHistory(); + baseConnectionOptions = await connectionOptionsReader.get(connectionOption.name as string); + getConnectionOptionsStub = sinon.stub(ConnectionOptionsReader.prototype, "get").resolves({ + ...baseConnectionOptions, + entities: [Username, Post] + }); + + await migrationGenerateCommand.handler(testHandlerArgs({ + "connection": connectionOption.name, + "pretty": true + })); + + // compare against "pretty" test strings in results-templates.ts + for (const pretty of resultsTemplates[connectionOption.type as string].pretty) { + sinon.assert.calledWith( + createFileStub, + sinon.match(/test-directory.*test-migration.ts/), + sinon.match(pretty) + ); + } + getConnectionOptionsStub.restore(); + } + }); +}); diff --git a/test/github-issues/4415/results-templates.ts b/test/github-issues/4415/results-templates.ts new file mode 100644 index 00000000000..ce7c7d63ee6 --- /dev/null +++ b/test/github-issues/4415/results-templates.ts @@ -0,0 +1,157 @@ +export const resultsTemplates: Record = { + + postgres: { + control: [ + `CREATE TABLE "post" ("id" SERIAL NOT NULL, "title" character varying NOT NULL, "createdAt" TIMESTAMP NOT NULL DEFAULT now(), CONSTRAINT "PK_be5fda3aac270b134ff9c21cdee" PRIMARY KEY ("id"))`, + `CREATE TABLE "username" ("username" character varying NOT NULL, "email" character varying NOT NULL, "something" character varying NOT NULL, CONSTRAINT "PK_b39ad32e514b17e90c93988888a" PRIMARY KEY ("username"))` + ], + pretty: [ + ` + CREATE TABLE "post" ( + "id" SERIAL NOT NULL, + "title" character varying NOT NULL, + "createdAt" TIMESTAMP NOT NULL DEFAULT now(), + CONSTRAINT "PK_be5fda3aac270b134ff9c21cdee" PRIMARY KEY ("id") + ) + `, + ` + CREATE TABLE "username" ( + "username" character varying NOT NULL, + "email" character varying NOT NULL, + "something" character varying NOT NULL, + CONSTRAINT "PK_b39ad32e514b17e90c93988888a" PRIMARY KEY ("username") + ) + ` + ] + }, + + mssql: { + control: [ + `CREATE TABLE "post" ("id" int NOT NULL IDENTITY(1,1), "title" nvarchar(255) NOT NULL, "createdAt" datetime2 NOT NULL CONSTRAINT "DF_fb91bea2d37140a877b775e6b2a" DEFAULT getdate(), CONSTRAINT "PK_be5fda3aac270b134ff9c21cdee" PRIMARY KEY ("id"))`, + `CREATE TABLE "username" ("username" nvarchar(255) NOT NULL, "email" nvarchar(255) NOT NULL, "something" nvarchar(255) NOT NULL, CONSTRAINT "PK_b39ad32e514b17e90c93988888a" PRIMARY KEY ("username"))` + ], + pretty: [ + ` + CREATE TABLE "post" ( + "id" int NOT NULL IDENTITY(1, 1), + "title" nvarchar(255) NOT NULL, + "createdAt" datetime2 NOT NULL CONSTRAINT "DF_fb91bea2d37140a877b775e6b2a" DEFAULT getdate(), + CONSTRAINT "PK_be5fda3aac270b134ff9c21cdee" PRIMARY KEY ("id") + ) + `, + ` + CREATE TABLE "username" ( + "username" nvarchar(255) NOT NULL, + "email" nvarchar(255) NOT NULL, + "something" nvarchar(255) NOT NULL, + CONSTRAINT "PK_b39ad32e514b17e90c93988888a" PRIMARY KEY ("username") + ) + ` + ] + }, + + sqlite: { + control: [ + `CREATE TABLE "post" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "title" varchar NOT NULL, "createdAt" datetime NOT NULL DEFAULT (datetime('now')))`, + `CREATE TABLE "username" ("username" varchar PRIMARY KEY NOT NULL, "email" varchar NOT NULL, "something" varchar NOT NULL)`, + ], + pretty: [ + ` + CREATE TABLE "post" ( + "id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, + "title" varchar NOT NULL, + "createdAt" datetime NOT NULL DEFAULT (datetime('now')) + ) + `, + ` + CREATE TABLE "username" ( + "username" varchar PRIMARY KEY NOT NULL, + "email" varchar NOT NULL, + "something" varchar NOT NULL + ) + ` + ] + }, + + mysql: { + control: [ + `CREATE TABLE \`post\` (\`id\` int NOT NULL AUTO_INCREMENT, \`title\` varchar(255) NOT NULL, \`createdAt\` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6), PRIMARY KEY (\`id\`)) ENGINE=InnoDB`, + `CREATE TABLE \`username\` (\`username\` varchar(255) NOT NULL, \`email\` varchar(255) NOT NULL, \`something\` varchar(255) NOT NULL, PRIMARY KEY (\`username\`)) ENGINE=InnoDB` + ], + pretty: [ + ` + CREATE TABLE \`post\` ( + \`id\` int NOT NULL AUTO_INCREMENT, + \`title\` varchar(255) NOT NULL, + \`createdAt\` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6), + PRIMARY KEY (\`id\`) + ) ENGINE = InnoDB + `, + ` + CREATE TABLE \`username\` ( + \`username\` varchar(255) NOT NULL, + \`email\` varchar(255) NOT NULL, + \`something\` varchar(255) NOT NULL, + PRIMARY KEY (\`username\`) + ) ENGINE = InnoDB + ` + ] + }, + + oracle: { + control: [ + `CREATE TABLE "post" ("id" number GENERATED BY DEFAULT AS IDENTITY, "title" varchar2(255) NOT NULL, "createdAt" timestamp DEFAULT CURRENT_TIMESTAMP NOT NULL, CONSTRAINT "PK_be5fda3aac270b134ff9c21cdee" PRIMARY KEY ("id"))`, + `CREATE TABLE "username" ("username" varchar2(255) NOT NULL, "email" varchar2(255) NOT NULL, "something" varchar2(255) NOT NULL, CONSTRAINT "PK_b39ad32e514b17e90c93988888a" PRIMARY KEY ("username"))` + ], + pretty: [ + ` + CREATE TABLE "post" ( + "id" number GENERATED BY DEFAULT AS IDENTITY, + "title" varchar2(255) NOT NULL, + "createdAt" timestamp DEFAULT CURRENT_TIMESTAMP NOT NULL, + CONSTRAINT "PK_be5fda3aac270b134ff9c21cdee" PRIMARY KEY ("id") + ) + `, + ` + CREATE TABLE "username" ( + "username" varchar2(255) NOT NULL, + "email" varchar2(255) NOT NULL, + "something" varchar2(255) NOT NULL, + CONSTRAINT "PK_b39ad32e514b17e90c93988888a" PRIMARY KEY ("username") + ) + ` + ] + }, + + cockroachdb: { + control: [ + `CREATE SEQUENCE "post_id_seq"`, + `CREATE TABLE "post" ("id" INT DEFAULT nextval('"post_id_seq"') NOT NULL, "title" varchar NOT NULL, "createdAt" timestamptz NOT NULL DEFAULT now(), CONSTRAINT "PK_be5fda3aac270b134ff9c21cdee" PRIMARY KEY ("id"))`, + `CREATE TABLE "username" ("username" varchar NOT NULL, "email" varchar NOT NULL, "something" varchar NOT NULL, CONSTRAINT "PK_b39ad32e514b17e90c93988888a" PRIMARY KEY ("username"))` + ], + pretty: [ + ` + CREATE SEQUENCE "post_id_seq" + `, + ` + CREATE TABLE "post" ( + "id" INT DEFAULT nextval('"post_id_seq"') NOT NULL, + "title" varchar NOT NULL, + "createdAt" timestamptz NOT NULL DEFAULT now(), + CONSTRAINT "PK_be5fda3aac270b134ff9c21cdee" PRIMARY KEY ("id") + ) + `, + ` + CREATE TABLE "username" ( + "username" varchar NOT NULL, + "email" varchar NOT NULL, + "something" varchar NOT NULL, + CONSTRAINT "PK_b39ad32e514b17e90c93988888a" PRIMARY KEY ("username") + ) + ` + ] + }, + + get mariadb() { return this.mysql; }, + get "better-sqlite3"() { return this.sqlite; }, +}; From 7a52f18c86613292c3503484eac332f59141a6e3 Mon Sep 17 00:00:00 2001 From: James Ward Date: Sat, 12 Sep 2020 17:57:33 -0400 Subject: [PATCH 070/212] feat: backport SQLite Busy handler & WAL mode enable (#6588) * added sqlitebusy handling logic * added sqlite wal mode enable logic * cleaner if block * move pragma journal mode setting to driver connection * add enable-wal test Co-authored-by: Umed Khudoiberdiev --- src/driver/sqlite/SqliteConnectionOptions.ts | 22 ++++++++++++- src/driver/sqlite/SqliteDriver.ts | 4 +++ src/driver/sqlite/SqliteQueryRunner.ts | 33 ++++++++++++++------ test/functional/sqlite/enable-wal.ts | 24 ++++++++++++++ 4 files changed, 72 insertions(+), 11 deletions(-) create mode 100644 test/functional/sqlite/enable-wal.ts diff --git a/src/driver/sqlite/SqliteConnectionOptions.ts b/src/driver/sqlite/SqliteConnectionOptions.ts index 9155047e4fc..8e092b9c697 100644 --- a/src/driver/sqlite/SqliteConnectionOptions.ts +++ b/src/driver/sqlite/SqliteConnectionOptions.ts @@ -20,4 +20,24 @@ export interface SqliteConnectionOptions extends BaseConnectionOptions { */ readonly key?: string; -} \ No newline at end of file + /** + * In your SQLite application when you perform parallel writes its common to face SQLITE_BUSY error. + * This error indicates that SQLite failed to write to the database file since someone else already writes into it. + * Since SQLite cannot handle parallel saves this error cannot be avoided. + * + * To simplify life's of those who have this error this particular option sets a timeout within which ORM will try + * to perform requested write operation again and again until it receives SQLITE_BUSY error. + * + * Enabling WAL can improve your app performance and face less SQLITE_BUSY issues. + * Time in milliseconds. + */ + readonly busyErrorRetry?: number; + + /** + * Enables WAL mode. By default its disabled. + * + * @see https://www.sqlite.org/wal.html + */ + readonly enableWAL?: boolean; + +} diff --git a/src/driver/sqlite/SqliteDriver.ts b/src/driver/sqlite/SqliteDriver.ts index fd271d72f2c..aa27e36544e 100644 --- a/src/driver/sqlite/SqliteDriver.ts +++ b/src/driver/sqlite/SqliteDriver.ts @@ -107,6 +107,10 @@ export class SqliteDriver extends AbstractSqliteDriver { }); } + if (this.options.enableWAL) { + await run(`PRAGMA journal_mode = WAL;`); + } + // we need to enable foreign keys in sqlite to make sure all foreign key related features // working properly. this also makes onDelete to work with sqlite. await run(`PRAGMA foreign_keys = ON;`); diff --git a/src/driver/sqlite/SqliteQueryRunner.ts b/src/driver/sqlite/SqliteQueryRunner.ts index 6e5a55d8851..308bb72855b 100644 --- a/src/driver/sqlite/SqliteQueryRunner.ts +++ b/src/driver/sqlite/SqliteQueryRunner.ts @@ -1,6 +1,7 @@ import {QueryRunnerAlreadyReleasedError} from "../../error/QueryRunnerAlreadyReleasedError"; import {QueryFailedError} from "../../error/QueryFailedError"; import {AbstractSqliteQueryRunner} from "../sqlite-abstract/AbstractSqliteQueryRunner"; +import {SqliteConnectionOptions} from "./SqliteConnectionOptions"; import {SqliteDriver} from "./SqliteDriver"; import {Broadcaster} from "../../subscriber/Broadcaster"; @@ -36,10 +37,30 @@ export class SqliteQueryRunner extends AbstractSqliteQueryRunner { throw new QueryRunnerAlreadyReleasedError(); const connection = this.driver.connection; + const options = connection.options as SqliteConnectionOptions; return new Promise(async (ok, fail) => { + const databaseConnection = await this.connect(); + this.driver.connection.logger.logQuery(query, parameters, this); + const queryStartTime = +new Date(); + const isInsertQuery = query.substr(0, 11) === "INSERT INTO"; + + const execute = async () => { + if (isInsertQuery) { + databaseConnection.run(query, parameters, handler); + } else { + databaseConnection.all(query, parameters, handler); + } + }; + const handler = function (err: any, result: any) { + if (err && err.toString().indexOf("SQLITE_BUSY:") !== -1) { + if (typeof options.busyErrorRetry === "number" && options.busyErrorRetry > 0) { + setTimeout(execute, options.busyErrorRetry); + return; + } + } // log slow queries if maxQueryExecution time is set const maxQueryExecutionTime = connection.options.maxQueryExecutionTime; @@ -56,15 +77,7 @@ export class SqliteQueryRunner extends AbstractSqliteQueryRunner { } }; - const databaseConnection = await this.connect(); - this.driver.connection.logger.logQuery(query, parameters, this); - const queryStartTime = +new Date(); - const isInsertQuery = query.substr(0, 11) === "INSERT INTO"; - if (isInsertQuery) { - databaseConnection.run(query, parameters, handler); - } else { - databaseConnection.all(query, parameters, handler); - } + await execute(); }); } -} \ No newline at end of file +} diff --git a/test/functional/sqlite/enable-wal.ts b/test/functional/sqlite/enable-wal.ts new file mode 100644 index 00000000000..b1af701ebf2 --- /dev/null +++ b/test/functional/sqlite/enable-wal.ts @@ -0,0 +1,24 @@ +import "reflect-metadata"; +import {expect} from "chai"; +import {Connection} from "../../../src/connection/Connection"; +import {closeTestingConnections, createTestingConnections, reloadTestingDatabases} from "../../utils/test-utils"; + +describe("sqlite driver > enable wal", () => { + let connections: Connection[]; + before(async () => connections = await createTestingConnections({ + entities: [], + enabledDrivers: ["sqlite"], + driverSpecific: { + enableWAL: true + } + })); + beforeEach(() => reloadTestingDatabases(connections)); + after(() => closeTestingConnections(connections)); + + it("should set the journal mode as expected", () => Promise.all(connections.map(async connection => { + // if we come this far, test was successful as a connection was established + const result = await connection.query('PRAGMA journal_mode'); + + expect(result).to.eql([{ journal_mode: 'wal'}]); + }))); +}); From 208cf6b0511a2d565c7999837497bb6cf8f8e7c7 Mon Sep 17 00:00:00 2001 From: James Ward Date: Mon, 14 Sep 2020 07:10:13 -0400 Subject: [PATCH 071/212] fix: prevent multiple `release` listeners in PostgresQueryRunner (#6708) move on-error-release code to the queryRunner connect function so we only need to have one listener per query runner on each connection - cutting donw the number of listeners total & preventing a problem with too many listeners closes #6699 --- src/driver/postgres/PostgresQueryRunner.ts | 31 +++++++++++++--------- test/github-issues/6699/issue-6699.ts | 30 +++++++++++++++++++++ 2 files changed, 49 insertions(+), 12 deletions(-) create mode 100644 test/github-issues/6699/issue-6699.ts diff --git a/src/driver/postgres/PostgresQueryRunner.ts b/src/driver/postgres/PostgresQueryRunner.ts index e0ff11ebb5a..716d3d190d5 100644 --- a/src/driver/postgres/PostgresQueryRunner.ts +++ b/src/driver/postgres/PostgresQueryRunner.ts @@ -79,10 +79,17 @@ export class PostgresQueryRunner extends BaseQueryRunner implements QueryRunner return this.databaseConnectionPromise; if (this.mode === "slave" && this.driver.isReplicated) { - this.databaseConnectionPromise = this.driver.obtainSlaveConnection().then(([ connection, release]: any[]) => { + this.databaseConnectionPromise = this.driver.obtainSlaveConnection().then(([connection, release]: any[]) => { this.driver.connectedQueryRunners.push(this); this.databaseConnection = connection; - this.releaseCallback = release; + + const onErrorCallback = () => this.release(); + this.releaseCallback = () => { + this.databaseConnection.removeListener("error", onErrorCallback); + release(); + }; + this.databaseConnection.on("error", onErrorCallback); + return this.databaseConnection; }); @@ -90,7 +97,14 @@ export class PostgresQueryRunner extends BaseQueryRunner implements QueryRunner this.databaseConnectionPromise = this.driver.obtainMasterConnection().then(([connection, release]: any[]) => { this.driver.connectedQueryRunners.push(this); this.databaseConnection = connection; - this.releaseCallback = release; + + const onErrorCallback = () => this.release(); + this.releaseCallback = () => { + this.databaseConnection.removeListener("error", onErrorCallback); + release(); + }; + this.databaseConnection.on("error", onErrorCallback); + return this.databaseConnection; }); } @@ -102,14 +116,14 @@ export class PostgresQueryRunner extends BaseQueryRunner implements QueryRunner * Releases used database connection. * You cannot use query runner methods once its released. */ - release(err?: any): Promise { + release(): Promise { if (this.isReleased) { return Promise.resolve(); } this.isReleased = true; if (this.releaseCallback) - this.releaseCallback(err); + this.releaseCallback(); const index = this.driver.connectedQueryRunners.indexOf(this); if (index !== -1) this.driver.connectedQueryRunners.splice(index); @@ -168,14 +182,7 @@ export class PostgresQueryRunner extends BaseQueryRunner implements QueryRunner this.driver.connection.logger.logQuery(query, parameters, this); const queryStartTime = +new Date(); - const onError = (err: any) => { - this.release(err); - }; - databaseConnection.once("error", onError); - databaseConnection.query(query, parameters, (err: any, result: any) => { - databaseConnection.removeListener("error", onError); - // log slow queries if maxQueryExecution time is set const maxQueryExecutionTime = this.driver.connection.options.maxQueryExecutionTime; const queryEndTime = +new Date(); diff --git a/test/github-issues/6699/issue-6699.ts b/test/github-issues/6699/issue-6699.ts new file mode 100644 index 00000000000..b7f6d525c1f --- /dev/null +++ b/test/github-issues/6699/issue-6699.ts @@ -0,0 +1,30 @@ +import {closeTestingConnections, createTestingConnections, reloadTestingDatabases} from "../../utils/test-utils"; +import {Connection} from "../../../src/connection/Connection"; +import {expect} from 'chai'; + +describe("github issues > #6699 MaxListenersExceededWarning occurs on Postgres", () => { + + let connections: Connection[]; + before(async () => connections = await createTestingConnections({ + entities: [], + enabledDrivers: ["postgres"] + })); + beforeEach(() => reloadTestingDatabases(connections)); + after(() => closeTestingConnections(connections)); + + it("queries in a transaction do not cause an EventEmitter memory leak", () => Promise.all(connections.map(async connection => { + await connection.transaction(async manager => { + const queryPromises = [...Array(10)].map( + () => manager.query('SELECT pg_sleep(0.0001)') + ); + + const pgConnection = await manager.queryRunner!.connect(); + + expect(pgConnection.listenerCount('error')).to.equal(1); + + // Wait for all of the queries to finish and drain the backlog + await Promise.all(queryPromises); + }); + }))); + +}); From b50576e1022ff773739429c8fe2672cc3bf059bb Mon Sep 17 00:00:00 2001 From: Juuso Mikkonen Date: Mon, 14 Sep 2020 14:12:10 +0300 Subject: [PATCH 072/212] docs: correct the comment of OneToMany decorator (#6712) --- src/decorator/relations/OneToMany.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/decorator/relations/OneToMany.ts b/src/decorator/relations/OneToMany.ts index 802c754e263..e174ba8f084 100644 --- a/src/decorator/relations/OneToMany.ts +++ b/src/decorator/relations/OneToMany.ts @@ -2,8 +2,8 @@ import {getMetadataArgsStorage, ObjectType, RelationOptions} from "../../"; import {RelationMetadataArgs} from "../../metadata-args/RelationMetadataArgs"; /** - * One-to-many relation allows to create type of relation when Entity2 can have multiple instances of Entity1. - * Entity1 have only one Entity2. Entity1 is an owner of the relationship, and storages Entity2 id on its own side. + * One-to-many relation allows to create type of relation when Entity1 can have multiple instances of Entity2. + * Entity2 have only one Entity1. Entity2 is an owner of the relationship, and storages Entity1 id on its own side. */ export function OneToMany(typeFunctionOrTarget: string|((type?: any) => ObjectType), inverseSide: string|((object: T) => any), options?: RelationOptions): PropertyDecorator { return function (object: Object, propertyName: string) { From 2b3780836f5fd737fdc58fe4e0eb2ea4200cae66 Mon Sep 17 00:00:00 2001 From: James Ward Date: Tue, 15 Sep 2020 07:27:24 -0400 Subject: [PATCH 073/212] fix: backport FindOperator return types (#6717) the `next` branch added return types to `FindOperator`s and this backports that change --- src/find-options/operator/Any.ts | 4 ++-- src/find-options/operator/Between.ts | 4 ++-- src/find-options/operator/In.ts | 4 ++-- src/find-options/operator/Raw.ts | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/find-options/operator/Any.ts b/src/find-options/operator/Any.ts index 4b39792c6b2..3d66e20887a 100644 --- a/src/find-options/operator/Any.ts +++ b/src/find-options/operator/Any.ts @@ -4,6 +4,6 @@ import {FindOperator} from "../FindOperator"; * Find Options Operator. * Example: { someField: Any([...]) } */ -export function Any(value: T[]|FindOperator) { +export function Any(value: T[]|FindOperator): FindOperator { return new FindOperator("any", value as any); -} \ No newline at end of file +} diff --git a/src/find-options/operator/Between.ts b/src/find-options/operator/Between.ts index 798b6560199..cbb07b63b5e 100644 --- a/src/find-options/operator/Between.ts +++ b/src/find-options/operator/Between.ts @@ -4,6 +4,6 @@ import {FindOperator} from "../FindOperator"; * Find Options Operator. * Example: { someField: Between(x, y) } */ -export function Between(from: T|FindOperator, to: T|FindOperator) { +export function Between(from: T|FindOperator, to: T|FindOperator): FindOperator { return new FindOperator("between", [from, to] as any, true, true); -} \ No newline at end of file +} diff --git a/src/find-options/operator/In.ts b/src/find-options/operator/In.ts index 97875e9a063..d907f43f140 100644 --- a/src/find-options/operator/In.ts +++ b/src/find-options/operator/In.ts @@ -4,6 +4,6 @@ import {FindOperator} from "../FindOperator"; * Find Options Operator. * Example: { someField: In([...]) } */ -export function In(value: T[]|FindOperator) { +export function In(value: T[]|FindOperator): FindOperator { return new FindOperator("in", value as any, true, true); -} \ No newline at end of file +} diff --git a/src/find-options/operator/Raw.ts b/src/find-options/operator/Raw.ts index 7c1f4c5d0ce..aeba177478d 100644 --- a/src/find-options/operator/Raw.ts +++ b/src/find-options/operator/Raw.ts @@ -4,6 +4,6 @@ import {FindOperator} from "../FindOperator"; * Find Options Operator. * Example: { someField: Raw([...]) } */ -export function Raw(value: string|((columnAlias: string) => string)) { +export function Raw(value: string|((columnAlias: string) => string)): FindOperator { return new FindOperator("raw", value as any, false); -} \ No newline at end of file +} From 4baac7108652d11af2e06a7702c18179e556adbd Mon Sep 17 00:00:00 2001 From: James Ward Date: Tue, 15 Sep 2020 07:33:27 -0400 Subject: [PATCH 074/212] style: backport style fixes in next to cut down on churn (#6715) the `next` branch has a number of style fixes for the project aroundnd whitespaces - this pulls them into `master` to cut down on the files changes between the two branches --- src/commands/MigrationGenerateCommand.ts | 4 +-- src/decorator/EntityRepository.ts | 6 ++-- src/decorator/columns/Column.ts | 10 +++++-- src/decorator/columns/PrimaryColumn.ts | 2 +- src/decorator/options/ColumnOptions.ts | 2 +- src/decorator/options/TransactionOptions.ts | 4 +-- src/driver/DriverUtils.ts | 4 +-- .../CockroachConnectionCredentialsOptions.ts | 2 +- src/driver/mongodb/MongoQueryRunner.ts | 28 +++++++++---------- src/driver/mongodb/typings.ts | 4 +-- src/driver/mysql/MysqlQueryRunner.ts | 2 +- src/driver/oracle/OracleDriver.ts | 2 +- .../PostgresConnectionCredentialsOptions.ts | 2 +- .../EntitySchemaColumnOptions.ts | 2 +- src/error/QueryFailedError.ts | 4 +-- .../RelationCountMetadataArgs.ts | 1 + src/metadata-args/RelationIdMetadataArgs.ts | 1 + src/migration/MigrationExecutor.ts | 4 +-- src/platform/PlatformTools.ts | 1 + src/query-builder/Alias.ts | 4 +-- .../RawSqlResultsToEntityTransformer.ts | 1 - src/repository/MongoRepository.ts | 5 ++-- src/schema-builder/MongoSchemaBuilder.ts | 10 +++---- src/schema-builder/view/View.ts | 3 +- src/util/ApplyValueTransformers.ts | 4 +-- src/util/DateUtils.ts | 2 +- src/util/OrmUtils.ts | 2 +- .../basic/entity/Post.ts | 4 +-- .../query-builder/join/query-builder-joins.ts | 2 +- .../basic-methods/repository-basic-methods.ts | 8 +++--- test/github-issues/1545/entity/DataModel.ts | 8 +++--- test/github-issues/1972/issue-1972.ts | 1 - test/github-issues/2044/issue-2044.ts | 3 +- test/github-issues/2965/index.ts | 7 ++--- tsconfig.json | 2 +- 35 files changed, 76 insertions(+), 75 deletions(-) diff --git a/src/commands/MigrationGenerateCommand.ts b/src/commands/MigrationGenerateCommand.ts index 5fb779b7cc9..a17005ca2d1 100644 --- a/src/commands/MigrationGenerateCommand.ts +++ b/src/commands/MigrationGenerateCommand.ts @@ -92,7 +92,7 @@ export class MigrationGenerateCommand implements yargs.CommandModule { downQuery.query = MigrationGenerateCommand.prettifyQuery(downQuery.query); }); } - + const upSqls: string[] = [], downSqls: string[] = []; // mysql is exceptional here because it uses ` character in to escape names in queries, that's why for mysql @@ -178,7 +178,7 @@ ${downSqls.join(` } /** - * + * */ protected static prettifyQuery(query: string) { const formattedQuery = format(query, { indent: " " }); diff --git a/src/decorator/EntityRepository.ts b/src/decorator/EntityRepository.ts index b97d58ce150..3a25adcdd0d 100644 --- a/src/decorator/EntityRepository.ts +++ b/src/decorator/EntityRepository.ts @@ -1,6 +1,6 @@ -import { getMetadataArgsStorage } from "../"; -import { EntityRepositoryMetadataArgs } from "../metadata-args/EntityRepositoryMetadataArgs"; -import { EntitySchema } from "../entity-schema/EntitySchema"; +import {getMetadataArgsStorage} from "../"; +import {EntityRepositoryMetadataArgs} from "../metadata-args/EntityRepositoryMetadataArgs"; +import {EntitySchema} from "../entity-schema/EntitySchema"; /** * Used to declare a class as a custom repository. diff --git a/src/decorator/columns/Column.ts b/src/decorator/columns/Column.ts index 84e937a6dfd..ac5467980cd 100644 --- a/src/decorator/columns/Column.ts +++ b/src/decorator/columns/Column.ts @@ -1,7 +1,11 @@ import {ColumnOptions, getMetadataArgsStorage} from "../../"; import { - ColumnType, SimpleColumnType, SpatialColumnType, WithLengthColumnType, - WithPrecisionColumnType, WithWidthColumnType + ColumnType, + SimpleColumnType, + SpatialColumnType, + WithLengthColumnType, + WithPrecisionColumnType, + WithWidthColumnType } from "../../driver/types/ColumnTypes"; import {ColumnMetadataArgs} from "../../metadata-args/ColumnMetadataArgs"; import {ColumnCommonOptions} from "../options/ColumnCommonOptions"; @@ -14,7 +18,7 @@ import {EmbeddedMetadataArgs} from "../../metadata-args/EmbeddedMetadataArgs"; import {ColumnTypeUndefinedError} from "../../error/ColumnTypeUndefinedError"; import {ColumnHstoreOptions} from "../options/ColumnHstoreOptions"; import {ColumnWithWidthOptions} from "../options/ColumnWithWidthOptions"; -import { GeneratedMetadataArgs } from "../../metadata-args/GeneratedMetadataArgs"; +import {GeneratedMetadataArgs} from "../../metadata-args/GeneratedMetadataArgs"; /** * Column decorator is used to mark a specific class property as a table column. Only properties decorated with this diff --git a/src/decorator/columns/PrimaryColumn.ts b/src/decorator/columns/PrimaryColumn.ts index 4ac950cc832..e84b8d12bac 100644 --- a/src/decorator/columns/PrimaryColumn.ts +++ b/src/decorator/columns/PrimaryColumn.ts @@ -2,7 +2,7 @@ import {ColumnOptions, ColumnType, getMetadataArgsStorage} from "../../"; import {ColumnTypeUndefinedError} from "../../error/ColumnTypeUndefinedError"; import {PrimaryColumnCannotBeNullableError} from "../../error/PrimaryColumnCannotBeNullableError"; import {ColumnMetadataArgs} from "../../metadata-args/ColumnMetadataArgs"; -import { GeneratedMetadataArgs } from "../../metadata-args/GeneratedMetadataArgs"; +import {GeneratedMetadataArgs} from "../../metadata-args/GeneratedMetadataArgs"; /** * Column decorator is used to mark a specific class property as a table column. diff --git a/src/decorator/options/ColumnOptions.ts b/src/decorator/options/ColumnOptions.ts index 52a1afe75e7..931042c6ed5 100644 --- a/src/decorator/options/ColumnOptions.ts +++ b/src/decorator/options/ColumnOptions.ts @@ -1,6 +1,6 @@ import {ColumnType} from "../../driver/types/ColumnTypes"; import {ValueTransformer} from "./ValueTransformer"; -import { ColumnCommonOptions } from "./ColumnCommonOptions"; +import {ColumnCommonOptions} from "./ColumnCommonOptions"; /** * Describes all column's options. diff --git a/src/decorator/options/TransactionOptions.ts b/src/decorator/options/TransactionOptions.ts index 1570f4a2460..564c6d6ba26 100644 --- a/src/decorator/options/TransactionOptions.ts +++ b/src/decorator/options/TransactionOptions.ts @@ -1,6 +1,6 @@ -import { IsolationLevel } from "../../driver/types/IsolationLevel"; +import {IsolationLevel} from "../../driver/types/IsolationLevel"; export interface TransactionOptions { connectionName?: string; isolation?: IsolationLevel; -} \ No newline at end of file +} diff --git a/src/driver/DriverUtils.ts b/src/driver/DriverUtils.ts index c022e3c8453..56d7309d9f9 100644 --- a/src/driver/DriverUtils.ts +++ b/src/driver/DriverUtils.ts @@ -1,7 +1,7 @@ -import { Driver } from "./Driver"; +import {Driver} from "./Driver"; import { hash } from "../util/StringUtils"; - /** +/** * Common driver utility functions. */ export class DriverUtils { diff --git a/src/driver/cockroachdb/CockroachConnectionCredentialsOptions.ts b/src/driver/cockroachdb/CockroachConnectionCredentialsOptions.ts index ba8fd9b968a..06a30cf66aa 100644 --- a/src/driver/cockroachdb/CockroachConnectionCredentialsOptions.ts +++ b/src/driver/cockroachdb/CockroachConnectionCredentialsOptions.ts @@ -1,4 +1,4 @@ -import { TlsOptions } from "tls"; +import {TlsOptions} from "tls"; /** * Cockroachdb specific connection credential options. diff --git a/src/driver/mongodb/MongoQueryRunner.ts b/src/driver/mongodb/MongoQueryRunner.ts index 5bdf54171ef..f12ed32bf01 100644 --- a/src/driver/mongodb/MongoQueryRunner.ts +++ b/src/driver/mongodb/MongoQueryRunner.ts @@ -1,9 +1,9 @@ -import { QueryRunner } from "../../query-runner/QueryRunner"; -import { ObjectLiteral } from "../../common/ObjectLiteral"; -import { TableColumn } from "../../schema-builder/table/TableColumn"; -import { Table } from "../../schema-builder/table/Table"; -import { TableForeignKey } from "../../schema-builder/table/TableForeignKey"; -import { TableIndex } from "../../schema-builder/table/TableIndex"; +import {QueryRunner} from "../../query-runner/QueryRunner"; +import {ObjectLiteral} from "../../common/ObjectLiteral"; +import {TableColumn} from "../../schema-builder/table/TableColumn"; +import {Table} from "../../schema-builder/table/Table"; +import {TableForeignKey} from "../../schema-builder/table/TableForeignKey"; +import {TableIndex} from "../../schema-builder/table/TableIndex"; import {View} from "../../schema-builder/view/View"; import { AggregationCursor, @@ -38,14 +38,14 @@ import { UnorderedBulkOperation, UpdateWriteOpResult } from "./typings"; -import { Connection } from "../../connection/Connection"; -import { ReadStream } from "../../platform/PlatformTools"; -import { MongoEntityManager } from "../../entity-manager/MongoEntityManager"; -import { SqlInMemory } from "../SqlInMemory"; -import { TableUnique } from "../../schema-builder/table/TableUnique"; -import { Broadcaster } from "../../subscriber/Broadcaster"; -import { TableCheck } from "../../schema-builder/table/TableCheck"; -import { TableExclusion } from "../../schema-builder/table/TableExclusion"; +import {Connection} from "../../connection/Connection"; +import {ReadStream} from "../../platform/PlatformTools"; +import {MongoEntityManager} from "../../entity-manager/MongoEntityManager"; +import {SqlInMemory} from "../SqlInMemory"; +import {TableUnique} from "../../schema-builder/table/TableUnique"; +import {Broadcaster} from "../../subscriber/Broadcaster"; +import {TableCheck} from "../../schema-builder/table/TableCheck"; +import {TableExclusion} from "../../schema-builder/table/TableExclusion"; /** * Runs queries on a single MongoDB connection. diff --git a/src/driver/mongodb/typings.ts b/src/driver/mongodb/typings.ts index 9ec1f61d6f4..f0605311353 100644 --- a/src/driver/mongodb/typings.ts +++ b/src/driver/mongodb/typings.ts @@ -1,4 +1,4 @@ -import { EventEmitter, Readable, Writable } from "../../platform/PlatformTools"; +import {EventEmitter, Readable, Writable} from "../../platform/PlatformTools"; /** * Creates a new MongoClient instance. @@ -5014,7 +5014,7 @@ export declare class Cursor extends Readable { * @see http://mongodb.github.io/node-mongodb-native/3.1/api/Cursor.html#forEach */ forEach(iterator: IteratorCallback, callback: EndCallback): void; - forEach(iterator: IteratorCallback): Promise; + forEach(iterator: IteratorCallback): Promise; /** * Check if there is any document still available in the cursor. diff --git a/src/driver/mysql/MysqlQueryRunner.ts b/src/driver/mysql/MysqlQueryRunner.ts index 4eff8332fac..f595487f919 100644 --- a/src/driver/mysql/MysqlQueryRunner.ts +++ b/src/driver/mysql/MysqlQueryRunner.ts @@ -21,7 +21,7 @@ import {ColumnType, PromiseUtils} from "../../index"; import {TableCheck} from "../../schema-builder/table/TableCheck"; import {IsolationLevel} from "../types/IsolationLevel"; import {TableExclusion} from "../../schema-builder/table/TableExclusion"; -import { VersionUtils } from "../../util/VersionUtils"; +import {VersionUtils} from "../../util/VersionUtils"; /** * Runs queries on a single mysql database connection. diff --git a/src/driver/oracle/OracleDriver.ts b/src/driver/oracle/OracleDriver.ts index 42575f61080..03bbef3cbce 100644 --- a/src/driver/oracle/OracleDriver.ts +++ b/src/driver/oracle/OracleDriver.ts @@ -392,7 +392,7 @@ export class OracleDriver implements Driver { return columnMetadata.transformer ? ApplyValueTransformers.transformFrom(columnMetadata.transformer, value) : value; if (columnMetadata.type === Boolean) { - value = value ? true : false; + value = !!value; } else if (columnMetadata.type === "date") { value = DateUtils.mixedDateToDateString(value); diff --git a/src/driver/postgres/PostgresConnectionCredentialsOptions.ts b/src/driver/postgres/PostgresConnectionCredentialsOptions.ts index 98f56027ce0..3601670bce3 100644 --- a/src/driver/postgres/PostgresConnectionCredentialsOptions.ts +++ b/src/driver/postgres/PostgresConnectionCredentialsOptions.ts @@ -1,4 +1,4 @@ -import { TlsOptions } from "tls"; +import {TlsOptions} from "tls"; /** * Postgres specific connection credential options. diff --git a/src/entity-schema/EntitySchemaColumnOptions.ts b/src/entity-schema/EntitySchemaColumnOptions.ts index 80e75363fa3..9d4a50b055b 100644 --- a/src/entity-schema/EntitySchemaColumnOptions.ts +++ b/src/entity-schema/EntitySchemaColumnOptions.ts @@ -1,6 +1,6 @@ import {ColumnType} from "../driver/types/ColumnTypes"; import {ValueTransformer} from "../decorator/options/ValueTransformer"; -import { SpatialColumnOptions } from "../decorator/options/SpatialColumnOptions"; +import {SpatialColumnOptions} from "../decorator/options/SpatialColumnOptions"; export interface EntitySchemaColumnOptions extends SpatialColumnOptions { diff --git a/src/error/QueryFailedError.ts b/src/error/QueryFailedError.ts index 9e2a63d3e61..26446280a1c 100644 --- a/src/error/QueryFailedError.ts +++ b/src/error/QueryFailedError.ts @@ -1,4 +1,4 @@ -import { ObjectUtils } from "../util/ObjectUtils"; +import {ObjectUtils} from "../util/ObjectUtils"; /** * Thrown when query execution has failed. @@ -20,4 +20,4 @@ export class QueryFailedError extends Error { }); } -} \ No newline at end of file +} diff --git a/src/metadata-args/RelationCountMetadataArgs.ts b/src/metadata-args/RelationCountMetadataArgs.ts index 31f003adc10..14c1e8cf08d 100644 --- a/src/metadata-args/RelationCountMetadataArgs.ts +++ b/src/metadata-args/RelationCountMetadataArgs.ts @@ -1,4 +1,5 @@ import {SelectQueryBuilder} from "../query-builder/SelectQueryBuilder"; + /** * Arguments for RelationCountMetadata class. */ diff --git a/src/metadata-args/RelationIdMetadataArgs.ts b/src/metadata-args/RelationIdMetadataArgs.ts index 8abec551876..5b5f627b642 100644 --- a/src/metadata-args/RelationIdMetadataArgs.ts +++ b/src/metadata-args/RelationIdMetadataArgs.ts @@ -1,4 +1,5 @@ import {SelectQueryBuilder} from "../query-builder/SelectQueryBuilder"; + /** * Arguments for RelationIdMetadataArgs class. */ diff --git a/src/migration/MigrationExecutor.ts b/src/migration/MigrationExecutor.ts index efec992f614..c7c90640241 100644 --- a/src/migration/MigrationExecutor.ts +++ b/src/migration/MigrationExecutor.ts @@ -8,8 +8,8 @@ import {SqlServerDriver} from "../driver/sqlserver/SqlServerDriver"; import {MssqlParameter} from "../driver/sqlserver/MssqlParameter"; import {SqlServerConnectionOptions} from "../driver/sqlserver/SqlServerConnectionOptions"; import {PostgresConnectionOptions} from "../driver/postgres/PostgresConnectionOptions"; -import { MongoDriver } from "../driver/mongodb/MongoDriver"; -import { MongoQueryRunner } from "../driver/mongodb/MongoQueryRunner"; +import {MongoDriver} from "../driver/mongodb/MongoDriver"; +import {MongoQueryRunner} from "../driver/mongodb/MongoQueryRunner"; /** * Executes migrations: runs pending and reverts previously executed migrations. diff --git a/src/platform/PlatformTools.ts b/src/platform/PlatformTools.ts index 1adb9042993..a43accfe6ce 100644 --- a/src/platform/PlatformTools.ts +++ b/src/platform/PlatformTools.ts @@ -2,6 +2,7 @@ import * as path from "path"; import * as fs from "fs"; import chalk from "chalk"; import {highlight, Theme} from "cli-highlight"; + export {ReadStream} from "fs"; export {EventEmitter} from "events"; export {Readable, Writable} from "stream"; diff --git a/src/query-builder/Alias.ts b/src/query-builder/Alias.ts index 0ad0c8b414e..5ba81a0eeb5 100644 --- a/src/query-builder/Alias.ts +++ b/src/query-builder/Alias.ts @@ -1,5 +1,5 @@ import {EntityMetadata} from "../metadata/EntityMetadata"; -import { ObjectUtils } from "../util/ObjectUtils"; +import {ObjectUtils} from "../util/ObjectUtils"; /** */ @@ -45,4 +45,4 @@ export class Alias { return this._metadata; } -} \ No newline at end of file +} diff --git a/src/query-builder/transformer/RawSqlResultsToEntityTransformer.ts b/src/query-builder/transformer/RawSqlResultsToEntityTransformer.ts index 89118a4adbd..cc75cdfca5e 100644 --- a/src/query-builder/transformer/RawSqlResultsToEntityTransformer.ts +++ b/src/query-builder/transformer/RawSqlResultsToEntityTransformer.ts @@ -255,7 +255,6 @@ export class RawSqlResultsToEntityTransformer { return idMap; }).filter(result => result); - const properties = rawRelationIdResult.relationIdAttribute.mapToPropertyPropertyPath.split("."); const mapToProperty = (properties: string[], map: ObjectLiteral, value: any): any => { diff --git a/src/repository/MongoRepository.ts b/src/repository/MongoRepository.ts index c43b6e859c8..2d9ccf754fa 100644 --- a/src/repository/MongoRepository.ts +++ b/src/repository/MongoRepository.ts @@ -24,7 +24,8 @@ import { InsertWriteOpResult, MapReduceOptions, MongoCountPreferences, - MongodbIndexOptions, ObjectID, + MongodbIndexOptions, + ObjectID, OrderedBulkOperation, ParallelCollectionScanOptions, ReadPreference, @@ -357,4 +358,4 @@ export class MongoRepository extends Repository Category) category: Category; @@ -27,4 +27,4 @@ export class Post { @RelationCount((post: Post) => post.category2) categoryCount2: number; -} \ No newline at end of file +} diff --git a/test/functional/query-builder/join/query-builder-joins.ts b/test/functional/query-builder/join/query-builder-joins.ts index 78bd1f1544a..ccc6638e8a1 100644 --- a/test/functional/query-builder/join/query-builder-joins.ts +++ b/test/functional/query-builder/join/query-builder-joins.ts @@ -10,7 +10,7 @@ import {Image} from "./entity/Image"; import {User} from "./entity/User"; describe("query builder > joins", () => { - + let connections: Connection[]; before(async () => connections = await createTestingConnections({ entities: [__dirname + "/entity/*{.js,.ts}"], diff --git a/test/functional/repository/basic-methods/repository-basic-methods.ts b/test/functional/repository/basic-methods/repository-basic-methods.ts index 7b5ba000245..44adfc6d54f 100644 --- a/test/functional/repository/basic-methods/repository-basic-methods.ts +++ b/test/functional/repository/basic-methods/repository-basic-methods.ts @@ -43,7 +43,7 @@ describe("repository > basic methods", () => { })); }); - + describe("hasId", function() { it("should return true if entity has an id", () => connections.forEach(connection => { @@ -222,7 +222,7 @@ describe("repository > basic methods", () => { blog.text = "Blog about good people"; blog.categories = [category]; await blogRepository.save(blog); - + // and preload it const plainBlogWithId = { id: 1 }; const preloadedBlog = await blogRepository.preload(plainBlogWithId); @@ -247,7 +247,7 @@ describe("repository > basic methods", () => { blog.text = "Blog about good people"; blog.categories = [category]; await blogRepository.save(blog); - + // and preload it const plainBlogWithId = { id: 1, categories: [{ id: 1 }] }; const preloadedBlog = await blogRepository.preload(plainBlogWithId); @@ -348,7 +348,7 @@ describe("repository > basic methods", () => { const saved = await postRepository.save(dbPost); saved.should.be.instanceOf(Post); - + saved.id!.should.be.equal(1); saved.title.should.be.equal("New title"); saved.dateAdded.should.be.instanceof(Date); diff --git a/test/github-issues/1545/entity/DataModel.ts b/test/github-issues/1545/entity/DataModel.ts index 204edd37456..67744624ebb 100644 --- a/test/github-issues/1545/entity/DataModel.ts +++ b/test/github-issues/1545/entity/DataModel.ts @@ -1,6 +1,6 @@ -import { Entity, ManyToOne, JoinColumn, Column } from "../../../../src/index"; -import { MainModel } from "./MainModel"; -import { ValidationModel } from "./ValidationModel"; +import {Column, Entity, JoinColumn, ManyToOne} from "../../../../src/index"; +import {MainModel} from "./MainModel"; +import {ValidationModel} from "./ValidationModel"; @Entity() export class DataModel { @@ -27,4 +27,4 @@ export class DataModel { default: false }) active: boolean; -} \ No newline at end of file +} diff --git a/test/github-issues/1972/issue-1972.ts b/test/github-issues/1972/issue-1972.ts index df65ea747f1..01391658c5a 100644 --- a/test/github-issues/1972/issue-1972.ts +++ b/test/github-issues/1972/issue-1972.ts @@ -32,7 +32,6 @@ describe("github issues > #1972 STI problem - empty columns", () => { // find user participant in the DB const result = await connection.manager.findOne(TournamentUserParticipant); - if (result) { assert(result.user instanceof User); } diff --git a/test/github-issues/2044/issue-2044.ts b/test/github-issues/2044/issue-2044.ts index 5960a5a2aab..f6aa3ce3b5a 100644 --- a/test/github-issues/2044/issue-2044.ts +++ b/test/github-issues/2044/issue-2044.ts @@ -31,7 +31,6 @@ describe("github issues > #2044 Should not double get embedded column value", () const photos = await connection.manager.find(Photo, { relations: ["user"] }); - // console.log(photos); const resultPhoto = photos[0]; @@ -39,4 +38,4 @@ describe("github issues > #2044 Should not double get embedded column value", () resultPhoto.user.id.should.be.eql(userId); }))); -}); \ No newline at end of file +}); diff --git a/test/github-issues/2965/index.ts b/test/github-issues/2965/index.ts index 4ee0ecfd4b1..670ff3a462b 100644 --- a/test/github-issues/2965/index.ts +++ b/test/github-issues/2965/index.ts @@ -1,8 +1,6 @@ import "reflect-metadata"; - import {closeTestingConnections, createTestingConnections, reloadTestingDatabases} from "../../utils/test-utils"; import {Connection} from "../../../src"; - import {Person} from "./entity/person"; import {Note} from "./entity/note"; @@ -21,8 +19,8 @@ describe("github issues > #2965 Reuse preloaded lazy relations", () => { const repoPerson = connection.getRepository(Person); const repoNote = connection.getRepository(Note); - const personA = await repoPerson.create({ name: "personA" }); - const personB = await repoPerson.create({ name: "personB" }); + const personA = await repoPerson.create({ name: "personA" }); + const personB = await repoPerson.create({ name: "personB" }); await repoPerson.save([ personA, @@ -32,7 +30,6 @@ describe("github issues > #2965 Reuse preloaded lazy relations", () => { await repoNote.insert({ label: "note1", owner: personA }); await repoNote.insert({ label: "note2", owner: personB }); - const originalLoad: (...args: any[]) => Promise = connection.relationLoader.load; let loadCalledCounter = 0; connection.relationLoader.load = (...args: any[]): Promise => { diff --git a/tsconfig.json b/tsconfig.json index 4dafdb0c76d..49cf3e690eb 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -4,7 +4,7 @@ "lib": ["es5", "es6"], "outDir": "build/compiled", "allowSyntheticDefaultImports": true, - "esModuleInterop": true, + "esModuleInterop": true, "target": "es5", "module": "commonjs", "moduleResolution": "node", From 96eddfba85be4b0934a568558d7bea5b96f44e8c Mon Sep 17 00:00:00 2001 From: James Ward Date: Thu, 17 Sep 2020 07:09:55 -0400 Subject: [PATCH 075/212] chore: explicitly pull in typescript 3.9 (#6724) this bumps the version of typescript accepted to >=3.9.7,<4.0 we were implicitly pulling in that version (per the package-lock.json) so this just codifies it in the package.json as well --- package-lock.json | 3 +-- package.json | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index edd53ab49d7..f16c8bf78f7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -254,8 +254,7 @@ "@sqltools/formatter": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/@sqltools/formatter/-/formatter-1.2.2.tgz", - "integrity": "sha512-/5O7Fq6Vnv8L6ucmPjaWbVG1XkP4FO+w5glqfkIsq3Xw4oyNAdJddbnYodNDAfjVUvo/rrSCTom4kAND7T1o5Q==", - "dev": true + "integrity": "sha512-/5O7Fq6Vnv8L6ucmPjaWbVG1XkP4FO+w5glqfkIsq3Xw4oyNAdJddbnYodNDAfjVUvo/rrSCTom4kAND7T1o5Q==" }, "@types/app-root-path": { "version": "1.2.4", diff --git a/package.json b/package.json index 6e22c75a480..0c9d3d620dc 100644 --- a/package.json +++ b/package.json @@ -101,7 +101,7 @@ "sqlite3": "^5.0.0", "ts-node": "^9.0.0", "typeorm-aurora-data-api-driver": "^1.4.0", - "typescript": "^3.3.3333" + "typescript": "^3.9.7" }, "dependencies": { "@sqltools/formatter": "1.2.2", From 8820d4a871fb1071228520f8f3f27d2877b90fe3 Mon Sep 17 00:00:00 2001 From: James Ward Date: Thu, 17 Sep 2020 07:11:31 -0400 Subject: [PATCH 076/212] test: disable logging for test 1960 (#6721) this test was emitting logs for no real reason so this removes the `logging: true` when creating the testing connection --- test/github-issues/1960/issue-1960.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/github-issues/1960/issue-1960.ts b/test/github-issues/1960/issue-1960.ts index 145a6b8981b..bf9c10c6400 100644 --- a/test/github-issues/1960/issue-1960.ts +++ b/test/github-issues/1960/issue-1960.ts @@ -8,8 +8,7 @@ describe.skip("github issues > #1960 Migration generator produces duplicated cha let connections: Connection[]; before(async () => connections = await createTestingConnections({ entities: [__dirname + "/entity/*{.js,.ts}"], - enabledDrivers: ["mysql"], - logging: true + enabledDrivers: ["mysql"] })); beforeEach(() => reloadTestingDatabases(connections)); after(() => closeTestingConnections(connections)); From 6e28322ca65ba739bf0d767075016bc0cae7a48c Mon Sep 17 00:00:00 2001 From: jesussegado Date: Thu, 17 Sep 2020 13:12:51 +0200 Subject: [PATCH 077/212] fix: migration:generate issue with onUpdate using mariadb 10.4 (#6714) * Update MysqlQueryRunner.ts In Mariadb the extra information of a DDL is in upper case and in javascript String.indexOf() function is case sensitive, because of that when you generate a new migrations in mariadb it always create a line to update "onUpdate" lines. example: ```sql CREATE TABLE `test` ( `test_id` int(11) NOT NULL AUTO_INCREMENT, `test_update` timestamp() NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(), PRIMARY KEY (`test_id`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 ``` When you try to generate a new migration always create the next migration file: ```ts import { MigrationInterface, QueryRunner } from 'typeorm'; export class test261600082802966 implements MigrationInterface { name = 'test261600082802966'; public async up(queryRunner: QueryRunner): Promise { await queryRunner.query( 'ALTER TABLE `test` CHANGE `test_update` `test_update` timestamp() NOT NULL DEFAULT CURRENT_TIMESTAMP() ON UPDATE CURRENT_TIMESTAMP()' ); } public async down(queryRunner: QueryRunner): Promise { await queryRunner.query( 'ALTER TABLE `test` CHANGE `test_update` `test_update` timestamp() NOT NULL DEFAULT CURRENT_TIMESTAMP() ON UPDATE current_timestamp()' ); } } ``` Entity file test.ts ```ts import { BaseEntity, Column, Entity, PrimaryGeneratedColumn } from 'typeorm'; @Entity() export class test extends BaseEntity { @PrimaryGeneratedColumn({}) test_id: number; @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP()', onUpdate: 'CURRENT_TIMESTAMP()', nullable: false, }) test_update: Date; } ``` * Update MysqlQueryRunner.ts * add test to issue 6714 * Update MysqlQueryRunner.ts * Update issue-6714.ts Co-authored-by: jesusegado --- src/driver/mysql/MysqlQueryRunner.ts | 4 +- test/github-issues/6714/entity/session.ts | 17 ++++++ .../6714/entity/sessionchanged.ts | 15 +++++ test/github-issues/6714/issue-6714.ts | 59 +++++++++++++++++++ 4 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 test/github-issues/6714/entity/session.ts create mode 100644 test/github-issues/6714/entity/sessionchanged.ts create mode 100644 test/github-issues/6714/issue-6714.ts diff --git a/src/driver/mysql/MysqlQueryRunner.ts b/src/driver/mysql/MysqlQueryRunner.ts index f595487f919..5a7cdb1875c 100644 --- a/src/driver/mysql/MysqlQueryRunner.ts +++ b/src/driver/mysql/MysqlQueryRunner.ts @@ -1321,7 +1321,9 @@ export class MysqlQueryRunner extends BaseQueryRunner implements QueryRunner { } if (dbColumn["EXTRA"].indexOf("on update") !== -1) { - tableColumn.onUpdate = dbColumn["EXTRA"].substring(dbColumn["EXTRA"].indexOf("on update") + 10); + // New versions of MariaDB return expressions in lowercase. We need to set it in + // uppercase so the comparison in MysqlDriver#compareExtraValues does not fail. + tableColumn.onUpdate = dbColumn["EXTRA"].substring(dbColumn["EXTRA"].indexOf("on update") + 10).toUpperCase(); } if (dbColumn["GENERATION_EXPRESSION"]) { diff --git a/test/github-issues/6714/entity/session.ts b/test/github-issues/6714/entity/session.ts new file mode 100644 index 00000000000..9ea05da3ac1 --- /dev/null +++ b/test/github-issues/6714/entity/session.ts @@ -0,0 +1,17 @@ +import { Entity, PrimaryGeneratedColumn, Column } from "../../../../src"; + +@Entity({ name: "Session" }) +export class Session { + + @PrimaryGeneratedColumn() + id?: number; + + @Column({ + type: "timestamp", + precision: 3, + default: () => "CURRENT_TIMESTAMP(3)", + onUpdate: "CURRENT_TIMESTAMP(3)", + }) + ts: Date; + +} diff --git a/test/github-issues/6714/entity/sessionchanged.ts b/test/github-issues/6714/entity/sessionchanged.ts new file mode 100644 index 00000000000..c689295e841 --- /dev/null +++ b/test/github-issues/6714/entity/sessionchanged.ts @@ -0,0 +1,15 @@ +import { Entity, PrimaryGeneratedColumn, Column } from "../../../../src"; + +@Entity({ name: "Session" }) +export class Session { + @PrimaryGeneratedColumn() + id?: number; + + @Column({ + type: "timestamp", + precision: 4, + default: () => "CURRENT_TIMESTAMP(4)", + onUpdate: "CURRENT_TIMESTAMP(4)", + }) + ts: Date; +} diff --git a/test/github-issues/6714/issue-6714.ts b/test/github-issues/6714/issue-6714.ts new file mode 100644 index 00000000000..e51fd4a7187 --- /dev/null +++ b/test/github-issues/6714/issue-6714.ts @@ -0,0 +1,59 @@ +import "reflect-metadata"; +import { + createTestingConnections, + closeTestingConnections, + reloadTestingDatabases, +} from "../../utils/test-utils"; +import { Connection } from "../../../src/connection/Connection"; +import { expect } from "chai"; +import { Session as baseEntity } from "./entity/session"; +import { Session as changedEntity } from "./entity/sessionchanged"; + +describe("github issues > #6714 Migration:generate issue with onUpdate using mariadb 10.4", () => { + it("dont change anything", async () => { + let connections: Connection[]; + connections = await createTestingConnections({ + entities: [baseEntity], + schemaCreate: false, + dropSchema: true, + enabledDrivers: ["mariadb"], + }); + await reloadTestingDatabases(connections); + await Promise.all( + connections.map(async (connection) => { + const schemaBuilder = connection.driver.createSchemaBuilder(); + const syncQueries = await schemaBuilder.log(); + expect(syncQueries.downQueries).to.be.eql([]); + expect(syncQueries.upQueries).to.be.eql([]); + }) + ); + await closeTestingConnections(connections); + }); + it("recognizing on update changes", async () => { + // this connection create database with a Session entity + const baseConnections = await createTestingConnections({ + entities: [baseEntity], + schemaCreate: true, // create the database + dropSchema: true, + enabledDrivers: ["mariadb"], + }); + // this connection change Session entity on update value + const connections = await createTestingConnections({ + entities: [changedEntity], + schemaCreate: false, // don't change the entity + dropSchema: false, + enabledDrivers: ["mariadb"], + name: "test", + }); + await Promise.all( + connections.map(async (connection) => { + const schemaBuilder = connection.driver.createSchemaBuilder(); + const syncQueries = await schemaBuilder.log(); + expect(syncQueries.downQueries.length).not.to.be.eql(0); + expect(syncQueries.upQueries.length).not.to.be.eql(0); + }) + ); + await closeTestingConnections(baseConnections); + await closeTestingConnections(connections); + }); +}); From 4bc7431043bda81b4725634d78088f1044fb921a Mon Sep 17 00:00:00 2001 From: Louai Hamada <47286486+Louai-H@users.noreply.github.com> Date: Thu, 17 Sep 2020 14:16:16 +0300 Subject: [PATCH 078/212] docs: update many-to-many-relations.md (#6725) * Update many-to-many-relations.md * Update many-to-many-relations.md Co-authored-by: Umed Khudoiberdiev --- docs/many-to-many-relations.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/many-to-many-relations.md b/docs/many-to-many-relations.md index 8a53a21e8db..10a53f3e95f 100644 --- a/docs/many-to-many-relations.md +++ b/docs/many-to-many-relations.md @@ -174,7 +174,7 @@ const questions = await connection .getMany(); ``` -With eager loading enabled on a relation you don't have to specify relation or join it - it will ALWAYS be loaded automatically. +When using `FindOptions` you don't need to specify eager relations - they are always automatically loaded. ## bi-directional relations From 5084e47be4fd42316ad47e6102645534fae45d9f Mon Sep 17 00:00:00 2001 From: Arty <26905074+artysidorenko@users.noreply.github.com> Date: Thu, 17 Sep 2020 12:40:28 +0100 Subject: [PATCH 079/212] feat: add option to pass postgres server notices to client logger (#6215) This feature for postgres connections means when you pass the logNotifications option, db notices and notifications will be passed to the logger with info log level Closes: #2216 --- docs/connection-options.md | 2 + .../postgres/PostgresConnectionOptions.ts | 5 + src/driver/postgres/PostgresDriver.ts | 9 ++ test/github-issues/2216/entity/Foo.ts | 16 +++ test/github-issues/2216/issue-2216.ts | 130 ++++++++++++++++++ 5 files changed, 162 insertions(+) create mode 100644 test/github-issues/2216/entity/Foo.ts create mode 100644 test/github-issues/2216/issue-2216.ts diff --git a/docs/connection-options.md b/docs/connection-options.md index d52a64bc810..219e1410504 100644 --- a/docs/connection-options.md +++ b/docs/connection-options.md @@ -182,6 +182,8 @@ See [SSL options](https://github.com/mysqljs/mysql#ssl-options). * `poolErrorHandler` - A function that get's called when underlying pool emits `'error'` event. Takes single parameter (error instance) and defaults to logging with `warn` level. +* `logNotifications` - A boolean to determine whether postgres server [notice messages](https://www.postgresql.org/docs/current/plpgsql-errors-and-messages.html) and [notification events](https://www.postgresql.org/docs/current/sql-notify.html) should be included in client's logs with `info` level (default: `false`). + ## `sqlite` connection options * `database` - Database path. For example "./mydb.sql" diff --git a/src/driver/postgres/PostgresConnectionOptions.ts b/src/driver/postgres/PostgresConnectionOptions.ts index 18e65183b9b..908360df6d1 100644 --- a/src/driver/postgres/PostgresConnectionOptions.ts +++ b/src/driver/postgres/PostgresConnectionOptions.ts @@ -52,4 +52,9 @@ export interface PostgresConnectionOptions extends BaseConnectionOptions, Postgr * Defaults to logging error with `warn` level. */ readonly poolErrorHandler?: (err: any) => any; + + /** + * Include notification messages from Postgres server in client logs + */ + readonly logNotifications?: boolean; } diff --git a/src/driver/postgres/PostgresDriver.ts b/src/driver/postgres/PostgresDriver.ts index 59684c74bfd..f5a8d8cdd6d 100644 --- a/src/driver/postgres/PostgresDriver.ts +++ b/src/driver/postgres/PostgresDriver.ts @@ -1001,6 +1001,15 @@ export class PostgresDriver implements Driver { return new Promise((ok, fail) => { pool.connect((err: any, connection: any, release: Function) => { if (err) return fail(err); + + if (options.logNotifications) { + connection.on("notice", (msg: any) => { + msg && this.connection.logger.log("info", msg.message); + }); + connection.on("notification", (msg: any) => { + msg && this.connection.logger.log("info", `Received NOTIFY on channel ${msg.channel}: ${msg.payload}.`); + }); + } release(); ok(pool); }); diff --git a/test/github-issues/2216/entity/Foo.ts b/test/github-issues/2216/entity/Foo.ts new file mode 100644 index 00000000000..d7e2038db88 --- /dev/null +++ b/test/github-issues/2216/entity/Foo.ts @@ -0,0 +1,16 @@ +import { + Column, + Entity, + PrimaryGeneratedColumn, +} from "../../../../src"; + +@Entity("foo") +export class Foo { + @PrimaryGeneratedColumn("uuid") public uuid: string; + + @Column({ type: "citext", nullable: false }) + public lowercaseval: string; + + @Column({ type: "citext", nullable: false }) + public lowercaseval2: string; +} diff --git a/test/github-issues/2216/issue-2216.ts b/test/github-issues/2216/issue-2216.ts new file mode 100644 index 00000000000..3cb4287d9fb --- /dev/null +++ b/test/github-issues/2216/issue-2216.ts @@ -0,0 +1,130 @@ +import sinon from "sinon"; +import {Connection} from "../../../src/connection/Connection"; +import {createTestingConnections, closeTestingConnections, reloadTestingDatabases } from "../../utils/test-utils"; +import { EntityManager, QueryRunner, SimpleConsoleLogger } from "../../../src"; +import { Foo } from "./entity/Foo"; +import { expect } from "chai"; + +describe("github issues > #2216 - Ability to capture Postgres notifications in logger", () => { + let connections: Connection[]; + let queryRunner: QueryRunner; + let manager: EntityManager; + let logInfoStub: sinon.SinonStub; + + before(() => { + logInfoStub = sinon.stub(SimpleConsoleLogger.prototype, "log"); + }); + beforeEach(async () => { + await reloadTestingDatabases(connections); + }); + afterEach(() => logInfoStub.resetHistory()); + after(() => logInfoStub.restore()); + + describe("when logNotifications option is NOT enabled", () => { + before(async () => { + connections = await createTestingConnections({ + enabledDrivers: ["postgres"], + entities: [Foo], + logging: true, + createLogger: () => new SimpleConsoleLogger(), + }); + }); + after(() => closeTestingConnections(connections)); + + it("should NOT pass extension setup notices to client", async () => Promise.all(connections.map(async connection => { + sinon.assert.neverCalledWith( + logInfoStub, + "info", + `extension "uuid-ossp" already exists, skipping` + ); + sinon.assert.neverCalledWith( + logInfoStub, + "info", + `extension "citext" already exists, skipping` + ); + }))); + + it("should NOT pass manual notices to client", async () => Promise.all(connections.map(async connection => { + queryRunner = connection.createQueryRunner(); + await queryRunner.query(`DO $do$ BEGIN RAISE NOTICE 'this is a notice'; END $do$`); + sinon.assert.neverCalledWith( + logInfoStub, + "info", + "this is a notice" + ); + await queryRunner.release(); + }))); + + it("should NOT pass 'listen -> notify' messages to client", async () => Promise.all(connections.map(async connection => { + queryRunner = connection.createQueryRunner(); + await queryRunner.query("LISTEN foo;"); + await queryRunner.query("NOTIFY foo, 'bar!'"); + sinon.assert.neverCalledWith( + logInfoStub, + "info", + "Received NOTIFY on channel foo: bar!." + ); + await queryRunner.release(); + }))); + }); + + describe("when logNotifications option is enabled", () => { + before(async () => { + connections = await createTestingConnections({ + enabledDrivers: ["postgres"], + entities: [Foo], + logging: true, + createLogger: () => new SimpleConsoleLogger(), + driverSpecific: { logNotifications: true }, + }); + }); + after(() => closeTestingConnections(connections)); + + it("should pass extension setup notices to client", async () => Promise.all(connections.map(async connection => { + sinon.assert.calledWith( + logInfoStub, + "info", + `extension "uuid-ossp" already exists, skipping` + ); + sinon.assert.calledWith( + logInfoStub, + "info", + `extension "citext" already exists, skipping` + ); + }))); + + it("should pass manual notices to client", async () => Promise.all(connections.map(async connection => { + queryRunner = connection.createQueryRunner(); + await queryRunner.query(`DO $do$ BEGIN RAISE NOTICE 'this is a notice'; END $do$`); + sinon.assert.calledWith( + logInfoStub, + "info", + "this is a notice" + ); + await queryRunner.release(); + }))); + + it("should pass 'listen -> notify' messages to client", async () => Promise.all(connections.map(async connection => { + queryRunner = connection.createQueryRunner(); + await queryRunner.query("LISTEN foo;"); + await queryRunner.query("NOTIFY foo, 'bar!'"); + sinon.assert.calledWith( + logInfoStub, + "info", + "Received NOTIFY on channel foo: bar!." + ); + await queryRunner.release(); + }))); + + it("should not interfere with actual queries", async () => Promise.all(connections.map(async connection => { + manager = connection.manager; + await manager.save(Object.assign(new Foo(), { lowercaseval: "foo", lowercaseval2: "bar"})); + const loadedFoo = await manager.findOne(Foo); + expect(loadedFoo).not.to.be.undefined; + expect(loadedFoo).to.contain({ + lowercaseval: "foo", + lowercaseval2: "bar", + }); + }))); + }); +}); From c714867d3d0c43ccbb7ca8fb3ce969207e4d5c04 Mon Sep 17 00:00:00 2001 From: James Ward Date: Sat, 19 Sep 2020 04:02:03 -0400 Subject: [PATCH 080/212] fix: ensure browser builds don't include any non-browser modules (#6743) currently we pull in BetterSqlite3Driver, SqliteDriver, and a few other drivers & files that aren't possible to use in a browser context. this change adds some more browser compatibility features so webpack builds targeted at browsers will be able to complete closes #6739 --- gulpfile.ts | 19 ++++++++++--- package.json | 5 ++++ src/connection/ConnectionOptionsReader.ts | 5 ++-- ...serDirectoryExportedClassesLoader.template | 22 +++++++++++++++ .../BrowserDisabledDriversDummy.template | 28 +++++++++++++++++-- src/platform/BrowserPlatformTools.template | 13 ++++++--- src/platform/PlatformTools.ts | 10 +++++++ 7 files changed, 89 insertions(+), 13 deletions(-) create mode 100644 src/platform/BrowserDirectoryExportedClassesLoader.template diff --git a/gulpfile.ts b/gulpfile.ts index a0ba65cc980..7d0fbeb05de 100644 --- a/gulpfile.ts +++ b/gulpfile.ts @@ -70,6 +70,15 @@ export class Gulpfile { .pipe(gulp.dest("./build/browser/src")); } + /** + * Replaces PlatformTools with browser-specific implementation called BrowserPlatformTools. + */ + @Task() + browserCopyDirectoryExportedClassesLoader() { + return gulp.src("./src/platform/BrowserDirectoryExportedClassesLoader.template") + .pipe(rename("BrowserDirectoryExportedClassesLoader.ts")) + .pipe(gulp.dest("./build/browser/src/platform")); + } /** * Replaces PlatformTools with browser-specific implementation called BrowserPlatformTools. */ @@ -97,7 +106,10 @@ export class Gulpfile { "lib": ["es5", "es6", "dom"], typescript: require("typescript") }); - const tsResult = gulp.src(["./build/browser/src/**/*.ts", "./node_modules/reflect-metadata/**/*.d.ts", "./node_modules/@types/**/*.ts"]) + const tsResult = gulp.src([ + "./build/browser/src/**/*.ts", + "./node_modules/reflect-metadata/**/*.d.ts" + ]) .pipe(sourcemaps.init()) .pipe(tsProject()); @@ -151,8 +163,7 @@ export class Gulpfile { typescript: require("typescript") }); const tsResult = gulp.src([ - "./src/**/*.ts", - "./node_modules/@types/**/*.ts", + "./src/**/*.ts" ]) .pipe(sourcemaps.init()) .pipe(tsProject()); @@ -231,7 +242,7 @@ export class Gulpfile { package() { return [ "clean", - ["browserCopySources", "browserCopyPlatformTools", "browserCopyDisabledDriversDummy"], + ["browserCopySources", "browserCopyPlatformTools", "browserCopyDisabledDriversDummy", "browserCopyDirectoryExportedClassesLoader"], ["packageCompile", "browserCompile"], "packageMoveCompiledFiles", [ diff --git a/package.json b/package.json index 0c9d3d620dc..60b1a0fe028 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,8 @@ }, "main": "./index.js", "browser": { + "./browser/driver/aurora-data-api/AuroraDataApiDriver.js": "./browser/platform/BrowserDisabledDriversDummy.js", + "./browser/driver/cockroachdb/CockroachDriver.js": "./browser/platform/BrowserDisabledDriversDummy.js", "./browser/driver/postgres/PostgresDriver.js": "./browser/platform/BrowserDisabledDriversDummy.js", "./browser/driver/oracle/OracleDriver.ts": "./browser/platform/BrowserDisabledDriversDummy.js", "./browser/driver/sap/SapDriver.ts": "./browser/platform/BrowserDisabledDriversDummy.js", @@ -20,6 +22,9 @@ "./browser/driver/mongodb/MongoQueryRunner.js": "./browser/platform/BrowserDisabledDriversDummy.js", "./browser/entity-manager/MongoEntityManager.js": "./browser/platform/BrowserDisabledDriversDummy.js", "./browser/repository/MongoRepository.js": "./browser/platform/BrowserDisabledDriversDummy.js", + "./browser/driver/sqlite/SqliteDriver.js": "./browser/platform/BrowserDisabledDriversDummy.js", + "./browser/driver/better-sqlite3/BetterSqlite3Driver.js": "./browser/platform/BrowserDisabledDriversDummy.js", + "./browser/util/DirectoryExportedClassesLoader.js": "./browser/platform/BrowserDirectoryExportedClassesLoader.js", "./index.js": "./browser/index.js" }, "repository": { diff --git a/src/connection/ConnectionOptionsReader.ts b/src/connection/ConnectionOptionsReader.ts index b995eba5653..997c2405545 100644 --- a/src/connection/ConnectionOptionsReader.ts +++ b/src/connection/ConnectionOptionsReader.ts @@ -1,4 +1,3 @@ -import dotenv from "dotenv"; import appRootPath from "app-root-path"; import {ConnectionOptions} from "./ConnectionOptions"; import {PlatformTools} from "../platform/PlatformTools"; @@ -95,9 +94,9 @@ export class ConnectionOptionsReader { // if .env file found then load all its variables into process.env using dotenv package if (foundFileFormat === "env") { - dotenv.config({ path: this.baseFilePath }); + PlatformTools.dotenv(this.baseFilePath); } else if (PlatformTools.fileExist(".env")) { - dotenv.config({ path: ".env" }); + PlatformTools.dotenv(".env"); } // Determine config file name diff --git a/src/platform/BrowserDirectoryExportedClassesLoader.template b/src/platform/BrowserDirectoryExportedClassesLoader.template new file mode 100644 index 00000000000..39fe932a7ba --- /dev/null +++ b/src/platform/BrowserDirectoryExportedClassesLoader.template @@ -0,0 +1,22 @@ +/** + * Dummy functions for replacement via `package.json` in browser builds. + * + * If we don't include these functions typeorm will throw an error on runtime + * as well as during webpack builds. + */ + +import {Logger} from "../logger/Logger"; + +/** + * Loads all exported classes from the given directory. + */ +export function importClassesFromDirectories(logger: Logger, directories: string[], formats = [".js", ".cjs", ".ts"]): Function[] { + return []; +} + +/** + * Loads all json files from the given directory. + */ +export function importJsonsFromDirectories(directories: string[], format = ".json"): any[] { + return []; +} diff --git a/src/platform/BrowserDisabledDriversDummy.template b/src/platform/BrowserDisabledDriversDummy.template index 25c8cc29341..9b34705886d 100644 --- a/src/platform/BrowserDisabledDriversDummy.template +++ b/src/platform/BrowserDisabledDriversDummy.template @@ -3,8 +3,8 @@ * Using those classes reduces the build size by one third. * * If we don't include those dummy classes (and just disable the driver import - * with `false` in `package.json`) typeorm will throw an error on runtime, - * even if those driver are not used. + * with `false` in `package.json`) typeorm will throw an error on runtime and + * during webpack builds even if those driver are not used. */ /** @@ -37,6 +37,18 @@ export class MongoRepository {} */ export class PostgresDriver {} +/** + * DO NOT IMPORT THIS CLASS - + * This is a dummy class for replacement via `package.json` in browser builds + */ +export class AuroraDataApiDriver {} + +/** + * DO NOT IMPORT THIS CLASS - + * This is a dummy class for replacement via `package.json` in browser builds + */ +export class CockroachDriver {} + /** * DO NOT IMPORT THIS CLASS - * This is a dummy class for replacement via `package.json` in browser builds @@ -66,3 +78,15 @@ export class MysqlDriver {} * This is a dummy class for replacement via `package.json` in browser builds */ export class OracleDriver {} + +/** + * DO NOT IMPORT THIS CLASS - + * This is a dummy class for replacement via `package.json` in browser builds + */ +export class SqliteDriver {} + +/** + * DO NOT IMPORT THIS CLASS - + * This is a dummy class for replacement via `package.json` in browser builds + */ +export class BetterSqlite3Driver {} diff --git a/src/platform/BrowserPlatformTools.template b/src/platform/BrowserPlatformTools.template index 216150aaa0d..72295f27d32 100644 --- a/src/platform/BrowserPlatformTools.template +++ b/src/platform/BrowserPlatformTools.template @@ -75,6 +75,11 @@ export class PlatformTools { return false; } + static dotenv(pathStr: string): void { + if (this.type === "browser") + throw new Error(`This option/function is not supported in the browser environment. Failed operation: dotenv.config({ path: "${pathStr}" }).`); + } + /** * Gets environment variable. */ @@ -89,7 +94,7 @@ export class PlatformTools { throw new Error(`This option/function is not supported in the browser environment. Failed operation: fs.readFileSync("${filename}").`); return null; } - + static appendFileSync(filename: string, data: any) { if (this.type === "browser") throw new Error(`This option/function is not supported in the browser environment. Failed operation: fs.appendFileSync("${filename}").`); @@ -125,11 +130,11 @@ export class PlatformTools { static logError(prefix: string, error: any) { console.error(prefix + " ", error); } - + static logWarn(prefix: string, warning: any) { console.warn(prefix + " ", warning); } - + static log(message: string) { console.log(message); } @@ -165,4 +170,4 @@ if (typeof window !== "undefined") { // NativeScript uses global, not window if (typeof global !== "undefined") { global.Buffer = require("buffer/").Buffer; -} \ No newline at end of file +} diff --git a/src/platform/PlatformTools.ts b/src/platform/PlatformTools.ts index a43accfe6ce..9d75d8a479b 100644 --- a/src/platform/PlatformTools.ts +++ b/src/platform/PlatformTools.ts @@ -1,5 +1,6 @@ import * as path from "path"; import * as fs from "fs"; +import dotenv from "dotenv"; import chalk from "chalk"; import {highlight, Theme} from "cli-highlight"; @@ -181,6 +182,15 @@ export class PlatformTools { }); } + /** + * Loads a dotenv file into the environment variables. + * + * @param path The file to load as a dotenv configuration + */ + static dotenv(pathStr: string): void { + dotenv.config({ path: pathStr }); + } + /** * Gets environment variable. */ From dfe8259ef53a432f1c02607e6ffee662dd4fd8a9 Mon Sep 17 00:00:00 2001 From: Temnov Aleksey Date: Mon, 21 Sep 2020 09:34:34 +0300 Subject: [PATCH 081/212] fix: count() method for multiple primary keys for cockroachdb (#6745) * fix: count() method for multiple primary keys for cockroachdb Cockroachdb does not support concat() for different types at the moment. To fix this problem, each primary key is cast to the text type. * fix: add doublequote * fix: add doublequote * test: update and move tests for count() method for multiple primary keys * fix: count() method for multiple primary keys for oracle Oracle does not support CONCAT() for more than 2 arguments at the moment. To solve this problem, operator || is used instead of CONCAT(). --- src/query-builder/SelectQueryBuilder.ts | 11 ++++++++++ .../query-builder/count/entity/Test.ts | 13 +++++++++++ .../count/query-builder-count.ts | 22 +++++++++++++++++++ 3 files changed, 46 insertions(+) create mode 100644 test/functional/query-builder/count/entity/Test.ts create mode 100644 test/functional/query-builder/count/query-builder-count.ts diff --git a/src/query-builder/SelectQueryBuilder.ts b/src/query-builder/SelectQueryBuilder.ts index 821be3186c3..11cb61b0a47 100644 --- a/src/query-builder/SelectQueryBuilder.ts +++ b/src/query-builder/SelectQueryBuilder.ts @@ -36,6 +36,7 @@ import {SelectQueryBuilderOption} from "./SelectQueryBuilderOption"; import {ObjectUtils} from "../util/ObjectUtils"; import {DriverUtils} from "../driver/DriverUtils"; import {AuroraDataApiDriver} from "../driver/aurora-data-api/AuroraDataApiDriver"; +import {CockroachDriver} from "../driver/cockroachdb/CockroachDriver"; /** * Allows to build complex sql queries in a fashion way and execute those queries. @@ -1787,6 +1788,16 @@ export class SelectQueryBuilder extends QueryBuilder implements return `${distinctAlias}.${propertyName}`; }).join(" || ") + ")) as \"cnt\""; + } else if (this.connection.driver instanceof CockroachDriver) { + countSql = `COUNT(DISTINCT(CONCAT(` + metadata.primaryColumns.map((primaryColumn, index) => { + const propertyName = this.escape(primaryColumn.databaseName); + return `${distinctAlias}.${propertyName}::text`; + }).join(", ") + "))) as \"cnt\""; + } else if (this.connection.driver instanceof OracleDriver) { + countSql = `COUNT(DISTINCT(` + metadata.primaryColumns.map((primaryColumn, index) => { + const propertyName = this.escape(primaryColumn.databaseName); + return `${distinctAlias}.${propertyName}`; + }).join(" || ") + ")) as \"cnt\""; } else { countSql = `COUNT(DISTINCT(CONCAT(` + metadata.primaryColumns.map((primaryColumn, index) => { const propertyName = this.escape(primaryColumn.databaseName); diff --git a/test/functional/query-builder/count/entity/Test.ts b/test/functional/query-builder/count/entity/Test.ts new file mode 100644 index 00000000000..360fce0ac07 --- /dev/null +++ b/test/functional/query-builder/count/entity/Test.ts @@ -0,0 +1,13 @@ +import {Entity, PrimaryColumn} from "../../../../../src"; + +@Entity("tests") +export class Test { + @PrimaryColumn() + varcharField: string; + + @PrimaryColumn("uuid") + uuidField: string; + + @PrimaryColumn() + intField: number; +} diff --git a/test/functional/query-builder/count/query-builder-count.ts b/test/functional/query-builder/count/query-builder-count.ts new file mode 100644 index 00000000000..39990f9d38b --- /dev/null +++ b/test/functional/query-builder/count/query-builder-count.ts @@ -0,0 +1,22 @@ +import {closeTestingConnections, createTestingConnections, reloadTestingDatabases} from "../../../utils/test-utils"; +import {Connection} from "../../../../src/connection/Connection"; +import {expect} from "chai"; +import {Test} from "./entity/Test"; + +describe("query builder > count", () => { + + let connections: Connection[]; + before(async () => connections = await createTestingConnections({ + entities: [Test], + schemaCreate: true, + dropSchema: true, + })); + beforeEach(() => reloadTestingDatabases(connections)); + after(() => closeTestingConnections(connections)); + + it("Count query should be completed successfully", () => Promise.all(connections.map(async connection => { + const count = await connection.getRepository(Test).count(); + expect(count).to.be.equal(0); + }))); + +}); From f2356dc628c807f3ab4a5e1cdd3fe64b730e1286 Mon Sep 17 00:00:00 2001 From: James Ward Date: Mon, 21 Sep 2020 05:40:18 -0400 Subject: [PATCH 082/212] refactor: create a ReplicationMode type and update function defs (#6747) create a type to track ReplicationMode instead of writing out `"master"|"slave"` everywhere. update to drop the default from the QueryRunner constructor as they will always receive the mode from the driver when it's part of the QueryRunner also drop the default from Driver.createQueryRunner in the implementations - the interface mandates the mode to be defined so it will never be omitted anyway also drop the explict "master" from any connection.createQueryRunner calls so we leave it either the default or `slave` when needed all of this makes it easier to eventually migrate to other naming convetions for the replication mode should it be deemed the right path to go down --- src/cache/DbQueryResultCache.ts | 2 +- src/commands/QueryCommand.ts | 2 +- src/connection/Connection.ts | 7 ++++--- src/driver/Driver.ts | 3 ++- .../AuroraDataApiPostgresQueryRunner.ts | 5 +++-- .../aurora-data-api/AuroraDataApiConnection.ts | 3 ++- src/driver/aurora-data-api/AuroraDataApiDriver.ts | 3 ++- src/driver/better-sqlite3/BetterSqlite3Driver.ts | 3 ++- src/driver/cockroachdb/CockroachDriver.ts | 3 ++- src/driver/cockroachdb/CockroachQueryRunner.ts | 3 ++- src/driver/cordova/CordovaDriver.ts | 13 +++++++------ src/driver/expo/ExpoDriver.ts | 13 +++++++------ src/driver/mongodb/MongoDriver.ts | 3 ++- src/driver/mysql/MysqlDriver.ts | 3 ++- src/driver/mysql/MysqlQueryRunner.ts | 3 ++- src/driver/nativescript/NativescriptDriver.ts | 3 ++- src/driver/oracle/OracleDriver.ts | 3 ++- src/driver/oracle/OracleQueryRunner.ts | 3 ++- src/driver/postgres/PostgresDriver.ts | 7 ++++--- src/driver/postgres/PostgresQueryRunner.ts | 3 ++- src/driver/react-native/ReactNativeDriver.ts | 13 +++++++------ src/driver/sap/SapDriver.ts | 3 ++- src/driver/sap/SapQueryRunner.ts | 7 ++++--- src/driver/sqlite-abstract/AbstractSqliteDriver.ts | 3 ++- src/driver/sqlite/SqliteDriver.ts | 3 ++- src/driver/sqljs/SqljsDriver.ts | 3 ++- src/driver/sqlserver/SqlServerDriver.ts | 3 ++- src/driver/sqlserver/SqlServerQueryRunner.ts | 3 ++- src/driver/types/ReplicationMode.ts | 1 + src/entity-manager/EntityManager.ts | 4 ++-- src/index.ts | 1 + src/migration/MigrationExecutor.ts | 8 ++++---- src/persistence/EntityPersistExecutor.ts | 2 +- src/query-builder/QueryBuilder.ts | 2 +- src/query-runner/BaseQueryRunner.ts | 3 ++- src/schema-builder/MongoSchemaBuilder.ts | 4 ++-- src/schema-builder/RdbmsSchemaBuilder.ts | 4 ++-- .../cache/provider/MockQueryResultCache.ts | 2 +- 38 files changed, 93 insertions(+), 64 deletions(-) create mode 100644 src/driver/types/ReplicationMode.ts diff --git a/src/cache/DbQueryResultCache.ts b/src/cache/DbQueryResultCache.ts index 34dc8e44429..be243ce6acb 100644 --- a/src/cache/DbQueryResultCache.ts +++ b/src/cache/DbQueryResultCache.ts @@ -229,7 +229,7 @@ export class DbQueryResultCache implements QueryResultCache { if (queryRunner) return queryRunner; - return this.connection.createQueryRunner("master"); + return this.connection.createQueryRunner(); } } diff --git a/src/commands/QueryCommand.ts b/src/commands/QueryCommand.ts index c7a62129f2f..3d705b9399f 100644 --- a/src/commands/QueryCommand.ts +++ b/src/commands/QueryCommand.ts @@ -48,7 +48,7 @@ export class QueryCommand implements yargs.CommandModule { connection = await createConnection(connectionOptions); // create a query runner and execute query using it - queryRunner = connection.createQueryRunner("master"); + queryRunner = connection.createQueryRunner(); console.log(chalk.green("Running query: ") + PlatformTools.highlightSql(args._[1])); const queryResult = await queryRunner.query(args._[1]); console.log(chalk.green("Query has been executed. Result: ")); diff --git a/src/connection/Connection.ts b/src/connection/Connection.ts index 3f7ba32706d..d1487cda804 100644 --- a/src/connection/Connection.ts +++ b/src/connection/Connection.ts @@ -40,6 +40,7 @@ import {PromiseUtils} from "../"; import {IsolationLevel} from "../driver/types/IsolationLevel"; import {AuroraDataApiDriver} from "../driver/aurora-data-api/AuroraDataApiDriver"; import {DriverUtils} from "../driver/DriverUtils"; +import {ReplicationMode} from "../driver/types/ReplicationMode"; /** * Connection is a single database ORM connection to a specific database. @@ -259,7 +260,7 @@ export class Connection { */ // TODO rename async dropDatabase(): Promise { - const queryRunner = this.createQueryRunner("master"); + const queryRunner = this.createQueryRunner(); try { if (this.driver instanceof SqlServerDriver || this.driver instanceof MysqlDriver || this.driver instanceof AuroraDataApiDriver) { const databases: string[] = this.driver.database ? [this.driver.database] : []; @@ -395,7 +396,7 @@ export class Connection { if (queryRunner && queryRunner.isReleased) throw new QueryRunnerProviderAlreadyReleasedError(); - const usedQueryRunner = queryRunner || this.createQueryRunner("master"); + const usedQueryRunner = queryRunner || this.createQueryRunner(); try { return await usedQueryRunner.query(query, parameters); // await is needed here because we are using finally @@ -444,7 +445,7 @@ export class Connection { * If you perform writes you must use master database, * if you perform reads you can use slave databases. */ - createQueryRunner(mode: "master"|"slave" = "master"): QueryRunner { + createQueryRunner(mode: ReplicationMode = "master"): QueryRunner { const queryRunner = this.driver.createQueryRunner(mode); const manager = this.createEntityManager(queryRunner); Object.assign(queryRunner, { manager: manager }); diff --git a/src/driver/Driver.ts b/src/driver/Driver.ts index 70dc4c0ee5c..61a19ed16d1 100644 --- a/src/driver/Driver.ts +++ b/src/driver/Driver.ts @@ -8,6 +8,7 @@ import {DataTypeDefaults} from "./types/DataTypeDefaults"; import {BaseConnectionOptions} from "../connection/BaseConnectionOptions"; import {TableColumn} from "../schema-builder/table/TableColumn"; import {EntityMetadata} from "../metadata/EntityMetadata"; +import {ReplicationMode} from "./types/ReplicationMode"; /** * Driver organizes TypeORM communication with specific database management system. @@ -102,7 +103,7 @@ export interface Driver { /** * Creates a query runner used for common queries. */ - createQueryRunner(mode: "master"|"slave"): QueryRunner; + createQueryRunner(mode: ReplicationMode): QueryRunner; /** * Replaces parameters in the given sql with special escaping character diff --git a/src/driver/aurora-data-api-pg/AuroraDataApiPostgresQueryRunner.ts b/src/driver/aurora-data-api-pg/AuroraDataApiPostgresQueryRunner.ts index 2a553c134c1..f9ec0cb06d8 100644 --- a/src/driver/aurora-data-api-pg/AuroraDataApiPostgresQueryRunner.ts +++ b/src/driver/aurora-data-api-pg/AuroraDataApiPostgresQueryRunner.ts @@ -5,11 +5,12 @@ import {QueryRunner} from "../../query-runner/QueryRunner"; import {IsolationLevel} from "../types/IsolationLevel"; import {AuroraDataApiPostgresDriver} from "../postgres/PostgresDriver"; import {PostgresQueryRunner} from "../postgres/PostgresQueryRunner"; +import {ReplicationMode} from "../types/ReplicationMode"; class PostgresQueryRunnerWrapper extends PostgresQueryRunner { driver: any; - constructor(driver: any, mode: "master"|"slave") { + constructor(driver: any, mode: ReplicationMode) { super(driver, mode); } } @@ -46,7 +47,7 @@ export class AuroraDataApiPostgresQueryRunner extends PostgresQueryRunnerWrapper // Constructor // ------------------------------------------------------------------------- - constructor(driver: AuroraDataApiPostgresDriver, mode: "master"|"slave" = "master") { + constructor(driver: AuroraDataApiPostgresDriver, mode: ReplicationMode) { super(driver, mode); } diff --git a/src/driver/aurora-data-api/AuroraDataApiConnection.ts b/src/driver/aurora-data-api/AuroraDataApiConnection.ts index 386248809fb..e79bc30dc9e 100644 --- a/src/driver/aurora-data-api/AuroraDataApiConnection.ts +++ b/src/driver/aurora-data-api/AuroraDataApiConnection.ts @@ -1,6 +1,7 @@ import {AuroraDataApiQueryRunner} from "./AuroraDataApiQueryRunner"; import {Connection} from "../../connection/Connection"; import {ConnectionOptions, QueryRunner} from "../.."; +import {ReplicationMode} from "../types/ReplicationMode"; /** * Organizes communication with MySQL DBMS. @@ -13,7 +14,7 @@ export class AuroraDataApiConnection extends Connection { this.queryRunnter = queryRunner; } - public createQueryRunner(mode: "master" | "slave" = "master"): QueryRunner { + public createQueryRunner(mode: ReplicationMode): QueryRunner { return this.queryRunnter; } diff --git a/src/driver/aurora-data-api/AuroraDataApiDriver.ts b/src/driver/aurora-data-api/AuroraDataApiDriver.ts index e85e545aa20..3138f9eb0c8 100644 --- a/src/driver/aurora-data-api/AuroraDataApiDriver.ts +++ b/src/driver/aurora-data-api/AuroraDataApiDriver.ts @@ -16,6 +16,7 @@ import {AuroraDataApiConnectionCredentialsOptions} from "./AuroraDataApiConnecti import {EntityMetadata} from "../../metadata/EntityMetadata"; import {OrmUtils} from "../../util/OrmUtils"; import {ApplyValueTransformers} from "../../util/ApplyValueTransformers"; +import {ReplicationMode} from "../types/ReplicationMode"; /** * Organizes communication with MySQL DBMS. @@ -355,7 +356,7 @@ export class AuroraDataApiDriver implements Driver { /** * Creates a query runner used to execute database queries. */ - createQueryRunner(mode: "master"|"slave" = "master") { + createQueryRunner(mode: ReplicationMode) { return new AuroraDataApiQueryRunner(this); } diff --git a/src/driver/better-sqlite3/BetterSqlite3Driver.ts b/src/driver/better-sqlite3/BetterSqlite3Driver.ts index 77864accf25..f5d9480759e 100644 --- a/src/driver/better-sqlite3/BetterSqlite3Driver.ts +++ b/src/driver/better-sqlite3/BetterSqlite3Driver.ts @@ -9,6 +9,7 @@ import { QueryRunner } from "../../query-runner/QueryRunner"; import { AbstractSqliteDriver } from "../sqlite-abstract/AbstractSqliteDriver"; import { BetterSqlite3ConnectionOptions } from "./BetterSqlite3ConnectionOptions"; import { BetterSqlite3QueryRunner } from "./BetterSqlite3QueryRunner"; +import {ReplicationMode} from "../types/ReplicationMode"; /** * Organizes communication with sqlite DBMS. @@ -63,7 +64,7 @@ export class BetterSqlite3Driver extends AbstractSqliteDriver { /** * Creates a query runner used to execute database queries. */ - createQueryRunner(mode: "master" | "slave" = "master"): QueryRunner { + createQueryRunner(mode: ReplicationMode): QueryRunner { if (!this.queryRunner) this.queryRunner = new BetterSqlite3QueryRunner(this); diff --git a/src/driver/cockroachdb/CockroachDriver.ts b/src/driver/cockroachdb/CockroachDriver.ts index 8cacf571187..b1e0f06e3b2 100644 --- a/src/driver/cockroachdb/CockroachDriver.ts +++ b/src/driver/cockroachdb/CockroachDriver.ts @@ -19,6 +19,7 @@ import {EntityMetadata} from "../../metadata/EntityMetadata"; import {OrmUtils} from "../../util/OrmUtils"; import {CockroachQueryRunner} from "./CockroachQueryRunner"; import {ApplyValueTransformers} from "../../util/ApplyValueTransformers"; +import {ReplicationMode} from "../types/ReplicationMode"; /** * Organizes communication with Cockroach DBMS. @@ -284,7 +285,7 @@ export class CockroachDriver implements Driver { /** * Creates a query runner used to execute database queries. */ - createQueryRunner(mode: "master"|"slave" = "master") { + createQueryRunner(mode: ReplicationMode) { return new CockroachQueryRunner(this, mode); } diff --git a/src/driver/cockroachdb/CockroachQueryRunner.ts b/src/driver/cockroachdb/CockroachQueryRunner.ts index 018b721f72f..1f97ba61cb2 100644 --- a/src/driver/cockroachdb/CockroachQueryRunner.ts +++ b/src/driver/cockroachdb/CockroachQueryRunner.ts @@ -22,6 +22,7 @@ import {TableCheck} from "../../schema-builder/table/TableCheck"; import {ColumnType} from "../../index"; import {IsolationLevel} from "../types/IsolationLevel"; import {TableExclusion} from "../../schema-builder/table/TableExclusion"; +import {ReplicationMode} from "../types/ReplicationMode"; /** * Runs queries on a single postgres database connection. @@ -65,7 +66,7 @@ export class CockroachQueryRunner extends BaseQueryRunner implements QueryRunner // Constructor // ------------------------------------------------------------------------- - constructor(driver: CockroachDriver, mode: "master"|"slave" = "master") { + constructor(driver: CockroachDriver, mode: ReplicationMode) { super(); this.driver = driver; this.connection = driver.connection; diff --git a/src/driver/cordova/CordovaDriver.ts b/src/driver/cordova/CordovaDriver.ts index bec6b6b63ff..6f6eb3a463f 100644 --- a/src/driver/cordova/CordovaDriver.ts +++ b/src/driver/cordova/CordovaDriver.ts @@ -5,6 +5,7 @@ import {QueryRunner} from "../../query-runner/QueryRunner"; import {Connection} from "../../connection/Connection"; import {DriverOptionNotSetError} from "../../error/DriverOptionNotSetError"; import {DriverPackageNotInstalledError} from "../../error/DriverPackageNotInstalledError"; +import {ReplicationMode} from "../types/ReplicationMode"; // needed for typescript compiler interface Window { @@ -15,7 +16,7 @@ declare var window: Window; export class CordovaDriver extends AbstractSqliteDriver { options: CordovaConnectionOptions; - + // ------------------------------------------------------------------------- // Constructor // ------------------------------------------------------------------------- @@ -37,7 +38,7 @@ export class CordovaDriver extends AbstractSqliteDriver { // load sqlite package this.loadDependencies(); } - + // ------------------------------------------------------------------------- // Public Methods @@ -52,17 +53,17 @@ export class CordovaDriver extends AbstractSqliteDriver { this.databaseConnection.close(ok, fail); }); } - + /** * Creates a query runner used to execute database queries. */ - createQueryRunner(mode: "master"|"slave" = "master"): QueryRunner { + createQueryRunner(mode: ReplicationMode): QueryRunner { if (!this.queryRunner) this.queryRunner = new CordovaQueryRunner(this); return this.queryRunner; } - + // ------------------------------------------------------------------------- // Protected Methods // ------------------------------------------------------------------------- @@ -104,4 +105,4 @@ export class CordovaDriver extends AbstractSqliteDriver { throw new DriverPackageNotInstalledError("Cordova-SQLite", "cordova-sqlite-storage"); } } -} \ No newline at end of file +} diff --git a/src/driver/expo/ExpoDriver.ts b/src/driver/expo/ExpoDriver.ts index 280b7e08b7c..1086e42e719 100644 --- a/src/driver/expo/ExpoDriver.ts +++ b/src/driver/expo/ExpoDriver.ts @@ -4,10 +4,11 @@ import {ExpoQueryRunner} from "./ExpoQueryRunner"; import {QueryRunner} from "../../query-runner/QueryRunner"; import {Connection} from "../../connection/Connection"; import {DriverOptionNotSetError} from "../../error/DriverOptionNotSetError"; +import {ReplicationMode} from "../types/ReplicationMode"; export class ExpoDriver extends AbstractSqliteDriver { options: ExpoConnectionOptions; - + // ------------------------------------------------------------------------- // Constructor // ------------------------------------------------------------------------- @@ -20,14 +21,14 @@ export class ExpoDriver extends AbstractSqliteDriver { // validate options to make sure everything is set if (!this.options.database) throw new DriverOptionNotSetError("database"); - + if (!this.options.driver) throw new DriverOptionNotSetError("driver"); // load sqlite package this.sqlite = this.options.driver; } - + // ------------------------------------------------------------------------- // Public Methods @@ -48,17 +49,17 @@ export class ExpoDriver extends AbstractSqliteDriver { } }); } - + /** * Creates a query runner used to execute database queries. */ - createQueryRunner(mode: "master"|"slave" = "master"): QueryRunner { + createQueryRunner(mode: ReplicationMode): QueryRunner { if (!this.queryRunner) this.queryRunner = new ExpoQueryRunner(this); return this.queryRunner; } - + // ------------------------------------------------------------------------- // Protected Methods // ------------------------------------------------------------------------- diff --git a/src/driver/mongodb/MongoDriver.ts b/src/driver/mongodb/MongoDriver.ts index f1d1b190e2b..1b53dc91f86 100644 --- a/src/driver/mongodb/MongoDriver.ts +++ b/src/driver/mongodb/MongoDriver.ts @@ -16,6 +16,7 @@ import {ConnectionOptions} from "../../connection/ConnectionOptions"; import {EntityMetadata} from "../../metadata/EntityMetadata"; import {ObjectUtils} from "../../util/ObjectUtils"; import {ApplyValueTransformers} from "../../util/ApplyValueTransformers"; +import {ReplicationMode} from "../types/ReplicationMode"; /** * Organizes communication with MongoDB. @@ -262,7 +263,7 @@ export class MongoDriver implements Driver { /** * Creates a query runner used to execute database queries. */ - createQueryRunner(mode: "master"|"slave" = "master") { + createQueryRunner(mode: ReplicationMode) { return this.queryRunner!; } diff --git a/src/driver/mysql/MysqlDriver.ts b/src/driver/mysql/MysqlDriver.ts index d65b5d6a5f6..4eb1e5644bc 100644 --- a/src/driver/mysql/MysqlDriver.ts +++ b/src/driver/mysql/MysqlDriver.ts @@ -18,6 +18,7 @@ import {MysqlConnectionCredentialsOptions} from "./MysqlConnectionCredentialsOpt import {EntityMetadata} from "../../metadata/EntityMetadata"; import {OrmUtils} from "../../util/OrmUtils"; import {ApplyValueTransformers} from "../../util/ApplyValueTransformers"; +import {ReplicationMode} from "../types/ReplicationMode"; /** * Organizes communication with MySQL DBMS. @@ -385,7 +386,7 @@ export class MysqlDriver implements Driver { /** * Creates a query runner used to execute database queries. */ - createQueryRunner(mode: "master"|"slave" = "master") { + createQueryRunner(mode: ReplicationMode) { return new MysqlQueryRunner(this, mode); } diff --git a/src/driver/mysql/MysqlQueryRunner.ts b/src/driver/mysql/MysqlQueryRunner.ts index 5a7cdb1875c..daee2507145 100644 --- a/src/driver/mysql/MysqlQueryRunner.ts +++ b/src/driver/mysql/MysqlQueryRunner.ts @@ -22,6 +22,7 @@ import {TableCheck} from "../../schema-builder/table/TableCheck"; import {IsolationLevel} from "../types/IsolationLevel"; import {TableExclusion} from "../../schema-builder/table/TableExclusion"; import {VersionUtils} from "../../util/VersionUtils"; +import {ReplicationMode} from "../types/ReplicationMode"; /** * Runs queries on a single mysql database connection. @@ -50,7 +51,7 @@ export class MysqlQueryRunner extends BaseQueryRunner implements QueryRunner { // Constructor // ------------------------------------------------------------------------- - constructor(driver: MysqlDriver, mode: "master"|"slave" = "master") { + constructor(driver: MysqlDriver, mode: ReplicationMode) { super(); this.driver = driver; this.connection = driver.connection; diff --git a/src/driver/nativescript/NativescriptDriver.ts b/src/driver/nativescript/NativescriptDriver.ts index 0d6e8d9daca..b6384f59daf 100644 --- a/src/driver/nativescript/NativescriptDriver.ts +++ b/src/driver/nativescript/NativescriptDriver.ts @@ -6,6 +6,7 @@ import {Connection} from "../../connection/Connection"; import {DriverOptionNotSetError} from "../../error/DriverOptionNotSetError"; import {DriverPackageNotInstalledError} from "../../error/DriverPackageNotInstalledError"; import {ColumnType} from "../types/ColumnTypes"; +import {ReplicationMode} from "../types/ReplicationMode"; /** * Organizes communication with sqlite DBMS within Nativescript. @@ -66,7 +67,7 @@ export class NativescriptDriver extends AbstractSqliteDriver { /** * Creates a query runner used to execute database queries. */ - createQueryRunner(mode: "master"|"slave" = "master"): QueryRunner { + createQueryRunner(mode: ReplicationMode): QueryRunner { if (!this.queryRunner) { this.queryRunner = new NativescriptQueryRunner(this); } diff --git a/src/driver/oracle/OracleDriver.ts b/src/driver/oracle/OracleDriver.ts index 03bbef3cbce..3d02f3b5375 100644 --- a/src/driver/oracle/OracleDriver.ts +++ b/src/driver/oracle/OracleDriver.ts @@ -18,6 +18,7 @@ import {DriverUtils} from "../DriverUtils"; import {EntityMetadata} from "../../metadata/EntityMetadata"; import {OrmUtils} from "../../util/OrmUtils"; import {ApplyValueTransformers} from "../../util/ApplyValueTransformers"; +import {ReplicationMode} from "../types/ReplicationMode"; /** * Organizes communication with Oracle RDBMS. @@ -287,7 +288,7 @@ export class OracleDriver implements Driver { /** * Creates a query runner used to execute database queries. */ - createQueryRunner(mode: "master"|"slave" = "master") { + createQueryRunner(mode: ReplicationMode) { return new OracleQueryRunner(this, mode); } diff --git a/src/driver/oracle/OracleQueryRunner.ts b/src/driver/oracle/OracleQueryRunner.ts index 15696da5b0b..f4187da3281 100644 --- a/src/driver/oracle/OracleQueryRunner.ts +++ b/src/driver/oracle/OracleQueryRunner.ts @@ -20,6 +20,7 @@ import {TableCheck} from "../../schema-builder/table/TableCheck"; import {ColumnType, PromiseUtils} from "../../index"; import {IsolationLevel} from "../types/IsolationLevel"; import {TableExclusion} from "../../schema-builder/table/TableExclusion"; +import {ReplicationMode} from "../types/ReplicationMode"; /** * Runs queries on a single oracle database connection. @@ -48,7 +49,7 @@ export class OracleQueryRunner extends BaseQueryRunner implements QueryRunner { // Constructor // ------------------------------------------------------------------------- - constructor(driver: OracleDriver, mode: "master"|"slave" = "master") { + constructor(driver: OracleDriver, mode: ReplicationMode) { super(); this.driver = driver; this.connection = driver.connection; diff --git a/src/driver/postgres/PostgresDriver.ts b/src/driver/postgres/PostgresDriver.ts index f5a8d8cdd6d..d65c4c6b950 100644 --- a/src/driver/postgres/PostgresDriver.ts +++ b/src/driver/postgres/PostgresDriver.ts @@ -21,6 +21,7 @@ import {OrmUtils} from "../../util/OrmUtils"; import {ApplyValueTransformers} from "../../util/ApplyValueTransformers"; import {AuroraDataApiPostgresConnectionOptions} from "../aurora-data-api-pg/AuroraDataApiPostgresConnectionOptions"; import {AuroraDataApiPostgresQueryRunner} from "../aurora-data-api-pg/AuroraDataApiPostgresQueryRunner"; +import {ReplicationMode} from "../types/ReplicationMode"; /** * Organizes communication with PostgreSQL DBMS. @@ -436,7 +437,7 @@ export class PostgresDriver implements Driver { /** * Creates a query runner used to execute database queries. */ - createQueryRunner(mode: "master"|"slave" = "master"): QueryRunner { + createQueryRunner(mode: ReplicationMode): QueryRunner { return new PostgresQueryRunner(this, mode); } @@ -1043,7 +1044,7 @@ export class PostgresDriver implements Driver { abstract class PostgresWrapper extends PostgresDriver { options: any; - abstract createQueryRunner(mode: "master"|"slave"): any; + abstract createQueryRunner(mode: ReplicationMode): any; } export class AuroraDataApiPostgresDriver extends PostgresWrapper { @@ -1123,7 +1124,7 @@ export class AuroraDataApiPostgresDriver extends PostgresWrapper { /** * Creates a query runner used to execute database queries. */ - createQueryRunner(mode: "master"|"slave" = "master") { + createQueryRunner(mode: ReplicationMode) { return new AuroraDataApiPostgresQueryRunner(this, mode); } diff --git a/src/driver/postgres/PostgresQueryRunner.ts b/src/driver/postgres/PostgresQueryRunner.ts index 716d3d190d5..f34b0b92a63 100644 --- a/src/driver/postgres/PostgresQueryRunner.ts +++ b/src/driver/postgres/PostgresQueryRunner.ts @@ -22,6 +22,7 @@ import {OrmUtils} from "../../util/OrmUtils"; import {Query} from "../Query"; import {IsolationLevel} from "../types/IsolationLevel"; import {PostgresDriver} from "./PostgresDriver"; +import {ReplicationMode} from "../types/ReplicationMode"; /** * Runs queries on a single postgres database connection. @@ -55,7 +56,7 @@ export class PostgresQueryRunner extends BaseQueryRunner implements QueryRunner // Constructor // ------------------------------------------------------------------------- - constructor(driver: PostgresDriver, mode: "master"|"slave" = "master") { + constructor(driver: PostgresDriver, mode: ReplicationMode) { super(); this.driver = driver; this.connection = driver.connection; diff --git a/src/driver/react-native/ReactNativeDriver.ts b/src/driver/react-native/ReactNativeDriver.ts index 8aca0aca75f..0763c04d7dc 100644 --- a/src/driver/react-native/ReactNativeDriver.ts +++ b/src/driver/react-native/ReactNativeDriver.ts @@ -6,10 +6,11 @@ import {Connection} from "../../connection/Connection"; import {DriverOptionNotSetError} from "../../error/DriverOptionNotSetError"; import {DriverPackageNotInstalledError} from "../../error/DriverPackageNotInstalledError"; import {PlatformTools} from "../../platform/PlatformTools"; +import {ReplicationMode} from "../types/ReplicationMode"; export class ReactNativeDriver extends AbstractSqliteDriver { options: ReactNativeConnectionOptions; - + // ------------------------------------------------------------------------- // Constructor // ------------------------------------------------------------------------- @@ -29,7 +30,7 @@ export class ReactNativeDriver extends AbstractSqliteDriver { // load sqlite package this.loadDependencies(); } - + // ------------------------------------------------------------------------- // Public Methods @@ -44,17 +45,17 @@ export class ReactNativeDriver extends AbstractSqliteDriver { this.databaseConnection.close(ok, fail); }); } - + /** * Creates a query runner used to execute database queries. */ - createQueryRunner(mode: "master"|"slave" = "master"): QueryRunner { + createQueryRunner(mode: ReplicationMode): QueryRunner { if (!this.queryRunner) this.queryRunner = new ReactNativeQueryRunner(this); return this.queryRunner; } - + // ------------------------------------------------------------------------- // Protected Methods // ------------------------------------------------------------------------- @@ -96,4 +97,4 @@ export class ReactNativeDriver extends AbstractSqliteDriver { throw new DriverPackageNotInstalledError("React-Native", "react-native-sqlite-storage"); } } -} \ No newline at end of file +} diff --git a/src/driver/sap/SapDriver.ts b/src/driver/sap/SapDriver.ts index 85b6a7f2f2e..958e199981c 100644 --- a/src/driver/sap/SapDriver.ts +++ b/src/driver/sap/SapDriver.ts @@ -11,6 +11,7 @@ import {DataTypeDefaults} from "../types/DataTypeDefaults"; import {MappedColumnTypes} from "../types/MappedColumnTypes"; import {SapConnectionOptions} from "./SapConnectionOptions"; import {SapQueryRunner} from "./SapQueryRunner"; +import {ReplicationMode} from "../types/ReplicationMode"; /** * Organizes communication with SAP Hana DBMS. @@ -273,7 +274,7 @@ export class SapDriver implements Driver { /** * Creates a query runner used to execute database queries. */ - createQueryRunner(mode: "master"|"slave" = "master") { + createQueryRunner(mode: ReplicationMode) { return new SapQueryRunner(this, mode); } diff --git a/src/driver/sap/SapQueryRunner.ts b/src/driver/sap/SapQueryRunner.ts index 9e839a44909..dfb955b0961 100644 --- a/src/driver/sap/SapQueryRunner.ts +++ b/src/driver/sap/SapQueryRunner.ts @@ -20,6 +20,7 @@ import {OrmUtils} from "../../util/OrmUtils"; import {Query} from "../Query"; import {IsolationLevel} from "../types/IsolationLevel"; import {SapDriver} from "./SapDriver"; +import {ReplicationMode} from "../types/ReplicationMode"; /** * Runs queries on a single SQL Server database connection. @@ -55,7 +56,7 @@ export class SapQueryRunner extends BaseQueryRunner implements QueryRunner { // Constructor // ------------------------------------------------------------------------- - constructor(driver: SapDriver, mode: "master"|"slave" = "master") { + constructor(driver: SapDriver, mode: ReplicationMode) { super(); this.driver = driver; this.connection = driver.connection; @@ -91,7 +92,7 @@ export class SapQueryRunner extends BaseQueryRunner implements QueryRunner { return this.driver.master.release(this.databaseConnection); } - return Promise.resolve(); + return Promise.resolve(); } /** @@ -1823,7 +1824,7 @@ export class SapQueryRunner extends BaseQueryRunner implements QueryRunner { let indexType = ""; if (index.isUnique) { indexType += "UNIQUE "; - } + } if (index.isFulltext) { indexType += "FULLTEXT "; } diff --git a/src/driver/sqlite-abstract/AbstractSqliteDriver.ts b/src/driver/sqlite-abstract/AbstractSqliteDriver.ts index 308f0c1a9f6..22d28cc35ec 100644 --- a/src/driver/sqlite-abstract/AbstractSqliteDriver.ts +++ b/src/driver/sqlite-abstract/AbstractSqliteDriver.ts @@ -13,6 +13,7 @@ import {BaseConnectionOptions} from "../../connection/BaseConnectionOptions"; import {EntityMetadata} from "../../metadata/EntityMetadata"; import {OrmUtils} from "../../util/OrmUtils"; import {ApplyValueTransformers} from "../../util/ApplyValueTransformers"; +import {ReplicationMode} from "../types/ReplicationMode"; /** * Organizes communication with sqlite DBMS. @@ -214,7 +215,7 @@ export abstract class AbstractSqliteDriver implements Driver { /** * Creates a query runner used to execute database queries. */ - abstract createQueryRunner(mode: "master"|"slave"): QueryRunner; + abstract createQueryRunner(mode: ReplicationMode): QueryRunner; // ------------------------------------------------------------------------- // Public Methods diff --git a/src/driver/sqlite/SqliteDriver.ts b/src/driver/sqlite/SqliteDriver.ts index aa27e36544e..caab6aeebab 100644 --- a/src/driver/sqlite/SqliteDriver.ts +++ b/src/driver/sqlite/SqliteDriver.ts @@ -9,6 +9,7 @@ import { SqliteConnectionOptions } from "./SqliteConnectionOptions"; import { ColumnType } from "../types/ColumnTypes"; import { QueryRunner } from "../../query-runner/QueryRunner"; import { AbstractSqliteDriver } from "../sqlite-abstract/AbstractSqliteDriver"; +import {ReplicationMode} from "../types/ReplicationMode"; /** * Organizes communication with sqlite DBMS. @@ -65,7 +66,7 @@ export class SqliteDriver extends AbstractSqliteDriver { /** * Creates a query runner used to execute database queries. */ - createQueryRunner(mode: "master" | "slave" = "master"): QueryRunner { + createQueryRunner(mode: ReplicationMode): QueryRunner { if (!this.queryRunner) this.queryRunner = new SqliteQueryRunner(this); diff --git a/src/driver/sqljs/SqljsDriver.ts b/src/driver/sqljs/SqljsDriver.ts index 1953bb6d158..ef06346ca81 100644 --- a/src/driver/sqljs/SqljsDriver.ts +++ b/src/driver/sqljs/SqljsDriver.ts @@ -9,6 +9,7 @@ import {PlatformTools} from "../../platform/PlatformTools"; import {EntityMetadata} from "../../metadata/EntityMetadata"; import {OrmUtils} from "../../util/OrmUtils"; import {ObjectLiteral} from "../../common/ObjectLiteral"; +import {ReplicationMode} from "../types/ReplicationMode"; // This is needed to satisfy the typescript compiler. interface Window { @@ -69,7 +70,7 @@ export class SqljsDriver extends AbstractSqliteDriver { /** * Creates a query runner used to execute database queries. */ - createQueryRunner(mode: "master" | "slave" = "master"): QueryRunner { + createQueryRunner(mode: ReplicationMode): QueryRunner { if (!this.queryRunner) this.queryRunner = new SqljsQueryRunner(this); diff --git a/src/driver/sqlserver/SqlServerDriver.ts b/src/driver/sqlserver/SqlServerDriver.ts index 5954431de09..e6f1735f1fc 100644 --- a/src/driver/sqlserver/SqlServerDriver.ts +++ b/src/driver/sqlserver/SqlServerDriver.ts @@ -19,6 +19,7 @@ import {SqlServerConnectionCredentialsOptions} from "./SqlServerConnectionCreden import {EntityMetadata} from "../../metadata/EntityMetadata"; import {OrmUtils} from "../../util/OrmUtils"; import {ApplyValueTransformers} from "../../util/ApplyValueTransformers"; +import {ReplicationMode} from "../types/ReplicationMode"; /** * Organizes communication with SQL Server DBMS. @@ -296,7 +297,7 @@ export class SqlServerDriver implements Driver { /** * Creates a query runner used to execute database queries. */ - createQueryRunner(mode: "master"|"slave" = "master") { + createQueryRunner(mode: ReplicationMode) { return new SqlServerQueryRunner(this, mode); } diff --git a/src/driver/sqlserver/SqlServerQueryRunner.ts b/src/driver/sqlserver/SqlServerQueryRunner.ts index 06677627af6..8776738c53e 100644 --- a/src/driver/sqlserver/SqlServerQueryRunner.ts +++ b/src/driver/sqlserver/SqlServerQueryRunner.ts @@ -22,6 +22,7 @@ import {Query} from "../Query"; import {IsolationLevel} from "../types/IsolationLevel"; import {MssqlParameter} from "./MssqlParameter"; import {SqlServerDriver} from "./SqlServerDriver"; +import {ReplicationMode} from "../types/ReplicationMode"; /** * Runs queries on a single SQL Server database connection. @@ -54,7 +55,7 @@ export class SqlServerQueryRunner extends BaseQueryRunner implements QueryRunner // Constructor // ------------------------------------------------------------------------- - constructor(driver: SqlServerDriver, mode: "master"|"slave" = "master") { + constructor(driver: SqlServerDriver, mode: ReplicationMode) { super(); this.driver = driver; this.connection = driver.connection; diff --git a/src/driver/types/ReplicationMode.ts b/src/driver/types/ReplicationMode.ts new file mode 100644 index 00000000000..53aca0d9978 --- /dev/null +++ b/src/driver/types/ReplicationMode.ts @@ -0,0 +1 @@ +export type ReplicationMode = "master" | "slave"; diff --git a/src/entity-manager/EntityManager.ts b/src/entity-manager/EntityManager.ts index 1d214757ecc..5677a371269 100644 --- a/src/entity-manager/EntityManager.ts +++ b/src/entity-manager/EntityManager.ts @@ -128,7 +128,7 @@ export class EntityManager { // if query runner is already defined in this class, it means this entity manager was already created for a single connection // if its not defined we create a new query runner - single connection where we'll execute all our operations - const queryRunner = this.queryRunner || this.connection.createQueryRunner("master"); + const queryRunner = this.queryRunner || this.connection.createQueryRunner(); try { if (isolation) { @@ -832,7 +832,7 @@ export class EntityManager { */ async clear(entityClass: EntityTarget): Promise { const metadata = this.connection.getMetadata(entityClass); - const queryRunner = this.queryRunner || this.connection.createQueryRunner("master"); + const queryRunner = this.queryRunner || this.connection.createQueryRunner(); try { return await queryRunner.clearTable(metadata.tablePath); // await is needed here because we are using finally diff --git a/src/index.ts b/src/index.ts index 422440c8319..ff39f966ba5 100644 --- a/src/index.ts +++ b/src/index.ts @@ -120,6 +120,7 @@ export * from "./schema-builder/table/TableUnique"; export * from "./schema-builder/table/Table"; export * from "./driver/mongodb/typings"; export * from "./driver/types/DatabaseType"; +export * from "./driver/types/ReplicationMode"; export * from "./driver/sqlserver/MssqlParameter"; export {ConnectionOptionsReader} from "./connection/ConnectionOptionsReader"; diff --git a/src/migration/MigrationExecutor.ts b/src/migration/MigrationExecutor.ts index c7c90640241..af67fa5f462 100644 --- a/src/migration/MigrationExecutor.ts +++ b/src/migration/MigrationExecutor.ts @@ -129,7 +129,7 @@ export class MigrationExecutor { */ async showMigrations(): Promise { let hasUnappliedMigrations = false; - const queryRunner = this.queryRunner || this.connection.createQueryRunner("master"); + const queryRunner = this.queryRunner || this.connection.createQueryRunner(); // create migrations table if its not created yet await this.createMigrationsTableIfNotExist(queryRunner); // get all migrations that are executed and saved in the database @@ -163,7 +163,7 @@ export class MigrationExecutor { */ async executePendingMigrations(): Promise { - const queryRunner = this.queryRunner || this.connection.createQueryRunner("master"); + const queryRunner = this.queryRunner || this.connection.createQueryRunner(); // create migrations table if its not created yet await this.createMigrationsTableIfNotExist(queryRunner); // get all migrations that are executed and saved in the database @@ -265,7 +265,7 @@ export class MigrationExecutor { */ async undoLastMigration(): Promise { - const queryRunner = this.queryRunner || this.connection.createQueryRunner("master"); + const queryRunner = this.queryRunner || this.connection.createQueryRunner(); // create migrations table if its not created yet await this.createMigrationsTableIfNotExist(queryRunner); @@ -496,7 +496,7 @@ export class MigrationExecutor { } protected async withQueryRunner(callback: (queryRunner: QueryRunner) => T) { - const queryRunner = this.queryRunner || this.connection.createQueryRunner("master"); + const queryRunner = this.queryRunner || this.connection.createQueryRunner(); try { return callback(queryRunner); diff --git a/src/persistence/EntityPersistExecutor.ts b/src/persistence/EntityPersistExecutor.ts index ec04e3459c1..e6dd62122b0 100644 --- a/src/persistence/EntityPersistExecutor.ts +++ b/src/persistence/EntityPersistExecutor.ts @@ -50,7 +50,7 @@ export class EntityPersistExecutor { // if query runner is already defined in this class, it means this entity manager was already created for a single connection // if its not defined we create a new query runner - single connection where we'll execute all our operations - const queryRunner = this.queryRunner || this.connection.createQueryRunner("master"); + const queryRunner = this.queryRunner || this.connection.createQueryRunner(); // save data in the query runner - this is useful functionality to share data from outside of the world // with third classes - like subscribers and listener methods diff --git a/src/query-builder/QueryBuilder.ts b/src/query-builder/QueryBuilder.ts index c883b5ad074..a1756f351b4 100644 --- a/src/query-builder/QueryBuilder.ts +++ b/src/query-builder/QueryBuilder.ts @@ -860,7 +860,7 @@ export abstract class QueryBuilder { * Creates a query builder used to execute sql queries inside this query builder. */ protected obtainQueryRunner() { - return this.queryRunner || this.connection.createQueryRunner("master"); + return this.queryRunner || this.connection.createQueryRunner(); } } diff --git a/src/query-runner/BaseQueryRunner.ts b/src/query-runner/BaseQueryRunner.ts index 7ab8ebf1feb..0cc41ce57ef 100644 --- a/src/query-runner/BaseQueryRunner.ts +++ b/src/query-runner/BaseQueryRunner.ts @@ -9,6 +9,7 @@ import {Table} from "../schema-builder/table/Table"; import {EntityManager} from "../entity-manager/EntityManager"; import {TableColumn} from "../schema-builder/table/TableColumn"; import {Broadcaster} from "../subscriber/Broadcaster"; +import {ReplicationMode} from "../driver/types/ReplicationMode"; export abstract class BaseQueryRunner { @@ -82,7 +83,7 @@ export abstract class BaseQueryRunner { * Used for replication. * If replication is not setup its value is ignored. */ - protected mode: "master"|"slave"; + protected mode: ReplicationMode; // ------------------------------------------------------------------------- // Public Abstract Methods diff --git a/src/schema-builder/MongoSchemaBuilder.ts b/src/schema-builder/MongoSchemaBuilder.ts index 1168c9dd2e9..5f580581f9a 100644 --- a/src/schema-builder/MongoSchemaBuilder.ts +++ b/src/schema-builder/MongoSchemaBuilder.ts @@ -1,6 +1,6 @@ import {Connection} from "../connection/Connection"; import {SchemaBuilder} from "./SchemaBuilder"; -import {MongoDriver} from "../driver/mongodb/MongoDriver"; +import {MongoQueryRunner} from "../driver/mongodb/MongoQueryRunner"; import {SqlInMemory} from "../driver/SqlInMemory"; import {MongodbIndexOptions} from "../driver/mongodb/typings"; @@ -35,7 +35,7 @@ export class MongoSchemaBuilder implements SchemaBuilder { * Creates complete schemas for the given entity metadatas. */ async build(): Promise { - const queryRunner = (this.connection.driver as MongoDriver).createQueryRunner(); + const queryRunner = this.connection.createQueryRunner() as MongoQueryRunner; const promises: Promise[] = []; this.connection.entityMetadatas.forEach(metadata => { metadata.indices.forEach(index => { diff --git a/src/schema-builder/RdbmsSchemaBuilder.ts b/src/schema-builder/RdbmsSchemaBuilder.ts index d5bd9f2aa0f..f7c11afbd81 100644 --- a/src/schema-builder/RdbmsSchemaBuilder.ts +++ b/src/schema-builder/RdbmsSchemaBuilder.ts @@ -65,7 +65,7 @@ export class RdbmsSchemaBuilder implements SchemaBuilder { * Creates complete schemas for the given entity metadatas. */ async build(): Promise { - this.queryRunner = this.connection.createQueryRunner("master"); + this.queryRunner = this.connection.createQueryRunner(); // CockroachDB implements asynchronous schema sync operations which can not been executed in transaction. // E.g. if you try to DROP column and ADD it again in the same transaction, crdb throws error. if (!(this.connection.driver instanceof CockroachDriver)) @@ -104,7 +104,7 @@ export class RdbmsSchemaBuilder implements SchemaBuilder { * Returns sql queries to be executed by schema builder. */ async log(): Promise { - this.queryRunner = this.connection.createQueryRunner("master"); + this.queryRunner = this.connection.createQueryRunner(); try { const tablePaths = this.entityToSyncMetadatas.map(metadata => metadata.tablePath); // TODO: typeorm_metadata table needs only for Views for now. diff --git a/test/functional/cache/provider/MockQueryResultCache.ts b/test/functional/cache/provider/MockQueryResultCache.ts index 1d2993911f8..de1335b0891 100644 --- a/test/functional/cache/provider/MockQueryResultCache.ts +++ b/test/functional/cache/provider/MockQueryResultCache.ts @@ -229,7 +229,7 @@ export class MockQueryResultCache implements QueryResultCache { if (queryRunner) return queryRunner; - return this.connection.createQueryRunner("master"); + return this.connection.createQueryRunner(); } } From 1b29591880cf44e28998d63c0dcd77dc80d2e6ff Mon Sep 17 00:00:00 2001 From: James Ward Date: Mon, 21 Sep 2020 06:32:14 -0400 Subject: [PATCH 083/212] refactor: drop promise utils (#6746) * stop using PromiseUtils.create & extractValue as they're doing nothing because we never use PromiseUtils.create, PromiseUtils.extract was technically never used either - the only case we were using this was in a test where we can replace it with Promise.resolve * stop using PromiseUtils.settle in test 1014 there was no reason to use this call in the test as it was not using the results and only used the `Promise.all` functionality * use Promise.all instead of PromiseUtils.runInSequence in tests in these cases of PromiseUtils.runInSequence in tests there was no need for us to be running them in sequence - so instead we could use Promise.all & Array.map for a replacement. removes the dependency on PromiseUtils & also speeds up our tests * run tests sequentially for those that deal with ActiveRecord because the activerecord mechanism creates a "global" scope through the class that ActiveRecord is applied to we have to run through the connections sequentially or end up with them being all over the place as far as what activerecord model is connected to what connection * use standard async/await + for/of instead of runInSequence in cases where actual order of the runs matter we can do for/of and then await any of the results - because none of the usages of runInSequence that rely on the correct order actually use the results * use Promise.all on runInSequence cases where order doesn't matter * drop PromiseUtils altogether * sequentially run when dealing with QueryRunner queryrunner is not 'thread-safe' or async safe * drop the test to lookup by Promise before, the test wasn't validating that you could lookup by promise the test was verifying that if you used something that wasn't a promise but instead had a magic __value__ variable you'd get a lookup that's not a promise, unfortunately I can't find that a promise may be passed into the find options anywhere in the documentation so I've removed this test --- src/connection/Connection.ts | 6 +- .../AuroraDataApiQueryRunner.ts | 14 +- .../cockroachdb/CockroachQueryRunner.ts | 41 +++-- src/driver/mysql/MysqlQueryRunner.ts | 14 +- src/driver/oracle/OracleQueryRunner.ts | 14 +- src/driver/postgres/PostgresQueryRunner.ts | 37 ++-- src/driver/sap/SapQueryRunner.ts | 14 +- src/driver/sqlserver/SqlServerQueryRunner.ts | 14 +- src/index.ts | 4 +- src/metadata/ColumnMetadata.ts | 17 +- src/migration/MigrationExecutor.ts | 7 +- src/persistence/EntityPersistExecutor.ts | 5 +- src/persistence/SubjectExecutor.ts | 13 +- src/query-runner/BaseQueryRunner.ts | 13 +- src/schema-builder/RdbmsSchemaBuilder.ts | 170 +++++++++--------- src/util/PromiseUtils.ts | 63 ------- test/functional/connection/connection.ts | 3 +- test/functional/entity-model/entity-model.ts | 116 ++++++------ .../conditional-index/conditional-index.ts | 2 +- .../repository-find-operators.ts | 31 ++-- .../soft-delete/entity-soft-remove.ts | 23 +-- .../schema-builder/change-check-constraint.ts | 13 +- .../schema-builder/change-column.ts | 30 ++-- .../change-exclusion-constraint.ts | 13 +- .../functional/schema-builder/change-index.ts | 17 +- .../change-unique-constraint.ts | 13 +- test/github-issues/1014/issue-1014.ts | 11 +- test/github-issues/1055/issue-1055.ts | 23 --- test/github-issues/1261/issue-1261.ts | 8 +- test/github-issues/1805/issue-1805.ts | 18 +- test/github-issues/2313/issue-2313.ts | 53 +++--- test/github-issues/3422/issue-3422.ts | 5 +- test/github-issues/3496/issue-3496.ts | 5 +- test/github-issues/3534/issue-3534.ts | 6 +- test/github-issues/3536/issue-3536.ts | 5 +- test/github-issues/3551/issue-3551.ts | 7 +- test/utils/test-utils.ts | 10 +- 37 files changed, 419 insertions(+), 439 deletions(-) delete mode 100644 src/util/PromiseUtils.ts diff --git a/src/connection/Connection.ts b/src/connection/Connection.ts index d1487cda804..9745cb70069 100644 --- a/src/connection/Connection.ts +++ b/src/connection/Connection.ts @@ -36,7 +36,6 @@ import {EntitySchema} from "../"; import {SqlServerDriver} from "../driver/sqlserver/SqlServerDriver"; import {MysqlDriver} from "../driver/mysql/MysqlDriver"; import {ObjectUtils} from "../util/ObjectUtils"; -import {PromiseUtils} from "../"; import {IsolationLevel} from "../driver/types/IsolationLevel"; import {AuroraDataApiDriver} from "../driver/aurora-data-api/AuroraDataApiDriver"; import {DriverUtils} from "../driver/DriverUtils"; @@ -268,7 +267,10 @@ export class Connection { if (metadata.database && databases.indexOf(metadata.database) === -1) databases.push(metadata.database); }); - await PromiseUtils.runInSequence(databases, database => queryRunner.clearDatabase(database)); + + for (const database of databases) { + await queryRunner.clearDatabase(database); + } } else { await queryRunner.clearDatabase(); } diff --git a/src/driver/aurora-data-api/AuroraDataApiQueryRunner.ts b/src/driver/aurora-data-api/AuroraDataApiQueryRunner.ts index 14d3d68bab0..b2e940486d1 100644 --- a/src/driver/aurora-data-api/AuroraDataApiQueryRunner.ts +++ b/src/driver/aurora-data-api/AuroraDataApiQueryRunner.ts @@ -16,7 +16,7 @@ import {TableIndexOptions} from "../../schema-builder/options/TableIndexOptions" import {TableUnique} from "../../schema-builder/table/TableUnique"; import {BaseQueryRunner} from "../../query-runner/BaseQueryRunner"; import {Broadcaster} from "../../subscriber/Broadcaster"; -import {ColumnType, PromiseUtils} from "../../index"; +import {ColumnType} from "../../index"; import {TableCheck} from "../../schema-builder/table/TableCheck"; import {IsolationLevel} from "../types/IsolationLevel"; import {TableExclusion} from "../../schema-builder/table/TableExclusion"; @@ -469,7 +469,9 @@ export class AuroraDataApiQueryRunner extends BaseQueryRunner implements QueryRu * Creates a new columns from the column in the table. */ async addColumns(tableOrName: Table|string, columns: TableColumn[]): Promise { - await PromiseUtils.runInSequence(columns, column => this.addColumn(tableOrName, column)); + for (const column of columns) { + await this.addColumn(tableOrName, column); + } } /** @@ -682,7 +684,9 @@ export class AuroraDataApiQueryRunner extends BaseQueryRunner implements QueryRu * Changes a column in the table. */ async changeColumns(tableOrName: Table|string, changedColumns: { newColumn: TableColumn, oldColumn: TableColumn }[]): Promise { - await PromiseUtils.runInSequence(changedColumns, changedColumn => this.changeColumn(tableOrName, changedColumn.oldColumn, changedColumn.newColumn)); + for (const {oldColumn, newColumn} of changedColumns) { + await this.changeColumn(tableOrName, oldColumn, newColumn) + } } /** @@ -774,7 +778,9 @@ export class AuroraDataApiQueryRunner extends BaseQueryRunner implements QueryRu * Drops the columns in the table. */ async dropColumns(tableOrName: Table|string, columns: TableColumn[]): Promise { - await PromiseUtils.runInSequence(columns, column => this.dropColumn(tableOrName, column)); + for (const column of columns) { + await this.dropColumn(tableOrName, column); + } } /** diff --git a/src/driver/cockroachdb/CockroachQueryRunner.ts b/src/driver/cockroachdb/CockroachQueryRunner.ts index 1f97ba61cb2..eeb97d510c5 100644 --- a/src/driver/cockroachdb/CockroachQueryRunner.ts +++ b/src/driver/cockroachdb/CockroachQueryRunner.ts @@ -17,7 +17,6 @@ import {TableIndexOptions} from "../../schema-builder/options/TableIndexOptions" import {TableUnique} from "../../schema-builder/table/TableUnique"; import {BaseQueryRunner} from "../../query-runner/BaseQueryRunner"; import {OrmUtils} from "../../util/OrmUtils"; -import {PromiseUtils} from "../../"; import {TableCheck} from "../../schema-builder/table/TableCheck"; import {ColumnType} from "../../index"; import {IsolationLevel} from "../types/IsolationLevel"; @@ -159,7 +158,9 @@ export class CockroachQueryRunner extends BaseQueryRunner implements QueryRunner } catch (e) { if (e.code === "40001") { await this.query("ROLLBACK TO SAVEPOINT cockroach_restart"); - await PromiseUtils.runInSequence(this.queries, q => this.query(q.query, q.parameters)); + for (const q of this.queries) { + await this.query(q.query, q.parameters); + } await this.commitTransaction(); } } @@ -594,7 +595,9 @@ export class CockroachQueryRunner extends BaseQueryRunner implements QueryRunner * Creates a new columns from the column in the table. */ async addColumns(tableOrName: Table|string, columns: TableColumn[]): Promise { - await PromiseUtils.runInSequence(columns, column => this.addColumn(tableOrName, column)); + for (const column of columns) { + await this.addColumn(tableOrName, column); + } } /** @@ -844,7 +847,9 @@ export class CockroachQueryRunner extends BaseQueryRunner implements QueryRunner * Changes a column in the table. */ async changeColumns(tableOrName: Table|string, changedColumns: { newColumn: TableColumn, oldColumn: TableColumn }[]): Promise { - await PromiseUtils.runInSequence(changedColumns, changedColumn => this.changeColumn(tableOrName, changedColumn.oldColumn, changedColumn.newColumn)); + for (const {oldColumn, newColumn} of changedColumns) { + await this.changeColumn(tableOrName, oldColumn, newColumn); + } } /** @@ -923,7 +928,9 @@ export class CockroachQueryRunner extends BaseQueryRunner implements QueryRunner * Drops the columns in the table. */ async dropColumns(tableOrName: Table|string, columns: TableColumn[]): Promise { - await PromiseUtils.runInSequence(columns, column => this.dropColumn(tableOrName, column)); + for (const column of columns) { + await this.dropColumn(tableOrName, column); + } } /** @@ -1014,7 +1021,9 @@ export class CockroachQueryRunner extends BaseQueryRunner implements QueryRunner * Creates new unique constraints. */ async createUniqueConstraints(tableOrName: Table|string, uniqueConstraints: TableUnique[]): Promise { - await PromiseUtils.runInSequence(uniqueConstraints, uniqueConstraint => this.createUniqueConstraint(tableOrName, uniqueConstraint)); + for (const uniqueConstraint of uniqueConstraints) { + await this.createUniqueConstraint(tableOrName, uniqueConstraint); + } } /** @@ -1038,7 +1047,9 @@ export class CockroachQueryRunner extends BaseQueryRunner implements QueryRunner * Drops unique constraints. */ async dropUniqueConstraints(tableOrName: Table|string, uniqueConstraints: TableUnique[]): Promise { - await PromiseUtils.runInSequence(uniqueConstraints, uniqueConstraint => this.dropUniqueConstraint(tableOrName, uniqueConstraint)); + for (const uniqueConstraint of uniqueConstraints) { + await this.dropUniqueConstraint(tableOrName, uniqueConstraint); + } } /** @@ -1136,7 +1147,9 @@ export class CockroachQueryRunner extends BaseQueryRunner implements QueryRunner * Creates a new foreign keys. */ async createForeignKeys(tableOrName: Table|string, foreignKeys: TableForeignKey[]): Promise { - await PromiseUtils.runInSequence(foreignKeys, foreignKey => this.createForeignKey(tableOrName, foreignKey)); + for (const foreignKey of foreignKeys) { + await this.createForeignKey(tableOrName, foreignKey); + } } /** @@ -1158,7 +1171,9 @@ export class CockroachQueryRunner extends BaseQueryRunner implements QueryRunner * Drops a foreign keys from the table. */ async dropForeignKeys(tableOrName: Table|string, foreignKeys: TableForeignKey[]): Promise { - await PromiseUtils.runInSequence(foreignKeys, foreignKey => this.dropForeignKey(tableOrName, foreignKey)); + for (const foreignKey of foreignKeys) { + await this.dropForeignKey(tableOrName, foreignKey); + } } /** @@ -1196,7 +1211,9 @@ export class CockroachQueryRunner extends BaseQueryRunner implements QueryRunner * Creates a new indices */ async createIndices(tableOrName: Table|string, indices: TableIndex[]): Promise { - await PromiseUtils.runInSequence(indices, index => this.createIndex(tableOrName, index)); + for (const index of indices) { + await this.createIndex(tableOrName, index); + } } /** @@ -1218,7 +1235,9 @@ export class CockroachQueryRunner extends BaseQueryRunner implements QueryRunner * Drops an indices from the table. */ async dropIndices(tableOrName: Table|string, indices: TableIndex[]): Promise { - await PromiseUtils.runInSequence(indices, index => this.dropIndex(tableOrName, index)); + for (const index of indices) { + await this.dropIndex(tableOrName, index); + } } /** diff --git a/src/driver/mysql/MysqlQueryRunner.ts b/src/driver/mysql/MysqlQueryRunner.ts index daee2507145..9d294492199 100644 --- a/src/driver/mysql/MysqlQueryRunner.ts +++ b/src/driver/mysql/MysqlQueryRunner.ts @@ -17,7 +17,7 @@ import {TableIndexOptions} from "../../schema-builder/options/TableIndexOptions" import {TableUnique} from "../../schema-builder/table/TableUnique"; import {BaseQueryRunner} from "../../query-runner/BaseQueryRunner"; import {Broadcaster} from "../../subscriber/Broadcaster"; -import {ColumnType, PromiseUtils} from "../../index"; +import {ColumnType} from "../../index"; import {TableCheck} from "../../schema-builder/table/TableCheck"; import {IsolationLevel} from "../types/IsolationLevel"; import {TableExclusion} from "../../schema-builder/table/TableExclusion"; @@ -519,7 +519,9 @@ export class MysqlQueryRunner extends BaseQueryRunner implements QueryRunner { * Creates a new columns from the column in the table. */ async addColumns(tableOrName: Table|string, columns: TableColumn[]): Promise { - await PromiseUtils.runInSequence(columns, column => this.addColumn(tableOrName, column)); + for (const column of columns) { + await this.addColumn(tableOrName, column); + } } /** @@ -734,7 +736,9 @@ export class MysqlQueryRunner extends BaseQueryRunner implements QueryRunner { * Changes a column in the table. */ async changeColumns(tableOrName: Table|string, changedColumns: { newColumn: TableColumn, oldColumn: TableColumn }[]): Promise { - await PromiseUtils.runInSequence(changedColumns, changedColumn => this.changeColumn(tableOrName, changedColumn.oldColumn, changedColumn.newColumn)); + for (const {oldColumn, newColumn} of changedColumns) { + await this.changeColumn(tableOrName, oldColumn, newColumn); + } } /** @@ -826,7 +830,9 @@ export class MysqlQueryRunner extends BaseQueryRunner implements QueryRunner { * Drops the columns in the table. */ async dropColumns(tableOrName: Table|string, columns: TableColumn[]): Promise { - await PromiseUtils.runInSequence(columns, column => this.dropColumn(tableOrName, column)); + for (const column of columns) { + await this.dropColumn(tableOrName, column); + } } /** diff --git a/src/driver/oracle/OracleQueryRunner.ts b/src/driver/oracle/OracleQueryRunner.ts index f4187da3281..52972434c90 100644 --- a/src/driver/oracle/OracleQueryRunner.ts +++ b/src/driver/oracle/OracleQueryRunner.ts @@ -17,7 +17,7 @@ import {Broadcaster} from "../../subscriber/Broadcaster"; import {BaseQueryRunner} from "../../query-runner/BaseQueryRunner"; import {OrmUtils} from "../../util/OrmUtils"; import {TableCheck} from "../../schema-builder/table/TableCheck"; -import {ColumnType, PromiseUtils} from "../../index"; +import {ColumnType} from "../../index"; import {IsolationLevel} from "../types/IsolationLevel"; import {TableExclusion} from "../../schema-builder/table/TableExclusion"; import {ReplicationMode} from "../types/ReplicationMode"; @@ -507,7 +507,9 @@ export class OracleQueryRunner extends BaseQueryRunner implements QueryRunner { * Creates a new columns from the column in the table. */ async addColumns(tableOrName: Table|string, columns: TableColumn[]): Promise { - await PromiseUtils.runInSequence(columns, column => this.addColumn(tableOrName, column)); + for (const column of columns) { + await this.addColumn(tableOrName, column); + } } /** @@ -734,7 +736,9 @@ export class OracleQueryRunner extends BaseQueryRunner implements QueryRunner { * Changes a column in the table. */ async changeColumns(tableOrName: Table|string, changedColumns: { newColumn: TableColumn, oldColumn: TableColumn }[]): Promise { - await PromiseUtils.runInSequence(changedColumns, changedColumn => this.changeColumn(tableOrName, changedColumn.oldColumn, changedColumn.newColumn)); + for (const {oldColumn, newColumn} of changedColumns) { + await this.changeColumn(tableOrName, oldColumn, newColumn); + } } /** @@ -806,7 +810,9 @@ export class OracleQueryRunner extends BaseQueryRunner implements QueryRunner { * Drops the columns in the table. */ async dropColumns(tableOrName: Table|string, columns: TableColumn[]): Promise { - await PromiseUtils.runInSequence(columns, column => this.dropColumn(tableOrName, column)); + for (const column of columns) { + await this.dropColumn(tableOrName, column); + } } /** diff --git a/src/driver/postgres/PostgresQueryRunner.ts b/src/driver/postgres/PostgresQueryRunner.ts index f34b0b92a63..e34f2d71946 100644 --- a/src/driver/postgres/PostgresQueryRunner.ts +++ b/src/driver/postgres/PostgresQueryRunner.ts @@ -1,4 +1,3 @@ -import {PromiseUtils} from "../../"; import {ObjectLiteral} from "../../common/ObjectLiteral"; import {QueryFailedError} from "../../error/QueryFailedError"; import {QueryRunnerAlreadyReleasedError} from "../../error/QueryRunnerAlreadyReleasedError"; @@ -574,7 +573,9 @@ export class PostgresQueryRunner extends BaseQueryRunner implements QueryRunner * Creates a new columns from the column in the table. */ async addColumns(tableOrName: Table|string, columns: TableColumn[]): Promise { - await PromiseUtils.runInSequence(columns, column => this.addColumn(tableOrName, column)); + for (const column of columns) { + await this.addColumn(tableOrName, column); + } } /** @@ -892,7 +893,9 @@ export class PostgresQueryRunner extends BaseQueryRunner implements QueryRunner * Changes a column in the table. */ async changeColumns(tableOrName: Table|string, changedColumns: { newColumn: TableColumn, oldColumn: TableColumn }[]): Promise { - await PromiseUtils.runInSequence(changedColumns, changedColumn => this.changeColumn(tableOrName, changedColumn.oldColumn, changedColumn.newColumn)); + for (const {oldColumn, newColumn} of changedColumns) { + await this.changeColumn(tableOrName, oldColumn, newColumn); + } } /** @@ -976,7 +979,9 @@ export class PostgresQueryRunner extends BaseQueryRunner implements QueryRunner * Drops the columns in the table. */ async dropColumns(tableOrName: Table|string, columns: TableColumn[]): Promise { - await PromiseUtils.runInSequence(columns, column => this.dropColumn(tableOrName, column)); + for (const column of columns) { + await this.dropColumn(tableOrName, column); + } } /** @@ -1065,7 +1070,9 @@ export class PostgresQueryRunner extends BaseQueryRunner implements QueryRunner * Creates new unique constraints. */ async createUniqueConstraints(tableOrName: Table|string, uniqueConstraints: TableUnique[]): Promise { - await PromiseUtils.runInSequence(uniqueConstraints, uniqueConstraint => this.createUniqueConstraint(tableOrName, uniqueConstraint)); + for (const uniqueConstraint of uniqueConstraints) { + await this.createUniqueConstraint(tableOrName, uniqueConstraint); + } } /** @@ -1087,7 +1094,9 @@ export class PostgresQueryRunner extends BaseQueryRunner implements QueryRunner * Drops unique constraints. */ async dropUniqueConstraints(tableOrName: Table|string, uniqueConstraints: TableUnique[]): Promise { - await PromiseUtils.runInSequence(uniqueConstraints, uniqueConstraint => this.dropUniqueConstraint(tableOrName, uniqueConstraint)); + for (const uniqueConstraint of uniqueConstraints) { + await this.dropUniqueConstraint(tableOrName, uniqueConstraint); + } } /** @@ -1204,7 +1213,9 @@ export class PostgresQueryRunner extends BaseQueryRunner implements QueryRunner * Creates a new foreign keys. */ async createForeignKeys(tableOrName: Table|string, foreignKeys: TableForeignKey[]): Promise { - await PromiseUtils.runInSequence(foreignKeys, foreignKey => this.createForeignKey(tableOrName, foreignKey)); + for (const foreignKey of foreignKeys) { + await this.createForeignKey(tableOrName, foreignKey); + } } /** @@ -1226,7 +1237,9 @@ export class PostgresQueryRunner extends BaseQueryRunner implements QueryRunner * Drops a foreign keys from the table. */ async dropForeignKeys(tableOrName: Table|string, foreignKeys: TableForeignKey[]): Promise { - await PromiseUtils.runInSequence(foreignKeys, foreignKey => this.dropForeignKey(tableOrName, foreignKey)); + for (const foreignKey of foreignKeys) { + await this.dropForeignKey(tableOrName, foreignKey); + } } /** @@ -1249,7 +1262,9 @@ export class PostgresQueryRunner extends BaseQueryRunner implements QueryRunner * Creates a new indices */ async createIndices(tableOrName: Table|string, indices: TableIndex[]): Promise { - await PromiseUtils.runInSequence(indices, index => this.createIndex(tableOrName, index)); + for (const index of indices) { + await this.createIndex(tableOrName, index); + } } /** @@ -1271,7 +1286,9 @@ export class PostgresQueryRunner extends BaseQueryRunner implements QueryRunner * Drops an indices from the table. */ async dropIndices(tableOrName: Table|string, indices: TableIndex[]): Promise { - await PromiseUtils.runInSequence(indices, index => this.dropIndex(tableOrName, index)); + for (const index of indices) { + await this.dropIndex(tableOrName, index); + } } /** diff --git a/src/driver/sap/SapQueryRunner.ts b/src/driver/sap/SapQueryRunner.ts index dfb955b0961..d070176d9d7 100644 --- a/src/driver/sap/SapQueryRunner.ts +++ b/src/driver/sap/SapQueryRunner.ts @@ -2,7 +2,7 @@ import {ObjectLiteral} from "../../common/ObjectLiteral"; import {QueryRunnerAlreadyReleasedError} from "../../error/QueryRunnerAlreadyReleasedError"; import {TransactionAlreadyStartedError} from "../../error/TransactionAlreadyStartedError"; import {TransactionNotStartedError} from "../../error/TransactionNotStartedError"; -import {ColumnType, PromiseUtils, QueryFailedError} from "../../index"; +import {ColumnType, QueryFailedError} from "../../index"; import {ReadStream} from "../../platform/PlatformTools"; import {BaseQueryRunner} from "../../query-runner/BaseQueryRunner"; import {QueryRunner} from "../../query-runner/QueryRunner"; @@ -634,7 +634,9 @@ export class SapQueryRunner extends BaseQueryRunner implements QueryRunner { * Creates a new columns from the column in the table. */ async addColumns(tableOrName: Table|string, columns: TableColumn[]): Promise { - await PromiseUtils.runInSequence(columns, column => this.addColumn(tableOrName, column)); + for (const column of columns) { + await this.addColumn(tableOrName, column); + } } /** @@ -870,7 +872,9 @@ export class SapQueryRunner extends BaseQueryRunner implements QueryRunner { * Changes a column in the table. */ async changeColumns(tableOrName: Table|string, changedColumns: { newColumn: TableColumn, oldColumn: TableColumn }[]): Promise { - await PromiseUtils.runInSequence(changedColumns, changedColumn => this.changeColumn(tableOrName, changedColumn.oldColumn, changedColumn.newColumn)); + for (const {oldColumn, newColumn} of changedColumns) { + await this.changeColumn(tableOrName, oldColumn, newColumn) + } } /** @@ -990,7 +994,9 @@ export class SapQueryRunner extends BaseQueryRunner implements QueryRunner { * Drops the columns in the table. */ async dropColumns(tableOrName: Table|string, columns: TableColumn[]): Promise { - await PromiseUtils.runInSequence(columns, column => this.dropColumn(tableOrName, column)); + for (const column of columns) { + await this.dropColumn(tableOrName, column); + } } /** diff --git a/src/driver/sqlserver/SqlServerQueryRunner.ts b/src/driver/sqlserver/SqlServerQueryRunner.ts index 8776738c53e..55e1c325a5c 100644 --- a/src/driver/sqlserver/SqlServerQueryRunner.ts +++ b/src/driver/sqlserver/SqlServerQueryRunner.ts @@ -3,7 +3,7 @@ import {QueryFailedError} from "../../error/QueryFailedError"; import {QueryRunnerAlreadyReleasedError} from "../../error/QueryRunnerAlreadyReleasedError"; import {TransactionAlreadyStartedError} from "../../error/TransactionAlreadyStartedError"; import {TransactionNotStartedError} from "../../error/TransactionNotStartedError"; -import {ColumnType, PromiseUtils} from "../../index"; +import {ColumnType} from "../../index"; import {ReadStream} from "../../platform/PlatformTools"; import {BaseQueryRunner} from "../../query-runner/BaseQueryRunner"; import {QueryRunner} from "../../query-runner/QueryRunner"; @@ -710,7 +710,9 @@ export class SqlServerQueryRunner extends BaseQueryRunner implements QueryRunner * Creates a new columns from the column in the table. */ async addColumns(tableOrName: Table|string, columns: TableColumn[]): Promise { - await PromiseUtils.runInSequence(columns, column => this.addColumn(tableOrName, column)); + for (const column of columns) { + await this.addColumn(tableOrName, column); + } } /** @@ -977,7 +979,9 @@ export class SqlServerQueryRunner extends BaseQueryRunner implements QueryRunner * Changes a column in the table. */ async changeColumns(tableOrName: Table|string, changedColumns: { newColumn: TableColumn, oldColumn: TableColumn }[]): Promise { - await PromiseUtils.runInSequence(changedColumns, changedColumn => this.changeColumn(tableOrName, changedColumn.oldColumn, changedColumn.newColumn)); + for (const {oldColumn, newColumn} of changedColumns) { + await this.changeColumn(tableOrName, oldColumn, newColumn); + } } /** @@ -1057,7 +1061,9 @@ export class SqlServerQueryRunner extends BaseQueryRunner implements QueryRunner * Drops the columns in the table. */ async dropColumns(tableOrName: Table|string, columns: TableColumn[]): Promise { - await PromiseUtils.runInSequence(columns, column => this.dropColumn(tableOrName, column)); + for (const column of columns) { + await this.dropColumn(tableOrName, column); + } } /** diff --git a/src/index.ts b/src/index.ts index ff39f966ba5..635876fb9d2 100644 --- a/src/index.ts +++ b/src/index.ts @@ -13,7 +13,6 @@ import {PlatformTools} from "./platform/PlatformTools"; import {TreeRepository} from "./repository/TreeRepository"; import {MongoRepository} from "./repository/MongoRepository"; import {ConnectionOptionsReader} from "./connection/ConnectionOptionsReader"; -import {PromiseUtils} from "./util/PromiseUtils"; import {MongoEntityManager} from "./entity-manager/MongoEntityManager"; import {SqljsEntityManager} from "./entity-manager/SqljsEntityManager"; import {SelectQueryBuilder} from "./query-builder/SelectQueryBuilder"; @@ -158,7 +157,6 @@ export {EntitySchemaColumnOptions} from "./entity-schema/EntitySchemaColumnOptio export {EntitySchemaIndexOptions} from "./entity-schema/EntitySchemaIndexOptions"; export {EntitySchemaRelationOptions} from "./entity-schema/EntitySchemaRelationOptions"; export {ColumnType} from "./driver/types/ColumnTypes"; -export {PromiseUtils} from "./util/PromiseUtils"; // ------------------------------------------------------------------------- // Deprecated @@ -241,7 +239,7 @@ export async function createConnections(options?: ConnectionOptions[]): Promise< if (!options) options = await new ConnectionOptionsReader().all(); const connections = options.map(options => getConnectionManager().create(options)); - return PromiseUtils.runInSequence(connections, connection => connection.connect()); + return Promise.all(connections.map(connection => connection.connect())); } /** diff --git a/src/metadata/ColumnMetadata.ts b/src/metadata/ColumnMetadata.ts index 395c0f4faf7..97f2ca23292 100644 --- a/src/metadata/ColumnMetadata.ts +++ b/src/metadata/ColumnMetadata.ts @@ -8,7 +8,6 @@ import {Connection} from "../connection/Connection"; import {OrmUtils} from "../util/OrmUtils"; import {ValueTransformer} from "../decorator/options/ValueTransformer"; import {MongoDriver} from "../driver/mongodb/MongoDriver"; -import {PromiseUtils} from "../util/PromiseUtils"; import {FindOperator} from "../find-options/FindOperator"; import {ApplyValueTransformers} from "../util/ApplyValueTransformers"; @@ -592,21 +591,21 @@ export class ColumnMetadata { if (this.relationMetadata && this.referencedColumn) { const relatedEntity = this.relationMetadata.getEntityValue(embeddedObject); if (relatedEntity && relatedEntity instanceof Object && !(relatedEntity instanceof FindOperator)) { - value = this.referencedColumn.getEntityValue(PromiseUtils.extractValue(relatedEntity)); + value = this.referencedColumn.getEntityValue(relatedEntity); } else if (embeddedObject[this.propertyName] && embeddedObject[this.propertyName] instanceof Object && !(embeddedObject[this.propertyName] instanceof FindOperator)) { - value = this.referencedColumn.getEntityValue(PromiseUtils.extractValue(embeddedObject[this.propertyName])); + value = this.referencedColumn.getEntityValue(embeddedObject[this.propertyName]); } else { - value = PromiseUtils.extractValue(embeddedObject[this.propertyName]); + value = embeddedObject[this.propertyName]; } } else if (this.referencedColumn) { - value = this.referencedColumn.getEntityValue(PromiseUtils.extractValue(embeddedObject[this.propertyName])); + value = this.referencedColumn.getEntityValue(embeddedObject[this.propertyName]); } else { - value = PromiseUtils.extractValue(embeddedObject[this.propertyName]); + value = embeddedObject[this.propertyName]; } } @@ -614,17 +613,17 @@ export class ColumnMetadata { if (this.relationMetadata && this.referencedColumn) { const relatedEntity = this.relationMetadata.getEntityValue(entity); if (relatedEntity && relatedEntity instanceof Object && !(relatedEntity instanceof FindOperator) && !(relatedEntity instanceof Function)) { - value = this.referencedColumn.getEntityValue(PromiseUtils.extractValue(relatedEntity)); + value = this.referencedColumn.getEntityValue(relatedEntity); } else if (entity[this.propertyName] && entity[this.propertyName] instanceof Object && !(entity[this.propertyName] instanceof FindOperator) && !(entity[this.propertyName] instanceof Function)) { - value = this.referencedColumn.getEntityValue(PromiseUtils.extractValue(entity[this.propertyName])); + value = this.referencedColumn.getEntityValue(entity[this.propertyName]); } else { value = entity[this.propertyName]; } } else if (this.referencedColumn) { - value = this.referencedColumn.getEntityValue(PromiseUtils.extractValue(entity[this.propertyName])); + value = this.referencedColumn.getEntityValue(entity[this.propertyName]); } else { value = entity[this.propertyName]; diff --git a/src/migration/MigrationExecutor.ts b/src/migration/MigrationExecutor.ts index af67fa5f462..3ec38750398 100644 --- a/src/migration/MigrationExecutor.ts +++ b/src/migration/MigrationExecutor.ts @@ -2,7 +2,6 @@ import {Table} from "../schema-builder/table/Table"; import {Connection} from "../connection/Connection"; import {Migration} from "./Migration"; import {ObjectLiteral} from "../common/ObjectLiteral"; -import {PromiseUtils} from "../util/PromiseUtils"; import {QueryRunner} from "../query-runner/QueryRunner"; import {SqlServerDriver} from "../driver/sqlserver/SqlServerDriver"; import {MssqlParameter} from "../driver/sqlserver/MssqlParameter"; @@ -218,13 +217,13 @@ export class MigrationExecutor { // run all pending migrations in a sequence try { - await PromiseUtils.runInSequence(pendingMigrations, async migration => { + for (const migration of pendingMigrations) { if (this.transaction === "each" && !queryRunner.isTransactionActive) { await queryRunner.startTransaction(); transactionStartedByUs = true; } - return migration.instance!.up(queryRunner) + await migration.instance!.up(queryRunner) .then(async () => { // now when migration is executed we need to insert record about it into the database await this.insertExecutedMigration(queryRunner, migration); // commit transaction if we started it @@ -235,7 +234,7 @@ export class MigrationExecutor { successMigrations.push(migration); this.connection.logger.logSchemaBuild(`Migration ${migration.name} has been executed successfully.`); }); - }); + } // commit transaction if we started it if (this.transaction === "all" && transactionStartedByUs) diff --git a/src/persistence/EntityPersistExecutor.ts b/src/persistence/EntityPersistExecutor.ts index e6dd62122b0..940e2f88ab0 100644 --- a/src/persistence/EntityPersistExecutor.ts +++ b/src/persistence/EntityPersistExecutor.ts @@ -13,7 +13,6 @@ import {ManyToManySubjectBuilder} from "./subject-builder/ManyToManySubjectBuild import {SubjectDatabaseEntityLoader} from "./SubjectDatabaseEntityLoader"; import {CascadesSubjectBuilder} from "./subject-builder/CascadesSubjectBuilder"; import {OrmUtils} from "../util/OrmUtils"; -import {PromiseUtils} from "../util/PromiseUtils"; /** * Persists a single entity or multiple entities - saves or removes them. @@ -144,7 +143,9 @@ export class EntityPersistExecutor { // execute all persistence operations for all entities we have // console.time("executing subject executors..."); - await PromiseUtils.runInSequence(executorsWithExecutableOperations, executor => executor.execute()); + for (const executor of executorsWithExecutableOperations) { + await executor.execute(); + } // console.timeEnd("executing subject executors..."); // commit transaction if it was started by us diff --git a/src/persistence/SubjectExecutor.ts b/src/persistence/SubjectExecutor.ts index 9db8f273a95..ec18625dd31 100644 --- a/src/persistence/SubjectExecutor.ts +++ b/src/persistence/SubjectExecutor.ts @@ -1,7 +1,6 @@ import {SapDriver} from "../driver/sap/SapDriver"; import {QueryRunner} from "../query-runner/QueryRunner"; import {Subject} from "./Subject"; -import {PromiseUtils} from "../util/PromiseUtils"; import {SubjectTopoligicalSorter} from "./SubjectTopoligicalSorter"; import {SubjectChangedColumnsComputer} from "./SubjectChangedColumnsComputer"; import {SubjectWithoutIdentifierError} from "../error/SubjectWithoutIdentifierError"; @@ -248,7 +247,7 @@ export class SubjectExecutor { const [groupedInsertSubjects, groupedInsertSubjectKeys] = this.groupBulkSubjects(this.insertSubjects, "insert"); // then we run insertion in the sequential order which is important since we have an ordered subjects - await PromiseUtils.runInSequence(groupedInsertSubjectKeys, async groupName => { + for (const groupName of groupedInsertSubjectKeys) { const subjects = groupedInsertSubjects[groupName]; // we must separately insert entities which does not have any values to insert @@ -331,7 +330,7 @@ export class SubjectExecutor { // insert subjects which must be inserted in separate requests (all default values) if (singleInsertSubjects.length > 0) { - await PromiseUtils.runInSequence(singleInsertSubjects, async subject => { + for (const subject of singleInsertSubjects) { subject.insertedValueSet = subject.createValueSetAndPopChangeMap(); // important to have because query builder sets inserted values into it // for nested set we execute additional queries @@ -359,7 +358,7 @@ export class SubjectExecutor { } else if (subject.metadata.treeType === "materialized-path") { await new MaterializedPathSubjectExecutor(this.queryRunner).insert(subject); } - }); + } } } @@ -374,7 +373,7 @@ export class SubjectExecutor { }); } }); - }); + } } /** @@ -464,7 +463,7 @@ export class SubjectExecutor { // group insertion subjects to make bulk insertions const [groupedRemoveSubjects, groupedRemoveSubjectKeys] = this.groupBulkSubjects(this.removeSubjects, "delete"); - await PromiseUtils.runInSequence(groupedRemoveSubjectKeys, async groupName => { + for (const groupName of groupedRemoveSubjectKeys) { const subjects = groupedRemoveSubjects[groupName]; const deleteMaps = subjects.map(subject => { if (!subject.identifier) @@ -493,7 +492,7 @@ export class SubjectExecutor { .callListeners(false) .execute(); } - }); + } } /** diff --git a/src/query-runner/BaseQueryRunner.ts b/src/query-runner/BaseQueryRunner.ts index 0cc41ce57ef..6e73f226e54 100644 --- a/src/query-runner/BaseQueryRunner.ts +++ b/src/query-runner/BaseQueryRunner.ts @@ -3,7 +3,6 @@ import {Query} from "../driver/Query"; import {SqlInMemory} from "../driver/SqlInMemory"; import {SqlServerConnectionOptions} from "../driver/sqlserver/SqlServerConnectionOptions"; import {View} from "../schema-builder/view/View"; -import {PromiseUtils} from "../util/PromiseUtils"; import {Connection} from "../connection/Connection"; import {Table} from "../schema-builder/table/Table"; import {EntityManager} from "../entity-manager/EntityManager"; @@ -177,14 +176,18 @@ export abstract class BaseQueryRunner { * Executes up sql queries. */ async executeMemoryUpSql(): Promise { - await PromiseUtils.runInSequence(this.sqlInMemory.upQueries, upQuery => this.query(upQuery.query, upQuery.parameters)); + for (const {query, parameters} of this.sqlInMemory.upQueries) { + await this.query(query, parameters); + } } /** * Executes down sql queries. */ async executeMemoryDownSql(): Promise { - await PromiseUtils.runInSequence(this.sqlInMemory.downQueries.reverse(), downQuery => this.query(downQuery.query, downQuery.parameters)); + for (const {query, parameters} of this.sqlInMemory.downQueries.reverse()) { + await this.query(query, parameters); + } } // ------------------------------------------------------------------------- @@ -371,7 +374,9 @@ export abstract class BaseQueryRunner { if (this.sqlMemoryMode === true) return Promise.resolve() as Promise; - await PromiseUtils.runInSequence(upQueries, upQuery => this.query(upQuery.query, upQuery.parameters)); + for (const {query, parameters} of upQueries) { + await this.query(query, parameters); + } } } diff --git a/src/schema-builder/RdbmsSchemaBuilder.ts b/src/schema-builder/RdbmsSchemaBuilder.ts index f7c11afbd81..7251efbfc64 100644 --- a/src/schema-builder/RdbmsSchemaBuilder.ts +++ b/src/schema-builder/RdbmsSchemaBuilder.ts @@ -9,7 +9,6 @@ import {TableIndex} from "./table/TableIndex"; import {QueryRunner} from "../query-runner/QueryRunner"; import {ColumnMetadata} from "../metadata/ColumnMetadata"; import {EntityMetadata} from "../metadata/EntityMetadata"; -import {PromiseUtils} from "../util/PromiseUtils"; import {Connection} from "../connection/Connection"; import {SchemaBuilder} from "./SchemaBuilder"; import {SqlInMemory} from "../driver/SqlInMemory"; @@ -179,11 +178,10 @@ export class RdbmsSchemaBuilder implements SchemaBuilder { * Drops all (old) foreign keys that exist in the tables, but do not exist in the entity metadata. */ protected async dropOldForeignKeys(): Promise { - await PromiseUtils.runInSequence(this.entityToSyncMetadatas, async metadata => { - + for (const metadata of this.entityToSyncMetadatas) { const table = this.queryRunner.loadedTables.find(table => table.name === metadata.tablePath); if (!table) - return; + continue; // find foreign keys that exist in the schemas but does not exist in the entity metadata const tableForeignKeysToDrop = table.foreignKeys.filter(tableForeignKey => { @@ -193,23 +191,22 @@ export class RdbmsSchemaBuilder implements SchemaBuilder { || (metadataFK.onUpdate && metadataFK.onUpdate !== tableForeignKey.onUpdate); }); if (tableForeignKeysToDrop.length === 0) - return; + continue; this.connection.logger.logSchemaBuild(`dropping old foreign keys of ${table.name}: ${tableForeignKeysToDrop.map(dbForeignKey => dbForeignKey.name).join(", ")}`); // drop foreign keys from the database await this.queryRunner.dropForeignKeys(table, tableForeignKeysToDrop); - }); + } } /** * Rename tables */ protected async renameTables(): Promise { - await PromiseUtils.runInSequence(this.entityToSyncMetadatas, async metadata => { - // const table = this.queryRunner.loadedTables.find(table => table.name === metadata.tablePath); - - }); + // for (const metadata of this.entityToSyncMetadatas) { + // const table = this.queryRunner.loadedTables.find(table => table.name === metadata.tablePath); + // } } /** @@ -218,13 +215,13 @@ export class RdbmsSchemaBuilder implements SchemaBuilder { * Changes only column name. If something besides name was changed, these changes will be ignored. */ protected async renameColumns(): Promise { - await PromiseUtils.runInSequence(this.entityToSyncMetadatas, async metadata => { + for (const metadata of this.entityToSyncMetadatas) { const table = this.queryRunner.loadedTables.find(table => table.name === metadata.tablePath); if (!table) - return; + continue; if (metadata.columns.length !== table.columns.length) - return; + continue; const renamedMetadataColumns = metadata.columns.filter(column => { return !table.columns.find(tableColumn => { @@ -236,7 +233,7 @@ export class RdbmsSchemaBuilder implements SchemaBuilder { }); if (renamedMetadataColumns.length === 0 || renamedMetadataColumns.length > 1) - return; + continue; const renamedTableColumns = table.columns.filter(tableColumn => { return !metadata.columns.find(column => { @@ -248,21 +245,21 @@ export class RdbmsSchemaBuilder implements SchemaBuilder { }); if (renamedTableColumns.length === 0 || renamedTableColumns.length > 1) - return; + continue; const renamedColumn = renamedTableColumns[0].clone(); renamedColumn.name = renamedMetadataColumns[0].databaseName; this.connection.logger.logSchemaBuild(`renaming column "${renamedTableColumns[0].name}" in to "${renamedColumn.name}"`); await this.queryRunner.renameColumn(table, renamedTableColumns[0], renamedColumn); - }); + } } protected async dropOldIndices(): Promise { - await PromiseUtils.runInSequence(this.entityToSyncMetadatas, async metadata => { + for (const metadata of this.entityToSyncMetadatas) { const table = this.queryRunner.loadedTables.find(table => table.name === metadata.tablePath); if (!table) - return; + continue; const dropQueries = table.indices .filter(tableIndex => { @@ -294,7 +291,7 @@ export class RdbmsSchemaBuilder implements SchemaBuilder { }); await Promise.all(dropQueries); - }); + } } protected async dropOldChecks(): Promise { @@ -302,39 +299,39 @@ export class RdbmsSchemaBuilder implements SchemaBuilder { if (this.connection.driver instanceof MysqlDriver || this.connection.driver instanceof AuroraDataApiDriver) return; - await PromiseUtils.runInSequence(this.entityToSyncMetadatas, async metadata => { + for (const metadata of this.entityToSyncMetadatas) { const table = this.queryRunner.loadedTables.find(table => table.name === metadata.tablePath); if (!table) - return; + continue; const oldChecks = table.checks.filter(tableCheck => { return !metadata.checks.find(checkMetadata => checkMetadata.name === tableCheck.name); }); if (oldChecks.length === 0) - return; + continue; this.connection.logger.logSchemaBuild(`dropping old check constraint: ${oldChecks.map(check => `"${check.name}"`).join(", ")} from table "${table.name}"`); await this.queryRunner.dropCheckConstraints(table, oldChecks); - }); + } } protected async dropCompositeUniqueConstraints(): Promise { - await PromiseUtils.runInSequence(this.entityToSyncMetadatas, async metadata => { + for (const metadata of this.entityToSyncMetadatas) { const table = this.queryRunner.loadedTables.find(table => table.name === metadata.tablePath); if (!table) - return; + continue; const compositeUniques = table.uniques.filter(tableUnique => { return tableUnique.columnNames.length > 1 && !metadata.uniques.find(uniqueMetadata => uniqueMetadata.name === tableUnique.name); }); if (compositeUniques.length === 0) - return; + continue; this.connection.logger.logSchemaBuild(`dropping old unique constraint: ${compositeUniques.map(unique => `"${unique.name}"`).join(", ")} from table "${table.name}"`); await this.queryRunner.dropUniqueConstraints(table, compositeUniques); - }); + } } protected async dropOldExclusions(): Promise { @@ -342,21 +339,21 @@ export class RdbmsSchemaBuilder implements SchemaBuilder { if (!(this.connection.driver instanceof PostgresDriver)) return; - await PromiseUtils.runInSequence(this.entityToSyncMetadatas, async metadata => { + for (const metadata of this.entityToSyncMetadatas) { const table = this.queryRunner.loadedTables.find(table => table.name === metadata.tablePath); if (!table) - return; + continue; const oldExclusions = table.exclusions.filter(tableExclusion => { return !metadata.exclusions.find(exclusionMetadata => exclusionMetadata.name === tableExclusion.name); }); if (oldExclusions.length === 0) - return; + continue; this.connection.logger.logSchemaBuild(`dropping old exclusion constraint: ${oldExclusions.map(exclusion => `"${exclusion.name}"`).join(", ")} from table "${table.name}"`); await this.queryRunner.dropExclusionConstraints(table, oldExclusions); - }); + } } /** @@ -365,7 +362,7 @@ export class RdbmsSchemaBuilder implements SchemaBuilder { * Primary key only can be created in conclusion with auto generated column. */ protected async createNewTables(): Promise { - await PromiseUtils.runInSequence(this.entityToSyncMetadatas, async metadata => { + for (const metadata of this.entityToSyncMetadatas) { // check if table does not exist yet const existTable = this.queryRunner.loadedTables.find(table => { const database = metadata.database && metadata.database !== this.connection.driver.database ? metadata.database : undefined; @@ -375,7 +372,7 @@ export class RdbmsSchemaBuilder implements SchemaBuilder { return table.name === fullTableName; }); if (existTable) - return; + continue; this.connection.logger.logSchemaBuild(`creating a new table: ${metadata.tablePath}`); @@ -383,11 +380,11 @@ export class RdbmsSchemaBuilder implements SchemaBuilder { const table = Table.create(metadata, this.connection.driver); await this.queryRunner.createTable(table, false, false); this.queryRunner.loadedTables.push(table); - }); + } } protected async createViews(): Promise { - await PromiseUtils.runInSequence(this.viewEntityToSyncMetadatas, async metadata => { + for (const metadata of this.viewEntityToSyncMetadatas) { // check if view does not exist yet const existView = this.queryRunner.loadedViews.find(view => { const database = metadata.database && metadata.database !== this.connection.driver.database ? metadata.database : undefined; @@ -398,7 +395,7 @@ export class RdbmsSchemaBuilder implements SchemaBuilder { return view.name === fullViewName && viewExpression === metadataExpression; }); if (existView) - return; + continue; this.connection.logger.logSchemaBuild(`creating a new view: ${metadata.tablePath}`); @@ -406,11 +403,11 @@ export class RdbmsSchemaBuilder implements SchemaBuilder { const view = View.create(metadata, this.connection.driver); await this.queryRunner.createView(view); this.queryRunner.loadedViews.push(view); - }); + } } protected async dropOldViews(): Promise { - await PromiseUtils.runInSequence(this.queryRunner.loadedViews, async view => { + for (const view of this.queryRunner.loadedViews) { const existViewMetadata = this.viewEntityToSyncMetadatas.find(metadata => { const database = metadata.database && metadata.database !== this.connection.driver.database ? metadata.database : undefined; const schema = metadata.schema || (this.connection.driver).options.schema; @@ -421,14 +418,14 @@ export class RdbmsSchemaBuilder implements SchemaBuilder { }); if (existViewMetadata) - return; + continue; this.connection.logger.logSchemaBuild(`dropping an old view: ${view.name}`); // drop an old view await this.queryRunner.dropView(view); this.queryRunner.loadedViews.splice(this.queryRunner.loadedViews.indexOf(view), 1); - }); + } } /** @@ -436,22 +433,23 @@ export class RdbmsSchemaBuilder implements SchemaBuilder { * We drop their keys too, since it should be safe. */ protected async dropRemovedColumns(): Promise { - await PromiseUtils.runInSequence(this.entityToSyncMetadatas, async metadata => { + for (const metadata of this.entityToSyncMetadatas) { const table = this.queryRunner.loadedTables.find(table => table.name === metadata.tablePath); - if (!table) return; + if (!table) + continue; // find columns that exist in the database but does not exist in the metadata const droppedTableColumns = table.columns.filter(tableColumn => { return !metadata.columns.find(columnMetadata => columnMetadata.databaseName === tableColumn.name); }); if (droppedTableColumns.length === 0) - return; + continue; this.connection.logger.logSchemaBuild(`columns dropped in ${table.name}: ` + droppedTableColumns.map(column => column.name).join(", ")); // drop columns from the database await this.queryRunner.dropColumns(table, droppedTableColumns); - }); + } } /** @@ -459,38 +457,38 @@ export class RdbmsSchemaBuilder implements SchemaBuilder { * Columns are created without keys. */ protected async addNewColumns(): Promise { - await PromiseUtils.runInSequence(this.entityToSyncMetadatas, async metadata => { + for (const metadata of this.entityToSyncMetadatas) { const table = this.queryRunner.loadedTables.find(table => table.name === metadata.tablePath); if (!table) - return; + continue; // find which columns are new const newColumnMetadatas = metadata.columns.filter(columnMetadata => { return !table.columns.find(tableColumn => tableColumn.name === columnMetadata.databaseName); }); if (newColumnMetadatas.length === 0) - return; + continue; // create columns in the database const newTableColumnOptions = this.metadataColumnsToTableColumnOptions(newColumnMetadatas); const newTableColumns = newTableColumnOptions.map(option => new TableColumn(option)); if (newTableColumns.length === 0) - return; + continue; this.connection.logger.logSchemaBuild(`new columns added: ` + newColumnMetadatas.map(column => column.databaseName).join(", ")); await this.queryRunner.addColumns(table, newTableColumns); - }); + } } /** * Updates composite primary keys. */ protected async updatePrimaryKeys(): Promise { - await PromiseUtils.runInSequence(this.entityToSyncMetadatas, async metadata => { + for (const metadata of this.entityToSyncMetadatas) { const table = this.queryRunner.loadedTables.find(table => table.name === metadata.tablePath); if (!table) - return; + continue; const primaryMetadataColumns = metadata.columns.filter(column => column.isPrimary); const primaryTableColumns = table.columns.filter(column => column.isPrimary); @@ -500,7 +498,7 @@ export class RdbmsSchemaBuilder implements SchemaBuilder { }); await this.queryRunner.updatePrimaryKeys(table, changedPrimaryColumns); } - }); + } } /** @@ -508,25 +506,31 @@ export class RdbmsSchemaBuilder implements SchemaBuilder { * Still don't create keys. Also we don't touch foreign keys of the changed columns. */ protected async updateExistColumns(): Promise { - await PromiseUtils.runInSequence(this.entityToSyncMetadatas, async metadata => { + for (const metadata of this.entityToSyncMetadatas) { const table = this.queryRunner.loadedTables.find(table => table.name === metadata.tablePath); if (!table) - return; + continue; const changedColumns = this.connection.driver.findChangedColumns(table.columns, metadata.columns); if (changedColumns.length === 0) - return; + continue; // drop all foreign keys that point to this column - await PromiseUtils.runInSequence(changedColumns, changedColumn => this.dropColumnReferencedForeignKeys(metadata.tablePath, changedColumn.databaseName)); + for (const changedColumn of changedColumns) { + await this.dropColumnReferencedForeignKeys(metadata.tablePath, changedColumn.databaseName); + } // drop all composite indices related to this column - await PromiseUtils.runInSequence(changedColumns, changedColumn => this.dropColumnCompositeIndices(metadata.tablePath, changedColumn.databaseName)); + for (const changedColumn of changedColumns) { + await this.dropColumnCompositeIndices(metadata.tablePath, changedColumn.databaseName); + } // drop all composite uniques related to this column // Mysql does not support unique constraints. if (!(this.connection.driver instanceof MysqlDriver || this.connection.driver instanceof AuroraDataApiDriver)) { - await PromiseUtils.runInSequence(changedColumns, changedColumn => this.dropColumnCompositeUniques(metadata.tablePath, changedColumn.databaseName)); + for (const changedColumn of changedColumns) { + await this.dropColumnCompositeUniques(metadata.tablePath, changedColumn.databaseName); + } } // generate a map of new/old columns @@ -542,32 +546,32 @@ export class RdbmsSchemaBuilder implements SchemaBuilder { }); if (newAndOldTableColumns.length === 0) - return; + continue; this.connection.logger.logSchemaBuild(`columns changed in "${table.name}". updating: ` + changedColumns.map(column => column.databaseName).join(", ")); await this.queryRunner.changeColumns(table, newAndOldTableColumns); - }); + } } /** * Creates composite indices which are missing in db yet. */ protected async createNewIndices(): Promise { - await PromiseUtils.runInSequence(this.entityToSyncMetadatas, async metadata => { + for (const metadata of this.entityToSyncMetadatas) { const table = this.queryRunner.loadedTables.find(table => table.name === metadata.tablePath); if (!table) - return; + continue; const newIndices = metadata.indices .filter(indexMetadata => !table.indices.find(tableIndex => tableIndex.name === indexMetadata.name) && indexMetadata.synchronize === true) .map(indexMetadata => TableIndex.create(indexMetadata)); if (newIndices.length === 0) - return; + continue; this.connection.logger.logSchemaBuild(`adding new indices ${newIndices.map(index => `"${index.name}"`).join(", ")} in table "${table.name}"`); await this.queryRunner.createIndices(table, newIndices); - }); + } } protected async createNewChecks(): Promise { @@ -575,42 +579,42 @@ export class RdbmsSchemaBuilder implements SchemaBuilder { if (this.connection.driver instanceof MysqlDriver || this.connection.driver instanceof AuroraDataApiDriver) return; - await PromiseUtils.runInSequence(this.entityToSyncMetadatas, async metadata => { + for (const metadata of this.entityToSyncMetadatas) { const table = this.queryRunner.loadedTables.find(table => table.name === metadata.tablePath); if (!table) - return; + continue; const newChecks = metadata.checks .filter(checkMetadata => !table.checks.find(tableCheck => tableCheck.name === checkMetadata.name)) .map(checkMetadata => TableCheck.create(checkMetadata)); if (newChecks.length === 0) - return; + continue; this.connection.logger.logSchemaBuild(`adding new check constraints: ${newChecks.map(index => `"${index.name}"`).join(", ")} in table "${table.name}"`); await this.queryRunner.createCheckConstraints(table, newChecks); - }); + } } /** * Creates composite uniques which are missing in db yet. */ protected async createCompositeUniqueConstraints(): Promise { - await PromiseUtils.runInSequence(this.entityToSyncMetadatas, async metadata => { + for (const metadata of this.entityToSyncMetadatas) { const table = this.queryRunner.loadedTables.find(table => table.name === metadata.tablePath); if (!table) - return; + continue; const compositeUniques = metadata.uniques .filter(uniqueMetadata => uniqueMetadata.columns.length > 1 && !table.uniques.find(tableUnique => tableUnique.name === uniqueMetadata.name)) .map(uniqueMetadata => TableUnique.create(uniqueMetadata)); if (compositeUniques.length === 0) - return; + continue; this.connection.logger.logSchemaBuild(`adding new unique constraints: ${compositeUniques.map(unique => `"${unique.name}"`).join(", ")} in table "${table.name}"`); await this.queryRunner.createUniqueConstraints(table, compositeUniques); - }); + } } /** @@ -621,42 +625,42 @@ export class RdbmsSchemaBuilder implements SchemaBuilder { if (!(this.connection.driver instanceof PostgresDriver)) return; - await PromiseUtils.runInSequence(this.entityToSyncMetadatas, async metadata => { + for (const metadata of this.entityToSyncMetadatas) { const table = this.queryRunner.loadedTables.find(table => table.name === metadata.tablePath); if (!table) - return; + continue; const newExclusions = metadata.exclusions .filter(exclusionMetadata => !table.exclusions.find(tableExclusion => tableExclusion.name === exclusionMetadata.name)) .map(exclusionMetadata => TableExclusion.create(exclusionMetadata)); if (newExclusions.length === 0) - return; + continue; this.connection.logger.logSchemaBuild(`adding new exclusion constraints: ${newExclusions.map(exclusion => `"${exclusion.name}"`).join(", ")} in table "${table.name}"`); await this.queryRunner.createExclusionConstraints(table, newExclusions); - }); + } } /** * Creates foreign keys which does not exist in the table yet. */ protected async createForeignKeys(): Promise { - await PromiseUtils.runInSequence(this.entityToSyncMetadatas, async metadata => { + for (const metadata of this.entityToSyncMetadatas) { const table = this.queryRunner.loadedTables.find(table => table.name === metadata.tablePath); if (!table) - return; + continue; const newKeys = metadata.foreignKeys.filter(foreignKey => { return !table.foreignKeys.find(dbForeignKey => foreignKeysMatch(dbForeignKey, foreignKey)); }); if (newKeys.length === 0) - return; + continue; const dbForeignKeys = newKeys.map(foreignKeyMetadata => TableForeignKey.create(foreignKeyMetadata)); this.connection.logger.logSchemaBuild(`creating a foreign keys: ${newKeys.map(key => key.name).join(", ")} on table "${table.name}"`); await this.queryRunner.createForeignKeys(table, dbForeignKeys); - }); + } } /** @@ -690,10 +694,10 @@ export class RdbmsSchemaBuilder implements SchemaBuilder { }); if (tablesWithFK.length > 0) { - await PromiseUtils.runInSequence(tablesWithFK, tableWithFK => { + for (const tableWithFK of tablesWithFK) { this.connection.logger.logSchemaBuild(`dropping related foreign keys of ${tableWithFK.name}: ${tableWithFK.foreignKeys.map(foreignKey => foreignKey.name).join(", ")}`); - return this.queryRunner.dropForeignKeys(tableWithFK, tableWithFK.foreignKeys); - }); + await this.queryRunner.dropForeignKeys(tableWithFK, tableWithFK.foreignKeys); + } } } diff --git a/src/util/PromiseUtils.ts b/src/util/PromiseUtils.ts deleted file mode 100644 index 326d6c44032..00000000000 --- a/src/util/PromiseUtils.ts +++ /dev/null @@ -1,63 +0,0 @@ -/** - * Utils to help to work with Promise objects. - */ -export class PromiseUtils { - - /** - * Creates a new promise with resolved value used for lazy relations. - */ - static create(value: any) { - const promise = Promise.resolve(value); - (promise as any)["__value__"] = value; - return promise; - } - - /** - * If given value is a promise created by "create" method this method gets its value. - * If given value is not a promise then given value is returned back. - */ - static extractValue(object: any) { - if (object instanceof Promise && (object as any)["__value__"]) - return (object as any)["__value__"]; - - return object; - } - - /** - * Runs given callback that returns promise for each item in the given collection in order. - * Operations executed after each other, right after previous promise being resolved. - */ - static runInSequence(collection: T[], callback: (item: T) => Promise): Promise { - const results: U[] = []; - return collection.reduce((promise, item) => { - return promise.then(() => { - return callback(item); - }).then(result => { - results.push(result); - }); - }, Promise.resolve()).then(() => { - return results; - }); - } - - /** - * Returns a promise that is fulfilled with an array of promise state snapshots, - * but only after all the original promises have settled, i.e. become either fulfilled or rejected. - */ - static settle(promises: Promise[]) { - return Promise.all(promises.map(p => Promise.resolve(p).then(v => ({ - state: "fulfilled", - value: v, - }), r => ({ - state: "rejected", - reason: r, - })))).then((results: any[]): any => { - const rejected = results.find(result => result.state === "rejected"); - if (rejected) - return Promise.reject(rejected.reason); - - return results.map(result => result.value); - }); - } - -} \ No newline at end of file diff --git a/test/functional/connection/connection.ts b/test/functional/connection/connection.ts index 3f03b099aaf..d7b7d74fdc4 100644 --- a/test/functional/connection/connection.ts +++ b/test/functional/connection/connection.ts @@ -17,7 +17,6 @@ import {EntityManager} from "../../../src/entity-manager/EntityManager"; import {CannotGetEntityManagerNotConnectedError} from "../../../src/error/CannotGetEntityManagerNotConnectedError"; import {ConnectionOptions} from "../../../src/connection/ConnectionOptions"; import {PostgresConnectionOptions} from "../../../src/driver/postgres/PostgresConnectionOptions"; -import {PromiseUtils} from "../../../src/util/PromiseUtils"; describe("Connection", () => { // const resourceDir = __dirname + "/../../../../../test/functional/connection/"; @@ -274,7 +273,7 @@ describe("Connection", () => { after(() => closeTestingConnections(connections)); it("should not interfere with each other", async () => { - await PromiseUtils.runInSequence(connections, c => c.synchronize()); + await Promise.all(connections.map(c => c.synchronize())); await closeTestingConnections(connections); const connections1 = await createTestingConnections({ name: "test", diff --git a/test/functional/entity-model/entity-model.ts b/test/functional/entity-model/entity-model.ts index 5be6481c122..baf250b4732 100644 --- a/test/functional/entity-model/entity-model.ts +++ b/test/functional/entity-model/entity-model.ts @@ -3,7 +3,6 @@ import {Post} from "./entity/Post"; import {Category} from "./entity/Category"; import {closeTestingConnections, createTestingConnections, reloadTestingDatabases} from "../../utils/test-utils"; import {Connection} from "../../../src/connection/Connection"; -import {PromiseUtils} from "../../../src/util/PromiseUtils"; describe("entity-model", () => { @@ -14,60 +13,65 @@ describe("entity-model", () => { beforeEach(() => reloadTestingDatabases(connections)); after(() => closeTestingConnections(connections)); - it("should save successfully and use static methods successfully", () => PromiseUtils.runInSequence(connections, async connection => { - Post.useConnection(connection); // change connection each time because of AR specifics - - const post = Post.create(); - post.title = "About ActiveRecord"; - post.text = "Huge discussion how good or bad ActiveRecord is."; - await post.save(); - - const loadedPost = await Post.findOne(post.id); - - loadedPost!.should.be.instanceOf(Post); - loadedPost!.id.should.be.eql(post.id); - loadedPost!.title.should.be.eql("About ActiveRecord"); - loadedPost!.text.should.be.eql("Huge discussion how good or bad ActiveRecord is."); - })); - - it("should reload given entity successfully", () => PromiseUtils.runInSequence(connections, async connection => { - await connection.synchronize(true); - Post.useConnection(connection); - Category.useConnection(connection); - - const category = Category.create(); - category.id = 1; - category.name = "Persistence"; - await category.save(); - - const post = Post.create(); - post.title = "About ActiveRecord"; - post.categories = [category]; - await post.save(); - - await post.reload(); - - const assertCategory = Object.assign({}, post.categories[0]); - post!.should.be.instanceOf(Post); - post!.id.should.be.eql(post.id); - post!.title.should.be.eql("About ActiveRecord"); - post!.text.should.be.eql("This is default text."); - assertCategory.should.be.eql({ - id: 1, - name: "Persistence" - }); - - category.name = "Persistence and Entity"; - await category.save(); - - await post.reload(); - - const assertReloadedCategory = Object.assign({}, post.categories[0]); - assertReloadedCategory.should.be.eql({ - id: 1, - name: "Persistence and Entity" - }); - - })); + it("should save successfully and use static methods successfully", async () => { + // These must run sequentially as we have the global context of the `Post` ActiveRecord class + for (const connection of connections) { + Post.useConnection(connection); // change connection each time because of AR specifics + + const post = Post.create(); + post.title = "About ActiveRecord"; + post.text = "Huge discussion how good or bad ActiveRecord is."; + await post.save(); + + const loadedPost = await Post.findOne(post.id); + + loadedPost!.should.be.instanceOf(Post); + loadedPost!.id.should.be.eql(post.id); + loadedPost!.title.should.be.eql("About ActiveRecord"); + loadedPost!.text.should.be.eql("Huge discussion how good or bad ActiveRecord is."); + } + }); + + it("should reload given entity successfully", async () => { + // These must run sequentially as we have the global context of the `Post` ActiveRecord class + for (const connection of connections) { + await connection.synchronize(true); + Post.useConnection(connection); + Category.useConnection(connection); + + const category = Category.create(); + category.id = 1; + category.name = "Persistence"; + await category.save(); + + const post = Post.create(); + post.title = "About ActiveRecord"; + post.categories = [category]; + await post.save(); + + await post.reload(); + + const assertCategory = Object.assign({}, post.categories[0]); + post!.should.be.instanceOf(Post); + post!.id.should.be.eql(post.id); + post!.title.should.be.eql("About ActiveRecord"); + post!.text.should.be.eql("This is default text."); + assertCategory.should.be.eql({ + id: 1, + name: "Persistence" + }); + + category.name = "Persistence and Entity"; + await category.save(); + + await post.reload(); + + const assertReloadedCategory = Object.assign({}, post.categories[0]); + assertReloadedCategory.should.be.eql({ + id: 1, + name: "Persistence and Entity" + }); + } + }); }); diff --git a/test/functional/indices/conditional-index/conditional-index.ts b/test/functional/indices/conditional-index/conditional-index.ts index 6b8ed7d5c9e..f195fe9b79f 100644 --- a/test/functional/indices/conditional-index/conditional-index.ts +++ b/test/functional/indices/conditional-index/conditional-index.ts @@ -37,7 +37,7 @@ describe("indices > conditional index", () => { expect(table!.indices[0].where).to.be.not.empty; expect(table!.indices[1].where).to.be.not.empty; - await queryRunner.dropIndices(table!, table!.indices); + await queryRunner.dropIndices(table!, [...table!.indices]); table = await queryRunner.getTable("post"); table!.indices.length.should.be.equal(0); diff --git a/test/functional/repository/find-options-operators/repository-find-operators.ts b/test/functional/repository/find-options-operators/repository-find-operators.ts index 4434721fb08..722a8279e4a 100644 --- a/test/functional/repository/find-options-operators/repository-find-operators.ts +++ b/test/functional/repository/find-options-operators/repository-find-operators.ts @@ -12,8 +12,7 @@ import { Like, MoreThan, MoreThanOrEqual, - Not, - PromiseUtils + Not } from "../../../../src"; import {Post} from "./entity/Post"; import {PostgresDriver} from "../../../../src/driver/postgres/PostgresDriver"; @@ -535,18 +534,20 @@ describe("repository > find options > operators", () => { }))); - it("should work with ActiveRecord model", () => PromiseUtils.runInSequence(connections, async connection => { - PersonAR.useConnection(connection); - - const person = new PersonAR(); - person.name = "Timber"; - await connection.manager.save(person); - - const loadedPeople = await PersonAR.find({ - name: In(["Timber"]) - }); - expect(loadedPeople[0].name).to.be.equal("Timber"); - - })); + it("should work with ActiveRecord model", async () => { + // These must run sequentially as we have the global context of the `PersonAR` ActiveRecord class + for (const connection of connections) { + PersonAR.useConnection(connection); + + const person = new PersonAR(); + person.name = "Timber"; + await connection.manager.save(person); + + const loadedPeople = await PersonAR.find({ + name: In(["Timber"]) + }); + expect(loadedPeople[0].name).to.be.equal("Timber"); + } + }); }); diff --git a/test/functional/repository/soft-delete/entity-soft-remove.ts b/test/functional/repository/soft-delete/entity-soft-remove.ts index f9c75399e65..f89f8289241 100644 --- a/test/functional/repository/soft-delete/entity-soft-remove.ts +++ b/test/functional/repository/soft-delete/entity-soft-remove.ts @@ -5,7 +5,6 @@ import {Connection} from "../../../../src/connection/Connection"; import {Post} from "./entity/Post"; import { PostWithoutDeleteDateColumn } from "./entity/PostWithoutDeleteDateColumn"; import { MissingDeleteDateColumnError } from "../../../../src/error/MissingDeleteDateColumnError"; -import { PromiseUtils } from "../../../../src"; describe("entity > soft-remove", () => { @@ -16,9 +15,7 @@ describe("entity > soft-remove", () => { beforeEach(() => reloadTestingDatabases(connections)); after(() => closeTestingConnections(connections)); - it("should perform soft removal and recovery correctly", () => PromiseUtils.runInSequence(connections, async connection => { - Post.useConnection(connection); // change connection each time because of AR specifics - + it("should perform soft removal and recovery correctly", () => Promise.all(connections.map(async connection => { const postRepository = connection.getRepository(Post); // save a new posts @@ -35,7 +32,7 @@ describe("entity > soft-remove", () => { await postRepository.save(newPost2); // soft-remove one - await newPost1.softRemove(); + await postRepository.softRemove(newPost1); // load to check const loadedPosts = await postRepository.find({ withDeleted: true }); @@ -53,7 +50,8 @@ describe("entity > soft-remove", () => { expect(loadedPost2!.name).to.equals("post#2"); // recover one - await loadedPost1!.recover(); + await postRepository.recover(loadedPost1!); + // load to check const recoveredPosts = await postRepository.find({ withDeleted: true }); @@ -68,12 +66,9 @@ describe("entity > soft-remove", () => { expect(recoveredPost2).to.exist; expect(recoveredPost2!.deletedAt).to.equals(null); expect(recoveredPost2!.name).to.equals("post#2"); + }))); - })); - - it("should throw error when delete date column is missing", () => PromiseUtils.runInSequence(connections, async connection => { - PostWithoutDeleteDateColumn.useConnection(connection); // change connection each time because of AR specifics - + it("should throw error when delete date column is missing", () => Promise.all(connections.map(async connection => { const postRepository = connection.getRepository(PostWithoutDeleteDateColumn); // save a new posts @@ -87,7 +82,7 @@ describe("entity > soft-remove", () => { let error1: Error | undefined; try { // soft-remove one - await newPost1.softRemove(); + await postRepository.softRemove(newPost1); } catch (err) { error1 = err; } @@ -96,11 +91,11 @@ describe("entity > soft-remove", () => { let error2: Error | undefined; try { // recover one - await newPost1.recover(); + await postRepository.recover(newPost1); } catch (err) { error2 = err; } expect(error2).to.be.an.instanceof(MissingDeleteDateColumnError); - })); + }))); }); diff --git a/test/functional/schema-builder/change-check-constraint.ts b/test/functional/schema-builder/change-check-constraint.ts index 5996b4eaf38..5e6d6cbf1a9 100644 --- a/test/functional/schema-builder/change-check-constraint.ts +++ b/test/functional/schema-builder/change-check-constraint.ts @@ -1,7 +1,6 @@ import "reflect-metadata"; import {Connection} from "../../../src/connection/Connection"; import {closeTestingConnections, createTestingConnections, reloadTestingDatabases} from "../../utils/test-utils"; -import {PromiseUtils} from "../../../src"; import {Teacher} from "./entity/Teacher"; import {Post} from "./entity/Post"; import {CheckMetadata} from "../../../src/metadata/CheckMetadata"; @@ -20,7 +19,7 @@ describe("schema builder > change check constraint", () => { beforeEach(() => reloadTestingDatabases(connections)); after(() => closeTestingConnections(connections)); - it("should correctly add new check constraint", () => PromiseUtils.runInSequence(connections, async connection => { + it("should correctly add new check constraint", () => Promise.all(connections.map(async connection => { // Mysql does not support check constraints. if (connection.driver instanceof MysqlDriver) return; @@ -43,9 +42,9 @@ describe("schema builder > change check constraint", () => { await queryRunner.release(); table!.checks.length.should.be.equal(1); - })); + }))); - it("should correctly change check", () => PromiseUtils.runInSequence(connections, async connection => { + it("should correctly change check", () => Promise.all(connections.map(async connection => { // Mysql does not support check constraints. if (connection.driver instanceof MysqlDriver) return; @@ -61,9 +60,9 @@ describe("schema builder > change check constraint", () => { await queryRunner.release(); table!.checks[0].expression!.indexOf("2000").should.be.not.equal(-1); - })); + }))); - it("should correctly drop removed check", () => PromiseUtils.runInSequence(connections, async connection => { + it("should correctly drop removed check", () => Promise.all(connections.map(async connection => { // Mysql does not support check constraints. if (connection.driver instanceof MysqlDriver) return; @@ -78,6 +77,6 @@ describe("schema builder > change check constraint", () => { await queryRunner.release(); table!.checks.length.should.be.equal(0); - })); + }))); }); diff --git a/test/functional/schema-builder/change-column.ts b/test/functional/schema-builder/change-column.ts index 2372e47400d..2b21f5f02b9 100644 --- a/test/functional/schema-builder/change-column.ts +++ b/test/functional/schema-builder/change-column.ts @@ -1,6 +1,6 @@ import {expect} from "chai"; import "reflect-metadata"; -import {Connection, PromiseUtils} from "../../../src"; +import {Connection} from "../../../src"; import {AuroraDataApiDriver} from "../../../src/driver/aurora-data-api/AuroraDataApiDriver"; import {CockroachDriver} from "../../../src/driver/cockroachdb/CockroachDriver"; import {MysqlDriver} from "../../../src/driver/mysql/MysqlDriver"; @@ -26,7 +26,7 @@ describe("schema builder > change column", () => { beforeEach(() => reloadTestingDatabases(connections)); after(() => closeTestingConnections(connections)); - it("should correctly change column name", () => PromiseUtils.runInSequence(connections, async connection => { + it("should correctly change column name", () => Promise.all(connections.map(async connection => { const postMetadata = connection.getMetadata(Post); const nameColumn = postMetadata.findColumnWithPropertyName("name")!; nameColumn.propertyName = "title"; @@ -44,9 +44,9 @@ describe("schema builder > change column", () => { // revert changes nameColumn.propertyName = "name"; nameColumn.build(connection); - })); + }))); - it("should correctly change column length", () => PromiseUtils.runInSequence(connections, async connection => { + it("should correctly change column length", () => Promise.all(connections.map(async connection => { const postMetadata = connection.getMetadata(Post); const nameColumn = postMetadata.findColumnWithPropertyName("name")!; const textColumn = postMetadata.findColumnWithPropertyName("text")!; @@ -71,9 +71,9 @@ describe("schema builder > change column", () => { // revert changes nameColumn.length = "255"; textColumn.length = "255"; - })); + }))); - it("should correctly change column type", () => PromiseUtils.runInSequence(connections, async connection => { + it("should correctly change column type", () => Promise.all(connections.map(async connection => { const postMetadata = connection.getMetadata(Post); const versionColumn = postMetadata.findColumnWithPropertyName("version")!; @@ -95,9 +95,9 @@ describe("schema builder > change column", () => { // revert changes versionColumn.type = "varchar"; postVersionColumn.type = "varchar"; - })); + }))); - it("should correctly make column primary and generated", () => PromiseUtils.runInSequence(connections, async connection => { + it("should correctly make column primary and generated", () => Promise.all(connections.map(async connection => { // CockroachDB does not allow changing PK if (connection.driver instanceof CockroachDriver) return; @@ -130,9 +130,9 @@ describe("schema builder > change column", () => { idColumn.isGenerated = false; idColumn.generationStrategy = undefined; versionColumn.isPrimary = false; - })); + }))); - it("should correctly change column `isGenerated` property when column is on foreign key", () => PromiseUtils.runInSequence(connections, async connection => { + it("should correctly change column `isGenerated` property when column is on foreign key", () => Promise.all(connections.map(async connection => { const teacherMetadata = connection.getMetadata("teacher"); const idColumn = teacherMetadata.findColumnWithPropertyName("id")!; idColumn.isGenerated = false; @@ -151,9 +151,9 @@ describe("schema builder > change column", () => { idColumn.isGenerated = true; idColumn.generationStrategy = "increment"; - })); + }))); - it("should correctly change non-generated column on to uuid-generated column", () => PromiseUtils.runInSequence(connections, async connection => { + it("should correctly change non-generated column on to uuid-generated column", () => Promise.all(connections.map(async connection => { // CockroachDB does not allow changing PK if (connection.driver instanceof CockroachDriver) return; @@ -199,9 +199,9 @@ describe("schema builder > change column", () => { postMetadata.generatedColumns.splice(postMetadata.generatedColumns.indexOf(idColumn), 1); postMetadata.hasUUIDGeneratedColumns = false; - })); + }))); - it("should correctly change generated column generation strategy", () => PromiseUtils.runInSequence(connections, async connection => { + it("should correctly change generated column generation strategy", () => Promise.all(connections.map(async connection => { // CockroachDB does not allow changing PK if (connection.driver instanceof CockroachDriver) return; @@ -246,6 +246,6 @@ describe("schema builder > change column", () => { idColumn.type = "int"; teacherColumn.type = "int"; - })); + }))); }); diff --git a/test/functional/schema-builder/change-exclusion-constraint.ts b/test/functional/schema-builder/change-exclusion-constraint.ts index c390f64dcfe..dfd6366f744 100644 --- a/test/functional/schema-builder/change-exclusion-constraint.ts +++ b/test/functional/schema-builder/change-exclusion-constraint.ts @@ -1,7 +1,6 @@ import "reflect-metadata"; import {Connection} from "../../../src/connection/Connection"; import {closeTestingConnections, createTestingConnections, reloadTestingDatabases} from "../../utils/test-utils"; -import {PromiseUtils} from "../../../src"; import {Teacher} from "./entity/Teacher"; import {Post} from "./entity/Post"; import {ExclusionMetadata} from "../../../src/metadata/ExclusionMetadata"; @@ -20,7 +19,7 @@ describe("schema builder > change exclusion constraint", () => { beforeEach(() => reloadTestingDatabases(connections)); after(() => closeTestingConnections(connections)); - it("should correctly add new exclusion constraint", () => PromiseUtils.runInSequence(connections, async connection => { + it("should correctly add new exclusion constraint", () => Promise.all(connections.map(async connection => { const teacherMetadata = connection.getMetadata(Teacher); const exclusionMetadata = new ExclusionMetadata({ @@ -40,9 +39,9 @@ describe("schema builder > change exclusion constraint", () => { await queryRunner.release(); table!.exclusions.length.should.be.equal(1); - })); + }))); - it("should correctly change exclusion", () => PromiseUtils.runInSequence(connections, async connection => { + it("should correctly change exclusion", () => Promise.all(connections.map(async connection => { const postMetadata = connection.getMetadata(Post); postMetadata.exclusions[0].expression = `USING gist ("tag" WITH =)`; @@ -55,9 +54,9 @@ describe("schema builder > change exclusion constraint", () => { await queryRunner.release(); table!.exclusions[0].expression!.indexOf("tag").should.be.not.equal(-1); - })); + }))); - it("should correctly drop removed exclusion", () => PromiseUtils.runInSequence(connections, async connection => { + it("should correctly drop removed exclusion", () => Promise.all(connections.map(async connection => { const postMetadata = connection.getMetadata(Post); postMetadata.exclusions = []; @@ -69,6 +68,6 @@ describe("schema builder > change exclusion constraint", () => { await queryRunner.release(); table!.exclusions.length.should.be.equal(0); - })); + }))); }); diff --git a/test/functional/schema-builder/change-index.ts b/test/functional/schema-builder/change-index.ts index 47cb52a26de..0d8b9793a83 100644 --- a/test/functional/schema-builder/change-index.ts +++ b/test/functional/schema-builder/change-index.ts @@ -2,7 +2,6 @@ import "reflect-metadata"; import {Connection} from "../../../src/connection/Connection"; import {CockroachDriver} from "../../../src/driver/cockroachdb/CockroachDriver"; import {closeTestingConnections, createTestingConnections, reloadTestingDatabases} from "../../utils/test-utils"; -import {PromiseUtils} from "../../../src"; import {IndexMetadata} from "../../../src/metadata/IndexMetadata"; import {Teacher} from "./entity/Teacher"; import {Student} from "./entity/Student"; @@ -22,7 +21,7 @@ describe("schema builder > change index", () => { beforeEach(() => reloadTestingDatabases(connections)); after(() => closeTestingConnections(connections)); - it("should correctly add new index", () => PromiseUtils.runInSequence(connections, async connection => { + it("should correctly add new index", () => Promise.all(connections.map(async connection => { const teacherMetadata = connection.getMetadata(Teacher); const nameColumn = teacherMetadata.findColumnWithPropertyName("name")!; const indexMetadata = new IndexMetadata({ @@ -46,9 +45,9 @@ describe("schema builder > change index", () => { // revert changes teacherMetadata.indices.splice(teacherMetadata.indices.indexOf(indexMetadata), 1); - })); + }))); - it("should correctly change index", () => PromiseUtils.runInSequence(connections, async connection => { + it("should correctly change index", () => Promise.all(connections.map(async connection => { const studentMetadata = connection.getMetadata(Student); studentMetadata.indices[0].name = "changed_index"; @@ -60,9 +59,9 @@ describe("schema builder > change index", () => { const index = studentTable!.indices.find(i => i.name === "changed_index"); expect(index).not.be.undefined; - })); + }))); - it("should correctly drop removed index", () => PromiseUtils.runInSequence(connections, async connection => { + it("should correctly drop removed index", () => Promise.all(connections.map(async connection => { const studentMetadata = connection.getMetadata(Student); studentMetadata.indices.splice(0, 1); @@ -77,9 +76,9 @@ describe("schema builder > change index", () => { } else { studentTable!.indices.length.should.be.equal(0); } - })); + }))); - it("should ignore index synchronization when `synchronize` set to false", () => PromiseUtils.runInSequence(connections, async connection => { + it("should ignore index synchronization when `synchronize` set to false", () => Promise.all(connections.map(async connection => { // You can not disable synchronization for unique index in CockroachDB, because unique indices are stored as UNIQUE constraints @@ -116,6 +115,6 @@ describe("schema builder > change index", () => { await queryRunner.release(); - })); + }))); }); diff --git a/test/functional/schema-builder/change-unique-constraint.ts b/test/functional/schema-builder/change-unique-constraint.ts index dc020b8658f..7791e24e9ff 100644 --- a/test/functional/schema-builder/change-unique-constraint.ts +++ b/test/functional/schema-builder/change-unique-constraint.ts @@ -1,5 +1,4 @@ import "reflect-metadata"; -import {PromiseUtils} from "../../../src"; import {Connection} from "../../../src"; import {MysqlDriver} from "../../../src/driver/mysql/MysqlDriver"; import {SapDriver} from "../../../src/driver/sap/SapDriver"; @@ -23,7 +22,7 @@ describe("schema builder > change unique constraint", () => { beforeEach(() => reloadTestingDatabases(connections)); after(() => closeTestingConnections(connections)); - it("should correctly add new unique constraint", () => PromiseUtils.runInSequence(connections, async connection => { + it("should correctly add new unique constraint", () => Promise.all(connections.map(async connection => { const teacherMetadata = connection.getMetadata(Teacher); const nameColumn = teacherMetadata.findColumnWithPropertyName("name")!; let uniqueIndexMetadata: IndexMetadata|undefined = undefined; @@ -74,9 +73,9 @@ describe("schema builder > change unique constraint", () => { // revert changes teacherMetadata.uniques.splice(teacherMetadata.uniques.indexOf(uniqueMetadata!), 1); } - })); + }))); - it("should correctly change unique constraint", () => PromiseUtils.runInSequence(connections, async connection => { + it("should correctly change unique constraint", () => Promise.all(connections.map(async connection => { // Sqlite does not store unique constraint name if (connection.driver instanceof AbstractSqliteDriver) return; @@ -116,9 +115,9 @@ describe("schema builder > change unique constraint", () => { uniqueMetadata!.name = connection.namingStrategy.uniqueConstraintName(table!, uniqueMetadata!.columns.map(c => c.databaseName)); } - })); + }))); - it("should correctly drop removed unique constraint", () => PromiseUtils.runInSequence(connections, async connection => { + it("should correctly drop removed unique constraint", () => Promise.all(connections.map(async connection => { const postMetadata = connection.getMetadata(Post); // Mysql and SAP stores unique constraints as unique indices. @@ -143,6 +142,6 @@ describe("schema builder > change unique constraint", () => { } else { table!.uniques.length.should.be.equal(1); } - })); + }))); }); diff --git a/test/github-issues/1014/issue-1014.ts b/test/github-issues/1014/issue-1014.ts index 943171764a4..787e9e878f2 100644 --- a/test/github-issues/1014/issue-1014.ts +++ b/test/github-issues/1014/issue-1014.ts @@ -3,7 +3,6 @@ import {closeTestingConnections, createTestingConnections, reloadTestingDatabase import {Connection} from "../../../src/connection/Connection"; import {TestEntity} from "./entity/TestEntity"; import {expect} from "chai"; -import {PromiseUtils} from "../../../src/util/PromiseUtils"; describe("github issues > #1014 Transaction doesn't rollback", () => { @@ -22,12 +21,10 @@ describe("github issues > #1014 Transaction doesn't rollback", () => { let error: any; try { - await connection.transaction(manager => { - return PromiseUtils.settle([ - manager.remove(testEntity), - Promise.reject(new Error()), - new Promise((resolve, reject) => reject(new Error())), - ]); + await connection.transaction(async manager => { + await manager.remove(testEntity); + + throw new Error(); }); } catch (err) { error = err; } diff --git a/test/github-issues/1055/issue-1055.ts b/test/github-issues/1055/issue-1055.ts index 3b821c5eea4..ddccb85757f 100644 --- a/test/github-issues/1055/issue-1055.ts +++ b/test/github-issues/1055/issue-1055.ts @@ -4,7 +4,6 @@ import {Connection} from "../../../src/connection/Connection"; import {Parent} from "./entity/Parent"; import {Child} from "./entity/Child"; import {expect} from "chai"; -import {PromiseUtils} from "../../../src/util/PromiseUtils"; describe("github issues > #1055 ind with relations not working, correct syntax causes type error", () => { @@ -38,28 +37,6 @@ describe("github issues > #1055 ind with relations not working, correct syntax c expect(foundChild).not.to.be.undefined; }))); - - it("should be able to lookup from promise as well", () => Promise.all(connections.map(async connection => { - const manager = connection.manager; - - const parent = new Parent(); - parent.name = "Parent"; - await manager.save(parent); - - const loadedParent = await manager.findOne(Parent, 1); - expect(loadedParent).not.to.be.undefined; - - if (!loadedParent) return; - - const child = new Child(); - child.name = "Child"; - child.parent = Promise.resolve(loadedParent); - await manager.save(child); - - const foundChild = await manager.findOne(Child, { parent: PromiseUtils.create(loadedParent) }); - expect(foundChild).not.to.be.undefined; - }))); - it("should not have type errors with the primary key type", () => Promise.all(connections.map(async connection => { const manager = connection.manager; diff --git a/test/github-issues/1261/issue-1261.ts b/test/github-issues/1261/issue-1261.ts index 0a1431ab4d8..db374143e26 100644 --- a/test/github-issues/1261/issue-1261.ts +++ b/test/github-issues/1261/issue-1261.ts @@ -1,9 +1,7 @@ import "reflect-metadata"; import {closeTestingConnections, createTestingConnections} from "../../utils/test-utils"; import {Connection} from "../../../src/connection/Connection"; -import {BaseEntity} from "../../../src/repository/BaseEntity"; import {Bar} from "./entity/Bar"; -import {PromiseUtils} from "../../../src"; describe("github issues > #1261 onDelete property on foreign key is not modified on sync", () => { @@ -13,10 +11,8 @@ describe("github issues > #1261 onDelete property on foreign key is not modified })); after(() => closeTestingConnections(connections)); - it("should modify onDelete property on foreign key on sync", () => PromiseUtils.runInSequence(connections, async connection => { - + it("should modify onDelete property on foreign key on sync", () => Promise.all(connections.map(async connection => { await connection.synchronize(); - BaseEntity.useConnection(connection); const queryRunner = connection.createQueryRunner(); let table = await queryRunner.getTable("bar"); @@ -31,6 +27,6 @@ describe("github issues > #1261 onDelete property on foreign key is not modified await queryRunner.release(); - })); + }))); }); diff --git a/test/github-issues/1805/issue-1805.ts b/test/github-issues/1805/issue-1805.ts index a1cc57b95a7..6d734cad031 100644 --- a/test/github-issues/1805/issue-1805.ts +++ b/test/github-issues/1805/issue-1805.ts @@ -2,7 +2,6 @@ import "reflect-metadata"; import {Connection} from "../../../src/connection/Connection"; import {closeTestingConnections, createTestingConnections} from "../../utils/test-utils"; import {Account} from "./entity/Account"; -import {PromiseUtils} from "../../../src"; describe("github issues > #1805 bigint PK incorrectly returning as a number (expecting a string)", () => { @@ -17,16 +16,17 @@ describe("github issues > #1805 bigint PK incorrectly returning as a number (exp }); after(() => closeTestingConnections(connections)); - it("should return `bigint` column as string", () => PromiseUtils.runInSequence(connections, async connection => { - Account.useConnection(connection); - let account: Account|undefined; + it("should return `bigint` column as string", () => Promise.all(connections.map(async connection => { const bigIntId = "76561198016705746"; - account = new Account(); + const account = new Account(); account.id = bigIntId; - await account.save(); - account = await Account.findOne(bigIntId); - account!.id.should.be.equal(bigIntId); - })); + const accountRepository = await connection.getRepository(Account); + + await accountRepository.save(account); + + const loadedAccount = await accountRepository.findOne(bigIntId); + loadedAccount!.id.should.be.equal(bigIntId); + }))); }); diff --git a/test/github-issues/2313/issue-2313.ts b/test/github-issues/2313/issue-2313.ts index fda6ff70337..b5b98f0eebd 100644 --- a/test/github-issues/2313/issue-2313.ts +++ b/test/github-issues/2313/issue-2313.ts @@ -1,6 +1,5 @@ import "reflect-metadata"; import {Connection} from "../../../src/connection/Connection"; -import {PromiseUtils} from "../../../src/util/PromiseUtils"; import {closeTestingConnections, createTestingConnections, reloadTestingDatabases} from "../../utils/test-utils"; import {Post} from "./entity/Post"; import {expect} from "chai"; @@ -16,35 +15,41 @@ describe("github issues > #2313 - BaseEntity has no findOneOrFail() method", () beforeEach(() => reloadTestingDatabases(connections)); after(() => closeTestingConnections(connections)); - it("should find the appropriate record when one exists", () => PromiseUtils.runInSequence(connections, async connection => { - Post.useConnection(connection); // change connection each time because of AR specifics + it("should find the appropriate record when one exists", async () => { + // These must run sequentially as we have the global context of the `Post` ActiveRecord class + for (const connection of connections) { + Post.useConnection(connection); // change connection each time because of AR specifics - const post1 = new Post(); - post1.data = 123; - await post1.save(); + const post1 = new Post(); + post1.data = 123; + await post1.save(); - const post2 = new Post(); - post2.data = 456; - await post2.save(); + const post2 = new Post(); + post2.data = 456; + await post2.save(); - const result1 = await Post.findOneOrFail(1); + const result1 = await Post.findOneOrFail(1); - result1.data.should.be.eql(123); + result1.data.should.be.eql(123); - const result2 = await Post.findOneOrFail(2); + const result2 = await Post.findOneOrFail(2); - result2.data.should.be.eql(456); - })); - - it("should throw no matching record exists", () => PromiseUtils.runInSequence(connections, async connection => { - Post.useConnection(connection); // change connection each time because of AR specifics - - try { - await Post.findOneOrFail(100); - expect.fail(); - } catch (e) { - e.should.be.instanceOf(EntityNotFoundError); + result2.data.should.be.eql(456); } - })); + }); + + it("should throw no matching record exists", async () => { + // These must run sequentially as we have the global context of the `Post` ActiveRecord class + for (const connection of connections) { + Post.useConnection(connection); // change connection each time because of AR specifics + + try { + await Post.findOneOrFail(100); + expect.fail(); + } catch (e) { + e.should.be.instanceOf(EntityNotFoundError); + } + } + }); }); diff --git a/test/github-issues/3422/issue-3422.ts b/test/github-issues/3422/issue-3422.ts index 01ebf26034a..3687e994f91 100644 --- a/test/github-issues/3422/issue-3422.ts +++ b/test/github-issues/3422/issue-3422.ts @@ -2,7 +2,6 @@ import "reflect-metadata"; import {Connection} from "../../../src/connection/Connection"; import {closeTestingConnections, createTestingConnections} from "../../utils/test-utils"; import {User} from "./entity/User"; -import {PromiseUtils} from "../../../src"; describe("github issues > #3422 cannot save to nested-tree table if schema is used in postgres", () => { @@ -16,7 +15,7 @@ describe("github issues > #3422 cannot save to nested-tree table if schema is us }); after(() => closeTestingConnections(connections)); - it("should not fail when using schema and nested-tree", () => PromiseUtils.runInSequence(connections, async connection => { + it("should not fail when using schema and nested-tree", () => Promise.all(connections.map(async connection => { await connection.query("CREATE SCHEMA IF NOT EXISTS admin"); await connection.synchronize(); const parent = new User(); @@ -28,5 +27,5 @@ describe("github issues > #3422 cannot save to nested-tree table if schema is us const user = await connection.manager.getRepository(User).findOne(child.id, {relations: ["manager"]}); user!.id.should.be.equal(child.id); user!.manager.id.should.be.equal(parent.id); - })); + }))); }); diff --git a/test/github-issues/3496/issue-3496.ts b/test/github-issues/3496/issue-3496.ts index 8bcea0464db..f96eee3f1c6 100644 --- a/test/github-issues/3496/issue-3496.ts +++ b/test/github-issues/3496/issue-3496.ts @@ -2,7 +2,6 @@ import "reflect-metadata"; import {Connection} from "../../../src"; import {closeTestingConnections, createTestingConnections} from "../../utils/test-utils"; import {Post} from "./entity/Post"; -import {PromiseUtils} from "../../../src"; describe("github issues > #3496 jsonb comparison doesn't work", () => { @@ -16,7 +15,7 @@ describe("github issues > #3496 jsonb comparison doesn't work", () => { }); after(() => closeTestingConnections(connections)); - it("the entity should not be updated a second time", () => PromiseUtils.runInSequence(connections, async connection => { + it("the entity should not be updated a second time", () => Promise.all(connections.map(async connection => { await connection.synchronize(); const repository = connection.getRepository(Post); @@ -34,5 +33,5 @@ describe("github issues > #3496 jsonb comparison doesn't work", () => { ); savedPost1!.version.should.be.equal(savedPost2!.version); - })); + }))); }); diff --git a/test/github-issues/3534/issue-3534.ts b/test/github-issues/3534/issue-3534.ts index 247bcb3d8ff..bcf25c022be 100644 --- a/test/github-issues/3534/issue-3534.ts +++ b/test/github-issues/3534/issue-3534.ts @@ -1,6 +1,6 @@ import "reflect-metadata"; import {expect} from "chai"; -import { Connection, PromiseUtils } from "../../../src"; +import { Connection } from "../../../src"; import { Foo } from "./entity/Foo"; import { closeTestingConnections, createTestingConnections, reloadTestingDatabases } from "../../utils/test-utils"; @@ -14,7 +14,7 @@ describe("github issues > #3534: store regexp", () => { beforeEach(() => reloadTestingDatabases(connections)); after(() => closeTestingConnections(connections)); - it("allows entities with regexp columns", () => PromiseUtils.runInSequence(connections, async connection => { + it("allows entities with regexp columns", () => Promise.all(connections.map(async connection => { const repository = connection.getRepository(Foo); const foo = new Foo(); @@ -25,6 +25,6 @@ describe("github issues > #3534: store regexp", () => { const storedFoo = await repository.findOneOrFail(foo.id); expect(storedFoo.bar).to.instanceOf(RegExp); expect(storedFoo.bar.toString()).to.eq(/foo/i.toString()); - })); + }))); }); diff --git a/test/github-issues/3536/issue-3536.ts b/test/github-issues/3536/issue-3536.ts index 2a284ddbde4..39d454f768b 100644 --- a/test/github-issues/3536/issue-3536.ts +++ b/test/github-issues/3536/issue-3536.ts @@ -1,7 +1,6 @@ import "reflect-metadata"; import { Connection } from "../../../src/connection/Connection"; import { closeTestingConnections, createTestingConnections } from "../../utils/test-utils"; -import { PromiseUtils } from "../../../src"; import { Roles } from "./entity/Roles"; describe("github issues > #3536 Sync only works once for enums on entities with capital letters in entity name", () => { @@ -18,8 +17,8 @@ describe("github issues > #3536 Sync only works once for enums on entities with }); after(() => closeTestingConnections(connections)); - it("should run without throw error", () => PromiseUtils.runInSequence(connections, async connection => { + it("should run without throw error", () => Promise.all(connections.map(async connection => { await connection.synchronize(); await connection.synchronize(); - })); + }))); }); diff --git a/test/github-issues/3551/issue-3551.ts b/test/github-issues/3551/issue-3551.ts index 2e89dd812ff..8d5bc5bdcc4 100644 --- a/test/github-issues/3551/issue-3551.ts +++ b/test/github-issues/3551/issue-3551.ts @@ -1,7 +1,6 @@ import "reflect-metadata"; import {Connection} from "../../../src/connection/Connection"; import {closeTestingConnections, createTestingConnections} from "../../utils/test-utils"; -import {PromiseUtils} from "../../../src"; import { Book } from "./entity/Book"; describe("github issues > #3551 array of embedded documents through multiple levels are not handled", () => { @@ -16,7 +15,7 @@ describe("github issues > #3551 array of embedded documents through multiple lev }); after(() => closeTestingConnections(connections)); - it("should return entity with all these embedded documents", () => PromiseUtils.runInSequence(connections, async connection => { + it("should return entity with all these embedded documents", () => Promise.all(connections.map(async connection => { const bookInput = { title: "Book 1", chapters: [ @@ -59,5 +58,5 @@ describe("github issues > #3551 array of embedded documents through multiple lev book!.chapters[1].pages.should.have.lengthOf(2); book!.chapters[1].pages[0].number.should.be.equal(bookInput.chapters[1].pages[0].number); book!.chapters[1].pages[1].number.should.be.equal(bookInput.chapters[1].pages[1].number); - })); -}); \ No newline at end of file + }))); +}); diff --git a/test/utils/test-utils.ts b/test/utils/test-utils.ts index 093df0c6917..ac76f4487ec 100644 --- a/test/utils/test-utils.ts +++ b/test/utils/test-utils.ts @@ -6,7 +6,6 @@ import {DatabaseType} from "../../src/driver/types/DatabaseType"; import {EntitySchema} from "../../src/entity-schema/EntitySchema"; import {createConnections} from "../../src/index"; import {NamingStrategyInterface} from "../../src/naming-strategy/NamingStrategyInterface"; -import {PromiseUtils} from "../../src/util/PromiseUtils"; import {QueryResultCache} from "../../src/cache/QueryResultCache"; import {Logger} from "../../src/logger/Logger"; @@ -252,7 +251,10 @@ export async function createTestingConnections(options?: TestingOptions): Promis }); const queryRunner = connection.createQueryRunner(); - await PromiseUtils.runInSequence(databases, database => queryRunner.createDatabase(database, true)); + + for (const database of databases) { + await queryRunner.createDatabase(database, true); + } // create new schemas if (connection.driver instanceof PostgresDriver || connection.driver instanceof SqlServerDriver) { @@ -269,7 +271,9 @@ export async function createTestingConnections(options?: TestingOptions): Promis if (schema && schemaPaths.indexOf(schema) === -1) schemaPaths.push(schema); - await PromiseUtils.runInSequence(schemaPaths, schemaPath => queryRunner.createSchema(schemaPath, true)); + for (const schemaPath of schemaPaths) { + await queryRunner.createSchema(schemaPath, true); + } } await queryRunner.release(); From b55a417ea4852ad2e66091cfa800534f7ccdd3c9 Mon Sep 17 00:00:00 2001 From: James Ward Date: Tue, 22 Sep 2020 08:42:54 -0400 Subject: [PATCH 084/212] fix: resolve issues ora-00972:identifier is too long (#6751) * fix: resolve issues ora-00972:identifier is too long Closes: #5067 * fix: ensure that this changes applies just for Oracle Driver Closes: #5067 * fix test - remove `.only` & set the `enabledDrivers` to oracle * simplify test case Co-authored-by: Murat Gundes --- src/driver/oracle/OracleDriver.ts | 2 +- test/github-issues/5067/issue-5067.ts | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 test/github-issues/5067/issue-5067.ts diff --git a/src/driver/oracle/OracleDriver.ts b/src/driver/oracle/OracleDriver.ts index 3d02f3b5375..52a2bf46f97 100644 --- a/src/driver/oracle/OracleDriver.ts +++ b/src/driver/oracle/OracleDriver.ts @@ -635,7 +635,7 @@ export class OracleDriver implements Driver { * Creates an escaped parameter. */ createParameter(parameterName: string, index: number): string { - return ":" + parameterName; + return ":" + (index + 1); } /** diff --git a/test/github-issues/5067/issue-5067.ts b/test/github-issues/5067/issue-5067.ts new file mode 100644 index 00000000000..3082a03894a --- /dev/null +++ b/test/github-issues/5067/issue-5067.ts @@ -0,0 +1,20 @@ +import "reflect-metadata"; +import {expect} from "chai"; +import {Connection} from "../../../src"; +import {closeTestingConnections, createTestingConnections} from "../../utils/test-utils"; + +describe("github issues > #5067 ORA-00972: identifier is too long", () => { + let connections: Connection[]; + before(async () => connections = await createTestingConnections({ + enabledDrivers: ["oracle"] + })); + after(() => closeTestingConnections(connections)); + + it("generated parameter name is within the size constraints", () => Promise.all(connections.map(async connection => { + const paramName = "output_that_is_really_long_and_must_be_truncated_in_this_driver"; + const createdParameter = await connection.driver.createParameter(paramName, 0); + + expect(createdParameter).to.be.an("String"); + expect(createdParameter.length).to.be.lessThan(30); + }))); +}); From 55fbb696c6c2324a67a08061322dc5726844b7d1 Mon Sep 17 00:00:00 2001 From: James Ward Date: Fri, 25 Sep 2020 22:56:41 -0400 Subject: [PATCH 085/212] fix: coerce port to number in ConnectionOptionsEnvReader (#6786) the expected type of `port` in all drivers is a number - and in MSSQL this is a problem as the underlying driver does not properly handle a string port - so we have to parseInt closes #6781 --- .../options-reader/ConnectionOptionsEnvReader.ts | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/connection/options-reader/ConnectionOptionsEnvReader.ts b/src/connection/options-reader/ConnectionOptionsEnvReader.ts index a0d00cb50b0..866b6126554 100644 --- a/src/connection/options-reader/ConnectionOptionsEnvReader.ts +++ b/src/connection/options-reader/ConnectionOptionsEnvReader.ts @@ -21,7 +21,7 @@ export class ConnectionOptionsEnvReader { type: PlatformTools.getEnvVariable("TYPEORM_CONNECTION") || (PlatformTools.getEnvVariable("TYPEORM_URL") ? PlatformTools.getEnvVariable("TYPEORM_URL").split("://")[0] : undefined), url: PlatformTools.getEnvVariable("TYPEORM_URL"), host: PlatformTools.getEnvVariable("TYPEORM_HOST"), - port: PlatformTools.getEnvVariable("TYPEORM_PORT"), + port: this.stringToNumber(PlatformTools.getEnvVariable("TYPEORM_PORT")), username: PlatformTools.getEnvVariable("TYPEORM_USERNAME"), password: PlatformTools.getEnvVariable("TYPEORM_PASSWORD"), database: PlatformTools.getEnvVariable("TYPEORM_DATABASE"), @@ -95,4 +95,14 @@ export class ConnectionOptionsEnvReader { return variable.split(",").map(str => str.trim()); } + /** + * Converts a string which contains a number into a javascript number + */ + private stringToNumber(value: any): number|undefined { + if (!value) { + return undefined; + } + + return parseInt(value); + } } From 89d83b3f477ed85ed3f16b68ecddb2998d71fed1 Mon Sep 17 00:00:00 2001 From: James Ward Date: Fri, 25 Sep 2020 22:57:27 -0400 Subject: [PATCH 086/212] refactor: move aurora-pg driver to the aurora-pg driver directory (#6785) for some reason the aurora postgres driver was living with the postgres driver - instead of in the directory explicitly for the aurora postgres driver. this moves the aurora-pg driver into that directory so there's a clearer delineation between the two drivers --- src/driver/DriverFactory.ts | 3 +- .../AuroraDataApiPostgresDriver.ts | 128 ++++++++++++++++++ .../AuroraDataApiPostgresQueryRunner.ts | 2 +- src/driver/postgres/PostgresDriver.ts | 123 ----------------- 4 files changed, 131 insertions(+), 125 deletions(-) create mode 100644 src/driver/aurora-data-api-pg/AuroraDataApiPostgresDriver.ts diff --git a/src/driver/DriverFactory.ts b/src/driver/DriverFactory.ts index e3eed40e59b..df4955a69bc 100644 --- a/src/driver/DriverFactory.ts +++ b/src/driver/DriverFactory.ts @@ -9,9 +9,10 @@ import {ReactNativeDriver} from "./react-native/ReactNativeDriver"; import {NativescriptDriver} from "./nativescript/NativescriptDriver"; import {SqljsDriver} from "./sqljs/SqljsDriver"; import {MysqlDriver} from "./mysql/MysqlDriver"; -import {PostgresDriver, AuroraDataApiPostgresDriver} from "./postgres/PostgresDriver"; +import {PostgresDriver} from "./postgres/PostgresDriver"; import {ExpoDriver} from "./expo/ExpoDriver"; import {AuroraDataApiDriver} from "./aurora-data-api/AuroraDataApiDriver"; +import {AuroraDataApiPostgresDriver} from "./aurora-data-api-pg/AuroraDataApiPostgresDriver"; import {Driver} from "./Driver"; import {Connection} from "../connection/Connection"; import {SapDriver} from "./sap/SapDriver"; diff --git a/src/driver/aurora-data-api-pg/AuroraDataApiPostgresDriver.ts b/src/driver/aurora-data-api-pg/AuroraDataApiPostgresDriver.ts new file mode 100644 index 00000000000..254ed17bf85 --- /dev/null +++ b/src/driver/aurora-data-api-pg/AuroraDataApiPostgresDriver.ts @@ -0,0 +1,128 @@ +import {Driver} from "../Driver"; +import {PostgresDriver} from "../postgres/PostgresDriver"; +import {PlatformTools} from "../../platform/PlatformTools"; +import {Connection} from "../../connection/Connection"; +import {AuroraDataApiPostgresConnectionOptions} from "../aurora-data-api-pg/AuroraDataApiPostgresConnectionOptions"; +import {AuroraDataApiPostgresQueryRunner} from "../aurora-data-api-pg/AuroraDataApiPostgresQueryRunner"; +import {ReplicationMode} from "../types/ReplicationMode"; + +abstract class PostgresWrapper extends PostgresDriver { + options: any; + + abstract createQueryRunner(mode: ReplicationMode): any; +} + +export class AuroraDataApiPostgresDriver extends PostgresWrapper implements Driver { + + // ------------------------------------------------------------------------- + // Public Properties + // ------------------------------------------------------------------------- + + /** + * Connection used by driver. + */ + connection: Connection; + + /** + * Aurora Data API underlying library. + */ + DataApiDriver: any; + + client: any; + + // ------------------------------------------------------------------------- + // Public Implemented Properties + // ------------------------------------------------------------------------- + + /** + * Connection options. + */ + options: AuroraDataApiPostgresConnectionOptions; + + /** + * Master database used to perform all write queries. + */ + database?: string; + + // ------------------------------------------------------------------------- + // Constructor + // ------------------------------------------------------------------------- + + constructor(connection: Connection) { + super(); + this.connection = connection; + this.options = connection.options as AuroraDataApiPostgresConnectionOptions; + this.isReplicated = false; + + // load data-api package + this.loadDependencies(); + + this.client = new this.DataApiDriver( + this.options.region, + this.options.secretArn, + this.options.resourceArn, + this.options.database, + (query: string, parameters?: any[]) => this.connection.logger.logQuery(query, parameters), + this.options.serviceConfigOptions, + this.options.formatOptions, + ); + } + + // ------------------------------------------------------------------------- + // Public Implemented Methods + // ------------------------------------------------------------------------- + + /** + * Performs connection to the database. + * Based on pooling options, it can either create connection immediately, + * either create a pool and create connection when needed. + */ + async connect(): Promise { + } + + /** + * Closes connection with database. + */ + async disconnect(): Promise { + } + + /** + * Creates a query runner used to execute database queries. + */ + createQueryRunner(mode: ReplicationMode) { + return new AuroraDataApiPostgresQueryRunner(this, mode); + } + + // ------------------------------------------------------------------------- + // Protected Methods + // ------------------------------------------------------------------------- + + /** + * If driver dependency is not given explicitly, then try to load it via "require". + */ + protected loadDependencies(): void { + const { pg } = PlatformTools.load("typeorm-aurora-data-api-driver"); + + this.DataApiDriver = pg; + } + + /** + * Executes given query. + */ + protected executeQuery(connection: any, query: string) { + return this.client.query(query); + } + + /** + * Makes any action after connection (e.g. create extensions in Postgres driver). + */ + async afterConnect(): Promise { + const extensionsMetadata = await this.checkMetadataForExtensions(); + + if (extensionsMetadata.hasExtensions) { + await this.enableExtensions(extensionsMetadata, this.connection); + } + + return Promise.resolve(); + } +} diff --git a/src/driver/aurora-data-api-pg/AuroraDataApiPostgresQueryRunner.ts b/src/driver/aurora-data-api-pg/AuroraDataApiPostgresQueryRunner.ts index f9ec0cb06d8..a0ed3899ef7 100644 --- a/src/driver/aurora-data-api-pg/AuroraDataApiPostgresQueryRunner.ts +++ b/src/driver/aurora-data-api-pg/AuroraDataApiPostgresQueryRunner.ts @@ -3,7 +3,7 @@ import {TransactionAlreadyStartedError} from "../../error/TransactionAlreadyStar import {TransactionNotStartedError} from "../../error/TransactionNotStartedError"; import {QueryRunner} from "../../query-runner/QueryRunner"; import {IsolationLevel} from "../types/IsolationLevel"; -import {AuroraDataApiPostgresDriver} from "../postgres/PostgresDriver"; +import {AuroraDataApiPostgresDriver} from "./AuroraDataApiPostgresDriver"; import {PostgresQueryRunner} from "../postgres/PostgresQueryRunner"; import {ReplicationMode} from "../types/ReplicationMode"; diff --git a/src/driver/postgres/PostgresDriver.ts b/src/driver/postgres/PostgresDriver.ts index d65c4c6b950..bb5f2f34dfa 100644 --- a/src/driver/postgres/PostgresDriver.ts +++ b/src/driver/postgres/PostgresDriver.ts @@ -19,8 +19,6 @@ import {PostgresConnectionCredentialsOptions} from "./PostgresConnectionCredenti import {EntityMetadata} from "../../metadata/EntityMetadata"; import {OrmUtils} from "../../util/OrmUtils"; import {ApplyValueTransformers} from "../../util/ApplyValueTransformers"; -import {AuroraDataApiPostgresConnectionOptions} from "../aurora-data-api-pg/AuroraDataApiPostgresConnectionOptions"; -import {AuroraDataApiPostgresQueryRunner} from "../aurora-data-api-pg/AuroraDataApiPostgresQueryRunner"; import {ReplicationMode} from "../types/ReplicationMode"; /** @@ -1040,124 +1038,3 @@ export class PostgresDriver implements Driver { } } - -abstract class PostgresWrapper extends PostgresDriver { - options: any; - - abstract createQueryRunner(mode: ReplicationMode): any; -} - -export class AuroraDataApiPostgresDriver extends PostgresWrapper { - - // ------------------------------------------------------------------------- - // Public Properties - // ------------------------------------------------------------------------- - - /** - * Connection used by driver. - */ - connection: Connection; - - /** - * Aurora Data API underlying library. - */ - DataApiDriver: any; - - client: any; - - // ------------------------------------------------------------------------- - // Public Implemented Properties - // ------------------------------------------------------------------------- - - /** - * Connection options. - */ - options: AuroraDataApiPostgresConnectionOptions; - - /** - * Master database used to perform all write queries. - */ - database?: string; - - // ------------------------------------------------------------------------- - // Constructor - // ------------------------------------------------------------------------- - - constructor(connection: Connection) { - super(); - this.connection = connection; - this.options = connection.options as AuroraDataApiPostgresConnectionOptions; - this.isReplicated = false; - - // load data-api package - this.loadDependencies(); - - this.client = new this.DataApiDriver( - this.options.region, - this.options.secretArn, - this.options.resourceArn, - this.options.database, - (query: string, parameters?: any[]) => this.connection.logger.logQuery(query, parameters), - this.options.serviceConfigOptions, - this.options.formatOptions, - ); - } - - // ------------------------------------------------------------------------- - // Public Implemented Methods - // ------------------------------------------------------------------------- - - /** - * Performs connection to the database. - * Based on pooling options, it can either create connection immediately, - * either create a pool and create connection when needed. - */ - async connect(): Promise { - } - - /** - * Closes connection with database. - */ - async disconnect(): Promise { - } - - /** - * Creates a query runner used to execute database queries. - */ - createQueryRunner(mode: ReplicationMode) { - return new AuroraDataApiPostgresQueryRunner(this, mode); - } - - // ------------------------------------------------------------------------- - // Protected Methods - // ------------------------------------------------------------------------- - - /** - * If driver dependency is not given explicitly, then try to load it via "require". - */ - protected loadDependencies(): void { - const { pg } = PlatformTools.load("typeorm-aurora-data-api-driver"); - - this.DataApiDriver = pg; - } - - /** - * Executes given query. - */ - protected executeQuery(connection: any, query: string) { - return this.client.query(query); - } - - /** - * Makes any action after connection (e.g. create extensions in Postgres driver). - */ - async afterConnect(): Promise { - const extensionsMetadata = await this.checkMetadataForExtensions(); - - if (extensionsMetadata.hasExtensions) { - await this.enableExtensions(extensionsMetadata, this.connection); - } - - return Promise.resolve(); - } -} From 180fbd415da80ce383b426f6d38486aa3826296d Mon Sep 17 00:00:00 2001 From: James Ward Date: Fri, 25 Sep 2020 23:03:30 -0400 Subject: [PATCH 087/212] fix: add dummy for FileLogger, ConnectionOptionsReaders, and update gulpfile (#6763) --- gulpfile.ts | 32 ++--------- package.json | 5 ++ src/connection/ConnectionOptionsReader.ts | 8 +-- .../ConnectionOptionsEnvReader.ts | 6 +- .../ConnectionOptionsYmlReader.ts | 2 +- ...owserConnectionOptionsReaderDummy.template | 55 +++++++++++++++++++ src/platform/BrowserFileLoggerDummy.template | 50 +++++++++++++++++ 7 files changed, 124 insertions(+), 34 deletions(-) create mode 100644 src/platform/BrowserConnectionOptionsReaderDummy.template create mode 100644 src/platform/BrowserFileLoggerDummy.template diff --git a/gulpfile.ts b/gulpfile.ts index 7d0fbeb05de..18edf52cb99 100644 --- a/gulpfile.ts +++ b/gulpfile.ts @@ -64,38 +64,18 @@ export class Gulpfile { "!./src/commands/*.ts", "!./src/cli.ts", "!./src/typeorm.ts", - "!./src/typeorm-model-shim.ts", - "!./src/platform/PlatformTools.ts" + "!./src/typeorm-model-shim.ts" ]) .pipe(gulp.dest("./build/browser/src")); } /** - * Replaces PlatformTools with browser-specific implementation called BrowserPlatformTools. + * Copies templates for compilation */ @Task() - browserCopyDirectoryExportedClassesLoader() { - return gulp.src("./src/platform/BrowserDirectoryExportedClassesLoader.template") - .pipe(rename("BrowserDirectoryExportedClassesLoader.ts")) - .pipe(gulp.dest("./build/browser/src/platform")); - } - /** - * Replaces PlatformTools with browser-specific implementation called BrowserPlatformTools. - */ - @Task() - browserCopyPlatformTools() { - return gulp.src("./src/platform/BrowserPlatformTools.template") - .pipe(rename("PlatformTools.ts")) - .pipe(gulp.dest("./build/browser/src/platform")); - } - - /** - * Adds dummy classes for disabled drivers (replacement is done via browser entry point in package.json) - */ - @Task() - browserCopyDisabledDriversDummy() { - return gulp.src("./src/platform/BrowserDisabledDriversDummy.template") - .pipe(rename("BrowserDisabledDriversDummy.ts")) + browserCopyTemplates() { + return gulp.src("./src/platform/*.template") + .pipe(rename((p: any) => { p.extname = '.ts'; })) .pipe(gulp.dest("./build/browser/src/platform")); } @@ -242,7 +222,7 @@ export class Gulpfile { package() { return [ "clean", - ["browserCopySources", "browserCopyPlatformTools", "browserCopyDisabledDriversDummy", "browserCopyDirectoryExportedClassesLoader"], + ["browserCopySources", "browserCopyTemplates"], ["packageCompile", "browserCompile"], "packageMoveCompiledFiles", [ diff --git a/package.json b/package.json index 60b1a0fe028..3404d7b2b8e 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,11 @@ "./browser/driver/sqlite/SqliteDriver.js": "./browser/platform/BrowserDisabledDriversDummy.js", "./browser/driver/better-sqlite3/BetterSqlite3Driver.js": "./browser/platform/BrowserDisabledDriversDummy.js", "./browser/util/DirectoryExportedClassesLoader.js": "./browser/platform/BrowserDirectoryExportedClassesLoader.js", + "./browser/logger/FileLogger.js": "./browser/platform/BrowserFileLoggerDummy.js", + "./browser/connection/ConnectionOptionsReader.js": "./browser/platform/BrowserConnectionOptionsReaderDummy.js", + "./browser/connection/options-reader/ConnectionOptionsXmlReader.js": "./browser/platform/BrowserConnectionOptionsReaderDummy.js", + "./browser/connection/options-reader/ConnectionOptionsYmlReader.js": "./browser/platform/BrowserConnectionOptionsReaderDummy.js", + "./browser/platform/PlatformTools.js": "./browser/platform/BrowserPlatformTools.js", "./index.js": "./browser/index.js" }, "repository": { diff --git a/src/connection/ConnectionOptionsReader.ts b/src/connection/ConnectionOptionsReader.ts index 997c2405545..af66a4d5663 100644 --- a/src/connection/ConnectionOptionsReader.ts +++ b/src/connection/ConnectionOptionsReader.ts @@ -103,8 +103,8 @@ export class ConnectionOptionsReader { const configFile = fileExtension ? this.baseFilePath : this.baseFilePath + "." + foundFileFormat; // try to find connection options from any of available sources of configuration - if (PlatformTools.getEnvVariable("TYPEORM_CONNECTION") || PlatformTools.getEnvVariable("TYPEORM_URL")) { - connectionOptions = new ConnectionOptionsEnvReader().read(); + if (PlatformTools.getEnvVariable("TYPEORM_CONNECTION") || PlatformTools.getEnvVariable("TYPEORM_URL")) { + connectionOptions = await new ConnectionOptionsEnvReader().read(); } else if (foundFileFormat === "js" || foundFileFormat === "cjs") { connectionOptions = await require(configFile); @@ -116,10 +116,10 @@ export class ConnectionOptionsReader { connectionOptions = require(configFile); } else if (foundFileFormat === "yml") { - connectionOptions = new ConnectionOptionsYmlReader().read(configFile); + connectionOptions = await new ConnectionOptionsYmlReader().read(configFile); } else if (foundFileFormat === "yaml") { - connectionOptions = new ConnectionOptionsYmlReader().read(configFile); + connectionOptions = await new ConnectionOptionsYmlReader().read(configFile); } else if (foundFileFormat === "xml") { connectionOptions = await new ConnectionOptionsXmlReader().read(configFile); diff --git a/src/connection/options-reader/ConnectionOptionsEnvReader.ts b/src/connection/options-reader/ConnectionOptionsEnvReader.ts index 866b6126554..9ad12910048 100644 --- a/src/connection/options-reader/ConnectionOptionsEnvReader.ts +++ b/src/connection/options-reader/ConnectionOptionsEnvReader.ts @@ -16,8 +16,8 @@ export class ConnectionOptionsEnvReader { /** * Reads connection options from environment variables. */ - read(): ConnectionOptions { - return { + async read(): Promise { + return [{ type: PlatformTools.getEnvVariable("TYPEORM_CONNECTION") || (PlatformTools.getEnvVariable("TYPEORM_URL") ? PlatformTools.getEnvVariable("TYPEORM_URL").split("://")[0] : undefined), url: PlatformTools.getEnvVariable("TYPEORM_URL"), host: PlatformTools.getEnvVariable("TYPEORM_HOST"), @@ -47,7 +47,7 @@ export class ConnectionOptionsEnvReader { }, cache: this.transformCaching(), uuidExtension: PlatformTools.getEnvVariable("TYPEORM_UUID_EXTENSION") - }; + }]; } // ------------------------------------------------------------------------- diff --git a/src/connection/options-reader/ConnectionOptionsYmlReader.ts b/src/connection/options-reader/ConnectionOptionsYmlReader.ts index 7c14a4d28f9..f43dd8867ec 100644 --- a/src/connection/options-reader/ConnectionOptionsYmlReader.ts +++ b/src/connection/options-reader/ConnectionOptionsYmlReader.ts @@ -14,7 +14,7 @@ export class ConnectionOptionsYmlReader { /** * Reads connection options from given yml file. */ - read(path: string): ConnectionOptions[] { + async read(path: string): Promise { const contentsBuffer = PlatformTools.readFileSync(path); const contents = contentsBuffer.toString(); diff --git a/src/platform/BrowserConnectionOptionsReaderDummy.template b/src/platform/BrowserConnectionOptionsReaderDummy.template new file mode 100644 index 00000000000..c3343dc50ab --- /dev/null +++ b/src/platform/BrowserConnectionOptionsReaderDummy.template @@ -0,0 +1,55 @@ +/** + * Dummy class for replacement via `package.json` in browser builds. + * + * If we don't include these functions typeorm will throw an error on runtime + * as well as during webpack builds. + */ +export class ConnectionOptionsEnvReader { + async read() { + throw new Error(`Cannot read connection options in a browser context.`); + } +} + +/** + * Dummy class for replacement via `package.json` in browser builds. + * + * If we don't include these functions typeorm will throw an error on runtime + * as well as during webpack builds. + */ +export class ConnectionOptionsXmlReader { + async read(path: string) { + throw new Error(`Cannot read connection options in a browser context.`); + } +} + +/** + * Dummy class for replacement via `package.json` in browser builds. + * + * If we don't include these functions typeorm will throw an error on runtime + * as well as during webpack builds. + */ +export class ConnectionOptionsYmlReader { + async read(path: string) { + throw new Error(`Cannot read connection options in a browser context.`); + } +} + +/** + * Dummy class for replacement via `package.json` in browser builds. + * + * If we don't include these functions typeorm will throw an error on runtime + * as well as during webpack builds. + */ +export class ConnectionOptionsReader { + async all() { + throw new Error(`Cannot read connection options in a browser context.`); + } + + async get() { + throw new Error(`Cannot read connection options in a browser context.`); + } + + async has() { + throw new Error(`Cannot read connection options in a browser context.`); + } +} diff --git a/src/platform/BrowserFileLoggerDummy.template b/src/platform/BrowserFileLoggerDummy.template new file mode 100644 index 00000000000..7277fe47ade --- /dev/null +++ b/src/platform/BrowserFileLoggerDummy.template @@ -0,0 +1,50 @@ +/** + * Performs logging of the events in TypeORM. + * This version of logger logs everything into ormlogs.log file. + */ +export class DummyLogger { + /** + * Logs query and parameters used in it. + */ + logQuery() { + throw new Error('This logger is not applicable in a browser context'); + } + + /** + * Logs query that is failed. + */ + logQueryError() { + throw new Error('This logger is not applicable in a browser context'); + } + + /** + * Logs query that is slow. + */ + logQuerySlow() { + throw new Error('This logger is not applicable in a browser context'); + } + + /** + * Logs events from the schema build process. + */ + logSchemaBuild() { + throw new Error('This logger is not applicable in a browser context'); + } + + /** + * Logs events from the migrations run process. + */ + logMigration() { + throw new Error('This logger is not applicable in a browser context'); + } + + /** + * Perform logging using given logger, or by default to the console. + * Log has its own level and message. + */ + log() { + throw new Error('This logger is not applicable in a browser context'); + } +} + +export class FileLogger extends DummyLogger {} From dfcb2db216d6ed33946dfa190e19eb14c0fed390 Mon Sep 17 00:00:00 2001 From: Akosua Date: Sat, 26 Sep 2020 03:57:13 -0400 Subject: [PATCH 088/212] fix: enforce name argument of migration generate command (#2719) (#6690) * fix: enforce name argument of migration generate command enforce the type of the name argument in order to return a more useful error message when the user forgets to provide a migration name to the generate migration command Closes: #2719, #4798, #4805 * fix: update error message text for generate migration command when missing name argument enforce the type of the name argument in order to return a more useful error message when the user forgets to provide a migration name to the generate migration command Closes: #2719, #4798, #4805 Co-authored-by: Akosua Asante --- src/commands/MigrationGenerateCommand.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/commands/MigrationGenerateCommand.ts b/src/commands/MigrationGenerateCommand.ts index a17005ca2d1..cdb098c2998 100644 --- a/src/commands/MigrationGenerateCommand.ts +++ b/src/commands/MigrationGenerateCommand.ts @@ -28,7 +28,8 @@ export class MigrationGenerateCommand implements yargs.CommandModule { .option("n", { alias: "name", describe: "Name of the migration class.", - demand: true + demand: true, + type: "string" }) .option("d", { alias: "dir", @@ -121,7 +122,7 @@ export class MigrationGenerateCommand implements yargs.CommandModule { console.log(chalk.green(`Migration ${chalk.blue(path)} has been generated successfully.`)); } else { - console.log(chalk.yellow("Please specify migration name")); + console.log(chalk.yellow("Please specify a migration name using the `-n` argument")); } } else { console.log(chalk.yellow(`No changes in database schema were found - cannot generate a migration. To create a new empty migration use "typeorm migration:create" command`)); From 44aff1712c168825827b5695cc3de70bde88d23e Mon Sep 17 00:00:00 2001 From: James Ward Date: Tue, 29 Sep 2020 12:28:05 -0400 Subject: [PATCH 089/212] refactor: Move `FindOperator` SQL generation into QueryBuilder (#6797) --- src/find-options/FindOperator.ts | 62 +++++++------------------------ src/query-builder/QueryBuilder.ts | 48 +++++++++++++++++++++++- 2 files changed, 60 insertions(+), 50 deletions(-) diff --git a/src/find-options/FindOperator.ts b/src/find-options/FindOperator.ts index d9c0ce69d54..fd0dae0b962 100644 --- a/src/find-options/FindOperator.ts +++ b/src/find-options/FindOperator.ts @@ -1,7 +1,4 @@ import {FindOperatorType} from "./FindOperatorType"; -import {Connection} from "../"; -import {OracleDriver} from "../driver/oracle/OracleDriver"; -import {MysqlDriver} from "../driver/mysql/MysqlDriver"; /** * Find Operator used in Find Conditions. @@ -69,6 +66,13 @@ export class FindOperator { return this._multipleParameters; } + /** + * Gets the Type of this FindOperator + */ + get type(): string { + return this._type; + } + /** * Gets the final value needs to be used as parameter value. */ @@ -79,53 +83,13 @@ export class FindOperator { return this._value; } - // ------------------------------------------------------------------------- - // Public Methods - // ------------------------------------------------------------------------- - /** - * Gets SQL needs to be inserted into final query. + * Gets the child FindOperator if it exists */ - toSql(connection: Connection, aliasPath: string, parameters: string[]): string { - switch (this._type) { - case "not": - if (this._value instanceof FindOperator) { - return `NOT(${this._value.toSql(connection, aliasPath, parameters)})`; - } else { - return `${aliasPath} != ${parameters[0]}`; - } - case "lessThan": - return `${aliasPath} < ${parameters[0]}`; - case "lessThanOrEqual": - return `${aliasPath} <= ${parameters[0]}`; - case "moreThan": - return `${aliasPath} > ${parameters[0]}`; - case "moreThanOrEqual": - return `${aliasPath} >= ${parameters[0]}`; - case "equal": - return `${aliasPath} = ${parameters[0]}`; - case "like": - return `${aliasPath} LIKE ${parameters[0]}`; - case "between": - return `${aliasPath} BETWEEN ${parameters[0]} AND ${parameters[1]}`; - case "in": - if ((connection.driver instanceof OracleDriver || connection.driver instanceof MysqlDriver) && parameters.length === 0) { - return `${aliasPath} IN (null)`; - } - return `${aliasPath} IN (${parameters.join(", ")})`; - case "any": - return `${aliasPath} = ANY(${parameters[0]})`; - case "isNull": - return `${aliasPath} IS NULL`; - case "raw": - if (this.value instanceof Function) { - return this.value(aliasPath); - } else { - return `${aliasPath} = ${this.value}`; - } - } - - return ""; - } + get child(): FindOperator|undefined { + if (this._value instanceof FindOperator) + return this._value; + return undefined; + } } diff --git a/src/query-builder/QueryBuilder.ts b/src/query-builder/QueryBuilder.ts index a1756f351b4..afb383ddd0a 100644 --- a/src/query-builder/QueryBuilder.ts +++ b/src/query-builder/QueryBuilder.ts @@ -17,6 +17,7 @@ import {ColumnMetadata} from "../metadata/ColumnMetadata"; import {SqljsDriver} from "../driver/sqljs/SqljsDriver"; import {SqlServerDriver} from "../driver/sqlserver/SqlServerDriver"; import {OracleDriver} from "../driver/oracle/OracleDriver"; +import {MysqlDriver} from "../driver/mysql/MysqlDriver"; import {EntitySchema} from "../"; import {FindOperator} from "../find-options/FindOperator"; import {In} from "../find-options/operator/In"; @@ -816,8 +817,8 @@ export abstract class QueryBuilder { parameters.push(this.connection.driver.createParameter(parameterName + (parameterBaseCount + realParameterValueIndex), parameterIndex - 1)); }); } - return parameterValue.toSql(this.connection, aliasPath, parameters); + return this.computeFindOperatorExpression(parameterValue, aliasPath, parameters); } else { this.expressionMap.nativeParameters[parameterName] = parameterValue; parameterIndex++; @@ -856,6 +857,51 @@ export abstract class QueryBuilder { return ""; } + /** + * Gets SQL needs to be inserted into final query. + */ + protected computeFindOperatorExpression(operator: FindOperator, aliasPath: string, parameters: any[]): string { + switch (operator.type) { + case "not": + if (operator.child) { + return `NOT(${this.computeFindOperatorExpression(operator.child, aliasPath, parameters)})`; + } else { + return `${aliasPath} != ${parameters[0]}`; + } + case "lessThan": + return `${aliasPath} < ${parameters[0]}`; + case "lessThanOrEqual": + return `${aliasPath} <= ${parameters[0]}`; + case "moreThan": + return `${aliasPath} > ${parameters[0]}`; + case "moreThanOrEqual": + return `${aliasPath} >= ${parameters[0]}`; + case "equal": + return `${aliasPath} = ${parameters[0]}`; + case "like": + return `${aliasPath} LIKE ${parameters[0]}`; + case "between": + return `${aliasPath} BETWEEN ${parameters[0]} AND ${parameters[1]}`; + case "in": + if ((this.connection.driver instanceof OracleDriver || this.connection.driver instanceof MysqlDriver) && parameters.length === 0) { + return `${aliasPath} IN (null)`; + } + return `${aliasPath} IN (${parameters.join(", ")})`; + case "any": + return `${aliasPath} = ANY(${parameters[0]})`; + case "isNull": + return `${aliasPath} IS NULL`; + case "raw": + if (typeof operator.value === "function") { + return operator.value(aliasPath); + } else { + return `${aliasPath} = ${operator.value}`; + } + } + + throw new TypeError(`Unsupported FindOperator ${FindOperator.constructor.name}`); + } + /** * Creates a query builder used to execute sql queries inside this query builder. */ From c1c8e88f8945bf6a03bde728de370f5c61c5bdb8 Mon Sep 17 00:00:00 2001 From: James Ward Date: Tue, 29 Sep 2020 12:39:37 -0400 Subject: [PATCH 090/212] fix: prevent wrong returned entity in ReturningResultsEntityUpdator (#6440) in the `ReturningResultsEntityUpdator` we have to check that the `entityId` we pull from the entity is actually there. if we don't we will create a where clause that's undefined - effectively querying for every record in the database and returning the wrong value --- src/query-builder/ReturningResultsEntityUpdator.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/query-builder/ReturningResultsEntityUpdator.ts b/src/query-builder/ReturningResultsEntityUpdator.ts index 2080dcf366b..c669dd9c10e 100644 --- a/src/query-builder/ReturningResultsEntityUpdator.ts +++ b/src/query-builder/ReturningResultsEntityUpdator.ts @@ -119,6 +119,13 @@ export class ReturningResultsEntityUpdator { if (this.queryRunner.connection.driver.isReturningSqlSupported() === false && insertionColumns.length > 0) { const entityIds = entities.map((entity) => { const entityId = metadata.getEntityIdMap(entity)!; + + // We have to check for an empty `entityId` - if we don't, the query against the database + // effectively drops the `where` clause entirely and the first record will be returned - + // not what we want at all. + if (!entityId) + throw new Error(`Cannot update entity because entity id is not set in the entity.`); + return entityId; }); From 45b980cf7fd61b0ee2e9560d9aadb96ce331d5cb Mon Sep 17 00:00:00 2001 From: Umed Khudoiberdiev Date: Tue, 29 Sep 2020 21:40:16 +0500 Subject: [PATCH 091/212] Revert "fix: properly override database url properties (#6247)" (#6802) This reverts commit 0ba2a48efdf18977ff5df55b950e763255c75ffc. --- src/driver/DriverUtils.ts | 2 +- test/github-issues/4878/issue-4878.ts | 19 ------------------- 2 files changed, 1 insertion(+), 20 deletions(-) delete mode 100644 test/github-issues/4878/issue-4878.ts diff --git a/src/driver/DriverUtils.ts b/src/driver/DriverUtils.ts index 56d7309d9f9..f6da56b5645 100644 --- a/src/driver/DriverUtils.ts +++ b/src/driver/DriverUtils.ts @@ -28,7 +28,7 @@ export class DriverUtils { if (buildOptions && buildOptions.useSid) { urlDriverOptions.sid = parsedUrl.database; } - return Object.assign({}, urlDriverOptions, options); + return Object.assign({}, options, urlDriverOptions); } return Object.assign({}, options); } diff --git a/test/github-issues/4878/issue-4878.ts b/test/github-issues/4878/issue-4878.ts deleted file mode 100644 index 8359d8b0eda..00000000000 --- a/test/github-issues/4878/issue-4878.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { DriverUtils } from "../../../src/driver/DriverUtils"; -import { expect } from "chai"; - -describe("github issues > #4878 URL Connection string not overridden by supplied options", () => { - it("should override url-built options with user-supplied options", () => { - const obj: any = { - username: "user", - password: "password", - host: "host", - database: "database", - port: 8888 - }; - - const url = `postgres://url_user:${obj.password}@${obj.host}:${obj.port}/${obj.database}`; - obj.url = url; - const options = DriverUtils.buildDriverOptions(obj); - expect(options.username).to.eql(obj.username); - }); -}); From 78a6ee90854f361bc0721ed338460b563b1fc119 Mon Sep 17 00:00:00 2001 From: Umed Khudoiberdiev Date: Tue, 29 Sep 2020 22:09:45 +0500 Subject: [PATCH 092/212] version bump --- CHANGELOG.md | 28 ++++++++++++++++++++++++++++ package-lock.json | 12 ++++++------ package.json | 2 +- 3 files changed, 35 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 676a6c4ec15..b43ef66fd45 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,31 @@ +## [0.2.27](https://github.com/typeorm/typeorm/compare/0.2.26...0.2.27) (2020-09-29) + +### Bug Fixes + +* add dummy for FileLogger, ConnectionOptionsReaders, and update gulpfile ([#6763](https://github.com/typeorm/typeorm/issues/6763)) ([180fbd4](https://github.com/typeorm/typeorm/commit/180fbd415da80ce383b426f6d38486aa3826296d)) +* backport FindOperator return types ([#6717](https://github.com/typeorm/typeorm/issues/6717)) ([2b37808](https://github.com/typeorm/typeorm/commit/2b3780836f5fd737fdc58fe4e0eb2ea4200cae66)) +* coerce port to number in ConnectionOptionsEnvReader ([#6786](https://github.com/typeorm/typeorm/issues/6786)) ([55fbb69](https://github.com/typeorm/typeorm/commit/55fbb696c6c2324a67a08061322dc5726844b7d1)), closes [#6781](https://github.com/typeorm/typeorm/issues/6781) +* count() method for multiple primary keys for cockroachdb ([#6745](https://github.com/typeorm/typeorm/issues/6745)) ([dfe8259](https://github.com/typeorm/typeorm/commit/dfe8259ef53a432f1c02607e6ffee662dd4fd8a9)) +* enforce name argument of migration generate command ([#2719](https://github.com/typeorm/typeorm/issues/2719)) ([#6690](https://github.com/typeorm/typeorm/issues/6690)) ([dfcb2db](https://github.com/typeorm/typeorm/commit/dfcb2db216d6ed33946dfa190e19eb14c0fed390)), closes [#4798](https://github.com/typeorm/typeorm/issues/4798) [#4805](https://github.com/typeorm/typeorm/issues/4805) [#4798](https://github.com/typeorm/typeorm/issues/4798) [#4805](https://github.com/typeorm/typeorm/issues/4805) +* ensure browser builds don't include any non-browser modules ([#6743](https://github.com/typeorm/typeorm/issues/6743)) ([c714867](https://github.com/typeorm/typeorm/commit/c714867d3d0c43ccbb7ca8fb3ce969207e4d5c04)), closes [#6739](https://github.com/typeorm/typeorm/issues/6739) +* hdb-pool is not namespaced under [@sap](https://github.com/sap) ([#6700](https://github.com/typeorm/typeorm/issues/6700)) ([9583430](https://github.com/typeorm/typeorm/commit/9583430e8282d1ad758724957971a5d5d9664f63)), closes [#6697](https://github.com/typeorm/typeorm/issues/6697) +* migration:generate issue with onUpdate using mariadb 10.4 ([#6714](https://github.com/typeorm/typeorm/issues/6714)) ([6e28322](https://github.com/typeorm/typeorm/commit/6e28322ca65ba739bf0d767075016bc0cae7a48c)) +* prevent multiple `release` listeners in PostgresQueryRunner ([#6708](https://github.com/typeorm/typeorm/issues/6708)) ([208cf6b](https://github.com/typeorm/typeorm/commit/208cf6b0511a2d565c7999837497bb6cf8f8e7c7)), closes [#6699](https://github.com/typeorm/typeorm/issues/6699) +* prevent wrong returned entity in ReturningResultsEntityUpdator ([#6440](https://github.com/typeorm/typeorm/issues/6440)) ([c1c8e88](https://github.com/typeorm/typeorm/commit/c1c8e88f8945bf6a03bde728de370f5c61c5bdb8)) +* resolve issues ora-00972:identifier is too long ([#6751](https://github.com/typeorm/typeorm/issues/6751)) ([b55a417](https://github.com/typeorm/typeorm/commit/b55a417ea4852ad2e66091cfa800534f7ccdd3c9)), closes [#5067](https://github.com/typeorm/typeorm/issues/5067) [#5067](https://github.com/typeorm/typeorm/issues/5067) +* sql.js v1.2+ don't support undefined parameters ([#6698](https://github.com/typeorm/typeorm/issues/6698)) ([ea59b8d](https://github.com/typeorm/typeorm/commit/ea59b8d46b2a36ac251f43c8a8fb98ff15ab4e2d)), closes [#5720](https://github.com/typeorm/typeorm/issues/5720) + +### Features + +* add option to pass postgres server notices to client logger ([#6215](https://github.com/typeorm/typeorm/issues/6215)) ([5084e47](https://github.com/typeorm/typeorm/commit/5084e47be4fd42316ad47e6102645534fae45d9f)), closes [#2216](https://github.com/typeorm/typeorm/issues/2216) +* backport SQLite Busy handler & WAL mode enable ([#6588](https://github.com/typeorm/typeorm/issues/6588)) ([7a52f18](https://github.com/typeorm/typeorm/commit/7a52f18c86613292c3503484eac332f59141a6e3)) +* Beautify generated SQL for migrations ([#6685](https://github.com/typeorm/typeorm/issues/6685)) ([370442c](https://github.com/typeorm/typeorm/commit/370442c27a0aecd67eeb44f6077922dda16bcef8)), closes [#4415](https://github.com/typeorm/typeorm/issues/4415) +* create EntityTarget and use instead of EntitySchema / ObjectType / etc ([#6701](https://github.com/typeorm/typeorm/issues/6701)) ([8b68f40](https://github.com/typeorm/typeorm/commit/8b68f40a01b6cdc0e8d21492d988fe21cbef64de)) + +### Reverts + +* Revert "fix: properly override database url properties (#6247)" (#6802) ([45b980c](https://github.com/typeorm/typeorm/commit/45b980cf7fd61b0ee2e9560d9aadb96ce331d5cb)), closes [#6247](https://github.com/typeorm/typeorm/issues/6247) [#6802](https://github.com/typeorm/typeorm/issues/6802) + ## [0.2.26](https://github.com/typeorm/typeorm/compare/0.2.25...0.2.26) (2020-09-10) ### Bug Fixes diff --git a/package-lock.json b/package-lock.json index f16c8bf78f7..35b2f1065b3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6331,7 +6331,7 @@ }, "is-accessor-descriptor": { "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "resolved": "http://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", "dev": true, "requires": { @@ -6393,7 +6393,7 @@ }, "is-data-descriptor": { "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "resolved": "http://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", "dev": true, "requires": { @@ -7176,7 +7176,7 @@ }, "load-json-file": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", "dev": true, "requires": { @@ -7189,7 +7189,7 @@ "dependencies": { "pify": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", "dev": true } @@ -9250,7 +9250,7 @@ "dependencies": { "pify": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", "dev": true } @@ -10854,7 +10854,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { diff --git a/package.json b/package.json index 3404d7b2b8e..280fe68499f 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "typeorm", "private": true, - "version": "0.2.26", + "version": "0.2.27", "description": "Data-Mapper ORM for TypeScript, ES7, ES6, ES5. Supports MySQL, PostgreSQL, MariaDB, SQLite, MS SQL Server, Oracle, MongoDB databases.", "license": "MIT", "readmeFilename": "README.md", From 7f7e4d53119506bdbb86999606707cd740859fe7 Mon Sep 17 00:00:00 2001 From: James Ward Date: Wed, 30 Sep 2020 03:16:33 -0400 Subject: [PATCH 093/212] fix: lock Typescript to 3.6.0 (#6810) Because of a breaking feature in Typescript 3.7.0 we cannot upgrade past that without marooning users of Typescript 3.5 / 3.6 & 4.0+ this locks typescript to ~3.6.0 explicitly and fixes some small issues that arise in using that version fixes #6809 fixes #6805 --- package-lock.json | 16 ++++++++-------- package.json | 2 +- src/entity-manager/MongoEntityManager.ts | 4 ++-- src/find-options/FindOptionsUtils.ts | 8 ++++---- tsconfig.json | 6 +++++- 5 files changed, 20 insertions(+), 16 deletions(-) diff --git a/package-lock.json b/package-lock.json index 35b2f1065b3..b24e1743a00 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "typeorm", - "version": "0.2.26", + "version": "0.2.27", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -6331,7 +6331,7 @@ }, "is-accessor-descriptor": { "version": "0.1.6", - "resolved": "http://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", "dev": true, "requires": { @@ -6393,7 +6393,7 @@ }, "is-data-descriptor": { "version": "0.1.4", - "resolved": "http://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", "dev": true, "requires": { @@ -7176,7 +7176,7 @@ }, "load-json-file": { "version": "1.1.0", - "resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", "dev": true, "requires": { @@ -10854,7 +10854,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { @@ -11463,9 +11463,9 @@ } }, "typescript": { - "version": "3.9.7", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.7.tgz", - "integrity": "sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw==", + "version": "3.6.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.6.5.tgz", + "integrity": "sha512-BEjlc0Z06ORZKbtcxGrIvvwYs5hAnuo6TKdNFL55frVDlB+na3z5bsLhFaIxmT+dPWgBIjMo6aNnTOgHHmHgiQ==", "dev": true }, "uglify-js": { diff --git a/package.json b/package.json index 280fe68499f..90efb181c57 100644 --- a/package.json +++ b/package.json @@ -111,7 +111,7 @@ "sqlite3": "^5.0.0", "ts-node": "^9.0.0", "typeorm-aurora-data-api-driver": "^1.4.0", - "typescript": "^3.9.7" + "typescript": "~3.6.0" }, "dependencies": { "@sqltools/formatter": "1.2.2", diff --git a/src/entity-manager/MongoEntityManager.ts b/src/entity-manager/MongoEntityManager.ts index 1a5ce451993..b8b8761a09a 100644 --- a/src/entity-manager/MongoEntityManager.ts +++ b/src/entity-manager/MongoEntityManager.ts @@ -570,7 +570,7 @@ export class MongoEntityManager extends EntityManager { if (!optionsOrConditions) return undefined; - if (FindOptionsUtils.isFindManyOptions(optionsOrConditions)) + if (FindOptionsUtils.isFindManyOptions(optionsOrConditions)) // If where condition is passed as a string which contains sql we have to ignore // as mongo is not a sql database return typeof optionsOrConditions.where === "string" @@ -587,7 +587,7 @@ export class MongoEntityManager extends EntityManager { if (!optionsOrConditions) return undefined; - if (FindOptionsUtils.isFindOneOptions(optionsOrConditions)) + if (FindOptionsUtils.isFindOneOptions(optionsOrConditions)) // If where condition is passed as a string which contains sql we have to ignore // as mongo is not a sql database return typeof optionsOrConditions.where === "string" diff --git a/src/find-options/FindOptionsUtils.ts b/src/find-options/FindOptionsUtils.ts index 4ecdcd7114f..cec9f17ae13 100644 --- a/src/find-options/FindOptionsUtils.ts +++ b/src/find-options/FindOptionsUtils.ts @@ -17,8 +17,8 @@ export class FindOptionsUtils { /** * Checks if given object is really instance of FindOneOptions interface. */ - static isFindOneOptions(obj: any): obj is FindOneOptions { - const possibleOptions: FindOneOptions = obj; + static isFindOneOptions(obj: any): obj is FindOneOptions { + const possibleOptions: FindOneOptions = obj; return possibleOptions && ( Array.isArray(possibleOptions.select) || @@ -41,8 +41,8 @@ export class FindOptionsUtils { /** * Checks if given object is really instance of FindManyOptions interface. */ - static isFindManyOptions(obj: any): obj is FindManyOptions { - const possibleOptions: FindManyOptions = obj; + static isFindManyOptions(obj: any): obj is FindManyOptions { + const possibleOptions: FindManyOptions = obj; return possibleOptions && ( this.isFindOneOptions(possibleOptions) || typeof (possibleOptions as FindManyOptions).skip === "number" || diff --git a/tsconfig.json b/tsconfig.json index 49cf3e690eb..6dee19ac7a9 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,5 +1,4 @@ { - "version": "2.1.1", "compilerOptions": { "lib": ["es5", "es6"], "outDir": "build/compiled", @@ -22,6 +21,11 @@ "noUnusedLocals": true, "downlevelIteration": true }, + "include": [ + "sample", + "src", + "test" + ], "exclude": [ "tmp", "temp", From 51608aebccd31570fc33ba0cd90c3147cdfc70b8 Mon Sep 17 00:00:00 2001 From: Umed Khudoiberdiev Date: Wed, 30 Sep 2020 19:00:38 +0500 Subject: [PATCH 094/212] fix: FindManyOptions order in parameter typing is important --- src/entity-manager/EntityManager.ts | 34 ++++++++++++++--------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/entity-manager/EntityManager.ts b/src/entity-manager/EntityManager.ts index 5677a371269..f29cd1655e7 100644 --- a/src/entity-manager/EntityManager.ts +++ b/src/entity-manager/EntityManager.ts @@ -622,22 +622,22 @@ export class EntityManager { } /** - * Counts entities that match given conditions. + * Counts entities that match given options. * Useful for pagination. */ - count(entityClass: EntityTarget, conditions?: FindConditions): Promise; + count(entityClass: EntityTarget, options?: FindOneOptions): Promise; /** * Counts entities that match given options. * Useful for pagination. */ - count(entityClass: EntityTarget, options?: FindOneOptions): Promise; + count(entityClass: EntityTarget, options?: FindManyOptions): Promise; /** - * Counts entities that match given options. + * Counts entities that match given conditions. * Useful for pagination. */ - count(entityClass: EntityTarget, options?: FindManyOptions): Promise; + count(entityClass: EntityTarget, conditions?: FindConditions): Promise; /** * Counts entities that match given find options or conditions. @@ -650,14 +650,14 @@ export class EntityManager { } /** - * Finds entities that match given conditions. + * Finds entities that match given options. */ - find(entityClass: EntityTarget, conditions?: FindConditions): Promise; + find(entityClass: EntityTarget, options?: FindManyOptions): Promise; /** - * Finds entities that match given options. + * Finds entities that match given conditions. */ - find(entityClass: EntityTarget, options?: FindManyOptions): Promise; + find(entityClass: EntityTarget, conditions?: FindConditions): Promise; /** * Finds entities that match given find options or conditions. @@ -673,18 +673,18 @@ export class EntityManager { } /** - * Finds entities that match given conditions. + * Finds entities that match given find options. * Also counts all entities that match given conditions, * but ignores pagination settings (from and take options). */ - findAndCount(entityClass: EntityTarget, conditions?: FindConditions): Promise<[Entity[], number]>; + findAndCount(entityClass: EntityTarget, options?: FindManyOptions): Promise<[Entity[], number]>; /** - * Finds entities that match given find options. + * Finds entities that match given conditions. * Also counts all entities that match given conditions, * but ignores pagination settings (from and take options). */ - findAndCount(entityClass: EntityTarget, options?: FindManyOptions): Promise<[Entity[], number]>; + findAndCount(entityClass: EntityTarget, conditions?: FindConditions): Promise<[Entity[], number]>; /** * Finds entities that match given find options and conditions. @@ -703,15 +703,15 @@ export class EntityManager { /** * Finds entities with ids. - * Optionally conditions can be applied. + * Optionally find options can be applied. */ - findByIds(entityClass: EntityTarget, ids: any[], conditions?: FindConditions): Promise; + findByIds(entityClass: EntityTarget, ids: any[], options?: FindManyOptions): Promise; /** * Finds entities with ids. - * Optionally find options can be applied. + * Optionally conditions can be applied. */ - findByIds(entityClass: EntityTarget, ids: any[], options?: FindManyOptions): Promise; + findByIds(entityClass: EntityTarget, ids: any[], conditions?: FindConditions): Promise; /** * Finds entities with ids. From 4eb5f107cca8c9e031ffe97e6e1145f753a24cac Mon Sep 17 00:00:00 2001 From: Umed Khudoiberdiev Date: Wed, 30 Sep 2020 19:37:23 +0500 Subject: [PATCH 095/212] version bump --- CHANGELOG.md | 7 +++++++ package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b43ef66fd45..e2034de721d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## [0.2.28](https://github.com/typeorm/typeorm/compare/0.2.27...0.2.28) (2020-09-30) + +### Bug Fixes + +* FindManyOptions order in parameter typing is important ([51608ae](https://github.com/typeorm/typeorm/commit/51608aebccd31570fc33ba0cd90c3147cdfc70b8)) +* lock Typescript to 3.6.0 ([#6810](https://github.com/typeorm/typeorm/issues/6810)) ([7f7e4d5](https://github.com/typeorm/typeorm/commit/7f7e4d53119506bdbb86999606707cd740859fe7)), closes [#6809](https://github.com/typeorm/typeorm/issues/6809) [#6805](https://github.com/typeorm/typeorm/issues/6805) + ## [0.2.27](https://github.com/typeorm/typeorm/compare/0.2.26...0.2.27) (2020-09-29) ### Bug Fixes diff --git a/package.json b/package.json index 90efb181c57..b5e878a28bc 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "typeorm", "private": true, - "version": "0.2.27", + "version": "0.2.28", "description": "Data-Mapper ORM for TypeScript, ES7, ES6, ES5. Supports MySQL, PostgreSQL, MariaDB, SQLite, MS SQL Server, Oracle, MongoDB databases.", "license": "MIT", "readmeFilename": "README.md", From cf8a2a4470ee751ecaaabadf2e573002f307c83e Mon Sep 17 00:00:00 2001 From: Gaurav Sharma Date: Thu, 1 Oct 2020 13:17:59 +0530 Subject: [PATCH 096/212] docs: remove stable release date temporarily (#6818) --- docs/roadmap.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/roadmap.md b/docs/roadmap.md index e6a7a28c62c..997c7ac12f9 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -4,7 +4,7 @@ See what amazing new features we are expecting to land in the next TypeORM versi ## Note on 1.0.0 release -We are planning to release a final stable `1.0.0` version somewhere in Autumn 2018. +We are planning to release a final stable `1.0.0` version in near future. However, TypeORM is already actively used in a number of big production systems. The main API is already very stable. TypeORM follows a semantic versioning and until `1.0.0`, breaking changes may appear in `0.x.x` versions. From 1a6383cecd74ee90388db313a74432f7ba12cfdf Mon Sep 17 00:00:00 2001 From: James Ward Date: Thu, 1 Oct 2020 08:12:19 -0400 Subject: [PATCH 097/212] fix: use `require` in `ReactNativeDriver` (#6814) Because react native uses the browser context we can't use `PlatformTools.load` so this reverts the behavior for this file to use a standard `require` call Fixes #6811 --- src/driver/react-native/ReactNativeDriver.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/driver/react-native/ReactNativeDriver.ts b/src/driver/react-native/ReactNativeDriver.ts index 0763c04d7dc..232fa676426 100644 --- a/src/driver/react-native/ReactNativeDriver.ts +++ b/src/driver/react-native/ReactNativeDriver.ts @@ -5,7 +5,6 @@ import {QueryRunner} from "../../query-runner/QueryRunner"; import {Connection} from "../../connection/Connection"; import {DriverOptionNotSetError} from "../../error/DriverOptionNotSetError"; import {DriverPackageNotInstalledError} from "../../error/DriverPackageNotInstalledError"; -import {PlatformTools} from "../../platform/PlatformTools"; import {ReplicationMode} from "../types/ReplicationMode"; export class ReactNativeDriver extends AbstractSqliteDriver { @@ -91,7 +90,7 @@ export class ReactNativeDriver extends AbstractSqliteDriver { */ protected loadDependencies(): void { try { - this.sqlite = PlatformTools.load("react-native-sqlite-storage"); + this.sqlite = require("react-native-sqlite-storage"); } catch (e) { throw new DriverPackageNotInstalledError("React-Native", "react-native-sqlite-storage"); From f3de0f6fe7bff1b973c0b4613295eb5fcf55b552 Mon Sep 17 00:00:00 2001 From: Dan Manastireanu <498419+danmana@users.noreply.github.com> Date: Thu, 1 Oct 2020 19:27:10 +0300 Subject: [PATCH 098/212] test: Fix typo in github issue 6442 test name (#6554) the test for #6442 was accidentally named `6642` --- test/github-issues/{6642 => 6442}/entity/v1/entities.ts | 0 test/github-issues/{6642 => 6442}/entity/v2/entities.ts | 0 test/github-issues/{6642/issue-6642.ts => 6442/issue-6442.ts} | 2 +- 3 files changed, 1 insertion(+), 1 deletion(-) rename test/github-issues/{6642 => 6442}/entity/v1/entities.ts (100%) rename test/github-issues/{6642 => 6442}/entity/v2/entities.ts (100%) rename test/github-issues/{6642/issue-6642.ts => 6442/issue-6442.ts} (97%) diff --git a/test/github-issues/6642/entity/v1/entities.ts b/test/github-issues/6442/entity/v1/entities.ts similarity index 100% rename from test/github-issues/6642/entity/v1/entities.ts rename to test/github-issues/6442/entity/v1/entities.ts diff --git a/test/github-issues/6642/entity/v2/entities.ts b/test/github-issues/6442/entity/v2/entities.ts similarity index 100% rename from test/github-issues/6642/entity/v2/entities.ts rename to test/github-issues/6442/entity/v2/entities.ts diff --git a/test/github-issues/6642/issue-6642.ts b/test/github-issues/6442/issue-6442.ts similarity index 97% rename from test/github-issues/6642/issue-6642.ts rename to test/github-issues/6442/issue-6442.ts index b8ba4f7d058..9d775f65ff6 100644 --- a/test/github-issues/6642/issue-6642.ts +++ b/test/github-issues/6442/issue-6442.ts @@ -10,7 +10,7 @@ import { fail } from "assert"; import { Query } from "../../../src/driver/Query"; import { MysqlConnectionOptions } from "../../../src/driver/mysql/MysqlConnectionOptions"; -describe("github issues > #6642 JoinTable does not respect inverseJoinColumns referenced column width", () => { +describe("github issues > #6442 JoinTable does not respect inverseJoinColumns referenced column width", () => { let connections: Connection[]; before(async () => { From d9a76e91bed06037ff28ec132893f40c09004438 Mon Sep 17 00:00:00 2001 From: Tomas Reimers Date: Thu, 1 Oct 2020 12:29:54 -0400 Subject: [PATCH 099/212] feat: add absolute path support to other CLI commands (#6807) --- src/commands/EntityCreateCommand.ts | 4 ++-- src/commands/SubscriberCreateCommand.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/commands/EntityCreateCommand.ts b/src/commands/EntityCreateCommand.ts index 314fa203d1d..221269617c3 100644 --- a/src/commands/EntityCreateCommand.ts +++ b/src/commands/EntityCreateCommand.ts @@ -37,7 +37,7 @@ export class EntityCreateCommand implements yargs.CommandModule { try { const fileContent = EntityCreateCommand.getTemplate(args.name as any); const filename = args.name + ".ts"; - let directory = args.dir; + let directory = args.dir as string; // if directory is not set then try to open tsconfig and find default path there if (!directory) { @@ -51,7 +51,7 @@ export class EntityCreateCommand implements yargs.CommandModule { } catch (err) { } } - const path = process.cwd() + "/" + (directory ? (directory + "/") : "") + filename; + const path = (directory.startsWith("/") ? "" : process.cwd() + "/") + (directory ? (directory + "/") : "") + filename; const fileExists = await CommandUtils.fileExists(path); if (fileExists) { throw `File ${chalk.blue(path)} already exists`; diff --git a/src/commands/SubscriberCreateCommand.ts b/src/commands/SubscriberCreateCommand.ts index 65d908843d5..65c5cafb978 100644 --- a/src/commands/SubscriberCreateCommand.ts +++ b/src/commands/SubscriberCreateCommand.ts @@ -38,7 +38,7 @@ export class SubscriberCreateCommand implements yargs.CommandModule { try { const fileContent = SubscriberCreateCommand.getTemplate(args.name as any); const filename = args.name + ".ts"; - let directory = args.dir; + let directory = args.dir as string; // if directory is not set then try to open tsconfig and find default path there if (!directory) { @@ -52,7 +52,7 @@ export class SubscriberCreateCommand implements yargs.CommandModule { } catch (err) { } } - const path = process.cwd() + "/" + (directory ? (directory + "/") : "") + filename; + const path = (directory.startsWith("/") ? "" : process.cwd() + "/") + (directory ? (directory + "/") : "") + filename; await CommandUtils.createFile(path, fileContent); console.log(chalk.green(`Subscriber ${chalk.blue(path)} has been created successfully.`)); From 0221a933d19125cc0703a7fdd2a243b494ac5e72 Mon Sep 17 00:00:00 2001 From: James Ward Date: Thu, 1 Oct 2020 15:25:56 -0400 Subject: [PATCH 100/212] fix: fixes the typescript errors in EntityCreateCommand & SubscriberCreateCommand (#6824) somehow #6807 passed as a PR but failed when merged in - this fixes the issues that cropped up after it was merged in --- src/commands/EntityCreateCommand.ts | 2 +- src/commands/SubscriberCreateCommand.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/commands/EntityCreateCommand.ts b/src/commands/EntityCreateCommand.ts index 221269617c3..86833f69ce3 100644 --- a/src/commands/EntityCreateCommand.ts +++ b/src/commands/EntityCreateCommand.ts @@ -47,7 +47,7 @@ export class EntityCreateCommand implements yargs.CommandModule { configName: args.config as any }); const connectionOptions = await connectionOptionsReader.get(args.connection as any); - directory = connectionOptions.cli ? connectionOptions.cli.entitiesDir : undefined; + directory = connectionOptions.cli ? (connectionOptions.cli.entitiesDir || "") : ""; } catch (err) { } } diff --git a/src/commands/SubscriberCreateCommand.ts b/src/commands/SubscriberCreateCommand.ts index 65c5cafb978..6acbb741873 100644 --- a/src/commands/SubscriberCreateCommand.ts +++ b/src/commands/SubscriberCreateCommand.ts @@ -48,7 +48,7 @@ export class SubscriberCreateCommand implements yargs.CommandModule { configName: args.config as any }); const connectionOptions = await connectionOptionsReader.get(args.connection as any); - directory = connectionOptions.cli ? connectionOptions.cli.subscribersDir : undefined; + directory = connectionOptions.cli ? (connectionOptions.cli.entitiesDir || "") : ""; } catch (err) { } } From 5ef94509b89f11f8337e18046c3f9d9632d234df Mon Sep 17 00:00:00 2001 From: James Ward Date: Thu, 1 Oct 2020 15:42:24 -0400 Subject: [PATCH 101/212] fix: subscribers should use the subscribersDir accidentally pulled over the entitiesDir instead - this fixes the subscribers generation command writing to the correct directory --- src/commands/SubscriberCreateCommand.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/SubscriberCreateCommand.ts b/src/commands/SubscriberCreateCommand.ts index 6acbb741873..dd0bb8b517d 100644 --- a/src/commands/SubscriberCreateCommand.ts +++ b/src/commands/SubscriberCreateCommand.ts @@ -48,7 +48,7 @@ export class SubscriberCreateCommand implements yargs.CommandModule { configName: args.config as any }); const connectionOptions = await connectionOptionsReader.get(args.connection as any); - directory = connectionOptions.cli ? (connectionOptions.cli.entitiesDir || "") : ""; + directory = connectionOptions.cli ? (connectionOptions.cli.subscribersDir || "") : ""; } catch (err) { } } From c060f95db0e261b02c4b28b19541cabcb1ac4a75 Mon Sep 17 00:00:00 2001 From: Ronit Steinberg <64842746+ronits-cx@users.noreply.github.com> Date: Sun, 4 Oct 2020 10:12:16 +0300 Subject: [PATCH 102/212] fix: wrong FK loaded in multi-database environment (#6828) Fixes an edge case where the wrong foreign key would be loaded when multiple databases exist with foreign keys that have the same name. Fixes #6168 --- src/driver/mysql/MysqlQueryRunner.ts | 2 +- test/github-issues/6168/issue-6168.ts | 106 ++++++++++++++++++++++++++ 2 files changed, 107 insertions(+), 1 deletion(-) create mode 100644 test/github-issues/6168/issue-6168.ts diff --git a/src/driver/mysql/MysqlQueryRunner.ts b/src/driver/mysql/MysqlQueryRunner.ts index 9d294492199..2364f8e2062 100644 --- a/src/driver/mysql/MysqlQueryRunner.ts +++ b/src/driver/mysql/MysqlQueryRunner.ts @@ -1234,7 +1234,7 @@ export class MysqlQueryRunner extends BaseQueryRunner implements QueryRunner { name = database; database = this.driver.database || currentDatabase; } - return `(\`kcu\`.\`TABLE_SCHEMA\` = '${database}' AND \`kcu\`.\`TABLE_NAME\` = '${name}')`; + return `(\`kcu\`.\`TABLE_SCHEMA\` = '${database}' AND \`kcu\`.\`TABLE_NAME\` = '${name}' AND \`rc\`.\`CONSTRAINT_SCHEMA\` = '${database}')`; }).join(" OR "); const foreignKeysSql = `SELECT \`kcu\`.\`TABLE_SCHEMA\`, \`kcu\`.\`TABLE_NAME\`, \`kcu\`.\`CONSTRAINT_NAME\`, \`kcu\`.\`COLUMN_NAME\`, \`kcu\`.\`REFERENCED_TABLE_SCHEMA\`, ` + `\`kcu\`.\`REFERENCED_TABLE_NAME\`, \`kcu\`.\`REFERENCED_COLUMN_NAME\`, \`rc\`.\`DELETE_RULE\` \`ON_DELETE\`, \`rc\`.\`UPDATE_RULE\` \`ON_UPDATE\` ` + diff --git a/test/github-issues/6168/issue-6168.ts b/test/github-issues/6168/issue-6168.ts new file mode 100644 index 00000000000..acdb8a9e45e --- /dev/null +++ b/test/github-issues/6168/issue-6168.ts @@ -0,0 +1,106 @@ +import "reflect-metadata"; +import {Connection} from "../../../src/connection/Connection"; +import {closeTestingConnections, createTestingConnections, reloadTestingDatabases} from "../../utils/test-utils"; +import {Table} from "../../../src/schema-builder/table/Table"; +import { QueryRunner } from "../../../src"; +import { expect } from "chai"; + +const questionName = "question"; +const categoryName = "category"; + +const createTables = async (queryRunner: QueryRunner, dbName: string) => { + const questionTableName = `${dbName}.${questionName}`; + const categoryTableName = `${dbName}.${categoryName}`; + + await queryRunner.createTable(new Table({ + name: questionTableName, + columns: [ + { + name: "id", + type: "int", + isPrimary: true, + isGenerated: true, + generationStrategy: "increment" + }, + { + name: "name", + type: "varchar", + } + ], + }), true); + + await queryRunner.createTable(new Table({ + name: categoryTableName, + columns: [ + { + name: "id", + type: "int", + isPrimary: true, + isGenerated: true, + generationStrategy: "increment" + }, + { + name: "questionId", + type: "int", + } + ], + foreignKeys: [ + { + columnNames: ["questionId"], + referencedTableName: questionTableName, + referencedColumnNames: ["id"], + name: "FK_CATEGORY_QUESTION" + } + ] + }), true); +}; + +describe("github issues > #6168 fix multiple foreign keys with the same name in a mysql multi-tenanted DB", () => { + + let connections: Connection[]; + before(async () => { + connections = await createTestingConnections({ + entities: [__dirname + "/entity/*{.js,.ts}"], + enabledDrivers: ["mysql"], + schemaCreate: false, + dropSchema: false, + }); + + await reloadTestingDatabases(connections); + + for (const connection of connections) { + const queryRunner = connection.createQueryRunner(); + await createTables(queryRunner, String(connection.driver.database)); + await queryRunner.createDatabase("test2", true); + await createTables(queryRunner, "test2"); + await queryRunner.release(); + }; + }); + + after(async () => { + for (const connection of connections) { + const queryRunner = connection.createQueryRunner(); + await queryRunner.dropDatabase("test2"); + await queryRunner.release(); + }; + + await closeTestingConnections(connections); + }); + + it("should only have one foreign key column", () => Promise.all(connections.map(async connection => { + const queryRunner = connection.createQueryRunner(); + const tables = await queryRunner.getTables([questionName, categoryName]); + + const questionTable = tables.find(table => table.name === questionName) as Table; + const categoryTable = tables.find(table => table.name === categoryName) as Table; + + queryRunner.release(); + + expect(categoryTable.foreignKeys.length).to.eq(1); + expect(categoryTable.foreignKeys[0].name).to.eq("FK_CATEGORY_QUESTION"); + expect(categoryTable.foreignKeys[0].columnNames.length).to.eq(1); // before the fix this was 2, one for each schema + expect(categoryTable.foreignKeys[0].columnNames[0]).to.eq("questionId"); + + expect(questionTable.foreignKeys.length).to.eq(0); + }))); +}); From 161432a149eb380cf12911c801997102753efd41 Mon Sep 17 00:00:00 2001 From: James Ward Date: Mon, 5 Oct 2020 02:47:14 -0400 Subject: [PATCH 103/212] chore: bump sql.js from 1.3.0 to 1.3.2 bumps sql.js to 1.3.2 because 1.3.0 has a number of issues in the compiled versions of the package --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index b24e1743a00..ab057ab553e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "typeorm", - "version": "0.2.27", + "version": "0.2.28", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -10738,9 +10738,9 @@ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" }, "sql.js": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/sql.js/-/sql.js-1.3.0.tgz", - "integrity": "sha512-bxrJ/9rqJ2SA6hpHnSodRjKBugZHewRvNTITTt74W1VZWmzODjdS68yQW0/J9oC0NWKylHEtV1ptkoTyOYO4Tw==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/sql.js/-/sql.js-1.3.2.tgz", + "integrity": "sha512-vRdzoj4TCrCX8yI2mv0OVVEuOOz2IlhEfw1x1Q65BhpmLep46iu+M04zxln4u2mHRk+wj7avFq2L3/1gQS1orQ==", "dev": true }, "sqlite3": { diff --git a/package.json b/package.json index b5e878a28bc..50eca7c0244 100644 --- a/package.json +++ b/package.json @@ -107,7 +107,7 @@ "sinon": "^9.0.0", "sinon-chai": "^3.5.0", "source-map-support": "^0.5.16", - "sql.js": "^1.3.0", + "sql.js": "^1.3.2", "sqlite3": "^5.0.0", "ts-node": "^9.0.0", "typeorm-aurora-data-api-driver": "^1.4.0", From 7ebca2b9b1fd21e546b3a345a069637d6aab4b3e Mon Sep 17 00:00:00 2001 From: James Ward Date: Mon, 5 Oct 2020 12:12:25 -0400 Subject: [PATCH 104/212] feat: support ESM in ormconfig js & ts (#6853) fixes #5003 --- docs/using-ormconfig.md | 13 +++++++++++++ src/connection/ConnectionOptionsReader.ts | 11 +++++++---- .../configs/test-path-config-esm.ts | 5 +++++ .../connection-options-reader.ts | 6 ++++++ 4 files changed, 31 insertions(+), 4 deletions(-) create mode 100644 test/functional/connection-options-reader/configs/test-path-config-esm.ts diff --git a/docs/using-ormconfig.md b/docs/using-ormconfig.md index 1f95b393545..5fc5dec05f3 100644 --- a/docs/using-ormconfig.md +++ b/docs/using-ormconfig.md @@ -80,6 +80,19 @@ module.exports = { } ``` +Alternatively, you may use the ECMAScript module format if your environment supports it: + +```javascript +export default { + "type": "mysql", + "host": "localhost", + "port": 3306, + "username": "test", + "password": "test", + "database": "test" +} +``` + You can specify any other options from [ConnectionOptions](./connection-options.md). If you want to create multiple connections then simply create multiple connections in a single array and return it. diff --git a/src/connection/ConnectionOptionsReader.ts b/src/connection/ConnectionOptionsReader.ts index af66a4d5663..5f6b2668231 100644 --- a/src/connection/ConnectionOptionsReader.ts +++ b/src/connection/ConnectionOptionsReader.ts @@ -106,11 +106,14 @@ export class ConnectionOptionsReader { if (PlatformTools.getEnvVariable("TYPEORM_CONNECTION") || PlatformTools.getEnvVariable("TYPEORM_URL")) { connectionOptions = await new ConnectionOptionsEnvReader().read(); - } else if (foundFileFormat === "js" || foundFileFormat === "cjs") { - connectionOptions = await require(configFile); + } else if (foundFileFormat === "js" || foundFileFormat === "cjs" || foundFileFormat === "ts") { + const configModule = await require(configFile); - } else if (foundFileFormat === "ts") { - connectionOptions = await require(configFile); + if (configModule && "__esModule" in configModule && "default" in configModule) { + connectionOptions = configModule.default; + } else { + connectionOptions = configModule; + } } else if (foundFileFormat === "json") { connectionOptions = require(configFile); diff --git a/test/functional/connection-options-reader/configs/test-path-config-esm.ts b/test/functional/connection-options-reader/configs/test-path-config-esm.ts new file mode 100644 index 00000000000..27495c20285 --- /dev/null +++ b/test/functional/connection-options-reader/configs/test-path-config-esm.ts @@ -0,0 +1,5 @@ +export default [{ + type: "sqlite", + name: "file", + database: "test-js" +}]; diff --git a/test/functional/connection-options-reader/connection-options-reader.ts b/test/functional/connection-options-reader/connection-options-reader.ts index fae1bf881d4..9ed51c222aa 100644 --- a/test/functional/connection-options-reader/connection-options-reader.ts +++ b/test/functional/connection-options-reader/connection-options-reader.ts @@ -37,6 +37,12 @@ describe("ConnectionOptionsReader", () => { expect(fileOptions.database).to.have.string("/test-js-async"); }); + it("properly loads config with specified file path from esm in js", async () => { + const connectionOptionsReader = new ConnectionOptionsReader({ root: __dirname, configName: "configs/test-path-config-esm.js" }); + const fileOptions: ConnectionOptions = await connectionOptionsReader.get("file"); + expect(fileOptions.database).to.have.string("/test-js"); + }); + // TODO This test requires the configs/.env file be moved to the matching directory in build/compiled it.skip("properly loads config from .env file", async () => { const connectionOptionsReader = new ConnectionOptionsReader({ root: __dirname, configName: "configs/.env" }); From d2b914da6a425d47916c72ac50bfa69bea4847fb Mon Sep 17 00:00:00 2001 From: James Ward Date: Mon, 5 Oct 2020 13:26:27 -0400 Subject: [PATCH 105/212] fix: check mysql constraint schema on join (#6851) in #6268 we pulled in a change that fixed the wrong FK getting loaded in a multi-database / multi-schema environment but in #6169 the approach was more desirable as it creates a simpler query that should be easier to change in the future as such, this pulls over that change from #6169 --- src/driver/mysql/MysqlQueryRunner.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/driver/mysql/MysqlQueryRunner.ts b/src/driver/mysql/MysqlQueryRunner.ts index 2364f8e2062..dc6005d37b2 100644 --- a/src/driver/mysql/MysqlQueryRunner.ts +++ b/src/driver/mysql/MysqlQueryRunner.ts @@ -1234,12 +1234,12 @@ export class MysqlQueryRunner extends BaseQueryRunner implements QueryRunner { name = database; database = this.driver.database || currentDatabase; } - return `(\`kcu\`.\`TABLE_SCHEMA\` = '${database}' AND \`kcu\`.\`TABLE_NAME\` = '${name}' AND \`rc\`.\`CONSTRAINT_SCHEMA\` = '${database}')`; + return `(\`kcu\`.\`TABLE_SCHEMA\` = '${database}' AND \`kcu\`.\`TABLE_NAME\` = '${name}')`; }).join(" OR "); const foreignKeysSql = `SELECT \`kcu\`.\`TABLE_SCHEMA\`, \`kcu\`.\`TABLE_NAME\`, \`kcu\`.\`CONSTRAINT_NAME\`, \`kcu\`.\`COLUMN_NAME\`, \`kcu\`.\`REFERENCED_TABLE_SCHEMA\`, ` + `\`kcu\`.\`REFERENCED_TABLE_NAME\`, \`kcu\`.\`REFERENCED_COLUMN_NAME\`, \`rc\`.\`DELETE_RULE\` \`ON_DELETE\`, \`rc\`.\`UPDATE_RULE\` \`ON_UPDATE\` ` + `FROM \`INFORMATION_SCHEMA\`.\`KEY_COLUMN_USAGE\` \`kcu\` ` + - `INNER JOIN \`INFORMATION_SCHEMA\`.\`REFERENTIAL_CONSTRAINTS\` \`rc\` ON \`rc\`.\`constraint_name\` = \`kcu\`.\`constraint_name\` ` + + `INNER JOIN \`INFORMATION_SCHEMA\`.\`REFERENTIAL_CONSTRAINTS\` \`rc\` ON \`rc\`.\`constraint_name\` = \`kcu\`.\`constraint_name\` AND \`rc\`.\`CONSTRAINT_SCHEMA\` = \`kcu\`.\`CONSTRAINT_SCHEMA\` AND \`rc\`.\`TABLE_NAME\` = \`kcu\`.\`TABLE_NAME\` ` + `WHERE ` + foreignKeysCondition; const [dbTables, dbColumns, dbPrimaryKeys, dbCollations, dbIndices, dbForeignKeys]: ObjectLiteral[][] = await Promise.all([ this.query(tablesSql), From 7147a0dbe7f2622a21c51edefa3b921f42e04b49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20M=C3=A4ki?= Date: Mon, 5 Oct 2020 20:31:20 +0300 Subject: [PATCH 106/212] fix: return null for nullable RelationId() column (#6848) Fix issue where attempting to cast bigints to strings also did it for null values. Fix issue where transformRelationIds() filtered out null values when it should only be done for undefined. Closes: #6815 --- src/metadata/ColumnMetadata.ts | 4 +- .../RawSqlResultsToEntityTransformer.ts | 2 +- test/github-issues/6815/entity/ChildEntity.ts | 7 +++ .../github-issues/6815/entity/ParentEntity.ts | 15 +++++ test/github-issues/6815/issue-6815.ts | 56 +++++++++++++++++++ 5 files changed, 81 insertions(+), 3 deletions(-) create mode 100644 test/github-issues/6815/entity/ChildEntity.ts create mode 100644 test/github-issues/6815/entity/ParentEntity.ts create mode 100644 test/github-issues/6815/issue-6815.ts diff --git a/src/metadata/ColumnMetadata.ts b/src/metadata/ColumnMetadata.ts index 97f2ca23292..94d090bba50 100644 --- a/src/metadata/ColumnMetadata.ts +++ b/src/metadata/ColumnMetadata.ts @@ -477,7 +477,7 @@ export class ColumnMetadata { } // this is bugfix for #720 when increment number is bigint we need to make sure its a string - if ((this.generationStrategy === "increment" || this.generationStrategy === "rowid") && this.type === "bigint") + if ((this.generationStrategy === "increment" || this.generationStrategy === "rowid") && this.type === "bigint" && value !== null) value = String(value); map[useDatabaseName ? this.databaseName : this.propertyName] = value; @@ -488,7 +488,7 @@ export class ColumnMetadata { } else { // no embeds - no problems. Simply return column property name and its value of the entity // this is bugfix for #720 when increment number is bigint we need to make sure its a string - if ((this.generationStrategy === "increment" || this.generationStrategy === "rowid") && this.type === "bigint") + if ((this.generationStrategy === "increment" || this.generationStrategy === "rowid") && this.type === "bigint" && value !== null) value = String(value); return { [useDatabaseName ? this.databaseName : this.propertyName]: value }; diff --git a/src/query-builder/transformer/RawSqlResultsToEntityTransformer.ts b/src/query-builder/transformer/RawSqlResultsToEntityTransformer.ts index cc75cdfca5e..34adec20bbb 100644 --- a/src/query-builder/transformer/RawSqlResultsToEntityTransformer.ts +++ b/src/query-builder/transformer/RawSqlResultsToEntityTransformer.ts @@ -253,7 +253,7 @@ export class RawSqlResultsToEntityTransformer { } } return idMap; - }).filter(result => result); + }).filter(result => result !== undefined); const properties = rawRelationIdResult.relationIdAttribute.mapToPropertyPropertyPath.split("."); const mapToProperty = (properties: string[], map: ObjectLiteral, value: any): any => { diff --git a/test/github-issues/6815/entity/ChildEntity.ts b/test/github-issues/6815/entity/ChildEntity.ts new file mode 100644 index 00000000000..3f5dc547d94 --- /dev/null +++ b/test/github-issues/6815/entity/ChildEntity.ts @@ -0,0 +1,7 @@ +import {Entity, PrimaryGeneratedColumn} from "../../../../src"; + +@Entity() +export class ChildEntity { + @PrimaryGeneratedColumn({type: "bigint"}) + id: string; +} diff --git a/test/github-issues/6815/entity/ParentEntity.ts b/test/github-issues/6815/entity/ParentEntity.ts new file mode 100644 index 00000000000..e3ec5530393 --- /dev/null +++ b/test/github-issues/6815/entity/ParentEntity.ts @@ -0,0 +1,15 @@ +import {Entity, JoinColumn, OneToOne, PrimaryGeneratedColumn, RelationId} from "../../../../src"; +import {ChildEntity} from "./ChildEntity"; + +@Entity() +export class ParentEntity { + @PrimaryGeneratedColumn({type: "bigint"}) + id: string; + + @OneToOne(() => ChildEntity, {nullable: true}) + @JoinColumn() + child: ChildEntity|null; + + @RelationId((parent: ParentEntity) => parent.child) + childId: string|null; +} diff --git a/test/github-issues/6815/issue-6815.ts b/test/github-issues/6815/issue-6815.ts new file mode 100644 index 00000000000..27e6916ac9e --- /dev/null +++ b/test/github-issues/6815/issue-6815.ts @@ -0,0 +1,56 @@ +import {expect} from "chai"; +import {Connection} from "../../../src/connection/Connection"; +import {EntityManager} from "../../../src/entity-manager/EntityManager"; +import { + createTestingConnections, + closeTestingConnections, + reloadTestingDatabases, +} from "../../utils/test-utils"; +import {ChildEntity} from "./entity/ChildEntity"; +import {ParentEntity} from "./entity/ParentEntity"; + +describe("github issues > #6815 RelationId() on nullable relation returns 'null' string", () => { + let connections: Connection[]; + + before(async () => connections = await createTestingConnections({ + entities: [__dirname + "/entity/*{.js,.ts}"], + schemaCreate: true, + dropSchema: true, + enabledDrivers: ["cockroachdb", "mariadb", "mssql", "mysql", "postgres"] + })); + + beforeEach(() => reloadTestingDatabases(connections)); + after(() => closeTestingConnections(connections)); + + it("should return null as childId if child doesn't exist", () => Promise.all( + connections.map(async connection => { + const em = new EntityManager(connection); + const parent = em.create(ParentEntity); + await em.save(parent); + + const loaded = await em.findOneOrFail(ParentEntity, parent.id); + expect(loaded.childId).to.be.null; + }) + )); + + it("should return string as childId if child exists", () => Promise.all( + connections.map(async connection => { + const em = new EntityManager(connection); + const child = em.create(ChildEntity); + await em.save(child); + + const parent = em.create(ParentEntity); + parent.child = child; + await em.save(parent); + + const loaded = await em.findOneOrFail(ParentEntity, parent.id); + + if (connection.name === "cockroachdb") { + // CockroachDB returns id as a number. + expect(loaded.childId).to.equal(child.id.toString()); + } else { + expect(loaded.childId).to.equal(child.id); + } + }) + )); +}); From 91b85bfe6e73ff93db2684a13935b9bd6a9abcfd Mon Sep 17 00:00:00 2001 From: Temnov Aleksey Date: Tue, 6 Oct 2020 11:08:54 +0300 Subject: [PATCH 107/212] feat: add ability for escaping for Raw() find operator (#6850) * feat: add ability for escaping for Raw() find operator * fix: update Raw() find operator * fix: fix tests for Raw() find operator * feat: add ability for escaping with object literal parameters for Raw() find operator * docs: correct the example comment of Raw() find operator * fix: delete redundant functional --- src/find-options/FindOperator.ts | 45 +++++++++++- src/find-options/operator/Raw.ts | 29 +++++++- src/query-builder/QueryBuilder.ts | 20 +++-- .../repository-find-operators.ts | 73 +++++++++++++++++++ 4 files changed, 155 insertions(+), 12 deletions(-) diff --git a/src/find-options/FindOperator.ts b/src/find-options/FindOperator.ts index fd0dae0b962..6189e31fe17 100644 --- a/src/find-options/FindOperator.ts +++ b/src/find-options/FindOperator.ts @@ -1,5 +1,8 @@ +import {ObjectLiteral} from "../common/ObjectLiteral"; import {FindOperatorType} from "./FindOperatorType"; +type SqlGeneratorType = (aliasPath: string) => string; + /** * Find Operator used in Find Conditions. */ @@ -19,6 +22,11 @@ export class FindOperator { */ private _value: T|FindOperator; + /** + * ObjectLiteral parameters. + */ + private _objectLiteralParameters: ObjectLiteral|undefined; + /** * Indicates if parameter is used or not for this operator. */ @@ -29,15 +37,29 @@ export class FindOperator { */ private _multipleParameters: boolean; + /** + * SQL generator + */ + private _getSql: SqlGeneratorType|undefined; + // ------------------------------------------------------------------------- // Constructor // ------------------------------------------------------------------------- - constructor(type: FindOperatorType, value: T|FindOperator, useParameter: boolean = true, multipleParameters: boolean = false) { + constructor( + type: FindOperatorType, + value: T|FindOperator, + useParameter: boolean = true, + multipleParameters: boolean = false, + getSql?: SqlGeneratorType, + objectLiteralParameters?: ObjectLiteral, + ) { this._type = type; this._value = value; this._useParameter = useParameter; this._multipleParameters = multipleParameters; + this._getSql = getSql; + this._objectLiteralParameters = objectLiteralParameters; } // ------------------------------------------------------------------------- @@ -83,6 +105,17 @@ export class FindOperator { return this._value; } + /** + * Gets ObjectLiteral parameters. + */ + get objectLiteralParameters(): ObjectLiteral|undefined { + if (this._value instanceof FindOperator) + return this._value.objectLiteralParameters; + + return this._objectLiteralParameters; + } + + /** * Gets the child FindOperator if it exists */ @@ -92,4 +125,14 @@ export class FindOperator { return undefined; } + + /** + * Gets the SQL generator + */ + get getSql(): SqlGeneratorType|undefined { + if (this._value instanceof FindOperator) + return this._value.getSql; + + return this._getSql; + } } diff --git a/src/find-options/operator/Raw.ts b/src/find-options/operator/Raw.ts index aeba177478d..dfe6859e13b 100644 --- a/src/find-options/operator/Raw.ts +++ b/src/find-options/operator/Raw.ts @@ -1,9 +1,32 @@ import {FindOperator} from "../FindOperator"; +import {ObjectLiteral} from "../../common/ObjectLiteral"; /** * Find Options Operator. - * Example: { someField: Raw([...]) } + * Example: { someField: Raw("12") } */ -export function Raw(value: string|((columnAlias: string) => string)): FindOperator { - return new FindOperator("raw", value as any, false); +export function Raw(value: string): FindOperator; + +/** + * Find Options Operator. + * Example: { someField: Raw((columnAlias) => `${columnAlias} = 5`) } + */ +export function Raw(sqlGenerator: ((columnAlias: string) => string)): FindOperator; + +/** + * Find Options Operator. + * For escaping parameters use next syntax: + * Example: { someField: Raw((columnAlias) => `${columnAlias} = :value`, { value: 5 }) } + */ +export function Raw(sqlGenerator: ((columnAlias: string) => string), parameters: ObjectLiteral): FindOperator; + +export function Raw( + valueOrSqlGenerator: string | ((columnAlias: string) => string), + sqlGeneratorParameters?: ObjectLiteral, +): FindOperator { + if (typeof valueOrSqlGenerator !== 'function') { + return new FindOperator("raw", valueOrSqlGenerator, false); + } + + return new FindOperator("raw", [], true, true, valueOrSqlGenerator, sqlGeneratorParameters); } diff --git a/src/query-builder/QueryBuilder.ts b/src/query-builder/QueryBuilder.ts index afb383ddd0a..4776a441490 100644 --- a/src/query-builder/QueryBuilder.ts +++ b/src/query-builder/QueryBuilder.ts @@ -810,12 +810,16 @@ export abstract class QueryBuilder { } else if (parameterValue instanceof FindOperator) { let parameters: any[] = []; if (parameterValue.useParameter) { - const realParameterValues: any[] = parameterValue.multipleParameters ? parameterValue.value : [parameterValue.value]; - realParameterValues.forEach((realParameterValue, realParameterValueIndex) => { - this.expressionMap.nativeParameters[parameterName + (parameterBaseCount + realParameterValueIndex)] = realParameterValue; - parameterIndex++; - parameters.push(this.connection.driver.createParameter(parameterName + (parameterBaseCount + realParameterValueIndex), parameterIndex - 1)); - }); + if (parameterValue.objectLiteralParameters) { + this.setParameters(parameterValue.objectLiteralParameters); + } else { + const realParameterValues: any[] = parameterValue.multipleParameters ? parameterValue.value : [parameterValue.value]; + realParameterValues.forEach((realParameterValue, realParameterValueIndex) => { + this.expressionMap.nativeParameters[parameterName + (parameterBaseCount + realParameterValueIndex)] = realParameterValue; + parameterIndex++; + parameters.push(this.connection.driver.createParameter(parameterName + (parameterBaseCount + realParameterValueIndex), parameterIndex - 1)); + }); + } } return this.computeFindOperatorExpression(parameterValue, aliasPath, parameters); @@ -892,8 +896,8 @@ export abstract class QueryBuilder { case "isNull": return `${aliasPath} IS NULL`; case "raw": - if (typeof operator.value === "function") { - return operator.value(aliasPath); + if (operator.getSql) { + return operator.getSql(aliasPath); } else { return `${aliasPath} = ${operator.value}`; } diff --git a/test/functional/repository/find-options-operators/repository-find-operators.ts b/test/functional/repository/find-options-operators/repository-find-operators.ts index 722a8279e4a..d0b88ebddf4 100644 --- a/test/functional/repository/find-options-operators/repository-find-operators.ts +++ b/test/functional/repository/find-options-operators/repository-find-operators.ts @@ -531,7 +531,80 @@ describe("repository > find options > operators", () => { likes: Raw(columnAlias => "1 + " + columnAlias + " = 4") }); loadedPosts.should.be.eql([{ id: 2, likes: 3, title: "About #2" }]); + }))); + + it("raw (function with object literal parameters)", () => Promise.all(connections.map(async connection => { + const createPost = (index: number): Post => { + const post = new Post(); + post.title = `About #${index}`; + post.likes = index; + + return post; + } + + // insert some fake data + await connection.manager.save([ + createPost(1), + createPost(2), + createPost(3), + createPost(4), + createPost(5), + createPost(6), + ]); + + // check operator + const result1 = await connection.getRepository(Post).find({ + likes: Raw((columnAlias) => { + return `(${columnAlias} = :value1) OR (${columnAlias} = :value2)` + }, { value1: 2, value2: 3 }), + }); + result1.should.be.eql([ + { id: 2, likes: 2, title: "About #2" }, + { id: 3, likes: 3, title: "About #3" }, + ]); + + // check operator + const result2 = await connection.getRepository(Post).find({ + likes: Raw((columnAlias) => { + return `(${columnAlias} IN (1, 4, 5, 6)) AND (${columnAlias} < :maxValue)` + }, { maxValue: 6 }), + }); + result2.should.be.eql([ + { id: 1, likes: 1, title: "About #1" }, + { id: 4, likes: 4, title: "About #4" }, + { id: 5, likes: 5, title: "About #5" }, + ]); + // check operator + const result3 = await connection.getRepository(Post).find({ + title: Raw((columnAlias) => { + return `${columnAlias} IN (:a, :b, :c)`; + }, { a: "About #1", b: "About #3", c: "About #5" }), + likes: Raw((columnAlias) => `${columnAlias} IN (:d, :e)`, { d: 5, e: 1 }), + }); + result3.should.be.eql([ + { id: 1, likes: 1, title: "About #1" }, + { id: 5, likes: 5, title: "About #5" }, + ]); + + // check operator + const result4 = await connection.getRepository(Post).find({ + likes: Raw((columnAlias) => `${columnAlias} IN (2, 6)`, { }), + }); + result4.should.be.eql([ + { id: 2, likes: 2, title: "About #2" }, + { id: 6, likes: 6, title: "About #6" }, + ]); + + // check operator + const result5 = await connection.getRepository(Post).find({ + likes: Raw((columnAlias) => `${columnAlias} IN (2, :value, 6)`, { value: 3 }), + }); + result5.should.be.eql([ + { id: 2, likes: 2, title: "About #2" }, + { id: 3, likes: 3, title: "About #3" }, + { id: 6, likes: 6, title: "About #6" }, + ]); }))); it("should work with ActiveRecord model", async () => { From e9f9e1cae69d2e58dbf8f5c75abdac2e5e37407e Mon Sep 17 00:00:00 2001 From: Gaurav Sharma Date: Tue, 6 Oct 2020 13:53:23 +0530 Subject: [PATCH 108/212] docs: docker-compose generation option in typeorm init command (#6841) --- README.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 72f9b72e452..3cb75b20728 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ maintainable applications the most productive way. TypeORM is highly influenced by other ORMs, such as [Hibernate](http://hibernate.org/orm/), [Doctrine](http://www.doctrine-project.org/) and [Entity Framework](https://www.asp.net/entity-framework). - + ## Features * supports both [DataMapper](./docs/active-record-data-mapper.md#what-is-the-data-mapper-pattern) and [ActiveRecord](./docs/active-record-data-mapper.md#what-is-the-active-record-pattern) (your choice) @@ -215,7 +215,7 @@ await timber.remove(); npm i @sap/hana-client npm i hdb-pool ``` - + *SAP Hana support made possible by sponsorship of [Neptune Software](https://www.neptune-software.com/).* * for **MongoDB** (experimental) @@ -328,6 +328,9 @@ creating more entities. > You can generate an even more advanced project with express installed by running `typeorm init --name MyProject --database mysql --express` command. +> You can generate docker-compose file by running +`typeorm init --name MyProject --database postgres --docker` command. + ## Step-by-Step Guide What are you expecting from ORM? From 08ec0a8ed922225ff529790ad5ff19c0e463954e Mon Sep 17 00:00:00 2001 From: James Ward Date: Tue, 6 Oct 2020 04:25:15 -0400 Subject: [PATCH 109/212] fix: prevent create-type commands edge-case TypeErrors (#6836) in some cases - where the connection options couldn't be read - we would end up with the migration:create and similar commands failing with a TypeError this refactors the create commands a bit to defend against an undefined directory, preventing the TypeError fixes #6831 --- src/commands/EntityCreateCommand.ts | 7 +++++-- src/commands/MigrationCreateCommand.ts | 7 +++++-- src/commands/SubscriberCreateCommand.ts | 7 +++++-- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/commands/EntityCreateCommand.ts b/src/commands/EntityCreateCommand.ts index 86833f69ce3..13918d891c7 100644 --- a/src/commands/EntityCreateCommand.ts +++ b/src/commands/EntityCreateCommand.ts @@ -37,7 +37,7 @@ export class EntityCreateCommand implements yargs.CommandModule { try { const fileContent = EntityCreateCommand.getTemplate(args.name as any); const filename = args.name + ".ts"; - let directory = args.dir as string; + let directory = args.dir as string | undefined; // if directory is not set then try to open tsconfig and find default path there if (!directory) { @@ -51,7 +51,10 @@ export class EntityCreateCommand implements yargs.CommandModule { } catch (err) { } } - const path = (directory.startsWith("/") ? "" : process.cwd() + "/") + (directory ? (directory + "/") : "") + filename; + if (directory && !directory.startsWith("/")) { + directory = process.cwd() + "/" + directory; + } + const path = (directory ? (directory + "/") : "") + filename; const fileExists = await CommandUtils.fileExists(path); if (fileExists) { throw `File ${chalk.blue(path)} already exists`; diff --git a/src/commands/MigrationCreateCommand.ts b/src/commands/MigrationCreateCommand.ts index a39247e919c..e33d69c4597 100644 --- a/src/commands/MigrationCreateCommand.ts +++ b/src/commands/MigrationCreateCommand.ts @@ -45,7 +45,7 @@ export class MigrationCreateCommand implements yargs.CommandModule { const timestamp = new Date().getTime(); const fileContent = MigrationCreateCommand.getTemplate(args.name as any, timestamp); const filename = timestamp + "-" + args.name + ".ts"; - let directory = args.dir as string; + let directory = args.dir as string | undefined; // if directory is not set then try to open tsconfig and find default path there if (!directory) { @@ -59,7 +59,10 @@ export class MigrationCreateCommand implements yargs.CommandModule { } catch (err) { } } - const path = (directory.startsWith("/") ? "" : process.cwd() + "/") + (directory ? (directory + "/") : "") + filename; + if (directory && !directory.startsWith("/")) { + directory = process.cwd() + "/" + directory; + } + const path = (directory ? (directory + "/") : "") + filename; await CommandUtils.createFile(path, fileContent); console.log(`Migration ${chalk.blue(path)} has been generated successfully.`); diff --git a/src/commands/SubscriberCreateCommand.ts b/src/commands/SubscriberCreateCommand.ts index dd0bb8b517d..48e40642295 100644 --- a/src/commands/SubscriberCreateCommand.ts +++ b/src/commands/SubscriberCreateCommand.ts @@ -38,7 +38,7 @@ export class SubscriberCreateCommand implements yargs.CommandModule { try { const fileContent = SubscriberCreateCommand.getTemplate(args.name as any); const filename = args.name + ".ts"; - let directory = args.dir as string; + let directory = args.dir as string | undefined; // if directory is not set then try to open tsconfig and find default path there if (!directory) { @@ -52,7 +52,10 @@ export class SubscriberCreateCommand implements yargs.CommandModule { } catch (err) { } } - const path = (directory.startsWith("/") ? "" : process.cwd() + "/") + (directory ? (directory + "/") : "") + filename; + if (directory && !directory.startsWith("/")) { + directory = process.cwd() + "/" + directory; + } + const path = (directory ? (directory + "/") : "") + filename; await CommandUtils.createFile(path, fileContent); console.log(chalk.green(`Subscriber ${chalk.blue(path)} has been created successfully.`)); From f95e9d8f9a6c7a1117564b3e3f65b5294f8d5ff5 Mon Sep 17 00:00:00 2001 From: maddimax Date: Tue, 6 Oct 2020 10:32:28 +0200 Subject: [PATCH 110/212] fix: allow for complex jsonb primary key columns (#6834) * fix: allow for complex jsonb primary key columns When using PrimaryColumn with a 'jsonb' type column ( on a postgres database ) the RawSqlResultsToEntityTransformer would simply convert the key to '[object Object]' instead of a unique value based on the key value. It would then wrongly consider each entity as having the same key. To allow for complex keys the transformer now uses JSON.stringify() to convert the keys value if they are of type obejct to a unique string that can be compared to other entities. fixes #6833 * test: add tests for jsonb primarykey columns These tests verify that Entities with jsonb primary columns are correctly converted to Entites --- .../RawSqlResultsToEntityTransformer.ts | 4 + test/github-issues/6833/entity/test.ts | 12 +++ test/github-issues/6833/issue-6833.ts | 81 +++++++++++++++++++ 3 files changed, 97 insertions(+) create mode 100644 test/github-issues/6833/entity/test.ts create mode 100644 test/github-issues/6833/issue-6833.ts diff --git a/src/query-builder/transformer/RawSqlResultsToEntityTransformer.ts b/src/query-builder/transformer/RawSqlResultsToEntityTransformer.ts index 34adec20bbb..e79fd24d633 100644 --- a/src/query-builder/transformer/RawSqlResultsToEntityTransformer.ts +++ b/src/query-builder/transformer/RawSqlResultsToEntityTransformer.ts @@ -70,6 +70,10 @@ export class RawSqlResultsToEntityTransformer { return keyValue.toString("hex"); } + if (typeof keyValue === "object") { + return JSON.stringify(keyValue); + } + return keyValue; }).join("_"); // todo: check partial diff --git a/test/github-issues/6833/entity/test.ts b/test/github-issues/6833/entity/test.ts new file mode 100644 index 00000000000..e0cb47ad6be --- /dev/null +++ b/test/github-issues/6833/entity/test.ts @@ -0,0 +1,12 @@ +import { Entity, PrimaryColumn } from "../../../../src"; + +export class MyId { + first: number; + second: number; +} + +@Entity({ name: "jsonb_key_tests" }) +export class JSONBKeyTest { + @PrimaryColumn("jsonb") + id: MyId; +} diff --git a/test/github-issues/6833/issue-6833.ts b/test/github-issues/6833/issue-6833.ts new file mode 100644 index 00000000000..4e1ed1179ba --- /dev/null +++ b/test/github-issues/6833/issue-6833.ts @@ -0,0 +1,81 @@ +import "reflect-metadata"; +import { + createTestingConnections, + closeTestingConnections, + reloadTestingDatabases, +} from "../../utils/test-utils"; +import { Connection } from "../../../src/connection/Connection"; +import { expect } from "chai"; +import { JSONBKeyTest } from "./entity/test"; + +describe("github issues > #6833 Entities with JSON key columns are incorrectly grouped", () => { + let connections: Connection[]; + before(async () => connections = await createTestingConnections({ + entities: [JSONBKeyTest], + dropSchema: true, + schemaCreate: true, + enabledDrivers: ["postgres"] + })); + beforeEach(() => reloadTestingDatabases(connections)); + after(() => closeTestingConnections(connections)); + + it("jsonB keys are correctly resolved", () => Promise.all(connections.map(async connection => { + await connection.transaction(async manager => { + await manager.save(manager.create(JSONBKeyTest, { id: { first: 1, second: 2 } })); + await manager.save(manager.create(JSONBKeyTest, { id: { first: 1, second: 3 } })); + + const entities = await manager.createQueryBuilder(JSONBKeyTest, "json_test").select().getMany(); + expect(entities.length).to.equal(2); + }); + }))); + + it("jsonB keys can be found", () => Promise.all(connections.map(async connection => { + await connection.transaction(async manager => { + await manager.save(manager.create(JSONBKeyTest, { id: { first: 3, second: 3 } })); + await manager.save(manager.create(JSONBKeyTest, { id: { first: 4, second: 3 } })); + + const entities = await manager.find(JSONBKeyTest, { where: { id: { first: 3, second: 3 } } } ); + expect(entities.length).to.equal(1); + expect(entities[0].id).to.deep.equal({ first: 3, second: 3 }); + }); + }))); + + it("jsonB keys can be found with IN", () => Promise.all(connections.map(async connection => { + await connection.transaction(async manager => { + await manager.save(manager.create(JSONBKeyTest, { id: { first: 3, second: 3 } })); + await manager.save(manager.create(JSONBKeyTest, { id: { first: 4, second: 3 } })); + await manager.save(manager.create(JSONBKeyTest, { id: { first: 5, second: 3 } })); + await manager.save(manager.create(JSONBKeyTest, { id: { first: 6, second: 4 } })); + + const entities = await manager + .createQueryBuilder(JSONBKeyTest, "json_test") + .select() + .where("id IN (:...ids)", { ids: [{first: 5, second: 3}, {first: 6, second: 4}]}) + .getMany(); + expect(entities.length).to.equal(2); + expect(entities[0].id).to.deep.equal({ first: 5, second: 3 }); + expect(entities[1].id).to.deep.equal({ first: 6, second: 4 }); + }); + }))); + + it("jsonB keys can be found regardless of order", () => Promise.all(connections.map(async connection => { + await connection.transaction(async manager => { + await manager.save(manager.create(JSONBKeyTest, { id: { first: 3, second: 3 } })); + await manager.save(manager.create(JSONBKeyTest, { id: { first: 4, second: 3 } })); + await manager.save(manager.create(JSONBKeyTest, { id: { first: 5, second: 3 } })); + await manager.save(manager.create(JSONBKeyTest, { id: { first: 6, second: 4 } })); + + + const payload = { second: 2, first: 1 }; + await manager.save(manager.create(JSONBKeyTest, { id: payload })); + const entities = await manager.find(JSONBKeyTest, { where: { id: payload } }); + expect(entities.length).to.equal(1); + expect(entities[0].id).to.deep.equal({ first: 1, second: 2 }); + + const entitiesOtherOrder = await manager.find(JSONBKeyTest, { where: { id: {first: 1, second: 2} } }); + expect(entitiesOtherOrder.length).to.equal(1); + expect(entitiesOtherOrder[0].id).to.deep.equal({ first: 1, second: 2 }); + + }); + }))); +}); From 2d9a3ce737996152f52872d5461860dbf6ef3900 Mon Sep 17 00:00:00 2001 From: Jakob Wagner Date: Tue, 6 Oct 2020 10:33:43 +0200 Subject: [PATCH 111/212] docs: update many-to-one-one-to-many-relations.md (#6832) Changing this as it would give an linting error (no unused variable) --- docs/many-to-one-one-to-many-relations.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/many-to-one-one-to-many-relations.md b/docs/many-to-one-one-to-many-relations.md index 16c24e23839..cf42f0cbd25 100644 --- a/docs/many-to-one-one-to-many-relations.md +++ b/docs/many-to-one-one-to-many-relations.md @@ -17,7 +17,7 @@ export class Photo { @Column() url: string; - @ManyToOne(type => User, user => user.photos) + @ManyToOne(() => User, user => user.photos) user: User; } @@ -36,7 +36,7 @@ export class User { @Column() name: string; - @OneToMany(type => Photo, photo => photo.user) + @OneToMany(() => Photo, photo => photo.user) photos: Photo[]; } From 21c41663ccecfa5f2d94f94424f1a9a53e5d817c Mon Sep 17 00:00:00 2001 From: Le Couteur Paul <32302162+paeolo@users.noreply.github.com> Date: Wed, 7 Oct 2020 06:58:43 +0200 Subject: [PATCH 112/212] fix: postgresql connection URL can use an UNIX Socket (#2614) (#6042) --- src/driver/postgres/PostgresDriver.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/driver/postgres/PostgresDriver.ts b/src/driver/postgres/PostgresDriver.ts index bb5f2f34dfa..2b8c0f02ee3 100644 --- a/src/driver/postgres/PostgresDriver.ts +++ b/src/driver/postgres/PostgresDriver.ts @@ -2,7 +2,6 @@ import {Driver} from "../Driver"; import {ConnectionIsNotSetError} from "../../error/ConnectionIsNotSetError"; import {ObjectLiteral} from "../../common/ObjectLiteral"; import {DriverPackageNotInstalledError} from "../../error/DriverPackageNotInstalledError"; -import {DriverUtils} from "../DriverUtils"; import {ColumnMetadata} from "../../metadata/ColumnMetadata"; import {PostgresQueryRunner} from "./PostgresQueryRunner"; import {DateUtils} from "../../util/DateUtils"; @@ -971,11 +970,12 @@ export class PostgresDriver implements Driver { */ protected async createPool(options: PostgresConnectionOptions, credentials: PostgresConnectionCredentialsOptions): Promise { - credentials = Object.assign({}, credentials, DriverUtils.buildDriverOptions(credentials)); // todo: do it better way + credentials = Object.assign({}, credentials); // build connection options for the driver // See: https://github.com/brianc/node-postgres/tree/master/packages/pg-pool#create const connectionOptions = Object.assign({}, { + connectionString: credentials.url, host: credentials.host, user: credentials.username, password: credentials.password, From c8bf81ed2d47ba0822f8d6267ae1997180db2e31 Mon Sep 17 00:00:00 2001 From: James Ward Date: Wed, 7 Oct 2020 02:32:15 -0400 Subject: [PATCH 113/212] feat: backport ilike from next (#6862) the next branch has support for ilike and this backports the FindOperator into the main branch --- src/find-options/FindOperatorType.ts | 1 + src/find-options/operator/ILike.ts | 9 ++++ src/index.ts | 1 + src/query-builder/QueryBuilder.ts | 2 + .../repository-find-operators.ts | 45 +++++++++++++++++++ 5 files changed, 58 insertions(+) create mode 100644 src/find-options/operator/ILike.ts diff --git a/src/find-options/FindOperatorType.ts b/src/find-options/FindOperatorType.ts index 3830dec8779..7b9e04923a0 100644 --- a/src/find-options/FindOperatorType.ts +++ b/src/find-options/FindOperatorType.ts @@ -11,5 +11,6 @@ export type FindOperatorType = "not" | "in" | "any" | "isNull" + | "ilike" | "like" | "raw"; diff --git a/src/find-options/operator/ILike.ts b/src/find-options/operator/ILike.ts new file mode 100644 index 00000000000..1d3cfaffe46 --- /dev/null +++ b/src/find-options/operator/ILike.ts @@ -0,0 +1,9 @@ +import {FindOperator} from "../FindOperator"; + +/** + * Find Options Operator. + * Example: { someField: ILike("%SOME string%") } + */ +export function ILike(value: T|FindOperator) { + return new FindOperator("ilike", value); +} \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index 635876fb9d2..61915963bad 100644 --- a/src/index.ts +++ b/src/index.ts @@ -84,6 +84,7 @@ export * from "./find-options/operator/In"; export * from "./find-options/operator/IsNull"; export * from "./find-options/operator/LessThan"; export * from "./find-options/operator/LessThanOrEqual"; +export * from "./find-options/operator/ILike"; export * from "./find-options/operator/Like"; export * from "./find-options/operator/MoreThan"; export * from "./find-options/operator/MoreThanOrEqual"; diff --git a/src/query-builder/QueryBuilder.ts b/src/query-builder/QueryBuilder.ts index 4776a441490..209758eebd6 100644 --- a/src/query-builder/QueryBuilder.ts +++ b/src/query-builder/QueryBuilder.ts @@ -882,6 +882,8 @@ export abstract class QueryBuilder { return `${aliasPath} >= ${parameters[0]}`; case "equal": return `${aliasPath} = ${parameters[0]}`; + case "ilike": + return `${aliasPath} ILIKE ${parameters[0]}`; case "like": return `${aliasPath} LIKE ${parameters[0]}`; case "between": diff --git a/test/functional/repository/find-options-operators/repository-find-operators.ts b/test/functional/repository/find-options-operators/repository-find-operators.ts index d0b88ebddf4..cf3df34cdb8 100644 --- a/test/functional/repository/find-options-operators/repository-find-operators.ts +++ b/test/functional/repository/find-options-operators/repository-find-operators.ts @@ -5,6 +5,7 @@ import { Between, Connection, Equal, + ILike, In, IsNull, LessThan, @@ -271,6 +272,50 @@ describe("repository > find options > operators", () => { }))); + it("ilike", () => Promise.all(connections.map(async connection => { + if (!(connection.driver instanceof PostgresDriver)) + return; + + // insert some fake data + const post1 = new Post(); + post1.title = "about #1"; + post1.likes = 12; + await connection.manager.save(post1); + const post2 = new Post(); + post2.title = "ABOUT #2"; + post2.likes = 3; + await connection.manager.save(post2); + + // check operator + const loadedPosts = await connection.getRepository(Post).find({ + title: ILike("%out #%") + }); + loadedPosts.should.be.eql([{ id: 1, likes: 12, title: "about #1" }, { id: 2, likes: 3, title: "ABOUT #2" }]); + + }))); + + it("not(ilike)", () => Promise.all(connections.map(async connection => { + if (!(connection.driver instanceof PostgresDriver)) + return; + + // insert some fake data + const post1 = new Post(); + post1.title = "about #1"; + post1.likes = 12; + await connection.manager.save(post1); + const post2 = new Post(); + post2.title = "ABOUT #2"; + post2.likes = 3; + await connection.manager.save(post2); + + // check operator + const loadedPosts = await connection.getRepository(Post).find({ + title: Not(ILike("%out #1")) + }); + loadedPosts.should.be.eql([{ id: 2, likes: 3, title: "ABOUT #2" }]); + + }))); + it("like", () => Promise.all(connections.map(async connection => { // insert some fake data From bc60dd559ba42af083ddea17f01205c78c83c7e0 Mon Sep 17 00:00:00 2001 From: Tycho Tatitscheff Date: Wed, 7 Oct 2020 10:11:24 +0200 Subject: [PATCH 114/212] docs: improve the doc about Raw operator and add missing test (#6863) * docs: improve raw documentation * test: add missing test case --- docs/find-options.md | 35 +++++++++++++++++-- .../repository-find-operators.ts | 10 ++++++ 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/docs/find-options.md b/docs/find-options.md index f1df389d2e1..87e8d18ba2d 100644 --- a/docs/find-options.md +++ b/docs/find-options.md @@ -367,8 +367,39 @@ will execute following query: SELECT * FROM "post" WHERE "currentDate" > NOW() ``` -> Note: beware with `Raw` operator. It executes pure SQL from supplied expression and should not contain a user input, - otherwise it will lead to SQL-injection. +If you need to provide user input, you should not include the user input directly in your query as this may create a SQL injection vulnerability. Instead, you can use the second argument of the `Raw` function to provide a list of parameters to bind to the query. + +```ts +import {Raw} from "typeorm"; + +const loadedPosts = await connection.getRepository(Post).find({ + currentDate: Raw(alias =>`${alias} > ':date'`, { date: "2020-10-06" }) +}); +``` + +will execute following query: + +```sql +SELECT * FROM "post" WHERE "currentDate" > '2020-10-06' +``` + +If you need to provide user input that is an array, you can bind them as a list of values in the SQL statement by using the special expression syntax: + +```ts +import {Raw} from "typeorm"; + +const loadedPosts = await connection.getRepository(Post).find({ + title: Raw(alias =>`${alias} IN (:...titles)`, { titles: ["Go To Statement Considered Harmful", "Structured Programming"] }) +}); +``` + +will execute following query: + +```sql +SELECT * FROM "post" WHERE "titles" IN ('Go To Statement Considered Harmful', 'Structured Programming') +``` + +## Combining Advanced Options Also you can combine these operators with `Not` operator: diff --git a/test/functional/repository/find-options-operators/repository-find-operators.ts b/test/functional/repository/find-options-operators/repository-find-operators.ts index cf3df34cdb8..ee6eb020e13 100644 --- a/test/functional/repository/find-options-operators/repository-find-operators.ts +++ b/test/functional/repository/find-options-operators/repository-find-operators.ts @@ -650,6 +650,16 @@ describe("repository > find options > operators", () => { { id: 3, likes: 3, title: "About #3" }, { id: 6, likes: 6, title: "About #6" }, ]); + + // check operator + const result6 = await connection.getRepository(Post).find({ + likes: Raw((columnAlias) => `${columnAlias} IN (:...values)`, { values: [2, 3, 6] }), + }); + result6.should.be.eql([ + { id: 2, likes: 2, title: "About #2" }, + { id: 3, likes: 3, title: "About #3" }, + { id: 6, likes: 6, title: "About #6" }, + ]); }))); it("should work with ActiveRecord model", async () => { From e37eb1e8e8544f91c3d0a44b55322966e121b3af Mon Sep 17 00:00:00 2001 From: Dan Manastireanu <498419+danmana@users.noreply.github.com> Date: Wed, 7 Oct 2020 11:34:45 +0300 Subject: [PATCH 115/212] fix: Fix Mongodb delete by ObjectId. Closes #6552 (#6553) * fix: Fix Mongodb delete by ObjectId. Closes #6552 * add regression test --- src/entity-manager/MongoEntityManager.ts | 19 +++- test/github-issues/6552/entity/Post.ts | 14 +++ test/github-issues/6552/entity/PostV2.ts | 14 +++ test/github-issues/6552/issue-6552.ts | 121 +++++++++++++++++++++++ 4 files changed, 165 insertions(+), 3 deletions(-) create mode 100644 test/github-issues/6552/entity/Post.ts create mode 100644 test/github-issues/6552/entity/PostV2.ts create mode 100644 test/github-issues/6552/issue-6552.ts diff --git a/src/entity-manager/MongoEntityManager.ts b/src/entity-manager/MongoEntityManager.ts index b8b8761a09a..fec1d5a2e70 100644 --- a/src/entity-manager/MongoEntityManager.ts +++ b/src/entity-manager/MongoEntityManager.ts @@ -630,6 +630,18 @@ export class MongoEntityManager extends EntityManager { * Ensures given id is an id for query. */ protected convertMixedCriteria(metadata: EntityMetadata, idMap: any): ObjectLiteral { + const objectIdInstance = PlatformTools.load("mongodb").ObjectID; + + // check first if it's ObjectId compatible: + // string, number, Buffer, ObjectId or ObjectId-like + if (objectIdInstance.isValid(idMap)) { + return { + "_id": new objectIdInstance(idMap) + }; + } + + // if it's some other type of object build a query from the columns + // this check needs to be after the ObjectId check, because a valid ObjectId is also an Object instance if (idMap instanceof Object) { return metadata.columns.reduce((query, column) => { const columnValue = column.getEntityValue(idMap); @@ -639,10 +651,11 @@ export class MongoEntityManager extends EntityManager { }, {} as any); } - // means idMap is just object id - const objectIdInstance = PlatformTools.load("mongodb").ObjectID; + // last resort: try to convert it to an ObjectID anyway + // most likely it will fail, but we want to be backwards compatible and keep the same thrown Errors. + // it can still pass with null/undefined return { - "_id": (idMap instanceof objectIdInstance) ? idMap : new objectIdInstance(idMap) + "_id": new objectIdInstance(idMap) }; } diff --git a/test/github-issues/6552/entity/Post.ts b/test/github-issues/6552/entity/Post.ts new file mode 100644 index 00000000000..8b1a13bc5fe --- /dev/null +++ b/test/github-issues/6552/entity/Post.ts @@ -0,0 +1,14 @@ +import { ObjectID, ObjectIdColumn } from "../../../../src"; +import { Column } from "../../../../src/decorator/columns/Column"; +import { Entity } from "../../../../src/decorator/entity/Entity"; + +@Entity() +export class Post { + + @ObjectIdColumn() + _id: ObjectID; + + @Column() + title: string; + +} diff --git a/test/github-issues/6552/entity/PostV2.ts b/test/github-issues/6552/entity/PostV2.ts new file mode 100644 index 00000000000..c9e798a4a82 --- /dev/null +++ b/test/github-issues/6552/entity/PostV2.ts @@ -0,0 +1,14 @@ +import { ObjectID, ObjectIdColumn } from "../../../../src"; +import { Column } from "../../../../src/decorator/columns/Column"; +import { Entity } from "../../../../src/decorator/entity/Entity"; + +@Entity() +export class PostV2 { + + @ObjectIdColumn() + postId: ObjectID; + + @Column() + title: string; + +} diff --git a/test/github-issues/6552/issue-6552.ts b/test/github-issues/6552/issue-6552.ts new file mode 100644 index 00000000000..368ea36ce95 --- /dev/null +++ b/test/github-issues/6552/issue-6552.ts @@ -0,0 +1,121 @@ +import { expect } from "chai"; +import "reflect-metadata"; +import { Connection } from "../../../src/connection/Connection"; +import { PlatformTools } from "../../../src/platform/PlatformTools"; +import { closeTestingConnections, createTestingConnections, reloadTestingDatabases } from "../../utils/test-utils"; +import { Post } from "./entity/Post"; +import { PostV2 } from "./entity/PostV2"; +import { FindConditions } from "../../../src"; + +describe("github issues > #6552 MongoRepository delete by ObjectId deletes the wrong entity", () => { + + let connections: Connection[]; + before(async () => connections = await createTestingConnections({ + entities: [__dirname + "/entity/*{.js,.ts}"], + enabledDrivers: ["mongodb"] + })); + beforeEach(() => reloadTestingDatabases(connections)); + after(() => closeTestingConnections(connections)); + + // before the fix this would delete incorrectly post1 instead of post2 + it("should delete the correct entity when id column is called _id", () => Promise.all(connections.map(async function (connection) { + + // setup: create 2 posts + const post1 = new Post(); + post1.title = "Post 1"; + await connection.manager.save(post1); + + const post2 = new Post(); + post2.title = "Post 2"; + await connection.manager.save(post2); + + const objectIdInstance = PlatformTools.load("mongodb").ObjectID; + + // double check that post2._id is actually an ObjectID + expect(post2._id).to.be.not.null; + expect(post2._id).to.be.not.undefined; + expect(post2._id).to.be.instanceof(objectIdInstance); + + // delete Post 2 by ObjectId directly + await connection.manager.delete(Post, post2._id); + // This used to wrongly perform deleteOne({}) - deleting the first Post in the collection + + // Post 1 should remain in the DB + const count1 = await connection.manager.count(Post, { _id: post1._id } as FindConditions); + expect(count1).to.be.equal(1, "Post 1 should still exist"); + + // Post 2 should be deleted + const count2 = await connection.manager.count(Post, { _id: post2._id } as FindConditions); + expect(count2).to.be.equal(0, "Post 2 should be deleted"); + + + }))); + + // before the fix this wouldn't delete anything + it("should delete the correct entity when id column is not called _id", () => Promise.all(connections.map(async function (connection) { + + // setup: create 2 posts + const post1 = new PostV2(); + post1.title = "Post 1"; + await connection.manager.save(post1); + + const post2 = new PostV2(); + post2.title = "Post 2"; + await connection.manager.save(post2); + + const objectIdInstance = PlatformTools.load("mongodb").ObjectID; + + // double check that post2.postId is actually an ObjectID + expect(post2.postId).to.be.not.null; + expect(post2.postId).to.be.not.undefined; + expect(post2.postId).to.be.instanceof(objectIdInstance); + + // delete Post 2 by ObjectId directly + await connection.manager.delete(PostV2, post2.postId); + // This used to wrongly perform deleteOne({_id: Buffer}) - not deleting anything because Buffer is not an ObjectId + + // Post 1 should remain in the DB + const count1 = await connection.manager.count(PostV2, { _id: post1.postId } as FindConditions); + expect(count1).to.be.equal(1, "Post 1 should still exist"); + + // Post 2 should be deleted + const count2 = await connection.manager.count(PostV2, { _id: post2.postId } as FindConditions); + expect(count2).to.be.equal(0, "Post 2 should be deleted"); + + + }))); + + // before the fix this passed (added here to make sure we don't cause any regressions) + it("should delete the correct entity when deleting by _id query", () => Promise.all(connections.map(async function (connection) { + + // setup: create 2 posts + const post1 = new Post(); + post1.title = "Post 1"; + await connection.manager.save(post1); + + const post2 = new Post(); + post2.title = "Post 2"; + await connection.manager.save(post2); + + const objectIdInstance = PlatformTools.load("mongodb").ObjectID; + + // double check that post2._id is actually an ObjectID + expect(post2._id).to.be.not.null; + expect(post2._id).to.be.not.undefined; + expect(post2._id).to.be.instanceof(objectIdInstance); + + // delete Post 2 by ObjectId directly + await connection.manager.delete(Post, { _id: post2._id }); + + // Post 1 should remain in the DB + const count1 = await connection.manager.count(Post, { _id: post1._id } as FindConditions); + expect(count1).to.be.equal(1, "Post 1 should still exist"); + + // Post 2 should be deleted + const count2 = await connection.manager.count(Post, { _id: post2._id } as FindConditions); + expect(count2).to.be.equal(0, "Post 2 should be deleted"); + + + }))); + +}); From 990442e891e91cd829f9f34eff2114d4c623d24b Mon Sep 17 00:00:00 2001 From: Nicolas Lenepveu Date: Wed, 7 Oct 2020 11:16:09 +0200 Subject: [PATCH 116/212] feat: schema synchronization for partitioned tables with PostgreSQL 12+ (#6780) * feat: ignore foreign keys on partitions of partitioned tables when syncing schema on postgresql 12+ * feat: consider partitionned tables as regular tables in order to keep them in sync --- src/driver/postgres/PostgresQueryRunner.ts | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/driver/postgres/PostgresQueryRunner.ts b/src/driver/postgres/PostgresQueryRunner.ts index e34f2d71946..ae94bd8bb7e 100644 --- a/src/driver/postgres/PostgresQueryRunner.ts +++ b/src/driver/postgres/PostgresQueryRunner.ts @@ -1412,7 +1412,7 @@ export class PostgresQueryRunner extends BaseQueryRunner implements QueryRunner `INNER JOIN "pg_class" "t" ON "t"."oid" = "cnst"."conrelid" ` + `INNER JOIN "pg_namespace" "ns" ON "ns"."oid" = "cnst"."connamespace" ` + `LEFT JOIN "pg_attribute" "a" ON "a"."attrelid" = "cnst"."conrelid" AND "a"."attnum" = ANY ("cnst"."conkey") ` + - `WHERE "t"."relkind" = 'r' AND (${constraintsCondition})`; + `WHERE "t"."relkind" IN ('r', 'p') AND (${constraintsCondition})`; const indicesSql = `SELECT "ns"."nspname" AS "table_schema", "t"."relname" AS "table_name", "i"."relname" AS "constraint_name", "a"."attname" AS "column_name", ` + `CASE "ix"."indisunique" WHEN 't' THEN 'TRUE' ELSE'FALSE' END AS "is_unique", pg_get_expr("ix"."indpred", "ix"."indrelid") AS "condition", ` + @@ -1424,7 +1424,7 @@ export class PostgresQueryRunner extends BaseQueryRunner implements QueryRunner `INNER JOIN "pg_class" "i" ON "i"."oid" = "ix"."indexrelid" ` + `INNER JOIN "pg_type" "types" ON "types"."oid" = "a"."atttypid" ` + `LEFT JOIN "pg_constraint" "cnst" ON "cnst"."conname" = "i"."relname" ` + - `WHERE "t"."relkind" = 'r' AND "cnst"."contype" IS NULL AND (${constraintsCondition})`; + `WHERE "t"."relkind" IN ('r', 'p') AND "cnst"."contype" IS NULL AND (${constraintsCondition})`; const foreignKeysCondition = tableNames.map(tableName => { let [schema, name] = tableName.split("."); @@ -1434,6 +1434,10 @@ export class PostgresQueryRunner extends BaseQueryRunner implements QueryRunner } return `("ns"."nspname" = '${schema}' AND "cl"."relname" = '${name}')`; }).join(" OR "); + + const hasRelispartitionColumn = await this.hasSupportForPartitionedTables(); + const isPartitionCondition = hasRelispartitionColumn ? ` AND "cl"."relispartition" = 'f'` : ""; + const foreignKeysSql = `SELECT "con"."conname" AS "constraint_name", "con"."nspname" AS "table_schema", "con"."relname" AS "table_name", "att2"."attname" AS "column_name", ` + `"ns"."nspname" AS "referenced_table_schema", "cl"."relname" AS "referenced_table_name", "att"."attname" AS "referenced_column_name", "con"."confdeltype" AS "on_delete", ` + `"con"."confupdtype" AS "on_update", "con"."condeferrable" AS "deferrable", "con"."condeferred" AS "deferred" ` + @@ -1449,7 +1453,7 @@ export class PostgresQueryRunner extends BaseQueryRunner implements QueryRunner `WHERE "con1"."contype" = 'f' AND (${foreignKeysCondition}) ` + `) "con" ` + `INNER JOIN "pg_attribute" "att" ON "att"."attrelid" = "con"."confrelid" AND "att"."attnum" = "con"."child" ` + - `INNER JOIN "pg_class" "cl" ON "cl"."oid" = "con"."confrelid" ` + + `INNER JOIN "pg_class" "cl" ON "cl"."oid" = "con"."confrelid" ${isPartitionCondition}` + `INNER JOIN "pg_namespace" "ns" ON "cl"."relnamespace" = "ns"."oid" ` + `INNER JOIN "pg_attribute" "att2" ON "att2"."attrelid" = "con"."conrelid" AND "att2"."attnum" = "con"."parent"`; const [dbTables, dbColumns, dbConstraints, dbIndices, dbForeignKeys]: ObjectLiteral[][] = await Promise.all([ @@ -2125,4 +2129,11 @@ export class PostgresQueryRunner extends BaseQueryRunner implements QueryRunner return c; } + /** + * Checks if the PostgreSQL server has support for partitioned tables + */ + protected async hasSupportForPartitionedTables() { + const result = await this.query(`SELECT TRUE FROM information_schema.columns WHERE table_name = 'pg_class' and column_name = 'relispartition'`); + return result.length ? true : false; + } } From 4a0faf0ae46fc534db03e89aedd0ac9408f506d5 Mon Sep 17 00:00:00 2001 From: James Ward Date: Wed, 7 Oct 2020 11:25:11 -0400 Subject: [PATCH 117/212] test: adds test to prevent #4958 from recurring (#6835) in #4958 we found that the PR #4804 caused issues in a variety of situations. this adds a test to prevent the issue from recurring where similar classes get mixed up in our metadata resolver --- test/github-issues/4958/entity/first.ts | 11 +++++++++++ test/github-issues/4958/entity/second.ts | 11 +++++++++++ test/github-issues/4958/issue-4958.ts | 24 ++++++++++++++++++++++++ 3 files changed, 46 insertions(+) create mode 100644 test/github-issues/4958/entity/first.ts create mode 100644 test/github-issues/4958/entity/second.ts create mode 100644 test/github-issues/4958/issue-4958.ts diff --git a/test/github-issues/4958/entity/first.ts b/test/github-issues/4958/entity/first.ts new file mode 100644 index 00000000000..84a6174f2b7 --- /dev/null +++ b/test/github-issues/4958/entity/first.ts @@ -0,0 +1,11 @@ +import { Column, Entity } from "../../../../src"; + +@Entity({ name: "first" }) +export default class Testing { + @Column("int", { + nullable: false, + primary: true, + unique: true, + }) + public id!: number; +} diff --git a/test/github-issues/4958/entity/second.ts b/test/github-issues/4958/entity/second.ts new file mode 100644 index 00000000000..53d53a8cfbe --- /dev/null +++ b/test/github-issues/4958/entity/second.ts @@ -0,0 +1,11 @@ +import { Column, Entity } from "../../../../src"; + +@Entity({ name: "second" }) +export default class Testing { + @Column("int", { + nullable: false, + primary: true, + unique: true, + }) + public notId!: number; +} diff --git a/test/github-issues/4958/issue-4958.ts b/test/github-issues/4958/issue-4958.ts new file mode 100644 index 00000000000..c3e54917f48 --- /dev/null +++ b/test/github-issues/4958/issue-4958.ts @@ -0,0 +1,24 @@ +import {expect} from "chai"; +import {Connection} from "../../../src/connection/Connection"; +import {closeTestingConnections, createTestingConnections, reloadTestingDatabases} from "../../utils/test-utils"; +import First from "./entity/first"; +import Second from "./entity/second"; + +describe("github issues > #4958 getRepository returns results from another Repo", () => { + let connections: Connection[]; + before(async () => connections = await createTestingConnections({ + entities: [First, Second], + enabledDrivers: ["sqlite"] + })); + beforeEach(() => reloadTestingDatabases(connections)); + after(() => closeTestingConnections(connections)); + + it("sql generated is for correct model", () => Promise.all(connections.map(async connection => { + const rawSql = await connection + .getRepository(Second) + .createQueryBuilder("a") + .getSql(); + + expect(rawSql).to.be.equal('SELECT "a"."notId" AS "a_notId" FROM "second" "a"'); + }))); +}); From 2bf15ca913016ad07080c38c9fc3ee848b60ca4f Mon Sep 17 00:00:00 2001 From: "Saulo S. Toledo" Date: Wed, 7 Oct 2020 13:27:31 -0300 Subject: [PATCH 118/212] fix: remove @DiscriminatorValue from error message (#5256) Closes: #5255 --- src/metadata-builder/EntityMetadataValidator.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/metadata-builder/EntityMetadataValidator.ts b/src/metadata-builder/EntityMetadataValidator.ts index 33329f0a8a7..2e94c3ab333 100644 --- a/src/metadata-builder/EntityMetadataValidator.ts +++ b/src/metadata-builder/EntityMetadataValidator.ts @@ -69,7 +69,7 @@ export class EntityMetadataValidator { return metadata !== entityMetadata && metadata.discriminatorValue === entityMetadata.discriminatorValue; }); if (sameDiscriminatorValueEntityMetadata) - throw new Error(`Entities ${entityMetadata.name} and ${sameDiscriminatorValueEntityMetadata.name} as equal discriminator values. Make sure their discriminator values are not equal using @DiscriminatorValue decorator.`); + throw new Error(`Entities ${entityMetadata.name} and ${sameDiscriminatorValueEntityMetadata.name} have the same discriminator values. Make sure they are different while using the @ChildEntity decorator.`); } entityMetadata.relationCounts.forEach(relationCount => { From b22c27feb2dd3892d47a9e82b0d7b11650d059b5 Mon Sep 17 00:00:00 2001 From: NthMetal <832529@gmail.com> Date: Thu, 8 Oct 2020 01:33:31 -0400 Subject: [PATCH 119/212] feat: support `autoEncryption` option for MongoDB (#6865) --- src/driver/mongodb/MongoConnectionOptions.ts | 5 +++++ src/driver/mongodb/MongoDriver.ts | 5 +++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/driver/mongodb/MongoConnectionOptions.ts b/src/driver/mongodb/MongoConnectionOptions.ts index 845f3f718c7..7cbb1aac82e 100644 --- a/src/driver/mongodb/MongoConnectionOptions.ts +++ b/src/driver/mongodb/MongoConnectionOptions.ts @@ -327,4 +327,9 @@ export interface MongoConnectionOptions extends BaseConnectionOptions { * https://github.com/mongodb/node-mongodb-native/releases/tag/v3.2.1 */ readonly useUnifiedTopology?: boolean; + + /** + * Automatic Client-Side Field Level Encryption configuration. + */ + readonly autoEncryption?: any; } diff --git a/src/driver/mongodb/MongoDriver.ts b/src/driver/mongodb/MongoDriver.ts index 1b53dc91f86..1602acee51c 100644 --- a/src/driver/mongodb/MongoDriver.ts +++ b/src/driver/mongodb/MongoDriver.ts @@ -135,7 +135,7 @@ export class MongoDriver implements Driver { /** * Valid mongo connection options * NOTE: Keep sync with MongoConnectionOptions - * Sync with http://mongodb.github.io/node-mongodb-native/3.1/api/MongoClient.html + * Sync with http://mongodb.github.io/node-mongodb-native/3.5/api/MongoClient.html */ protected validOptionNames: string[] = [ "poolSize", @@ -196,7 +196,8 @@ export class MongoDriver implements Driver { "minSize", "monitorCommands", "useNewUrlParser", - "useUnifiedTopology" + "useUnifiedTopology", + "autoEncryption" ]; // ------------------------------------------------------------------------- From d86671cb179751730d0324b23d9f4bcb21010728 Mon Sep 17 00:00:00 2001 From: Mohamed Akram Date: Thu, 8 Oct 2020 10:10:29 +0400 Subject: [PATCH 120/212] perf: Improve replacePropertyNames (#4760) Reduce the number of regular expressions created & strings created when replacing the property names in a statement. --- src/query-builder/QueryBuilder.ts | 64 +++++++++++++++++++++---------- 1 file changed, 44 insertions(+), 20 deletions(-) diff --git a/src/query-builder/QueryBuilder.ts b/src/query-builder/QueryBuilder.ts index 209758eebd6..eda2e4054bd 100644 --- a/src/query-builder/QueryBuilder.ts +++ b/src/query-builder/QueryBuilder.ts @@ -565,27 +565,51 @@ export abstract class QueryBuilder { * Replaces all entity's propertyName to name in the given statement. */ protected replacePropertyNames(statement: string) { - this.expressionMap.aliases.forEach(alias => { - if (!alias.hasMetadata) return; - const replaceAliasNamePrefix = this.expressionMap.aliasNamePrefixingEnabled ? alias.name + "\\." : ""; - const replacementAliasNamePrefix = this.expressionMap.aliasNamePrefixingEnabled ? this.escape(alias.name) + "." : ""; - alias.metadata.columns.forEach(column => { - const expression = "([ =\(]|^.{0})" + replaceAliasNamePrefix + column.propertyPath + "([ =\)\,]|.{0}$)"; - statement = statement.replace(new RegExp(expression, "gm"), "$1" + replacementAliasNamePrefix + this.escape(column.databaseName) + "$2"); - const expression2 = "([ =\(]|^.{0})" + replaceAliasNamePrefix + column.propertyName + "([ =\)\,]|.{0}$)"; - statement = statement.replace(new RegExp(expression2, "gm"), "$1" + replacementAliasNamePrefix + this.escape(column.databaseName) + "$2"); - }); - alias.metadata.relations.forEach(relation => { - [...relation.joinColumns, ...relation.inverseJoinColumns].forEach(joinColumn => { - const expression = "([ =\(]|^.{0})" + replaceAliasNamePrefix + relation.propertyPath + "\\." + joinColumn.referencedColumn!.propertyPath + "([ =\)\,]|.{0}$)"; - statement = statement.replace(new RegExp(expression, "gm"), "$1" + replacementAliasNamePrefix + this.escape(joinColumn.databaseName) + "$2"); // todo: fix relation.joinColumns[0], what if multiple columns - }); - if (relation.joinColumns.length > 0) { - const expression = "([ =\(]|^.{0})" + replaceAliasNamePrefix + relation.propertyPath + "([ =\)\,]|.{0}$)"; - statement = statement.replace(new RegExp(expression, "gm"), "$1" + replacementAliasNamePrefix + this.escape(relation.joinColumns[0].databaseName) + "$2"); // todo: fix relation.joinColumns[0], what if multiple columns + // Escape special characters in regular expressions + // Per https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#Escaping + const escapeRegExp = (s: String) => s.replace(/[.*+\-?^${}()|[\]\\]/g, "\\$&"); + + for (const alias of this.expressionMap.aliases) { + if (!alias.hasMetadata) continue; + const replaceAliasNamePrefix = this.expressionMap.aliasNamePrefixingEnabled ? `${alias.name}.` : ""; + const replacementAliasNamePrefix = this.expressionMap.aliasNamePrefixingEnabled ? `${this.escape(alias.name)}.` : ""; + + const replacements: { [key: string]: string } = {}; + + for (const column of alias.metadata.columns) { + if (!(column.propertyPath in replacements)) + replacements[column.propertyPath] = column.databaseName; + if (!(column.propertyName in replacements)) + replacements[column.propertyName] = column.databaseName; + if (!(column.databaseName in replacements)) + replacements[column.databaseName] = column.databaseName; + } + + for (const relation of alias.metadata.relations) { + for (const joinColumn of [...relation.joinColumns, ...relation.inverseJoinColumns]) { + const key = `${relation.propertyPath}.${joinColumn.referencedColumn!.propertyPath}`; + if (!(key in replacements)) + replacements[key] = joinColumn.databaseName; } - }); - }); + + if (relation.joinColumns.length > 0 && !(relation.propertyPath in replacements)) + replacements[relation.propertyPath] = relation.joinColumns[0].databaseName; + } + + const replacementKeys = Object.keys(replacements); + + if (replacementKeys.length) { + statement = statement.replace(new RegExp( + `(?<=[ =\(]|^.{0})` + + `${escapeRegExp(replaceAliasNamePrefix)}(${replacementKeys.map(escapeRegExp).join("|")})` + + `(?=[ =\)\,]|.{0}$)`, + "gm" + ), (_, p) => + `${replacementAliasNamePrefix}${this.escape(replacements[p])}` + ); + } + } + return statement; } From 0280cdc451c35ef73c830eb1191c95d34f6ce06e Mon Sep 17 00:00:00 2001 From: hahahu Date: Thu, 8 Oct 2020 14:29:50 +0800 Subject: [PATCH 121/212] fix: Cannot read property 'hasMetadata' of undefined (#5659) fixes #3685 --- src/query-builder/QueryBuilder.ts | 3 ++ test/github-issues/3685/entity/user.ts | 15 +++++++ test/github-issues/3685/issue-3685.ts | 62 ++++++++++++++++++++++++++ 3 files changed, 80 insertions(+) create mode 100644 test/github-issues/3685/entity/user.ts create mode 100644 test/github-issues/3685/issue-3685.ts diff --git a/src/query-builder/QueryBuilder.ts b/src/query-builder/QueryBuilder.ts index eda2e4054bd..1b1d8ef0d56 100644 --- a/src/query-builder/QueryBuilder.ts +++ b/src/query-builder/QueryBuilder.ts @@ -797,6 +797,9 @@ export abstract class QueryBuilder { if (where instanceof Brackets) { const whereQueryBuilder = this.createQueryBuilder(); + whereQueryBuilder.expressionMap.mainAlias = this.expressionMap.mainAlias; + whereQueryBuilder.expressionMap.aliasNamePrefixingEnabled = this.expressionMap.aliasNamePrefixingEnabled; + whereQueryBuilder.expressionMap.nativeParameters = this.expressionMap.nativeParameters; where.whereFactory(whereQueryBuilder as any); const whereString = whereQueryBuilder.createWhereExpressionString(); this.setParameters(whereQueryBuilder.getParameters()); diff --git a/test/github-issues/3685/entity/user.ts b/test/github-issues/3685/entity/user.ts new file mode 100644 index 00000000000..6c6c64daa56 --- /dev/null +++ b/test/github-issues/3685/entity/user.ts @@ -0,0 +1,15 @@ +import { Column, Entity, PrimaryGeneratedColumn } from "../../../../src"; + +@Entity() +export class User { + + @PrimaryGeneratedColumn() + id: number; + + @Column() + firstName: string; + + @Column() + lastName: string; + +} diff --git a/test/github-issues/3685/issue-3685.ts b/test/github-issues/3685/issue-3685.ts new file mode 100644 index 00000000000..70fd13a681e --- /dev/null +++ b/test/github-issues/3685/issue-3685.ts @@ -0,0 +1,62 @@ +import {expect} from "chai"; +import {Brackets, Connection} from "../../../src"; +import {closeTestingConnections, createTestingConnections, reloadTestingDatabases} from "../../utils/test-utils"; +import {User} from "./entity/user"; + +describe("github issues > #3685 Brackets syntax failed when use where with object literal", () => { + + let connections: Connection[]; + before(async () => connections = await createTestingConnections({ + entities: [__dirname + "/entity/*{.js,.ts}"], + dropSchema: true, + schemaCreate: true, + })); + beforeEach(() => reloadTestingDatabases(connections)); + after(() => connections && closeTestingConnections(connections)); + + it("should accept objects in .where method (github issue #3685)", () => Promise.all(connections.map(async connection => { + + await Promise.all([ + connection.manager.save(Object.assign(new User(), { + firstName: "Jean", + lastName: "Doe", + })), + + connection.manager.save(Object.assign(new User(), { + firstName: "John", + lastName: "Doe", + })), + + connection.manager.save(Object.assign(new User(), { + firstName: "John", + lastName: "Dupont", + })), + + connection.manager.save(Object.assign(new User(), { + firstName: "Fred", + lastName: "Doe", + })) + ]); + + const qb = connection.createQueryBuilder(User, "u") + .where(new Brackets(qb => { + qb.where({ firstName: "John" }) + .orWhere("u.firstName = :firstName", { firstName: "Jean" }); + })) + .andWhere("u.lastName = :lastName", { lastName: "Doe" }) + .orderBy({ + "u.firstName": "ASC", + "u.lastName": "ASC", + }); + + const results = await qb.getMany(); + + expect(results.length).to.equal(2); + + expect(results[0].firstName).to.equal("Jean"); + expect(results[0].lastName).to.equal("Doe"); + + expect(results[1].firstName).to.equal("John"); + expect(results[1].lastName).to.equal("Doe"); + }))); +}); From 645176fe9b88df26f49646358de56ce631e0e9f6 Mon Sep 17 00:00:00 2001 From: James Ward Date: Thu, 8 Oct 2020 23:54:03 -0400 Subject: [PATCH 122/212] test: Pull correct entity in test for #6633 --- test/github-issues/6633/issue-6633.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/github-issues/6633/issue-6633.ts b/test/github-issues/6633/issue-6633.ts index 31df86b5b8a..cd2dbbffa6f 100644 --- a/test/github-issues/6633/issue-6633.ts +++ b/test/github-issues/6633/issue-6633.ts @@ -2,14 +2,14 @@ import "reflect-metadata"; import { expect } from "chai"; import { Connection } from "../../../src"; import { closeTestingConnections, createTestingConnections, reloadTestingDatabases } from "../../utils/test-utils"; -import { Post } from "../4440/entity/Post"; +import { Test } from "./entity/Test"; describe("github issues > #6633 Fulltext indices continually dropped & re-created", () => { let connections: Connection[]; before(async () => { connections = await createTestingConnections({ - entities: [Post], + entities: [Test], schemaCreate: true, dropSchema: true }); From 5c407deed4016c7eacb9cf25e4de7bade4a88407 Mon Sep 17 00:00:00 2001 From: James Ward Date: Fri, 9 Oct 2020 01:52:04 -0400 Subject: [PATCH 123/212] chore: add `funding` to the package manifest (#6873) adds the funding key to the manifest as the opencollective per https://docs.npmjs.com/configuring-npm/package-json.html#funding fixes #4649 --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 50eca7c0244..73b32e39268 100644 --- a/package.json +++ b/package.json @@ -150,6 +150,7 @@ "bin": { "typeorm": "./cli.js" }, + "funding": "https://opencollective.com/typeorm", "collective": { "type": "opencollective", "url": "https://opencollective.com/typeorm", From 4abfb342aa390ab4643a1133daaf90c0996b61c2 Mon Sep 17 00:00:00 2001 From: James Ward Date: Fri, 9 Oct 2020 02:22:08 -0400 Subject: [PATCH 124/212] fix: handle count multiple PK & edge cases more gracefully (#6870) currently we use concatenation of multiple primary keys and a COUNT DISTINCT of that to figure out how many records we have matched in a query. however, that fails if the records have keys when the keys are ambigious when concatenated (`"A", "AA"` & `"AA", "A"`) the fact that we do a distinct can also be a performance impact that isn't needed when we aren't doing joins as such, in MySQL & Postgres we can use the built in counting of multiple distinct values to resolve some of the issues, and in other environments we can make it SLIGHTLY better by adding delimiters between the concatenated values. It is not perfect because it technically could run into the same issue if the delimiters are in the primary keys but it's BETTER in most cases. also, in cases where we do not perform any joins we can short circuit all of this and do a much more performant `COUNT(1)` operation fixes #5989 fixes #5314 fixes #4550 --- src/query-builder/SelectQueryBuilder.ts | 93 ++++++++++++------- .../count/entity/AmbigiousPrimaryKey.ts | 19 ++++ .../count/query-builder-count.ts | 73 ++++++++++++++- 3 files changed, 151 insertions(+), 34 deletions(-) create mode 100644 test/functional/query-builder/count/entity/AmbigiousPrimaryKey.ts diff --git a/src/query-builder/SelectQueryBuilder.ts b/src/query-builder/SelectQueryBuilder.ts index 11cb61b0a47..5fa2fde9e6c 100644 --- a/src/query-builder/SelectQueryBuilder.ts +++ b/src/query-builder/SelectQueryBuilder.ts @@ -1774,44 +1774,75 @@ export class SelectQueryBuilder extends QueryBuilder implements }); } - protected async executeCountQuery(queryRunner: QueryRunner): Promise { - + private computeCountExpression() { const mainAlias = this.expressionMap.mainAlias!.name; // todo: will this work with "fromTableName"? const metadata = this.expressionMap.mainAlias!.metadata; + const primaryColumns = metadata.primaryColumns; const distinctAlias = this.escape(mainAlias); - let countSql: string = ""; - if (metadata.hasMultiplePrimaryKeys) { - if (this.connection.driver instanceof AbstractSqliteDriver) { - countSql = `COUNT(DISTINCT(` + metadata.primaryColumns.map((primaryColumn, index) => { - const propertyName = this.escape(primaryColumn.databaseName); - return `${distinctAlias}.${propertyName}`; - }).join(" || ") + ")) as \"cnt\""; - - } else if (this.connection.driver instanceof CockroachDriver) { - countSql = `COUNT(DISTINCT(CONCAT(` + metadata.primaryColumns.map((primaryColumn, index) => { - const propertyName = this.escape(primaryColumn.databaseName); - return `${distinctAlias}.${propertyName}::text`; - }).join(", ") + "))) as \"cnt\""; - } else if (this.connection.driver instanceof OracleDriver) { - countSql = `COUNT(DISTINCT(` + metadata.primaryColumns.map((primaryColumn, index) => { - const propertyName = this.escape(primaryColumn.databaseName); - return `${distinctAlias}.${propertyName}`; - }).join(" || ") + ")) as \"cnt\""; - } else { - countSql = `COUNT(DISTINCT(CONCAT(` + metadata.primaryColumns.map((primaryColumn, index) => { - const propertyName = this.escape(primaryColumn.databaseName); - return `${distinctAlias}.${propertyName}`; - }).join(", ") + "))) as \"cnt\""; + + // If we aren't doing anything that will create a join, we can use a simpler `COUNT` instead + // so we prevent poor query patterns in the most likely cases + if ( + this.expressionMap.joinAttributes.length === 0 && + this.expressionMap.relationIdAttributes.length === 0 && + this.expressionMap.relationCountAttributes.length === 0 + ) { + return "COUNT(1)"; + } + + // For everything else, we'll need to do some hackery to get the correct count values. + + if (this.connection.driver instanceof CockroachDriver || this.connection.driver instanceof PostgresDriver) { + // Postgres and CockroachDB can pass multiple parameters to the `DISTINCT` function + // https://www.postgresql.org/docs/9.5/sql-select.html#SQL-DISTINCT + return "COUNT(DISTINCT(" + + primaryColumns.map(c => `${distinctAlias}.${this.escape(c.databaseName)}`).join(", ") + + "))"; + } + + if (this.connection.driver instanceof MysqlDriver) { + // MySQL & MariaDB can pass multiple parameters to the `DISTINCT` language construct + // https://mariadb.com/kb/en/count-distinct/ + return "COUNT(DISTINCT " + + primaryColumns.map(c => `${distinctAlias}.${this.escape(c.databaseName)}`).join(", ") + + ")"; + } + + if (this.connection.driver instanceof SqlServerDriver) { + // SQL Server has gotta be different from everyone else. They don't support + // distinct counting multiple columns & they don't have the same operator + // characteristic for concatenating, so we gotta use the `CONCAT` function. + // However, If it's exactly 1 column we can omit the `CONCAT` for better performance. + + const columnsExpression = primaryColumns.map( + primaryColumn => `${distinctAlias}.${this.escape(primaryColumn.databaseName)}` + ).join(", '|;|', "); + + if (primaryColumns.length === 1) { + + return `COUNT(DISTINCT(${columnsExpression}))`; } - } else { - countSql = `COUNT(DISTINCT(` + metadata.primaryColumns.map((primaryColumn, index) => { - const propertyName = this.escape(primaryColumn.databaseName); - return `${distinctAlias}.${propertyName}`; - }).join(", ") + ")) as \"cnt\""; + return `COUNT(DISTINCT(CONCAT(${columnsExpression})))`; + } + // If all else fails, fall back to a `COUNT` and `DISTINCT` across all the primary columns concatenated. + // Per the SQL spec, this is the canonical string concatenation mechanism which is most + // likely to work across servers implementing the SQL standard. + + // Please note, if there is only one primary column that the concatenation does not occur in this + // query and the query is a standard `COUNT DISTINCT` in that case. + + return `COUNT(DISTINCT(` + + primaryColumns.map(c => `${distinctAlias}.${this.escape(c.databaseName)}`).join(" || '|;|' || ") + + "))"; + } + + protected async executeCountQuery(queryRunner: QueryRunner): Promise { + const countSql = this.computeCountExpression(); + const results = await this.clone() .orderBy() .groupBy() @@ -1819,7 +1850,7 @@ export class SelectQueryBuilder extends QueryBuilder implements .limit(undefined) .skip(undefined) .take(undefined) - .select(countSql) + .select(countSql, "cnt") .setOption("disable-global-order") .loadRawResults(queryRunner); diff --git a/test/functional/query-builder/count/entity/AmbigiousPrimaryKey.ts b/test/functional/query-builder/count/entity/AmbigiousPrimaryKey.ts new file mode 100644 index 00000000000..3492003321f --- /dev/null +++ b/test/functional/query-builder/count/entity/AmbigiousPrimaryKey.ts @@ -0,0 +1,19 @@ +import {Entity, PrimaryColumn} from "../../../../../src"; + +@Entity("ambig_primary_key") +export class AmbigiousPrimaryKey { + @PrimaryColumn() + a: string; + + @PrimaryColumn() + b: string; + + static make({ a, b }: { a: string, b: string }): AmbigiousPrimaryKey { + const apk = new AmbigiousPrimaryKey(); + apk.a = a; + apk.b = b; + + return apk; + } + +} diff --git a/test/functional/query-builder/count/query-builder-count.ts b/test/functional/query-builder/count/query-builder-count.ts index 39990f9d38b..59db9594e94 100644 --- a/test/functional/query-builder/count/query-builder-count.ts +++ b/test/functional/query-builder/count/query-builder-count.ts @@ -2,21 +2,88 @@ import {closeTestingConnections, createTestingConnections, reloadTestingDatabase import {Connection} from "../../../../src/connection/Connection"; import {expect} from "chai"; import {Test} from "./entity/Test"; +import {AmbigiousPrimaryKey} from "./entity/AmbigiousPrimaryKey"; describe("query builder > count", () => { let connections: Connection[]; before(async () => connections = await createTestingConnections({ - entities: [Test], + entities: [Test, AmbigiousPrimaryKey], schemaCreate: true, dropSchema: true, })); beforeEach(() => reloadTestingDatabases(connections)); after(() => closeTestingConnections(connections)); - it("Count query should be completed successfully", () => Promise.all(connections.map(async connection => { - const count = await connection.getRepository(Test).count(); + it("Count query should of empty table should be 0", () => Promise.all(connections.map(async connection => { + const repo = connection.getRepository(Test); + + const count = await repo.count(); expect(count).to.be.equal(0); }))); + it("Count query should count database values", () => Promise.all(connections.map(async connection => { + const repo = connection.getRepository(Test); + + await Promise.all([ + repo.save({ varcharField: 'ok', uuidField: '123e4567-e89b-12d3-a456-426614174000', intField: 4}), + repo.save({ varcharField: 'ok', uuidField: '123e4567-e89b-12d3-a456-426614174001', intField: 4}), + ]); + + const count = await repo.count(); + expect(count).to.be.equal(2); + }))); + + it("Count query should handle ambiguous values", () => Promise.all(connections.map(async connection => { + const repo = connection.getRepository(AmbigiousPrimaryKey); + + await Promise.all([ + repo.save({ a: 'A', b: 'AAA' }), + repo.save({ a: 'AAA', b: 'A' }), + repo.save({ a: 'AA', b: 'AA' }), + repo.save({ a: 'BB', b: 'BB' }), + repo.save({ a: 'B', b: 'BBB' }), + repo.save({ a: 'BBB', b: 'B' }) + ]); + + const count = await repo.count(); + expect(count).to.be.equal(6, connection.name); + }))); + + it("counting joined query should count database values", () => Promise.all(connections.map(async connection => { + const repo = connection.getRepository(Test); + + await Promise.all([ + repo.save({ varcharField: 'ok', uuidField: '123e4567-e89b-12d3-a456-426614174000', intField: 4}), + repo.save({ varcharField: 'ok', uuidField: '123e4567-e89b-12d3-a456-426614174001', intField: 4}), + ]); + + const count = await repo.createQueryBuilder() + .from(Test, 'main') + .leftJoin(Test, 'self', 'self.intField = main.intField') + .getCount(); + + expect(count).to.be.equal(2); + }))); + + it("counting joined queries should handle ambiguous values", () => Promise.all(connections.map(async connection => { + const repo = connection.getRepository(AmbigiousPrimaryKey); + + await Promise.all([ + repo.save({ a: 'A', b: 'AAA' }), + repo.save({ a: 'AAA', b: 'A' }), + repo.save({ a: 'AA', b: 'AA' }), + repo.save({ a: 'BB', b: 'BB' }), + repo.save({ a: 'B', b: 'BBB' }), + repo.save({ a: 'BBB', b: 'B' }) + ]); + + const count = await repo.createQueryBuilder() + .from(AmbigiousPrimaryKey, 'main') + .leftJoin(AmbigiousPrimaryKey, 'self', 'self.a = main.a') + .getCount(); + + expect(count).to.be.equal(6, connection.name); + }))); + }); From 2ec1e11f31f3c86c93dec4906d3fc2aa433e4e01 Mon Sep 17 00:00:00 2001 From: Zhixing Zhang Date: Fri, 9 Oct 2020 04:00:26 -0400 Subject: [PATCH 125/212] docs: clarify how to query replicas in the documentation (#6173) --- docs/multiple-connections.md | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/docs/multiple-connections.md b/docs/multiple-connections.md index 21d021eb2a6..d0c2cc44b22 100644 --- a/docs/multiple-connections.md +++ b/docs/multiple-connections.md @@ -275,7 +275,8 @@ Example of replication connection settings: ``` All schema update and write operations are performed using `master` server. -All simple queries performed by find methods or select query builder are using a random `slave` instance. +All simple queries performed by find methods or select query builder are using a random `slave` instance. +All queries performed by query method are performed using the `master` instance. If you want to explicitly use master in SELECT created by query builder, you can use the following code: @@ -291,6 +292,18 @@ try { ``` +If you want to use `slave` in raw queries, you also need to explicitly specify the query runner. + +```typescript + +const slaveQueryRunner = connection.createQueryRunner("slave"); +try { + const userFromSlave = await connection.query('SELECT * FROM users WHERE id = $1', [userId], slaveQueryRunner); +} finally { + return slaveQueryRunner.release(); +} +``` + Note that connection created by a `QueryRunner` need to be explicitly released. Replication is supported by mysql, postgres and sql server databases. From ec9392222821e1fdd459f0b064b1631acf58a9d0 Mon Sep 17 00:00:00 2001 From: TJ Date: Fri, 9 Oct 2020 04:32:06 -0400 Subject: [PATCH 126/212] docs: adds note regarding dangerous findOne behavior (#4921) Calling `findOne(undefined)` or `findOne(null)` results in potentially unexpected and dangerous behavior. --- docs/repository-api.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/repository-api.md b/docs/repository-api.md index 22c84794bee..e77bb252668 100644 --- a/docs/repository-api.md +++ b/docs/repository-api.md @@ -235,6 +235,8 @@ const user = await repository.findOneOrFail(1); const timber = await repository.findOneOrFail({ firstName: "Timber" }); ``` +>Note: It is strongly recommended to ensure that your `id` or `FindOptions` value is not `null` or `undefined` before calling `findOne` and `findOneOrFail`. When passed `null` or `undefined`, the query will match with every entity in the repository and return the first record. + * `query` - Executes a raw SQL query. ```typescript From 54067be59d47ac26339bea2b59272cdfd9775816 Mon Sep 17 00:00:00 2001 From: James Ward Date: Fri, 9 Oct 2020 16:57:37 -0400 Subject: [PATCH 127/212] test: remove console logging from tests (#6880) we have a bunch of console loggers in our tests that cause extra output to be emitted when we don't need it. because these were for debugging & not part of the tests success this removes them --- .../modules/blog/subscriber/TestBlogSubscriber.ts | 6 +++--- .../modules/question/subscriber/TestQuestionSubscriber.ts | 6 +++--- .../modules/video/subscriber/TestVideoSubscriber.ts | 6 +++--- .../connection/subscriber/FirstConnectionSubscriber.ts | 6 +++--- .../connection/subscriber/SecondConnectionSubscriber.ts | 6 +++--- test/functional/migrations/generate-command/command.ts | 1 - .../custom-column-names/persistence-custom-column-names.ts | 3 +-- test/github-issues/2703/memory-logger.ts | 4 ---- 8 files changed, 16 insertions(+), 22 deletions(-) diff --git a/test/functional/connection/modules/blog/subscriber/TestBlogSubscriber.ts b/test/functional/connection/modules/blog/subscriber/TestBlogSubscriber.ts index f6a40b238c6..db6553da7bc 100644 --- a/test/functional/connection/modules/blog/subscriber/TestBlogSubscriber.ts +++ b/test/functional/connection/modules/blog/subscriber/TestBlogSubscriber.ts @@ -4,12 +4,12 @@ import {InsertEvent} from "../../../../../../src/subscriber/event/InsertEvent"; @EventSubscriber() export class TestBlogSubscriber implements EntitySubscriberInterface { - + /** * Called after entity insertion. */ beforeInsert(event: InsertEvent) { - console.log(`BEFORE ENTITY INSERTED: `, event.entity); + // Do nothing } -} \ No newline at end of file +} diff --git a/test/functional/connection/modules/question/subscriber/TestQuestionSubscriber.ts b/test/functional/connection/modules/question/subscriber/TestQuestionSubscriber.ts index d22940cbd4c..d9682c3b8b0 100644 --- a/test/functional/connection/modules/question/subscriber/TestQuestionSubscriber.ts +++ b/test/functional/connection/modules/question/subscriber/TestQuestionSubscriber.ts @@ -4,12 +4,12 @@ import {InsertEvent} from "../../../../../../src/subscriber/event/InsertEvent"; @EventSubscriber() export class TestQuestionSubscriber implements EntitySubscriberInterface { - + /** * Called before entity insertion. */ beforeInsert(event: InsertEvent) { - console.log(`BEFORE ENTITY INSERTED: `, event.entity); + // Do nothing } -} \ No newline at end of file +} diff --git a/test/functional/connection/modules/video/subscriber/TestVideoSubscriber.ts b/test/functional/connection/modules/video/subscriber/TestVideoSubscriber.ts index 58f66b5eb3b..e745ae03af3 100644 --- a/test/functional/connection/modules/video/subscriber/TestVideoSubscriber.ts +++ b/test/functional/connection/modules/video/subscriber/TestVideoSubscriber.ts @@ -4,12 +4,12 @@ import {InsertEvent} from "../../../../../../src/subscriber/event/InsertEvent"; @EventSubscriber() export class TestVideoSubscriber implements EntitySubscriberInterface { - + /** * Called after entity insertion. */ beforeInsert(event: InsertEvent) { - console.log(`BEFORE ENTITY INSERTED: `, event.entity); + // Do nothing } -} \ No newline at end of file +} diff --git a/test/functional/connection/subscriber/FirstConnectionSubscriber.ts b/test/functional/connection/subscriber/FirstConnectionSubscriber.ts index 2aefd827413..d47c31d3917 100644 --- a/test/functional/connection/subscriber/FirstConnectionSubscriber.ts +++ b/test/functional/connection/subscriber/FirstConnectionSubscriber.ts @@ -4,12 +4,12 @@ import {InsertEvent} from "../../../../src/subscriber/event/InsertEvent"; @EventSubscriber() export class FirstConnectionSubscriber implements EntitySubscriberInterface { - + /** * Called after entity insertion. */ beforeInsert(event: InsertEvent) { - console.log(`BEFORE ENTITY INSERTED: `, event.entity); + // Do nothing } -} \ No newline at end of file +} diff --git a/test/functional/connection/subscriber/SecondConnectionSubscriber.ts b/test/functional/connection/subscriber/SecondConnectionSubscriber.ts index 2ef4427b3a5..8046e640ff2 100644 --- a/test/functional/connection/subscriber/SecondConnectionSubscriber.ts +++ b/test/functional/connection/subscriber/SecondConnectionSubscriber.ts @@ -4,12 +4,12 @@ import {InsertEvent} from "../../../../src/subscriber/event/InsertEvent"; @EventSubscriber() export class SecondConnectionSubscriber implements EntitySubscriberInterface { - + /** * Called after entity insertion. */ beforeInsert(event: InsertEvent) { - console.log(`BEFORE ENTITY INSERTED: `, event.entity); + // Do nothing } -} \ No newline at end of file +} diff --git a/test/functional/migrations/generate-command/command.ts b/test/functional/migrations/generate-command/command.ts index 1c136334286..f23be595196 100644 --- a/test/functional/migrations/generate-command/command.ts +++ b/test/functional/migrations/generate-command/command.ts @@ -28,7 +28,6 @@ describe("migrations > generate command", () => { const sqlInMemory = await connection.driver.createSchemaBuilder().log(); - console.log(sqlInMemory.upQueries); sqlInMemory.upQueries.length.should.be.equal(0); sqlInMemory.downQueries.length.should.be.equal(0); diff --git a/test/functional/persistence/custom-column-names/persistence-custom-column-names.ts b/test/functional/persistence/custom-column-names/persistence-custom-column-names.ts index bc597c3e354..34805630878 100644 --- a/test/functional/persistence/custom-column-names/persistence-custom-column-names.ts +++ b/test/functional/persistence/custom-column-names/persistence-custom-column-names.ts @@ -34,7 +34,6 @@ describe("persistence > custom-column-names", function() { return connection .synchronize(true) .catch(e => { - console.log("Error during schema re-creation: ", e); throw e; }); } @@ -53,7 +52,7 @@ describe("persistence > custom-column-names", function() { // ------------------------------------------------------------------------- // Specifications // ------------------------------------------------------------------------- - + describe("attach exist entity to exist entity with many-to-one relation", function() { if (!connection) return; diff --git a/test/github-issues/2703/memory-logger.ts b/test/github-issues/2703/memory-logger.ts index 3ec36711fc2..3221760f9f8 100644 --- a/test/github-issues/2703/memory-logger.ts +++ b/test/github-issues/2703/memory-logger.ts @@ -22,10 +22,6 @@ export class MemoryLogger implements Logger { log(level: "log" | "info" | "warn", message: any) {} - writeToConsole() { - this.queries.forEach(q => console.log(`query: ${q}`)); - } - clear() { this._queries = []; } From 0aedf43874a6f950614134967bf4b173e4513ba0 Mon Sep 17 00:00:00 2001 From: Matt Kornatz Date: Sat, 10 Oct 2020 15:23:57 -0400 Subject: [PATCH 128/212] fix: Allows valid non-object JSON to be retrieved in simple-json columns (#6574) Fixes #5501 --- src/util/DateUtils.ts | 9 +- test/github-issues/4440/issue-4440.ts | 43 ------- .../{4440 => 5501}/entity/Post.ts | 1 - test/github-issues/5501/issue-5501.ts | 112 ++++++++++++++++++ 4 files changed, 114 insertions(+), 51 deletions(-) delete mode 100644 test/github-issues/4440/issue-4440.ts rename test/github-issues/{4440 => 5501}/entity/Post.ts (99%) create mode 100644 test/github-issues/5501/issue-5501.ts diff --git a/src/util/DateUtils.ts b/src/util/DateUtils.ts index dcc649d7662..8f3b99a02d5 100644 --- a/src/util/DateUtils.ts +++ b/src/util/DateUtils.ts @@ -1,4 +1,4 @@ -import {ColumnMetadata} from "../metadata/ColumnMetadata"; +import { ColumnMetadata } from "../metadata/ColumnMetadata"; /** * Provides utilities to transform hydrated and persisted data. @@ -175,12 +175,7 @@ export class DateUtils { } static stringToSimpleJson(value: any) { - try { - const simpleJSON = JSON.parse(value); - return (typeof simpleJSON === "object") ? simpleJSON : {}; - } catch (err) { - return {}; - } + return typeof value === "string" ? JSON.parse(value) : value; } static simpleEnumToString(value: any) { diff --git a/test/github-issues/4440/issue-4440.ts b/test/github-issues/4440/issue-4440.ts deleted file mode 100644 index e42ca2eb309..00000000000 --- a/test/github-issues/4440/issue-4440.ts +++ /dev/null @@ -1,43 +0,0 @@ -import "reflect-metadata"; -import { Connection } from "../../../src/connection/Connection"; -import { closeTestingConnections, createTestingConnections, reloadTestingDatabases } from "../../utils/test-utils"; -import { Post } from "./entity/Post"; - -describe("github issues > #4440 simple-json column type throws error for string with no value", () => { - - let connections: Connection[]; - before(async () => { - connections = await createTestingConnections({ - entities: [Post], - schemaCreate: true, - dropSchema: true - }); - }); - beforeEach(() => reloadTestingDatabases(connections)); - after(() => closeTestingConnections(connections)); - - it("should correctly add retrieve simple-json field with no value", () => - Promise.all(connections.map(async (connection) => { - const repo = connection.getRepository(Post); - const post = new Post(); - post.id = 1; - post.jsonField = ""; - await repo.save(post); - const postFound = await repo.findOne(1); - postFound!.id.should.eql(1); - postFound!.jsonField.should.eql({}); - }))); - - it("should correctly add retrieve simple-json field with some value", () => - Promise.all(connections.map(async (connection) => { - const repo = connection.getRepository(Post); - const post = new Post(); - post.id = 1; - post.jsonField = {"key": "value"}; - await repo.save(post); - const postFound = await repo.findOne(1); - postFound!.id.should.eql(1); - postFound!.jsonField.should.eql({"key": "value"}); - }))); - -}); diff --git a/test/github-issues/4440/entity/Post.ts b/test/github-issues/5501/entity/Post.ts similarity index 99% rename from test/github-issues/4440/entity/Post.ts rename to test/github-issues/5501/entity/Post.ts index 5220e523cd1..72dbebb2ff5 100644 --- a/test/github-issues/4440/entity/Post.ts +++ b/test/github-issues/5501/entity/Post.ts @@ -12,5 +12,4 @@ export class Post { nullable: true }) jsonField: any; - } diff --git a/test/github-issues/5501/issue-5501.ts b/test/github-issues/5501/issue-5501.ts new file mode 100644 index 00000000000..b5b0c3cb11c --- /dev/null +++ b/test/github-issues/5501/issue-5501.ts @@ -0,0 +1,112 @@ +import "reflect-metadata"; +import { Connection } from "../../../src/connection/Connection"; +import { closeTestingConnections, createTestingConnections, reloadTestingDatabases } from "../../utils/test-utils"; +import { Post } from "./entity/Post"; +import { expect } from "chai"; + +describe("github issues > #5501 Incorrect data loading from JSON string for column type 'simple-json'", () => { + + let connections: Connection[]; + before(async () => { + connections = await createTestingConnections({ + entities: [Post], + schemaCreate: true, + dropSchema: true + }); + }); + beforeEach(() => reloadTestingDatabases(connections)); + after(() => closeTestingConnections(connections)); + + it("should correctly store simple-json field", () => Promise.all(connections.map(async (connection) => { + let id = 0; + const runTestCase = async (input: any, expected: any, message: string) => { + id++; + + await connection.getRepository(Post).save({ id , jsonField: input }); + + const actual = ( + await connection.createQueryBuilder() + .from("Post", "post") + .select("post.jsonField", "json") + .where("post.id = :id", {id}) + .getRawOne() + )!.json; + + expect(actual).to.be.equal(expected, message); + } + + await runTestCase("hello world", "\"hello world\"", "normal string"); + await runTestCase("", "\"\"", "empty string"); + await runTestCase("null", "\"null\"", "string containing the word null"); + await runTestCase( { "key": "value" }, "{\"key\":\"value\"}", "object containing a key and string value"); + await runTestCase([ "hello" ], "[\"hello\"]", "array containing a string"); + await runTestCase(null, null, "a null object value"); + await runTestCase(1, "1", "the real number 1"); + await runTestCase(0.3, "0.3", "the number 0.3"); + await runTestCase(true, "true", "the boolean value true"); + await runTestCase( + [ { hello: "earth", planet: true }, { hello: "moon", planet: false } ], + "[{\"hello\":\"earth\",\"planet\":true},{\"hello\":\"moon\",\"planet\":false}]", + "a complex object example" + ); + }))); + + it("should correctly retrieve simple-json field", () => Promise.all(connections.map(async (connection) => { + let id = 0; + const runTestCase = async (input: string | null, expected: any, message: string) => { + id++; + await connection.createQueryBuilder() + .insert() + .into(Post) + .values({id, jsonField: () => ':field'} as any) // A bit of a hack to get the raw value inserting + .setParameter('field', input) + .execute(); + + const actual = ( + await connection.getRepository(Post).findOne({ where: { id } }) + )!.jsonField; + + expect(actual).to.be.eql(expected, message); + } + + await runTestCase("\"hello world\"", "hello world", "normal string"); + await runTestCase("\"\"", "", "empty string"); + await runTestCase("\"null\"", "null", "string containing the word null"); + await runTestCase("{\"key\":\"value\"}", { "key": "value" }, "object containing a key and string value"); + await runTestCase("[\"hello\"]", [ "hello" ], "array containing a string"); + await runTestCase(null, null, "a null object value");; + await runTestCase("1", 1, "the real number 1"); + await runTestCase("0.3", 0.3, "the number 0.3"); + await runTestCase("true", true, "the boolean value true"); + await runTestCase( + "[{\"hello\":\"earth\",\"planet\":true},{\"hello\":\"moon\",\"planet\":false}]", + [{"hello":"earth","planet":true},{"hello":"moon","planet":false}], + "a complex object example" + ); + }))); + + it("should throw an error when the data in the database is invalid", () => Promise.all(connections.map(async (connection) => { + const insert = (id: number, value: string | null) => + connection.createQueryBuilder() + .insert() + .into(Post) + .values({ id, jsonField: () => ':field' } as any) // A bit of a hack to get the raw value inserting + .setParameter('field', value) + .execute() + + // This was the likely data within the database in #4440 + // This will happen if you've tried to manually insert the data in ways where + // we aren't expecting you to - like switching the column type to a text & + // trying to push a value into it that is an object. + await insert(1, "[object Object]"); + + const repo = connection.getRepository(Post); + + const getJson = async (id: number) => + ( + await repo.findOne({ where: { id } }) + )!.jsonField; + + await expect(getJson(1)).to.be.rejected; + }))); +}); From 3e8ddca19f4815e9cd279e0e64d25c2d5394bee2 Mon Sep 17 00:00:00 2001 From: Marko Kaznovac Date: Sat, 10 Oct 2020 23:29:00 +0200 Subject: [PATCH 129/212] test: multiple primary keys many-to-many can fail with 'Specified key was too long' (#5925) --- .../entity/Category.ts | 10 +++++++--- .../multiple-primary-keys-many-to-many/entity/Tag.ts | 10 +++++++--- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/test/functional/relations/multiple-primary-keys/multiple-primary-keys-many-to-many/entity/Category.ts b/test/functional/relations/multiple-primary-keys/multiple-primary-keys-many-to-many/entity/Category.ts index f07912c2c51..c973f4cbc51 100644 --- a/test/functional/relations/multiple-primary-keys/multiple-primary-keys-many-to-many/entity/Category.ts +++ b/test/functional/relations/multiple-primary-keys/multiple-primary-keys-many-to-many/entity/Category.ts @@ -10,10 +10,14 @@ import {Unique} from "../../../../../../src"; @Unique(["code", "version", "description"]) export class Category { - @PrimaryColumn() + @PrimaryColumn("varchar", { + length: 31, + }) name: string; - @PrimaryColumn() + @PrimaryColumn("varchar", { + length: 31, + }) type: string; @Column() @@ -43,4 +47,4 @@ export class Category { @ManyToMany(type => Tag, tag => tag.categoriesWithNonPKColumns) tagsWithNonPKColumns: Tag[]; -} \ No newline at end of file +} diff --git a/test/functional/relations/multiple-primary-keys/multiple-primary-keys-many-to-many/entity/Tag.ts b/test/functional/relations/multiple-primary-keys/multiple-primary-keys-many-to-many/entity/Tag.ts index 71453dbc5b8..fcb9c5436d7 100644 --- a/test/functional/relations/multiple-primary-keys/multiple-primary-keys-many-to-many/entity/Tag.ts +++ b/test/functional/relations/multiple-primary-keys/multiple-primary-keys-many-to-many/entity/Tag.ts @@ -11,10 +11,14 @@ export class Tag { @Column() code: number; - @PrimaryColumn() + @PrimaryColumn("varchar", { + length: 31, + }) title: string; - @PrimaryColumn() + @PrimaryColumn("varchar", { + length: 31, + }) description: string; @ManyToMany(type => Category, category => category.tags) @@ -64,4 +68,4 @@ export class Tag { }) categoriesWithNonPKColumns: Category[]; -} \ No newline at end of file +} From 6ff67f71fa7ad2bcf8a89c01ead7f54386e35f3a Mon Sep 17 00:00:00 2001 From: jeiea Date: Mon, 12 Oct 2020 08:21:35 +0900 Subject: [PATCH 130/212] fix: redundant migration with decimal default (#6879) MySQL/MariaDB decimal column is represented like '0.0'. MysqlDriver.normalizeDefault didn't consider trailing zeros. User can bypass this by passing default as string, but we can't guide the zeros by type, so we should convert user input. undefined scale was compared with defined scale. Skip this comparison. Close #6140 Close #5407 --- src/driver/cockroachdb/CockroachDriver.ts | 4 +- .../cockroachdb/CockroachQueryRunner.ts | 1 + src/driver/mysql/MysqlDriver.ts | 6 +-- src/driver/postgres/PostgresDriver.ts | 8 ++-- src/driver/postgres/PostgresQueryRunner.ts | 1 + test/github-issues/5407/entity/User.ts | 41 +++++++++++++++++++ test/github-issues/5407/issue-5407.ts | 30 ++++++++++++++ 7 files changed, 82 insertions(+), 9 deletions(-) create mode 100644 test/github-issues/5407/entity/User.ts create mode 100644 test/github-issues/5407/issue-5407.ts diff --git a/src/driver/cockroachdb/CockroachDriver.ts b/src/driver/cockroachdb/CockroachDriver.ts index b1e0f06e3b2..11ab71ae13c 100644 --- a/src/driver/cockroachdb/CockroachDriver.ts +++ b/src/driver/cockroachdb/CockroachDriver.ts @@ -484,7 +484,7 @@ export class CockroachDriver implements Driver { const arrayCast = columnMetadata.isArray ? `::${columnMetadata.type}[]` : ""; if (typeof defaultValue === "number") { - return "" + defaultValue; + return `(${defaultValue})`; } else if (typeof defaultValue === "boolean") { return defaultValue === true ? "true" : "false"; @@ -618,7 +618,7 @@ export class CockroachDriver implements Driver { || tableColumn.type !== this.normalizeType(columnMetadata) || tableColumn.length !== columnMetadata.length || tableColumn.precision !== columnMetadata.precision - || tableColumn.scale !== columnMetadata.scale + || (columnMetadata.scale !== undefined && tableColumn.scale !== columnMetadata.scale) // || tableColumn.comment !== columnMetadata.comment // todo || (!tableColumn.isGenerated && this.lowerDefaultValueIfNecessary(this.normalizeDefault(columnMetadata)) !== tableColumn.default) // we included check for generated here, because generated columns already can have default values || tableColumn.isPrimary !== columnMetadata.isPrimary diff --git a/src/driver/cockroachdb/CockroachQueryRunner.ts b/src/driver/cockroachdb/CockroachQueryRunner.ts index eeb97d510c5..80c1b2663ff 100644 --- a/src/driver/cockroachdb/CockroachQueryRunner.ts +++ b/src/driver/cockroachdb/CockroachQueryRunner.ts @@ -1492,6 +1492,7 @@ export class CockroachQueryRunner extends BaseQueryRunner implements QueryRunner } else { tableColumn.default = dbColumn["column_default"].replace(/:::.*/, ""); + tableColumn.default = tableColumn.default.replace(/^(-?[\d\.]+)$/, "($1)"); } } diff --git a/src/driver/mysql/MysqlDriver.ts b/src/driver/mysql/MysqlDriver.ts index 4eb1e5644bc..6d7f3180723 100644 --- a/src/driver/mysql/MysqlDriver.ts +++ b/src/driver/mysql/MysqlDriver.ts @@ -591,7 +591,7 @@ export class MysqlDriver implements Driver { } if (typeof defaultValue === "number") { - return "" + defaultValue; + return `'${defaultValue.toFixed(columnMetadata.scale)}'`; } else if (typeof defaultValue === "boolean") { return defaultValue === true ? "1" : "0"; @@ -770,8 +770,8 @@ export class MysqlDriver implements Driver { || tableColumn.type !== this.normalizeType(columnMetadata) || tableColumn.length !== columnMetadataLength || tableColumn.width !== columnMetadata.width - || tableColumn.precision !== columnMetadata.precision - || tableColumn.scale !== columnMetadata.scale + || (columnMetadata.precision !== undefined && tableColumn.precision !== columnMetadata.precision) + || (columnMetadata.scale !== undefined && tableColumn.scale !== columnMetadata.scale) || tableColumn.zerofill !== columnMetadata.zerofill || tableColumn.unsigned !== columnMetadata.unsigned || tableColumn.asExpression !== columnMetadata.asExpression diff --git a/src/driver/postgres/PostgresDriver.ts b/src/driver/postgres/PostgresDriver.ts index 2b8c0f02ee3..f7b6adb8f66 100644 --- a/src/driver/postgres/PostgresDriver.ts +++ b/src/driver/postgres/PostgresDriver.ts @@ -393,7 +393,7 @@ export class PostgresDriver implements Driver { return metadata.columns.filter(column => this.spatialTypes.indexOf(column.type) >= 0).length > 0; }); const hasLtreeColumns = this.connection.entityMetadatas.some(metadata => { - return metadata.columns.filter(column => column.type === 'ltree').length > 0; + return metadata.columns.filter(column => column.type === "ltree").length > 0; }); const hasExclusionConstraints = this.connection.entityMetadatas.some(metadata => { return metadata.exclusions.length > 0; @@ -498,7 +498,7 @@ export class PostgresDriver implements Driver { return `(${value.join(",")})`; } else if (columnMetadata.type === "ltree") { - return value.split(".").filter(Boolean).join('.').replace(/[\s]+/g, "_"); + return value.split(".").filter(Boolean).join(".").replace(/[\s]+/g, "_"); } else if ( ( columnMetadata.type === "enum" @@ -734,7 +734,7 @@ export class PostgresDriver implements Driver { } if (typeof defaultValue === "number") { - return "" + defaultValue; + return `'${defaultValue}'`; } else if (typeof defaultValue === "boolean") { return defaultValue === true ? "true" : "false"; @@ -874,7 +874,7 @@ export class PostgresDriver implements Driver { || tableColumn.type !== this.normalizeType(columnMetadata) || tableColumn.length !== columnMetadata.length || tableColumn.precision !== columnMetadata.precision - || tableColumn.scale !== columnMetadata.scale + || (columnMetadata.scale !== undefined && tableColumn.scale !== columnMetadata.scale) // || tableColumn.comment !== columnMetadata.comment // todo || (!tableColumn.isGenerated && this.lowerDefaultValueIfNecessary(this.normalizeDefault(columnMetadata)) !== tableColumn.default) // we included check for generated here, because generated columns already can have default values || tableColumn.isPrimary !== columnMetadata.isPrimary diff --git a/src/driver/postgres/PostgresQueryRunner.ts b/src/driver/postgres/PostgresQueryRunner.ts index ae94bd8bb7e..d1996a97c28 100644 --- a/src/driver/postgres/PostgresQueryRunner.ts +++ b/src/driver/postgres/PostgresQueryRunner.ts @@ -1589,6 +1589,7 @@ export class PostgresQueryRunner extends BaseQueryRunner implements QueryRunner tableColumn.generationStrategy = "uuid"; } else { tableColumn.default = dbColumn["column_default"].replace(/::.*/, ""); + tableColumn.default = tableColumn.default.replace(/^(-?\d+)$/, "'$1'"); } } diff --git a/test/github-issues/5407/entity/User.ts b/test/github-issues/5407/entity/User.ts new file mode 100644 index 00000000000..61bd4e6ab3b --- /dev/null +++ b/test/github-issues/5407/entity/User.ts @@ -0,0 +1,41 @@ +import {PrimaryColumn, Column} from "../../../../src"; +import {Entity} from "../../../../src/decorator/entity/Entity"; + +@Entity() +export class User { + + @PrimaryColumn() + id: number; + + @Column("decimal", { default: -0, precision: 3, scale: 1 }) + decimalWithDefault: number; + + @Column("decimal", { default: 100, precision: 3 }) + noScale: number; + + @Column("decimal", { default: 10, precision: 3, scale: 0 }) + zeroScale: number; + + @Column("decimal", { default: 9999999999 }) + maxDefault: number; + + @Column("decimal", { default: -9999999999 }) + minDefault: number; + + @Column("int", { default: -100 }) + intDefault: number; + + @Column("float", { default: 3.5 }) + floatDefault: number; + + @Column({ default: "New user" }) + stringDefault: string; + + // ER_PARSE_ERROR + // @Column("decimal", { default: 0, precision: 8, scale: -4 }) + // negativeScale: number; + + // ER_INVALID_DEFAULT + // @Column("decimal", { default: -12345.67890, precision: 8, scale: 4 }) + // defaultOverflow: number; +} diff --git a/test/github-issues/5407/issue-5407.ts b/test/github-issues/5407/issue-5407.ts new file mode 100644 index 00000000000..3bb05278f72 --- /dev/null +++ b/test/github-issues/5407/issue-5407.ts @@ -0,0 +1,30 @@ +import "reflect-metadata"; +import {Connection} from "../../../src"; +import {createTestingConnections, closeTestingConnections} from "../../utils/test-utils"; +import {User} from "./entity/User"; + +describe("github issues > #5407 Wrong migration created because of default column value format", () => { + let connections: Connection[]; + before(async () => connections = await createTestingConnections({ + migrations: [], + enabledDrivers: ["mysql", "mariadb", "postgres", "better-sqlite3", "cockroachdb", "sqlite"], + schemaCreate: false, + dropSchema: true, + entities: [User], + })); + after(() => closeTestingConnections(connections)); + + it("can recognize model changes", () => Promise.all(connections.map(async connection => { + const sqlInMemory = await connection.driver.createSchemaBuilder().log(); + sqlInMemory.upQueries.length.should.be.greaterThan(0); + sqlInMemory.downQueries.length.should.be.greaterThan(0); + }))); + + it("does not generate when no model changes", () => Promise.all(connections.map(async connection => { + await connection.driver.createSchemaBuilder().build(); + + const sqlInMemory = await connection.driver.createSchemaBuilder().log(); + sqlInMemory.upQueries.length.should.be.equal(0); + sqlInMemory.downQueries.length.should.be.equal(0); + }))); +}); From 68bb9dcc9f55e4ba2128470c5f7c9cf7b534545e Mon Sep 17 00:00:00 2001 From: Ophir LOJKINE Date: Mon, 12 Oct 2020 20:13:47 +0200 Subject: [PATCH 131/212] chore: Update link to sql.js (#6895) --- docs/supported-platforms.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/supported-platforms.md b/docs/supported-platforms.md index ec817e6e843..df850cbeb4d 100644 --- a/docs/supported-platforms.md +++ b/docs/supported-platforms.md @@ -13,7 +13,7 @@ TypeORM was tested on Node.js version 4 and above. ## Browser -You can use [sql.js](https://github.com/kripken/sql.js) in the browser. +You can use [sql.js](https://sql.js.org) in the browser. **Webpack configuration** From e08d9c61aab72f16ecd8bd790cb32bf0d164a5af Mon Sep 17 00:00:00 2001 From: maayanbar13 Date: Mon, 12 Oct 2020 21:55:07 +0300 Subject: [PATCH 132/212] fix: resolves issue proto-less object validation (#6884) Due to `instanceof` comparison, object without prototype is mistaken for a privative value, throwing `TypeError: Cannot convert object to primitive value.` when trying to `.toString` said object (inside template string). This mostly effects usage with `graphql` as `graphql-js`, [by design](https://github.com/graphql/graphql-js/pull/504), creates objects by using Object.create(null). This fix allows saving these objects. The fix uses `typeof` instead of `toString` comparison since I see no reason why `new Number/Boolean/Date` should be a supported use case. Closes: #2065 --- src/persistence/EntityPersistExecutor.ts | 2 +- test/github-issues/2065/entity/Post.ts | 17 +++++++++++++++++ test/github-issues/2065/issue-2065.ts | 23 +++++++++++++++++++++++ 3 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 test/github-issues/2065/entity/Post.ts create mode 100644 test/github-issues/2065/issue-2065.ts diff --git a/src/persistence/EntityPersistExecutor.ts b/src/persistence/EntityPersistExecutor.ts index 940e2f88ab0..bc8f0ae2ce0 100644 --- a/src/persistence/EntityPersistExecutor.ts +++ b/src/persistence/EntityPersistExecutor.ts @@ -41,7 +41,7 @@ export class EntityPersistExecutor { execute(): Promise { // check if entity we are going to save is valid and is an object - if (!this.entity || !(this.entity instanceof Object)) + if (!this.entity || typeof this.entity !== "object") return Promise.reject(new MustBeEntityError(this.mode, this.entity)); // we MUST call "fake" resolve here to make sure all properties of lazily loaded relations are resolved diff --git a/test/github-issues/2065/entity/Post.ts b/test/github-issues/2065/entity/Post.ts new file mode 100644 index 00000000000..4d4a12218a6 --- /dev/null +++ b/test/github-issues/2065/entity/Post.ts @@ -0,0 +1,17 @@ +import { Entity, PrimaryColumn, Column } from "../../../../src"; + +@Entity() +export class Post { + + @PrimaryColumn() + id: number; + + @Column() + title: string; + + constructor(id: number, title: string) { + this.id = id; + this.title = title; + } + +} diff --git a/test/github-issues/2065/issue-2065.ts b/test/github-issues/2065/issue-2065.ts new file mode 100644 index 00000000000..0ae582edfd2 --- /dev/null +++ b/test/github-issues/2065/issue-2065.ts @@ -0,0 +1,23 @@ +import "reflect-metadata"; +import {createTestingConnections, closeTestingConnections, reloadTestingDatabases} from "../../utils/test-utils"; +import {Connection} from "../../../src/connection/Connection"; +import {Post} from "./entity/Post"; + +describe("github issues > #2065 TypeError: Cannot convert object to primitive value", () => { + + let connections: Connection[]; + before(async () => connections = await createTestingConnections({ + entities: [__dirname + "/entity/*{.js,.ts}"], + schemaCreate: true, + dropSchema: true, + })); + beforeEach(() => reloadTestingDatabases(connections)); + after(() => closeTestingConnections(connections)); + + it("should save an entity created with Object.create(null)", () => Promise.all(connections.map(async connection => { + const post = Object.create(null) as Post; + post.id = 1; + post.title = "Hello Post"; + await connection.manager.save(Post, post); + }))); +}); From c72e48b9c7b893f8a2483ba1ddaa7ded039fe349 Mon Sep 17 00:00:00 2001 From: James Ward Date: Tue, 13 Oct 2020 00:07:14 -0400 Subject: [PATCH 133/212] fix: sync the typeorm-model-shim (#6891) this updates the shim to include all current decorators exported from index.ts - adding @Unique and a few others fixes: #6288 fixes: #5920 --- extra/typeorm-model-shim.js | 273 +++++++++++++++++++----------------- 1 file changed, 145 insertions(+), 128 deletions(-) diff --git a/extra/typeorm-model-shim.js b/extra/typeorm-model-shim.js index e3a297be3de..ff69bc08979 100644 --- a/extra/typeorm-model-shim.js +++ b/extra/typeorm-model-shim.js @@ -21,230 +21,247 @@ // } -// columns - -/* export */ function Column(typeOrOptions, options) { - return function (object, propertyName) { - }; +/* export */ function Column() { + return function () {}; } exports.Column = Column; -/* export */ function ViewColumn(typeOrOptions, options) { - return function (object, propertyName) { - }; +/* export */ function CreateDateColumn() { + return function () {}; } -exports.ViewColumn = ViewColumn; +exports.CreateDateColumn = CreateDateColumn; -/* export */ function DeleteDateColumn(options) { - return function (object, propertyName) { - }; +/* export */ function DeleteDateColumn() { + return function () {}; } exports.DeleteDateColumn = DeleteDateColumn; -/* export */ function CreateDateColumn(options) { - return function (object, propertyName) { - }; -} -exports.CreateDateColumn = CreateDateColumn; - -/* export */ function ObjectIdColumn(columnOptions) { - return function (object, propertyName) { - }; +/* export */ function PrimaryGeneratedColumn() { + return function () {}; } -exports.ObjectIdColumn = ObjectIdColumn; +exports.PrimaryGeneratedColumn = PrimaryGeneratedColumn; -/* export */ function PrimaryColumn(typeOrOptions, options) { - return function (object, propertyName) { - }; +/* export */ function PrimaryColumn() { + return function () {}; } exports.PrimaryColumn = PrimaryColumn; -/* export */ function PrimaryGeneratedColumn(options) { - return function (object, propertyName) { - }; -} -exports.PrimaryGeneratedColumn = PrimaryGeneratedColumn; - -/* export */ function UpdateDateColumn(options) { - return function (object, propertyName) { - }; +/* export */ function UpdateDateColumn() { + return function () {}; } exports.UpdateDateColumn = UpdateDateColumn; -/* export */ function VersionColumn(options) { - return function (object, propertyName) { - }; +/* export */ function VersionColumn() { + return function () {}; } exports.VersionColumn = VersionColumn; -// entities - -/* export */ function ChildEntity(tableName, options) { - return function (object) { - }; -} -exports.ChildEntity = ChildEntity; - -/* export */ function Entity(name, options) { - return function (object) { - }; -} -exports.Entity = Entity; - -/* export */ function ViewEntity(name, options) { - return function (object) { - }; +/* export */ function ViewColumn() { + return function () {}; } -exports.ViewEntity = ViewEntity; +exports.ViewColumn = ViewColumn; -/* export */ function TableInheritance(type) { - return function (object) { - }; +/* export */ function ObjectIdColumn() { + return function () {}; } -exports.TableInheritance = TableInheritance; - -// listeners +exports.ObjectIdColumn = ObjectIdColumn; /* export */ function AfterInsert() { - return function (object, propertyName) { - }; + return function () {}; } exports.AfterInsert = AfterInsert; /* export */ function AfterLoad() { - return function (object, propertyName) { - }; + return function () {}; } exports.AfterLoad = AfterLoad; /* export */ function AfterRemove() { - return function (object, propertyName) { - }; + return function () {}; } exports.AfterRemove = AfterRemove; /* export */ function AfterUpdate() { - return function (object, propertyName) { - }; + return function () {}; } exports.AfterUpdate = AfterUpdate; /* export */ function BeforeInsert() { - return function (object, propertyName) { - }; + return function () {}; } exports.BeforeInsert = BeforeInsert; /* export */ function BeforeRemove() { - return function (object, propertyName) { - }; + return function () {}; } exports.BeforeRemove = BeforeRemove; /* export */ function BeforeUpdate() { - return function (object, propertyName) { - }; + return function () {}; } exports.BeforeUpdate = BeforeUpdate; /* export */ function EventSubscriber() { - return function (object, propertyName) { - }; + return function () {}; } exports.EventSubscriber = EventSubscriber; -// relations +/* export */ function ColumnOptions() { + return function () {}; +} +exports.ColumnOptions = ColumnOptions; + +/* export */ function IndexOptions() { + return function () {}; +} +exports.IndexOptions = IndexOptions; + +/* export */ function JoinColumnOptions() { + return function () {}; +} +exports.JoinColumnOptions = JoinColumnOptions; + +/* export */ function JoinTableOptions() { + return function () {}; +} +exports.JoinTableOptions = JoinTableOptions; + +/* export */ function RelationOptions() { + return function () {}; +} +exports.RelationOptions = RelationOptions; + +/* export */ function EntityOptions() { + return function () {}; +} +exports.EntityOptions = EntityOptions; + +/* export */ function ValueTransformer() { + return function () {}; +} +exports.ValueTransformer = ValueTransformer; -/* export */ function JoinColumn(options) { - return function (object, propertyName) { - }; +/* export */ function JoinColumn() { + return function () {}; } exports.JoinColumn = JoinColumn; -/* export */ function JoinTable(options) { - return function (object, propertyName) { - }; +/* export */ function JoinTable() { + return function () {}; } exports.JoinTable = JoinTable; -/* export */ function ManyToMany(typeFunction, inverseSideOrOptions, options) { - return function (object, propertyName) { - }; +/* export */ function ManyToMany() { + return function () {}; } exports.ManyToMany = ManyToMany; -/* export */ function ManyToOne(typeFunction, inverseSideOrOptions, options) { - return function (object, propertyName) { - }; +/* export */ function ManyToOne() { + return function () {}; } exports.ManyToOne = ManyToOne; -/* export */ function OneToMany(typeFunction, inverseSideOrOptions, options) { - return function (object, propertyName) { - }; +/* export */ function OneToMany() { + return function () {}; } exports.OneToMany = OneToMany; -/* export */ function OneToOne(typeFunction, inverseSideOrOptions, options) { - return function (object, propertyName) { - }; +/* export */ function OneToOne() { + return function () {}; } exports.OneToOne = OneToOne; -/* export */ function RelationCount(relation) { - return function (object, propertyName) { - }; +/* export */ function RelationCount() { + return function () {}; } exports.RelationCount = RelationCount; -/* export */ function RelationId(relation) { - return function (object, propertyName) { - }; +/* export */ function RelationId() { + return function () {}; } exports.RelationId = RelationId; -// tree +/* export */ function Entity() { + return function () {}; +} +exports.Entity = Entity; -/* export */ function Tree(name, options) { - return function (object) { - }; +/* export */ function ChildEntity() { + return function () {}; } -exports.Tree = Tree; +exports.ChildEntity = ChildEntity; -/* export */ function TreeChildren(options) { - return function (object, propertyName) { - }; +/* export */ function TableInheritance() { + return function () {}; } -exports.TreeChildren = TreeChildren; +exports.TableInheritance = TableInheritance; + +/* export */ function ViewEntity() { + return function () {}; +} +exports.ViewEntity = ViewEntity; + +/* export */ function Transaction() { + return function () {}; +} +exports.Transaction = Transaction; + +/* export */ function TransactionManager() { + return function () {}; +} +exports.TransactionManager = TransactionManager; -/* export */ function TreeChildrenCount(options) { - return function (object, propertyName) { - }; +/* export */ function TransactionRepository() { + return function () {}; } -exports.TreeChildrenCount = TreeChildrenCount; +exports.TransactionRepository = TransactionRepository; /* export */ function TreeLevelColumn() { - return function (object, propertyName) { - }; + return function () {}; } exports.TreeLevelColumn = TreeLevelColumn; -/* export */ function TreeParent(options) { - return function (object, propertyName) { - }; +/* export */ function TreeParent() { + return function () {}; } exports.TreeParent = TreeParent; -// other +/* export */ function TreeChildren() { + return function () {}; +} +exports.TreeChildren = TreeChildren; -/* export */ function Generated(options) { - return function (object, propertyName) { - }; +/* export */ function Tree() { + return function () {}; } -exports.Generated = Generated; +exports.Tree = Tree; -/* export */ function Index(options) { - return function (object, propertyName) { - }; +/* export */ function Index() { + return function () {}; } exports.Index = Index; + +/* export */ function Unique() { + return function () {}; +} +exports.Unique = Unique; + +/* export */ function Check() { + return function () {}; +} +exports.Check = Check; + +/* export */ function Exclusion() { + return function () {}; +} +exports.Exclusion = Exclusion; + +/* export */ function Generated() { + return function () {}; +} +exports.Generated = Generated; + +/* export */ function EntityRepository() { + return function () {}; +} +exports.EntityRepository = EntityRepository; From 1ed7f50b88eba728db20ae14a6b3649c82195f30 Mon Sep 17 00:00:00 2001 From: James Ward Date: Tue, 13 Oct 2020 00:01:33 -0400 Subject: [PATCH 134/212] test: remove logging from migration functional test --- test/functional/migrations/generate-command/command.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/test/functional/migrations/generate-command/command.ts b/test/functional/migrations/generate-command/command.ts index f23be595196..491dfd7a4b3 100644 --- a/test/functional/migrations/generate-command/command.ts +++ b/test/functional/migrations/generate-command/command.ts @@ -11,7 +11,6 @@ describe("migrations > generate command", () => { schemaCreate: false, dropSchema: true, entities: [Post, Category], - logging: true, schema: "public", })); // beforeEach(() => reloadTestingDatabases(connections)); From 4475d8067592b91b857f2b456dc31c5850a21081 Mon Sep 17 00:00:00 2001 From: James Ward Date: Wed, 14 Oct 2020 14:07:25 -0400 Subject: [PATCH 135/212] fix: explicitly define `query` command's param (#6899) the CLI command `query` had an implicit `query` positional parameter and in earlier versions of yargs that was okay - but in the later versions aiming for more correct code they've refactored it to not support that explicitly define the `query` positional parameter & add a helpful description so people can tell what it is for fixes #6896 --- src/commands/QueryCommand.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/commands/QueryCommand.ts b/src/commands/QueryCommand.ts index 3d705b9399f..1834c3646f4 100644 --- a/src/commands/QueryCommand.ts +++ b/src/commands/QueryCommand.ts @@ -10,11 +10,15 @@ import chalk from "chalk"; * Executes an sql query on the given connection. */ export class QueryCommand implements yargs.CommandModule { - command = "query"; + command = "query [query]"; describe = "Executes given SQL query on a default connection. Specify connection name to run query on a specific connection."; builder(args: yargs.Argv) { return args + .positional("query", { + describe: "The SQL Query to run", + type: "string" + }) .option("c", { alias: "connection", default: "default", From 84c18a9cab2e87b28eb046b5688bfca4d3ce9da6 Mon Sep 17 00:00:00 2001 From: James Ward Date: Thu, 15 Oct 2020 04:15:44 -0400 Subject: [PATCH 136/212] feat: support query comments in the query builder (#6892) add a `comment` method to the QueryBuilder so we can include an arbitrary comment in our queries for a variety of purposes - from query plan stability to SQL reverse proxy routing, to debugging. the comment builder is supported in selects, inserts, deletes, and updates this is directly inspired by the functionality supported by hibernate to handle SQL Query comments it uses C-style queries which are ANSI SQL 2003 & supported in all of the dialects of SQL that we support as drivers fixes #3643 --- src/query-builder/DeleteQueryBuilder.ts | 3 +- src/query-builder/InsertQueryBuilder.ts | 3 +- src/query-builder/QueryBuilder.ts | 23 +++++ src/query-builder/QueryExpressionMap.ts | 5 ++ src/query-builder/SelectQueryBuilder.ts | 3 +- src/query-builder/UpdateQueryBuilder.ts | 3 +- .../query-builder/comment/entity/Test.ts | 10 +++ .../comment/query-builder-comment.ts | 85 +++++++++++++++++++ 8 files changed, 131 insertions(+), 4 deletions(-) create mode 100644 test/functional/query-builder/comment/entity/Test.ts create mode 100644 test/functional/query-builder/comment/query-builder-comment.ts diff --git a/src/query-builder/DeleteQueryBuilder.ts b/src/query-builder/DeleteQueryBuilder.ts index c4c1358d163..1840a487280 100644 --- a/src/query-builder/DeleteQueryBuilder.ts +++ b/src/query-builder/DeleteQueryBuilder.ts @@ -40,7 +40,8 @@ export class DeleteQueryBuilder extends QueryBuilder implements * Gets generated sql query without parameters being replaced. */ getQuery(): string { - let sql = this.createDeleteExpression(); + let sql = this.createComment(); + sql += this.createDeleteExpression(); return sql.trim(); } diff --git a/src/query-builder/InsertQueryBuilder.ts b/src/query-builder/InsertQueryBuilder.ts index 8192293f627..4d63755fcd4 100644 --- a/src/query-builder/InsertQueryBuilder.ts +++ b/src/query-builder/InsertQueryBuilder.ts @@ -33,7 +33,8 @@ export class InsertQueryBuilder extends QueryBuilder { * Gets generated sql query without parameters being replaced. */ getQuery(): string { - let sql = this.createInsertExpression(); + let sql = this.createComment(); + sql += this.createInsertExpression(); return sql.trim(); } diff --git a/src/query-builder/QueryBuilder.ts b/src/query-builder/QueryBuilder.ts index 1b1d8ef0d56..7d8ddc8727c 100644 --- a/src/query-builder/QueryBuilder.ts +++ b/src/query-builder/QueryBuilder.ts @@ -446,6 +446,16 @@ export abstract class QueryBuilder { return new (this.constructor as any)(this); } + /** + * Includes a Query comment in the query builder. This is helpful for debugging purposes, + * such as finding a specific query in the database server's logs, or for categorization using + * an APM product. + */ + comment(comment: string): this { + this.expressionMap.comment = comment; + return this; + } + /** * Disables escaping. */ @@ -613,6 +623,19 @@ export abstract class QueryBuilder { return statement; } + protected createComment(): string { + if (!this.expressionMap.comment) { + return ""; + } + + // ANSI SQL 2003 support C style comments - comments that start with `/*` and end with `*/` + // In some dialects query nesting is available - but not all. Because of this, we'll need + // to scrub "ending" characters from the SQL but otherwise we can leave everything else + // as-is and it should be valid. + + return `/* ${this.expressionMap.comment.replace("*/", "")} */ `; + } + /** * Creates "WHERE" expression. */ diff --git a/src/query-builder/QueryExpressionMap.ts b/src/query-builder/QueryExpressionMap.ts index e4c638888a9..42f1f61642b 100644 --- a/src/query-builder/QueryExpressionMap.ts +++ b/src/query-builder/QueryExpressionMap.ts @@ -271,6 +271,11 @@ export class QueryExpressionMap { */ nativeParameters: ObjectLiteral = {}; + /** + * Query Comment to include extra information for debugging or other purposes. + */ + comment?: string; + // ------------------------------------------------------------------------- // Constructor // ------------------------------------------------------------------------- diff --git a/src/query-builder/SelectQueryBuilder.ts b/src/query-builder/SelectQueryBuilder.ts index 5fa2fde9e6c..7f95fd7d611 100644 --- a/src/query-builder/SelectQueryBuilder.ts +++ b/src/query-builder/SelectQueryBuilder.ts @@ -51,7 +51,8 @@ export class SelectQueryBuilder extends QueryBuilder implements * Gets generated sql query without parameters being replaced. */ getQuery(): string { - let sql = this.createSelectExpression(); + let sql = this.createComment(); + sql += this.createSelectExpression(); sql += this.createJoinExpression(); sql += this.createWhereExpression(); sql += this.createGroupByExpression(); diff --git a/src/query-builder/UpdateQueryBuilder.ts b/src/query-builder/UpdateQueryBuilder.ts index 2e0497f1f50..19a091da615 100644 --- a/src/query-builder/UpdateQueryBuilder.ts +++ b/src/query-builder/UpdateQueryBuilder.ts @@ -48,7 +48,8 @@ export class UpdateQueryBuilder extends QueryBuilder implements * Gets generated sql query without parameters being replaced. */ getQuery(): string { - let sql = this.createUpdateExpression(); + let sql = this.createComment(); + sql += this.createUpdateExpression(); sql += this.createOrderByExpression(); sql += this.createLimitExpression(); return sql.trim(); diff --git a/test/functional/query-builder/comment/entity/Test.ts b/test/functional/query-builder/comment/entity/Test.ts new file mode 100644 index 00000000000..6312daa316c --- /dev/null +++ b/test/functional/query-builder/comment/entity/Test.ts @@ -0,0 +1,10 @@ +import {Entity} from "../../../../../src/decorator/entity/Entity"; +import {PrimaryGeneratedColumn} from "../../../../../src/decorator/columns/PrimaryGeneratedColumn"; + +@Entity() +export class Test { + + @PrimaryGeneratedColumn() + id: number; + +} diff --git a/test/functional/query-builder/comment/query-builder-comment.ts b/test/functional/query-builder/comment/query-builder-comment.ts new file mode 100644 index 00000000000..a691251705a --- /dev/null +++ b/test/functional/query-builder/comment/query-builder-comment.ts @@ -0,0 +1,85 @@ +import "reflect-metadata"; +import {closeTestingConnections, createTestingConnections, reloadTestingDatabases} from "../../../utils/test-utils"; +import {Connection} from "../../../../src/connection/Connection"; +import {Test} from "./entity/Test"; +import {expect} from "chai"; + +describe("query builder > comment", () => { + + let connections: Connection[]; + before(async () => connections = await createTestingConnections({ + entities: [Test], + })); + beforeEach(() => reloadTestingDatabases(connections)); + after(() => closeTestingConnections(connections)); + + it("should scrub end comment pattern from string", () => Promise.all(connections.map(async connection => { + const sql = connection.manager.createQueryBuilder(Test, "test") + .comment("Hello World */") + .getSql(); + + expect(sql).to.match(/^\/\* Hello World \*\/ SELECT/); + }))); + + it("should not allow an empty comment", () => Promise.all(connections.map(async connection => { + const sql = connection.manager.createQueryBuilder(Test, "test") + .comment("") + .getSql(); + + expect(sql).to.not.match(/^\/\* Hello World \*\/ SELECT/); + }))); + + it("should allow a comment with just whitespaces", () => Promise.all(connections.map(async connection => { + const sql = connection.manager.createQueryBuilder(Test, "test") + .comment(" ") + .getSql(); + + expect(sql).to.match(/^\/\* \*\/ SELECT/); + }))); + + it("should allow a multi-line comment", () => Promise.all(connections.map(async connection => { + const sql = connection.manager.createQueryBuilder(Test, "test") + .comment("Hello World\nIt's a beautiful day!") + .getSql(); + + expect(sql).to.match(/^\/\* Hello World\nIt's a beautiful day! \*\/ SELECT/); + }))); + + it("should include comment in select", () => Promise.all(connections.map(async connection => { + const sql = connection.manager.createQueryBuilder(Test, "test") + .comment("Hello World") + .getSql(); + + expect(sql).to.match(/^\/\* Hello World \*\/ SELECT/); + }))); + + it("should include comment in update", () => Promise.all(connections.map(async connection => { + const sql = connection.manager.createQueryBuilder(Test, "test") + .update() + .set({ id: 2 }) + .comment("Hello World") + .getSql(); + + expect(sql).to.match(/^\/\* Hello World \*\/ UPDATE/); + }))); + + it("should include comment in insert", () => Promise.all(connections.map(async connection => { + const sql = connection.manager.createQueryBuilder(Test, "test") + .insert() + .values({ id: 1 }) + .comment("Hello World") + .getSql(); + + expect(sql).to.match(/^\/\* Hello World \*\/ INSERT/); + }))); + + it("should include comment in delete", () => Promise.all(connections.map(async connection => { + const sql = connection.manager.createQueryBuilder(Test, "test") + .delete() + .comment("Hello World") + .getSql(); + + expect(sql).to.match(/^\/\* Hello World \*\/ DELETE/); + }))); + +}); From da70b405498b142ecc29f7ff01e7a37f88227360 Mon Sep 17 00:00:00 2001 From: James Ward Date: Thu, 15 Oct 2020 04:39:36 -0400 Subject: [PATCH 137/212] fix: use correct type for MongoQueryRunner.databaseConnection (#6906) fixes #6453 --- src/driver/mongodb/MongoQueryRunner.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/driver/mongodb/MongoQueryRunner.ts b/src/driver/mongodb/MongoQueryRunner.ts index f12ed32bf01..edfcb17c8e7 100644 --- a/src/driver/mongodb/MongoQueryRunner.ts +++ b/src/driver/mongodb/MongoQueryRunner.ts @@ -20,7 +20,6 @@ import { CollStats, CommandCursor, Cursor, - Db, DeleteWriteOpResultObject, FindAndModifyWriteOpResultObject, FindOneAndReplaceOption, @@ -29,6 +28,7 @@ import { InsertOneWriteOpResult, InsertWriteOpResult, MapReduceOptions, + MongoClient, MongoCountPreferences, MongodbIndexOptions, OrderedBulkOperation, @@ -103,13 +103,13 @@ export class MongoQueryRunner implements QueryRunner { /** * Real database connection from a connection pool used to perform queries. */ - databaseConnection: Db; + databaseConnection: MongoClient; // ------------------------------------------------------------------------- // Constructor // ------------------------------------------------------------------------- - constructor(connection: Connection, databaseConnection: Db) { + constructor(connection: Connection, databaseConnection: MongoClient) { this.connection = connection; this.databaseConnection = databaseConnection; this.broadcaster = new Broadcaster(this); From 0f0e0b660c83409bb59f806b9f6e099ca8dbc61c Mon Sep 17 00:00:00 2001 From: James Ward Date: Thu, 15 Oct 2020 13:27:53 -0400 Subject: [PATCH 138/212] perf: Improve MySQL LoadTables Performance (#6886) fixes #6800 --- src/driver/mysql/MysqlQueryRunner.ts | 188 +++++++++++++++++++++++---- 1 file changed, 162 insertions(+), 26 deletions(-) diff --git a/src/driver/mysql/MysqlQueryRunner.ts b/src/driver/mysql/MysqlQueryRunner.ts index dc6005d37b2..91d2cda09f9 100644 --- a/src/driver/mysql/MysqlQueryRunner.ts +++ b/src/driver/mysql/MysqlQueryRunner.ts @@ -1200,47 +1200,183 @@ export class MysqlQueryRunner extends BaseQueryRunner implements QueryRunner { return []; const currentDatabase = await this.getCurrentDatabase(); - const tablesCondition = tableNames.map(tableName => { + + // The following SQL brought to you by: + // A terrible understanding of https://dev.mysql.com/doc/refman/8.0/en/information-schema-optimization.html + // + // Short Version: + // INFORMATION_SCHEMA is a weird metadata virtual table and follows VERY FEW of the normal + // query optimization rules. Depending on the columns you query against & the columns you're SELECTing + // there can be a drastically different query performance - this is because the tables map to + // data on the disk and some pieces of data require a scan of the data directory, the database files, etc + + // With most of these, you'll want to do an `EXPLAIN` when making changes to make sure + // the changes you're making aren't changing the query performance profile negatively + // When you do the explain you'll want to look at the `Extra` field - + // It will look something like: "Using where; {FILE_OPENING}; Scanned {DB_NUM} databases" + // FILE_OPENING will commonly be OPEN_FRM_ONLY or OPEN_FULL_TABLE - you want to aim to NOT do + // an OPEN_FULL_TABLE unless necessary. DB_NUM may be a number or "all" - you really want to + // keep this to 0 or 1. Ideally 0. "All" means you've scanned all databases - not good. + // + // For more info, see the above link to the MySQL docs. + // + // Something not noted in the docs is that complex `WHERE` clauses - such as `OR` expressions - + // will cause the query to not hit the optimizations & do full scans. This is why + // a number of queries below do `UNION`s of single `WHERE` clauses. + + // Avoid data directory scan: TABLE_SCHEMA + // Avoid database directory scan: TABLE_NAME + // Full columns: CARDINALITY & INDEX_TYPE - everything else is FRM only + const statsSubquerySql = tableNames.map(tableName => { let [database, name] = tableName.split("."); if (!name) { name = database; database = this.driver.database || currentDatabase; } - return `(\`TABLE_SCHEMA\` = '${database}' AND \`TABLE_NAME\` = '${name}')`; - }).join(" OR "); - const tablesSql = `SELECT * FROM \`INFORMATION_SCHEMA\`.\`TABLES\` WHERE ` + tablesCondition; - - const columnsSql = `SELECT * FROM \`INFORMATION_SCHEMA\`.\`COLUMNS\` WHERE ` + tablesCondition; - - const primaryKeySql = `SELECT * FROM \`INFORMATION_SCHEMA\`.\`KEY_COLUMN_USAGE\` WHERE \`CONSTRAINT_NAME\` = 'PRIMARY' AND (${tablesCondition})`; - - const collationsSql = `SELECT \`SCHEMA_NAME\`, \`DEFAULT_CHARACTER_SET_NAME\` as \`CHARSET\`, \`DEFAULT_COLLATION_NAME\` AS \`COLLATION\` FROM \`INFORMATION_SCHEMA\`.\`SCHEMATA\``; - - const indicesCondition = tableNames.map(tableName => { + return ` + SELECT + * + FROM \`INFORMATION_SCHEMA\`.\`STATISTICS\` + WHERE + \`TABLE_SCHEMA\` = '${database}' + AND + \`TABLE_NAME\` = '${name}' + `; + }).join(" UNION "); + + // Avoid data directory scan: TABLE_SCHEMA + // Avoid database directory scan: TABLE_NAME + // All columns will hit the full table. + const kcuSubquerySql = tableNames.map(tableName => { let [database, name] = tableName.split("."); if (!name) { name = database; database = this.driver.database || currentDatabase; } - return `(\`s\`.\`TABLE_SCHEMA\` = '${database}' AND \`s\`.\`TABLE_NAME\` = '${name}')`; - }).join(" OR "); - const indicesSql = `SELECT \`s\`.* FROM \`INFORMATION_SCHEMA\`.\`STATISTICS\` \`s\` ` + - `LEFT JOIN \`INFORMATION_SCHEMA\`.\`REFERENTIAL_CONSTRAINTS\` \`rc\` ON \`s\`.\`INDEX_NAME\` = \`rc\`.\`CONSTRAINT_NAME\` AND \`s\`.\`TABLE_SCHEMA\` = \`rc\`.\`CONSTRAINT_SCHEMA\`` + - `WHERE (${indicesCondition}) AND \`s\`.\`INDEX_NAME\` != 'PRIMARY' AND \`rc\`.\`CONSTRAINT_NAME\` IS NULL`; - - const foreignKeysCondition = tableNames.map(tableName => { + return ` + SELECT + * + FROM \`INFORMATION_SCHEMA\`.\`KEY_COLUMN_USAGE\` \`kcu\` + WHERE + \`kcu\`.\`TABLE_SCHEMA\` = '${database}' + AND + \`kcu\`.\`TABLE_NAME\` = '${name}' + `; + }).join(" UNION "); + + // Avoid data directory scan: CONSTRAINT_SCHEMA + // Avoid database directory scan: TABLE_NAME + // All columns will hit the full table. + const rcSubquerySql = tableNames.map(tableName => { let [database, name] = tableName.split("."); if (!name) { name = database; database = this.driver.database || currentDatabase; } - return `(\`kcu\`.\`TABLE_SCHEMA\` = '${database}' AND \`kcu\`.\`TABLE_NAME\` = '${name}')`; - }).join(" OR "); - const foreignKeysSql = `SELECT \`kcu\`.\`TABLE_SCHEMA\`, \`kcu\`.\`TABLE_NAME\`, \`kcu\`.\`CONSTRAINT_NAME\`, \`kcu\`.\`COLUMN_NAME\`, \`kcu\`.\`REFERENCED_TABLE_SCHEMA\`, ` + - `\`kcu\`.\`REFERENCED_TABLE_NAME\`, \`kcu\`.\`REFERENCED_COLUMN_NAME\`, \`rc\`.\`DELETE_RULE\` \`ON_DELETE\`, \`rc\`.\`UPDATE_RULE\` \`ON_UPDATE\` ` + - `FROM \`INFORMATION_SCHEMA\`.\`KEY_COLUMN_USAGE\` \`kcu\` ` + - `INNER JOIN \`INFORMATION_SCHEMA\`.\`REFERENTIAL_CONSTRAINTS\` \`rc\` ON \`rc\`.\`constraint_name\` = \`kcu\`.\`constraint_name\` AND \`rc\`.\`CONSTRAINT_SCHEMA\` = \`kcu\`.\`CONSTRAINT_SCHEMA\` AND \`rc\`.\`TABLE_NAME\` = \`kcu\`.\`TABLE_NAME\` ` + - `WHERE ` + foreignKeysCondition; + return ` + SELECT + * + FROM \`INFORMATION_SCHEMA\`.\`REFERENTIAL_CONSTRAINTS\` + WHERE + \`CONSTRAINT_SCHEMA\` = '${database}' + AND + \`TABLE_NAME\` = '${name}' + `; + }).join(" UNION "); + + // Avoid data directory scan: TABLE_SCHEMA + // Avoid database directory scan: TABLE_NAME + // We only use `TABLE_SCHEMA` and `TABLE_NAME` which is `SKIP_OPEN_TABLE` + const tablesSql = tableNames.map(tableName => { + let [database, name] = tableName.split("."); + if (!name) { + name = database; + database = this.driver.database || currentDatabase; + } + return ` + SELECT + \`TABLE_SCHEMA\`, + \`TABLE_NAME\` + FROM + \`INFORMATION_SCHEMA\`.\`TABLES\` + WHERE + \`TABLE_SCHEMA\` = '${database}' + AND + \`TABLE_NAME\` = '${name}' + `; + }).join(" UNION "); + + // Avoid data directory scan: TABLE_SCHEMA + // Avoid database directory scan: TABLE_NAME + // OPEN_FRM_ONLY applies to all columns + const columnsSql = tableNames.map(tableName => { + let [database, name] = tableName.split("."); + if (!name) { + name = database; + database = this.driver.database || currentDatabase; + } + return ` + SELECT + * + FROM + \`INFORMATION_SCHEMA\`.\`COLUMNS\` + WHERE + \`TABLE_SCHEMA\` = '${database}' + AND + \`TABLE_NAME\` = '${name}' + `; + }).join(" UNION "); + + // No Optimizations are available for COLLATIONS + const collationsSql = ` + SELECT + \`SCHEMA_NAME\`, + \`DEFAULT_CHARACTER_SET_NAME\` as \`CHARSET\`, + \`DEFAULT_COLLATION_NAME\` AS \`COLLATION\` + FROM \`INFORMATION_SCHEMA\`.\`SCHEMATA\` + `; + + // Key Column Usage but only for PKs + const primaryKeySql = `SELECT * FROM (${kcuSubquerySql}) \`kcu\` WHERE \`CONSTRAINT_NAME\` = 'PRIMARY'`; + + // Combine stats & referential constraints + const indicesSql = ` + SELECT + \`s\`.* + FROM (${statsSubquerySql}) \`s\` + LEFT JOIN (${rcSubquerySql}) \`rc\` + ON + \`s\`.\`INDEX_NAME\` = \`rc\`.\`CONSTRAINT_NAME\` + AND + \`s\`.\`TABLE_SCHEMA\` = \`rc\`.\`CONSTRAINT_SCHEMA\` + WHERE + \`s\`.\`INDEX_NAME\` != 'PRIMARY' + AND + \`rc\`.\`CONSTRAINT_NAME\` IS NULL + `; + + // Combine Key Column Usage & Referential Constraints + const foreignKeysSql = ` + SELECT + \`kcu\`.\`TABLE_SCHEMA\`, + \`kcu\`.\`TABLE_NAME\`, + \`kcu\`.\`CONSTRAINT_NAME\`, + \`kcu\`.\`COLUMN_NAME\`, + \`kcu\`.\`REFERENCED_TABLE_SCHEMA\`, + \`kcu\`.\`REFERENCED_TABLE_NAME\`, + \`kcu\`.\`REFERENCED_COLUMN_NAME\`, + \`rc\`.\`DELETE_RULE\` \`ON_DELETE\`, + \`rc\`.\`UPDATE_RULE\` \`ON_UPDATE\` + FROM (${kcuSubquerySql}) \`kcu\` + INNER JOIN (${rcSubquerySql}) \`rc\` + ON + \`rc\`.\`CONSTRAINT_SCHEMA\` = \`kcu\`.\`CONSTRAINT_SCHEMA\` + AND + \`rc\`.\`TABLE_NAME\` = \`kcu\`.\`TABLE_NAME\` + AND + \`rc\`.\`CONSTRAINT_NAME\` = \`kcu\`.\`CONSTRAINT_NAME\` + `; + const [dbTables, dbColumns, dbPrimaryKeys, dbCollations, dbIndices, dbForeignKeys]: ObjectLiteral[][] = await Promise.all([ this.query(tablesSql), this.query(columnsSql), From 96350805fb9f02b8fb2c90b5528a15d5cdb9faeb Mon Sep 17 00:00:00 2001 From: James Ward Date: Thu, 15 Oct 2020 13:29:32 -0400 Subject: [PATCH 139/212] fix: support empty `IN` clause across all dialects (#6887) we were supporting an empty `IN` clause for MySQL and Oracle and this updates the handling to be for all other dialects as well by making the "empty" clause be `0=1` Closes #4865 fixes #2195 --- src/query-builder/QueryBuilder.ts | 5 ++--- .../find-options-operators/repository-find-operators.ts | 8 ++++++++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/query-builder/QueryBuilder.ts b/src/query-builder/QueryBuilder.ts index 7d8ddc8727c..17e4cd37932 100644 --- a/src/query-builder/QueryBuilder.ts +++ b/src/query-builder/QueryBuilder.ts @@ -17,7 +17,6 @@ import {ColumnMetadata} from "../metadata/ColumnMetadata"; import {SqljsDriver} from "../driver/sqljs/SqljsDriver"; import {SqlServerDriver} from "../driver/sqlserver/SqlServerDriver"; import {OracleDriver} from "../driver/oracle/OracleDriver"; -import {MysqlDriver} from "../driver/mysql/MysqlDriver"; import {EntitySchema} from "../"; import {FindOperator} from "../find-options/FindOperator"; import {In} from "../find-options/operator/In"; @@ -939,8 +938,8 @@ export abstract class QueryBuilder { case "between": return `${aliasPath} BETWEEN ${parameters[0]} AND ${parameters[1]}`; case "in": - if ((this.connection.driver instanceof OracleDriver || this.connection.driver instanceof MysqlDriver) && parameters.length === 0) { - return `${aliasPath} IN (null)`; + if (parameters.length === 0) { + return "0=1"; } return `${aliasPath} IN (${parameters.join(", ")})`; case "any": diff --git a/test/functional/repository/find-options-operators/repository-find-operators.ts b/test/functional/repository/find-options-operators/repository-find-operators.ts index ee6eb020e13..249f2bedd08 100644 --- a/test/functional/repository/find-options-operators/repository-find-operators.ts +++ b/test/functional/repository/find-options-operators/repository-find-operators.ts @@ -433,6 +433,10 @@ describe("repository > find options > operators", () => { }); loadedPosts.should.be.eql([{ id: 2, likes: 3, title: "About #2" }]); + const noPosts = await connection.getRepository(Post).find({ + title: In([]) + }); + noPosts.length.should.be.eql(0); }))); it("not(in)", () => Promise.all(connections.map(async connection => { @@ -453,6 +457,10 @@ describe("repository > find options > operators", () => { }); loadedPosts.should.be.eql([{ id: 2, likes: 3, title: "About #2" }]); + const noPosts = await connection.getRepository(Post).find({ + title: Not(In([])) + }); + noPosts.length.should.be.eql(2); }))); it("any", () => Promise.all(connections.map(async connection => { From 920e7812cd9d405df921f9ae9ce52ba0a9743bea Mon Sep 17 00:00:00 2001 From: James Ward Date: Thu, 15 Oct 2020 22:54:57 -0400 Subject: [PATCH 140/212] feat: Add SelectQueryBuilder.getOneOrFail() (#6885) This adds a `getOneOrFail` which which is to `getOne` as `findOneOrFail` is to `findOne` - it never returns `undefined`, it will instead throw an `EntityNotFoundError` closes #6246 --- docs/select-query-builder.md | 10 +++++ src/query-builder/SelectQueryBuilder.ts | 14 ++++++ .../select/query-builder-select.ts | 43 +++++++++++++++++++ 3 files changed, 67 insertions(+) diff --git a/docs/select-query-builder.md b/docs/select-query-builder.md index ba590c2d398..5b2352d51b4 100644 --- a/docs/select-query-builder.md +++ b/docs/select-query-builder.md @@ -174,6 +174,16 @@ const timber = await getRepository(User) .getOne(); ``` +`getOneOrFail` will get a single result from the database, but if +no result exists it will throw an `EntityNotFoundError`: + +```typescript +const timber = await getRepository(User) + .createQueryBuilder("user") + .where("user.id = :id OR user.name = :name", { id: 1, name: "Timber" }) + .getOneOrFail(); +``` + To get multiple results from the database, for example, to get all users from the database, use `getMany`: diff --git a/src/query-builder/SelectQueryBuilder.ts b/src/query-builder/SelectQueryBuilder.ts index 7f95fd7d611..50f7592183b 100644 --- a/src/query-builder/SelectQueryBuilder.ts +++ b/src/query-builder/SelectQueryBuilder.ts @@ -37,6 +37,7 @@ import {ObjectUtils} from "../util/ObjectUtils"; import {DriverUtils} from "../driver/DriverUtils"; import {AuroraDataApiDriver} from "../driver/aurora-data-api/AuroraDataApiDriver"; import {CockroachDriver} from "../driver/cockroachdb/CockroachDriver"; +import {EntityNotFoundError} from "../error/EntityNotFoundError"; /** * Allows to build complex sql queries in a fashion way and execute those queries. @@ -1105,6 +1106,19 @@ export class SelectQueryBuilder extends QueryBuilder implements return result; } + /** + * Gets the first entity returned by execution of generated query builder sql or rejects the returned promise on error. + */ + async getOneOrFail(): Promise { + const entity = await this.getOne(); + + if (!entity) { + throw new EntityNotFoundError(this.expressionMap.mainAlias!.target, this); + } + + return entity; + } + /** * Gets entities returned by execution of generated query builder sql. */ diff --git a/test/functional/query-builder/select/query-builder-select.ts b/test/functional/query-builder/select/query-builder-select.ts index 6b1ba78e893..c2883263a92 100644 --- a/test/functional/query-builder/select/query-builder-select.ts +++ b/test/functional/query-builder/select/query-builder-select.ts @@ -3,6 +3,7 @@ import {closeTestingConnections, createTestingConnections, reloadTestingDatabase import {Connection} from "../../../../src/connection/Connection"; import {Post} from "./entity/Post"; import {expect} from "chai"; +import {EntityNotFoundError} from "../../../../src/error/EntityNotFoundError"; describe("query builder > select", () => { @@ -110,4 +111,46 @@ describe("query builder > select", () => { expect(sql).to.equal("SELECT post.name FROM post post"); }))); + it("should return a single entity for getOne when found", () => Promise.all(connections.map(async connection => { + await connection.getRepository(Post).save({ id: 1, title: "Hello", description: 'World', rating: 0 }); + + const entity = await connection.createQueryBuilder(Post, "post") + .where("post.id = :id", { id: 1 }) + .getOne(); + + expect(entity).not.to.be.undefined; + expect(entity!.id).to.equal(1); + expect(entity!.title).to.equal("Hello"); + }))); + + it("should return undefined for getOne when not found", () => Promise.all(connections.map(async connection => { + await connection.getRepository(Post).save({ id: 1, title: "Hello", description: 'World', rating: 0 }); + + const entity = await connection.createQueryBuilder(Post, "post") + .where("post.id = :id", { id: 2 }) + .getOne(); + + expect(entity).to.be.undefined; + }))); + + it("should return a single entity for getOneOrFail when found", () => Promise.all(connections.map(async connection => { + await connection.getRepository(Post).save({ id: 1, title: "Hello", description: 'World', rating: 0 }); + + const entity = await connection.createQueryBuilder(Post, "post") + .where("post.id = :id", { id: 1 }) + .getOneOrFail(); + + expect(entity.id).to.equal(1); + expect(entity.title).to.equal("Hello"); + }))); + + it("should throw an Error for getOneOrFail when not found", () => Promise.all(connections.map(async connection => { + await connection.getRepository(Post).save({ id: 1, title: "Hello", description: 'World', rating: 0 }); + + await expect( + connection.createQueryBuilder(Post, "post") + .where("post.id = :id", { id: 2 }) + .getOneOrFail() + ).to.be.rejectedWith(EntityNotFoundError); + }))); }); From 6f285dce1ac315707fe01a892c1c74521a98aae2 Mon Sep 17 00:00:00 2001 From: James Ward Date: Fri, 16 Oct 2020 00:34:04 -0400 Subject: [PATCH 141/212] fix: Handle undefined querysets in QueryCommand (#6910) fixes #6612 --- src/commands/QueryCommand.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/commands/QueryCommand.ts b/src/commands/QueryCommand.ts index 1834c3646f4..1916958b413 100644 --- a/src/commands/QueryCommand.ts +++ b/src/commands/QueryCommand.ts @@ -55,8 +55,13 @@ export class QueryCommand implements yargs.CommandModule { queryRunner = connection.createQueryRunner(); console.log(chalk.green("Running query: ") + PlatformTools.highlightSql(args._[1])); const queryResult = await queryRunner.query(args._[1]); - console.log(chalk.green("Query has been executed. Result: ")); - console.log(PlatformTools.highlightJson(JSON.stringify(queryResult, undefined, 2))); + + if (typeof queryResult === "undefined") { + console.log(chalk.green("Query has been executed. No result was returned.")); + } else { + console.log(chalk.green("Query has been executed. Result: ")); + console.log(PlatformTools.highlightJson(JSON.stringify(queryResult, undefined, 2))); + } await queryRunner.release(); await connection.close(); From d7c15e1829b4ab0ca070fb871415270b828f88d6 Mon Sep 17 00:00:00 2001 From: Samuel Okoroafor Date: Fri, 16 Oct 2020 08:37:30 +0200 Subject: [PATCH 142/212] docs: correct grammar error in cache description (#6913) Correct the description for setting a custom table name for the typeorm cache. --- docs/caching.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/caching.md b/docs/caching.md index 85013484301..36393434f45 100644 --- a/docs/caching.md +++ b/docs/caching.md @@ -113,7 +113,7 @@ await connection.queryResultCache.remove(["users_admins"]); By default, TypeORM uses a separate table called `query-result-cache` and stores all queries and results there. -Table name is configurable, so you could change its by give the value in the tableName property. +Table name is configurable, so you could change it by specifying a different value in the tableName property. Example: ```typescript @@ -188,7 +188,7 @@ In case you want to connect to a redis-cluster using IORedis's cluster functiona } ``` -Note that, you can still use options as first argument of IORedis's cluster constructor. +Note that, you can still use options as the first argument of IORedis's cluster constructor. ```typescript { From 60a5dd5c2924c97874a9381204411189f474811f Mon Sep 17 00:00:00 2001 From: James Ward Date: Fri, 16 Oct 2020 14:52:20 -0400 Subject: [PATCH 143/212] test: make test for query comment less restrictive (#6921) the query comment test was causing problems in a few other PRs because it expects a very specific comment then verb pattern - which may or may not always be the case. --- .../comment/query-builder-comment.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/test/functional/query-builder/comment/query-builder-comment.ts b/test/functional/query-builder/comment/query-builder-comment.ts index a691251705a..a84441075a3 100644 --- a/test/functional/query-builder/comment/query-builder-comment.ts +++ b/test/functional/query-builder/comment/query-builder-comment.ts @@ -18,7 +18,7 @@ describe("query builder > comment", () => { .comment("Hello World */") .getSql(); - expect(sql).to.match(/^\/\* Hello World \*\/ SELECT/); + expect(sql).to.match(/^\/\* Hello World \*\/ /); }))); it("should not allow an empty comment", () => Promise.all(connections.map(async connection => { @@ -26,7 +26,7 @@ describe("query builder > comment", () => { .comment("") .getSql(); - expect(sql).to.not.match(/^\/\* Hello World \*\/ SELECT/); + expect(sql).to.not.match(/^\/\* Hello World \*\/ /); }))); it("should allow a comment with just whitespaces", () => Promise.all(connections.map(async connection => { @@ -34,7 +34,7 @@ describe("query builder > comment", () => { .comment(" ") .getSql(); - expect(sql).to.match(/^\/\* \*\/ SELECT/); + expect(sql).to.match(/^\/\* \*\/ /); }))); it("should allow a multi-line comment", () => Promise.all(connections.map(async connection => { @@ -42,7 +42,7 @@ describe("query builder > comment", () => { .comment("Hello World\nIt's a beautiful day!") .getSql(); - expect(sql).to.match(/^\/\* Hello World\nIt's a beautiful day! \*\/ SELECT/); + expect(sql).to.match(/^\/\* Hello World\nIt's a beautiful day! \*\/ /); }))); it("should include comment in select", () => Promise.all(connections.map(async connection => { @@ -50,7 +50,7 @@ describe("query builder > comment", () => { .comment("Hello World") .getSql(); - expect(sql).to.match(/^\/\* Hello World \*\/ SELECT/); + expect(sql).to.match(/^\/\* Hello World \*\/ /); }))); it("should include comment in update", () => Promise.all(connections.map(async connection => { @@ -60,7 +60,7 @@ describe("query builder > comment", () => { .comment("Hello World") .getSql(); - expect(sql).to.match(/^\/\* Hello World \*\/ UPDATE/); + expect(sql).to.match(/^\/\* Hello World \*\/ /); }))); it("should include comment in insert", () => Promise.all(connections.map(async connection => { @@ -70,7 +70,7 @@ describe("query builder > comment", () => { .comment("Hello World") .getSql(); - expect(sql).to.match(/^\/\* Hello World \*\/ INSERT/); + expect(sql).to.match(/^\/\* Hello World \*\/ /); }))); it("should include comment in delete", () => Promise.all(connections.map(async connection => { @@ -79,7 +79,7 @@ describe("query builder > comment", () => { .comment("Hello World") .getSql(); - expect(sql).to.match(/^\/\* Hello World \*\/ DELETE/); + expect(sql).to.match(/^\/\* Hello World \*\/ /); }))); }); From a09fb7fb919e7ebb1c174ba4b0abe09b245e0442 Mon Sep 17 00:00:00 2001 From: James Ward Date: Sat, 17 Oct 2020 05:05:29 -0400 Subject: [PATCH 144/212] fix: correct reading of custom ormconfig.env files (#6922) update the ConnectionOptionsReader so that ormconfig.env files are loaded as expected from the filesystem & included as a dotenv configuration --- src/connection/ConnectionOptionsReader.ts | 12 ++--- .../connection-options-reader/configs/.env | 2 +- .../configs/ormconfig.env | 2 + .../configs/test-path-config-esm.ts | 2 +- .../connection-options-reader.ts | 50 +++++++++++++++---- 5 files changed, 51 insertions(+), 17 deletions(-) create mode 100644 test/functional/connection-options-reader/configs/ormconfig.env diff --git a/src/connection/ConnectionOptionsReader.ts b/src/connection/ConnectionOptionsReader.ts index 5f6b2668231..d8d04646990 100644 --- a/src/connection/ConnectionOptionsReader.ts +++ b/src/connection/ConnectionOptionsReader.ts @@ -92,16 +92,16 @@ export class ConnectionOptionsReader { return PlatformTools.fileExist(this.baseFilePath + "." + format); }); + // Determine config file name + const configFile = fileExtension ? this.baseFilePath : this.baseFilePath + "." + foundFileFormat; + // if .env file found then load all its variables into process.env using dotenv package if (foundFileFormat === "env") { - PlatformTools.dotenv(this.baseFilePath); - } else if (PlatformTools.fileExist(".env")) { - PlatformTools.dotenv(".env"); + PlatformTools.dotenv(configFile); + } else if (PlatformTools.fileExist(this.baseDirectory + "/.env")) { + PlatformTools.dotenv(this.baseDirectory + "/.env"); } - // Determine config file name - const configFile = fileExtension ? this.baseFilePath : this.baseFilePath + "." + foundFileFormat; - // try to find connection options from any of available sources of configuration if (PlatformTools.getEnvVariable("TYPEORM_CONNECTION") || PlatformTools.getEnvVariable("TYPEORM_URL")) { connectionOptions = await new ConnectionOptionsEnvReader().read(); diff --git a/test/functional/connection-options-reader/configs/.env b/test/functional/connection-options-reader/configs/.env index 1930f2b109c..2d7a79b5a0c 100644 --- a/test/functional/connection-options-reader/configs/.env +++ b/test/functional/connection-options-reader/configs/.env @@ -1,2 +1,2 @@ TYPEORM_CONNECTION = mysql -TYPEORM_DATABASE = test-js +TYPEORM_DATABASE = test-env \ No newline at end of file diff --git a/test/functional/connection-options-reader/configs/ormconfig.env b/test/functional/connection-options-reader/configs/ormconfig.env new file mode 100644 index 00000000000..2bf6d39e066 --- /dev/null +++ b/test/functional/connection-options-reader/configs/ormconfig.env @@ -0,0 +1,2 @@ +TYPEORM_CONNECTION = mysql +TYPEORM_DATABASE = test-ormconfig-env \ No newline at end of file diff --git a/test/functional/connection-options-reader/configs/test-path-config-esm.ts b/test/functional/connection-options-reader/configs/test-path-config-esm.ts index 27495c20285..e51c1aa7826 100644 --- a/test/functional/connection-options-reader/configs/test-path-config-esm.ts +++ b/test/functional/connection-options-reader/configs/test-path-config-esm.ts @@ -1,5 +1,5 @@ export default [{ type: "sqlite", name: "file", - database: "test-js" + database: "test-js-esm" }]; diff --git a/test/functional/connection-options-reader/connection-options-reader.ts b/test/functional/connection-options-reader/connection-options-reader.ts index 9ed51c222aa..23302a65cac 100644 --- a/test/functional/connection-options-reader/connection-options-reader.ts +++ b/test/functional/connection-options-reader/connection-options-reader.ts @@ -1,8 +1,21 @@ +import {promises as fs} from "fs"; import {expect} from "chai"; import {ConnectionOptions} from "../../../src/connection/ConnectionOptions"; import {ConnectionOptionsReader} from "../../../src/connection/ConnectionOptionsReader"; +import path from "path"; + +async function createDotenvFiles() { + // These files may not always exist + await fs.writeFile(path.join(__dirname, "configs/.env"), "TYPEORM_CONNECTION = mysql\nTYPEORM_DATABASE = test-env"); + await fs.writeFile(path.join(__dirname, "configs/ormconfig.env"), "TYPEORM_CONNECTION = mysql\nTYPEORM_DATABASE = test-ormconfig-env"); +} describe("ConnectionOptionsReader", () => { + beforeEach(() => { + delete process.env['TYPEORM_CONNECTION']; + delete process.env['TYPEORM_DATABASE']; + }); + after(() => { delete process.env.TYPEORM_CONNECTION; delete process.env.TYPEORM_DATABASE; @@ -26,28 +39,47 @@ describe("ConnectionOptionsReader", () => { }); it("properly loads config with specified file path", async () => { - const connectionOptionsReader = new ConnectionOptionsReader({ root: __dirname, configName: "configs/test-path-config.js" }); + const connectionOptionsReader = new ConnectionOptionsReader({ root: __dirname, configName: "configs/test-path-config" }); const fileOptions: ConnectionOptions = await connectionOptionsReader.get("file"); expect(fileOptions.database).to.have.string("/test-js"); }); it("properly loads asynchronous config with specified file path", async () => { - const connectionOptionsReader = new ConnectionOptionsReader({ root: __dirname, configName: "configs/test-path-config-async.js" }); + const connectionOptionsReader = new ConnectionOptionsReader({ root: __dirname, configName: "configs/test-path-config-async" }); const fileOptions: ConnectionOptions = await connectionOptionsReader.get("file"); expect(fileOptions.database).to.have.string("/test-js-async"); }); it("properly loads config with specified file path from esm in js", async () => { - const connectionOptionsReader = new ConnectionOptionsReader({ root: __dirname, configName: "configs/test-path-config-esm.js" }); + const connectionOptionsReader = new ConnectionOptionsReader({ root: __dirname, configName: "configs/test-path-config-esm" }); const fileOptions: ConnectionOptions = await connectionOptionsReader.get("file"); - expect(fileOptions.database).to.have.string("/test-js"); + expect(fileOptions.database).to.have.string("/test-js-esm"); }); - // TODO This test requires the configs/.env file be moved to the matching directory in build/compiled - it.skip("properly loads config from .env file", async () => { - const connectionOptionsReader = new ConnectionOptionsReader({ root: __dirname, configName: "configs/.env" }); + it("properly loads config from .env file", async () => { + await createDotenvFiles(); + + const connectionOptionsReader = new ConnectionOptionsReader({ root: __dirname, configName: "configs/.env" }); + const [ fileOptions ]: ConnectionOptions[] = await connectionOptionsReader.all(); + expect(fileOptions.database).to.have.string("test-env"); + expect(process.env.TYPEORM_DATABASE).to.equal("test-env"); + }); + + it("properly loads config from ormconfig.env file", async () => { + await createDotenvFiles(); + + const connectionOptionsReader = new ConnectionOptionsReader({ root: __dirname, configName: "configs/ormconfig.env" }); + const [ fileOptions ]: ConnectionOptions[] = await connectionOptionsReader.all(); + expect(fileOptions.database).to.have.string("test-ormconfig-env"); + expect(process.env.TYPEORM_DATABASE).to.equal("test-ormconfig-env"); + }); + + it("properly loads config ormconfig.env when given multiple choices", async () => { + await createDotenvFiles(); + + const connectionOptionsReader = new ConnectionOptionsReader({ root: path.join(__dirname, "configs") }); const [ fileOptions ]: ConnectionOptions[] = await connectionOptionsReader.all(); - expect(fileOptions.database).to.have.string("test-js"); - expect(process.env.TYPEORM_DATABASE).to.equal("test-js"); + expect(fileOptions.database).to.have.string("test-ormconfig-env"); + expect(process.env.TYPEORM_DATABASE).to.equal("test-ormconfig-env"); }); }); From 6fa2df5ade71a3fee550e3c8fb7bcd7cd02080a8 Mon Sep 17 00:00:00 2001 From: James Ward Date: Sat, 17 Oct 2020 12:18:58 -0400 Subject: [PATCH 145/212] fix: handle Undefined values in driver URL options (#6925) the `buildDriverOptions` parses the URL & will have undefined values which it ends up overwriting non-undefined values with - which isn't great --- src/driver/DriverUtils.ts | 22 ++++---- src/driver/mongodb/MongoDriver.ts | 28 +++++----- test/github-issues/6900/entity/Warn.ts | 22 ++++++++ test/github-issues/6900/issue-6900.ts | 75 ++++++++++++++++++++++++++ 4 files changed, 122 insertions(+), 25 deletions(-) create mode 100644 test/github-issues/6900/entity/Warn.ts create mode 100644 test/github-issues/6900/issue-6900.ts diff --git a/src/driver/DriverUtils.ts b/src/driver/DriverUtils.ts index f6da56b5645..8fed97a3ea7 100644 --- a/src/driver/DriverUtils.ts +++ b/src/driver/DriverUtils.ts @@ -16,18 +16,18 @@ export class DriverUtils { */ static buildDriverOptions(options: any, buildOptions?: { useSid: boolean }): any { if (options.url) { - const parsedUrl = this.parseConnectionUrl(options.url); - let urlDriverOptions: any = { - type: parsedUrl.type, - host: parsedUrl.host, - username: parsedUrl.username, - password: parsedUrl.password, - port: parsedUrl.port, - database: parsedUrl.database - }; - if (buildOptions && buildOptions.useSid) { - urlDriverOptions.sid = parsedUrl.database; + const urlDriverOptions = this.parseConnectionUrl(options.url) as { [key: string]: any }; + + if (buildOptions && buildOptions.useSid && urlDriverOptions.database) { + urlDriverOptions.sid = urlDriverOptions.database; + } + + for (const key of Object.keys(urlDriverOptions)) { + if (typeof urlDriverOptions[key] === 'undefined') { + delete urlDriverOptions[key]; + } } + return Object.assign({}, options, urlDriverOptions); } return Object.assign({}, options); diff --git a/src/driver/mongodb/MongoDriver.ts b/src/driver/mongodb/MongoDriver.ts index 1602acee51c..b204df39dcf 100644 --- a/src/driver/mongodb/MongoDriver.ts +++ b/src/driver/mongodb/MongoDriver.ts @@ -17,6 +17,7 @@ import {EntityMetadata} from "../../metadata/EntityMetadata"; import {ObjectUtils} from "../../util/ObjectUtils"; import {ApplyValueTransformers} from "../../util/ApplyValueTransformers"; import {ReplicationMode} from "../types/ReplicationMode"; +import {DriverUtils} from "../DriverUtils"; /** * Organizes communication with MongoDB. @@ -223,9 +224,11 @@ export class MongoDriver implements Driver { */ connect(): Promise { return new Promise((ok, fail) => { + const options = DriverUtils.buildDriverOptions(this.options); + this.mongodb.MongoClient.connect( - this.buildConnectionUrl(), - this.buildConnectionOptions(), + this.buildConnectionUrl(options), + this.buildConnectionOptions(options), (err: any, client: any) => { if (err) return fail(err); @@ -434,30 +437,27 @@ export class MongoDriver implements Driver { /** * Builds connection url that is passed to underlying driver to perform connection to the mongodb database. */ - protected buildConnectionUrl(): string { - if (this.options.url) - return this.options.url; - - const credentialsUrlPart = (this.options.username && this.options.password) - ? `${this.options.username}:${this.options.password}@` + protected buildConnectionUrl(options: { [key: string]: any }): string { + const credentialsUrlPart = (options.username && options.password) + ? `${options.username}:${options.password}@` : ""; - return `mongodb://${credentialsUrlPart}${this.options.host || "127.0.0.1"}:${this.options.port || "27017"}/${this.options.database}`; + return `mongodb://${credentialsUrlPart}${options.host || "127.0.0.1"}:${options.port || "27017"}/${options.database || ""}`; } /** * Build connection options from MongoConnectionOptions */ - protected buildConnectionOptions(): any { + protected buildConnectionOptions(options: { [key: string]: any }): any { const mongoOptions: any = {}; for (let index = 0; index < this.validOptionNames.length; index++) { const optionName = this.validOptionNames[index]; - if (this.options.extra && optionName in this.options.extra) { - mongoOptions[optionName] = this.options.extra[optionName]; - } else if (optionName in this.options) { - mongoOptions[optionName] = (this.options as any)[optionName]; + if (options.extra && optionName in options.extra) { + mongoOptions[optionName] = options.extra[optionName]; + } else if (optionName in options) { + mongoOptions[optionName] = options[optionName]; } } diff --git a/test/github-issues/6900/entity/Warn.ts b/test/github-issues/6900/entity/Warn.ts new file mode 100644 index 00000000000..cbabc4df7e2 --- /dev/null +++ b/test/github-issues/6900/entity/Warn.ts @@ -0,0 +1,22 @@ +import { Entity, ObjectID, ObjectIdColumn, Column } from "../../../../src"; + +@Entity("warnings") +export class Warn { + @ObjectIdColumn() + id!: ObjectID + + @Column() + guild!: string; + + @Column() + user!: string; + + @Column() + moderator!: string; + + @Column() + reason!: string; + + @Column() + createdAt!: Date; +} diff --git a/test/github-issues/6900/issue-6900.ts b/test/github-issues/6900/issue-6900.ts new file mode 100644 index 00000000000..560adffc306 --- /dev/null +++ b/test/github-issues/6900/issue-6900.ts @@ -0,0 +1,75 @@ +import { expect } from "chai"; +import { + closeTestingConnections, reloadTestingDatabases, + setupTestingConnections +} from "../../utils/test-utils"; +import {MongoDriver} from "../../../src/driver/mongodb/MongoDriver"; +import {Connection, ConnectionOptions, createConnection, MongoClient} from "../../../src"; +import {Warn} from "./entity/Warn"; + +describe("github issues > #6900 MongoDB ConnectionManager doesn't select given database, creates new database \"test\" instead", () => { + let connections: Connection[] = []; + afterEach(async () => { + await closeTestingConnections(connections); + connections.length = 0; + }); + + it("should connect to the expected database", async () => { + const options = setupTestingConnections({ enabledDrivers: ["mongodb"] }); + + if (options.length === 0) { + // Skip if we can't grab the mongodb + return; + } + + const connection = await createConnection({ + ...options[0], + url: 'mongodb://localhost', + database: 'foo' + } as ConnectionOptions); + connections.push(connection); + + await reloadTestingDatabases(connections); + + const mongoDriver = connection.driver as MongoDriver ; + const client = (mongoDriver.queryRunner!.databaseConnection as any) as MongoClient; + + expect(client.db().databaseName).to.be.equal('foo'); + expect(mongoDriver.database).to.be.equal('foo'); + }); + + it("should write data to the correct database", async () => { + const options = setupTestingConnections({ enabledDrivers: ["mongodb"] }); + + if (options.length === 0) { + // Skip if we can't grab the mongodb + return; + } + + const connection = await createConnection({ + ...options[0], + entities: [ Warn ], + url: 'mongodb://localhost', + database: 'foo' + } as ConnectionOptions); + connections.push(connection); + + await reloadTestingDatabases(connections); + + const repo = connection.getRepository(Warn) + + await repo.insert({ + id: Math.floor(Math.random() * 1000000), + guild: "Hello", + user: "WORLD", + moderator: "Good Moderator", + reason: "For Mongo not writing correctly to the databsae!", + createdAt: new Date() + }); + + const mongoDriver = connection.driver as MongoDriver ; + const client = (mongoDriver.queryRunner!.databaseConnection as any) as MongoClient; + + expect(await client.db('foo').collection('warnings').count({})).to.be.greaterThan(0); + }) +}); From dee17589cfe26a86c9a68d28d08c5dfe82ad8363 Mon Sep 17 00:00:00 2001 From: James Ward Date: Sat, 17 Oct 2020 12:26:20 -0400 Subject: [PATCH 146/212] style: double quotes in `DriverUtils` --- src/driver/DriverUtils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/driver/DriverUtils.ts b/src/driver/DriverUtils.ts index 8fed97a3ea7..162c882dc8a 100644 --- a/src/driver/DriverUtils.ts +++ b/src/driver/DriverUtils.ts @@ -23,7 +23,7 @@ export class DriverUtils { } for (const key of Object.keys(urlDriverOptions)) { - if (typeof urlDriverOptions[key] === 'undefined') { + if (typeof urlDriverOptions[key] === "undefined") { delete urlDriverOptions[key]; } } From 0956ffcdacd88c29e36d7c09c4600859cfa2513f Mon Sep 17 00:00:00 2001 From: James Ward Date: Sat, 17 Oct 2020 16:02:56 -0400 Subject: [PATCH 147/212] test: fix test 6900 in CI (#6928) test 6900 only ran correctly in local testing & didn't correctly handle the different hostnames in CI / CD --- test/github-issues/6900/issue-6900.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/test/github-issues/6900/issue-6900.ts b/test/github-issues/6900/issue-6900.ts index 560adffc306..801ae54940d 100644 --- a/test/github-issues/6900/issue-6900.ts +++ b/test/github-issues/6900/issue-6900.ts @@ -6,6 +6,7 @@ import { import {MongoDriver} from "../../../src/driver/mongodb/MongoDriver"; import {Connection, ConnectionOptions, createConnection, MongoClient} from "../../../src"; import {Warn} from "./entity/Warn"; +import {MongoConnectionOptions} from "../../../src/driver/mongodb/MongoConnectionOptions"; describe("github issues > #6900 MongoDB ConnectionManager doesn't select given database, creates new database \"test\" instead", () => { let connections: Connection[] = []; @@ -22,9 +23,11 @@ describe("github issues > #6900 MongoDB ConnectionManager doesn't select given d return; } + const host: string = (options[0] as MongoConnectionOptions).host || 'localhost'; + const connection = await createConnection({ ...options[0], - url: 'mongodb://localhost', + url: `mongodb://${host}`, database: 'foo' } as ConnectionOptions); connections.push(connection); @@ -46,10 +49,12 @@ describe("github issues > #6900 MongoDB ConnectionManager doesn't select given d return; } + const host: string = (options[0] as MongoConnectionOptions).host || 'localhost'; + const connection = await createConnection({ ...options[0], entities: [ Warn ], - url: 'mongodb://localhost', + url: `mongodb://${host}`, database: 'foo' } as ConnectionOptions); connections.push(connection); From c5143aab08a04e96aebb55996ed7683d48542bbd Mon Sep 17 00:00:00 2001 From: James Ward Date: Sun, 18 Oct 2020 12:34:19 -0400 Subject: [PATCH 148/212] fix: support changing comments in MySQL columns (#6903) in the mysql driver, column comments were only half supported - adding them to new columns & new tables was possible, but updating existing columns to include comments was not possible there also was no escaping done on the column comments - so depending on the contents of your comment, an invalid query could be generated adds support to add comments to existing columns, adds simple comment escaping code, & creates tests to verify the behavior --- src/driver/mysql/MysqlDriver.ts | 2 +- src/driver/mysql/MysqlQueryRunner.ts | 24 ++++++++-- .../columns/comments/columns-comments.ts | 34 ++++++++++++++ .../columns/comments/entity/Test.ts | 46 +++++++++++++++++++ .../migrations/generate-command/command.ts | 2 +- .../schema-builder/change-column.ts | 31 +++++++++++++ 6 files changed, 133 insertions(+), 6 deletions(-) create mode 100644 test/functional/columns/comments/columns-comments.ts create mode 100644 test/functional/columns/comments/entity/Test.ts diff --git a/src/driver/mysql/MysqlDriver.ts b/src/driver/mysql/MysqlDriver.ts index 6d7f3180723..cdf3deb7c37 100644 --- a/src/driver/mysql/MysqlDriver.ts +++ b/src/driver/mysql/MysqlDriver.ts @@ -776,7 +776,7 @@ export class MysqlDriver implements Driver { || tableColumn.unsigned !== columnMetadata.unsigned || tableColumn.asExpression !== columnMetadata.asExpression || tableColumn.generatedType !== columnMetadata.generatedType - // || tableColumn.comment !== columnMetadata.comment // todo + || (tableColumn.comment || "") !== columnMetadata.comment || !this.compareDefaultValues(this.normalizeDefault(columnMetadata), tableColumn.default) || (tableColumn.enum && columnMetadata.enum && !OrmUtils.isArraysEqual(tableColumn.enum, columnMetadata.enum.map(val => val + ""))) || tableColumn.onUpdate !== columnMetadata.onUpdate diff --git a/src/driver/mysql/MysqlQueryRunner.ts b/src/driver/mysql/MysqlQueryRunner.ts index 91d2cda09f9..cdc848eaa9c 100644 --- a/src/driver/mysql/MysqlQueryRunner.ts +++ b/src/driver/mysql/MysqlQueryRunner.ts @@ -637,7 +637,7 @@ export class MysqlQueryRunner extends BaseQueryRunner implements QueryRunner { oldColumn.name = newColumn.name; } - if (this.isColumnChanged(oldColumn, newColumn, true)) { + if (this.isColumnChanged(oldColumn, newColumn, true, true)) { upQueries.push(new Query(`ALTER TABLE ${this.escapePath(table)} CHANGE \`${oldColumn.name}\` ${this.buildCreateColumnSql(newColumn, true)}`)); downQueries.push(new Query(`ALTER TABLE ${this.escapePath(table)} CHANGE \`${newColumn.name}\` ${this.buildCreateColumnSql(oldColumn, true)}`)); } @@ -1483,7 +1483,7 @@ export class MysqlQueryRunner extends BaseQueryRunner implements QueryRunner { if (tableColumn.isGenerated) tableColumn.generationStrategy = "increment"; - tableColumn.comment = dbColumn["COLUMN_COMMENT"]; + tableColumn.comment = (typeof dbColumn["COLUMN_COMMENT"] === "string" && dbColumn["COLUMN_COMMENT"].length === 0) ? undefined : dbColumn["COLUMN_COMMENT"]; if (dbColumn["CHARACTER_SET_NAME"]) tableColumn.charset = dbColumn["CHARACTER_SET_NAME"] === defaultCharset ? undefined : dbColumn["CHARACTER_SET_NAME"]; if (dbColumn["COLLATION_NAME"]) @@ -1783,6 +1783,22 @@ export class MysqlQueryRunner extends BaseQueryRunner implements QueryRunner { }; } + /** + * Escapes a given comment so it's safe to include in a query. + */ + protected escapeComment(comment?: string) { + if (comment === undefined || comment.length === 0) { + return `''`; + } + + comment = comment + .replace("\\", "\\\\") // MySQL allows escaping characters via backslashes + .replace("'", "''") + .replace("\0", ""); // Null bytes aren't allowed in comments + + return `'${comment}'`; + } + /** * Escapes given table or view path. */ @@ -1824,8 +1840,8 @@ export class MysqlQueryRunner extends BaseQueryRunner implements QueryRunner { c += " PRIMARY KEY"; if (column.isGenerated && column.generationStrategy === "increment") // don't use skipPrimary here since updates can update already exist primary without auto inc. c += " AUTO_INCREMENT"; - if (column.comment) - c += ` COMMENT '${column.comment.replace("'", "''")}'`; + if (column.comment !== undefined && column.comment.length > 0) + c += ` COMMENT ${this.escapeComment(column.comment)}`; if (column.default !== undefined && column.default !== null) c += ` DEFAULT ${column.default}`; if (column.onUpdate) diff --git a/test/functional/columns/comments/columns-comments.ts b/test/functional/columns/comments/columns-comments.ts new file mode 100644 index 00000000000..859750b2de9 --- /dev/null +++ b/test/functional/columns/comments/columns-comments.ts @@ -0,0 +1,34 @@ +import {expect} from "chai"; +import "reflect-metadata"; +import {Connection} from "../../../../src"; +import {closeTestingConnections, createTestingConnections, reloadTestingDatabases} from "../../../utils/test-utils"; +import {Test} from "./entity/Test"; + +describe("columns > comments", () => { + + let connections: Connection[]; + before(async () => connections = await createTestingConnections({ + entities: [Test], + // Only supported on mysql + enabledDrivers: ["mysql"] + })); + beforeEach(() => reloadTestingDatabases(connections)); + after(() => closeTestingConnections(connections)); + + it("should persist comments of different types to the database", () => Promise.all(connections.map(async connection => { + const table = (await connection.createQueryRunner().getTable("test"))!; + + expect(table.findColumnByName("a")!.comment).to.be.equal("Hello World") + expect(table.findColumnByName("b")!.comment).to.be.equal("Hello\nWorld") + expect(table.findColumnByName("c")!.comment).to.be.equal("Hello World! It's going to be a beautiful day.") + expect(table.findColumnByName("d")!.comment).to.be.equal("Hello World! #@!$`") + expect(table.findColumnByName("e")!.comment).to.be.equal("Hello World. \r\n\t\b\f\v") + expect(table.findColumnByName("f")!.comment).to.be.equal("Hello World.\\") + expect(table.findColumnByName("g")!.comment).to.be.equal(" ") + expect(table.findColumnByName("h")!.comment).to.be.equal(undefined); + expect(table.findColumnByName("i")!.comment).to.be.equal(undefined); + + }))); + + +}); diff --git a/test/functional/columns/comments/entity/Test.ts b/test/functional/columns/comments/entity/Test.ts new file mode 100644 index 00000000000..1fdaea37cb6 --- /dev/null +++ b/test/functional/columns/comments/entity/Test.ts @@ -0,0 +1,46 @@ +import {Entity} from "../../../../../src/decorator/entity/Entity"; +import {Column} from "../../../../../src/decorator/columns/Column"; +import {PrimaryGeneratedColumn} from "../../../../../src/decorator/columns/PrimaryGeneratedColumn"; + +@Entity() +export class Test { + + @PrimaryGeneratedColumn() + id: number; + + // Standard Comment + @Column({ comment: "Hello World"}) + a: string; + + // Comment with a newline + @Column({ comment: "Hello\nWorld"}) + b: string; + + // Comment with a single quote + @Column({ comment: "Hello World! It's going to be a beautiful day."}) + c: string; + + // Comment with special characters + @Column({ comment: "Hello World! #@!$`"}) + d: string; + + // Comment with control characters + @Column({ comment: "Hello World. \r\n\t\b\f\v\0"}) + e: string; + + // Comment that ends with a backslash + @Column({ comment: "Hello World.\\"}) + f: string; + + // Comment that is only whitespace + @Column({ comment: " "}) + g: string; + + // Comment that is empty + @Column({ comment: ""}) + h: string; + + // No comment. + @Column() + i: string; +} diff --git a/test/functional/migrations/generate-command/command.ts b/test/functional/migrations/generate-command/command.ts index 491dfd7a4b3..465ee27871b 100644 --- a/test/functional/migrations/generate-command/command.ts +++ b/test/functional/migrations/generate-command/command.ts @@ -7,7 +7,7 @@ describe("migrations > generate command", () => { let connections: Connection[]; before(async () => connections = await createTestingConnections({ migrations: [], - enabledDrivers: ["postgres"], + enabledDrivers: ["postgres", "cockroachdb", "mysql"], schemaCreate: false, dropSchema: true, entities: [Post, Category], diff --git a/test/functional/schema-builder/change-column.ts b/test/functional/schema-builder/change-column.ts index 2b21f5f02b9..d5e752336e3 100644 --- a/test/functional/schema-builder/change-column.ts +++ b/test/functional/schema-builder/change-column.ts @@ -248,4 +248,35 @@ describe("schema builder > change column", () => { }))); + it("should correctly change column comment", () => Promise.all(connections.map(async connection => { + // Skip thie contents of this test if not one of the drivers that support comments + if (!(connection.driver instanceof MysqlDriver)) { + return; + } + + const teacherMetadata = connection.getMetadata("teacher"); + const idColumn = teacherMetadata.findColumnWithPropertyName("id")!; + + idColumn.comment = "The Teacher's Key"; + + await connection.synchronize(); + + const queryRunnerA = connection.createQueryRunner(); + const teacherTableA = await queryRunnerA.getTable("teacher"); + await queryRunnerA.release(); + + expect(teacherTableA!.findColumnByName("id")!.comment).to.be.equal("The Teacher's Key", connection.name); + + // revert changes + idColumn.comment = ""; + + await connection.synchronize(); + + const queryRunnerB = connection.createQueryRunner(); + const teacherTableB = await queryRunnerB.getTable("teacher"); + await queryRunnerB.release(); + + expect(teacherTableB!.findColumnByName("id")!.comment).to.be.undefined; + + }))); }); From f9caf5d90bb59d6490423eeb456588e2df9bdd15 Mon Sep 17 00:00:00 2001 From: Manuel Nucci <32201854+manuelnucci@users.noreply.github.com> Date: Sun, 18 Oct 2020 22:19:26 -0300 Subject: [PATCH 149/212] docs: fix decorators in example class using adjacency list (#6932) Closes: #6527 --- docs/entities.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/entities.md b/docs/entities.md index 9b562454ce6..0bd5cbcd1b6 100644 --- a/docs/entities.md +++ b/docs/entities.md @@ -705,11 +705,11 @@ export class Category { @Column() description: string; - @OneToMany(type => Category, category => category.children) + @ManyToOne(type => Category, category => category.children) parent: Category; - @ManyToOne(type => Category, category => category.parent) - children: Category; + @OneToMany(type => Category, category => category.parent) + children: Category[]; } ``` From bc623a42a868eae7c988779abc4cdc0bbf775def Mon Sep 17 00:00:00 2001 From: James Ward Date: Mon, 19 Oct 2020 12:45:53 -0400 Subject: [PATCH 150/212] feat: Support column comments in Postgres and CockroachDB (#6902) adds support for column comments to both the Postgres and CockroachDB driver - for migrations & in metadata. also includes new tests that validate the functionality works as expected fixes #3360 --- src/driver/cockroachdb/CockroachDriver.ts | 2 +- .../cockroachdb/CockroachQueryRunner.ts | 40 +++++++++++++++++-- src/driver/postgres/PostgresDriver.ts | 2 +- src/driver/postgres/PostgresQueryRunner.ts | 40 +++++++++++++++++-- .../columns/comments/columns-comments.ts | 4 +- .../schema-builder/change-column.ts | 2 +- 6 files changed, 77 insertions(+), 13 deletions(-) diff --git a/src/driver/cockroachdb/CockroachDriver.ts b/src/driver/cockroachdb/CockroachDriver.ts index 11ab71ae13c..8cb82185d68 100644 --- a/src/driver/cockroachdb/CockroachDriver.ts +++ b/src/driver/cockroachdb/CockroachDriver.ts @@ -619,7 +619,7 @@ export class CockroachDriver implements Driver { || tableColumn.length !== columnMetadata.length || tableColumn.precision !== columnMetadata.precision || (columnMetadata.scale !== undefined && tableColumn.scale !== columnMetadata.scale) - // || tableColumn.comment !== columnMetadata.comment // todo + || (tableColumn.comment || "") !== columnMetadata.comment || (!tableColumn.isGenerated && this.lowerDefaultValueIfNecessary(this.normalizeDefault(columnMetadata)) !== tableColumn.default) // we included check for generated here, because generated columns already can have default values || tableColumn.isPrimary !== columnMetadata.isPrimary || tableColumn.isNullable !== columnMetadata.isNullable diff --git a/src/driver/cockroachdb/CockroachQueryRunner.ts b/src/driver/cockroachdb/CockroachQueryRunner.ts index 80c1b2663ff..30761f830eb 100644 --- a/src/driver/cockroachdb/CockroachQueryRunner.ts +++ b/src/driver/cockroachdb/CockroachQueryRunner.ts @@ -585,6 +585,12 @@ export class CockroachQueryRunner extends BaseQueryRunner implements QueryRunner downQueries.push(this.dropIndexSql(table, uniqueConstraint.name!)); // CockroachDB creates indices for unique constraints } + // create column's comment + if (column.comment) { + upQueries.push(new Query(`COMMENT ON COLUMN ${this.escapePath(table)}."${column.name}" IS ${this.escapeComment(column.comment)}`)); + downQueries.push(new Query(`COMMENT ON COLUMN ${this.escapePath(table)}."${column.name}" IS ${this.escapeComment(column.comment)}`)); + } + await this.executeQueries(upQueries, downQueries); clonedTable.addColumn(column); @@ -738,8 +744,8 @@ export class CockroachQueryRunner extends BaseQueryRunner implements QueryRunner } if (oldColumn.comment !== newColumn.comment) { - upQueries.push(new Query(`COMMENT ON COLUMN ${this.escapePath(table)}."${oldColumn.name}" IS '${newColumn.comment}'`)); - downQueries.push(new Query(`COMMENT ON COLUMN ${this.escapePath(table)}."${newColumn.name}" IS '${oldColumn.comment}'`)); + upQueries.push(new Query(`COMMENT ON COLUMN ${this.escapePath(table)}."${oldColumn.name}" IS ${this.escapeComment(newColumn.comment)}`)); + downQueries.push(new Query(`COMMENT ON COLUMN ${this.escapePath(table)}."${newColumn.name}" IS ${this.escapeComment(oldColumn.comment)}`)); } if (newColumn.isPrimary !== oldColumn.isPrimary) { @@ -1344,7 +1350,13 @@ export class CockroachQueryRunner extends BaseQueryRunner implements QueryRunner return `("table_schema" = '${schema}' AND "table_name" = '${name}')`; }).join(" OR "); const tablesSql = `SELECT * FROM "information_schema"."tables" WHERE ` + tablesCondition; - const columnsSql = `SELECT * FROM "information_schema"."columns" WHERE "is_hidden" = 'NO' AND ` + tablesCondition; + + const columnsSql = ` + SELECT + *, + pg_catalog.col_description(('"' || table_catalog || '"."' || table_schema || '"."' || table_name || '"')::regclass::oid, ordinal_position) as description + FROM "information_schema"."columns" + WHERE "is_hidden" = 'NO' AND ` + tablesCondition; const constraintsCondition = tableNames.map(tableName => { let [schema, name] = tableName.split("."); @@ -1496,7 +1508,7 @@ export class CockroachQueryRunner extends BaseQueryRunner implements QueryRunner } } - tableColumn.comment = ""; // dbColumn["COLUMN_COMMENT"]; + tableColumn.comment = dbColumn["description"] == null ? undefined : dbColumn["description"]; if (dbColumn["character_set_name"]) tableColumn.charset = dbColumn["character_set_name"]; @@ -1663,6 +1675,11 @@ export class CockroachQueryRunner extends BaseQueryRunner implements QueryRunner sql += `)`; + table.columns + .filter(it => it.comment) + .forEach(it => sql += `; COMMENT ON COLUMN ${this.escapePath(table)}."${it.name}" IS ${this.escapeComment(it.comment)}`); + + return new Query(sql); } @@ -1841,6 +1858,21 @@ export class CockroachQueryRunner extends BaseQueryRunner implements QueryRunner return disableEscape ? `${table.name}_${columnName}_seq` : `"${table.name}_${columnName}_seq"`; } + /** + * Escapes a given comment so it's safe to include in a query. + */ + protected escapeComment(comment?: string) { + if (comment === undefined || comment.length === 0) { + return 'NULL'; + } + + comment = comment + .replace("'", "''") + .replace("\0", ""); // Null bytes aren't allowed in comments + + return `'${comment}'`; + } + /** * Escapes given table or view path. */ diff --git a/src/driver/postgres/PostgresDriver.ts b/src/driver/postgres/PostgresDriver.ts index f7b6adb8f66..99a94da8a5c 100644 --- a/src/driver/postgres/PostgresDriver.ts +++ b/src/driver/postgres/PostgresDriver.ts @@ -875,7 +875,7 @@ export class PostgresDriver implements Driver { || tableColumn.length !== columnMetadata.length || tableColumn.precision !== columnMetadata.precision || (columnMetadata.scale !== undefined && tableColumn.scale !== columnMetadata.scale) - // || tableColumn.comment !== columnMetadata.comment // todo + || (tableColumn.comment || "") !== columnMetadata.comment || (!tableColumn.isGenerated && this.lowerDefaultValueIfNecessary(this.normalizeDefault(columnMetadata)) !== tableColumn.default) // we included check for generated here, because generated columns already can have default values || tableColumn.isPrimary !== columnMetadata.isPrimary || tableColumn.isNullable !== columnMetadata.isNullable diff --git a/src/driver/postgres/PostgresQueryRunner.ts b/src/driver/postgres/PostgresQueryRunner.ts index d1996a97c28..2f7b65b8fd2 100644 --- a/src/driver/postgres/PostgresQueryRunner.ts +++ b/src/driver/postgres/PostgresQueryRunner.ts @@ -563,6 +563,12 @@ export class PostgresQueryRunner extends BaseQueryRunner implements QueryRunner downQueries.push(new Query(`ALTER TABLE ${this.escapePath(table)} DROP CONSTRAINT "${uniqueConstraint.name}"`)); } + // create column's comment + if (column.comment) { + upQueries.push(new Query(`COMMENT ON COLUMN ${this.escapePath(table)}."${column.name}" IS ${this.escapeComment(column.comment)}`)); + downQueries.push(new Query(`COMMENT ON COLUMN ${this.escapePath(table)}."${column.name}" IS ${this.escapeComment(column.comment)}`)); + } + await this.executeQueries(upQueries, downQueries); clonedTable.addColumn(column); @@ -782,8 +788,8 @@ export class PostgresQueryRunner extends BaseQueryRunner implements QueryRunner } if (oldColumn.comment !== newColumn.comment) { - upQueries.push(new Query(`COMMENT ON COLUMN ${this.escapePath(table)}."${oldColumn.name}" IS '${newColumn.comment}'`)); - downQueries.push(new Query(`COMMENT ON COLUMN ${this.escapePath(table)}."${newColumn.name}" IS '${oldColumn.comment}'`)); + upQueries.push(new Query(`COMMENT ON COLUMN ${this.escapePath(table)}."${oldColumn.name}" IS ${this.escapeComment(newColumn.comment)}`)); + downQueries.push(new Query(`COMMENT ON COLUMN ${this.escapePath(table)}."${newColumn.name}" IS ${this.escapeComment(oldColumn.comment)}`)); } if (newColumn.isPrimary !== oldColumn.isPrimary) { @@ -1394,7 +1400,14 @@ export class PostgresQueryRunner extends BaseQueryRunner implements QueryRunner return `("table_schema" = '${schema}' AND "table_name" = '${name}')`; }).join(" OR "); const tablesSql = `SELECT * FROM "information_schema"."tables" WHERE ` + tablesCondition; - const columnsSql = `SELECT *, ('"' || "udt_schema" || '"."' || "udt_name" || '"')::"regtype" AS "regtype" FROM "information_schema"."columns" WHERE ` + tablesCondition; + const columnsSql = ` + SELECT + *, + pg_catalog.col_description(('"' || table_catalog || '"."' || table_schema || '"."' || table_name || '"')::regclass::oid, ordinal_position) as description, + ('"' || "udt_schema" || '"."' || "udt_name" || '"')::"regtype" AS "regtype" + FROM "information_schema"."columns" + WHERE + ` + tablesCondition; const constraintsCondition = tableNames.map(tableName => { let [schema, name] = tableName.split("."); @@ -1593,7 +1606,7 @@ export class PostgresQueryRunner extends BaseQueryRunner implements QueryRunner } } - tableColumn.comment = ""; // dbColumn["COLUMN_COMMENT"]; + tableColumn.comment = dbColumn["description"] == null ? undefined : dbColumn["description"]; if (dbColumn["character_set_name"]) tableColumn.charset = dbColumn["character_set_name"]; if (dbColumn["collation_name"]) @@ -1768,6 +1781,10 @@ export class PostgresQueryRunner extends BaseQueryRunner implements QueryRunner sql += `)`; + table.columns + .filter(it => it.comment) + .forEach(it => sql += `; COMMENT ON COLUMN ${this.escapePath(table)}."${it.name}" IS ${this.escapeComment(it.comment)}`); + return new Query(sql); } @@ -2065,6 +2082,21 @@ export class PostgresQueryRunner extends BaseQueryRunner implements QueryRunner }; } + /** + * Escapes a given comment so it's safe to include in a query. + */ + protected escapeComment(comment?: string) { + if (comment === undefined || comment.length === 0) { + return 'NULL'; + } + + comment = comment + .replace("'", "''") + .replace("\0", ""); // Null bytes aren't allowed in comments + + return `'${comment}'`; + } + /** * Escapes given table or view path. */ diff --git a/test/functional/columns/comments/columns-comments.ts b/test/functional/columns/comments/columns-comments.ts index 859750b2de9..2ad8a8ea7c2 100644 --- a/test/functional/columns/comments/columns-comments.ts +++ b/test/functional/columns/comments/columns-comments.ts @@ -9,8 +9,8 @@ describe("columns > comments", () => { let connections: Connection[]; before(async () => connections = await createTestingConnections({ entities: [Test], - // Only supported on mysql - enabledDrivers: ["mysql"] + // Only supported on postgres, cockroachdb, and mysql + enabledDrivers: ["postgres", "cockroachdb", "mysql"] })); beforeEach(() => reloadTestingDatabases(connections)); after(() => closeTestingConnections(connections)); diff --git a/test/functional/schema-builder/change-column.ts b/test/functional/schema-builder/change-column.ts index d5e752336e3..b39cca93173 100644 --- a/test/functional/schema-builder/change-column.ts +++ b/test/functional/schema-builder/change-column.ts @@ -250,7 +250,7 @@ describe("schema builder > change column", () => { it("should correctly change column comment", () => Promise.all(connections.map(async connection => { // Skip thie contents of this test if not one of the drivers that support comments - if (!(connection.driver instanceof MysqlDriver)) { + if (!(connection.driver instanceof CockroachDriver || connection.driver instanceof PostgresDriver || connection.driver instanceof MysqlDriver)) { return; } From c0d691d5d5d8043af4882edc25c345389c09b94b Mon Sep 17 00:00:00 2001 From: Omar Diab Date: Tue, 20 Oct 2020 01:59:01 +0900 Subject: [PATCH 151/212] Allow Error to be a type of logQueryError param (#6934) I haven't inspected the code to know if string or any other type does get returned, but this can at least inform people without needing to inspect the code that it can be an easily parsable Error instance. --- src/logger/Logger.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/logger/Logger.ts b/src/logger/Logger.ts index 3bb677fbea6..4925cfa83e0 100644 --- a/src/logger/Logger.ts +++ b/src/logger/Logger.ts @@ -13,7 +13,7 @@ export interface Logger { /** * Logs query that is failed. */ - logQueryError(error: string, query: string, parameters?: any[], queryRunner?: QueryRunner): any; + logQueryError(error: string | Error, query: string, parameters?: any[], queryRunner?: QueryRunner): any; /** * Logs query that is slow. @@ -36,4 +36,4 @@ export interface Logger { */ log(level: "log"|"info"|"warn", message: any, queryRunner?: QueryRunner): any; -} \ No newline at end of file +} From 06903d1c914e8082620dbf16551caa302862d328 Mon Sep 17 00:00:00 2001 From: Travis Watkins Date: Mon, 19 Oct 2020 23:31:18 -0500 Subject: [PATCH 152/212] fix: Only check for discriminator conflicts on STI entities (#2985) If an entity has the same discriminator value as one using `TableInheritance` this should be allowed as there is no way for them to conflict. This commit also fixes the discriminatorColumn check to check all the entities it should be checking. Only the parent in an STI setup has the "STI" inheritancePattern, the children just have the "entity-child" tableType. Before two children with the same discriminatorValue would be (incorrectly) allowed as they'd never even get checked. Fixes #2984 --- .../EntityMetadataValidator.ts | 7 +++++-- test/github-issues/2984/entity/commit/note.ts | 9 ++++++++ test/github-issues/2984/entity/issue/note.ts | 10 +++++++++ .../2984/entity/issue/ownernote.ts | 10 +++++++++ test/github-issues/2984/entity/wiki/note.ts | 10 +++++++++ .../2984/entity/wiki/ownernote.ts | 10 +++++++++ test/github-issues/2984/issue-2984.ts | 21 +++++++++++++++++++ 7 files changed, 75 insertions(+), 2 deletions(-) create mode 100755 test/github-issues/2984/entity/commit/note.ts create mode 100755 test/github-issues/2984/entity/issue/note.ts create mode 100644 test/github-issues/2984/entity/issue/ownernote.ts create mode 100755 test/github-issues/2984/entity/wiki/note.ts create mode 100644 test/github-issues/2984/entity/wiki/ownernote.ts create mode 100644 test/github-issues/2984/issue-2984.ts diff --git a/src/metadata-builder/EntityMetadataValidator.ts b/src/metadata-builder/EntityMetadataValidator.ts index 2e94c3ab333..41fc1b99b18 100644 --- a/src/metadata-builder/EntityMetadataValidator.ts +++ b/src/metadata-builder/EntityMetadataValidator.ts @@ -58,7 +58,7 @@ export class EntityMetadataValidator { // validate if table is using inheritance it has a discriminator // also validate if discriminator values are not empty and not repeated - if (entityMetadata.inheritancePattern === "STI") { + if (entityMetadata.inheritancePattern === "STI" || entityMetadata.tableType === "entity-child") { if (!entityMetadata.discriminatorColumn) throw new Error(`Entity ${entityMetadata.name} using single-table inheritance, it should also have a discriminator column. Did you forget to put discriminator column options?`); @@ -66,7 +66,10 @@ export class EntityMetadataValidator { throw new Error(`Entity ${entityMetadata.name} has empty discriminator value. Discriminator value should not be empty.`); const sameDiscriminatorValueEntityMetadata = allEntityMetadatas.find(metadata => { - return metadata !== entityMetadata && metadata.discriminatorValue === entityMetadata.discriminatorValue; + return metadata !== entityMetadata + && (metadata.inheritancePattern === "STI" || metadata.tableType === "entity-child") + && metadata.discriminatorValue === entityMetadata.discriminatorValue + && metadata.inheritanceTree.some(parent => entityMetadata.inheritanceTree.indexOf(parent) !== -1); }); if (sameDiscriminatorValueEntityMetadata) throw new Error(`Entities ${entityMetadata.name} and ${sameDiscriminatorValueEntityMetadata.name} have the same discriminator values. Make sure they are different while using the @ChildEntity decorator.`); diff --git a/test/github-issues/2984/entity/commit/note.ts b/test/github-issues/2984/entity/commit/note.ts new file mode 100755 index 00000000000..555c1523dbf --- /dev/null +++ b/test/github-issues/2984/entity/commit/note.ts @@ -0,0 +1,9 @@ +import {Entity, PrimaryGeneratedColumn} from "../../../../../src"; + +@Entity({name: "commitNote"}) +export class Note { + + @PrimaryGeneratedColumn() + public id: number; + +} diff --git a/test/github-issues/2984/entity/issue/note.ts b/test/github-issues/2984/entity/issue/note.ts new file mode 100755 index 00000000000..8b0368f0a18 --- /dev/null +++ b/test/github-issues/2984/entity/issue/note.ts @@ -0,0 +1,10 @@ +import {Entity, PrimaryGeneratedColumn, TableInheritance} from "../../../../../src"; + +@Entity({name: "issueNote"}) +@TableInheritance({column: {type: "varchar", name: "type"}}) +export class Note { + + @PrimaryGeneratedColumn() + public id: number; + +} diff --git a/test/github-issues/2984/entity/issue/ownernote.ts b/test/github-issues/2984/entity/issue/ownernote.ts new file mode 100644 index 00000000000..a76663d4c22 --- /dev/null +++ b/test/github-issues/2984/entity/issue/ownernote.ts @@ -0,0 +1,10 @@ +import {ChildEntity, Column} from "../../../../../src"; +import {Note} from "./note"; + +@ChildEntity() +export class OwnerNote extends Note { + + @Column() + public owner: string; + +} diff --git a/test/github-issues/2984/entity/wiki/note.ts b/test/github-issues/2984/entity/wiki/note.ts new file mode 100755 index 00000000000..b678caa5c06 --- /dev/null +++ b/test/github-issues/2984/entity/wiki/note.ts @@ -0,0 +1,10 @@ +import {Entity, PrimaryGeneratedColumn, TableInheritance} from "../../../../../src"; + +@Entity({name: "wikiNote"}) +@TableInheritance({column: {type: "varchar", name: "type"}}) +export class Note { + + @PrimaryGeneratedColumn() + public id: number; + +} diff --git a/test/github-issues/2984/entity/wiki/ownernote.ts b/test/github-issues/2984/entity/wiki/ownernote.ts new file mode 100644 index 00000000000..a76663d4c22 --- /dev/null +++ b/test/github-issues/2984/entity/wiki/ownernote.ts @@ -0,0 +1,10 @@ +import {ChildEntity, Column} from "../../../../../src"; +import {Note} from "./note"; + +@ChildEntity() +export class OwnerNote extends Note { + + @Column() + public owner: string; + +} diff --git a/test/github-issues/2984/issue-2984.ts b/test/github-issues/2984/issue-2984.ts new file mode 100644 index 00000000000..9e8b18acc15 --- /dev/null +++ b/test/github-issues/2984/issue-2984.ts @@ -0,0 +1,21 @@ +import "reflect-metadata"; + +import {closeTestingConnections, createTestingConnections, reloadTestingDatabases} from "../../utils/test-utils"; +import {Connection} from "../../../src"; + +describe("github issues > #2984 Discriminator conflict reported even for non-inherited tables", () => { + + let connections: Connection[]; + before(async () => connections = await createTestingConnections({ + entities: [__dirname + "/entity/**/*{.js,.ts}"], + })); + beforeEach(() => reloadTestingDatabases(connections)); + after(() => closeTestingConnections(connections)); + + it("should load entities even with the same discriminator", () => Promise.all(connections.map(async connection => { + connection.entityMetadatas.should.have.length(5); + connection.entityMetadatas.forEach(metadata => + metadata.discriminatorValue!.should.be.oneOf(["Note", "OwnerNote"])); + }))); + +}); From 37f0d8f7938ee5dbcf899a7f2855ea6dc6dc604e Mon Sep 17 00:00:00 2001 From: Leonardo Falk Date: Wed, 21 Oct 2020 02:18:23 -0300 Subject: [PATCH 153/212] fix: ILike operator generally available for any driver (#6945) --- src/query-builder/QueryBuilder.ts | 10 +++++++++- .../repository-find-operators.ts | 6 ------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/query-builder/QueryBuilder.ts b/src/query-builder/QueryBuilder.ts index 17e4cd37932..6482b6de28b 100644 --- a/src/query-builder/QueryBuilder.ts +++ b/src/query-builder/QueryBuilder.ts @@ -15,6 +15,8 @@ import {QueryDeepPartialEntity} from "./QueryPartialEntity"; import {EntityMetadata} from "../metadata/EntityMetadata"; import {ColumnMetadata} from "../metadata/ColumnMetadata"; import {SqljsDriver} from "../driver/sqljs/SqljsDriver"; +import {PostgresDriver} from "../driver/postgres/PostgresDriver"; +import {CockroachDriver} from "../driver/cockroachdb/CockroachDriver"; import {SqlServerDriver} from "../driver/sqlserver/SqlServerDriver"; import {OracleDriver} from "../driver/oracle/OracleDriver"; import {EntitySchema} from "../"; @@ -914,6 +916,8 @@ export abstract class QueryBuilder { * Gets SQL needs to be inserted into final query. */ protected computeFindOperatorExpression(operator: FindOperator, aliasPath: string, parameters: any[]): string { + const { driver } = this.connection; + switch (operator.type) { case "not": if (operator.child) { @@ -932,7 +936,11 @@ export abstract class QueryBuilder { case "equal": return `${aliasPath} = ${parameters[0]}`; case "ilike": - return `${aliasPath} ILIKE ${parameters[0]}`; + if (driver instanceof PostgresDriver || driver instanceof CockroachDriver) { + return `${aliasPath} ILIKE ${parameters[0]}`; + } + + return `UPPER(${aliasPath}) LIKE UPPER(${parameters[0]})`; case "like": return `${aliasPath} LIKE ${parameters[0]}`; case "between": diff --git a/test/functional/repository/find-options-operators/repository-find-operators.ts b/test/functional/repository/find-options-operators/repository-find-operators.ts index 249f2bedd08..b41b1352d68 100644 --- a/test/functional/repository/find-options-operators/repository-find-operators.ts +++ b/test/functional/repository/find-options-operators/repository-find-operators.ts @@ -273,9 +273,6 @@ describe("repository > find options > operators", () => { }))); it("ilike", () => Promise.all(connections.map(async connection => { - if (!(connection.driver instanceof PostgresDriver)) - return; - // insert some fake data const post1 = new Post(); post1.title = "about #1"; @@ -295,9 +292,6 @@ describe("repository > find options > operators", () => { }))); it("not(ilike)", () => Promise.all(connections.map(async connection => { - if (!(connection.driver instanceof PostgresDriver)) - return; - // insert some fake data const post1 = new Post(); post1.title = "about #1"; From 7ec1b75f12832e4d99e1ed0cef40755f2b6d650a Mon Sep 17 00:00:00 2001 From: Ilyas Foo Date: Wed, 21 Oct 2020 13:56:38 +0800 Subject: [PATCH 154/212] fix: TreeRepository based entities primary column supports custom name. (#6942) Previously "id" was hardcoded, thus errors when an entity has a custom primary column name other than "id". Now it fetches the column name from metadata instead. --- src/repository/TreeRepository.ts | 2 +- test/github-issues/6947/entity/Category.ts | 17 +++++++ test/github-issues/6947/issue-6947.ts | 54 ++++++++++++++++++++++ 3 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 test/github-issues/6947/entity/Category.ts create mode 100644 test/github-issues/6947/issue-6947.ts diff --git a/src/repository/TreeRepository.ts b/src/repository/TreeRepository.ts index 376a26693aa..f15aad1f915 100644 --- a/src/repository/TreeRepository.ts +++ b/src/repository/TreeRepository.ts @@ -265,7 +265,7 @@ export class TreeRepository extends Repository { const parentEntityId = this.metadata.primaryColumns[0].getEntityValue(entity); const childRelationMaps = relationMaps.filter(relationMap => relationMap.parentId === parentEntityId); const childIds = new Set(childRelationMaps.map(relationMap => relationMap.id)); - entity[childProperty] = entities.filter(entity => childIds.has(entity.id)); + entity[childProperty] = entities.filter(entity => childIds.has(entity[this.metadata.primaryColumns[0].propertyName])); entity[childProperty].forEach((childEntity: any) => { this.buildChildrenEntityTree(childEntity, entities, relationMaps); }); diff --git a/test/github-issues/6947/entity/Category.ts b/test/github-issues/6947/entity/Category.ts new file mode 100644 index 00000000000..7ef4ca9faef --- /dev/null +++ b/test/github-issues/6947/entity/Category.ts @@ -0,0 +1,17 @@ +import { Entity, PrimaryGeneratedColumn, Column, Tree, TreeParent, TreeChildren } from "../../../../src"; + +@Entity() +@Tree("closure-table") +export class Category { + @PrimaryGeneratedColumn() + cat_id: number; + + @Column() + cat_name: string; + + @TreeParent() + parent: Category; + + @TreeChildren({ cascade: true }) + children: Category[]; +} diff --git a/test/github-issues/6947/issue-6947.ts b/test/github-issues/6947/issue-6947.ts new file mode 100644 index 00000000000..25cf1176372 --- /dev/null +++ b/test/github-issues/6947/issue-6947.ts @@ -0,0 +1,54 @@ +import "reflect-metadata"; +import { Category } from "./entity/Category"; +import { Connection } from "../../../src/connection/Connection"; +import { + closeTestingConnections, + createTestingConnections, + reloadTestingDatabases, +} from "../../../test/utils/test-utils"; + +describe("github issues > #6947 Custom primary column for TreeRepository based entities unable to get tree descendants", () => { + let connections: Connection[]; + before( + async () => + (connections = await createTestingConnections({ + entities: [Category], + })) + ); + beforeEach(() => reloadTestingDatabases(connections)); + after(() => closeTestingConnections(connections)); + + it("entities with custom primary column names should work", () => + Promise.all( + connections.map(async (connection) => { + const categoryRepository = connection.getTreeRepository( + Category + ); + + const parent = new Category(); + parent.cat_name = "parent"; + await categoryRepository.save(parent); + + const child = new Category(); + child.cat_name = "child"; + child.parent = parent; + await categoryRepository.save(child); + + const tree = await categoryRepository.findDescendantsTree( + (await categoryRepository.findOne({ cat_name: "parent" }))! + ); + + tree.should.deep.include({ + cat_id: 1, + cat_name: "parent", + children: [ + { + cat_id: 2, + cat_name: "child", + children: [], + }, + ], + }); + }) + )); +}); From 9a0497b533b2f6896b8e7d189b36dd3892e58007 Mon Sep 17 00:00:00 2001 From: James Ward Date: Wed, 21 Oct 2020 04:17:47 -0400 Subject: [PATCH 155/212] fix: support combination of many-to-one/cacade/composte PK (#6417) handle setting values deeply in entities with relations in ColumnMetadata, also check for a virtual relationship column in rawsqlresultstoentitytransformer this allows us to handle a case where `many-to-one` with explicit composite PKs columns were failing to persist a second time- instead of correctly updating the field they would cause an insert to occur leading to a unique PK constraint error --- src/metadata/ColumnMetadata.ts | 13 +++- src/persistence/Subject.ts | 3 +- .../RawSqlResultsToEntityTransformer.ts | 2 +- test/github-issues/6416/entity/Post.ts | 52 +++++++++++++++ .../6416/entity/PostAttachment.ts | 35 ++++++++++ test/github-issues/6416/entity/PostTag.ts | 51 ++++++++++++++ test/github-issues/6416/issue-6416.ts | 66 +++++++++++++++++++ 7 files changed, 219 insertions(+), 3 deletions(-) create mode 100644 test/github-issues/6416/entity/Post.ts create mode 100644 test/github-issues/6416/entity/PostAttachment.ts create mode 100644 test/github-issues/6416/entity/PostTag.ts create mode 100644 test/github-issues/6416/issue-6416.ts diff --git a/src/metadata/ColumnMetadata.ts b/src/metadata/ColumnMetadata.ts index 94d090bba50..d4e1d36b0c8 100644 --- a/src/metadata/ColumnMetadata.ts +++ b/src/metadata/ColumnMetadata.ts @@ -662,7 +662,18 @@ export class ColumnMetadata { return extractEmbeddedColumnValue([...this.embeddedMetadata.embeddedMetadataTree], entity); } else { - entity[this.propertyName] = value; + // we write a deep object in this entity only if the column is virtual + // because if its not virtual it means the user defined a real column for this relation + // also we don't do it if column is inside a junction table + if (!this.entityMetadata.isJunction && this.isVirtual && this.referencedColumn && this.referencedColumn.propertyName !== this.propertyName) { + if (!(this.propertyName in entity)) { + entity[this.propertyName] = {}; + } + + entity[this.propertyName][this.referencedColumn.propertyName] = value; + } else { + entity[this.propertyName] = value; + } } } diff --git a/src/persistence/Subject.ts b/src/persistence/Subject.ts index 988509fbb7d..80405b1ffee 100644 --- a/src/persistence/Subject.ts +++ b/src/persistence/Subject.ts @@ -289,7 +289,8 @@ export class Subject { if (this.parentSubject) { this.metadata.primaryColumns.forEach(primaryColumn => { if (primaryColumn.relationMetadata && primaryColumn.relationMetadata.inverseEntityMetadata === this.parentSubject!.metadata) { - primaryColumn.setEntityValue(this.entityWithFulfilledIds!, this.parentSubject!.entity); + const value = primaryColumn.referencedColumn!.getEntityValue(this.parentSubject!.entity!); + primaryColumn.setEntityValue(this.entityWithFulfilledIds!, value); } }); } diff --git a/src/query-builder/transformer/RawSqlResultsToEntityTransformer.ts b/src/query-builder/transformer/RawSqlResultsToEntityTransformer.ts index e79fd24d633..05dc941ac78 100644 --- a/src/query-builder/transformer/RawSqlResultsToEntityTransformer.ts +++ b/src/query-builder/transformer/RawSqlResultsToEntityTransformer.ts @@ -237,7 +237,7 @@ export class RawSqlResultsToEntityTransformer { const idMap = columns.reduce((idMap, column) => { let value = result[column.databaseName]; if (relation.isOneToMany || relation.isOneToOneNotOwner) { - if (column.referencedColumn) // if column is a relation + if (column.isVirtual && column.referencedColumn && column.referencedColumn.propertyName !== column.propertyName) // if column is a relation value = column.referencedColumn.createValueMap(value); return OrmUtils.mergeDeep(idMap, column.createValueMap(value)); diff --git a/test/github-issues/6416/entity/Post.ts b/test/github-issues/6416/entity/Post.ts new file mode 100644 index 00000000000..d70667904e0 --- /dev/null +++ b/test/github-issues/6416/entity/Post.ts @@ -0,0 +1,52 @@ +import { EntitySchema } from "../../../../src"; + +import PostTag from "./PostTag"; +import PostAttachment from "./PostAttachment"; + +let id = 0; + +export default class Post { + postId: number; + + otherId: number; + + tags: PostTag[]; + + attachments: PostAttachment[]; + + constructor() { + this.postId = id++; + this.otherId = id++; + } +} + +export const PostSchema = new EntitySchema({ + name: "Post", + target: Post, + columns: { + otherId: { + type: Number, + primary: true, + nullable: false + }, + postId: { + type: Number, + primary: true, + nullable: false + } + }, + relations: { + tags: { + target: () => PostTag, + type: "one-to-many", + inverseSide: "post", + cascade: true + }, + attachments: { + target: () => PostAttachment, + type: "one-to-many", + inverseSide: "post", + cascade: true + } + } +}); diff --git a/test/github-issues/6416/entity/PostAttachment.ts b/test/github-issues/6416/entity/PostAttachment.ts new file mode 100644 index 00000000000..2408e5816ed --- /dev/null +++ b/test/github-issues/6416/entity/PostAttachment.ts @@ -0,0 +1,35 @@ +import { EntitySchema } from "../../../../src"; + +import Post from "./Post"; + +let id = 0; + +export default class PostAttachment { + attachmentId: number; + + post: Post; + + constructor () { + this.attachmentId = id++; + } +} + +export const PostAttachmentSchema = new EntitySchema({ + name: "PostAttachment", + target: PostAttachment, + columns: { + attachmentId: { + type: Number, + primary: true, + nullable: false + } + }, + relations: { + post: { + primary: true, + nullable: false, + target: () => Post, + type: "many-to-one" + } + } +}); diff --git a/test/github-issues/6416/entity/PostTag.ts b/test/github-issues/6416/entity/PostTag.ts new file mode 100644 index 00000000000..1217085738a --- /dev/null +++ b/test/github-issues/6416/entity/PostTag.ts @@ -0,0 +1,51 @@ +import { EntitySchema } from "../../../../src"; + +import Post from "./Post"; + +let id = 0; + +export default class PostTag { + tagId: number; + + tagOtherId: string; + + tagPostId: string; + + post: Post; + + constructor () { + this.tagId = id++; + } +} + +export const PostTagSchema = new EntitySchema({ + name: "PostTag", + target: PostTag, + columns: { + tagOtherId: { + type: Number, + primary: true + }, + tagPostId: { + type: Number, + primary: true + }, + tagId: { + type: Number, + primary: true, + nullable: false + } + }, + relations: { + post: { + primary: true, + nullable: false, + target: () => Post, + type: "many-to-one", + joinColumn: [ + { name: "tagPostId", referencedColumnName: "postId" }, + { name: "tagOtherId", referencedColumnName: "otherId" } + ] + } + } +}); diff --git a/test/github-issues/6416/issue-6416.ts b/test/github-issues/6416/issue-6416.ts new file mode 100644 index 00000000000..f09ab22b212 --- /dev/null +++ b/test/github-issues/6416/issue-6416.ts @@ -0,0 +1,66 @@ +import {closeTestingConnections, createTestingConnections, reloadTestingDatabases} from "../../utils/test-utils"; +import {Connection} from "../../../src"; + +import { assert } from "chai"; + +import Post, { PostSchema } from "./entity/Post"; +import PostTag, { PostTagSchema } from "./entity/PostTag"; +import PostAttachment, { PostAttachmentSchema } from "./entity/PostAttachment"; + +describe("github issues > #6399 Combining ManyToOne, Cascade, & Composite Primary Key causes Unique Constraint issues", () => { + + let connections: Connection[]; + before(async () => connections = await createTestingConnections({ + entities: [PostSchema, PostTagSchema, PostAttachmentSchema], + enabledDrivers: ["sqlite"], + })); + beforeEach(() => reloadTestingDatabases(connections)); + after(() => closeTestingConnections(connections)); + + it("persisting the cascading entities should succeed", () => Promise.all(connections.map(async connection => { + + const post = new Post(); + const postTag = new PostTag(); + post.tags = [postTag]; + + await connection.manager.save(post, { reload: true }); + + try { + await connection.manager.save(post); + } catch (e) { + assert.fail(e.toString(), null, "Second save had an exception"); + } + }))); + + it("persisting the cascading entities without JoinColumn should succeed", () => Promise.all(connections.map(async connection => { + + const post = new Post(); + const postAttachment = new PostAttachment(); + post.attachments = [postAttachment]; + + await connection.manager.save(post, { reload: true }); + + try { + await connection.manager.save(post); + } catch (e) { + assert.fail(e.toString(), null, "Second save had an exception"); + } + }))); + + it("persisting the child entity should succeed", () => Promise.all(connections.map(async connection => { + const post = new Post(); + + await connection.manager.save(post); + + const postTag = new PostTag(); + postTag.post = post; + + await connection.manager.save(postTag, { reload: true }); + + try { + await connection.manager.save(postTag); + } catch (e) { + assert.fail(e.toString(), null, "Second save had an exception"); + } + }))); +}); From d624ca3b4efa7bbffe4802d04c5950aa5ac1e488 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Abd=C3=BCssamet=20=C3=96zay?= Date: Wed, 21 Oct 2020 13:18:25 +0200 Subject: [PATCH 156/212] docs: update usage-with-javascript.md (#6952) --- docs/usage-with-javascript.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/usage-with-javascript.md b/docs/usage-with-javascript.md index 6e883022f8a..fcce717d8d6 100644 --- a/docs/usage-with-javascript.md +++ b/docs/usage-with-javascript.md @@ -16,7 +16,7 @@ typeorm.createConnection({ password: "admin", database: "test", synchronize: true, - entitySchemas: [ + entities: [ require("./entity/Post"), require("./entity/Category") ] @@ -102,4 +102,4 @@ module.exports = { }; ``` -You can checkout this example [typeorm/javascript-example](https://github.com/typeorm/javascript-example) to learn more. \ No newline at end of file +You can checkout this example [typeorm/javascript-example](https://github.com/typeorm/javascript-example) to learn more. From 43e7f394932a510e50f92911c22f9e61c4e192ab Mon Sep 17 00:00:00 2001 From: Duong Le Date: Thu, 22 Oct 2020 15:10:25 +0700 Subject: [PATCH 157/212] docs: Remove unused variable (#6957) * docs: remove unused variable in many-to-many-relations.md * docs: remove unused variable in one-to-one-relations.md --- docs/many-to-many-relations.md | 16 ++++++++-------- docs/one-to-one-relations.md | 6 +++--- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/docs/many-to-many-relations.md b/docs/many-to-many-relations.md index 10a53f3e95f..1de5c9d0011 100644 --- a/docs/many-to-many-relations.md +++ b/docs/many-to-many-relations.md @@ -44,7 +44,7 @@ export class Question { @Column() text: string; - @ManyToMany(type => Category) + @ManyToMany(() => Category) @JoinTable() categories: Category[]; @@ -146,7 +146,7 @@ export class Question { @PrimaryGeneratedColumn() id: number; - @ManyToMany(type => Category, category => category.questions, { + @ManyToMany(() => Category, category => category.questions, { cascade: true }) @JoinTable() @@ -197,7 +197,7 @@ export class Category { @Column() name: string; - @ManyToMany(type => Question, question => question.categories) + @ManyToMany(() => Question, question => question.categories) questions: Question[]; } @@ -219,7 +219,7 @@ export class Question { @Column() text: string; - @ManyToMany(type => Category, category => category.questions) + @ManyToMany(() => Category, category => category.questions) @JoinTable() categories: Category[]; @@ -263,10 +263,10 @@ export class PostToCategory { @Column() public order!: number; - @ManyToOne(type => Post, post => post.postToCategories) + @ManyToOne(() => Post, post => post.postToCategories) public post!: Post; - @ManyToOne(type => Category, category => category.postToCategories) + @ManyToOne(() => Category, category => category.postToCategories) public category!: Category; } ``` @@ -276,11 +276,11 @@ Additionally you will have to add a relationship like the following to `Post` an ```typescript // category.ts ... -@OneToMany(type => PostToCategory, postToCategory => postToCategory.category) +@OneToMany(() => PostToCategory, postToCategory => postToCategory.category) public postToCategories!: PostToCategory[]; // post.ts ... -@OneToMany(type => PostToCategory, postToCategory => postToCategory.post) +@OneToMany(() => PostToCategory, postToCategory => postToCategory.post) public postToCategories!: PostToCategory[]; ``` diff --git a/docs/one-to-one-relations.md b/docs/one-to-one-relations.md index ee5c86774fe..4188e50e5a2 100644 --- a/docs/one-to-one-relations.md +++ b/docs/one-to-one-relations.md @@ -35,7 +35,7 @@ export class User { @Column() name: string; - @OneToOne(type => Profile) + @OneToOne(() => Profile) @JoinColumn() profile: Profile; @@ -125,7 +125,7 @@ export class Profile { @Column() photo: string; - @OneToOne(type => User, user => user.profile) // specify inverse side as a second parameter + @OneToOne(() => User, user => user.profile) // specify inverse side as a second parameter user: User; } @@ -144,7 +144,7 @@ export class User { @Column() name: string; - @OneToOne(type => Profile, profile => profile.user) // specify inverse side as a second parameter + @OneToOne(() => Profile, profile => profile.user) // specify inverse side as a second parameter @JoinColumn() profile: Profile; From fa23f36313d80a76539d7fa9d065a96dc5086fb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Abd=C3=BCssamet=20=C3=96zay?= Date: Thu, 22 Oct 2020 10:10:59 +0200 Subject: [PATCH 158/212] docs: update usage-with-javascript.md (#6955) --- docs/usage-with-javascript.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/usage-with-javascript.md b/docs/usage-with-javascript.md index fcce717d8d6..0ecf7cbf099 100644 --- a/docs/usage-with-javascript.md +++ b/docs/usage-with-javascript.md @@ -59,7 +59,8 @@ typeorm.createConnection({ ```typescript module.exports = { - name: "Category", + name: "Category", // Will use table name `category` as default behaviour. + tableName: "categories", // Optional: Provide `tableName` property to override the default behaviour for table name. columns: { id: { primary: true, @@ -77,7 +78,8 @@ module.exports = { ```typescript module.exports = { - name: "Post", + name: "Post", // Will use table name `post` as default behaviour. + tableName: "posts", // Optional: Provide `tableName` property to override the default behaviour for table name. columns: { id: { primary: true, From 82df614c6eaf821672e978fd27e5d41a4419b0eb Mon Sep 17 00:00:00 2001 From: Rohan Talip Date: Thu, 22 Oct 2020 17:01:34 -0700 Subject: [PATCH 159/212] docs: fix typo in entities.md : hustle --> hassle (#6963) --- docs/entities.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/entities.md b/docs/entities.md index 0bd5cbcd1b6..f8d12af430a 100644 --- a/docs/entities.md +++ b/docs/entities.md @@ -480,7 +480,7 @@ Note you **MUST NOT** have any comma in values you write. There is a special column type called `simple-json` which can store any values which can be stored in database via JSON.stringify. Very useful when you do not have json type in your database and you want to store and load object -without any hustle. +without any hassle. For example: ```typescript From 6ed990666604ca9b8c0029d4fe972a039ef28570 Mon Sep 17 00:00:00 2001 From: Dr Nic Williams Date: Sun, 25 Oct 2020 10:18:14 +1000 Subject: [PATCH 160/212] fix: use pg ^8 in `init` command without postgres v8+ nodejs 14+ will hang --- src/commands/InitCommand.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/InitCommand.ts b/src/commands/InitCommand.ts index 3dbe7f2c51f..62922a30df5 100644 --- a/src/commands/InitCommand.ts +++ b/src/commands/InitCommand.ts @@ -548,7 +548,7 @@ Steps to run this project: break; case "postgres": case "cockroachdb": - packageJson.dependencies["pg"] = "^7.3.0"; + packageJson.dependencies["pg"] = "^8.4.0"; break; case "sqlite": packageJson.dependencies["sqlite3"] = "^4.0.3"; From e71ff10b9e466455fc807d718cfd6ca6001bcff0 Mon Sep 17 00:00:00 2001 From: James Ward Date: Mon, 26 Oct 2020 01:41:54 -0400 Subject: [PATCH 161/212] chore: add issue type templates & link to support (#6972) --- .github/ISSUE_TEMPLATE/bug-report.md | 127 ++++++++++++++++++ .github/ISSUE_TEMPLATE/config.yml | 4 + .github/ISSUE_TEMPLATE/documentation-issue.md | 79 +++++++++++ .github/ISSUE_TEMPLATE/feature-request.md | 89 ++++++++++++ ISSUE_TEMPLATE.md | 42 ------ 5 files changed, 299 insertions(+), 42 deletions(-) create mode 100644 .github/ISSUE_TEMPLATE/bug-report.md create mode 100644 .github/ISSUE_TEMPLATE/config.yml create mode 100644 .github/ISSUE_TEMPLATE/documentation-issue.md create mode 100644 .github/ISSUE_TEMPLATE/feature-request.md delete mode 100644 ISSUE_TEMPLATE.md diff --git a/.github/ISSUE_TEMPLATE/bug-report.md b/.github/ISSUE_TEMPLATE/bug-report.md new file mode 100644 index 00000000000..2db7dc3466f --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug-report.md @@ -0,0 +1,127 @@ +--- +name: "🐛 Bug Report" +about: Report a reproducible bug or regression. +title: '' +labels: requires triage, bug +assignees: '' + +--- + + + +## Issue Description + +### Expected Behavior + + + + +### Actual Behavior + + + +``` +// include the output in code tags like these! +``` + + +### Steps to Reproduce + + + +1. +2. + +```typescript +// insert code here +``` + +### My Environment + + + +| Dependency | Version | +| --- | --- | +| Operating System | | +| Node.js version | vX.Y.ZZZ | +| Typescript version | vX.Y.ZZZ | +| TypeORM version | vX.Y.ZZZ | + + +### Additional Context + + + + +### Relevant Database Driver(s) + + + +- [ ] `aurora-data-api` +- [ ] `aurora-data-api-pg` +- [ ] `better-sqlite3` +- [ ] `cockroachdb` +- [ ] `cordova` +- [ ] `expo` +- [ ] `mongodb` +- [ ] `mysql` +- [ ] `nativescript` +- [ ] `oracle` +- [ ] `postgres` +- [ ] `react-native` +- [ ] `sap` +- [ ] `sqlite` +- [ ] `sqlite-abstract` +- [ ] `sqljs` +- [ ] `sqlserver` + + +### Are you willing to resolve this issue by submitting a Pull Request? + + + +- [ ] Yes, I have the time, and I know how to start. +- [ ] Yes, I have the time, but I don't know how to start. I would need guidance. +- [ ] No, I don't have the time, although I believe I could do it if I had the time... +- [ ] No, I don't have the time and I wouldn't even know how to start. + + + diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 00000000000..94d91af328b --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,4 @@ +contact_links: + - name: 🤔 Questions, General Support, and Help + url: https://github.com/typeorm/typeorm/blob/master/docs/support.md + about: This issue tracker is not for support questions. Please refer to the TypeORM community support documentation. diff --git a/.github/ISSUE_TEMPLATE/documentation-issue.md b/.github/ISSUE_TEMPLATE/documentation-issue.md new file mode 100644 index 00000000000..6efa7f99203 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/documentation-issue.md @@ -0,0 +1,79 @@ +--- +name: 📝 Documentation Issue +about: Documentation is unclear or otherwise insufficient. +title: '' +labels: documentation, requires triage +assignees: '' + +--- + +## Documentation Issue + +### What was unclear or otherwise insufficient? + + + + +### Recommended Fix + + + + +### Additional Context + + + + +### Relevant Database Driver(s) + + + +- [ ] `aurora-data-api` +- [ ] `aurora-data-api-pg` +- [ ] `better-sqlite3` +- [ ] `cockroachdb` +- [ ] `cordova` +- [ ] `expo` +- [ ] `mongodb` +- [ ] `mysql` +- [ ] `nativescript` +- [ ] `oracle` +- [ ] `postgres` +- [ ] `react-native` +- [ ] `sap` +- [ ] `sqlite` +- [ ] `sqlite-abstract` +- [ ] `sqljs` +- [ ] `sqlserver` + + +### Are you willing to resolve this issue by submitting a Pull Request? + + + +- [ ] Yes, I have the time, and I know how to start. +- [ ] Yes, I have the time, but I don't know how to start. I would need guidance. +- [ ] No, I don't have the time, although I believe I could do it if I had the time... +- [ ] No, I don't have the time and I wouldn't even know how to start. + + + diff --git a/.github/ISSUE_TEMPLATE/feature-request.md b/.github/ISSUE_TEMPLATE/feature-request.md new file mode 100644 index 00000000000..a250dadc7ab --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature-request.md @@ -0,0 +1,89 @@ +--- +name: 🌈 Feature request +about: Suggest an amazing new idea for this project +title: '' +labels: new feature, requires triage +assignees: '' + +--- + +## Feature Description + +### The Problem + + + + +### The Solution + + + + +### Considered Alternatives + + + + +### Additional Context + + + + +### Relevant Database Driver(s) + + + +- [ ] `aurora-data-api` +- [ ] `aurora-data-api-pg` +- [ ] `better-sqlite3` +- [ ] `cockroachdb` +- [ ] `cordova` +- [ ] `expo` +- [ ] `mongodb` +- [ ] `mysql` +- [ ] `nativescript` +- [ ] `oracle` +- [ ] `postgres` +- [ ] `react-native` +- [ ] `sap` +- [ ] `sqlite` +- [ ] `sqlite-abstract` +- [ ] `sqljs` +- [ ] `sqlserver` + + +### Are you willing to resolve this issue by submitting a Pull Request? + + + +- [ ] Yes, I have the time, and I know how to start. +- [ ] Yes, I have the time, but I don't know how to start. I would need guidance. +- [ ] No, I don't have the time, although I believe I could do it if I had the time... +- [ ] No, I don't have the time and I wouldn't even know how to start. + + + diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md deleted file mode 100644 index 7dc654f6150..00000000000 --- a/ISSUE_TEMPLATE.md +++ /dev/null @@ -1,42 +0,0 @@ -**Issue type:** - - - -[ ] bug report -[ ] feature request -[ ] documentation issue - -**Database system/driver:** - -[ ] `cordova` -[ ] `mongodb` -[ ] `mssql` -[ ] `mysql` / `mariadb` -[ ] `oracle` -[ ] `postgres` -[ ] `cockroachdb` -[ ] `sqlite` -[ ] `sqljs` -[ ] `react-native` -[ ] `expo` - -**TypeORM version:** - -[ ] `latest` -[ ] `@next` -[ ] `0.x.x` (or put your version here) - -**Steps to reproduce or a small repository showing the problem:** - - From 343042dc6736c93f41eb0efe9f185e4a533b4a0b Mon Sep 17 00:00:00 2001 From: Duong Le Date: Mon, 26 Oct 2020 12:43:39 +0700 Subject: [PATCH 162/212] docs: Remove unused variable (#6971) --- docs/zh_CN/many-to-many-relations.md | 6 +++--- docs/zh_CN/many-to-one-one-to-many-relations.md | 4 ++-- docs/zh_CN/one-to-one-relations.md | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/zh_CN/many-to-many-relations.md b/docs/zh_CN/many-to-many-relations.md index aacd8b87cd6..7f4a6d48cad 100644 --- a/docs/zh_CN/many-to-many-relations.md +++ b/docs/zh_CN/many-to-many-relations.md @@ -32,7 +32,7 @@ export class Question { @Column() text: string; - @ManyToMany(type => Category) + @ManyToMany(() => Category) @JoinTable() categories: Category[]; } @@ -121,7 +121,7 @@ export class Category { @Column() name: string; - @ManyToMany(type => Question, question => question.categories) + @ManyToMany(() => Question, question => question.categories) questions: Question[]; } ``` @@ -141,7 +141,7 @@ export class Question { @Column() text: string; - @ManyToMany(type => Category, category => category.questions) + @ManyToMany(() => Category, category => category.questions) @JoinTable() categories: Category[]; } diff --git a/docs/zh_CN/many-to-one-one-to-many-relations.md b/docs/zh_CN/many-to-one-one-to-many-relations.md index 248c5b5f591..3dcbfd23457 100644 --- a/docs/zh_CN/many-to-one-one-to-many-relations.md +++ b/docs/zh_CN/many-to-one-one-to-many-relations.md @@ -16,7 +16,7 @@ export class Photo { @Column() url: string; - @ManyToOne(type => User, user => user.photos) + @ManyToOne(() => User, user => user.photos) user: User; } ``` @@ -33,7 +33,7 @@ export class User { @Column() name: string; - @OneToMany(type => Photo, photo => photo.user) + @OneToMany(() => Photo, photo => photo.user) photos: Photo[]; } ``` diff --git a/docs/zh_CN/one-to-one-relations.md b/docs/zh_CN/one-to-one-relations.md index 1ec4065d0ae..de00087f337 100644 --- a/docs/zh_CN/one-to-one-relations.md +++ b/docs/zh_CN/one-to-one-relations.md @@ -33,7 +33,7 @@ export class User { @Column() name: string; - @OneToOne(type => Profile) + @OneToOne(() => Profile) @JoinColumn() profile: Profile; } @@ -121,7 +121,7 @@ export class Profile { @Column() photo: string; - @OneToOne(type => User, user => user.profile) // 将另一面指定为第二个参数 + @OneToOne(() => User, user => user.profile) // 将另一面指定为第二个参数 user: User; } ``` @@ -138,7 +138,7 @@ export class User { @Column() name: string; - @OneToOne(type => Profile, profile => profile.user) // 指定另一面作为第二个参数 + @OneToOne(() => Profile, profile => profile.user) // 指定另一面作为第二个参数 @JoinColumn() profile: Profile; } From 3902fd1c9bbc75ee441347497fb448479d54480f Mon Sep 17 00:00:00 2001 From: Dr Nic Williams Date: Mon, 26 Oct 2020 15:51:32 +1000 Subject: [PATCH 163/212] docs: photo.views/isPublished are required fields (#6970) * photo.views is required field In the many-to-many photos/albums example - photo.views is required field * photo.isPublished must be provided Fixes `null value in column "isPublished" violates not-null constraint` --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 3cb75b20728..fbfd6d89d7e 100644 --- a/README.md +++ b/README.md @@ -1205,6 +1205,8 @@ let photo = new Photo(); photo.name = "Me and Bears"; photo.description = "I am near polar bears"; photo.filename = "photo-with-bears.jpg"; +photo.views = 1 +photo.isPublished = true photo.albums = [album1, album2]; await connection.manager.save(photo); From 877e343f73326a2c6b0e0c35d7ee296e7c3e8992 Mon Sep 17 00:00:00 2001 From: James Ward Date: Sun, 25 Oct 2020 23:22:48 -0400 Subject: [PATCH 164/212] chore: include support message on templates & create PR template --- .github/ISSUE_TEMPLATE/bug-report.md | 8 ++-- .github/ISSUE_TEMPLATE/documentation-issue.md | 14 +++++- .github/ISSUE_TEMPLATE/feature-request.md | 14 +++++- .github/PULL_REQUEST_TEMPLATE.md | 47 +++++++++++++++++++ 4 files changed, 75 insertions(+), 8 deletions(-) create mode 100644 .github/PULL_REQUEST_TEMPLATE.md diff --git a/.github/ISSUE_TEMPLATE/bug-report.md b/.github/ISSUE_TEMPLATE/bug-report.md index 2db7dc3466f..aa3d4af1355 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.md +++ b/.github/ISSUE_TEMPLATE/bug-report.md @@ -11,9 +11,9 @@ assignees: '' Please follow the template. If you don't, your issue may be closed. Have a question? This is the TypeORM issue tracker - and not the right place - for general support or questions. + for general support or questions. Instead, check the "Support" Documentation + on the best places to ask questions! - Check the "Support" Documentation on the best places to ask questions! https://github.com/typeorm/typeorm/blob/master/docs/support.md --> @@ -113,7 +113,7 @@ assignees: '' ### Are you willing to resolve this issue by submitting a Pull Request? - [ ] Yes, I have the time, and I know how to start. @@ -123,5 +123,5 @@ assignees: '' diff --git a/.github/ISSUE_TEMPLATE/documentation-issue.md b/.github/ISSUE_TEMPLATE/documentation-issue.md index 6efa7f99203..cf314029803 100644 --- a/.github/ISSUE_TEMPLATE/documentation-issue.md +++ b/.github/ISSUE_TEMPLATE/documentation-issue.md @@ -7,6 +7,16 @@ assignees: '' --- + + ## Documentation Issue ### What was unclear or otherwise insufficient? @@ -65,7 +75,7 @@ assignees: '' ### Are you willing to resolve this issue by submitting a Pull Request? - [ ] Yes, I have the time, and I know how to start. @@ -75,5 +85,5 @@ assignees: '' diff --git a/.github/ISSUE_TEMPLATE/feature-request.md b/.github/ISSUE_TEMPLATE/feature-request.md index a250dadc7ab..c2b13944b72 100644 --- a/.github/ISSUE_TEMPLATE/feature-request.md +++ b/.github/ISSUE_TEMPLATE/feature-request.md @@ -7,6 +7,16 @@ assignees: '' --- + + ## Feature Description ### The Problem @@ -75,7 +85,7 @@ assignees: '' ### Are you willing to resolve this issue by submitting a Pull Request? - [ ] Yes, I have the time, and I know how to start. @@ -85,5 +95,5 @@ assignees: '' diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 00000000000..fd33e7cbf69 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,47 @@ + + +### Description of change + + + + +### Pull-Request Checklist + + + +- [ ] Code is up-to-date with the `master` branch +- [ ] `npm run lint` passes with this change +- [ ] `npm run test` passes with this change +- [ ] This pull request links relevant issues as `Fixes #0000` +- [ ] There are new or updated unit tests validating the change +- [ ] Documentation has been updated to reflect this change +- [ ] The new commits follow conventions explained in [CONTRIBUTING.md](https://github.com/typeorm/typeorm/blob/master/CONTRIBUTING.md) + + From fa86413a7f82f19fc4857665e2e8ad62e15dad43 Mon Sep 17 00:00:00 2001 From: Piotr Kuczynski Date: Mon, 26 Oct 2020 13:39:40 +0100 Subject: [PATCH 165/212] refactor: export LoggerOptions interface (#6976) --- src/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/index.ts b/src/index.ts index 61915963bad..a3e6b7d0203 100644 --- a/src/index.ts +++ b/src/index.ts @@ -99,6 +99,7 @@ export * from "./find-options/JoinOptions"; export * from "./find-options/OrderByCondition"; export * from "./find-options/FindOptionsUtils"; export * from "./logger/Logger"; +export * from "./logger/LoggerOptions"; export * from "./logger/AdvancedConsoleLogger"; export * from "./logger/SimpleConsoleLogger"; export * from "./logger/FileLogger"; From 5f6bbecd6166f1e80ed87d7e6c2c181fe463bdef Mon Sep 17 00:00:00 2001 From: Jurriaan BW <12056384+jjhbw@users.noreply.github.com> Date: Mon, 26 Oct 2020 13:40:42 +0100 Subject: [PATCH 166/212] fix: check if the connection is closed before executing a query. This prevents SQLITE_MISUSE errors (https://sqlite.org/rescode.html#misuse) originating from sqlite itself (#6975) --- src/driver/sqlite/SqliteQueryRunner.ts | 5 +++++ .../sqlite/error-on-query-after-close.ts | 21 +++++++++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 test/functional/sqlite/error-on-query-after-close.ts diff --git a/src/driver/sqlite/SqliteQueryRunner.ts b/src/driver/sqlite/SqliteQueryRunner.ts index 308bb72855b..9e617866597 100644 --- a/src/driver/sqlite/SqliteQueryRunner.ts +++ b/src/driver/sqlite/SqliteQueryRunner.ts @@ -4,6 +4,7 @@ import {AbstractSqliteQueryRunner} from "../sqlite-abstract/AbstractSqliteQueryR import {SqliteConnectionOptions} from "./SqliteConnectionOptions"; import {SqliteDriver} from "./SqliteDriver"; import {Broadcaster} from "../../subscriber/Broadcaster"; +import { ConnectionIsNotSetError } from '../../error/ConnectionIsNotSetError'; /** * Runs queries on a single sqlite database connection. @@ -39,6 +40,10 @@ export class SqliteQueryRunner extends AbstractSqliteQueryRunner { const connection = this.driver.connection; const options = connection.options as SqliteConnectionOptions; + if (!connection.isConnected){ + throw new ConnectionIsNotSetError('sqlite') + } + return new Promise(async (ok, fail) => { const databaseConnection = await this.connect(); diff --git a/test/functional/sqlite/error-on-query-after-close.ts b/test/functional/sqlite/error-on-query-after-close.ts new file mode 100644 index 00000000000..21126ecc9f1 --- /dev/null +++ b/test/functional/sqlite/error-on-query-after-close.ts @@ -0,0 +1,21 @@ +import "reflect-metadata"; +import {expect} from "chai"; +import {Connection} from "../../../src/connection/Connection"; +import {closeTestingConnections, createTestingConnections, reloadTestingDatabases} from "../../utils/test-utils"; + +describe("sqlite driver > throws an error when queried after closing connection", () => { + let connections: Connection[]; + before(async () => connections = await createTestingConnections({ + entities: [], + enabledDrivers: ["sqlite"], + })); + beforeEach(() => reloadTestingDatabases(connections)); + after(() => closeTestingConnections(connections)); + + it("should throw", () => Promise.all(connections.map(async connection => { + await connection.close() + await expect(connection.query('select * from sqlite_master;')).to.rejectedWith( + 'Connection with sqlite database is not established. Check connection configuration.' + ); + }))); +}); From f3ba2420396341ad3b808ea8540ea6a2272ff916 Mon Sep 17 00:00:00 2001 From: James Ward Date: Mon, 26 Oct 2020 08:42:03 -0400 Subject: [PATCH 167/212] fix: allow falsey discriminator values (#6973) allow discriminator values in Single Table Inheritance like 0, "", or `null` fixes #3891 --- src/decorator/entity/ChildEntity.ts | 2 +- src/metadata-builder/EntityMetadataBuilder.ts | 7 ++- .../EntityMetadataValidator.ts | 4 +- .../RawSqlResultsToEntityTransformer.ts | 2 +- .../entity/Other.ts | 11 ++++ .../non-virtual-discriminator-column.ts | 20 +++++++ .../numeric-types/entity/Person.ts | 18 ++++++ .../numeric-types/entity/Student.ts | 11 ++++ .../numeric-types/entity/Teacher.ts | 11 ++++ .../numeric-types/numeric-types.ts | 57 +++++++++++++++++++ 10 files changed, 138 insertions(+), 5 deletions(-) create mode 100644 test/functional/table-inheritance/single-table/non-virtual-discriminator-column/entity/Other.ts create mode 100644 test/functional/table-inheritance/single-table/numeric-types/entity/Person.ts create mode 100644 test/functional/table-inheritance/single-table/numeric-types/entity/Student.ts create mode 100644 test/functional/table-inheritance/single-table/numeric-types/entity/Teacher.ts create mode 100644 test/functional/table-inheritance/single-table/numeric-types/numeric-types.ts diff --git a/src/decorator/entity/ChildEntity.ts b/src/decorator/entity/ChildEntity.ts index aee1b9746a4..2405e4305b0 100644 --- a/src/decorator/entity/ChildEntity.ts +++ b/src/decorator/entity/ChildEntity.ts @@ -15,7 +15,7 @@ export function ChildEntity(discriminatorValue?: any): ClassDecorator { } as TableMetadataArgs); // register discriminator value if it was provided - if (discriminatorValue) { + if (typeof discriminatorValue !== 'undefined') { getMetadataArgsStorage().discriminatorValues.push({ target: target, value: discriminatorValue diff --git a/src/metadata-builder/EntityMetadataBuilder.ts b/src/metadata-builder/EntityMetadataBuilder.ts index ab5cf5d1fe1..cd8de9b57ea 100644 --- a/src/metadata-builder/EntityMetadataBuilder.ts +++ b/src/metadata-builder/EntityMetadataBuilder.ts @@ -335,7 +335,12 @@ export class EntityMetadataBuilder { const entityInheritance = this.metadataArgsStorage.findInheritanceType(entityMetadata.target); const discriminatorValue = this.metadataArgsStorage.findDiscriminatorValue(entityMetadata.target); - entityMetadata.discriminatorValue = discriminatorValue ? discriminatorValue.value : (entityMetadata.target as any).name; // todo: pass this to naming strategy to generate a name + + if (typeof discriminatorValue !== "undefined") { + entityMetadata.discriminatorValue = discriminatorValue.value; + } else { + entityMetadata.discriminatorValue = (entityMetadata.target as any).name; + } // if single table inheritance is used, we need to mark all embedded columns as nullable entityMetadata.embeddeds = this.createEmbeddedsRecursively(entityMetadata, this.metadataArgsStorage.filterEmbeddeds(entityMetadata.inheritanceTree)) diff --git a/src/metadata-builder/EntityMetadataValidator.ts b/src/metadata-builder/EntityMetadataValidator.ts index 41fc1b99b18..9e3fe488d5b 100644 --- a/src/metadata-builder/EntityMetadataValidator.ts +++ b/src/metadata-builder/EntityMetadataValidator.ts @@ -62,8 +62,8 @@ export class EntityMetadataValidator { if (!entityMetadata.discriminatorColumn) throw new Error(`Entity ${entityMetadata.name} using single-table inheritance, it should also have a discriminator column. Did you forget to put discriminator column options?`); - if (["", undefined, null].indexOf(entityMetadata.discriminatorValue) !== -1) - throw new Error(`Entity ${entityMetadata.name} has empty discriminator value. Discriminator value should not be empty.`); + if (typeof entityMetadata.discriminatorValue === "undefined") + throw new Error(`Entity ${entityMetadata.name} has an undefined discriminator value. Discriminator value should be defined.`); const sameDiscriminatorValueEntityMetadata = allEntityMetadatas.find(metadata => { return metadata !== entityMetadata diff --git a/src/query-builder/transformer/RawSqlResultsToEntityTransformer.ts b/src/query-builder/transformer/RawSqlResultsToEntityTransformer.ts index 05dc941ac78..7048429245a 100644 --- a/src/query-builder/transformer/RawSqlResultsToEntityTransformer.ts +++ b/src/query-builder/transformer/RawSqlResultsToEntityTransformer.ts @@ -97,7 +97,7 @@ export class RawSqlResultsToEntityTransformer { if (metadata.discriminatorColumn) { const discriminatorValues = rawResults.map(result => result[DriverUtils.buildColumnAlias(this.driver, alias.name, alias.metadata.discriminatorColumn!.databaseName)]); const discriminatorMetadata = metadata.childEntityMetadatas.find(childEntityMetadata => { - return !!discriminatorValues.find(value => value === childEntityMetadata.discriminatorValue); + return typeof discriminatorValues.find(value => value === childEntityMetadata.discriminatorValue) !== 'undefined'; }); if (discriminatorMetadata) metadata = discriminatorMetadata; diff --git a/test/functional/table-inheritance/single-table/non-virtual-discriminator-column/entity/Other.ts b/test/functional/table-inheritance/single-table/non-virtual-discriminator-column/entity/Other.ts new file mode 100644 index 00000000000..4ef0c856c3e --- /dev/null +++ b/test/functional/table-inheritance/single-table/non-virtual-discriminator-column/entity/Other.ts @@ -0,0 +1,11 @@ +import {Column} from "../../../../../../src/decorator/columns/Column"; +import {ChildEntity} from "../../../../../../src/decorator/entity/ChildEntity"; +import {Person} from "./Person"; + +@ChildEntity("") +export class Other extends Person { + + @Column() + mood: string; + +} diff --git a/test/functional/table-inheritance/single-table/non-virtual-discriminator-column/non-virtual-discriminator-column.ts b/test/functional/table-inheritance/single-table/non-virtual-discriminator-column/non-virtual-discriminator-column.ts index 700f9e616cc..a413b0b38a4 100644 --- a/test/functional/table-inheritance/single-table/non-virtual-discriminator-column/non-virtual-discriminator-column.ts +++ b/test/functional/table-inheritance/single-table/non-virtual-discriminator-column/non-virtual-discriminator-column.ts @@ -3,7 +3,9 @@ import {closeTestingConnections, createTestingConnections, reloadTestingDatabase import {Connection} from "../../../../../src/connection/Connection"; import {Student} from "./entity/Student"; import {Employee} from "./entity/Employee"; +import {Other} from "./entity/Other"; import {Person} from "./entity/Person"; +import {OracleDriver} from "../../../../../src/driver/oracle/OracleDriver"; describe("table-inheritance > single-table > non-virtual-discriminator-column", () => { @@ -30,6 +32,15 @@ describe("table-inheritance > single-table > non-virtual-discriminator-column", employee.salary = 1000; await connection.getRepository(Employee).save(employee); + if (!(connection.driver instanceof OracleDriver)) { + // In Oracle, empty string is a `null` so this isn't exactly possible there. + + const other = new Other(); + other.name = "Empty"; + other.mood = "Happy" + await connection.getRepository(Other).save(other); + } + // ------------------------------------------------------------------------- // Select // ------------------------------------------------------------------------- @@ -47,6 +58,15 @@ describe("table-inheritance > single-table > non-virtual-discriminator-column", persons[1].type.should.be.equal("employee-type"); persons[1].name.should.be.equal("Roger"); (persons[1] as Employee).salary.should.be.equal(1000); + + if (!(connection.driver instanceof OracleDriver)) { + // In Oracle, empty string is a `null` so this isn't exactly possible there. + + persons[2].id.should.be.equal(3); + persons[2].type.should.be.equal(""); + persons[2].name.should.be.equal("Empty"); + (persons[2] as Other).mood.should.be.equal("Happy"); + } }))); }); diff --git a/test/functional/table-inheritance/single-table/numeric-types/entity/Person.ts b/test/functional/table-inheritance/single-table/numeric-types/entity/Person.ts new file mode 100644 index 00000000000..16ee3285a1b --- /dev/null +++ b/test/functional/table-inheritance/single-table/numeric-types/entity/Person.ts @@ -0,0 +1,18 @@ +import {Column} from "../../../../../../src/decorator/columns/Column"; +import {TableInheritance} from "../../../../../../src/decorator/entity/TableInheritance"; +import {Entity} from "../../../../../../src/decorator/entity/Entity"; +import {PrimaryGeneratedColumn} from "../../../../../../src/decorator/columns/PrimaryGeneratedColumn"; + +@Entity() +@TableInheritance({ column: { name: "type", type: "int" } }) +export class Person { + + @PrimaryGeneratedColumn() + id: number; + + @Column() + name: string; + + @Column() + type: number; +} diff --git a/test/functional/table-inheritance/single-table/numeric-types/entity/Student.ts b/test/functional/table-inheritance/single-table/numeric-types/entity/Student.ts new file mode 100644 index 00000000000..14f96bc3a27 --- /dev/null +++ b/test/functional/table-inheritance/single-table/numeric-types/entity/Student.ts @@ -0,0 +1,11 @@ +import {Column} from "../../../../../../src/decorator/columns/Column"; +import {ChildEntity} from "../../../../../../src/decorator/entity/ChildEntity"; +import {Person} from "./Person"; + +@ChildEntity(0) +export class Student extends Person { + + @Column() + faculty: string; + +} diff --git a/test/functional/table-inheritance/single-table/numeric-types/entity/Teacher.ts b/test/functional/table-inheritance/single-table/numeric-types/entity/Teacher.ts new file mode 100644 index 00000000000..71657f528e2 --- /dev/null +++ b/test/functional/table-inheritance/single-table/numeric-types/entity/Teacher.ts @@ -0,0 +1,11 @@ +import {Column} from "../../../../../../src/decorator/columns/Column"; +import {ChildEntity} from "../../../../../../src/decorator/entity/ChildEntity"; +import {Person} from "./Person"; + +@ChildEntity(1) +export class Teacher extends Person { + + @Column() + specialization: string; + +} diff --git a/test/functional/table-inheritance/single-table/numeric-types/numeric-types.ts b/test/functional/table-inheritance/single-table/numeric-types/numeric-types.ts new file mode 100644 index 00000000000..4a603c23048 --- /dev/null +++ b/test/functional/table-inheritance/single-table/numeric-types/numeric-types.ts @@ -0,0 +1,57 @@ +import "reflect-metadata"; +import {expect} from "chai"; +import {closeTestingConnections, createTestingConnections, reloadTestingDatabases} from "../../../../utils/test-utils"; +import {Connection} from "../../../../../src/connection/Connection"; +import {Student} from "./entity/Student"; +import {Teacher} from "./entity/Teacher"; +import {Person} from "./entity/Person"; +import {CockroachDriver} from "../../../../../src/driver/cockroachdb/CockroachDriver"; + +describe("table-inheritance > single-table > numeric types", () => { + + let connections: Connection[]; + before(async () => connections = await createTestingConnections({ + entities: [Person, Student, Teacher] + })); + beforeEach(() => reloadTestingDatabases(connections)); + after(() => closeTestingConnections(connections)); + + it("should allow numeric types for the discriminator, including 0", () => Promise.all(connections.map(async connection => { + if (connection.driver instanceof CockroachDriver) { + return; + } + + // ------------------------------------------------------------------------- + // Create + // ------------------------------------------------------------------------- + + const student = new Student(); + student.name = "Alice"; + student.faculty = "Economics"; + await connection.getRepository(Student).save(student); + + const teacher = new Teacher(); + teacher.name = "Roger"; + teacher.specialization = "Math"; + await connection.getRepository(Teacher).save(teacher); + + // ------------------------------------------------------------------------- + // Select + // ------------------------------------------------------------------------- + + let persons = await connection.manager + .createQueryBuilder(Person, "person") + .getMany(); + + expect(persons[0].id).to.be.equal(1); + expect(persons[0].type).to.be.equal(0); + expect(persons[0].name).to.be.equal("Alice"); + expect((persons[0] as Student).faculty).to.be.equal("Economics"); + + expect(persons[1].id).to.be.equal(2); + expect(persons[1].type).to.be.equal(1); + expect(persons[1].name).to.be.equal("Roger"); + expect((persons[1] as Teacher).specialization).to.be.equal("Math"); + }))); + +}); From a5eb946117a18d94c0157188b6a39542c8d50756 Mon Sep 17 00:00:00 2001 From: Wilson Pena Date: Mon, 26 Oct 2020 12:00:51 -0300 Subject: [PATCH 168/212] fix: support multiple row insert on oracle (#6927) change generated insert query to allow inserting an array of objects to oracle fixes: #2434 --- src/query-builder/InsertQueryBuilder.ts | 33 ++++++--- test/github-issues/2434/entity/Item.ts | 18 +++++ test/github-issues/2434/entity/Post.ts | 16 +++++ test/github-issues/2434/issue-2434.ts | 90 +++++++++++++++++++++++++ 4 files changed, 149 insertions(+), 8 deletions(-) create mode 100644 test/github-issues/2434/entity/Item.ts create mode 100644 test/github-issues/2434/entity/Post.ts create mode 100644 test/github-issues/2434/issue-2434.ts diff --git a/src/query-builder/InsertQueryBuilder.ts b/src/query-builder/InsertQueryBuilder.ts index 4d63755fcd4..49e435a8a90 100644 --- a/src/query-builder/InsertQueryBuilder.ts +++ b/src/query-builder/InsertQueryBuilder.ts @@ -87,8 +87,9 @@ export class InsertQueryBuilder extends QueryBuilder { // console.time(".prepare returning statement"); const returningResultsEntityUpdator = new ReturningResultsEntityUpdator(queryRunner, this.expressionMap); if (this.expressionMap.updateEntity === true && this.expressionMap.mainAlias!.hasMetadata) { - this.expressionMap.extraReturningColumns = returningResultsEntityUpdator.getInsertionReturningColumns(); - + if (!(valueSets.length > 1 && this.connection.driver instanceof OracleDriver)) { + this.expressionMap.extraReturningColumns = returningResultsEntityUpdator.getInsertionReturningColumns(); + } if (this.expressionMap.extraReturningColumns.length > 0 && this.connection.driver instanceof SqlServerDriver) { declareSql = this.connection.driver.buildTableVariableDeclaration("@OutputTable", this.expressionMap.extraReturningColumns); selectOutputSql = `SELECT * FROM @OutputTable`; @@ -293,7 +294,7 @@ export class InsertQueryBuilder extends QueryBuilder { protected createInsertExpression() { const tableName = this.getTableName(this.getMainTableName()); const valuesExpression = this.createValuesExpression(); // its important to get values before returning expression because oracle rely on native parameters and ordering of them is important - const returningExpression = this.createReturningExpression(); + const returningExpression = (this.connection.driver instanceof OracleDriver && this.getValueSets().length > 1) ? null : this.createReturningExpression(); // oracle doesnt support returning with multi-row insert const columnsExpression = this.createColumnNamesExpression(); let query = "INSERT "; @@ -318,7 +319,11 @@ export class InsertQueryBuilder extends QueryBuilder { // add VALUES expression if (valuesExpression) { - query += ` VALUES ${valuesExpression}`; + if (this.connection.driver instanceof OracleDriver && this.getValueSets().length > 1) { + query += ` ${valuesExpression}`; + } else { + query += ` VALUES ${valuesExpression}`; + } } else { if (this.connection.driver instanceof MysqlDriver || this.connection.driver instanceof AuroraDataApiDriver) { // special syntax for mysql DEFAULT VALUES insertion query += " VALUES ()"; @@ -413,7 +418,11 @@ export class InsertQueryBuilder extends QueryBuilder { valueSets.forEach((valueSet, valueSetIndex) => { columns.forEach((column, columnIndex) => { if (columnIndex === 0) { - expression += "("; + if (this.connection.driver instanceof OracleDriver && valueSets.length > 1) { + expression += " SELECT "; + } else { + expression += "("; + } } const paramName = "i" + valueSetIndex + "_" + column.databaseName; @@ -473,7 +482,7 @@ export class InsertQueryBuilder extends QueryBuilder { // if value for this column was not provided then insert default value } else if (value === undefined) { - if (this.connection.driver instanceof AbstractSqliteDriver || this.connection.driver instanceof SapDriver) { // unfortunately sqlite does not support DEFAULT expression in INSERT queries + if ((this.connection.driver instanceof OracleDriver && valueSets.length > 1) || this.connection.driver instanceof AbstractSqliteDriver || this.connection.driver instanceof SapDriver) { // unfortunately sqlite does not support DEFAULT expression in INSERT queries if (column.default !== undefined) { // try to use default defined in the column expression += this.connection.driver.normalizeDefault(column); } else { @@ -522,9 +531,17 @@ export class InsertQueryBuilder extends QueryBuilder { if (columnIndex === columns.length - 1) { if (valueSetIndex === valueSets.length - 1) { - expression += ")"; + if (this.connection.driver instanceof OracleDriver && valueSets.length > 1) { + expression += " FROM DUAL "; + } else { + expression += ")"; + } } else { - expression += "), "; + if (this.connection.driver instanceof OracleDriver && valueSets.length > 1) { + expression += " FROM DUAL UNION ALL "; + } else { + expression += "), "; + } } } else { expression += ", "; diff --git a/test/github-issues/2434/entity/Item.ts b/test/github-issues/2434/entity/Item.ts new file mode 100644 index 00000000000..56ec4b15ced --- /dev/null +++ b/test/github-issues/2434/entity/Item.ts @@ -0,0 +1,18 @@ +import { CreateDateColumn, Column } from "../../../../src"; +import { PrimaryGeneratedColumn } from "../../../../src/decorator/columns/PrimaryGeneratedColumn"; +import { Entity } from "../../../../src/decorator/entity/Entity"; + +@Entity("ITEM") +export class Item { + @PrimaryGeneratedColumn("uuid") + id: number; + + @CreateDateColumn() + date: Date; + + @Column() + itemName: string; + + @Column({nullable: true}) + itemDescription?: string; +} diff --git a/test/github-issues/2434/entity/Post.ts b/test/github-issues/2434/entity/Post.ts new file mode 100644 index 00000000000..1a433766d58 --- /dev/null +++ b/test/github-issues/2434/entity/Post.ts @@ -0,0 +1,16 @@ +import {Entity} from "../../../../src/decorator/entity/Entity"; +import {PrimaryColumn} from "../../../../src/decorator/columns/PrimaryColumn"; +import {Column} from "../../../../src/decorator/columns/Column"; + +@Entity({name: "POST"}) +export class Post { + + @PrimaryColumn() + id: number; + + @Column({ nullable: true }) + title?: string; + + @Column({name: "named_column", nullable: true}) + namedColumn?: string; +} diff --git a/test/github-issues/2434/issue-2434.ts b/test/github-issues/2434/issue-2434.ts new file mode 100644 index 00000000000..7a8a639c7bf --- /dev/null +++ b/test/github-issues/2434/issue-2434.ts @@ -0,0 +1,90 @@ +import "reflect-metadata"; +import {Connection} from "../../../src"; +import {Post} from './entity/Post'; +import {Item} from './entity/Item'; +import { closeTestingConnections, reloadTestingDatabases, createTestingConnections } from '../../utils/test-utils'; +import { expect } from 'chai'; + +describe("github issues > #2434 QueryBuilder insert for Oracle failed", () => { + let connections: Connection[] = []; + before(async () => connections = await createTestingConnections({ + entities: [__dirname + "/entity/*{.js,.ts}"], + enabledDrivers: ["oracle"] + })); + beforeEach(() => reloadTestingDatabases(connections)); + after(() => closeTestingConnections(connections)); + + it("should insert multiple rows with QueryBuilder", () => Promise.all(connections.map(async connection => { + const result = await connection.createQueryBuilder() + .insert() + .into(Post) + .values([ + {id: 5, title: "title 1"}, + {id: 6}, + ]) + .execute(); + expect(result.raw).to.be.equal(2); + expect(result.identifiers).to.deep.equal([ + {id: 5}, + {id: 6}, + ]); + }))); + + it("should throw ORA-00001 error if constraint violated when inserting multiple rows", () => Promise.all(connections.map(async connection => { + try { + await connection.createQueryBuilder() + .insert() + .into(Post) + .values([ + {id: 6, title: "title 3"}, + {id: 6}, + ]) + .execute(); + } catch(err) { + expect(err.message).to.contain("ORA-00001"); + } + }))); + + it("should insert multiple rows of entity with generated columns with QueryBuilder", () => Promise.all(connections.map(async connection => { + const result = await connection.createQueryBuilder() + .insert() + .into(Item) + .values([ + {itemName: "item name 1"}, + {itemName: "item name 2"}, + ]) + .execute(); + expect(result.raw).to.be.equal(2); + const items = await connection.getRepository(Item).find(); + expect(items.length).to.be.equal(2); + }))); + + it("should still insert one row with QueryBuilder", () => Promise.all(connections.map(async connection => { + const result = await connection.createQueryBuilder() + .insert() + .into(Item) + .values({itemName: "item name 20"}) + .execute(); + expect(result.identifiers.length).to.be.equal(1); + const items = await connection.getRepository(Item).find(); + expect(items[0].itemName).to.be.equal("item name 20"); + }))); + + it("should still insert multiple rows with save", () => Promise.all(connections.map(async connection => { + const result = await connection.getRepository(Post).save([ + {id: 8, namedColumn: "test col 1"}, + {id: 9, title: "title id 9"}, + ]); + expect(result).to.deep.equal([ + {id: 8, title: null, namedColumn: "test col 1"}, + {id: 9, title: "title id 9", namedColumn: null}, + ]); + + }))); + + it("should still insert one row with save", () => Promise.all(connections.map(async connection => { + const result = await connection.getRepository(Post).save({id: 10}); + expect(result).to.deep.equal({id: 10, title: null, namedColumn: null}); + }))); + +}); From 8244ea1371d5cf37e3f80e1b141f5945af38cb5e Mon Sep 17 00:00:00 2001 From: Christian Holm Date: Fri, 30 Oct 2020 06:23:00 +0100 Subject: [PATCH 169/212] feat: Exit with code 1 on empty migration:generate (#6978) This makes the `migration:generate` cli command exit with code 1 if no changes were found between the database and the schema from the code. --- docs/using-cli.md | 2 + src/commands/MigrationGenerateCommand.ts | 66 ++++++++++++------------ 2 files changed, 35 insertions(+), 33 deletions(-) diff --git a/docs/using-cli.md b/docs/using-cli.md index a240a9bf9d5..35e193f5aca 100644 --- a/docs/using-cli.md +++ b/docs/using-cli.md @@ -203,6 +203,8 @@ Learn more about [Migrations](./migrations.md). Automatic migration generation creates a new migration file and writes all sql queries that must be executed to update the database. +If no there were no changes generated, the command will exit with code 1. + ``` typeorm migration:generate -n UserMigration ``` diff --git a/src/commands/MigrationGenerateCommand.ts b/src/commands/MigrationGenerateCommand.ts index cdb098c2998..07f5ac87297 100644 --- a/src/commands/MigrationGenerateCommand.ts +++ b/src/commands/MigrationGenerateCommand.ts @@ -1,6 +1,5 @@ import {ConnectionOptionsReader} from "../connection/ConnectionOptionsReader"; import {CommandUtils} from "./CommandUtils"; -import {Connection} from "../connection/Connection"; import {createConnection} from "../index"; import {MysqlDriver} from "../driver/mysql/MysqlDriver"; import {camelCase} from "../util/StringUtils"; @@ -69,7 +68,6 @@ export class MigrationGenerateCommand implements yargs.CommandModule { } catch (err) { } } - let connection: Connection|undefined = undefined; try { const connectionOptionsReader = new ConnectionOptionsReader({ root: process.cwd(), @@ -82,36 +80,41 @@ export class MigrationGenerateCommand implements yargs.CommandModule { dropSchema: false, logging: false }); - connection = await createConnection(connectionOptions); - const sqlInMemory = await connection.driver.createSchemaBuilder().log(); - - if (args.pretty) { - sqlInMemory.upQueries.forEach(upQuery => { - upQuery.query = MigrationGenerateCommand.prettifyQuery(upQuery.query); - }); - sqlInMemory.downQueries.forEach(downQuery => { - downQuery.query = MigrationGenerateCommand.prettifyQuery(downQuery.query); - }); - } const upSqls: string[] = [], downSqls: string[] = []; - // mysql is exceptional here because it uses ` character in to escape names in queries, that's why for mysql - // we are using simple quoted string instead of template string syntax - if (connection.driver instanceof MysqlDriver || connection.driver instanceof AuroraDataApiDriver) { - sqlInMemory.upQueries.forEach(upQuery => { - upSqls.push(" await queryRunner.query(\"" + upQuery.query.replace(new RegExp(`"`, "g"), `\\"`) + "\"" + MigrationGenerateCommand.queryParams(upQuery.parameters) + ");"); - }); - sqlInMemory.downQueries.forEach(downQuery => { - downSqls.push(" await queryRunner.query(\"" + downQuery.query.replace(new RegExp(`"`, "g"), `\\"`) + "\"" + MigrationGenerateCommand.queryParams(downQuery.parameters) + ");"); - }); - } else { - sqlInMemory.upQueries.forEach(upQuery => { - upSqls.push(" await queryRunner.query(`" + upQuery.query.replace(new RegExp("`", "g"), "\\`") + "`" + MigrationGenerateCommand.queryParams(upQuery.parameters) + ");"); - }); - sqlInMemory.downQueries.forEach(downQuery => { - downSqls.push(" await queryRunner.query(`" + downQuery.query.replace(new RegExp("`", "g"), "\\`") + "`" + MigrationGenerateCommand.queryParams(downQuery.parameters) + ");"); - }); + const connection = await createConnection(connectionOptions); + try { + const sqlInMemory = await connection.driver.createSchemaBuilder().log(); + + if (args.pretty) { + sqlInMemory.upQueries.forEach(upQuery => { + upQuery.query = MigrationGenerateCommand.prettifyQuery(upQuery.query); + }); + sqlInMemory.downQueries.forEach(downQuery => { + downQuery.query = MigrationGenerateCommand.prettifyQuery(downQuery.query); + }); + } + + // mysql is exceptional here because it uses ` character in to escape names in queries, that's why for mysql + // we are using simple quoted string instead of template string syntax + if (connection.driver instanceof MysqlDriver || connection.driver instanceof AuroraDataApiDriver) { + sqlInMemory.upQueries.forEach(upQuery => { + upSqls.push(" await queryRunner.query(\"" + upQuery.query.replace(new RegExp(`"`, "g"), `\\"`) + "\"" + MigrationGenerateCommand.queryParams(upQuery.parameters) + ");"); + }); + sqlInMemory.downQueries.forEach(downQuery => { + downSqls.push(" await queryRunner.query(\"" + downQuery.query.replace(new RegExp(`"`, "g"), `\\"`) + "\"" + MigrationGenerateCommand.queryParams(downQuery.parameters) + ");"); + }); + } else { + sqlInMemory.upQueries.forEach(upQuery => { + upSqls.push(" await queryRunner.query(`" + upQuery.query.replace(new RegExp("`", "g"), "\\`") + "`" + MigrationGenerateCommand.queryParams(upQuery.parameters) + ");"); + }); + sqlInMemory.downQueries.forEach(downQuery => { + downSqls.push(" await queryRunner.query(`" + downQuery.query.replace(new RegExp("`", "g"), "\\`") + "`" + MigrationGenerateCommand.queryParams(downQuery.parameters) + ");"); + }); + } + } finally { + await connection.close(); } if (upSqls.length) { @@ -126,12 +129,9 @@ export class MigrationGenerateCommand implements yargs.CommandModule { } } else { console.log(chalk.yellow(`No changes in database schema were found - cannot generate a migration. To create a new empty migration use "typeorm migration:create" command`)); + process.exit(1); } - await connection.close(); - } catch (err) { - if (connection) await (connection as Connection).close(); - console.log(chalk.black.bgRed("Error during migration generation:")); console.error(err); process.exit(1); From f2ba9012fe4e851bc667dfdfedc3fd4af665d52b Mon Sep 17 00:00:00 2001 From: Ilyas Foo Date: Fri, 30 Oct 2020 14:16:00 +0800 Subject: [PATCH 170/212] fix: findRoots should get the defined primary key column (#6982) * test: added failing test for github issue #6948 * fix: findRoots should get the actual primary key column, fixes #6948 --- src/repository/TreeRepository.ts | 2 +- test/github-issues/6948/entity/Category.ts | 17 ++++++++++ test/github-issues/6948/issue-6948.ts | 38 ++++++++++++++++++++++ 3 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 test/github-issues/6948/entity/Category.ts create mode 100644 test/github-issues/6948/issue-6948.ts diff --git a/src/repository/TreeRepository.ts b/src/repository/TreeRepository.ts index f15aad1f915..725a947a3d2 100644 --- a/src/repository/TreeRepository.ts +++ b/src/repository/TreeRepository.ts @@ -33,7 +33,7 @@ export class TreeRepository extends Repository { const escapeAlias = (alias: string) => this.manager.connection.driver.escape(alias); const escapeColumn = (column: string) => this.manager.connection.driver.escape(column); const parentPropertyName = this.manager.connection.namingStrategy.joinColumnName( - this.metadata.treeParentRelation!.propertyName, "id" + this.metadata.treeParentRelation!.propertyName, this.metadata.primaryColumns[0].propertyName ); return this.createQueryBuilder("treeEntity") diff --git a/test/github-issues/6948/entity/Category.ts b/test/github-issues/6948/entity/Category.ts new file mode 100644 index 00000000000..66e7d15ef25 --- /dev/null +++ b/test/github-issues/6948/entity/Category.ts @@ -0,0 +1,17 @@ +import { Entity, PrimaryGeneratedColumn, Column, Tree, TreeParent, TreeChildren } from "../../../../src"; + +@Entity() +@Tree("materialized-path") +export class Category { + @PrimaryGeneratedColumn() + cat_id: number; + + @Column() + cat_name: string; + + @TreeParent() + cat_parent: Category; + + @TreeChildren({ cascade: true }) + cat_children: Category[]; +} diff --git a/test/github-issues/6948/issue-6948.ts b/test/github-issues/6948/issue-6948.ts new file mode 100644 index 00000000000..0891f1a1870 --- /dev/null +++ b/test/github-issues/6948/issue-6948.ts @@ -0,0 +1,38 @@ +import "reflect-metadata"; +import { Category } from "./entity/Category"; +import { Connection } from "../../../src/connection/Connection"; +import { + closeTestingConnections, + createTestingConnections, + reloadTestingDatabases, +} from "../../../test/utils/test-utils"; + +describe("github issues > #6948 TreeRepository's findRoots query incorrectly when using a custom primary key", () => { + let connections: Connection[]; + before( + async () => + (connections = await createTestingConnections({ + entities: [Category], + })) + ); + beforeEach(() => reloadTestingDatabases(connections)); + after(() => closeTestingConnections(connections)); + + it("entity parent column should work with custom primary column names ", () => + Promise.all( + connections.map(async (connection) => { + const categoryRepository = connection.getTreeRepository( + Category + ); + await categoryRepository.save( + categoryRepository.create({ + cat_name: "Root node", + }) + ); + const rootNodes = await categoryRepository.findRoots(); + rootNodes[0].should.deep.include({ + cat_name: "Root node", + }); + }) + )); +}); From 0e4b2397a6e62f5f2c35e5890bba53abe40a49ac Mon Sep 17 00:00:00 2001 From: Umed Khudoiberdiev Date: Mon, 2 Nov 2020 20:54:27 +0500 Subject: [PATCH 171/212] feat: transactional events in subscriber interface + "transaction" option in FindOptions (#6996) * added new decorators * added hooks to etnity subscriber interface * added test code in one query runner * removed new decorators and implemented in subscriber instead * added "transaction" option to FindOneOptions * added event listeners in query runners; added test for event listeners; updated docs; * working on test; * working on test; * added test for `transaction` option; * fixing failing test * fixing failing test * fixing typos * fixing test I broke Co-authored-by: Dmitry Zotov --- docs/listeners-and-subscribers.md | 112 +++++++-- .../AuroraDataApiPostgresQueryRunner.ts | 25 ++ .../AuroraDataApiQueryRunner.ts | 25 ++ .../cockroachdb/CockroachQueryRunner.ts | 25 ++ src/driver/expo/ExpoQueryRunner.ts | 35 ++- src/driver/mysql/MysqlQueryRunner.ts | 25 ++ src/driver/oracle/OracleQueryRunner.ts | 26 +++ src/driver/postgres/PostgresQueryRunner.ts | 25 ++ src/driver/sap/SapQueryRunner.ts | 25 ++ .../AbstractSqliteQueryRunner.ts | 30 ++- src/driver/sqlserver/SqlServerQueryRunner.ts | 33 ++- src/find-options/FindOneOptions.ts | 5 + src/find-options/FindOptionsUtils.ts | 7 +- src/metadata-builder/EntityMetadataBuilder.ts | 15 +- src/metadata/types/EventListenerTypes.ts | 25 +- src/query-runner/QueryRunner.ts | 2 +- src/subscriber/Broadcaster.ts | 120 ++++++++++ src/subscriber/EntitySubscriberInterface.ts | 33 +++ .../event/TransactionCommitEvent.ts | 27 +++ .../event/TransactionRollbackEvent.ts | 27 +++ src/subscriber/event/TransactionStartEvent.ts | 27 +++ .../entity-subscriber-transaction-flow.ts | 213 ++++++++++++++++++ .../find-options/repository-find-options.ts | 31 ++- 23 files changed, 875 insertions(+), 43 deletions(-) create mode 100644 src/subscriber/event/TransactionCommitEvent.ts create mode 100644 src/subscriber/event/TransactionRollbackEvent.ts create mode 100644 src/subscriber/event/TransactionStartEvent.ts create mode 100644 test/functional/entity-subscriber-transaction-flow/entity-subscriber-transaction-flow.ts diff --git a/docs/listeners-and-subscribers.md b/docs/listeners-and-subscribers.md index 8ecde6f2852..ef164b4d45f 100644 --- a/docs/listeners-and-subscribers.md +++ b/docs/listeners-and-subscribers.md @@ -18,14 +18,14 @@ You must mark those methods with special decorators depending on what event you ### `@AfterLoad` You can define a method with any name in entity and mark it with `@AfterLoad` -and TypeORM will call it each time the entity +and TypeORM will call it each time the entity is loaded using `QueryBuilder` or repository/manager find methods. Example: ```typescript @Entity() export class Post { - + @AfterLoad() updateCounters() { if (this.likesCount === undefined) @@ -43,7 +43,7 @@ Example: ```typescript @Entity() export class Post { - + @BeforeInsert() updateDates() { this.createdDate = new Date(); @@ -60,7 +60,7 @@ Example: ```typescript @Entity() export class Post { - + @AfterInsert() resetCounters() { this.counters = 0; @@ -77,7 +77,7 @@ Example: ```typescript @Entity() export class Post { - + @BeforeUpdate() updateDates() { this.updatedDate = new Date(); @@ -94,7 +94,7 @@ Example: ```typescript @Entity() export class Post { - + @AfterUpdate() updateCounters() { this.counter = 0; @@ -111,7 +111,7 @@ Example: ```typescript @Entity() export class Post { - + @BeforeRemove() updateStatus() { this.status = "removed"; @@ -128,7 +128,7 @@ Example: ```typescript @Entity() export class Post { - + @AfterRemove() updateStatus() { this.status = "removed"; @@ -146,14 +146,14 @@ Example: @EventSubscriber() export class PostSubscriber implements EntitySubscriberInterface { - + /** * Indicates that this subscriber only listen to Post events. */ listenTo() { return Post; } - + /** * Called before post insertion. */ @@ -170,15 +170,99 @@ To listen to any entity you just omit `listenTo` method and use `any`: ```typescript @EventSubscriber() export class PostSubscriber implements EntitySubscriberInterface { - + /** - * Called before entity insertion. + * Called after entity is loaded. + */ + afterLoad(entity: any) { + console.log(`AFTER ENTITY LOADED: `, entity); + } + + /** + * Called before post insertion. */ beforeInsert(event: InsertEvent) { - console.log(`BEFORE ENTITY INSERTED: `, event.entity); + console.log(`BEFORE POST INSERTED: `, event.entity); + } + + /** + * Called after entity insertion. + */ + afterInsert(event: InsertEvent) { + console.log(`AFTER ENTITY INSERTED: `, event.entity); + } + + /** + * Called before entity update. + */ + beforeUpdate(event: UpdateEvent) { + console.log(`BEFORE ENTITY UPDATED: `, event.entity); + } + + /** + * Called after entity update. + */ + afterUpdate(event: UpdateEvent) { + console.log(`AFTER ENTITY UPDATED: `, event.entity); + } + + /** + * Called before entity removal. + */ + beforeRemove(event: RemoveEvent) { + console.log(`BEFORE ENTITY WITH ID ${event.entityId} REMOVED: `, event.entity); + } + + /** + * Called after entity removal. + */ + afterRemove(event: RemoveEvent) { + console.log(`AFTER ENTITY WITH ID ${event.entityId} REMOVED: `, event.entity); + } + + /** + * Called before transaction start. + */ + beforeTransactionStart(event: TransactionStartEvent) { + console.log(`BEFORE TRANSACTION STARTED: `, event); + } + + /** + * Called after transaction start. + */ + afterTransactionStart(event: TransactionStartEvent) { + console.log(`AFTER TRANSACTION STARTED: `, event); + } + + /** + * Called before transaction commit. + */ + beforeTransactionCommit(event: TransactionCommitEvent) { + console.log(`BEFORE TRANSACTION COMMITTED: `, event); + } + + /** + * Called after transaction commit. + */ + afterTransactionCommit(event: TransactionCommitEvent) { + console.log(`AFTER TRANSACTION COMMITTED: `, event); + } + + /** + * Called before transaction rollback. + */ + beforeTransactionRollback(event: TransactionRollbackEvent) { + console.log(`BEFORE TRANSACTION ROLLBACK: `, event); + } + + /** + * Called after transaction rollback. + */ + afterTransactionRollback(event: TransactionRollbackEvent) { + console.log(`AFTER TRANSACTION ROLLBACK: `, event); } } ``` -Make sure your `subscribers` property is set in your [Connection Options](./connection-options.md#common-connection-options) so TypeORM loads your subscriber. \ No newline at end of file +Make sure your `subscribers` property is set in your [Connection Options](./connection-options.md#common-connection-options) so TypeORM loads your subscriber. diff --git a/src/driver/aurora-data-api-pg/AuroraDataApiPostgresQueryRunner.ts b/src/driver/aurora-data-api-pg/AuroraDataApiPostgresQueryRunner.ts index a0ed3899ef7..f2fc9f0fd00 100644 --- a/src/driver/aurora-data-api-pg/AuroraDataApiPostgresQueryRunner.ts +++ b/src/driver/aurora-data-api-pg/AuroraDataApiPostgresQueryRunner.ts @@ -6,6 +6,7 @@ import {IsolationLevel} from "../types/IsolationLevel"; import {AuroraDataApiPostgresDriver} from "./AuroraDataApiPostgresDriver"; import {PostgresQueryRunner} from "../postgres/PostgresQueryRunner"; import {ReplicationMode} from "../types/ReplicationMode"; +import {BroadcasterResult} from "../../subscriber/BroadcasterResult"; class PostgresQueryRunnerWrapper extends PostgresQueryRunner { driver: any; @@ -93,8 +94,16 @@ export class AuroraDataApiPostgresQueryRunner extends PostgresQueryRunnerWrapper if (this.isTransactionActive) throw new TransactionAlreadyStartedError(); + const beforeBroadcastResult = new BroadcasterResult(); + this.broadcaster.broadcastBeforeTransactionStartEvent(beforeBroadcastResult); + if (beforeBroadcastResult.promises.length > 0) await Promise.all(beforeBroadcastResult.promises); + this.isTransactionActive = true; await this.driver.client.startTransaction(); + + const afterBroadcastResult = new BroadcasterResult(); + this.broadcaster.broadcastAfterTransactionStartEvent(afterBroadcastResult); + if (afterBroadcastResult.promises.length > 0) await Promise.all(afterBroadcastResult.promises); } /** @@ -105,8 +114,16 @@ export class AuroraDataApiPostgresQueryRunner extends PostgresQueryRunnerWrapper if (!this.isTransactionActive) throw new TransactionNotStartedError(); + const beforeBroadcastResult = new BroadcasterResult(); + this.broadcaster.broadcastBeforeTransactionCommitEvent(beforeBroadcastResult); + if (beforeBroadcastResult.promises.length > 0) await Promise.all(beforeBroadcastResult.promises); + await this.driver.client.commitTransaction(); this.isTransactionActive = false; + + const afterBroadcastResult = new BroadcasterResult(); + this.broadcaster.broadcastAfterTransactionCommitEvent(afterBroadcastResult); + if (afterBroadcastResult.promises.length > 0) await Promise.all(afterBroadcastResult.promises); } /** @@ -117,8 +134,16 @@ export class AuroraDataApiPostgresQueryRunner extends PostgresQueryRunnerWrapper if (!this.isTransactionActive) throw new TransactionNotStartedError(); + const beforeBroadcastResult = new BroadcasterResult(); + this.broadcaster.broadcastBeforeTransactionRollbackEvent(beforeBroadcastResult); + if (beforeBroadcastResult.promises.length > 0) await Promise.all(beforeBroadcastResult.promises); + await this.driver.client.rollbackTransaction(); this.isTransactionActive = false; + + const afterBroadcastResult = new BroadcasterResult(); + this.broadcaster.broadcastAfterTransactionRollbackEvent(afterBroadcastResult); + if (afterBroadcastResult.promises.length > 0) await Promise.all(afterBroadcastResult.promises); } /** diff --git a/src/driver/aurora-data-api/AuroraDataApiQueryRunner.ts b/src/driver/aurora-data-api/AuroraDataApiQueryRunner.ts index b2e940486d1..94ae797b035 100644 --- a/src/driver/aurora-data-api/AuroraDataApiQueryRunner.ts +++ b/src/driver/aurora-data-api/AuroraDataApiQueryRunner.ts @@ -20,6 +20,7 @@ import {ColumnType} from "../../index"; import {TableCheck} from "../../schema-builder/table/TableCheck"; import {IsolationLevel} from "../types/IsolationLevel"; import {TableExclusion} from "../../schema-builder/table/TableExclusion"; +import {BroadcasterResult} from "../../subscriber/BroadcasterResult"; /** * Runs queries on a single mysql database connection. @@ -86,8 +87,16 @@ export class AuroraDataApiQueryRunner extends BaseQueryRunner implements QueryRu if (this.isTransactionActive) throw new TransactionAlreadyStartedError(); + const beforeBroadcastResult = new BroadcasterResult(); + this.broadcaster.broadcastBeforeTransactionStartEvent(beforeBroadcastResult); + if (beforeBroadcastResult.promises.length > 0) await Promise.all(beforeBroadcastResult.promises); + this.isTransactionActive = true; await this.driver.client.startTransaction(); + + const afterBroadcastResult = new BroadcasterResult(); + this.broadcaster.broadcastAfterTransactionStartEvent(afterBroadcastResult); + if (afterBroadcastResult.promises.length > 0) await Promise.all(afterBroadcastResult.promises); } /** @@ -98,8 +107,16 @@ export class AuroraDataApiQueryRunner extends BaseQueryRunner implements QueryRu if (!this.isTransactionActive) throw new TransactionNotStartedError(); + const beforeBroadcastResult = new BroadcasterResult(); + this.broadcaster.broadcastBeforeTransactionCommitEvent(beforeBroadcastResult); + if (beforeBroadcastResult.promises.length > 0) await Promise.all(beforeBroadcastResult.promises); + await this.driver.client.commitTransaction(); this.isTransactionActive = false; + + const afterBroadcastResult = new BroadcasterResult(); + this.broadcaster.broadcastAfterTransactionCommitEvent(afterBroadcastResult); + if (afterBroadcastResult.promises.length > 0) await Promise.all(afterBroadcastResult.promises); } /** @@ -110,8 +127,16 @@ export class AuroraDataApiQueryRunner extends BaseQueryRunner implements QueryRu if (!this.isTransactionActive) throw new TransactionNotStartedError(); + const beforeBroadcastResult = new BroadcasterResult(); + this.broadcaster.broadcastBeforeTransactionRollbackEvent(beforeBroadcastResult); + if (beforeBroadcastResult.promises.length > 0) await Promise.all(beforeBroadcastResult.promises); + await this.driver.client.rollbackTransaction(); this.isTransactionActive = false; + + const afterBroadcastResult = new BroadcasterResult(); + this.broadcaster.broadcastAfterTransactionRollbackEvent(afterBroadcastResult); + if (afterBroadcastResult.promises.length > 0) await Promise.all(afterBroadcastResult.promises); } /** diff --git a/src/driver/cockroachdb/CockroachQueryRunner.ts b/src/driver/cockroachdb/CockroachQueryRunner.ts index 30761f830eb..2c3e4d3b7a1 100644 --- a/src/driver/cockroachdb/CockroachQueryRunner.ts +++ b/src/driver/cockroachdb/CockroachQueryRunner.ts @@ -22,6 +22,7 @@ import {ColumnType} from "../../index"; import {IsolationLevel} from "../types/IsolationLevel"; import {TableExclusion} from "../../schema-builder/table/TableExclusion"; import {ReplicationMode} from "../types/ReplicationMode"; +import {BroadcasterResult} from "../../subscriber/BroadcasterResult"; /** * Runs queries on a single postgres database connection. @@ -130,6 +131,10 @@ export class CockroachQueryRunner extends BaseQueryRunner implements QueryRunner if (this.isTransactionActive) throw new TransactionAlreadyStartedError(); + const beforeBroadcastResult = new BroadcasterResult(); + this.broadcaster.broadcastBeforeTransactionStartEvent(beforeBroadcastResult); + if (beforeBroadcastResult.promises.length > 0) await Promise.all(beforeBroadcastResult.promises); + this.isTransactionActive = true; await this.query("START TRANSACTION"); await this.query("SAVEPOINT cockroach_restart"); @@ -137,6 +142,10 @@ export class CockroachQueryRunner extends BaseQueryRunner implements QueryRunner await this.query("SET TRANSACTION ISOLATION LEVEL " + isolationLevel); } this.storeQueries = true; + + const afterBroadcastResult = new BroadcasterResult(); + this.broadcaster.broadcastAfterTransactionStartEvent(afterBroadcastResult); + if (afterBroadcastResult.promises.length > 0) await Promise.all(afterBroadcastResult.promises); } /** @@ -147,6 +156,10 @@ export class CockroachQueryRunner extends BaseQueryRunner implements QueryRunner if (!this.isTransactionActive) throw new TransactionNotStartedError(); + const beforeBroadcastResult = new BroadcasterResult(); + this.broadcaster.broadcastBeforeTransactionCommitEvent(beforeBroadcastResult); + if (beforeBroadcastResult.promises.length > 0) await Promise.all(beforeBroadcastResult.promises); + this.storeQueries = false; try { @@ -164,6 +177,10 @@ export class CockroachQueryRunner extends BaseQueryRunner implements QueryRunner await this.commitTransaction(); } } + + const afterBroadcastResult = new BroadcasterResult(); + this.broadcaster.broadcastAfterTransactionCommitEvent(afterBroadcastResult); + if (afterBroadcastResult.promises.length > 0) await Promise.all(afterBroadcastResult.promises); } /** @@ -174,10 +191,18 @@ export class CockroachQueryRunner extends BaseQueryRunner implements QueryRunner if (!this.isTransactionActive) throw new TransactionNotStartedError(); + const beforeBroadcastResult = new BroadcasterResult(); + this.broadcaster.broadcastBeforeTransactionRollbackEvent(beforeBroadcastResult); + if (beforeBroadcastResult.promises.length > 0) await Promise.all(beforeBroadcastResult.promises); + this.storeQueries = false; await this.query("ROLLBACK"); this.queries = []; this.isTransactionActive = false; + + const afterBroadcastResult = new BroadcasterResult(); + this.broadcaster.broadcastAfterTransactionRollbackEvent(afterBroadcastResult); + if (afterBroadcastResult.promises.length > 0) await Promise.all(afterBroadcastResult.promises); } /** diff --git a/src/driver/expo/ExpoQueryRunner.ts b/src/driver/expo/ExpoQueryRunner.ts index 3931e49a81b..2169f629a20 100644 --- a/src/driver/expo/ExpoQueryRunner.ts +++ b/src/driver/expo/ExpoQueryRunner.ts @@ -5,6 +5,7 @@ import {TransactionAlreadyStartedError} from "../../error/TransactionAlreadyStar import {TransactionNotStartedError} from "../../error/TransactionNotStartedError"; import {ExpoDriver} from "./ExpoDriver"; import {Broadcaster} from "../../subscriber/Broadcaster"; +import {BroadcasterResult} from "../../subscriber/BroadcasterResult"; // Needed to satisfy the Typescript compiler interface IResultSet { @@ -29,7 +30,7 @@ interface ITransaction { * Runs queries on a single sqlite database connection. */ export class ExpoQueryRunner extends AbstractSqliteQueryRunner { - + /** * Database driver used by connection. */ @@ -39,7 +40,7 @@ export class ExpoQueryRunner extends AbstractSqliteQueryRunner { * Database transaction object */ private transaction?: ITransaction; - + // ------------------------------------------------------------------------- // Constructor // ------------------------------------------------------------------------- @@ -55,9 +56,9 @@ export class ExpoQueryRunner extends AbstractSqliteQueryRunner { * Starts transaction. Within Expo, all database operations happen in a * transaction context, so issuing a `BEGIN TRANSACTION` command is * redundant and will result in the following error: - * + * * `Error: Error code 1: cannot start a transaction within a transaction` - * + * * Instead, we keep track of a `Transaction` object in `this.transaction` * and continue using the same object until we wish to commit the * transaction. @@ -66,7 +67,15 @@ export class ExpoQueryRunner extends AbstractSqliteQueryRunner { if (this.isTransactionActive && typeof this.transaction !== "undefined") throw new TransactionAlreadyStartedError(); + const beforeBroadcastResult = new BroadcasterResult(); + this.broadcaster.broadcastBeforeTransactionStartEvent(beforeBroadcastResult); + if (beforeBroadcastResult.promises.length > 0) await Promise.all(beforeBroadcastResult.promises); + this.isTransactionActive = true; + + const afterBroadcastResult = new BroadcasterResult(); + this.broadcaster.broadcastAfterTransactionStartEvent(afterBroadcastResult); + if (afterBroadcastResult.promises.length > 0) await Promise.all(afterBroadcastResult.promises); } /** @@ -81,8 +90,16 @@ export class ExpoQueryRunner extends AbstractSqliteQueryRunner { if (!this.isTransactionActive && typeof this.transaction === "undefined") throw new TransactionNotStartedError(); + const beforeBroadcastResult = new BroadcasterResult(); + this.broadcaster.broadcastBeforeTransactionCommitEvent(beforeBroadcastResult); + if (beforeBroadcastResult.promises.length > 0) await Promise.all(beforeBroadcastResult.promises); + this.isTransactionActive = false; this.transaction = undefined; + + const afterBroadcastResult = new BroadcasterResult(); + this.broadcaster.broadcastAfterTransactionCommitEvent(afterBroadcastResult); + if (afterBroadcastResult.promises.length > 0) await Promise.all(afterBroadcastResult.promises); } /** @@ -96,8 +113,16 @@ export class ExpoQueryRunner extends AbstractSqliteQueryRunner { if (!this.isTransactionActive && typeof this.transaction === "undefined") throw new TransactionNotStartedError(); + const beforeBroadcastResult = new BroadcasterResult(); + this.broadcaster.broadcastBeforeTransactionRollbackEvent(beforeBroadcastResult); + if (beforeBroadcastResult.promises.length > 0) await Promise.all(beforeBroadcastResult.promises); + this.isTransactionActive = false; this.transaction = undefined; + + const afterBroadcastResult = new BroadcasterResult(); + this.broadcaster.broadcastAfterTransactionRollbackEvent(afterBroadcastResult); + if (afterBroadcastResult.promises.length > 0) await Promise.all(afterBroadcastResult.promises); } /** @@ -125,7 +150,7 @@ export class ExpoQueryRunner extends AbstractSqliteQueryRunner { if (maxQueryExecutionTime && queryExecutionTime > maxQueryExecutionTime) { this.driver.connection.logger.logQuerySlow(queryExecutionTime, query, parameters, this); } - + // return id of inserted row, if query was insert statement. if (query.substr(0, 11) === "INSERT INTO") { ok(result.insertId); diff --git a/src/driver/mysql/MysqlQueryRunner.ts b/src/driver/mysql/MysqlQueryRunner.ts index cdc848eaa9c..53b7b4eb1e6 100644 --- a/src/driver/mysql/MysqlQueryRunner.ts +++ b/src/driver/mysql/MysqlQueryRunner.ts @@ -23,6 +23,7 @@ import {IsolationLevel} from "../types/IsolationLevel"; import {TableExclusion} from "../../schema-builder/table/TableExclusion"; import {VersionUtils} from "../../util/VersionUtils"; import {ReplicationMode} from "../types/ReplicationMode"; +import {BroadcasterResult} from "../../subscriber/BroadcasterResult"; /** * Runs queries on a single mysql database connection. @@ -109,6 +110,10 @@ export class MysqlQueryRunner extends BaseQueryRunner implements QueryRunner { if (this.isTransactionActive) throw new TransactionAlreadyStartedError(); + const beforeBroadcastResult = new BroadcasterResult(); + this.broadcaster.broadcastBeforeTransactionStartEvent(beforeBroadcastResult); + if (beforeBroadcastResult.promises.length > 0) await Promise.all(beforeBroadcastResult.promises); + this.isTransactionActive = true; if (isolationLevel) { await this.query("SET TRANSACTION ISOLATION LEVEL " + isolationLevel); @@ -116,6 +121,10 @@ export class MysqlQueryRunner extends BaseQueryRunner implements QueryRunner { } else { await this.query("START TRANSACTION"); } + + const afterBroadcastResult = new BroadcasterResult(); + this.broadcaster.broadcastAfterTransactionStartEvent(afterBroadcastResult); + if (afterBroadcastResult.promises.length > 0) await Promise.all(afterBroadcastResult.promises); } /** @@ -126,8 +135,16 @@ export class MysqlQueryRunner extends BaseQueryRunner implements QueryRunner { if (!this.isTransactionActive) throw new TransactionNotStartedError(); + const beforeBroadcastResult = new BroadcasterResult(); + this.broadcaster.broadcastBeforeTransactionCommitEvent(beforeBroadcastResult); + if (beforeBroadcastResult.promises.length > 0) await Promise.all(beforeBroadcastResult.promises); + await this.query("COMMIT"); this.isTransactionActive = false; + + const afterBroadcastResult = new BroadcasterResult(); + this.broadcaster.broadcastAfterTransactionCommitEvent(afterBroadcastResult); + if (afterBroadcastResult.promises.length > 0) await Promise.all(afterBroadcastResult.promises); } /** @@ -138,8 +155,16 @@ export class MysqlQueryRunner extends BaseQueryRunner implements QueryRunner { if (!this.isTransactionActive) throw new TransactionNotStartedError(); + const beforeBroadcastResult = new BroadcasterResult(); + this.broadcaster.broadcastBeforeTransactionRollbackEvent(beforeBroadcastResult); + if (beforeBroadcastResult.promises.length > 0) await Promise.all(beforeBroadcastResult.promises); + await this.query("ROLLBACK"); this.isTransactionActive = false; + + const afterBroadcastResult = new BroadcasterResult(); + this.broadcaster.broadcastAfterTransactionRollbackEvent(afterBroadcastResult); + if (afterBroadcastResult.promises.length > 0) await Promise.all(afterBroadcastResult.promises); } /** diff --git a/src/driver/oracle/OracleQueryRunner.ts b/src/driver/oracle/OracleQueryRunner.ts index 52972434c90..508ef434952 100644 --- a/src/driver/oracle/OracleQueryRunner.ts +++ b/src/driver/oracle/OracleQueryRunner.ts @@ -21,6 +21,7 @@ import {ColumnType} from "../../index"; import {IsolationLevel} from "../types/IsolationLevel"; import {TableExclusion} from "../../schema-builder/table/TableExclusion"; import {ReplicationMode} from "../types/ReplicationMode"; +import {BroadcasterResult} from "../../subscriber/BroadcasterResult"; /** * Runs queries on a single oracle database connection. @@ -122,8 +123,17 @@ export class OracleQueryRunner extends BaseQueryRunner implements QueryRunner { if (isolationLevel !== "SERIALIZABLE" && isolationLevel !== "READ COMMITTED") { throw new Error(`Oracle only supports SERIALIZABLE and READ COMMITTED isolation`); } + + const beforeBroadcastResult = new BroadcasterResult(); + this.broadcaster.broadcastBeforeTransactionStartEvent(beforeBroadcastResult); + if (beforeBroadcastResult.promises.length > 0) await Promise.all(beforeBroadcastResult.promises); + await this.query("SET TRANSACTION ISOLATION LEVEL " + isolationLevel); this.isTransactionActive = true; + + const afterBroadcastResult = new BroadcasterResult(); + this.broadcaster.broadcastAfterTransactionStartEvent(afterBroadcastResult); + if (afterBroadcastResult.promises.length > 0) await Promise.all(afterBroadcastResult.promises); } /** @@ -134,8 +144,16 @@ export class OracleQueryRunner extends BaseQueryRunner implements QueryRunner { if (!this.isTransactionActive) throw new TransactionNotStartedError(); + const beforeBroadcastResult = new BroadcasterResult(); + this.broadcaster.broadcastBeforeTransactionCommitEvent(beforeBroadcastResult); + if (beforeBroadcastResult.promises.length > 0) await Promise.all(beforeBroadcastResult.promises); + await this.query("COMMIT"); this.isTransactionActive = false; + + const afterBroadcastResult = new BroadcasterResult(); + this.broadcaster.broadcastAfterTransactionCommitEvent(afterBroadcastResult); + if (afterBroadcastResult.promises.length > 0) await Promise.all(afterBroadcastResult.promises); } /** @@ -146,8 +164,16 @@ export class OracleQueryRunner extends BaseQueryRunner implements QueryRunner { if (!this.isTransactionActive) throw new TransactionNotStartedError(); + const beforeBroadcastResult = new BroadcasterResult(); + this.broadcaster.broadcastBeforeTransactionRollbackEvent(beforeBroadcastResult); + if (beforeBroadcastResult.promises.length > 0) await Promise.all(beforeBroadcastResult.promises); + await this.query("ROLLBACK"); this.isTransactionActive = false; + + const afterBroadcastResult = new BroadcasterResult(); + this.broadcaster.broadcastAfterTransactionRollbackEvent(afterBroadcastResult); + if (afterBroadcastResult.promises.length > 0) await Promise.all(afterBroadcastResult.promises); } /** diff --git a/src/driver/postgres/PostgresQueryRunner.ts b/src/driver/postgres/PostgresQueryRunner.ts index 2f7b65b8fd2..7654bb82202 100644 --- a/src/driver/postgres/PostgresQueryRunner.ts +++ b/src/driver/postgres/PostgresQueryRunner.ts @@ -22,6 +22,7 @@ import {Query} from "../Query"; import {IsolationLevel} from "../types/IsolationLevel"; import {PostgresDriver} from "./PostgresDriver"; import {ReplicationMode} from "../types/ReplicationMode"; +import {BroadcasterResult} from "../../subscriber/BroadcasterResult"; /** * Runs queries on a single postgres database connection. @@ -138,11 +139,19 @@ export class PostgresQueryRunner extends BaseQueryRunner implements QueryRunner if (this.isTransactionActive) throw new TransactionAlreadyStartedError(); + const beforeBroadcastResult = new BroadcasterResult(); + this.broadcaster.broadcastBeforeTransactionStartEvent(beforeBroadcastResult); + if (beforeBroadcastResult.promises.length > 0) await Promise.all(beforeBroadcastResult.promises); + this.isTransactionActive = true; await this.query("START TRANSACTION"); if (isolationLevel) { await this.query("SET TRANSACTION ISOLATION LEVEL " + isolationLevel); } + + const afterBroadcastResult = new BroadcasterResult(); + this.broadcaster.broadcastAfterTransactionStartEvent(afterBroadcastResult); + if (afterBroadcastResult.promises.length > 0) await Promise.all(afterBroadcastResult.promises); } /** @@ -153,8 +162,16 @@ export class PostgresQueryRunner extends BaseQueryRunner implements QueryRunner if (!this.isTransactionActive) throw new TransactionNotStartedError(); + const beforeBroadcastResult = new BroadcasterResult(); + this.broadcaster.broadcastBeforeTransactionCommitEvent(beforeBroadcastResult); + if (beforeBroadcastResult.promises.length > 0) await Promise.all(beforeBroadcastResult.promises); + await this.query("COMMIT"); this.isTransactionActive = false; + + const afterBroadcastResult = new BroadcasterResult(); + this.broadcaster.broadcastAfterTransactionCommitEvent(afterBroadcastResult); + if (afterBroadcastResult.promises.length > 0) await Promise.all(afterBroadcastResult.promises); } /** @@ -165,8 +182,16 @@ export class PostgresQueryRunner extends BaseQueryRunner implements QueryRunner if (!this.isTransactionActive) throw new TransactionNotStartedError(); + const beforeBroadcastResult = new BroadcasterResult(); + this.broadcaster.broadcastBeforeTransactionRollbackEvent(beforeBroadcastResult); + if (beforeBroadcastResult.promises.length > 0) await Promise.all(beforeBroadcastResult.promises); + await this.query("ROLLBACK"); this.isTransactionActive = false; + + const afterBroadcastResult = new BroadcasterResult(); + this.broadcaster.broadcastAfterTransactionRollbackEvent(afterBroadcastResult); + if (afterBroadcastResult.promises.length > 0) await Promise.all(afterBroadcastResult.promises); } /** diff --git a/src/driver/sap/SapQueryRunner.ts b/src/driver/sap/SapQueryRunner.ts index d070176d9d7..c3dc3485b1b 100644 --- a/src/driver/sap/SapQueryRunner.ts +++ b/src/driver/sap/SapQueryRunner.ts @@ -21,6 +21,7 @@ import {Query} from "../Query"; import {IsolationLevel} from "../types/IsolationLevel"; import {SapDriver} from "./SapDriver"; import {ReplicationMode} from "../types/ReplicationMode"; +import {BroadcasterResult} from "../../subscriber/BroadcasterResult"; /** * Runs queries on a single SQL Server database connection. @@ -105,10 +106,18 @@ export class SapQueryRunner extends BaseQueryRunner implements QueryRunner { if (this.isTransactionActive) throw new TransactionAlreadyStartedError(); + const beforeBroadcastResult = new BroadcasterResult(); + this.broadcaster.broadcastBeforeTransactionStartEvent(beforeBroadcastResult); + if (beforeBroadcastResult.promises.length > 0) await Promise.all(beforeBroadcastResult.promises); + this.isTransactionActive = true; if (isolationLevel) { await this.query(`SET TRANSACTION ISOLATION LEVEL ${isolationLevel || ""}`); } + + const afterBroadcastResult = new BroadcasterResult(); + this.broadcaster.broadcastAfterTransactionStartEvent(afterBroadcastResult); + if (afterBroadcastResult.promises.length > 0) await Promise.all(afterBroadcastResult.promises); } /** @@ -122,8 +131,16 @@ export class SapQueryRunner extends BaseQueryRunner implements QueryRunner { if (!this.isTransactionActive) throw new TransactionNotStartedError(); + const beforeBroadcastResult = new BroadcasterResult(); + this.broadcaster.broadcastBeforeTransactionCommitEvent(beforeBroadcastResult); + if (beforeBroadcastResult.promises.length > 0) await Promise.all(beforeBroadcastResult.promises); + await this.query("COMMIT"); this.isTransactionActive = false; + + const afterBroadcastResult = new BroadcasterResult(); + this.broadcaster.broadcastAfterTransactionCommitEvent(afterBroadcastResult); + if (afterBroadcastResult.promises.length > 0) await Promise.all(afterBroadcastResult.promises); } /** @@ -137,8 +154,16 @@ export class SapQueryRunner extends BaseQueryRunner implements QueryRunner { if (!this.isTransactionActive) throw new TransactionNotStartedError(); + const beforeBroadcastResult = new BroadcasterResult(); + this.broadcaster.broadcastBeforeTransactionRollbackEvent(beforeBroadcastResult); + if (beforeBroadcastResult.promises.length > 0) await Promise.all(beforeBroadcastResult.promises); + await this.query("ROLLBACK"); this.isTransactionActive = false; + + const afterBroadcastResult = new BroadcasterResult(); + this.broadcaster.broadcastAfterTransactionRollbackEvent(afterBroadcastResult); + if (afterBroadcastResult.promises.length > 0) await Promise.all(afterBroadcastResult.promises); } /** diff --git a/src/driver/sqlite-abstract/AbstractSqliteQueryRunner.ts b/src/driver/sqlite-abstract/AbstractSqliteQueryRunner.ts index 995b22d785b..ce9eb957962 100644 --- a/src/driver/sqlite-abstract/AbstractSqliteQueryRunner.ts +++ b/src/driver/sqlite-abstract/AbstractSqliteQueryRunner.ts @@ -8,6 +8,7 @@ import {Table} from "../../schema-builder/table/Table"; import {TableIndex} from "../../schema-builder/table/TableIndex"; import {TableForeignKey} from "../../schema-builder/table/TableForeignKey"; import {View} from "../../schema-builder/view/View"; +import { BroadcasterResult } from "../../subscriber/BroadcasterResult"; import {Query} from "../Query"; import {AbstractSqliteDriver} from "./AbstractSqliteDriver"; import {ReadStream} from "../../platform/PlatformTools"; @@ -70,8 +71,6 @@ export abstract class AbstractSqliteQueryRunner extends BaseQueryRunner implemen if (this.isTransactionActive) throw new TransactionAlreadyStartedError(); - this.isTransactionActive = true; - if (isolationLevel) { if (isolationLevel !== "READ UNCOMMITTED" && isolationLevel !== "SERIALIZABLE") { throw new Error(`SQLite only supports SERIALIZABLE and READ UNCOMMITTED isolation`); @@ -84,7 +83,17 @@ export abstract class AbstractSqliteQueryRunner extends BaseQueryRunner implemen } } + const beforeBroadcastResult = new BroadcasterResult(); + this.broadcaster.broadcastBeforeTransactionStartEvent(beforeBroadcastResult); + if (beforeBroadcastResult.promises.length > 0) await Promise.all(beforeBroadcastResult.promises); + + this.isTransactionActive = true; + await this.query("BEGIN TRANSACTION"); + + const afterBroadcastResult = new BroadcasterResult(); + this.broadcaster.broadcastAfterTransactionStartEvent(afterBroadcastResult); + if (afterBroadcastResult.promises.length > 0) await Promise.all(afterBroadcastResult.promises); } /** @@ -95,8 +104,16 @@ export abstract class AbstractSqliteQueryRunner extends BaseQueryRunner implemen if (!this.isTransactionActive) throw new TransactionNotStartedError(); + const beforeBroadcastResult = new BroadcasterResult(); + this.broadcaster.broadcastBeforeTransactionCommitEvent(beforeBroadcastResult); + if (beforeBroadcastResult.promises.length > 0) await Promise.all(beforeBroadcastResult.promises); + await this.query("COMMIT"); this.isTransactionActive = false; + + const afterBroadcastResult = new BroadcasterResult(); + this.broadcaster.broadcastAfterTransactionCommitEvent(afterBroadcastResult); + if (afterBroadcastResult.promises.length > 0) await Promise.all(afterBroadcastResult.promises); } /** @@ -107,8 +124,17 @@ export abstract class AbstractSqliteQueryRunner extends BaseQueryRunner implemen if (!this.isTransactionActive) throw new TransactionNotStartedError(); + const beforeBroadcastResult = new BroadcasterResult(); + this.broadcaster.broadcastBeforeTransactionRollbackEvent(beforeBroadcastResult); + if (beforeBroadcastResult.promises.length > 0) await Promise.all(beforeBroadcastResult.promises); + await this.query("ROLLBACK"); + this.isTransactionActive = false; + + const afterBroadcastResult = new BroadcasterResult(); + this.broadcaster.broadcastAfterTransactionRollbackEvent(afterBroadcastResult); + if (afterBroadcastResult.promises.length > 0) await Promise.all(afterBroadcastResult.promises); } /** diff --git a/src/driver/sqlserver/SqlServerQueryRunner.ts b/src/driver/sqlserver/SqlServerQueryRunner.ts index 55e1c325a5c..898a3667cd4 100644 --- a/src/driver/sqlserver/SqlServerQueryRunner.ts +++ b/src/driver/sqlserver/SqlServerQueryRunner.ts @@ -23,6 +23,7 @@ import {IsolationLevel} from "../types/IsolationLevel"; import {MssqlParameter} from "./MssqlParameter"; import {SqlServerDriver} from "./SqlServerDriver"; import {ReplicationMode} from "../types/ReplicationMode"; +import {BroadcasterResult} from "../../subscriber/BroadcasterResult"; /** * Runs queries on a single SQL Server database connection. @@ -94,6 +95,10 @@ export class SqlServerQueryRunner extends BaseQueryRunner implements QueryRunner if (this.isTransactionActive) throw new TransactionAlreadyStartedError(); + const beforeBroadcastResult = new BroadcasterResult(); + this.broadcaster.broadcastBeforeTransactionStartEvent(beforeBroadcastResult); + if (beforeBroadcastResult.promises.length > 0) await Promise.all(beforeBroadcastResult.promises); + return new Promise(async (ok, fail) => { this.isTransactionActive = true; @@ -117,6 +122,10 @@ export class SqlServerQueryRunner extends BaseQueryRunner implements QueryRunner } else { this.databaseConnection.begin(transactionCallback); } + + const afterBroadcastResult = new BroadcasterResult(); + this.broadcaster.broadcastAfterTransactionStartEvent(afterBroadcastResult); + if (afterBroadcastResult.promises.length > 0) await Promise.all(afterBroadcastResult.promises); }); } @@ -131,11 +140,20 @@ export class SqlServerQueryRunner extends BaseQueryRunner implements QueryRunner if (!this.isTransactionActive) throw new TransactionNotStartedError(); + const beforeBroadcastResult = new BroadcasterResult(); + this.broadcaster.broadcastBeforeTransactionCommitEvent(beforeBroadcastResult); + if (beforeBroadcastResult.promises.length > 0) await Promise.all(beforeBroadcastResult.promises); + return new Promise((ok, fail) => { - this.databaseConnection.commit((err: any) => { + this.databaseConnection.commit(async (err: any) => { if (err) return fail(err); this.isTransactionActive = false; this.databaseConnection = null; + + const afterBroadcastResult = new BroadcasterResult(); + this.broadcaster.broadcastAfterTransactionCommitEvent(afterBroadcastResult); + if (afterBroadcastResult.promises.length > 0) await Promise.all(afterBroadcastResult.promises); + ok(); this.connection.logger.logQuery("COMMIT"); }); @@ -153,11 +171,20 @@ export class SqlServerQueryRunner extends BaseQueryRunner implements QueryRunner if (!this.isTransactionActive) throw new TransactionNotStartedError(); - return new Promise((ok, fail) => { - this.databaseConnection.rollback((err: any) => { + const beforeBroadcastResult = new BroadcasterResult(); + this.broadcaster.broadcastBeforeTransactionRollbackEvent(beforeBroadcastResult); + if (beforeBroadcastResult.promises.length > 0) await Promise.all(beforeBroadcastResult.promises); + + return new Promise( (ok, fail) => { + this.databaseConnection.rollback(async (err: any) => { if (err) return fail(err); this.isTransactionActive = false; this.databaseConnection = null; + + const afterBroadcastResult = new BroadcasterResult(); + this.broadcaster.broadcastAfterTransactionRollbackEvent(afterBroadcastResult); + if (afterBroadcastResult.promises.length > 0) await Promise.all(afterBroadcastResult.promises); + ok(); this.connection.logger.logQuery("ROLLBACK"); }); diff --git a/src/find-options/FindOneOptions.ts b/src/find-options/FindOneOptions.ts index 309e262020d..92c9ff96cbc 100644 --- a/src/find-options/FindOneOptions.ts +++ b/src/find-options/FindOneOptions.ts @@ -59,4 +59,9 @@ export interface FindOneOptions { */ loadEagerRelations?: boolean; + /** + * If this is set to true, SELECT query in a `find` method will be executed in a transaction. + */ + transaction?: boolean + } diff --git a/src/find-options/FindOptionsUtils.ts b/src/find-options/FindOptionsUtils.ts index cec9f17ae13..210d75e23e9 100644 --- a/src/find-options/FindOptionsUtils.ts +++ b/src/find-options/FindOptionsUtils.ts @@ -34,7 +34,8 @@ export class FindOptionsUtils { possibleOptions.loadRelationIds instanceof Object || typeof possibleOptions.loadRelationIds === "boolean" || typeof possibleOptions.loadEagerRelations === "boolean" || - typeof possibleOptions.withDeleted === "boolean" + typeof possibleOptions.withDeleted === "boolean" || + typeof possibleOptions.transaction === "boolean" ); } @@ -84,6 +85,10 @@ export class FindOptionsUtils { if (!options || (!this.isFindOneOptions(options) && !this.isFindManyOptions(options))) return qb; + if (options.transaction === true) { + qb.expressionMap.useTransaction = true; + } + if (!qb.expressionMap.mainAlias || !qb.expressionMap.mainAlias.hasMetadata) return qb; diff --git a/src/metadata-builder/EntityMetadataBuilder.ts b/src/metadata-builder/EntityMetadataBuilder.ts index cd8de9b57ea..c3554add3fb 100644 --- a/src/metadata-builder/EntityMetadataBuilder.ts +++ b/src/metadata-builder/EntityMetadataBuilder.ts @@ -9,6 +9,7 @@ import {MetadataArgsStorage} from "../metadata-args/MetadataArgsStorage"; import {EmbeddedMetadataArgs} from "../metadata-args/EmbeddedMetadataArgs"; import {RelationIdMetadata} from "../metadata/RelationIdMetadata"; import {RelationCountMetadata} from "../metadata/RelationCountMetadata"; +import { EventListenerTypes } from "../metadata/types/EventListenerTypes"; import {MetadataUtils} from "./MetadataUtils"; import {TableMetadataArgs} from "../metadata-args/TableMetadataArgs"; import {JunctionEntityMetadataBuilder} from "./JunctionEntityMetadataBuilder"; @@ -615,13 +616,13 @@ export class EntityMetadataBuilder { entityMetadata.treeChildrenRelation = entityMetadata.relations.find(relation => relation.isTreeChildren); entityMetadata.columns = entityMetadata.embeddeds.reduce((columns, embedded) => columns.concat(embedded.columnsFromTree), entityMetadata.ownColumns); entityMetadata.listeners = entityMetadata.embeddeds.reduce((columns, embedded) => columns.concat(embedded.listenersFromTree), entityMetadata.ownListeners); - entityMetadata.afterLoadListeners = entityMetadata.listeners.filter(listener => listener.type === "after-load"); - entityMetadata.afterInsertListeners = entityMetadata.listeners.filter(listener => listener.type === "after-insert"); - entityMetadata.afterUpdateListeners = entityMetadata.listeners.filter(listener => listener.type === "after-update"); - entityMetadata.afterRemoveListeners = entityMetadata.listeners.filter(listener => listener.type === "after-remove"); - entityMetadata.beforeInsertListeners = entityMetadata.listeners.filter(listener => listener.type === "before-insert"); - entityMetadata.beforeUpdateListeners = entityMetadata.listeners.filter(listener => listener.type === "before-update"); - entityMetadata.beforeRemoveListeners = entityMetadata.listeners.filter(listener => listener.type === "before-remove"); + entityMetadata.afterLoadListeners = entityMetadata.listeners.filter(listener => listener.type === EventListenerTypes.AFTER_LOAD); + entityMetadata.afterInsertListeners = entityMetadata.listeners.filter(listener => listener.type === EventListenerTypes.AFTER_INSERT); + entityMetadata.afterUpdateListeners = entityMetadata.listeners.filter(listener => listener.type === EventListenerTypes.AFTER_UPDATE); + entityMetadata.afterRemoveListeners = entityMetadata.listeners.filter(listener => listener.type === EventListenerTypes.AFTER_REMOVE); + entityMetadata.beforeInsertListeners = entityMetadata.listeners.filter(listener => listener.type === EventListenerTypes.BEFORE_INSERT); + entityMetadata.beforeUpdateListeners = entityMetadata.listeners.filter(listener => listener.type === EventListenerTypes.BEFORE_UPDATE); + entityMetadata.beforeRemoveListeners = entityMetadata.listeners.filter(listener => listener.type === EventListenerTypes.BEFORE_REMOVE); entityMetadata.indices = entityMetadata.embeddeds.reduce((columns, embedded) => columns.concat(embedded.indicesFromTree), entityMetadata.ownIndices); entityMetadata.uniques = entityMetadata.embeddeds.reduce((columns, embedded) => columns.concat(embedded.uniquesFromTree), entityMetadata.ownUniques); entityMetadata.primaryColumns = entityMetadata.columns.filter(column => column.isPrimary); diff --git a/src/metadata/types/EventListenerTypes.ts b/src/metadata/types/EventListenerTypes.ts index 8f65645353b..9a310b9aa18 100644 --- a/src/metadata/types/EventListenerTypes.ts +++ b/src/metadata/types/EventListenerTypes.ts @@ -1,17 +1,24 @@ /** * All types that entity listener can be. */ -export type EventListenerType = "after-load"|"before-insert"|"after-insert"|"before-update"|"after-update"|"before-remove"|"after-remove"; +export type EventListenerType = + | "after-load" + | "before-insert" + | "after-insert" + | "before-update" + | "after-update" + | "before-remove" + | "after-remove"; /** * Provides a constants for each entity listener type. */ export class EventListenerTypes { - static AFTER_LOAD: EventListenerType = "after-load"; - static BEFORE_INSERT: EventListenerType = "before-insert"; - static AFTER_INSERT: EventListenerType = "after-insert"; - static BEFORE_UPDATE: EventListenerType = "before-update"; - static AFTER_UPDATE: EventListenerType = "after-update"; - static BEFORE_REMOVE: EventListenerType = "before-remove"; - static AFTER_REMOVE: EventListenerType = "after-remove"; -} \ No newline at end of file + static AFTER_LOAD = "after-load" as const; + static BEFORE_INSERT = "before-insert" as const; + static AFTER_INSERT = "after-insert" as const; + static BEFORE_UPDATE = "before-update" as const; + static AFTER_UPDATE = "after-update" as const; + static BEFORE_REMOVE = "before-remove" as const; + static AFTER_REMOVE = "after-remove" as const; +} diff --git a/src/query-runner/QueryRunner.ts b/src/query-runner/QueryRunner.ts index 62c9f78424e..532fae39913 100644 --- a/src/query-runner/QueryRunner.ts +++ b/src/query-runner/QueryRunner.ts @@ -92,7 +92,7 @@ export interface QueryRunner { commitTransaction(): Promise; /** - * Ends transaction. + * Rollbacks transaction. * Error will be thrown if transaction was not started. */ rollbackTransaction(): Promise; diff --git a/src/subscriber/Broadcaster.ts b/src/subscriber/Broadcaster.ts index 0dc3aaf326f..2ac9986063d 100644 --- a/src/subscriber/Broadcaster.ts +++ b/src/subscriber/Broadcaster.ts @@ -181,6 +181,126 @@ export class Broadcaster { } } + /** + * Broadcasts "BEFORE_TRANSACTION_START" event. + */ + broadcastBeforeTransactionStartEvent(result: BroadcasterResult): void { + if (this.queryRunner.connection.subscribers.length) { + this.queryRunner.connection.subscribers.forEach(subscriber => { + if (subscriber.beforeTransactionStart) { + const executionResult = subscriber.beforeTransactionStart({ + connection: this.queryRunner.connection, + queryRunner: this.queryRunner, + manager: this.queryRunner.manager, + }); + if (executionResult instanceof Promise) + result.promises.push(executionResult); + result.count++; + } + }); + } + } + + /** + * Broadcasts "AFTER_TRANSACTION_START" event. + */ + broadcastAfterTransactionStartEvent(result: BroadcasterResult): void { + if (this.queryRunner.connection.subscribers.length) { + this.queryRunner.connection.subscribers.forEach(subscriber => { + if (subscriber.afterTransactionStart) { + const executionResult = subscriber.afterTransactionStart({ + connection: this.queryRunner.connection, + queryRunner: this.queryRunner, + manager: this.queryRunner.manager, + }); + if (executionResult instanceof Promise) + result.promises.push(executionResult); + result.count++; + } + }); + } + } + + /** + * Broadcasts "BEFORE_TRANSACTION_COMMIT" event. + */ + broadcastBeforeTransactionCommitEvent(result: BroadcasterResult): void { + if (this.queryRunner.connection.subscribers.length) { + this.queryRunner.connection.subscribers.forEach(subscriber => { + if (subscriber.beforeTransactionCommit) { + const executionResult = subscriber.beforeTransactionCommit({ + connection: this.queryRunner.connection, + queryRunner: this.queryRunner, + manager: this.queryRunner.manager, + }); + if (executionResult instanceof Promise) + result.promises.push(executionResult); + result.count++; + } + }); + } + } + + /** + * Broadcasts "AFTER_TRANSACTION_COMMIT" event. + */ + broadcastAfterTransactionCommitEvent(result: BroadcasterResult): void { + if (this.queryRunner.connection.subscribers.length) { + this.queryRunner.connection.subscribers.forEach(subscriber => { + if (subscriber.afterTransactionCommit) { + const executionResult = subscriber.afterTransactionCommit({ + connection: this.queryRunner.connection, + queryRunner: this.queryRunner, + manager: this.queryRunner.manager, + }); + if (executionResult instanceof Promise) + result.promises.push(executionResult); + result.count++; + } + }); + } + } + + /** + * Broadcasts "BEFORE_TRANSACTION_ROLLBACK" event. + */ + broadcastBeforeTransactionRollbackEvent(result: BroadcasterResult): void { + if (this.queryRunner.connection.subscribers.length) { + this.queryRunner.connection.subscribers.forEach(subscriber => { + if (subscriber.beforeTransactionRollback) { + const executionResult = subscriber.beforeTransactionRollback({ + connection: this.queryRunner.connection, + queryRunner: this.queryRunner, + manager: this.queryRunner.manager, + }); + if (executionResult instanceof Promise) + result.promises.push(executionResult); + result.count++; + } + }); + } + } + + /** + * Broadcasts "AFTER_TRANSACTION_ROLLBACK" event. + */ + broadcastAfterTransactionRollbackEvent(result: BroadcasterResult): void { + if (this.queryRunner.connection.subscribers.length) { + this.queryRunner.connection.subscribers.forEach(subscriber => { + if (subscriber.afterTransactionRollback) { + const executionResult = subscriber.afterTransactionRollback({ + connection: this.queryRunner.connection, + queryRunner: this.queryRunner, + manager: this.queryRunner.manager, + }); + if (executionResult instanceof Promise) + result.promises.push(executionResult); + result.count++; + } + }); + } + } + /** * Broadcasts "AFTER_UPDATE" event. * After update event is executed after entity is being updated in the database. diff --git a/src/subscriber/EntitySubscriberInterface.ts b/src/subscriber/EntitySubscriberInterface.ts index bc726d52792..3cfb5776640 100644 --- a/src/subscriber/EntitySubscriberInterface.ts +++ b/src/subscriber/EntitySubscriberInterface.ts @@ -1,3 +1,6 @@ +import { TransactionCommitEvent } from "./event/TransactionCommitEvent"; +import { TransactionRollbackEvent } from "./event/TransactionRollbackEvent"; +import { TransactionStartEvent } from "./event/TransactionStartEvent"; import {UpdateEvent} from "./event/UpdateEvent"; import {RemoveEvent} from "./event/RemoveEvent"; import {InsertEvent} from "./event/InsertEvent"; @@ -54,4 +57,34 @@ export interface EntitySubscriberInterface { */ afterRemove?(event: RemoveEvent): Promise|void; + /** + * Called before transaction is started. + */ + beforeTransactionStart?(event: TransactionStartEvent): Promise|void; + + /** + * Called after transaction is started. + */ + afterTransactionStart?(event: TransactionStartEvent): Promise|void; + + /** + * Called before transaction is committed. + */ + beforeTransactionCommit?(event: TransactionCommitEvent): Promise|void; + + /** + * Called after transaction is committed. + */ + afterTransactionCommit?(event: TransactionCommitEvent): Promise|void; + + /** + * Called before transaction rollback. + */ + beforeTransactionRollback?(event: TransactionRollbackEvent): Promise|void; + + /** + * Called after transaction rollback. + */ + afterTransactionRollback?(event: TransactionRollbackEvent): Promise|void; + } diff --git a/src/subscriber/event/TransactionCommitEvent.ts b/src/subscriber/event/TransactionCommitEvent.ts new file mode 100644 index 00000000000..2a4e82c2cf0 --- /dev/null +++ b/src/subscriber/event/TransactionCommitEvent.ts @@ -0,0 +1,27 @@ +import {EntityManager} from "../../entity-manager/EntityManager"; +import {Connection} from "../../connection/Connection"; +import {QueryRunner} from "../../query-runner/QueryRunner"; + +/** + * TransactionCommitEvent is an object that broadcaster sends to the entity subscriber when an transaction is committed. + */ +export interface TransactionCommitEvent { + + /** + * Connection used in the event. + */ + connection: Connection; + + /** + * QueryRunner used in the event transaction. + * All database operations in the subscribed event listener should be performed using this query runner instance. + */ + queryRunner: QueryRunner; + + /** + * EntityManager used in the event transaction. + * All database operations in the subscribed event listener should be performed using this entity manager instance. + */ + manager: EntityManager; + +} diff --git a/src/subscriber/event/TransactionRollbackEvent.ts b/src/subscriber/event/TransactionRollbackEvent.ts new file mode 100644 index 00000000000..ae7fb5b1831 --- /dev/null +++ b/src/subscriber/event/TransactionRollbackEvent.ts @@ -0,0 +1,27 @@ +import {EntityManager} from "../../entity-manager/EntityManager"; +import {Connection} from "../../connection/Connection"; +import {QueryRunner} from "../../query-runner/QueryRunner"; + +/** + * TransactionRollbackEvent is an object that broadcaster sends to the entity subscriber on transaction rollback. + */ +export interface TransactionRollbackEvent { + + /** + * Connection used in the event. + */ + connection: Connection; + + /** + * QueryRunner used in the event transaction. + * All database operations in the subscribed event listener should be performed using this query runner instance. + */ + queryRunner: QueryRunner; + + /** + * EntityManager used in the event transaction. + * All database operations in the subscribed event listener should be performed using this entity manager instance. + */ + manager: EntityManager; + +} diff --git a/src/subscriber/event/TransactionStartEvent.ts b/src/subscriber/event/TransactionStartEvent.ts new file mode 100644 index 00000000000..b6409160ffe --- /dev/null +++ b/src/subscriber/event/TransactionStartEvent.ts @@ -0,0 +1,27 @@ +import {EntityManager} from "../../entity-manager/EntityManager"; +import {Connection} from "../../connection/Connection"; +import {QueryRunner} from "../../query-runner/QueryRunner"; + +/** + * TransactionStartEvent is an object that broadcaster sends to the entity subscriber before transaction is started. + */ +export interface TransactionStartEvent { + + /** + * Connection used in the event. + */ + connection: Connection; + + /** + * QueryRunner used in the event transaction. + * All database operations in the subscribed event listener should be performed using this query runner instance. + */ + queryRunner: QueryRunner; + + /** + * EntityManager used in the event transaction. + * All database operations in the subscribed event listener should be performed using this entity manager instance. + */ + manager: EntityManager; + +} diff --git a/test/functional/entity-subscriber-transaction-flow/entity-subscriber-transaction-flow.ts b/test/functional/entity-subscriber-transaction-flow/entity-subscriber-transaction-flow.ts new file mode 100644 index 00000000000..cdd235797c9 --- /dev/null +++ b/test/functional/entity-subscriber-transaction-flow/entity-subscriber-transaction-flow.ts @@ -0,0 +1,213 @@ +import { + Connection, + EntitySubscriberInterface, + EventSubscriber, +} from "../../../src"; +import {closeTestingConnections, createTestingConnections} from "../../utils/test-utils"; +import sinon from "sinon"; +import {expect} from "chai"; +import {SapDriver} from "../../../src/driver/sap/SapDriver"; +import {OracleDriver} from "../../../src/driver/oracle/OracleDriver"; +import {AuroraDataApiPostgresDriver} from "../../../src/driver/aurora-data-api-pg/AuroraDataApiPostgresDriver"; +import {AuroraDataApiDriver} from "../../../src/driver/aurora-data-api/AuroraDataApiDriver"; +import {SqlServerDriver} from "../../../src/driver/sqlserver/SqlServerDriver"; + +describe("entity subscriber transaction flow", () => { + + let beforeTransactionStart = sinon.spy(); + let afterTransactionStart = sinon.spy(); + let beforeTransactionCommit = sinon.spy(); + let afterTransactionCommit = sinon.spy(); + let beforeTransactionRollback = sinon.spy(); + let afterTransactionRollback = sinon.spy(); + + @EventSubscriber() + class PostSubscriber implements EntitySubscriberInterface { + + beforeTransactionStart() { + if (beforeTransactionStart) + beforeTransactionStart(); + } + + afterTransactionStart() { + if (afterTransactionStart) + afterTransactionStart(); + } + + beforeTransactionCommit() { + if (beforeTransactionCommit) + beforeTransactionCommit(); + } + + afterTransactionCommit() { + if (afterTransactionCommit) + afterTransactionCommit(); + } + + beforeTransactionRollback() { + if (beforeTransactionRollback) + beforeTransactionRollback(); + } + + afterTransactionRollback() { + if (afterTransactionRollback) + afterTransactionRollback(); + } + } + + let connections: Connection[]; + before(async () => connections = await createTestingConnections({ + subscribers: [PostSubscriber], + dropSchema: true, + schemaCreate: true, + })); + after(() => closeTestingConnections(connections)); + + it("transactionStart", async () => { + for (let connection of connections) { + if (connection.driver instanceof SqlServerDriver) return; + + beforeTransactionStart.resetHistory(); + afterTransactionStart.resetHistory(); + + let isolationLevel: any = undefined; + if (connection.driver instanceof SapDriver || connection.driver instanceof OracleDriver) { + isolationLevel = "READ COMMITTED"; + } + + const queryRunner = await connection.createQueryRunner(); + + if (connection.driver instanceof AuroraDataApiPostgresDriver || connection.driver instanceof AuroraDataApiDriver) { + const startTransactionFn = sinon.spy(connection.driver.client.startTransaction); + await queryRunner.startTransaction(); + + expect(beforeTransactionStart.calledBefore(startTransactionFn)).to.be.true; + expect(afterTransactionStart.calledAfter(startTransactionFn)).to.be.true; + + startTransactionFn.restore(); + await queryRunner.commitTransaction(); + + } else { + const startTransactionFn = sinon.spy(queryRunner, "query"); + + const queryCallBeforeTransactionStart = startTransactionFn.getCalls().find(call => { + return call.args[0] === "BEGIN TRANSACTION" + || call.args[0] === "START TRANSACTION" + || call.args[0] === "SET TRANSACTION ISOLATION LEVEL READ COMMITTED"; + }) + expect(queryCallBeforeTransactionStart).to.be.undefined; + + await queryRunner.startTransaction(isolationLevel); + + const queryCallAfterTransactionStart = startTransactionFn.getCalls().find(call => { + return call.args[0] === "BEGIN TRANSACTION" + || call.args[0] === "START TRANSACTION" + || call.args[0] === "SET TRANSACTION ISOLATION LEVEL READ COMMITTED"; + }); + expect(beforeTransactionStart.called).to.be.true; + expect(afterTransactionStart.called).to.be.true; + expect(queryCallAfterTransactionStart).to.be.not.undefined; + expect(beforeTransactionStart.getCall(0).calledBefore(queryCallAfterTransactionStart!)).to.be.true; + expect(afterTransactionStart.getCall(0).calledAfter(queryCallAfterTransactionStart!)).to.be.true; + + await queryRunner.commitTransaction(); + startTransactionFn.restore(); + } + + await queryRunner.release(); + } + }); + + it("transactionCommit", async () => { + + for (let connection of connections) { + if (connection.driver instanceof SqlServerDriver) return; + + beforeTransactionCommit.resetHistory(); + afterTransactionCommit.resetHistory(); + + const queryRunner = await connection.createQueryRunner(); + await queryRunner.startTransaction(); + + if (connection.driver instanceof AuroraDataApiPostgresDriver || connection.driver instanceof AuroraDataApiDriver) { + const commitTransactionFn = sinon.spy(connection.driver.client.commitTransaction); + await queryRunner.commitTransaction(); + + expect(beforeTransactionCommit.calledBefore(commitTransactionFn)).to.be.true; + expect(afterTransactionCommit.calledAfter(commitTransactionFn)).to.be.true; + + commitTransactionFn.restore(); + + } else { + const commitTransactionFn = sinon.spy(queryRunner, "query"); + + const queryCallBeforeTransactionCommit = commitTransactionFn.getCalls().find(call => { + return call.args[0] === "COMMIT"; + }); + expect(queryCallBeforeTransactionCommit).to.be.undefined; + + await queryRunner.commitTransaction(); + + const queryCallAfterTransactionCommit = commitTransactionFn.getCalls().find(call => { + return call.args[0] === "COMMIT"; + }); + expect(queryCallAfterTransactionCommit).to.be.not.undefined; + expect(beforeTransactionCommit.called).to.be.true; + expect(afterTransactionCommit.called).to.be.true; + expect(beforeTransactionCommit.getCall(0).calledBefore(queryCallAfterTransactionCommit!)).to.be.true; + expect(afterTransactionCommit.getCall(0).calledAfter(queryCallAfterTransactionCommit!)).to.be.true; + + commitTransactionFn.restore(); + } + + await queryRunner.release(); + } + }); + + it("transactionRollback", async () => { + + for (let connection of connections) { + if (connection.driver instanceof SqlServerDriver) return; + + beforeTransactionRollback.resetHistory(); + afterTransactionRollback.resetHistory(); + + const queryRunner = await connection.createQueryRunner(); + await queryRunner.startTransaction(); + + if (connection.driver instanceof AuroraDataApiPostgresDriver || connection.driver instanceof AuroraDataApiDriver) { + const rollbackTransactionFn = sinon.spy(connection.driver.client.rollbackTransaction); + await queryRunner.rollbackTransaction(); + + expect(beforeTransactionRollback.calledBefore(rollbackTransactionFn)).to.be.true; + expect(afterTransactionRollback.calledAfter(rollbackTransactionFn)).to.be.true; + + rollbackTransactionFn.restore(); + + } else { + const rollbackTransactionFn = sinon.spy(queryRunner, "query"); + + const queryCallBeforeTransactionRollback = rollbackTransactionFn.getCalls().find(call => { + return call.args[0] === "ROLLBACK"; + }); + expect(queryCallBeforeTransactionRollback).to.be.undefined; + + await queryRunner.rollbackTransaction(); + + const queryCallAfterTransactionRollback = rollbackTransactionFn.getCalls().find(call => { + return call.args[0] === "ROLLBACK"; + }); + expect(queryCallAfterTransactionRollback).to.be.not.undefined; + expect(beforeTransactionRollback.called).to.be.true; + expect(afterTransactionRollback.called).to.be.true; + expect(beforeTransactionRollback.getCall(0).calledBefore(queryCallAfterTransactionRollback!)).to.be.true; + expect(afterTransactionRollback.getCall(0).calledAfter(queryCallAfterTransactionRollback!)).to.be.true; + + rollbackTransactionFn.restore(); + } + + await queryRunner.release(); + } + }); + +}); diff --git a/test/functional/repository/find-options/repository-find-options.ts b/test/functional/repository/find-options/repository-find-options.ts index e899d6158c3..cc40d87607b 100644 --- a/test/functional/repository/find-options/repository-find-options.ts +++ b/test/functional/repository/find-options/repository-find-options.ts @@ -6,13 +6,13 @@ import {User} from "./entity/User"; import {Category} from "./entity/Category"; import {Post} from "./entity/Post"; import {Photo} from "./entity/Photo"; +import sinon from "sinon"; describe("repository > find options", () => { let connections: Connection[]; before(async () => connections = await createTestingConnections({ entities: [__dirname + "/entity/*{.js,.ts}"], - enabledDrivers: ["sqlite", "better-sqlite3"] })); beforeEach(() => reloadTestingDatabases(connections)); after(() => closeTestingConnections(connections)); @@ -51,6 +51,35 @@ describe("repository > find options", () => { }))); + it("should execute select query inside transaction", () => Promise.all(connections.map(async connection => { + + const user = new User(); + user.name = "Alex Messer"; + await connection.manager.save(user); + + + const queryRunner = await connection.createQueryRunner(); + + const startTransactionFn = sinon.spy(queryRunner, "startTransaction"); + const commitTransactionFn = sinon.spy(queryRunner, "commitTransaction"); + + expect(startTransactionFn.called).to.be.false; + expect(commitTransactionFn.called).to.be.false; + + await connection + .createEntityManager(queryRunner) + .getRepository(User) + .findOne(1, { + transaction: true + }); + + expect(startTransactionFn.calledOnce).to.be.true; + expect(commitTransactionFn.calledOnce).to.be.true; + + await queryRunner.release(); + + }))); + it("should select specific columns", () => Promise.all(connections.map(async connection => { const category = new Category(); From c683c8eeecea9b849a960a8bd5cd7cbb9a4eb4b1 Mon Sep 17 00:00:00 2001 From: Umed Khudoiberdiev Date: Mon, 2 Nov 2020 21:06:23 +0500 Subject: [PATCH 172/212] version bump --- CHANGELOG.md | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++ package.json | 2 +- 2 files changed, 59 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e2034de721d..0ad3a8919b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,61 @@ +## [0.2.29](https://github.com/typeorm/typeorm/compare/0.2.28...0.2.29) (2020-11-02) + +### Bug Fixes + +* allow falsey discriminator values ([#6973](https://github.com/typeorm/typeorm/issues/6973)) ([f3ba242](https://github.com/typeorm/typeorm/commit/f3ba2420396341ad3b808ea8540ea6a2272ff916)), closes [#3891](https://github.com/typeorm/typeorm/issues/3891) +* allow for complex jsonb primary key columns ([#6834](https://github.com/typeorm/typeorm/issues/6834)) ([f95e9d8](https://github.com/typeorm/typeorm/commit/f95e9d8f9a6c7a1117564b3e3f65b5294f8d5ff5)), closes [#6833](https://github.com/typeorm/typeorm/issues/6833) +* Allows valid non-object JSON to be retrieved in simple-json columns ([#6574](https://github.com/typeorm/typeorm/issues/6574)) ([0aedf43](https://github.com/typeorm/typeorm/commit/0aedf43874a6f950614134967bf4b173e4513ba0)), closes [#5501](https://github.com/typeorm/typeorm/issues/5501) +* Cannot read property 'hasMetadata' of undefined ([#5659](https://github.com/typeorm/typeorm/issues/5659)) ([0280cdc](https://github.com/typeorm/typeorm/commit/0280cdc451c35ef73c830eb1191c95d34f6ce06e)), closes [#3685](https://github.com/typeorm/typeorm/issues/3685) +* check if the connection is closed before executing a query. This prevents SQLITE_MISUSE errors (https://sqlite.org/rescode.html#misuse) originating from sqlite itself ([#6975](https://github.com/typeorm/typeorm/issues/6975)) ([5f6bbec](https://github.com/typeorm/typeorm/commit/5f6bbecd6166f1e80ed87d7e6c2c181fe463bdef)) +* check mysql constraint schema on join ([#6851](https://github.com/typeorm/typeorm/issues/6851)) ([d2b914d](https://github.com/typeorm/typeorm/commit/d2b914da6a425d47916c72ac50bfa69bea4847fb)), closes [#6169](https://github.com/typeorm/typeorm/issues/6169) [#6169](https://github.com/typeorm/typeorm/issues/6169) +* correct reading of custom ormconfig.env files ([#6922](https://github.com/typeorm/typeorm/issues/6922)) ([a09fb7f](https://github.com/typeorm/typeorm/commit/a09fb7fb919e7ebb1c174ba4b0abe09b245e0442)) +* explicitly define `query` command's param ([#6899](https://github.com/typeorm/typeorm/issues/6899)) ([4475d80](https://github.com/typeorm/typeorm/commit/4475d8067592b91b857f2b456dc31c5850a21081)), closes [#6896](https://github.com/typeorm/typeorm/issues/6896) +* findRoots should get the defined primary key column ([#6982](https://github.com/typeorm/typeorm/issues/6982)) ([f2ba901](https://github.com/typeorm/typeorm/commit/f2ba9012fe4e851bc667dfdfedc3fd4af665d52b)), closes [#6948](https://github.com/typeorm/typeorm/issues/6948) [#6948](https://github.com/typeorm/typeorm/issues/6948) +* Fix Mongodb delete by ObjectId. Closes [#6552](https://github.com/typeorm/typeorm/issues/6552) ([#6553](https://github.com/typeorm/typeorm/issues/6553)) ([e37eb1e](https://github.com/typeorm/typeorm/commit/e37eb1e8e8544f91c3d0a44b55322966e121b3af)) +* fixes the typescript errors in EntityCreateCommand & SubscriberCreateCommand ([#6824](https://github.com/typeorm/typeorm/issues/6824)) ([0221a93](https://github.com/typeorm/typeorm/commit/0221a933d19125cc0703a7fdd2a243b494ac5e72)) +* handle count multiple PK & edge cases more gracefully ([#6870](https://github.com/typeorm/typeorm/issues/6870)) ([4abfb34](https://github.com/typeorm/typeorm/commit/4abfb342aa390ab4643a1133daaf90c0996b61c2)), closes [#5989](https://github.com/typeorm/typeorm/issues/5989) [#5314](https://github.com/typeorm/typeorm/issues/5314) [#4550](https://github.com/typeorm/typeorm/issues/4550) +* Handle undefined querysets in QueryCommand ([#6910](https://github.com/typeorm/typeorm/issues/6910)) ([6f285dc](https://github.com/typeorm/typeorm/commit/6f285dce1ac315707fe01a892c1c74521a98aae2)), closes [#6612](https://github.com/typeorm/typeorm/issues/6612) +* handle Undefined values in driver URL options ([#6925](https://github.com/typeorm/typeorm/issues/6925)) ([6fa2df5](https://github.com/typeorm/typeorm/commit/6fa2df5ade71a3fee550e3c8fb7bcd7cd02080a8)) +* ILike operator generally available for any driver ([#6945](https://github.com/typeorm/typeorm/issues/6945)) ([37f0d8f](https://github.com/typeorm/typeorm/commit/37f0d8f7938ee5dbcf899a7f2855ea6dc6dc604e)) +* Only check for discriminator conflicts on STI entities ([#2985](https://github.com/typeorm/typeorm/issues/2985)) ([06903d1](https://github.com/typeorm/typeorm/commit/06903d1c914e8082620dbf16551caa302862d328)), closes [#2984](https://github.com/typeorm/typeorm/issues/2984) +* postgresql connection URL can use an UNIX Socket ([#2614](https://github.com/typeorm/typeorm/issues/2614)) ([#6042](https://github.com/typeorm/typeorm/issues/6042)) ([21c4166](https://github.com/typeorm/typeorm/commit/21c41663ccecfa5f2d94f94424f1a9a53e5d817c)) +* prevent create-type commands edge-case TypeErrors ([#6836](https://github.com/typeorm/typeorm/issues/6836)) ([08ec0a8](https://github.com/typeorm/typeorm/commit/08ec0a8ed922225ff529790ad5ff19c0e463954e)), closes [#6831](https://github.com/typeorm/typeorm/issues/6831) +* redundant migration with decimal default ([#6879](https://github.com/typeorm/typeorm/issues/6879)) ([6ff67f7](https://github.com/typeorm/typeorm/commit/6ff67f71fa7ad2bcf8a89c01ead7f54386e35f3a)), closes [#6140](https://github.com/typeorm/typeorm/issues/6140) [#5407](https://github.com/typeorm/typeorm/issues/5407) +* remove @DiscriminatorValue from error message ([#5256](https://github.com/typeorm/typeorm/issues/5256)) ([2bf15ca](https://github.com/typeorm/typeorm/commit/2bf15ca913016ad07080c38c9fc3ee848b60ca4f)), closes [#5255](https://github.com/typeorm/typeorm/issues/5255) +* resolves issue proto-less object validation ([#6884](https://github.com/typeorm/typeorm/issues/6884)) ([e08d9c6](https://github.com/typeorm/typeorm/commit/e08d9c61aab72f16ecd8bd790cb32bf0d164a5af)), closes [#2065](https://github.com/typeorm/typeorm/issues/2065) +* return null for nullable RelationId() column ([#6848](https://github.com/typeorm/typeorm/issues/6848)) ([7147a0d](https://github.com/typeorm/typeorm/commit/7147a0dbe7f2622a21c51edefa3b921f42e04b49)), closes [#6815](https://github.com/typeorm/typeorm/issues/6815) +* subscribers should use the subscribersDir ([5ef9450](https://github.com/typeorm/typeorm/commit/5ef94509b89f11f8337e18046c3f9d9632d234df)) +* support changing comments in MySQL columns ([#6903](https://github.com/typeorm/typeorm/issues/6903)) ([c5143aa](https://github.com/typeorm/typeorm/commit/c5143aab08a04e96aebb55996ed7683d48542bbd)) +* support combination of many-to-one/cacade/composte PK ([#6417](https://github.com/typeorm/typeorm/issues/6417)) ([9a0497b](https://github.com/typeorm/typeorm/commit/9a0497b533b2f6896b8e7d189b36dd3892e58007)) +* support empty `IN` clause across all dialects ([#6887](https://github.com/typeorm/typeorm/issues/6887)) ([9635080](https://github.com/typeorm/typeorm/commit/96350805fb9f02b8fb2c90b5528a15d5cdb9faeb)), closes [#4865](https://github.com/typeorm/typeorm/issues/4865) [#2195](https://github.com/typeorm/typeorm/issues/2195) +* support multiple row insert on oracle ([#6927](https://github.com/typeorm/typeorm/issues/6927)) ([a5eb946](https://github.com/typeorm/typeorm/commit/a5eb946117a18d94c0157188b6a39542c8d50756)), closes [#2434](https://github.com/typeorm/typeorm/issues/2434) +* sync the typeorm-model-shim ([#6891](https://github.com/typeorm/typeorm/issues/6891)) ([c72e48b](https://github.com/typeorm/typeorm/commit/c72e48b9c7b893f8a2483ba1ddaa7ded039fe349)), closes [#6288](https://github.com/typeorm/typeorm/issues/6288) [#5920](https://github.com/typeorm/typeorm/issues/5920) +* TreeRepository based entities primary column supports custom name. ([#6942](https://github.com/typeorm/typeorm/issues/6942)) ([7ec1b75](https://github.com/typeorm/typeorm/commit/7ec1b75f12832e4d99e1ed0cef40755f2b6d650a)) +* use `require` in `ReactNativeDriver` ([#6814](https://github.com/typeorm/typeorm/issues/6814)) ([1a6383c](https://github.com/typeorm/typeorm/commit/1a6383cecd74ee90388db313a74432f7ba12cfdf)), closes [#6811](https://github.com/typeorm/typeorm/issues/6811) +* use correct type for MongoQueryRunner.databaseConnection ([#6906](https://github.com/typeorm/typeorm/issues/6906)) ([da70b40](https://github.com/typeorm/typeorm/commit/da70b405498b142ecc29f7ff01e7a37f88227360)), closes [#6453](https://github.com/typeorm/typeorm/issues/6453) +* use pg ^8 in `init` command ([6ed9906](https://github.com/typeorm/typeorm/commit/6ed990666604ca9b8c0029d4fe972a039ef28570)) +* wrong FK loaded in multi-database environment ([#6828](https://github.com/typeorm/typeorm/issues/6828)) ([c060f95](https://github.com/typeorm/typeorm/commit/c060f95db0e261b02c4b28b19541cabcb1ac4a75)), closes [#6168](https://github.com/typeorm/typeorm/issues/6168) + + +### Features + +* add ability for escaping for Raw() find operator ([#6850](https://github.com/typeorm/typeorm/issues/6850)) ([91b85bf](https://github.com/typeorm/typeorm/commit/91b85bfe6e73ff93db2684a13935b9bd6a9abcfd)) +* add absolute path support to other CLI commands ([#6807](https://github.com/typeorm/typeorm/issues/6807)) ([d9a76e9](https://github.com/typeorm/typeorm/commit/d9a76e91bed06037ff28ec132893f40c09004438)) +* Add SelectQueryBuilder.getOneOrFail() ([#6885](https://github.com/typeorm/typeorm/issues/6885)) ([920e781](https://github.com/typeorm/typeorm/commit/920e7812cd9d405df921f9ae9ce52ba0a9743bea)), closes [#6246](https://github.com/typeorm/typeorm/issues/6246) +* backport ilike from next ([#6862](https://github.com/typeorm/typeorm/issues/6862)) ([c8bf81e](https://github.com/typeorm/typeorm/commit/c8bf81ed2d47ba0822f8d6267ae1997180db2e31)) +* Exit with code 1 on empty migration:generate ([#6978](https://github.com/typeorm/typeorm/issues/6978)) ([8244ea1](https://github.com/typeorm/typeorm/commit/8244ea1371d5cf37e3f80e1b141f5945af38cb5e)) +* schema synchronization for partitioned tables with PostgreSQL 12+ ([#6780](https://github.com/typeorm/typeorm/issues/6780)) ([990442e](https://github.com/typeorm/typeorm/commit/990442e891e91cd829f9f34eff2114d4c623d24b)) +* support `autoEncryption` option for MongoDB ([#6865](https://github.com/typeorm/typeorm/issues/6865)) ([b22c27f](https://github.com/typeorm/typeorm/commit/b22c27feb2dd3892d47a9e82b0d7b11650d059b5)) +* Support column comments in Postgres and CockroachDB ([#6902](https://github.com/typeorm/typeorm/issues/6902)) ([bc623a4](https://github.com/typeorm/typeorm/commit/bc623a42a868eae7c988779abc4cdc0bbf775def)), closes [#3360](https://github.com/typeorm/typeorm/issues/3360) +* support ESM in ormconfig js & ts ([#6853](https://github.com/typeorm/typeorm/issues/6853)) ([7ebca2b](https://github.com/typeorm/typeorm/commit/7ebca2b9b1fd21e546b3a345a069637d6aab4b3e)), closes [#5003](https://github.com/typeorm/typeorm/issues/5003) +* support query comments in the query builder ([#6892](https://github.com/typeorm/typeorm/issues/6892)) ([84c18a9](https://github.com/typeorm/typeorm/commit/84c18a9cab2e87b28eb046b5688bfca4d3ce9da6)), closes [#3643](https://github.com/typeorm/typeorm/issues/3643) +* transactional events in subscriber interface + "transaction" option in FindOptions ([#6996](https://github.com/typeorm/typeorm/issues/6996)) ([0e4b239](https://github.com/typeorm/typeorm/commit/0e4b2397a6e62f5f2c35e5890bba53abe40a49ac)) + +### Performance Improvements + +* Improve MySQL LoadTables Performance ([#6886](https://github.com/typeorm/typeorm/issues/6886)) ([0f0e0b6](https://github.com/typeorm/typeorm/commit/0f0e0b660c83409bb59f806b9f6e099ca8dbc61c)), closes [#6800](https://github.com/typeorm/typeorm/issues/6800) +* Improve replacePropertyNames ([#4760](https://github.com/typeorm/typeorm/issues/4760)) ([d86671c](https://github.com/typeorm/typeorm/commit/d86671cb179751730d0324b23d9f4bcb21010728)) + ## [0.2.28](https://github.com/typeorm/typeorm/compare/0.2.27...0.2.28) (2020-09-30) ### Bug Fixes diff --git a/package.json b/package.json index 73b32e39268..12a902e39df 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "typeorm", "private": true, - "version": "0.2.28", + "version": "0.2.29", "description": "Data-Mapper ORM for TypeScript, ES7, ES6, ES5. Supports MySQL, PostgreSQL, MariaDB, SQLite, MS SQL Server, Oracle, MongoDB databases.", "license": "MIT", "readmeFilename": "README.md", From aa99150ed68bc001f91e86da8af996a5f1d35b5b Mon Sep 17 00:00:00 2001 From: Bogdan Gusiev Date: Mon, 9 Nov 2020 05:24:10 +0200 Subject: [PATCH 173/212] refactor: Use ES6 style in postgres driver when making a query (#6991) --- src/driver/postgres/PostgresQueryRunner.ts | 60 ++++++++++------------ 1 file changed, 26 insertions(+), 34 deletions(-) diff --git a/src/driver/postgres/PostgresQueryRunner.ts b/src/driver/postgres/PostgresQueryRunner.ts index 7654bb82202..e366562766d 100644 --- a/src/driver/postgres/PostgresQueryRunner.ts +++ b/src/driver/postgres/PostgresQueryRunner.ts @@ -197,44 +197,36 @@ export class PostgresQueryRunner extends BaseQueryRunner implements QueryRunner /** * Executes a given SQL query. */ - query(query: string, parameters?: any[]): Promise { + async query(query: string, parameters?: any[]): Promise { if (this.isReleased) throw new QueryRunnerAlreadyReleasedError(); - return new Promise(async (ok, fail) => { - try { - const databaseConnection = await this.connect(); - this.driver.connection.logger.logQuery(query, parameters, this); - const queryStartTime = +new Date(); - - databaseConnection.query(query, parameters, (err: any, result: any) => { - // log slow queries if maxQueryExecution time is set - const maxQueryExecutionTime = this.driver.connection.options.maxQueryExecutionTime; - const queryEndTime = +new Date(); - const queryExecutionTime = queryEndTime - queryStartTime; - if (maxQueryExecutionTime && queryExecutionTime > maxQueryExecutionTime) - this.driver.connection.logger.logQuerySlow(queryExecutionTime, query, parameters, this); - - if (err) { - this.driver.connection.logger.logQueryError(err, query, parameters, this); - fail(new QueryFailedError(query, parameters, err)); - } else { - switch (result.command) { - case "DELETE": - case "UPDATE": - // for UPDATE and DELETE query additionally return number of affected rows - ok([result.rows, result.rowCount]); - break; - default: - ok(result.rows); - } - } - }); + const databaseConnection = await this.connect(); - } catch (err) { - fail(err); + this.driver.connection.logger.logQuery(query, parameters, this); + try { + const queryStartTime = +new Date(); + const result = await databaseConnection.query(query, parameters); + // log slow queries if maxQueryExecution time is set + const maxQueryExecutionTime = this.driver.connection.options.maxQueryExecutionTime; + const queryEndTime = +new Date(); + const queryExecutionTime = queryEndTime - queryStartTime; + if (maxQueryExecutionTime && queryExecutionTime > maxQueryExecutionTime) + this.driver.connection.logger.logQuerySlow(queryExecutionTime, query, parameters, this); + + switch (result.command) { + case "DELETE": + case "UPDATE": + // for UPDATE and DELETE query additionally return number of affected rows + return [result.rows, result.rowCount]; + break; + default: + return result.rows; } - }); + } catch (err) { + this.driver.connection.logger.logQueryError(err, query, parameters, this); + throw new QueryFailedError(query, parameters, err); + } } /** @@ -2112,7 +2104,7 @@ export class PostgresQueryRunner extends BaseQueryRunner implements QueryRunner */ protected escapeComment(comment?: string) { if (comment === undefined || comment.length === 0) { - return 'NULL'; + return "NULL"; } comment = comment From 6ef8ffe387980c51f9f20e9cc03d6199c7068ac5 Mon Sep 17 00:00:00 2001 From: Emily Marigold Klassen Date: Sun, 8 Nov 2020 19:25:14 -0800 Subject: [PATCH 174/212] fix: use default import of yargs for --help (#6986) --- src/cli.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cli.ts b/src/cli.ts index 26b9364c8fe..ebca7a4c8df 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -1,6 +1,6 @@ #!/usr/bin/env node import "reflect-metadata"; -import * as yargs from "yargs"; +import yargs from "yargs"; import {SchemaSyncCommand} from "./commands/SchemaSyncCommand"; import {SchemaDropCommand} from "./commands/SchemaDropCommand"; import {QueryCommand} from "./commands/QueryCommand"; From b35397ea07982a21d3b263cb0b7c04d5aa057d1a Mon Sep 17 00:00:00 2001 From: Peter Roberts Date: Mon, 9 Nov 2020 18:56:04 +0000 Subject: [PATCH 175/212] fix: Fix CLI query command TypeError (#7043) Switch to using named args property now that it is explicitly defined in the command. --- src/commands/QueryCommand.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/commands/QueryCommand.ts b/src/commands/QueryCommand.ts index 1916958b413..215bf9a442e 100644 --- a/src/commands/QueryCommand.ts +++ b/src/commands/QueryCommand.ts @@ -53,8 +53,9 @@ export class QueryCommand implements yargs.CommandModule { // create a query runner and execute query using it queryRunner = connection.createQueryRunner(); - console.log(chalk.green("Running query: ") + PlatformTools.highlightSql(args._[1])); - const queryResult = await queryRunner.query(args._[1]); + const query = args.query as string; + console.log(chalk.green("Running query: ") + PlatformTools.highlightSql(query)); + const queryResult = await queryRunner.query(query); if (typeof queryResult === "undefined") { console.log(chalk.green("Query has been executed. No result was returned.")); From b518fa15f9b2183545b3c0daa2447ecd38ecc859 Mon Sep 17 00:00:00 2001 From: James Ward Date: Tue, 10 Nov 2020 05:46:45 -0500 Subject: [PATCH 176/212] fix: handle overlapping property / database names in querybuilder (#7042) we should always prioritize replacement of any property path first, then property names, then database names, then relation values whenever there's ambiguous values fixes #7030 --- src/query-builder/QueryBuilder.ts | 37 +++++++++++++++++--------- test/github-issues/7030/entity/Post.ts | 20 ++++++++++++++ test/github-issues/7030/issue-7030.ts | 37 ++++++++++++++++++++++++++ 3 files changed, 82 insertions(+), 12 deletions(-) create mode 100644 test/github-issues/7030/entity/Post.ts create mode 100644 test/github-issues/7030/issue-7030.ts diff --git a/src/query-builder/QueryBuilder.ts b/src/query-builder/QueryBuilder.ts index 6482b6de28b..c3b340f276e 100644 --- a/src/query-builder/QueryBuilder.ts +++ b/src/query-builder/QueryBuilder.ts @@ -587,24 +587,37 @@ export abstract class QueryBuilder { const replacements: { [key: string]: string } = {}; - for (const column of alias.metadata.columns) { - if (!(column.propertyPath in replacements)) - replacements[column.propertyPath] = column.databaseName; - if (!(column.propertyName in replacements)) - replacements[column.propertyName] = column.databaseName; - if (!(column.databaseName in replacements)) - replacements[column.databaseName] = column.databaseName; + // Insert & overwrite the replacements from least to most relevant in our replacements object. + // To do this we iterate and overwrite in the order of relevance. + // Least to Most Relevant: + // * Relation Property Path to first join column key + // * Relation Property Path + Column Path + // * Column Database Name + // * Column Propety Name + // * Column Property Path + + for (const relation of alias.metadata.relations) { + if (relation.joinColumns.length > 0) + replacements[relation.propertyPath] = relation.joinColumns[0].databaseName; } for (const relation of alias.metadata.relations) { for (const joinColumn of [...relation.joinColumns, ...relation.inverseJoinColumns]) { - const key = `${relation.propertyPath}.${joinColumn.referencedColumn!.propertyPath}`; - if (!(key in replacements)) - replacements[key] = joinColumn.databaseName; + const propertyKey = `${relation.propertyPath}.${joinColumn.referencedColumn!.propertyPath}`; + replacements[propertyKey] = joinColumn.databaseName; } + } - if (relation.joinColumns.length > 0 && !(relation.propertyPath in replacements)) - replacements[relation.propertyPath] = relation.joinColumns[0].databaseName; + for (const column of alias.metadata.columns) { + replacements[column.databaseName] = column.databaseName; + } + + for (const column of alias.metadata.columns) { + replacements[column.propertyName] = column.databaseName; + } + + for (const column of alias.metadata.columns) { + replacements[column.propertyPath] = column.databaseName; } const replacementKeys = Object.keys(replacements); diff --git a/test/github-issues/7030/entity/Post.ts b/test/github-issues/7030/entity/Post.ts new file mode 100644 index 00000000000..306188a6587 --- /dev/null +++ b/test/github-issues/7030/entity/Post.ts @@ -0,0 +1,20 @@ +import { Column, Entity, PrimaryGeneratedColumn } from '../../../../src'; + + +@Entity() +export class Post { + + @PrimaryGeneratedColumn({ + type: 'integer', + name: 'id', + }) + oldId: number; + + @Column({ + nullable: false, + unique: true, + length: 38, + name: 'new_id', + }) + id: string; +} diff --git a/test/github-issues/7030/issue-7030.ts b/test/github-issues/7030/issue-7030.ts new file mode 100644 index 00000000000..9dcd705e27f --- /dev/null +++ b/test/github-issues/7030/issue-7030.ts @@ -0,0 +1,37 @@ +import { expect } from "chai"; +import {Connection} from "../../../src/connection/Connection"; +import { + createTestingConnections, + closeTestingConnections, + reloadTestingDatabases, +} from "../../utils/test-utils"; +import {Post} from "./entity/Post"; + +describe("github issues > #7030", () => { + let connections: Connection[]; + + before(async () => connections = await createTestingConnections({ + entities: [Post], + schemaCreate: true, + dropSchema: true, + enabledDrivers: ["postgres"] + })); + + beforeEach(() => reloadTestingDatabases(connections)); + after(() => closeTestingConnections(connections)); + + it("should insert and fetch from the expected column", () => Promise.all(connections.map(async connection => { + const id = '123e4567-e89b-12d3-a456-426614174000' + + const post = new Post(); + post.id = id; + + let postRepository = connection.getRepository(Post); + + await postRepository.save(post); + + const actualPost = await postRepository.findOneOrFail({ id }); + + expect(actualPost!.id).to.be.equal(id); + }))); +}); From 296eb390627c684998b28467a494ea686139cea9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rados=C5=82aw=20K=C5=82os?= Date: Tue, 10 Nov 2020 11:47:09 +0100 Subject: [PATCH 177/212] docs: add missing connection options for mongodb (#7046) Closes: #7037 --- docs/connection-options.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/connection-options.md b/docs/connection-options.md index 219e1410504..c5b89758662 100644 --- a/docs/connection-options.md +++ b/docs/connection-options.md @@ -370,6 +370,10 @@ See [SSL options](https://github.com/mysqljs/mysql#ssl-options). * `port` - Database host port. Default mongodb port is `27017`. +* `username` - Database username (replacement for `auth.user`). + +* `password` - Database password (replacement for `auth.password`). + * `database` - Database name. * `poolSize` - Set the maximum pool size for each individual server or proxy connection. From 6ce65fbf6be5e696c3ae907d3f8e63b1e7332a1e Mon Sep 17 00:00:00 2001 From: Arseny Yankovsky Date: Wed, 11 Nov 2020 09:16:16 +0100 Subject: [PATCH 178/212] fix(data-api): Fixed how data api driver uses and reuses a client (#6869) Now each queryRunner will have it's own client which will allow it to handle transactions correctly. --- .../AuroraDataApiPostgresDriver.ts | 28 +++++++++---------- .../AuroraDataApiPostgresQueryRunner.ts | 19 ++++++++----- .../aurora-data-api/AuroraDataApiDriver.ts | 22 ++++++--------- .../AuroraDataApiQueryRunner.ts | 15 ++++++---- .../entity-subscriber-transaction-flow.ts | 6 ++-- 5 files changed, 48 insertions(+), 42 deletions(-) diff --git a/src/driver/aurora-data-api-pg/AuroraDataApiPostgresDriver.ts b/src/driver/aurora-data-api-pg/AuroraDataApiPostgresDriver.ts index 254ed17bf85..be827d60602 100644 --- a/src/driver/aurora-data-api-pg/AuroraDataApiPostgresDriver.ts +++ b/src/driver/aurora-data-api-pg/AuroraDataApiPostgresDriver.ts @@ -28,8 +28,6 @@ export class AuroraDataApiPostgresDriver extends PostgresWrapper implements Driv */ DataApiDriver: any; - client: any; - // ------------------------------------------------------------------------- // Public Implemented Properties // ------------------------------------------------------------------------- @@ -56,16 +54,6 @@ export class AuroraDataApiPostgresDriver extends PostgresWrapper implements Driv // load data-api package this.loadDependencies(); - - this.client = new this.DataApiDriver( - this.options.region, - this.options.secretArn, - this.options.resourceArn, - this.options.database, - (query: string, parameters?: any[]) => this.connection.logger.logQuery(query, parameters), - this.options.serviceConfigOptions, - this.options.formatOptions, - ); } // ------------------------------------------------------------------------- @@ -90,7 +78,19 @@ export class AuroraDataApiPostgresDriver extends PostgresWrapper implements Driv * Creates a query runner used to execute database queries. */ createQueryRunner(mode: ReplicationMode) { - return new AuroraDataApiPostgresQueryRunner(this, mode); + return new AuroraDataApiPostgresQueryRunner( + this, + new this.DataApiDriver( + this.options.region, + this.options.secretArn, + this.options.resourceArn, + this.options.database, + (query: string, parameters?: any[]) => this.connection.logger.logQuery(query, parameters), + this.options.serviceConfigOptions, + this.options.formatOptions, + ), + mode + ); } // ------------------------------------------------------------------------- @@ -110,7 +110,7 @@ export class AuroraDataApiPostgresDriver extends PostgresWrapper implements Driv * Executes given query. */ protected executeQuery(connection: any, query: string) { - return this.client.query(query); + return this.connection.query(query); } /** diff --git a/src/driver/aurora-data-api-pg/AuroraDataApiPostgresQueryRunner.ts b/src/driver/aurora-data-api-pg/AuroraDataApiPostgresQueryRunner.ts index f2fc9f0fd00..f6950a4ef28 100644 --- a/src/driver/aurora-data-api-pg/AuroraDataApiPostgresQueryRunner.ts +++ b/src/driver/aurora-data-api-pg/AuroraDataApiPostgresQueryRunner.ts @@ -30,6 +30,8 @@ export class AuroraDataApiPostgresQueryRunner extends PostgresQueryRunnerWrapper */ driver: AuroraDataApiPostgresDriver; + protected client: any; + // ------------------------------------------------------------------------- // Protected Properties // ------------------------------------------------------------------------- @@ -48,8 +50,10 @@ export class AuroraDataApiPostgresQueryRunner extends PostgresQueryRunnerWrapper // Constructor // ------------------------------------------------------------------------- - constructor(driver: AuroraDataApiPostgresDriver, mode: ReplicationMode) { + constructor(driver: AuroraDataApiPostgresDriver, client: any, mode: ReplicationMode) { super(driver, mode); + + this.client = client } // ------------------------------------------------------------------------- @@ -99,7 +103,8 @@ export class AuroraDataApiPostgresQueryRunner extends PostgresQueryRunnerWrapper if (beforeBroadcastResult.promises.length > 0) await Promise.all(beforeBroadcastResult.promises); this.isTransactionActive = true; - await this.driver.client.startTransaction(); + + await this.client.startTransaction(); const afterBroadcastResult = new BroadcasterResult(); this.broadcaster.broadcastAfterTransactionStartEvent(afterBroadcastResult); @@ -113,12 +118,13 @@ export class AuroraDataApiPostgresQueryRunner extends PostgresQueryRunnerWrapper async commitTransaction(): Promise { if (!this.isTransactionActive) throw new TransactionNotStartedError(); - + const beforeBroadcastResult = new BroadcasterResult(); this.broadcaster.broadcastBeforeTransactionCommitEvent(beforeBroadcastResult); if (beforeBroadcastResult.promises.length > 0) await Promise.all(beforeBroadcastResult.promises); - await this.driver.client.commitTransaction(); + await this.client.commitTransaction(); + this.isTransactionActive = false; const afterBroadcastResult = new BroadcasterResult(); @@ -138,8 +144,7 @@ export class AuroraDataApiPostgresQueryRunner extends PostgresQueryRunnerWrapper this.broadcaster.broadcastBeforeTransactionRollbackEvent(beforeBroadcastResult); if (beforeBroadcastResult.promises.length > 0) await Promise.all(beforeBroadcastResult.promises); - await this.driver.client.rollbackTransaction(); - this.isTransactionActive = false; + await this.client.rollbackTransaction(); const afterBroadcastResult = new BroadcasterResult(); this.broadcaster.broadcastAfterTransactionRollbackEvent(afterBroadcastResult); @@ -153,7 +158,7 @@ export class AuroraDataApiPostgresQueryRunner extends PostgresQueryRunnerWrapper if (this.isReleased) throw new QueryRunnerAlreadyReleasedError(); - const result = await this.driver.client.query(query, parameters); + const result = await this.client.query(query, parameters); if (result.records) { return result.records; diff --git a/src/driver/aurora-data-api/AuroraDataApiDriver.ts b/src/driver/aurora-data-api/AuroraDataApiDriver.ts index 3138f9eb0c8..bdbb14d7cd8 100644 --- a/src/driver/aurora-data-api/AuroraDataApiDriver.ts +++ b/src/driver/aurora-data-api/AuroraDataApiDriver.ts @@ -33,8 +33,6 @@ export class AuroraDataApiDriver implements Driver { */ DataApiDriver: any; - client: any; - /** * Connection pool. * Used in non-replication mode. @@ -301,16 +299,6 @@ export class AuroraDataApiDriver implements Driver { // load mysql package this.loadDependencies(); - this.client = new this.DataApiDriver( - this.options.region, - this.options.secretArn, - this.options.resourceArn, - this.options.database, - (query: string, parameters?: any[]) => this.connection.logger.logQuery(query, parameters), - this.options.serviceConfigOptions, - this.options.formatOptions, - ); - // validate options to make sure everything is set // todo: revisit validation with replication in mind // if (!(this.options.host || (this.options.extra && this.options.extra.socketPath)) && !this.options.socketPath) @@ -357,7 +345,15 @@ export class AuroraDataApiDriver implements Driver { * Creates a query runner used to execute database queries. */ createQueryRunner(mode: ReplicationMode) { - return new AuroraDataApiQueryRunner(this); + return new AuroraDataApiQueryRunner(this, new this.DataApiDriver( + this.options.region, + this.options.secretArn, + this.options.resourceArn, + this.options.database, + (query: string, parameters?: any[]) => this.connection.logger.logQuery(query, parameters), + this.options.serviceConfigOptions, + this.options.formatOptions, + )); } /** diff --git a/src/driver/aurora-data-api/AuroraDataApiQueryRunner.ts b/src/driver/aurora-data-api/AuroraDataApiQueryRunner.ts index 94ae797b035..87099ddcb5b 100644 --- a/src/driver/aurora-data-api/AuroraDataApiQueryRunner.ts +++ b/src/driver/aurora-data-api/AuroraDataApiQueryRunner.ts @@ -37,6 +37,8 @@ export class AuroraDataApiQueryRunner extends BaseQueryRunner implements QueryRu driver: AuroraDataApiDriver; + protected client: any + // ------------------------------------------------------------------------- // Protected Properties // ------------------------------------------------------------------------- @@ -50,10 +52,11 @@ export class AuroraDataApiQueryRunner extends BaseQueryRunner implements QueryRu // Constructor // ------------------------------------------------------------------------- - constructor(driver: AuroraDataApiDriver) { + constructor(driver: AuroraDataApiDriver, client: any) { super(); this.driver = driver; this.connection = driver.connection; + this.client = client; this.broadcaster = new Broadcaster(this); } @@ -92,7 +95,8 @@ export class AuroraDataApiQueryRunner extends BaseQueryRunner implements QueryRu if (beforeBroadcastResult.promises.length > 0) await Promise.all(beforeBroadcastResult.promises); this.isTransactionActive = true; - await this.driver.client.startTransaction(); + await this.client.startTransaction(); + const afterBroadcastResult = new BroadcasterResult(); this.broadcaster.broadcastAfterTransactionStartEvent(afterBroadcastResult); @@ -111,7 +115,7 @@ export class AuroraDataApiQueryRunner extends BaseQueryRunner implements QueryRu this.broadcaster.broadcastBeforeTransactionCommitEvent(beforeBroadcastResult); if (beforeBroadcastResult.promises.length > 0) await Promise.all(beforeBroadcastResult.promises); - await this.driver.client.commitTransaction(); + await this.client.commitTransaction(); this.isTransactionActive = false; const afterBroadcastResult = new BroadcasterResult(); @@ -131,7 +135,8 @@ export class AuroraDataApiQueryRunner extends BaseQueryRunner implements QueryRu this.broadcaster.broadcastBeforeTransactionRollbackEvent(beforeBroadcastResult); if (beforeBroadcastResult.promises.length > 0) await Promise.all(beforeBroadcastResult.promises); - await this.driver.client.rollbackTransaction(); + await this.client.rollbackTransaction(); + this.isTransactionActive = false; const afterBroadcastResult = new BroadcasterResult(); @@ -146,7 +151,7 @@ export class AuroraDataApiQueryRunner extends BaseQueryRunner implements QueryRu if (this.isReleased) throw new QueryRunnerAlreadyReleasedError(); - const result = await this.driver.client.query(query, parameters); + const result = await this.client.query(query, parameters); if (result.records) { return result.records; diff --git a/test/functional/entity-subscriber-transaction-flow/entity-subscriber-transaction-flow.ts b/test/functional/entity-subscriber-transaction-flow/entity-subscriber-transaction-flow.ts index cdd235797c9..d9b404a6654 100644 --- a/test/functional/entity-subscriber-transaction-flow/entity-subscriber-transaction-flow.ts +++ b/test/functional/entity-subscriber-transaction-flow/entity-subscriber-transaction-flow.ts @@ -78,7 +78,7 @@ describe("entity subscriber transaction flow", () => { const queryRunner = await connection.createQueryRunner(); if (connection.driver instanceof AuroraDataApiPostgresDriver || connection.driver instanceof AuroraDataApiDriver) { - const startTransactionFn = sinon.spy(connection.driver.client.startTransaction); + const startTransactionFn = sinon.spy(queryRunner.startTransaction); await queryRunner.startTransaction(); expect(beforeTransactionStart.calledBefore(startTransactionFn)).to.be.true; @@ -130,7 +130,7 @@ describe("entity subscriber transaction flow", () => { await queryRunner.startTransaction(); if (connection.driver instanceof AuroraDataApiPostgresDriver || connection.driver instanceof AuroraDataApiDriver) { - const commitTransactionFn = sinon.spy(connection.driver.client.commitTransaction); + const commitTransactionFn = sinon.spy(queryRunner.commitTransaction); await queryRunner.commitTransaction(); expect(beforeTransactionCommit.calledBefore(commitTransactionFn)).to.be.true; @@ -176,7 +176,7 @@ describe("entity subscriber transaction flow", () => { await queryRunner.startTransaction(); if (connection.driver instanceof AuroraDataApiPostgresDriver || connection.driver instanceof AuroraDataApiDriver) { - const rollbackTransactionFn = sinon.spy(connection.driver.client.rollbackTransaction); + const rollbackTransactionFn = sinon.spy(queryRunner.rollbackTransaction); await queryRunner.rollbackTransaction(); expect(beforeTransactionRollback.calledBefore(rollbackTransactionFn)).to.be.true; From c4a36da62593469436b074873eba186f0f8b990d Mon Sep 17 00:00:00 2001 From: Eugene Manuilov Date: Sun, 15 Nov 2020 08:49:21 +0200 Subject: [PATCH 179/212] docs: added typeorm-uml to the extensions list. (#7066) --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index fbfd6d89d7e..4176f6c8382 100644 --- a/README.md +++ b/README.md @@ -1293,6 +1293,7 @@ There are several extensions that simplify working with TypeORM and integrating * [TypeORM integration](https://github.com/typeorm/typeorm-routing-controllers-extensions) with [routing-controllers](https://github.com/pleerock/routing-controllers) * Models generation from existing database - [typeorm-model-generator](https://github.com/Kononnable/typeorm-model-generator) * Fixtures loader - [typeorm-fixtures-cli](https://github.com/RobinCK/typeorm-fixtures) +* ER Diagram generator - [typeorm-uml](https://github.com/eugene-manuilov/typeorm-uml/) ## Contributing From f27622daf9784d06496975bbbcacdb0938fd2c82 Mon Sep 17 00:00:00 2001 From: ericcrosson-bitgo <67922293+ericcrosson-bitgo@users.noreply.github.com> Date: Wed, 2 Dec 2020 09:24:16 -0600 Subject: [PATCH 180/212] docs: fix grammatical error (#7133) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4176f6c8382..7d0dd605739 100644 --- a/README.md +++ b/README.md @@ -1305,7 +1305,7 @@ This project exists thanks to all the people who contribute: ## Sponsors -Open source is hard and time-consuming. If you want to invest into TypeORM's future you can become a sponsor and make our core team to spend more time on TypeORM's improvements and new features. [Become a sponsor](https://opencollective.com/typeorm) +Open source is hard and time-consuming. If you want to invest into TypeORM's future you can become a sponsor and allow our core team to spend more time on TypeORM's improvements and new features. [Become a sponsor](https://opencollective.com/typeorm) From f730bb9fc1908a65edacc07e5e364648efb48768 Mon Sep 17 00:00:00 2001 From: nocheintobi Date: Tue, 22 Dec 2020 08:45:07 +0100 Subject: [PATCH 181/212] fix: support MongoDB DNS seed list connection (#7136) As described in [MongoDB Docs](https://docs.mongodb.com/manual/reference/connection-string/#dns-seed-list-connection-format), an additional connection string format called DNS Seed List Connection format can be used. As this is the default format for MongoDB Atlas, the hosted service of MongoDB, this should be available also for typeorm. The connection format is identified by the url-schema "mongodb+srv" and does not allow specifying a port. Fixes #3347 Fixes #3133 --- src/driver/mongodb/MongoDriver.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/driver/mongodb/MongoDriver.ts b/src/driver/mongodb/MongoDriver.ts index b204df39dcf..ebf1a9b6487 100644 --- a/src/driver/mongodb/MongoDriver.ts +++ b/src/driver/mongodb/MongoDriver.ts @@ -438,11 +438,15 @@ export class MongoDriver implements Driver { * Builds connection url that is passed to underlying driver to perform connection to the mongodb database. */ protected buildConnectionUrl(options: { [key: string]: any }): string { - const credentialsUrlPart = (options.username && options.password) + const schemaUrlPart = options.type.toLowerCase(); + const credentialsUrlPart = (options.username && options.password) ? `${options.username}:${options.password}@` : ""; + const portUrlPart = (schemaUrlPart === "mongodb+srv") + ? "" + : `:${options.port || "27017"}`; - return `mongodb://${credentialsUrlPart}${options.host || "127.0.0.1"}:${options.port || "27017"}/${options.database || ""}`; + return `${schemaUrlPart}://${credentialsUrlPart}${options.host || "127.0.0.1"}${portUrlPart}/${options.database || ""}`; } /** From f0197710ab986b474ce0b6c260d57e8234a5bb4f Mon Sep 17 00:00:00 2001 From: Astrit Shehu Date: Tue, 22 Dec 2020 08:46:43 +0100 Subject: [PATCH 182/212] fix: add missing "comment" field to QB clone method (#7205) Closes: #7203 Co-authored-by: Astrit Shehu --- src/query-builder/QueryExpressionMap.ts | 1 + test/github-issues/7203/issue-7203.ts | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 test/github-issues/7203/issue-7203.ts diff --git a/src/query-builder/QueryExpressionMap.ts b/src/query-builder/QueryExpressionMap.ts index 42f1f61642b..93df26a5b21 100644 --- a/src/query-builder/QueryExpressionMap.ts +++ b/src/query-builder/QueryExpressionMap.ts @@ -434,6 +434,7 @@ export class QueryExpressionMap { map.callListeners = this.callListeners; map.useTransaction = this.useTransaction; map.nativeParameters = Object.assign({}, this.nativeParameters); + map.comment = this.comment; return map; } diff --git a/test/github-issues/7203/issue-7203.ts b/test/github-issues/7203/issue-7203.ts new file mode 100644 index 00000000000..8bd38357d9d --- /dev/null +++ b/test/github-issues/7203/issue-7203.ts @@ -0,0 +1,23 @@ +import {closeTestingConnections, createTestingConnections, reloadTestingDatabases} from "../../utils/test-utils"; +import {Connection} from "../../../src/connection/Connection"; +import {expect} from "chai"; + +describe("github issues > #7203 QueryExpressionMap doesn't clone comment field", () => { + let connections: Connection[]; + before( + async () => + (connections = await createTestingConnections({ + dropSchema: true, + enabledDrivers: ["postgres"], + })) + ); + beforeEach(() => reloadTestingDatabases(connections)); + after(() => closeTestingConnections(connections)); + + it("should be able to clone comment field", () => Promise.all(connections.map(async connection => { + const comment = "a comment"; + const queryBuilder = await connection.createQueryBuilder().comment(comment); + const clonedQueryBuilder = queryBuilder.clone(); + expect(clonedQueryBuilder.expressionMap.comment).to.be.eq(comment); + }))); +}); From 01941937df11abd63fad9da082e1b5cf6a1300ce Mon Sep 17 00:00:00 2001 From: rysi3k Date: Tue, 22 Dec 2020 08:48:22 +0100 Subject: [PATCH 183/212] fix: order should allow only model fields, not methods (#7188) Closes: #7178 Co-authored-by: Tomasz Rychlewicz --- src/common/EntityFieldsNames.ts | 6 ++++++ src/find-options/FindOneOptions.ts | 3 ++- 2 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 src/common/EntityFieldsNames.ts diff --git a/src/common/EntityFieldsNames.ts b/src/common/EntityFieldsNames.ts new file mode 100644 index 00000000000..9af3f4d8a50 --- /dev/null +++ b/src/common/EntityFieldsNames.ts @@ -0,0 +1,6 @@ +/** + * Interface of the entity fields names only (without functions) + */ +export type EntityFieldsNames = { + [P in keyof Entity]: Entity[P] extends Function ? never : P; +}[keyof Entity]; diff --git a/src/find-options/FindOneOptions.ts b/src/find-options/FindOneOptions.ts index 92c9ff96cbc..dcb016a474d 100644 --- a/src/find-options/FindOneOptions.ts +++ b/src/find-options/FindOneOptions.ts @@ -1,3 +1,4 @@ +import {EntityFieldsNames} from "../common/EntityFieldsNames"; import {JoinOptions} from "./JoinOptions"; import {ObjectLiteral} from "../common/ObjectLiteral"; import {FindConditions} from "./FindConditions"; @@ -30,7 +31,7 @@ export interface FindOneOptions { /** * Order, in which entities should be ordered. */ - order?: { [P in keyof Entity]?: "ASC"|"DESC"|1|-1 }; + order?: { [P in EntityFieldsNames]?: "ASC"|"DESC"|1|-1 }; /** * Enables or disables query result caching. From 66df9f1e5332fc47d8a47a8f50d74ea44bd339f8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 22 Dec 2020 12:51:20 +0500 Subject: [PATCH 184/212] chore(deps): bump ini from 1.3.5 to 1.3.7 (#7176) Bumps [ini](https://github.com/isaacs/ini) from 1.3.5 to 1.3.7. - [Release notes](https://github.com/isaacs/ini/releases) - [Commits](https://github.com/isaacs/ini/compare/v1.3.5...v1.3.7) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/package-lock.json b/package-lock.json index ab057ab553e..6a640473ebc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "typeorm", - "version": "0.2.28", + "version": "0.2.29", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -6116,9 +6116,9 @@ "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" }, "ini": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", - "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.7.tgz", + "integrity": "sha512-iKpRpXP+CrP2jyrxvg1kMUpXDyRUFDWurxbnVT1vQPx+Wz9uCYsMIqYuSBLV+PAaZG/d7kRLKRFc9oDMsH+mFQ==", "dev": true }, "inquirer": { @@ -7189,7 +7189,7 @@ "dependencies": { "pify": { "version": "2.3.0", - "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", "dev": true } @@ -9250,7 +9250,7 @@ "dependencies": { "pify": { "version": "2.3.0", - "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", "dev": true } @@ -9736,7 +9736,7 @@ }, "readable-stream": { "version": "2.3.6", - "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { From 9abe0076f65afba9034fb48ba3ebd43be7e7557a Mon Sep 17 00:00:00 2001 From: Alvise Trevisan Date: Tue, 29 Dec 2020 11:09:42 +0200 Subject: [PATCH 185/212] fix: avoid early release of PostgresQueryRunner (#7109) (#7185) * fix: avoid early release of PostgresQueryRunner (#7109) If the QueryRunner is not connected yet, release is a no-op * fix: avoid early release of PostgresQueryRunner (#7109) Revert no-op driver-wide early release, fix only for stream case. * fix: avoid early release of PostgresQueryRunner (#7109) Restrict stream unit test to drivers who implement the stream interface * fix: avoid early release of PostgresQueryRunner (#7109) Restrict unit test to drivers whose stream implementation works in master --- package-lock.json | 15 ++++++++ package.json | 1 + src/query-builder/SelectQueryBuilder.ts | 3 -- test/github-issues/7109/entity/Dummy.ts | 13 +++++++ test/github-issues/7109/issue-7109.ts | 46 +++++++++++++++++++++++++ 5 files changed, 75 insertions(+), 3 deletions(-) create mode 100644 test/github-issues/7109/entity/Dummy.ts create mode 100644 test/github-issues/7109/issue-7109.ts diff --git a/package-lock.json b/package-lock.json index 6a640473ebc..dcfe3a708a1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9298,6 +9298,12 @@ "integrity": "sha512-ukMTJXLI7/hZIwTW7hGMZJ0Lj0S2XQBCJ4Shv4y1zgQ/vqVea+FLhzywvPj0ujSuofu+yA4MYHGZPTsgjBgJ+w==", "dev": true }, + "pg-cursor": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/pg-cursor/-/pg-cursor-2.5.2.tgz", + "integrity": "sha512-yS0lxXA5WoIVK7BUgJr1uOJDJe5JxVezItTLvqnTXj6bF3di4UtQOrPx8RW3GpFmom2NTQfpEc2N6vvdpopQSw==", + "dev": true + }, "pg-int8": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", @@ -9316,6 +9322,15 @@ "integrity": "sha512-1uYCckkuTfzz/FCefvavRywkowa6M5FohNMF5OjKrqo9PSR8gYc8poVmwwYQaBxhmQdBjhtP514eXy9/Us2xKg==", "dev": true }, + "pg-query-stream": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pg-query-stream/-/pg-query-stream-4.0.0.tgz", + "integrity": "sha512-Jftit2EUBn+ilh4JtAgw0JXKR54vATmYHlZ4fmIlbZgL1qT/GKUuwMzLFT8QQm+qJHZwlRIIfkMUOP7soY38ag==", + "dev": true, + "requires": { + "pg-cursor": "^2.5.2" + } + }, "pg-types": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", diff --git a/package.json b/package.json index 12a902e39df..65e326afd8a 100644 --- a/package.json +++ b/package.json @@ -101,6 +101,7 @@ "mysql2": "^2.1.0", "oracledb": "^5.0.0", "pg": "^8.3.0", + "pg-query-stream": "^4.0.0", "redis": "^3.0.2", "remap-istanbul": "^0.13.0", "rimraf": "^3.0.2", diff --git a/src/query-builder/SelectQueryBuilder.ts b/src/query-builder/SelectQueryBuilder.ts index 50f7592183b..44d45041d07 100644 --- a/src/query-builder/SelectQueryBuilder.ts +++ b/src/query-builder/SelectQueryBuilder.ts @@ -1261,9 +1261,6 @@ export class SelectQueryBuilder extends QueryBuilder implements } throw error; - } finally { - if (queryRunner !== this.queryRunner) // means we created our own query runner - await queryRunner.release(); } } diff --git a/test/github-issues/7109/entity/Dummy.ts b/test/github-issues/7109/entity/Dummy.ts new file mode 100644 index 00000000000..9c91d783a1c --- /dev/null +++ b/test/github-issues/7109/entity/Dummy.ts @@ -0,0 +1,13 @@ +import {Entity, PrimaryGeneratedColumn} from "../../../../src"; +import {Column} from "../../../../src/decorator/columns/Column"; + +@Entity() +export class Dummy { + + @PrimaryGeneratedColumn() + id: number; + + @Column() + field: string; + +} \ No newline at end of file diff --git a/test/github-issues/7109/issue-7109.ts b/test/github-issues/7109/issue-7109.ts new file mode 100644 index 00000000000..5474540b80b --- /dev/null +++ b/test/github-issues/7109/issue-7109.ts @@ -0,0 +1,46 @@ +import "reflect-metadata"; +import {createTestingConnections, closeTestingConnections, reloadTestingDatabases} from "../../utils/test-utils"; +import {Connection} from "../../../src/connection/Connection"; +import {Dummy} from './entity/Dummy'; +import {ReadStream} from 'fs'; +import {expect} from "chai"; + +function ingestStream (stream: ReadStream): Promise { + let chunks: any[] = []; + return new Promise((resolve, reject) => { + stream.on('data', chunk => chunks.push(chunk)) + stream.on('error', reject) + stream.on('end', () => resolve(chunks)) + }) + } + +describe("github issues > #7109 stream() bug from 0.2.25 to 0.2.26 with postgresql", () => { + let connections: Connection[]; + before(async () => connections = await createTestingConnections({ + entities: [__dirname + "/entity/*{.js,.ts}"], + schemaCreate: true, + dropSchema: true, + enabledDrivers: ["postgres", "mysql", "mariadb", "cockroachdb"] + })); + beforeEach(() => reloadTestingDatabases(connections)); + after(() => closeTestingConnections(connections)); + + it("should release the QueryRunner created by a SelectQueryBuilder", () => Promise.all(connections.map(async connection => { + const values = [{field: "abc"}, {field: "def"}, {field: "ghi"}]; + // First create some test data + await connection.createQueryBuilder() + .insert() + .into(Dummy) + .values(values) + .execute(); + + // Stream data: + const stream = await connection.createQueryBuilder().from(Dummy, 'dummy').select('field').stream(); + const streamedEntities = await ingestStream(stream); + + // If the runner is properly released, the test is already successful; this assert is just a sanity check. + const extractFields = (val: {field: string}) => val.field; + expect(streamedEntities.map(extractFields)).to.have.members(values.map(extractFields)); + + }))); +}); \ No newline at end of file From f47b8773bf89851d12a608fa6d65df44aee856a2 Mon Sep 17 00:00:00 2001 From: Marius Obert Date: Tue, 29 Dec 2020 16:23:17 +0100 Subject: [PATCH 186/212] docs: remove SAP registry (#7224) This registry is deprecated now: --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 7d0dd605739..aa40f1cf42c 100644 --- a/README.md +++ b/README.md @@ -211,7 +211,6 @@ await timber.remove(); * for **SAP Hana** ``` - npm config set @sap:registry https://npm.sap.com npm i @sap/hana-client npm i hdb-pool ``` From eb82f786cbe3244351d5860289dace3169cf473b Mon Sep 17 00:00:00 2001 From: Ed Colvin Date: Mon, 4 Jan 2021 02:43:11 -0900 Subject: [PATCH 187/212] fix: get length attribute of postgres array columns (#7239) Change loadTables in PostgresQueryRunner to use pg_catalog to find length attribute of array columns. Previously, it relied on information_schema.columns character_maximum_length, which is null for array columns. This caused synchronize to always drop and recreate array columns. Closes: #6990 --- src/driver/postgres/PostgresQueryRunner.ts | 38 ++++++++++++++---- test/github-issues/6990/entity/foo.ts | 15 +++++++ test/github-issues/6990/issue-6990.ts | 46 ++++++++++++++++++++++ 3 files changed, 92 insertions(+), 7 deletions(-) create mode 100644 test/github-issues/6990/entity/foo.ts create mode 100644 test/github-issues/6990/issue-6990.ts diff --git a/src/driver/postgres/PostgresQueryRunner.ts b/src/driver/postgres/PostgresQueryRunner.ts index e366562766d..2e1a4efcf2f 100644 --- a/src/driver/postgres/PostgresQueryRunner.ts +++ b/src/driver/postgres/PostgresQueryRunner.ts @@ -1417,12 +1417,28 @@ export class PostgresQueryRunner extends BaseQueryRunner implements QueryRunner return `("table_schema" = '${schema}' AND "table_name" = '${name}')`; }).join(" OR "); const tablesSql = `SELECT * FROM "information_schema"."tables" WHERE ` + tablesCondition; + + /** + * Uses standard SQL information_schema.columns table and postgres-specific + * pg_catalog.pg_attribute table to get column information. + * @see https://stackoverflow.com/a/19541865 + */ const columnsSql = ` - SELECT - *, - pg_catalog.col_description(('"' || table_catalog || '"."' || table_schema || '"."' || table_name || '"')::regclass::oid, ordinal_position) as description, - ('"' || "udt_schema" || '"."' || "udt_name" || '"')::"regtype" AS "regtype" - FROM "information_schema"."columns" + SELECT columns.*, + pg_catalog.col_description(('"' || table_catalog || '"."' || table_schema || '"."' || table_name || '"')::regclass::oid, ordinal_position) AS description, + ('"' || "udt_schema" || '"."' || "udt_name" || '"')::"regtype" AS "regtype", + pg_catalog.format_type("col_attr"."atttypid", "col_attr"."atttypmod") AS "format_type" + FROM "information_schema"."columns" + LEFT JOIN "pg_catalog"."pg_attribute" AS "col_attr" + ON "col_attr"."attname" = "columns"."column_name" + AND "col_attr"."attrelid" = ( + SELECT + "cls"."oid" FROM "pg_catalog"."pg_class" AS "cls" + LEFT JOIN "pg_catalog"."pg_namespace" AS "ns" + ON "ns"."oid" = "cls"."relnamespace" + WHERE "cls"."relname" = "columns"."table_name" + AND "ns"."nspname" = "columns"."table_schema" + ) WHERE ` + tablesCondition; @@ -1595,9 +1611,17 @@ export class PostgresQueryRunner extends BaseQueryRunner implements QueryRunner } // check only columns that have length property - if (this.driver.withLengthColumnTypes.indexOf(tableColumn.type as ColumnType) !== -1 && dbColumn["character_maximum_length"]) { - const length = dbColumn["character_maximum_length"].toString(); + if (this.driver.withLengthColumnTypes.indexOf(tableColumn.type as ColumnType) !== -1) { + let length; + if (tableColumn.isArray) { + const match = /\((\d+)\)/.exec(dbColumn["format_type"]); + length = match ? match[1] : undefined; + } else if (dbColumn["character_maximum_length"]) { + length = dbColumn["character_maximum_length"].toString(); + } + if (length) { tableColumn.length = !this.isDefaultColumnLength(table, tableColumn, length) ? length : ""; + } } tableColumn.isNullable = dbColumn["is_nullable"] === "YES"; tableColumn.isPrimary = !!columnConstraints.find(constraint => constraint["constraint_type"] === "PRIMARY"); diff --git a/test/github-issues/6990/entity/foo.ts b/test/github-issues/6990/entity/foo.ts new file mode 100644 index 00000000000..a76c47b9276 --- /dev/null +++ b/test/github-issues/6990/entity/foo.ts @@ -0,0 +1,15 @@ +import { Column, Entity, PrimaryGeneratedColumn } from "../../../../src"; + +@Entity() +export class Foo { + @PrimaryGeneratedColumn() + id: number; + + @Column({ + array: true, + type: "varchar", + length: 64, + nullable: true, + }) + varchararray: string[]; +} diff --git a/test/github-issues/6990/issue-6990.ts b/test/github-issues/6990/issue-6990.ts new file mode 100644 index 00000000000..7606ea3cba5 --- /dev/null +++ b/test/github-issues/6990/issue-6990.ts @@ -0,0 +1,46 @@ +import "reflect-metadata"; +import { + closeTestingConnections, + createTestingConnections, + reloadTestingDatabases, +} from "../../utils/test-utils"; +import { Connection } from "../../../src/connection/Connection"; +import { Foo } from "./entity/foo"; +import { expect } from "chai"; + +describe("github issues > #6990 synchronize drops array columns in postgres if a length is set", () => { + let connections: Connection[]; + before( + async () => + (connections = await createTestingConnections({ + entities: [__dirname + "/entity/*{.js,.ts}"], + subscribers: [__dirname + "/subscriber/*{.js,.ts}"], + enabledDrivers: ["postgres"], + })) + ); + beforeEach(() => reloadTestingDatabases(connections)); + after(() => closeTestingConnections(connections)); + + it("should not drop varchar array column on synchronize using postgres driver", () => + Promise.all( + connections.map(async function (connection) { + const foo = new Foo(); + foo.id = 1; + foo.varchararray = ["able", "baker", "charlie"]; + await connection.manager.save(foo); + + await connection.synchronize(); + + const loadedFoo: + | Foo + | undefined = await connection.manager.findOne(Foo, 1); + + expect(loadedFoo).to.be.not.empty; + expect(loadedFoo!.varchararray).to.deep.eq([ + "able", + "baker", + "charlie", + ]); + }) + )); +}); From c119cb42a9af612426fcce2f6f545e433bd0d475 Mon Sep 17 00:00:00 2001 From: Rohan Talip Date: Mon, 4 Jan 2021 03:45:53 -0800 Subject: [PATCH 188/212] test: rename test GitHub issue 1465 and add "github issues > #issueNum" to the test description (#7234) * test: update the description for a test to include "github issues > #issueNum" * test: rename save-relation.ts to issue-1465.ts to match other tests Co-authored-by: Rohan Talip --- test/github-issues/1465/{save-relation.ts => issue-1465.ts} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename test/github-issues/1465/{save-relation.ts => issue-1465.ts} (94%) diff --git a/test/github-issues/1465/save-relation.ts b/test/github-issues/1465/issue-1465.ts similarity index 94% rename from test/github-issues/1465/save-relation.ts rename to test/github-issues/1465/issue-1465.ts index e0ee4f0ce2d..723f7c137f8 100644 --- a/test/github-issues/1465/save-relation.ts +++ b/test/github-issues/1465/issue-1465.ts @@ -5,7 +5,7 @@ import {closeTestingConnections, createTestingConnections, reloadTestingDatabase import {Account} from "./entity/Account"; import {AccountActivationToken} from "./entity/AccountActivationToken"; -describe("save child and parent entity", () => { +describe("github issues > #1465 save child and parent entity", () => { let connections: Connection[] = []; before(async () => connections = await createTestingConnections({ From 7e3a36bf07ccfd0f422a60150d2915c73163e524 Mon Sep 17 00:00:00 2001 From: Rohan Talip Date: Mon, 4 Jan 2021 04:08:40 -0800 Subject: [PATCH 189/212] test: add describe to a couple of tests and refactor them (#7233) Co-authored-by: Rohan Talip --- test/github-issues/3158/issue-3158.ts | 34 ++++++++++++++------------- test/github-issues/3588/issue-3588.ts | 32 +++++++++++++------------ 2 files changed, 35 insertions(+), 31 deletions(-) diff --git a/test/github-issues/3158/issue-3158.ts b/test/github-issues/3158/issue-3158.ts index 7f26cc6da9e..89768cb3382 100644 --- a/test/github-issues/3158/issue-3158.ts +++ b/test/github-issues/3158/issue-3158.ts @@ -2,21 +2,23 @@ import "reflect-metadata"; import { createTestingConnections, closeTestingConnections, reloadTestingDatabases } from "../../utils/test-utils"; import { Connection } from "../../../src/connection/Connection"; import { expect } from "chai"; -it("github issues > #3158 Cannot run sync a second time", async () => { + +describe("github issues > #3158 Cannot run sync a second time", async () => { let connections: Connection[]; - connections = await createTestingConnections({ - entities: [__dirname + "/entity/*{.js,.ts}"], - schemaCreate: true, - dropSchema: true, - enabledDrivers: ["mysql", "mariadb", "oracle", "mssql", "sqljs", "sqlite", "better-sqlite3"], - // todo(AlexMesser): check why tests are failing under postgres driver - }); - await reloadTestingDatabases(connections); - await Promise.all(connections.map(async connection => { - const schemaBuilder = connection.driver.createSchemaBuilder(); - const syncQueries = await schemaBuilder.log(); - expect(syncQueries.downQueries).to.be.eql([]); - expect(syncQueries.upQueries).to.be.eql([]); - })); - await closeTestingConnections(connections); + before(async () => connections = await createTestingConnections({ + entities: [__dirname + "/entity/*{.js,.ts}"], + schemaCreate: true, + dropSchema: true, + enabledDrivers: ["mysql", "mariadb", "oracle", "mssql", "sqljs", "sqlite", "better-sqlite3"], + // todo(AlexMesser): check why tests are failing under postgres driver + })); + beforeEach(async () => await reloadTestingDatabases(connections)); + after(async () => await closeTestingConnections(connections)); + + it("can recognize model changes", () => Promise.all(connections.map(async connection => { + const schemaBuilder = connection.driver.createSchemaBuilder(); + const syncQueries = await schemaBuilder.log(); + expect(syncQueries.downQueries).to.be.eql([]); + expect(syncQueries.upQueries).to.be.eql([]); + }))); }); diff --git a/test/github-issues/3588/issue-3588.ts b/test/github-issues/3588/issue-3588.ts index ba45afecd32..cffa0598c43 100644 --- a/test/github-issues/3588/issue-3588.ts +++ b/test/github-issues/3588/issue-3588.ts @@ -2,20 +2,22 @@ import "reflect-metadata"; import { createTestingConnections, closeTestingConnections, reloadTestingDatabases } from "../../utils/test-utils"; import { Connection } from "../../../src/connection/Connection"; import { expect } from "chai"; -it("github issues > #3588 Migration:generate issue with onUpdate using mysql 8.0", async () => { + +describe("github issues > #3588 Migration:generate issue with onUpdate using mysql 8.0", async () => { let connections: Connection[]; - connections = await createTestingConnections({ - entities: [__dirname + "/entity/*{.js,.ts}"], - schemaCreate: true, - dropSchema: true, - enabledDrivers: ["mysql"], - }); - await reloadTestingDatabases(connections); - await Promise.all(connections.map(async connection => { - const schemaBuilder = connection.driver.createSchemaBuilder(); - const syncQueries = await schemaBuilder.log(); - expect(syncQueries.downQueries).to.be.eql([]); - expect(syncQueries.upQueries).to.be.eql([]); - })); - await closeTestingConnections(connections); + before(async () => connections = await createTestingConnections({ + entities: [__dirname + "/entity/*{.js,.ts}"], + schemaCreate: true, + dropSchema: true, + enabledDrivers: ["mysql"], + })); + beforeEach(async () => await reloadTestingDatabases(connections)); + after(async () => await closeTestingConnections(connections)); + + it("can recognize model changes", () => Promise.all(connections.map(async connection => { + const schemaBuilder = connection.driver.createSchemaBuilder(); + const syncQueries = await schemaBuilder.log(); + expect(syncQueries.downQueries).to.be.eql([]); + expect(syncQueries.upQueries).to.be.eql([]); + }))); }); From 16954c3213bb611c497dc136a9164760049e9056 Mon Sep 17 00:00:00 2001 From: Rohan Talip Date: Mon, 4 Jan 2021 04:09:07 -0800 Subject: [PATCH 190/212] test: update the description for some tests to include "github issues > #issueNum" (#7232) Co-authored-by: Rohan Talip --- test/github-issues/6284/issue-6284.ts | 2 +- test/github-issues/863/issue-863.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/github-issues/6284/issue-6284.ts b/test/github-issues/6284/issue-6284.ts index ff686e3cd98..85231df5090 100644 --- a/test/github-issues/6284/issue-6284.ts +++ b/test/github-issues/6284/issue-6284.ts @@ -4,7 +4,7 @@ import { ConnectionOptionsReader } from "../../../src/connection/ConnectionOptio import { importClassesFromDirectories } from "../../../src/util/DirectoryExportedClassesLoader"; import { LoggerFactory } from "../../../src/logger/LoggerFactory"; -describe("cli support for cjs extension", () => { +describe("github issues > #6284 cli support for cjs extension", () => { it("will load a cjs file", async () => { const cjsConfigPath = [__dirname, "ormconfig.cjs"].join("/"); const databaseType = "postgres"; diff --git a/test/github-issues/863/issue-863.ts b/test/github-issues/863/issue-863.ts index 53a89a76f6f..937a22f6989 100644 --- a/test/github-issues/863/issue-863.ts +++ b/test/github-issues/863/issue-863.ts @@ -5,7 +5,7 @@ import { Connection } from "../../../src/connection/Connection"; import { Master } from "./entities/master"; import { Detail } from "./entities/detail"; -describe("indices > create schema", () => { +describe("github issues > #863 indices > create schema", () => { let connections: Connection[]; before(async () => connections = await createTestingConnections({ From d91f74979ed4a389928e106a6c3b53beaa848432 Mon Sep 17 00:00:00 2001 From: Rohan Talip Date: Mon, 4 Jan 2021 04:09:32 -0800 Subject: [PATCH 191/212] test: remove unnecessary await (#7231) Co-authored-by: Rohan Talip --- test/github-issues/4415/issue-4415.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/github-issues/4415/issue-4415.ts b/test/github-issues/4415/issue-4415.ts index 5f0a08af579..5d46f6400b4 100644 --- a/test/github-issues/4415/issue-4415.ts +++ b/test/github-issues/4415/issue-4415.ts @@ -44,7 +44,7 @@ describe("github issues > #4415 allow beautify generated migrations", () => { await reloadTestingDatabases(connections); await closeTestingConnections(connections); - connectionOptions = await setupTestingConnections({ + connectionOptions = setupTestingConnections({ entities: [Username, Post], enabledDrivers }); From 7cdf3767812b36f514e056c5ba98d0e3a891be81 Mon Sep 17 00:00:00 2001 From: Rohan Talip Date: Mon, 4 Jan 2021 04:09:56 -0800 Subject: [PATCH 192/212] test: update the description for some tests under test/github-issues to include #issueNum (#7230) Co-authored-by: Rohan Talip --- test/github-issues/300/issue-300.ts | 2 +- test/github-issues/306/issue-306.ts | 2 +- test/github-issues/341/issue-341.ts | 2 +- test/github-issues/345/issue-345.ts | 2 +- test/github-issues/4782/issue-4782.ts | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/test/github-issues/300/issue-300.ts b/test/github-issues/300/issue-300.ts index a9b89927c4b..2e9c986372d 100644 --- a/test/github-issues/300/issue-300.ts +++ b/test/github-issues/300/issue-300.ts @@ -4,7 +4,7 @@ import {Connection} from "../../../src/connection/Connection"; import {expect} from "chai"; import {Race} from "./entity/Race"; -describe("github issues > support of embeddeds that are not set", () => { +describe("github issues > #300 support of embeddeds that are not set", () => { let connections: Connection[]; before(async () => connections = await createTestingConnections({ diff --git a/test/github-issues/306/issue-306.ts b/test/github-issues/306/issue-306.ts index 1c570642a11..6900c03c88c 100644 --- a/test/github-issues/306/issue-306.ts +++ b/test/github-issues/306/issue-306.ts @@ -5,7 +5,7 @@ import {expect} from "chai"; import {Race} from "./entity/Race"; import {Duration} from "./entity/Duration"; -describe("github issues > embeddeds with custom column name don't work", () => { +describe("github issues > #306 embeddeds with custom column name don't work", () => { let connections: Connection[]; before(async () => connections = await createTestingConnections({ diff --git a/test/github-issues/341/issue-341.ts b/test/github-issues/341/issue-341.ts index 9510745533a..7776162e13d 100644 --- a/test/github-issues/341/issue-341.ts +++ b/test/github-issues/341/issue-341.ts @@ -5,7 +5,7 @@ import {Post} from "./entity/Post"; import {Category} from "./entity/Category"; import {expect} from "chai"; -describe("github issues > OneToOne relation with referencedColumnName does not work", () => { +describe("github issues > #341 OneToOne relation with referencedColumnName does not work", () => { let connections: Connection[]; before(async () => connections = await createTestingConnections({ diff --git a/test/github-issues/345/issue-345.ts b/test/github-issues/345/issue-345.ts index bf3054b5766..1c987370e81 100644 --- a/test/github-issues/345/issue-345.ts +++ b/test/github-issues/345/issue-345.ts @@ -5,7 +5,7 @@ import {Post} from "./entity/Post"; import {Category} from "./entity/Category"; import {expect} from "chai"; -describe("github issues > Join query on ManyToMany relations not working", () => { +describe("github issues > #345 Join query on ManyToMany relations not working", () => { let connections: Connection[]; before(async () => connections = await createTestingConnections({ diff --git a/test/github-issues/4782/issue-4782.ts b/test/github-issues/4782/issue-4782.ts index b54b58c4f9c..6e03bddb039 100644 --- a/test/github-issues/4782/issue-4782.ts +++ b/test/github-issues/4782/issue-4782.ts @@ -4,7 +4,7 @@ import {Connection} from "../../../src/connection/Connection"; import {expect} from "chai"; import { VersionUtils } from "../../../src/util/VersionUtils"; -describe("github issues > 4782 mariadb driver wants to recreate create/update date columns CURRENT_TIMESTAMP(6) === current_timestamp(6)", () => { +describe("github issues > #4782 mariadb driver wants to recreate create/update date columns CURRENT_TIMESTAMP(6) === current_timestamp(6)", () => { let connections: Connection[]; before(async () => connections = await createTestingConnections({ From a9e039eae4a7c91afd01cd430c84244fc38be46e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl?= Date: Mon, 11 Jan 2021 11:16:06 +0100 Subject: [PATCH 193/212] chore: update dependency cli-highlight to v2.1.10 (#7265) Closes: #7259 --- package-lock.json | 234 ++++++++-------------------------------------- package.json | 2 +- 2 files changed, 39 insertions(+), 197 deletions(-) diff --git a/package-lock.json b/package-lock.json index dcfe3a708a1..c81b332f8b7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1761,115 +1761,16 @@ } }, "cli-highlight": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/cli-highlight/-/cli-highlight-2.1.4.tgz", - "integrity": "sha512-s7Zofobm20qriqDoU9sXptQx0t2R9PEgac92mENNm7xaEe1hn71IIMsXMK+6encA6WRCWWxIGQbipr3q998tlQ==", + "version": "2.1.10", + "resolved": "https://registry.npmjs.org/cli-highlight/-/cli-highlight-2.1.10.tgz", + "integrity": "sha512-CcPFD3JwdQ2oSzy+AMG6j3LRTkNjM82kzcSKzoVw6cLanDCJNlsLjeqVTOTfOfucnWv5F0rmBemVf1m9JiIasw==", "requires": { - "chalk": "^3.0.0", - "highlight.js": "^9.6.0", + "chalk": "^4.0.0", + "highlight.js": "^10.0.0", "mz": "^2.4.0", "parse5": "^5.1.1", - "parse5-htmlparser2-tree-adapter": "^5.1.1", - "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.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" - } - }, - "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" - } - }, - "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==" - }, - "get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" - }, - "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==" - }, - "require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" - }, - "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" - } - }, - "y18n": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", - "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==" - }, - "yargs": { - "version": "15.4.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", - "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", - "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": "^18.1.2" - } - } + "parse5-htmlparser2-tree-adapter": "^6.0.0", + "yargs": "^16.0.0" } }, "cli-truncate": { @@ -1928,83 +1829,6 @@ "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", "dev": true }, - "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" - }, - "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.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" - } - }, - "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==" - }, - "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==" - }, - "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" - } - } - } - }, "clone": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", @@ -2709,7 +2533,8 @@ "decamelize": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true }, "decamelize-keys": { "version": "1.1.0", @@ -3902,6 +3727,7 @@ "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" @@ -3910,7 +3736,8 @@ "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==" + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true } } }, @@ -5959,9 +5786,9 @@ "dev": true }, "highlight.js": { - "version": "9.18.3", - "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.18.3.tgz", - "integrity": "sha512-zBZAmhSupHIl5sITeMqIJnYCDfAEc3Gdkqj65wC1lpI468MMQeeQkhcIAvk+RylAkxrCcI9xy9piHiXeQ1BdzQ==" + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.5.0.tgz", + "integrity": "sha512-xTmvd9HiIHR6L53TMC7TKolEj65zG1XU+Onr8oi86mYa+nLcIbxTTWkpW7CsEwv/vK7u1zb8alZIMLDqqN6KTw==" }, "homedir-polyfill": { "version": "1.0.3", @@ -7199,6 +7026,7 @@ "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" } @@ -9065,6 +8893,7 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, "requires": { "p-try": "^2.0.0" } @@ -9073,6 +8902,7 @@ "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" } @@ -9089,7 +8919,8 @@ "p-try": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true }, "packet-reader": { "version": "1.0.0", @@ -9163,11 +8994,18 @@ "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==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz", + "integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==", "requires": { - "parse5": "^5.1.1" + "parse5": "^6.0.1" + }, + "dependencies": { + "parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==" + } } }, "pascalcase": { @@ -10339,7 +10177,8 @@ "set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true }, "set-value": { "version": "2.0.1", @@ -11772,7 +11611,8 @@ "which-module": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true }, "which-pm-runs": { "version": "1.0.0", @@ -12092,6 +11932,7 @@ "version": "18.1.3", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "dev": true, "requires": { "camelcase": "^5.0.0", "decamelize": "^1.2.0" @@ -12100,7 +11941,8 @@ "camelcase": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true } } }, diff --git a/package.json b/package.json index 65e326afd8a..bbcd72ab91a 100644 --- a/package.json +++ b/package.json @@ -119,7 +119,7 @@ "app-root-path": "^3.0.0", "buffer": "^5.5.0", "chalk": "^4.1.0", - "cli-highlight": "^2.1.4", + "cli-highlight": "^2.1.10", "debug": "^4.1.1", "dotenv": "^8.2.0", "glob": "^7.1.6", From 37698fea1385f51424349e15e679978049e25336 Mon Sep 17 00:00:00 2001 From: Saydolimkhon Agzamkhodjaev Date: Mon, 11 Jan 2021 04:19:26 -0600 Subject: [PATCH 194/212] docs: update Repository.ts (#7254) Fixed typos in method documentations: Intended use of "present" in its meaning as an adjective should be preceded with a verb (in this case, "are"). Fixed an indefinite article before plural noun: "an entities" -> "entities" --- src/repository/Repository.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/repository/Repository.ts b/src/repository/Repository.ts index 96c9223fa73..6050de50de2 100644 --- a/src/repository/Repository.ts +++ b/src/repository/Repository.ts @@ -80,14 +80,14 @@ export class Repository { create(): Entity; /** - * Creates a new entities and copies all entity properties from given objects into their new entities. - * Note that it copies only properties that present in entity schema. + * Creates new entities and copies all entity properties from given objects into their new entities. + * Note that it copies only properties that are present in entity schema. */ create(entityLikeArray: DeepPartial[]): Entity[]; /** * Creates a new entity instance and copies all entity properties from this object into a new entity. - * Note that it copies only properties that present in entity schema. + * Note that it copies only properties that are present in entity schema. */ create(entityLike: DeepPartial): Entity; From ce9cb8732cb70458f29c0976d980d34b0f4fa3d7 Mon Sep 17 00:00:00 2001 From: Jorge Luis Vargas Date: Mon, 11 Jan 2021 11:40:05 +0100 Subject: [PATCH 195/212] feat: JavaScript file migrations output (#7253) --- src/commands/MigrationCreateCommand.ts | 29 +++++++++++++++++-- src/commands/MigrationGenerateCommand.ts | 37 ++++++++++++++++++++++-- 2 files changed, 62 insertions(+), 4 deletions(-) diff --git a/src/commands/MigrationCreateCommand.ts b/src/commands/MigrationCreateCommand.ts index e33d69c4597..d4cb7f3fc66 100644 --- a/src/commands/MigrationCreateCommand.ts +++ b/src/commands/MigrationCreateCommand.ts @@ -33,6 +33,12 @@ export class MigrationCreateCommand implements yargs.CommandModule { alias: "config", default: "ormconfig", describe: "Name of the file with connection configuration." + }) + .option("o", { + alias: "outputJs", + type: "boolean", + default: false, + describe: "Generate a migration file on Javascript instead of Typescript", }); } @@ -43,8 +49,11 @@ export class MigrationCreateCommand implements yargs.CommandModule { try { const timestamp = new Date().getTime(); - const fileContent = MigrationCreateCommand.getTemplate(args.name as any, timestamp); - const filename = timestamp + "-" + args.name + ".ts"; + const fileContent = args.outputJs ? + MigrationCreateCommand.getJavascriptTemplate(args.name as any, timestamp) + : MigrationCreateCommand.getTemplate(args.name as any, timestamp); + const extension = args.outputJs ? ".js" : ".ts"; + const filename = timestamp + "-" + args.name + extension; let directory = args.dir as string | undefined; // if directory is not set then try to open tsconfig and find default path there @@ -95,4 +104,20 @@ export class ${camelCase(name, true)}${timestamp} implements MigrationInterface `; } + /** + * Gets contents of the migration file in Javascript. + */ + protected static getJavascriptTemplate(name: string, timestamp: number): string { + return `const { MigrationInterface, QueryRunner } = require("typeorm"); + +module.exports = class ${camelCase(name, true)}${timestamp} { + + async up(queryRunner) { + } + + async down(queryRunner) { + } +} + `; + } } diff --git a/src/commands/MigrationGenerateCommand.ts b/src/commands/MigrationGenerateCommand.ts index 07f5ac87297..f10d198497e 100644 --- a/src/commands/MigrationGenerateCommand.ts +++ b/src/commands/MigrationGenerateCommand.ts @@ -44,6 +44,12 @@ export class MigrationGenerateCommand implements yargs.CommandModule { alias: "config", default: "ormconfig", describe: "Name of the file with connection configuration." + }) + .option("o", { + alias: "outputJs", + type: "boolean", + default: false, + describe: "Generate a migration file on Javascript instead of Typescript", }); } @@ -53,7 +59,8 @@ export class MigrationGenerateCommand implements yargs.CommandModule { } const timestamp = new Date().getTime(); - const filename = timestamp + "-" + args.name + ".ts"; + const extension = args.outputJs ? ".js" : ".ts"; + const filename = timestamp + "-" + args.name + extension; let directory = args.dir; // if directory is not set then try to open tsconfig and find default path there @@ -119,7 +126,9 @@ export class MigrationGenerateCommand implements yargs.CommandModule { if (upSqls.length) { if (args.name) { - const fileContent = MigrationGenerateCommand.getTemplate(args.name as any, timestamp, upSqls, downSqls.reverse()); + const fileContent = args.outputJs ? + MigrationGenerateCommand.getJavascriptTemplate(args.name as any, timestamp, upSqls, downSqls.reverse()) : + MigrationGenerateCommand.getTemplate(args.name as any, timestamp, upSqls, downSqls.reverse()); const path = process.cwd() + "/" + (directory ? (directory + "/") : "") + filename; await CommandUtils.createFile(path, fileContent); @@ -178,6 +187,30 @@ ${downSqls.join(` `; } + /** + * Gets contents of the migration file in Javascript. + */ + protected static getJavascriptTemplate(name: string, timestamp: number, upSqls: string[], downSqls: string[]): string { + const migrationName = `${camelCase(name, true)}${timestamp}`; + + return `const { MigrationInterface, QueryRunner } = require("typeorm"); + +module.exports = class ${migrationName} { + name = '${migrationName}' + + async up(queryRunner) { +${upSqls.join(` +`)} + } + + async down(queryRunner) { +${downSqls.join(` +`)} + } +} +`; + } + /** * */ From ea3bc3527654bca247a0bc6e014ee1bdbca683a3 Mon Sep 17 00:00:00 2001 From: Will Dembinski Date: Mon, 11 Jan 2021 02:42:55 -0800 Subject: [PATCH 196/212] docs: update OneToMany grammar (#7252) --- src/decorator/relations/OneToMany.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/decorator/relations/OneToMany.ts b/src/decorator/relations/OneToMany.ts index e174ba8f084..ae32f1cf3b4 100644 --- a/src/decorator/relations/OneToMany.ts +++ b/src/decorator/relations/OneToMany.ts @@ -2,8 +2,8 @@ import {getMetadataArgsStorage, ObjectType, RelationOptions} from "../../"; import {RelationMetadataArgs} from "../../metadata-args/RelationMetadataArgs"; /** - * One-to-many relation allows to create type of relation when Entity1 can have multiple instances of Entity2. - * Entity2 have only one Entity1. Entity2 is an owner of the relationship, and storages Entity1 id on its own side. + * One-to-many relation allows us to create a type of relation where Entity1 can have multiple instances of Entity2. + * Entity2 has only one Entity1. Entity2 is the owner of the relationship and stores Entity1's id on its own side. */ export function OneToMany(typeFunctionOrTarget: string|((type?: any) => ObjectType), inverseSide: string|((object: T) => any), options?: RelationOptions): PropertyDecorator { return function (object: Object, propertyName: string) { From 9407507a742a3fe0ea2a836417d6851cad72e74c Mon Sep 17 00:00:00 2001 From: lacunadream <6987359+lacunadream@users.noreply.github.com> Date: Mon, 11 Jan 2021 18:56:12 +0800 Subject: [PATCH 197/212] feat: add NOWAIT and SKIP LOCKED lock support for MySQL (#7236) * feat: add mysql support for locks Add pessimistic_write_or_fail and pessimistic_partial_write support for mysql Closes: #6530 * test: add tests * fix: remove .only flags on tests * test: add db version check for tests --- src/query-builder/SelectQueryBuilder.ts | 4 +- .../locking/query-builder-locking.ts | 151 ++++++++++++++++++ 2 files changed, 153 insertions(+), 2 deletions(-) diff --git a/src/query-builder/SelectQueryBuilder.ts b/src/query-builder/SelectQueryBuilder.ts index 44d45041d07..8fcc1f652b5 100644 --- a/src/query-builder/SelectQueryBuilder.ts +++ b/src/query-builder/SelectQueryBuilder.ts @@ -1686,14 +1686,14 @@ export class SelectQueryBuilder extends QueryBuilder implements throw new LockNotSupportedOnGivenDriverError(); } case "pessimistic_partial_write": - if (driver instanceof PostgresDriver) { + if (driver instanceof PostgresDriver || driver instanceof MysqlDriver) { return " FOR UPDATE SKIP LOCKED"; } else { throw new LockNotSupportedOnGivenDriverError(); } case "pessimistic_write_or_fail": - if (driver instanceof PostgresDriver) { + if (driver instanceof PostgresDriver || driver instanceof MysqlDriver) { return " FOR UPDATE NOWAIT"; } else { throw new LockNotSupportedOnGivenDriverError(); diff --git a/test/functional/query-builder/locking/query-builder-locking.ts b/test/functional/query-builder/locking/query-builder-locking.ts index adcf7420879..bfa5d1583b9 100644 --- a/test/functional/query-builder/locking/query-builder-locking.ts +++ b/test/functional/query-builder/locking/query-builder-locking.ts @@ -18,6 +18,7 @@ import {SqlServerDriver} from "../../../../src/driver/sqlserver/SqlServerDriver" import {AbstractSqliteDriver} from "../../../../src/driver/sqlite-abstract/AbstractSqliteDriver"; import {OracleDriver} from "../../../../src/driver/oracle/OracleDriver"; import {LockNotSupportedOnGivenDriverError} from "../../../../src/error/LockNotSupportedOnGivenDriverError"; +import { VersionUtils } from "../../../../src/util/VersionUtils"; describe("query builder > locking", () => { @@ -99,6 +100,108 @@ describe("query builder > locking", () => { return; }))); + it("should throw error if pessimistic_partial_write lock used without transaction", () => Promise.all(connections.map(async connection => { + if (connection.driver instanceof PostgresDriver) { + return connection.createQueryBuilder(PostWithVersion, "post") + .setLock("pessimistic_partial_write") + .where("post.id = :id", { id: 1 }) + .getOne().should.be.rejectedWith(PessimisticLockTransactionRequiredError); + } + + if (connection.driver instanceof MysqlDriver) { + let [{ version }] = await connection.query( + "SELECT VERSION() as version;" + ); + version = version.toLowerCase(); + if (version.includes('maria')) return; // not supported in mariadb + if (VersionUtils.isGreaterOrEqual(version, '8.0.0')) { + return connection.createQueryBuilder(PostWithVersion, "post") + .setLock("pessimistic_partial_write") + .where("post.id = :id", { id: 1 }) + .getOne().should.be.rejectedWith(PessimisticLockTransactionRequiredError); + } + } + return; + }))); + + it("should not throw error if pessimistic_partial_write lock used with transaction", () => Promise.all(connections.map(async connection => { + if (connection.driver instanceof PostgresDriver) { + return connection.manager.transaction(entityManager => { + return Promise.all([entityManager.createQueryBuilder(PostWithVersion, "post") + .setLock("pessimistic_partial_write") + .where("post.id = :id", { id: 1}) + .getOne().should.not.be.rejected]); + }); + } + + if (connection.driver instanceof MysqlDriver) { + let [{ version }] = await connection.query( + "SELECT VERSION() as version;" + ); + version = version.toLowerCase(); + if (version.includes('maria')) return; // not supported in mariadb + if (VersionUtils.isGreaterOrEqual(version, '8.0.0')) { + return connection.manager.transaction(entityManager => { + return Promise.all([entityManager.createQueryBuilder(PostWithVersion, "post") + .setLock("pessimistic_partial_write") + .where("post.id = :id", { id: 1}) + .getOne().should.not.be.rejected]); + }); + } + } + return; + }))); + + it("should throw error if pessimistic_write_or_fail lock used without transaction", () => Promise.all(connections.map(async connection => { + if (connection.driver instanceof PostgresDriver) { + return connection.createQueryBuilder(PostWithVersion, "post") + .setLock("pessimistic_write_or_fail") + .where("post.id = :id", { id: 1 }) + .getOne().should.be.rejectedWith(PessimisticLockTransactionRequiredError); + } + + if (connection.driver instanceof MysqlDriver) { + let [{ version }] = await connection.query( + "SELECT VERSION() as version;" + ); + version = version.toLowerCase(); + if ((version.includes('maria') && VersionUtils.isGreaterOrEqual(version, "10.3.0")) || !version.includes('maria') && VersionUtils.isGreaterOrEqual(version, '8.0.0')) { + return connection.createQueryBuilder(PostWithVersion, "post") + .setLock("pessimistic_write_or_fail") + .where("post.id = :id", { id: 1 }) + .getOne().should.be.rejectedWith(PessimisticLockTransactionRequiredError); + } + } + return; + }))); + + it("should not throw error if pessimistic_write_or_fail lock used with transaction", () => Promise.all(connections.map(async connection => { + if (connection.driver instanceof PostgresDriver) { + return connection.manager.transaction(entityManager => { + return Promise.all([entityManager.createQueryBuilder(PostWithVersion, "post") + .setLock("pessimistic_write_or_fail") + .where("post.id = :id", { id: 1}) + .getOne().should.not.be.rejected]); + }); + } + + if (connection.driver instanceof MysqlDriver) { + let [{ version }] = await connection.query( + "SELECT VERSION() as version;" + ); + version = version.toLowerCase(); + if ((version.includes('maria') && VersionUtils.isGreaterOrEqual(version, "10.3.0")) || !version.includes('maria') && VersionUtils.isGreaterOrEqual(version, '8.0.0')) { + return connection.manager.transaction(entityManager => { + return Promise.all([entityManager.createQueryBuilder(PostWithVersion, "post") + .setLock("pessimistic_write_or_fail") + .where("post.id = :id", { id: 1}) + .getOne().should.not.be.rejected]); + }); + } + } + return; + }))); + it("should attach pessimistic read lock statement on query if locking enabled", () => Promise.all(connections.map(async connection => { if (connection.driver instanceof AbstractSqliteDriver || connection.driver instanceof CockroachDriver || connection.driver instanceof SapDriver) return; @@ -187,6 +290,54 @@ describe("query builder > locking", () => { }))); + it("should not attach pessimistic_partial_write lock statement on query if locking is not used", () => Promise.all(connections.map(async connection => { + if (connection.driver instanceof PostgresDriver || connection.driver instanceof MysqlDriver) { + const sql = connection.createQueryBuilder(PostWithVersion, "post") + .where("post.id = :id", { id: 1 }) + .getSql(); + + expect(sql.indexOf("FOR UPDATE SKIP LOCKED") === -1).to.be.true; + } + return; + }))); + + it("should attach pessimistic_partial_write lock statement on query if locking enabled", () => Promise.all(connections.map(async connection => { + if (connection.driver instanceof PostgresDriver || connection.driver instanceof MysqlDriver) { + const sql = connection.createQueryBuilder(PostWithVersion, "post") + .setLock("pessimistic_partial_write") + .where("post.id = :id", { id: 1 }) + .getSql(); + + expect(sql.indexOf("FOR UPDATE SKIP LOCKED") !== -1).to.be.true; + } + return; + + }))); + + it("should not attach pessimistic_write_or_fail lock statement on query if locking is not used", () => Promise.all(connections.map(async connection => { + if (connection.driver instanceof PostgresDriver || connection.driver instanceof MysqlDriver) { + const sql = connection.createQueryBuilder(PostWithVersion, "post") + .where("post.id = :id", { id: 1 }) + .getSql(); + + expect(sql.indexOf("FOR UPDATE NOWAIT") === -1).to.be.true; + } + return; + }))); + + it("should attach pessimistic_write_or_fail lock statement on query if locking enabled", () => Promise.all(connections.map(async connection => { + if (connection.driver instanceof PostgresDriver || connection.driver instanceof MysqlDriver) { + const sql = connection.createQueryBuilder(PostWithVersion, "post") + .setLock("pessimistic_write_or_fail") + .where("post.id = :id", { id: 1 }) + .getSql(); + + expect(sql.indexOf("FOR UPDATE NOWAIT") !== -1).to.be.true; + } + return; + + }))); + it("should throw error if optimistic lock used with getMany method", () => Promise.all(connections.map(async connection => { return connection.createQueryBuilder(PostWithVersion, "post") From d44f2bc769a37daabbbd171362f0a400f1e1eec0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Neboj=C5=A1a=20Cvetkovi=C4=87?= Date: Mon, 11 Jan 2021 11:03:40 +0000 Subject: [PATCH 198/212] refactor: remove Oracle multirow insert workaround (since #6927) (#7083) --- src/entity-manager/EntityManager.ts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/entity-manager/EntityManager.ts b/src/entity-manager/EntityManager.ts index f29cd1655e7..cc5616b48a3 100644 --- a/src/entity-manager/EntityManager.ts +++ b/src/entity-manager/EntityManager.ts @@ -32,7 +32,6 @@ import {ObjectID} from "../driver/mongodb/typings"; import {InsertResult} from "../query-builder/result/InsertResult"; import {UpdateResult} from "../query-builder/result/UpdateResult"; import {DeleteResult} from "../query-builder/result/DeleteResult"; -import {OracleDriver} from "../driver/oracle/OracleDriver"; import {FindConditions} from "../find-options/FindConditions"; import {IsolationLevel} from "../driver/types/IsolationLevel"; import {ObjectUtils} from "../util/ObjectUtils"; @@ -457,11 +456,6 @@ export class EntityManager { * You can execute bulk inserts using this method. */ async insert(target: EntityTarget, entity: QueryDeepPartialEntity|(QueryDeepPartialEntity[])): Promise { - // TODO: Oracle does not support multiple values. Need to create another nice solution. - if (this.connection.driver instanceof OracleDriver && Array.isArray(entity)) { - const results = await Promise.all(entity.map(entity => this.insert(target, entity))); - return results.reduce((mergedResult, result) => Object.assign(mergedResult, result), {} as InsertResult); - } return this.createQueryBuilder() .insert() .into(target) From 0dfe5b83f584c3960cdef28e53d2f0ded3f829ce Mon Sep 17 00:00:00 2001 From: Bogdan Gusiev Date: Mon, 11 Jan 2021 13:07:37 +0200 Subject: [PATCH 199/212] fix: improve stack traces when using persist executor (#7218) --- src/persistence/EntityPersistExecutor.ts | 235 +++++++++++------------ 1 file changed, 117 insertions(+), 118 deletions(-) diff --git a/src/persistence/EntityPersistExecutor.ts b/src/persistence/EntityPersistExecutor.ts index bc8f0ae2ce0..b4a0bc23d3f 100644 --- a/src/persistence/EntityPersistExecutor.ts +++ b/src/persistence/EntityPersistExecutor.ts @@ -38,140 +38,139 @@ export class EntityPersistExecutor { /** * Executes persistence operation ob given entity or entities. */ - execute(): Promise { + async execute(): Promise { // check if entity we are going to save is valid and is an object if (!this.entity || typeof this.entity !== "object") return Promise.reject(new MustBeEntityError(this.mode, this.entity)); // we MUST call "fake" resolve here to make sure all properties of lazily loaded relations are resolved - return Promise.resolve().then(async () => { - - // if query runner is already defined in this class, it means this entity manager was already created for a single connection - // if its not defined we create a new query runner - single connection where we'll execute all our operations - const queryRunner = this.queryRunner || this.connection.createQueryRunner(); - - // save data in the query runner - this is useful functionality to share data from outside of the world - // with third classes - like subscribers and listener methods - if (this.options && this.options.data) - queryRunner.data = this.options.data; - - try { - - // collect all operate subjects - const entities: ObjectLiteral[] = Array.isArray(this.entity) ? this.entity : [this.entity]; - const entitiesInChunks = this.options && this.options.chunk && this.options.chunk > 0 ? OrmUtils.chunk(entities, this.options.chunk) : [entities]; - - // console.time("building subject executors..."); - const executors = await Promise.all(entitiesInChunks.map(async entities => { - const subjects: Subject[] = []; - - // create subjects for all entities we received for the persistence - entities.forEach(entity => { - const entityTarget = this.target ? this.target : entity.constructor; - if (entityTarget === Object) - throw new CannotDetermineEntityError(this.mode); - - subjects.push(new Subject({ - metadata: this.connection.getMetadata(entityTarget), - entity: entity, - canBeInserted: this.mode === "save", - canBeUpdated: this.mode === "save", - mustBeRemoved: this.mode === "remove", - canBeSoftRemoved: this.mode === "soft-remove", - canBeRecovered: this.mode === "recover" - })); - }); - - // console.time("building cascades..."); - // go through each entity with metadata and create subjects and subjects by cascades for them - const cascadesSubjectBuilder = new CascadesSubjectBuilder(subjects); + await Promise.resolve(); + + // if query runner is already defined in this class, it means this entity manager was already created for a single connection + // if its not defined we create a new query runner - single connection where we'll execute all our operations + const queryRunner = this.queryRunner || this.connection.createQueryRunner(); + + // save data in the query runner - this is useful functionality to share data from outside of the world + // with third classes - like subscribers and listener methods + if (this.options && this.options.data) + queryRunner.data = this.options.data; + + try { + + // collect all operate subjects + const entities: ObjectLiteral[] = Array.isArray(this.entity) ? this.entity : [this.entity]; + const entitiesInChunks = this.options && this.options.chunk && this.options.chunk > 0 ? OrmUtils.chunk(entities, this.options.chunk) : [entities]; + + // console.time("building subject executors..."); + const executors = await Promise.all(entitiesInChunks.map(async entities => { + const subjects: Subject[] = []; + + // create subjects for all entities we received for the persistence + entities.forEach(entity => { + const entityTarget = this.target ? this.target : entity.constructor; + if (entityTarget === Object) + throw new CannotDetermineEntityError(this.mode); + + subjects.push(new Subject({ + metadata: this.connection.getMetadata(entityTarget), + entity: entity, + canBeInserted: this.mode === "save", + canBeUpdated: this.mode === "save", + mustBeRemoved: this.mode === "remove", + canBeSoftRemoved: this.mode === "soft-remove", + canBeRecovered: this.mode === "recover" + })); + }); + + // console.time("building cascades..."); + // go through each entity with metadata and create subjects and subjects by cascades for them + const cascadesSubjectBuilder = new CascadesSubjectBuilder(subjects); + subjects.forEach(subject => { + // next step we build list of subjects we will operate with + // these subjects are subjects that we need to insert or update alongside with main persisted entity + cascadesSubjectBuilder.build(subject, this.mode); + }); + // console.timeEnd("building cascades..."); + + // load database entities for all subjects we have + // next step is to load database entities for all operate subjects + // console.time("loading..."); + await new SubjectDatabaseEntityLoader(queryRunner, subjects).load(this.mode); + // console.timeEnd("loading..."); + + // console.time("other subjects..."); + // build all related subjects and change maps + if (this.mode === "save" || this.mode === "soft-remove" || this.mode === "recover") { + new OneToManySubjectBuilder(subjects).build(); + new OneToOneInverseSideSubjectBuilder(subjects).build(); + new ManyToManySubjectBuilder(subjects).build(); + } else { subjects.forEach(subject => { - // next step we build list of subjects we will operate with - // these subjects are subjects that we need to insert or update alongside with main persisted entity - cascadesSubjectBuilder.build(subject, this.mode); - }); - // console.timeEnd("building cascades..."); - - // load database entities for all subjects we have - // next step is to load database entities for all operate subjects - // console.time("loading..."); - await new SubjectDatabaseEntityLoader(queryRunner, subjects).load(this.mode); - // console.timeEnd("loading..."); - - // console.time("other subjects..."); - // build all related subjects and change maps - if (this.mode === "save" || this.mode === "soft-remove" || this.mode === "recover") { - new OneToManySubjectBuilder(subjects).build(); - new OneToOneInverseSideSubjectBuilder(subjects).build(); - new ManyToManySubjectBuilder(subjects).build(); - } else { - subjects.forEach(subject => { - if (subject.mustBeRemoved) { - new ManyToManySubjectBuilder(subjects).buildForAllRemoval(subject); - } - }); - } - // console.timeEnd("other subjects..."); - // console.timeEnd("building subjects..."); - // console.log("subjects", subjects); - - // create a subject executor - return new SubjectExecutor(queryRunner, subjects, this.options); - })); - // console.timeEnd("building subject executors..."); - - // make sure we have at least one executable operation before we create a transaction and proceed - // if we don't have operations it means we don't really need to update or remove something - const executorsWithExecutableOperations = executors.filter(executor => executor.hasExecutableOperations); - if (executorsWithExecutableOperations.length === 0) - return; - - // start execute queries in a transaction - // if transaction is already opened in this query runner then we don't touch it - // if its not opened yet then we open it here, and once we finish - we close it - let isTransactionStartedByUs = false; - try { - - // open transaction if its not opened yet - if (!queryRunner.isTransactionActive) { - if (!this.options || this.options.transaction !== false) { // start transaction until it was not explicitly disabled - isTransactionStartedByUs = true; - await queryRunner.startTransaction(); + if (subject.mustBeRemoved) { + new ManyToManySubjectBuilder(subjects).buildForAllRemoval(subject); } - } + }); + } + // console.timeEnd("other subjects..."); + // console.timeEnd("building subjects..."); + // console.log("subjects", subjects); + + // create a subject executor + return new SubjectExecutor(queryRunner, subjects, this.options); + })); + // console.timeEnd("building subject executors..."); + + // make sure we have at least one executable operation before we create a transaction and proceed + // if we don't have operations it means we don't really need to update or remove something + const executorsWithExecutableOperations = executors.filter(executor => executor.hasExecutableOperations); + if (executorsWithExecutableOperations.length === 0) + return; + + // start execute queries in a transaction + // if transaction is already opened in this query runner then we don't touch it + // if its not opened yet then we open it here, and once we finish - we close it + let isTransactionStartedByUs = false; + try { - // execute all persistence operations for all entities we have - // console.time("executing subject executors..."); - for (const executor of executorsWithExecutableOperations) { - await executor.execute(); + // open transaction if its not opened yet + if (!queryRunner.isTransactionActive) { + if (!this.options || this.options.transaction !== false) { // start transaction until it was not explicitly disabled + isTransactionStartedByUs = true; + await queryRunner.startTransaction(); } - // console.timeEnd("executing subject executors..."); + } - // commit transaction if it was started by us - // console.time("commit"); - if (isTransactionStartedByUs === true) - await queryRunner.commitTransaction(); - // console.timeEnd("commit"); + // execute all persistence operations for all entities we have + // console.time("executing subject executors..."); + for (const executor of executorsWithExecutableOperations) { + await executor.execute(); + } + // console.timeEnd("executing subject executors..."); - } catch (error) { + // commit transaction if it was started by us + // console.time("commit"); + if (isTransactionStartedByUs === true) + await queryRunner.commitTransaction(); + // console.timeEnd("commit"); - // rollback transaction if it was started by us - if (isTransactionStartedByUs) { - try { - await queryRunner.rollbackTransaction(); - } catch (rollbackError) { } - } - throw error; + } catch (error) { + + // rollback transaction if it was started by us + if (isTransactionStartedByUs) { + try { + await queryRunner.rollbackTransaction(); + } catch (rollbackError) { } } + throw error; + } - } finally { + } finally { - // release query runner only if its created by us - if (!this.queryRunner) - await queryRunner.release(); - } - }); + // release query runner only if its created by us + if (!this.queryRunner) + await queryRunner.release(); + } } } From 28368917a3ab696c3497024641592aa8f78a1405 Mon Sep 17 00:00:00 2001 From: ericcrosson-bitgo <67922293+ericcrosson-bitgo@users.noreply.github.com> Date: Mon, 11 Jan 2021 06:06:30 -0600 Subject: [PATCH 200/212] docs: add .ts to supported ormconfig formats (#7139) --- docs/using-ormconfig.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/using-ormconfig.md b/docs/using-ormconfig.md index 5fc5dec05f3..6a1b816696c 100644 --- a/docs/using-ormconfig.md +++ b/docs/using-ormconfig.md @@ -24,7 +24,7 @@ import {createConnection} from "typeorm"; const connection = await createConnection(); ``` -Supported ormconfig file formats are: `.json`, `.js`, `.env`, `.yml` and `.xml`. +Supported ormconfig file formats are: `.json`, `.js`, `.ts`, `.env`, `.yml` and `.xml`. ## Using `ormconfig.json` From cc044a90c2bd37f0b0dd1198812ac800f693c563 Mon Sep 17 00:00:00 2001 From: Gergo Tolnai Date: Mon, 11 Jan 2021 13:06:55 +0100 Subject: [PATCH 201/212] docs: update cascade options (#7140) --- docs/relations.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/relations.md b/docs/relations.md index 0c30ff5aa23..0ebc646258b 100644 --- a/docs/relations.md +++ b/docs/relations.md @@ -96,7 +96,7 @@ Also, they provide a less explicit way of saving new objects into the database. ### Cascade Options -The `cascade` option can be set as a `boolean` or an array of cascade options `("insert", "update")[]`. +The `cascade` option can be set as a `boolean` or an array of cascade options `("insert" | "update" | "remove" | "soft-remove" | "recover")[]`. It will default to `false`, meaning no cascades. Setting `cascade: true` will enable full cascades. You can also specify options by providing an array. From 9b278c99e52bbcdf0d36ece29168785ee8641687 Mon Sep 17 00:00:00 2001 From: Kenneth Johnson Date: Mon, 11 Jan 2021 07:09:06 -0500 Subject: [PATCH 202/212] fix: return 'null' (instead of 'undefined') on lazy relations that have no results (#7146) (#7147) Fix an issue where a lazy relation returns a Promise that resolves to 'undefined'. As implied by documentation, if the database has a NULL or no results, the result should be a literal 'null' in Javascript. Also added units tests to hilight the three scenarios in which this occurred. Closes #7146 --- src/query-builder/RelationLoader.ts | 2 +- test/github-issues/7146/entity/Category.ts | 18 +++++ test/github-issues/7146/entity/Post.ts | 32 ++++++++ test/github-issues/7146/issue-7146.ts | 92 ++++++++++++++++++++++ 4 files changed, 143 insertions(+), 1 deletion(-) create mode 100644 test/github-issues/7146/entity/Category.ts create mode 100644 test/github-issues/7146/entity/Post.ts create mode 100644 test/github-issues/7146/issue-7146.ts diff --git a/src/query-builder/RelationLoader.ts b/src/query-builder/RelationLoader.ts index 04eb5dd72d0..6f0c58ab5de 100644 --- a/src/query-builder/RelationLoader.ts +++ b/src/query-builder/RelationLoader.ts @@ -216,7 +216,7 @@ export class RelationLoader { // nothing is loaded yet, load relation data and save it in the model once they are loaded const loader = relationLoader.load(relation, this, queryRunner).then( - result => relation.isOneToOne || relation.isManyToOne ? result[0] : result + result => relation.isOneToOne || relation.isManyToOne ? (result.length === 0 ? null : result[0]) : result ); return setPromise(this, loader); }, diff --git a/test/github-issues/7146/entity/Category.ts b/test/github-issues/7146/entity/Category.ts new file mode 100644 index 00000000000..d04a78b6781 --- /dev/null +++ b/test/github-issues/7146/entity/Category.ts @@ -0,0 +1,18 @@ +import { Entity, JoinColumn, OneToOne, PrimaryGeneratedColumn } from "../../../../src"; +import { Post } from "./Post"; + +@Entity() +export class Category { + + @PrimaryGeneratedColumn() + id: number; + + @OneToOne(type => Post, post => post.lazyOneToOne, { nullable: true, eager: false }) + @JoinColumn() + backRef1: Post; + + @OneToOne(type => Post, post => post.eagerOneToOne, { nullable: true, eager: false }) + @JoinColumn() + backRef2: Post; + +} diff --git a/test/github-issues/7146/entity/Post.ts b/test/github-issues/7146/entity/Post.ts new file mode 100644 index 00000000000..08414825b47 --- /dev/null +++ b/test/github-issues/7146/entity/Post.ts @@ -0,0 +1,32 @@ +import { Entity, JoinColumn, ManyToOne, OneToOne, PrimaryGeneratedColumn } from "../../../../src"; +import { Category } from "./Category"; + +@Entity() +export class Post { + + @PrimaryGeneratedColumn() + id: number; + + @ManyToOne(type => Category, { nullable: true, eager: false }) + lazyManyToOne: Promise; + + @ManyToOne(type => Category, { nullable: true, eager: true }) + eagerManyToOne: Category | null; + + @OneToOne(type => Category, { nullable: true, eager: false }) + @JoinColumn() + lazyOneToOneOwner: Promise; + + @OneToOne(type => Category, { nullable: true, eager: true }) + @JoinColumn() + eagerOneToOneOwner: Category | null; + + // Not a column; actual value is stored on the other side of this relation + @OneToOne(type => Category, category => category.backRef1, { eager: false }) + lazyOneToOne: Promise; + + // Not a column; actual value is stored on the other side of this relation + @OneToOne(type => Category, category => category.backRef2, { eager: true }) + eagerOneToOne: Category | null; + +} diff --git a/test/github-issues/7146/issue-7146.ts b/test/github-issues/7146/issue-7146.ts new file mode 100644 index 00000000000..dac333a9a99 --- /dev/null +++ b/test/github-issues/7146/issue-7146.ts @@ -0,0 +1,92 @@ +import "reflect-metadata"; +import { createTestingConnections, closeTestingConnections, reloadTestingDatabases } from "../../utils/test-utils"; +import { Connection } from "../../../src/connection/Connection"; +import { expect } from "chai"; +import { Post } from "./entity/Post"; + +describe("github issues > #7146 Lazy relations resolve to 'undefined' instead of 'null'", () => { + + let connections: Connection[]; + before(async () => connections = await createTestingConnections({ + entities: [__dirname + "/entity/*{.js,.ts}"], + schemaCreate: true, + dropSchema: true, + })); + beforeEach(() => reloadTestingDatabases(connections)); + after(() => closeTestingConnections(connections)); + + async function prepareData(connection: Connection) { + const savedPost = new Post(); + await connection.manager.save(savedPost); + } + + // The following 3 tests hilight the reported issue. + // The remaining 6 tests were already succeeding before, but are included for completeness sake. + + describe("lazy-loaded relations", () => { + + it("should return null if ManyToOne relation has NULL in database", () => Promise.all(connections.map(async connection => { + await prepareData(connection); + const post = (await connection.manager.findOneOrFail(Post, 1)); + expect(await post.lazyManyToOne).to.be.null; + }))); + + it("should return null if OneToOne+JoinColumn relation has NULL in database", () => Promise.all(connections.map(async connection => { + await prepareData(connection); + const post = (await connection.manager.findOneOrFail(Post, 1)); + expect(await post.lazyOneToOneOwner).to.be.null; + }))); + + it("should return null if OneToOne relation has NULL in database", () => Promise.all(connections.map(async connection => { + await prepareData(connection); + const post = (await connection.manager.findOneOrFail(Post, 1)); + expect(await post.lazyOneToOne).to.be.null; + }))); + + }); + + describe("lazy-loaded relations included in 'relations' find option", () => { + + it("should return null if ManyToOne relation has NULL in database", () => Promise.all(connections.map(async connection => { + await prepareData(connection); + const post = (await connection.manager.findOneOrFail(Post, 1, { relations: ['lazyManyToOne'] })); + expect(await post.lazyManyToOne).to.be.null; + }))); + + it("should return null if OneToOne+JoinColumn relation has NULL in database", () => Promise.all(connections.map(async connection => { + await prepareData(connection); + const post = (await connection.manager.findOneOrFail(Post, 1, { relations: ['lazyOneToOneOwner'] })); + expect(await post.lazyOneToOneOwner).to.be.null; + }))); + + it("should return null if OneToOne relation has NULL in database", () => Promise.all(connections.map(async connection => { + await prepareData(connection); + const post = (await connection.manager.findOneOrFail(Post, 1, { relations: ['lazyOneToOne'] })); + expect(await post.lazyOneToOne).to.be.null; + }))); + + }); + + describe("eager-loaded relations", () => { + + it("should return null if ManyToOne relation has NULL in database", () => Promise.all(connections.map(async connection => { + await prepareData(connection); + const post = (await connection.manager.findOneOrFail(Post, 1)); + expect(post.eagerManyToOne).to.be.null; + }))); + + it("should return null if OneToOne+JoinColumn relation has NULL in database", () => Promise.all(connections.map(async connection => { + await prepareData(connection); + const post = (await connection.manager.findOneOrFail(Post, 1)); + expect(post.eagerOneToOneOwner).to.be.null; + }))); + + it("should return null if OneToOne relation has NULL in database", () => Promise.all(connections.map(async connection => { + await prepareData(connection); + const post = (await connection.manager.findOneOrFail(Post, 1)); + expect(post.eagerOneToOne).to.be.null; + }))); + + }); + +}); From a49db9612b86cd95727f1ba9ffa2c6d4818bcbb5 Mon Sep 17 00:00:00 2001 From: Adrian Date: Mon, 11 Jan 2021 13:57:23 +0100 Subject: [PATCH 203/212] docs: document withDeleted option (#7132) --- docs/find-options.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/find-options.md b/docs/find-options.md index 87e8d18ba2d..0147ebb70b7 100644 --- a/docs/find-options.md +++ b/docs/find-options.md @@ -74,6 +74,13 @@ userRepository.find({ }); ``` +* `withDeleted` - include entities which have been soft deleted with `softDelete` or `softRemove`, e.g. have their `@DeleteDateColumn` column set. By default, soft deleted entities are not included. + +```typescript +userRepository.find({ + withDeleted: true +}); + `find` methods which return multiple entities (`find`, `findAndCount`, `findByIds`) also accept following options: * `skip` - offset (paginated) from where entities should be taken. From a7acb6b021b06541f150cb635fb96f5df67991c2 Mon Sep 17 00:00:00 2001 From: Yuuki Takahashi <20282867+yktakaha4@users.noreply.github.com> Date: Mon, 11 Jan 2021 22:00:53 +0900 Subject: [PATCH 204/212] docs: Embodying the example (#7116) I thought it would be more appropriate to give an example of a `Geometry` type. --- docs/indices.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/indices.md b/docs/indices.md index daa226b7d8a..3ce2ce12f35 100644 --- a/docs/indices.md +++ b/docs/indices.md @@ -127,6 +127,11 @@ export class Thing { To create a spatial index on a column in PostgreSQL, add an `Index` with `spatial: true` on a column that uses a spatial type (`geometry`, `geography`): ```typescript +export interface Geometry { + type: "Point"; + coordinates: [Number, Number]; +} + @Entity() export class Thing { @Column("geometry", { From a3faf49987346607a620525c0da77b1ffebf8024 Mon Sep 17 00:00:00 2001 From: Oleksandr Kovpashko Date: Tue, 12 Jan 2021 09:53:21 +0200 Subject: [PATCH 205/212] docs: fix invalid code block in "find many options" (#7268) --- docs/find-options.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/find-options.md b/docs/find-options.md index 0147ebb70b7..b506594de23 100644 --- a/docs/find-options.md +++ b/docs/find-options.md @@ -80,6 +80,7 @@ userRepository.find({ userRepository.find({ withDeleted: true }); +``` `find` methods which return multiple entities (`find`, `findAndCount`, `findByIds`) also accept following options: From efc283769ed972d022980e681e294d695087a807 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Neboj=C5=A1a=20Cvetkovi=C4=87?= Date: Tue, 12 Jan 2021 08:35:13 +0000 Subject: [PATCH 206/212] feat: relations: Orphaned row action (#7105) Co-authored-by: adenhertog Co-authored-by: adenhertog --- src/decorator/options/RelationOptions.ts | 5 ++ src/metadata/RelationMetadata.ts | 6 ++ .../OneToManySubjectBuilder.ts | 16 ++-- .../delete-orphans/delete-orphans.ts | 73 +++++++++++++++++++ .../delete-orphans/entity/Category.ts | 18 +++++ .../persistence/delete-orphans/entity/Post.ts | 21 ++++++ 6 files changed, 134 insertions(+), 5 deletions(-) create mode 100644 test/functional/persistence/delete-orphans/delete-orphans.ts create mode 100644 test/functional/persistence/delete-orphans/entity/Category.ts create mode 100644 test/functional/persistence/delete-orphans/entity/Post.ts diff --git a/src/decorator/options/RelationOptions.ts b/src/decorator/options/RelationOptions.ts index b8ab7d575cb..d37d62091ce 100644 --- a/src/decorator/options/RelationOptions.ts +++ b/src/decorator/options/RelationOptions.ts @@ -64,4 +64,9 @@ export interface RelationOptions { */ persistence?: boolean; + /** + * When a child row is removed from its parent, determines if the child row should be orphaned (default) or deleted. + */ + orphanedRowAction?: "nullify" | "delete"; + } diff --git a/src/metadata/RelationMetadata.ts b/src/metadata/RelationMetadata.ts index 654747b5a9c..e7a49cf3f4d 100644 --- a/src/metadata/RelationMetadata.ts +++ b/src/metadata/RelationMetadata.ts @@ -109,6 +109,11 @@ export class RelationMetadata { */ persistenceEnabled: boolean = true; + /** + * When a child row is removed from its parent, determines if the child row should be orphaned (default) or deleted. + */ + orphanedRowAction?: "nullify" | "delete"; + /** * If set to true then related objects are allowed to be inserted to the database. */ @@ -298,6 +303,7 @@ export class RelationMetadata { this.deferrable = args.options.deferrable; this.isEager = args.options.eager || false; this.persistenceEnabled = args.options.persistence === false ? false : true; + this.orphanedRowAction = args.options.orphanedRowAction || "nullify"; this.isTreeParent = args.isTreeParent || false; this.isTreeChildren = args.isTreeChildren || false; this.type = args.type instanceof Function ? (args.type as () => any)() : args.type; diff --git a/src/persistence/subject-builder/OneToManySubjectBuilder.ts b/src/persistence/subject-builder/OneToManySubjectBuilder.ts index 2578bf1cdbd..57f28d06482 100644 --- a/src/persistence/subject-builder/OneToManySubjectBuilder.ts +++ b/src/persistence/subject-builder/OneToManySubjectBuilder.ts @@ -165,15 +165,21 @@ export class OneToManySubjectBuilder { const removedRelatedEntitySubject = new Subject({ metadata: relation.inverseEntityMetadata, parentSubject: subject, - canBeUpdated: true, identifier: removedRelatedEntityRelationId, - changeMaps: [{ + }); + + if (!relation.inverseRelation || relation.inverseRelation.orphanedRowAction === "nullify") { + removedRelatedEntitySubject.canBeUpdated = true; + removedRelatedEntitySubject.changeMaps = [{ relation: relation.inverseRelation!, value: null - }] - }); + }]; + } else if (relation.inverseRelation.orphanedRowAction === "delete") { + removedRelatedEntitySubject.mustBeRemoved = true; + } + this.subjects.push(removedRelatedEntitySubject); }); } -} \ No newline at end of file +} diff --git a/test/functional/persistence/delete-orphans/delete-orphans.ts b/test/functional/persistence/delete-orphans/delete-orphans.ts new file mode 100644 index 00000000000..e000d884a78 --- /dev/null +++ b/test/functional/persistence/delete-orphans/delete-orphans.ts @@ -0,0 +1,73 @@ +import "reflect-metadata"; +import { Connection, Repository } from "../../../../src/index"; +import { reloadTestingDatabases, createTestingConnections, closeTestingConnections } from "../../../utils/test-utils"; +import { expect } from "chai"; +import { Category } from "./entity/Category"; +import { Post } from "./entity/Post"; + +describe("persistence > delete orphans", () => { + + // ------------------------------------------------------------------------- + // Configuration + // ------------------------------------------------------------------------- + + // connect to db + let connections: Connection[] = []; + + before(async () => connections = await createTestingConnections({ + entities: [__dirname + "/entity/*{.js,.ts}"], + + })); + beforeEach(() => reloadTestingDatabases(connections)); + after(() => closeTestingConnections(connections)); + + // ------------------------------------------------------------------------- + // Specifications + // ------------------------------------------------------------------------- + + describe("when a Post is removed from a Category", () => { + let categoryRepository: Repository; + let postRepository: Repository; + let categoryId: number; + + beforeEach(async () => { + await Promise.all(connections.map(async connection => { + categoryRepository = connection.getRepository(Category); + postRepository = connection.getRepository(Post); + })); + + const categoryToInsert = await categoryRepository.save(new Category()); + categoryToInsert.posts = [ + new Post(), + new Post() + ]; + + await categoryRepository.save(categoryToInsert); + categoryId = categoryToInsert.id; + + const categoryToUpdate = (await categoryRepository.findOne(categoryId))!; + categoryToUpdate.posts = categoryToInsert.posts.filter(p => p.id === 1); // Keep the first post + + await categoryRepository.save(categoryToUpdate); + }); + + it("should retain a Post on the Category", async () => { + const category = await categoryRepository.findOne(categoryId); + expect(category).not.to.be.undefined; + expect(category!.posts).to.have.lengthOf(1); + expect(category!.posts[0].id).to.equal(1); + }); + + it("should delete the orphaned Post from the database", async () => { + const postCount = await postRepository.count(); + expect(postCount).to.equal(1); + }); + + it("should retain foreign keys on remaining Posts", async () => { + const postsWithoutForeignKeys = (await postRepository.find()) + .filter(p => !p.categoryId); + expect(postsWithoutForeignKeys).to.have.lengthOf(0); + }); + }); + +}); diff --git a/test/functional/persistence/delete-orphans/entity/Category.ts b/test/functional/persistence/delete-orphans/entity/Category.ts new file mode 100644 index 00000000000..477195b90aa --- /dev/null +++ b/test/functional/persistence/delete-orphans/entity/Category.ts @@ -0,0 +1,18 @@ +import {Entity} from "../../../../../src/decorator/entity/Entity"; +import {PrimaryGeneratedColumn} from "../../../../../src/decorator/columns/PrimaryGeneratedColumn"; +import {Post} from "./Post"; +import {OneToMany} from "../../../../../src/decorator/relations/OneToMany"; + +@Entity() +export class Category { + + @PrimaryGeneratedColumn() + id: number; + + @OneToMany(() => Post, post => post.category, { + cascade: ["insert"], + eager: true + }) + posts: Post[]; + +} diff --git a/test/functional/persistence/delete-orphans/entity/Post.ts b/test/functional/persistence/delete-orphans/entity/Post.ts new file mode 100644 index 00000000000..6587c8f06c7 --- /dev/null +++ b/test/functional/persistence/delete-orphans/entity/Post.ts @@ -0,0 +1,21 @@ +import {Category} from "./Category"; +import {Entity} from "../../../../../src/decorator/entity/Entity"; +import {PrimaryGeneratedColumn} from "../../../../../src/decorator/columns/PrimaryGeneratedColumn"; +import {Column} from "../../../../../src/decorator/columns/Column"; +import {ManyToOne} from "../../../../../src/decorator/relations/ManyToOne"; +import {JoinColumn} from "../../../../../src/decorator/relations/JoinColumn"; + +@Entity() +export class Post { + + @PrimaryGeneratedColumn() + id: number; + + @Column() + categoryId: string; + + @ManyToOne(() => Category, category => category.posts, { orphanedRowAction: "delete" }) + @JoinColumn({ name: "categoryId" }) + category: Category; + +} From bcd998b4f384893679e60914d3c52b3d68e7792e Mon Sep 17 00:00:00 2001 From: alexey2baranov Date: Tue, 12 Jan 2021 12:26:05 +0300 Subject: [PATCH 207/212] feat: closure table custom naming (#7120) * add metadata to @Tree * add simple test * ref column naming from string to callback(column)=>name * fix Closure junction metadata builder * fix ClosureSubjectExecutor columns naming * ref ClosureSubjectExecutor columns naming * fix ClosureEntityMetadataBuilder * add tests * fix test name * doc: add closure-table custom naming docs. * refactor: small code-style changing. * refactor: minor refactoring during code review Co-authored-by: alexey2baranov --- docs/tree-entities.md | 18 +- src/decorator/tree/Tree.ts | 6 +- src/metadata-args/TreeMetadataArgs.ts | 5 + .../ClosureJunctionEntityMetadataBuilder.ts | 6 +- src/metadata/EntityMetadata.ts | 7 + src/metadata/types/ClosureTreeOptions.ts | 11 + .../tree/ClosureSubjectExecutor.ts | 12 +- test/github-issues/7068/entity/Category.ts | 30 +++ test/github-issues/7068/issue-7068.ts | 190 ++++++++++++++++++ 9 files changed, 270 insertions(+), 15 deletions(-) create mode 100644 src/metadata/types/ClosureTreeOptions.ts create mode 100644 test/github-issues/7068/entity/Category.ts create mode 100644 test/github-issues/7068/issue-7068.ts diff --git a/docs/tree-entities.md b/docs/tree-entities.md index a4127ff4c7d..a674723f273 100644 --- a/docs/tree-entities.md +++ b/docs/tree-entities.md @@ -11,8 +11,8 @@ To learn more about hierarchy table take a look at [this awesome presentation by ## Adjacency list -Adjacency list is a simple model with self-referencing. -The benefit of this approach is simplicity, +Adjacency list is a simple model with self-referencing. +The benefit of this approach is simplicity, drawback is that you can't load big trees in all at once because of join limitations. To learn more about the benefits and use of Adjacency Lists look at [this article by Matthew Schinckel](http://schinckel.net/2014/09/13/long-live-adjacency-lists/). Example: @@ -38,7 +38,7 @@ export class Category { @OneToMany(type => Category, category => category.parent) children: Category[]; } - + ``` ## Nested set @@ -98,7 +98,7 @@ export class Category { ## Closure table -Closure table stores relations between parent and child in a separate table in a special way. +Closure table stores relations between parent and child in a separate table in a special way. It's efficient in both reads and writes. Example: @@ -123,6 +123,16 @@ export class Category { } ``` +You can specify closure table name and / or closure table columns names by setting optional parameter `options` into `@Tree("closure-table", options)`. `ancestorColumnName` and `descandantColumnName` are callback functions, which receive primary column's metadata and return column's name. + +```ts +@Tree("closure-table", { + closureTableName: "category_closure", + ancestorColumnName: (column) => "ancestor_" + column.propertyName, + descendantColumnName: (column) => "descendant_" + column.propertyName, +}) +``` + ### Note: Updating or removing a component's parent has not been implemented yet ([see this issue](https://github.com/typeorm/typeorm/issues/2032)). The closure table will need to be explicitly updated to do either of these operations. diff --git a/src/decorator/tree/Tree.ts b/src/decorator/tree/Tree.ts index 79da2fc96b2..8e39a04cfd7 100644 --- a/src/decorator/tree/Tree.ts +++ b/src/decorator/tree/Tree.ts @@ -1,6 +1,7 @@ import {getMetadataArgsStorage} from "../../"; import {TreeMetadataArgs} from "../../metadata-args/TreeMetadataArgs"; import {TreeType} from "../../metadata/types/TreeTypes"; +import {ClosureTreeOptions} from "../../metadata/types/ClosureTreeOptions"; /** * Marks entity to work like a tree. @@ -8,12 +9,13 @@ import {TreeType} from "../../metadata/types/TreeTypes"; * @TreeParent decorator must be used in tree entities. * TreeRepository can be used to manipulate with tree entities. */ -export function Tree(type: TreeType): ClassDecorator { +export function Tree(type: TreeType, options?: ClosureTreeOptions): ClassDecorator { return function (target: Function) { getMetadataArgsStorage().trees.push({ target: target, - type: type + type: type, + options: type === "closure-table" ? options : undefined } as TreeMetadataArgs); }; } diff --git a/src/metadata-args/TreeMetadataArgs.ts b/src/metadata-args/TreeMetadataArgs.ts index 021cd48bdaa..bd1897db37d 100644 --- a/src/metadata-args/TreeMetadataArgs.ts +++ b/src/metadata-args/TreeMetadataArgs.ts @@ -1,4 +1,5 @@ import {TreeType} from "../metadata/types/TreeTypes"; +import {ClosureTreeOptions} from "../metadata/types/ClosureTreeOptions"; /** * Stores metadata collected for Tree entities. @@ -15,4 +16,8 @@ export interface TreeMetadataArgs { */ type: TreeType; + /** + * Tree options + */ + options?: ClosureTreeOptions; } diff --git a/src/metadata-builder/ClosureJunctionEntityMetadataBuilder.ts b/src/metadata-builder/ClosureJunctionEntityMetadataBuilder.ts index 36250479a09..6fedeb50916 100644 --- a/src/metadata-builder/ClosureJunctionEntityMetadataBuilder.ts +++ b/src/metadata-builder/ClosureJunctionEntityMetadataBuilder.ts @@ -32,7 +32,7 @@ export class ClosureJunctionEntityMetadataBuilder { connection: this.connection, args: { target: "", - name: parentClosureEntityMetadata.tableNameWithoutPrefix, + name: parentClosureEntityMetadata.treeOptions && parentClosureEntityMetadata.treeOptions.closureTableName ? parentClosureEntityMetadata.treeOptions.closureTableName : parentClosureEntityMetadata.tableNameWithoutPrefix, type: "closure-junction" } }); @@ -48,7 +48,7 @@ export class ClosureJunctionEntityMetadataBuilder { args: { target: "", mode: "virtual", - propertyName: primaryColumn.propertyName + "_ancestor", // todo: naming strategy + propertyName: parentClosureEntityMetadata.treeOptions && parentClosureEntityMetadata.treeOptions.ancestorColumnName ? parentClosureEntityMetadata.treeOptions.ancestorColumnName(primaryColumn) : primaryColumn.propertyName + "_ancestor", options: { primary: true, length: primaryColumn.length, @@ -64,7 +64,7 @@ export class ClosureJunctionEntityMetadataBuilder { args: { target: "", mode: "virtual", - propertyName: primaryColumn.propertyName + "_descendant", + propertyName: parentClosureEntityMetadata.treeOptions && parentClosureEntityMetadata.treeOptions.descendantColumnName ? parentClosureEntityMetadata.treeOptions.descendantColumnName(primaryColumn) : primaryColumn.propertyName + "_descendant", options: { primary: true, length: primaryColumn.length, diff --git a/src/metadata/EntityMetadata.ts b/src/metadata/EntityMetadata.ts index 6975928d3e5..a2246ada944 100644 --- a/src/metadata/EntityMetadata.ts +++ b/src/metadata/EntityMetadata.ts @@ -26,6 +26,7 @@ import {RelationMetadata} from "./RelationMetadata"; import {TableType} from "./types/TableTypes"; import {TreeType} from "./types/TreeTypes"; import {UniqueMetadata} from "./UniqueMetadata"; +import {ClosureTreeOptions} from "./types/ClosureTreeOptions"; /** * Contains all entity metadata. @@ -191,6 +192,11 @@ export class EntityMetadata { */ treeType?: TreeType; + /** + * Indicates if this entity is a tree, what options of tree it has. + */ + treeOptions?: ClosureTreeOptions; + /** * Checks if this table is a junction table of the closure table. * This type is for tables that contain junction metadata of the closure tables. @@ -503,6 +509,7 @@ export class EntityMetadata { this.inheritanceTree = options.inheritanceTree || []; this.inheritancePattern = options.inheritancePattern; this.treeType = options.tableTree ? options.tableTree.type : undefined; + this.treeOptions = options.tableTree ? options.tableTree.options : undefined; this.parentClosureEntityMetadata = options.parentClosureEntityMetadata!; this.tableMetadataArgs = options.args; this.target = this.tableMetadataArgs.target; diff --git a/src/metadata/types/ClosureTreeOptions.ts b/src/metadata/types/ClosureTreeOptions.ts new file mode 100644 index 00000000000..444924c134f --- /dev/null +++ b/src/metadata/types/ClosureTreeOptions.ts @@ -0,0 +1,11 @@ +/** + * Tree type. + * Specifies what table pattern will be used for the tree entity. + */ +import {ColumnMetadata} from "../ColumnMetadata"; + +export interface ClosureTreeOptions { + closureTableName?: string, + ancestorColumnName?: (column: ColumnMetadata) => string, + descendantColumnName?: (column: ColumnMetadata) => string, +} diff --git a/src/persistence/tree/ClosureSubjectExecutor.ts b/src/persistence/tree/ClosureSubjectExecutor.ts index 0a88e34516b..2a9d7021f59 100644 --- a/src/persistence/tree/ClosureSubjectExecutor.ts +++ b/src/persistence/tree/ClosureSubjectExecutor.ts @@ -22,7 +22,7 @@ export class ClosureSubjectExecutor { /** * Removes all children of the given subject's entity. - async deleteChildrenOf(subject: Subject) { + async deleteChildrenOf(subject: Subject) { // const relationValue = subject.metadata.treeParentRelation.getEntityValue(subject.databaseEntity); // console.log("relationValue: ", relationValue); // this.queryRunner.manager @@ -75,14 +75,14 @@ export class ClosureSubjectExecutor { firstQueryParameters.push(childEntityIdValues[index]); return this.queryRunner.connection.driver.createParameter("child_entity_" + column.databaseName, firstQueryParameters.length - 1); }); - const whereCondition = subject.metadata.primaryColumns.map(column => { - const columnName = escape(column.databaseName + "_descendant"); - const parentId = column.getEntityValue(parent); + const whereCondition = subject.metadata.closureJunctionTable.descendantColumns.map(column => { + const columnName = escape(column.databaseName); + const parentId = column.referencedColumn!.getEntityValue(parent); if (!parentId) throw new CannotAttachTreeChildrenEntityError(subject.metadata.name); firstQueryParameters.push(parentId); - const parameterName = this.queryRunner.connection.driver.createParameter("parent_entity_" + column.databaseName, firstQueryParameters.length - 1); + const parameterName = this.queryRunner.connection.driver.createParameter("parent_entity_" + column.referencedColumn!.databaseName, firstQueryParameters.length - 1); return columnName + " = " + parameterName; }).join(", "); @@ -109,4 +109,4 @@ export class ClosureSubjectExecutor { } -} \ No newline at end of file +} diff --git a/test/github-issues/7068/entity/Category.ts b/test/github-issues/7068/entity/Category.ts new file mode 100644 index 00000000000..dfe54addc88 --- /dev/null +++ b/test/github-issues/7068/entity/Category.ts @@ -0,0 +1,30 @@ +import {PrimaryGeneratedColumn} from "../../../../src/decorator/columns/PrimaryGeneratedColumn"; +import {Column} from "../../../../src/decorator/columns/Column"; +import {TreeParent} from "../../../../src/decorator/tree/TreeParent"; +import {TreeChildren} from "../../../../src/decorator/tree/TreeChildren"; +import {Entity} from "../../../../src/decorator/entity/Entity"; +import {Tree} from "../../../../src/decorator/tree/Tree"; + +@Entity() +@Tree("closure-table", { + closureTableName: "category_xyz_closure", + ancestorColumnName: (column) => "ancestor_xyz_" + column.propertyName, + descendantColumnName: (column) => "descendant_xyz_" + column.propertyName, +}) +export class Category { + + @PrimaryGeneratedColumn() + id: number; + + @Column() + name: string; + + @TreeParent() + parentCategory: Category; + + @TreeChildren({cascade: true}) + childCategories: Category[]; + + // @TreeLevelColumn() + // level: number; +} diff --git a/test/github-issues/7068/issue-7068.ts b/test/github-issues/7068/issue-7068.ts new file mode 100644 index 00000000000..f961c284e18 --- /dev/null +++ b/test/github-issues/7068/issue-7068.ts @@ -0,0 +1,190 @@ +import "reflect-metadata"; +import {Category} from "./entity/Category"; +import {Connection} from "../../../src/connection/Connection"; +import {closeTestingConnections, createTestingConnections, reloadTestingDatabases} from "../../utils/test-utils"; + +describe.only("github issues > #7068", () => { + + let connections: Connection[]; + before(async () => connections = await createTestingConnections({ + entities: [Category] + })); + beforeEach(() => reloadTestingDatabases(connections)); + after(() => closeTestingConnections(connections)); + + it("categories should be attached via parent and saved properly", () => Promise.all(connections.map(async connection => { + const categoryRepository = connection.getTreeRepository(Category); + + const a1 = new Category(); + a1.name = "a1"; + await categoryRepository.save(a1); + + const a11 = new Category(); + a11.name = "a11"; + a11.parentCategory = a1; + await categoryRepository.save(a11); + + const a12 = new Category(); + a12.name = "a12"; + a12.parentCategory = a1; + await categoryRepository.save(a12); + + const rootCategories = await categoryRepository.findRoots(); + rootCategories.should.be.eql([{ + id: 1, + name: "a1" + }]); + + const a11Parent = await categoryRepository.findAncestors(a11); + a11Parent.length.should.be.equal(2); + a11Parent.should.deep.include({ id: 1, name: "a1" }); + a11Parent.should.deep.include({ id: 2, name: "a11" }); + + const a1Children = await categoryRepository.findDescendants(a1); + a1Children.length.should.be.equal(3); + a1Children.should.deep.include({ id: 1, name: "a1" }); + a1Children.should.deep.include({ id: 2, name: "a11" }); + a1Children.should.deep.include({ id: 3, name: "a12" }); + }))); + + it("categories should be attached via children and saved properly", () => Promise.all(connections.map(async connection => { + const categoryRepository = connection.getTreeRepository(Category); + + const a1 = new Category(); + a1.name = "a1"; + await categoryRepository.save(a1); + + const a11 = new Category(); + a11.name = "a11"; + + const a12 = new Category(); + a12.name = "a12"; + + a1.childCategories = [a11, a12]; + await categoryRepository.save(a1); + + const rootCategories = await categoryRepository.findRoots(); + rootCategories.should.be.eql([{ + id: 1, + name: "a1" + }]); + + const a11Parent = await categoryRepository.findAncestors(a11); + a11Parent.length.should.be.equal(2); + a11Parent.should.deep.include({ id: 1, name: "a1" }); + a11Parent.should.deep.include({ id: 2, name: "a11" }); + + const a1Children = await categoryRepository.findDescendants(a1); + a1Children.length.should.be.equal(3); + a1Children.should.deep.include({ id: 1, name: "a1" }); + a1Children.should.deep.include({ id: 2, name: "a11" }); + a1Children.should.deep.include({ id: 3, name: "a12" }); + }))); + + it("categories should be attached via children and saved properly and everything must be saved in cascades", () => Promise.all(connections.map(async connection => { + const categoryRepository = connection.getTreeRepository(Category); + + const a1 = new Category(); + a1.name = "a1"; + + const a11 = new Category(); + a11.name = "a11"; + + const a12 = new Category(); + a12.name = "a12"; + + const a111 = new Category(); + a111.name = "a111"; + + const a112 = new Category(); + a112.name = "a112"; + + a1.childCategories = [a11, a12]; + a11.childCategories = [a111, a112]; + await categoryRepository.save(a1); + + const rootCategories = await categoryRepository.findRoots(); + rootCategories.should.be.eql([{ + id: 1, + name: "a1" + }]); + + const a11Parent = await categoryRepository.findAncestors(a11); + a11Parent.length.should.be.equal(2); + a11Parent.should.deep.include({ id: 1, name: "a1" }); + a11Parent.should.deep.include({ id: 2, name: "a11" }); + + const a1Children = await categoryRepository.findDescendants(a1); + const a1ChildrenNames = a1Children.map(child => child.name); + a1ChildrenNames.length.should.be.equal(5); + a1ChildrenNames.should.deep.include("a1"); + a1ChildrenNames.should.deep.include("a11"); + a1ChildrenNames.should.deep.include("a12"); + a1ChildrenNames.should.deep.include("a111"); + a1ChildrenNames.should.deep.include("a112"); + }))); + + // todo: finish implementation and implement on other trees + it.skip("categories should remove removed children", () => Promise.all(connections.map(async connection => { + const categoryRepository = connection.getTreeRepository(Category); + + const a1 = new Category(); + a1.name = "a1"; + const a11 = new Category(); + a11.name = "a11"; + const a12 = new Category(); + a12.name = "a12"; + a1.childCategories = [a11, a12]; + await categoryRepository.save(a1); + + const a1Children1 = await categoryRepository.findDescendants(a1); + const a1ChildrenNames1 = a1Children1.map(child => child.name); + a1ChildrenNames1.length.should.be.equal(3); + a1ChildrenNames1.should.deep.include("a1"); + a1ChildrenNames1.should.deep.include("a11"); + a1ChildrenNames1.should.deep.include("a12"); + + // a1.childCategories = [a11]; + // await categoryRepository.save(a1); + // + // const a1Children2 = await categoryRepository.findDescendants(a1); + // const a1ChildrenNames2 = a1Children2.map(child => child.name); + // a1ChildrenNames2.length.should.be.equal(3); + // a1ChildrenNames2.should.deep.include("a1"); + // a1ChildrenNames2.should.deep.include("a11"); + // a1ChildrenNames2.should.deep.include("a12"); + }))); + + // todo: finish implementation and implement on other trees + it.skip("sub-category should be removed with all its children", () => Promise.all(connections.map(async connection => { + const categoryRepository = connection.getTreeRepository(Category); + + const a1 = new Category(); + a1.name = "a1"; + const a11 = new Category(); + a11.name = "a11"; + const a12 = new Category(); + a12.name = "a12"; + a1.childCategories = [a11, a12]; + await categoryRepository.save(a1); + + const a1Children1 = await categoryRepository.findDescendants(a1); + const a1ChildrenNames1 = a1Children1.map(child => child.name); + a1ChildrenNames1.length.should.be.equal(3); + a1ChildrenNames1.should.deep.include("a1"); + a1ChildrenNames1.should.deep.include("a11"); + a1ChildrenNames1.should.deep.include("a12"); + + await categoryRepository.remove(a1); + + // a1.childCategories = [a11]; + // await categoryRepository.save(a1); + // + // const a1Children2 = await categoryRepository.findDescendants(a1); + // const a1ChildrenNames2 = a1Children2.map(child => child.name); + // a1ChildrenNames2.length.should.be.equal(3); + // a1ChildrenNames2.should.deep.include("a1"); + // a1ChildrenNames2.should.deep.include("a11"); + // a1ChildrenNames2.should.deep.include("a12"); + }))); +}); From 568ef3546e6da6e73f68437fff418901d6232c51 Mon Sep 17 00:00:00 2001 From: Matthew Berryman Date: Tue, 12 Jan 2021 23:21:18 +1100 Subject: [PATCH 208/212] fix: resolves Postgres sequence identifier length error (#7115) Changes the sequence name generator to handle cases where PostgreSQL auto-generated sequence name differed from TypeORM generated sequence name. Closes: #7106 --- src/driver/postgres/PostgresQueryRunner.ts | 9 ++-- .../ReallyReallyVeryVeryVeryLongTableName.ts | 17 ++++++++ .../7106/entity/ShortTableName.ts | 15 +++++++ test/github-issues/7106/issue-7106.ts | 41 +++++++++++++++++++ 4 files changed, 79 insertions(+), 3 deletions(-) create mode 100644 test/github-issues/7106/entity/ReallyReallyVeryVeryVeryLongTableName.ts create mode 100644 test/github-issues/7106/entity/ShortTableName.ts create mode 100644 test/github-issues/7106/issue-7106.ts diff --git a/src/driver/postgres/PostgresQueryRunner.ts b/src/driver/postgres/PostgresQueryRunner.ts index 2e1a4efcf2f..8245d09f798 100644 --- a/src/driver/postgres/PostgresQueryRunner.ts +++ b/src/driver/postgres/PostgresQueryRunner.ts @@ -2075,11 +2075,14 @@ export class PostgresQueryRunner extends BaseQueryRunner implements QueryRunner tableName = table.name.split(".")[1]; } + let seqName = `${tableName}_${columnName}_seq`; + if (seqName.length > this.connection.driver.maxAliasLength!) // note doesn't yet handle corner cases where .length differs from number of UTF-8 bytes + seqName=`${tableName.substring(0,29)}_${columnName.substring(0,Math.max(29,63-tableName.length-5))}_seq`; + if (schema && schema !== currentSchema && !skipSchema) { - return disableEscape ? `${schema}.${tableName}_${columnName}_seq` : `"${schema}"."${tableName}_${columnName}_seq"`; - + return disableEscape ? `${schema}.${seqName}` : `"${schema}"."${seqName}"`; } else { - return disableEscape ? `${tableName}_${columnName}_seq` : `"${tableName}_${columnName}_seq"`; + return disableEscape ? `${seqName}` : `"${seqName}"`; } } diff --git a/test/github-issues/7106/entity/ReallyReallyVeryVeryVeryLongTableName.ts b/test/github-issues/7106/entity/ReallyReallyVeryVeryVeryLongTableName.ts new file mode 100644 index 00000000000..b9a8f7f132f --- /dev/null +++ b/test/github-issues/7106/entity/ReallyReallyVeryVeryVeryLongTableName.ts @@ -0,0 +1,17 @@ +import {PrimaryGeneratedColumn} from "../../../../src/decorator/columns/PrimaryGeneratedColumn"; +import {Column, Entity, Generated } from "../../../../src"; + +@Entity() +export class ReallyReallyVeryVeryVeryLongTableName { + @PrimaryGeneratedColumn() // typeORM requires a pkey + PrimaryGeneratedColumnIDBlahBlahBlahThisIsReallyLong: number; + + @Column() + Name: string; + + @Column() @Generated("increment") + MyNumber: number; + + +} + diff --git a/test/github-issues/7106/entity/ShortTableName.ts b/test/github-issues/7106/entity/ShortTableName.ts new file mode 100644 index 00000000000..cef4f851130 --- /dev/null +++ b/test/github-issues/7106/entity/ShortTableName.ts @@ -0,0 +1,15 @@ +import {PrimaryGeneratedColumn} from "../../../../src/decorator/columns/PrimaryGeneratedColumn"; +import {Column, Entity } from "../../../../src"; + +@Entity() +export class ShortTableName { + @PrimaryGeneratedColumn() // typeORM requires a pkey + PrimaryGeneratedColumnIDBlahBlahBlahThisIsReallyLong: number; + + @Column() + Name: string; + + @Column() + Value: number; +} + diff --git a/test/github-issues/7106/issue-7106.ts b/test/github-issues/7106/issue-7106.ts new file mode 100644 index 00000000000..c815102a478 --- /dev/null +++ b/test/github-issues/7106/issue-7106.ts @@ -0,0 +1,41 @@ +import "reflect-metadata"; +import {expect} from "chai"; +import {Connection} from "../../../src/connection/Connection"; +import {closeTestingConnections, createTestingConnections, reloadTestingDatabases} from "../../utils/test-utils"; +import { ShortTableName } from "./entity/ShortTableName"; +import { ReallyReallyVeryVeryVeryLongTableName } from "./entity/ReallyReallyVeryVeryVeryLongTableName"; +import { QueryFailedError } from "../../../src/error/QueryFailedError"; + + +/** + * @see https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS + * "The system uses no more than NAMEDATALEN-1 bytes of an identifier; longer names can be + * written in commands, but they will be truncated. By default, NAMEDATALEN is 64 so the + * maximum identifier length is 63 bytes. If this limit is problematic, it can be raised + * by changing the NAMEDATALEN constant in src/include/pg_config_manual.h." + */ +describe("github issues > #7106 shorten sequence names (for RDBMS with a limit) when they are longer than 63 characters", () => { + let connections: Connection[]; + before(async () => connections = await createTestingConnections({ + entities: [__dirname + "/entity/*{.js,.ts}"], + enabledDrivers: ["postgres"] + })); + beforeEach(() => reloadTestingDatabases(connections)); + after(() => closeTestingConnections(connections)); + + it("should be able to work with long sequence name with short table name", () => Promise.all(connections.map(async (connection) => { + const short = new ShortTableName(); + short.Name = "Dharawal"; + short.Value = 2500; + await connection.getRepository(ShortTableName).save(short); + return expect(connection.synchronize()).to.not.be.rejectedWith(QueryFailedError); + }))); + + it("should be able to work with long sequence name with long table name", () => Promise.all(connections.map(async (connection) => { + const long = new ReallyReallyVeryVeryVeryLongTableName(); + long.Name = "Eora"; + await connection.getRepository(ReallyReallyVeryVeryVeryLongTableName).save(long); + return expect(connection.synchronize()).to.not.be.rejectedWith(QueryFailedError); + }))); + +}); From d27dd2af2ca320e74a17b3ab273cd3bf55d01923 Mon Sep 17 00:00:00 2001 From: Niko Abeler Date: Tue, 12 Jan 2021 13:22:14 +0100 Subject: [PATCH 209/212] fix: Error when sorting by an embedded entity while using join and skip/take (#7082) Closes: #7079 --- src/query-builder/SelectQueryBuilder.ts | 12 +++-- test/github-issues/7079/entities.ts | 43 +++++++++++++++++ test/github-issues/7079/issue-7079.ts | 62 +++++++++++++++++++++++++ 3 files changed, 113 insertions(+), 4 deletions(-) create mode 100644 test/github-issues/7079/entities.ts create mode 100644 test/github-issues/7079/issue-7079.ts diff --git a/src/query-builder/SelectQueryBuilder.ts b/src/query-builder/SelectQueryBuilder.ts index 8fcc1f652b5..d4e1caa97b2 100644 --- a/src/query-builder/SelectQueryBuilder.ts +++ b/src/query-builder/SelectQueryBuilder.ts @@ -2004,9 +2004,11 @@ export class SelectQueryBuilder extends QueryBuilder implements const selectString = Object.keys(orderBys) .map(orderCriteria => { if (orderCriteria.indexOf(".") !== -1) { - const [aliasName, propertyPath] = orderCriteria.split("."); + const criteriaParts = orderCriteria.split("."); + const aliasName = criteriaParts[0]; + const propertyPath = criteriaParts.slice(1).join("."); const alias = this.expressionMap.findAliasByName(aliasName); - const column = alias.metadata.findColumnWithPropertyName(propertyPath); + const column = alias.metadata.findColumnWithPropertyPath(propertyPath); return this.escape(parentAlias) + "." + this.escape(DriverUtils.buildColumnAlias(this.connection.driver, aliasName, column!.databaseName)); } else { if (this.expressionMap.selects.find(select => select.selection === orderCriteria || select.aliasName === orderCriteria)) @@ -2020,9 +2022,11 @@ export class SelectQueryBuilder extends QueryBuilder implements const orderByObject: OrderByCondition = {}; Object.keys(orderBys).forEach(orderCriteria => { if (orderCriteria.indexOf(".") !== -1) { - const [aliasName, propertyPath] = orderCriteria.split("."); + const criteriaParts = orderCriteria.split("."); + const aliasName = criteriaParts[0]; + const propertyPath = criteriaParts.slice(1).join("."); const alias = this.expressionMap.findAliasByName(aliasName); - const column = alias.metadata.findColumnWithPropertyName(propertyPath); + const column = alias.metadata.findColumnWithPropertyPath(propertyPath); orderByObject[this.escape(parentAlias) + "." + this.escape(DriverUtils.buildColumnAlias(this.connection.driver, aliasName, column!.databaseName))] = orderBys[orderCriteria]; } else { if (this.expressionMap.selects.find(select => select.selection === orderCriteria || select.aliasName === orderCriteria)) { diff --git a/test/github-issues/7079/entities.ts b/test/github-issues/7079/entities.ts new file mode 100644 index 00000000000..bda9c4784ed --- /dev/null +++ b/test/github-issues/7079/entities.ts @@ -0,0 +1,43 @@ +import { Column, Entity, ManyToOne, OneToMany, PrimaryGeneratedColumn } from "../../../src"; + + +@Entity() +export class User { + @PrimaryGeneratedColumn() + id: number; + + @Column() + name: string; + + @OneToMany( + () => Post, + (post) => post.user, + ) + posts: Post[]; +} + +export class PublishInfo { + @Column({ nullable: true }) + date: Date; +} + +@Entity() +export class Post { + @PrimaryGeneratedColumn() + id: number; + + @Column() + text: string; + + @Column(_type => PublishInfo) + blog: PublishInfo; + + @Column(_type => PublishInfo) + newsletter: PublishInfo; + + @ManyToOne( + () => User, + (user) => user.posts, + ) + user: User +} \ No newline at end of file diff --git a/test/github-issues/7079/issue-7079.ts b/test/github-issues/7079/issue-7079.ts new file mode 100644 index 00000000000..48b45f9a884 --- /dev/null +++ b/test/github-issues/7079/issue-7079.ts @@ -0,0 +1,62 @@ +import "reflect-metadata"; +import { createTestingConnections, closeTestingConnections, reloadTestingDatabases } from "../../utils/test-utils"; +import { Connection } from "../../../src/connection/Connection"; +import { expect } from "chai"; +import {Post, User} from "./entities" + +describe("github issues > #7079 Error when sorting by an embedded entity while using join and skip/take", () => { + + let connections: Connection[]; + before(async () => connections = await createTestingConnections({ + entities: [Post, User], + schemaCreate: true, + dropSchema: true, + })); + beforeEach(() => reloadTestingDatabases(connections)); + after(() => closeTestingConnections(connections)); + + it("should be able to getMany with join and sorting by an embedded entity column while user take and skip", () => Promise.all(connections.map(async connection => { + const postRepo = connection.getRepository(Post) + const userRepo = connection.getRepository(User) + + const users = [ + { id: 1, name: "Mike" }, + { id: 2, name: "Alice" } + ] + await userRepo.save(users) + + const posts = [ + { + id: 1, + text: "Happy Holidays", + userId: 1, + blog: { date: new Date().toISOString() }, + newsletter: { date: new Date().toISOString() } + }, + { + id: 2, + text: "My Vacation", + userId: 1, + blog: { date: new Date().toISOString() }, + newsletter: { date: new Date().toISOString() } + }, + { + id: 3, + text: "Working with TypeORM", + userId: 2, + blog: { date: new Date().toISOString() }, + newsletter: { date: new Date().toISOString() } + } + ] + await postRepo.save(posts); + + const result = await postRepo.createQueryBuilder("post") + .leftJoinAndSelect("post.user", "user") + .orderBy("post.blog.date") + .take(2) + .skip(1) + .getMany(); + expect(result.length).eq(2); + }))); + +}); \ No newline at end of file From ddd8cbcdf6d67b6b1425de581c3da5d264a01167 Mon Sep 17 00:00:00 2001 From: jafio <61668332+jafio@users.noreply.github.com> Date: Tue, 12 Jan 2021 07:24:47 -0500 Subject: [PATCH 210/212] fix: resolve migration for UpdateDateColumn without ON UPDATE clause (#7057) Closes: #6995 --- src/metadata/ColumnMetadata.ts | 2 ++ .../6995/entity/default-update-date.ts | 16 ++++++++++++ test/github-issues/6995/issue-6995.ts | 25 +++++++++++++++++++ 3 files changed, 43 insertions(+) create mode 100644 test/github-issues/6995/entity/default-update-date.ts create mode 100644 test/github-issues/6995/issue-6995.ts diff --git a/src/metadata/ColumnMetadata.ts b/src/metadata/ColumnMetadata.ts index d4e1d36b0c8..86f3d742214 100644 --- a/src/metadata/ColumnMetadata.ts +++ b/src/metadata/ColumnMetadata.ts @@ -421,6 +421,8 @@ export class ColumnMetadata { this.type = options.connection.driver.mappedDataTypes.updateDate; if (!this.default) this.default = () => options.connection.driver.mappedDataTypes.updateDateDefault; + if (!this.onUpdate) + this.onUpdate = options.connection.driver.mappedDataTypes.updateDateDefault; if (this.precision === undefined && options.connection.driver.mappedDataTypes.updateDatePrecision) this.precision = options.connection.driver.mappedDataTypes.updateDatePrecision; } diff --git a/test/github-issues/6995/entity/default-update-date.ts b/test/github-issues/6995/entity/default-update-date.ts new file mode 100644 index 00000000000..ba95bcec3b0 --- /dev/null +++ b/test/github-issues/6995/entity/default-update-date.ts @@ -0,0 +1,16 @@ +import { PrimaryGeneratedColumn, CreateDateColumn, UpdateDateColumn, Entity } from '../../../../src'; + +@Entity() +export class DefaultUpdateDate { + + @PrimaryGeneratedColumn({ + type: "int" + }) + public id: number; + + @CreateDateColumn() + public createdDate: Date; + + @UpdateDateColumn() + public updatedDate: Date; +} \ No newline at end of file diff --git a/test/github-issues/6995/issue-6995.ts b/test/github-issues/6995/issue-6995.ts new file mode 100644 index 00000000000..02a4057f51e --- /dev/null +++ b/test/github-issues/6995/issue-6995.ts @@ -0,0 +1,25 @@ +import "reflect-metadata"; +import { Connection } from "../../../src"; +import { createTestingConnections, closeTestingConnections } from "../../utils/test-utils"; +import { DefaultUpdateDate } from './entity/default-update-date'; + +describe("github issues > #6995 Generating migrations for UpdateDateColumn should generate on update clause", () => { + + let connections: Connection[]; + before(async () => connections = await createTestingConnections({ + migrations: [], + enabledDrivers: ["mysql", "mariadb"], + schemaCreate: false, + dropSchema: true, + entities: [DefaultUpdateDate] + })); + after(() => closeTestingConnections(connections)); + + it("should create migration with default ON UPDATE clause", () => Promise.all(connections.map(async connection => { + + const sqlInMemory = await connection.driver.createSchemaBuilder().log(); + sqlInMemory.upQueries.filter(i => i.query.includes("ON UPDATE")).length.should.be.greaterThan(0); + + }))); + +}); \ No newline at end of file From 4ed1c4bf8e4a3c72f73b6dbb1f987556a7250a41 Mon Sep 17 00:00:00 2001 From: Ed Colvin Date: Tue, 12 Jan 2021 03:26:06 -0900 Subject: [PATCH 211/212] docs: fix javascript usage examples (#7031) --- docs/usage-with-javascript.md | 16 ++++++++++------ docs/zh_CN/usage-with-javascript.md | 21 ++++++++++++++------- 2 files changed, 24 insertions(+), 13 deletions(-) diff --git a/docs/usage-with-javascript.md b/docs/usage-with-javascript.md index 0ecf7cbf099..7eacd79ee8a 100644 --- a/docs/usage-with-javascript.md +++ b/docs/usage-with-javascript.md @@ -58,7 +58,9 @@ typeorm.createConnection({ ##### entity/Category.js ```typescript -module.exports = { +var EntitySchema = require("typeorm").EntitySchema; + +module.exports = new EntitySchema({ name: "Category", // Will use table name `category` as default behaviour. tableName: "categories", // Optional: Provide `tableName` property to override the default behaviour for table name. columns: { @@ -68,16 +70,18 @@ module.exports = { generated: true }, name: { - type: "string" + type: "varchar" } } -}; +}); ``` ##### entity/Post.js ```typescript -module.exports = { +var EntitySchema = require("typeorm").EntitySchema; + +module.exports = new EntitySchema({ name: "Post", // Will use table name `post` as default behaviour. tableName: "posts", // Optional: Provide `tableName` property to override the default behaviour for table name. columns: { @@ -87,7 +91,7 @@ module.exports = { generated: true }, title: { - type: "string" + type: "varchar" }, text: { type: "text" @@ -101,7 +105,7 @@ module.exports = { cascade: true } } -}; +}); ``` You can checkout this example [typeorm/javascript-example](https://github.com/typeorm/javascript-example) to learn more. diff --git a/docs/zh_CN/usage-with-javascript.md b/docs/zh_CN/usage-with-javascript.md index c3d193d0187..4a8922dee22 100644 --- a/docs/zh_CN/usage-with-javascript.md +++ b/docs/zh_CN/usage-with-javascript.md @@ -17,7 +17,10 @@ typeorm password: "admin", database: "test", synchronize: true, - entitySchemas: [require("./entity/Post"), require("./entity/Category")] + entities: [ + require("./entity/Post"), + require("./entity/Category") + ] }) .then(function(connection) { var category1 = { @@ -54,7 +57,9 @@ typeorm ##### entity/Category.js ```typescript -module.exports = { +var EntitySchema = require("typeorm").EntitySchema; + +module.exports = new EntitySchema({ name: "Category", columns: { id: { @@ -63,16 +68,18 @@ module.exports = { generated: true }, name: { - type: "string" + type: "varchar" } } -}; +}); ``` ##### entity/Post.js ```typescript -module.exports = { +var EntitySchema = require("typeorm").EntitySchema; + +module.exports = new EntitySchema({ name: "Post", columns: { id: { @@ -81,7 +88,7 @@ module.exports = { generated: true }, title: { - type: "string" + type: "varchar" }, text: { type: "text" @@ -95,7 +102,7 @@ module.exports = { cascade: true } } -}; +}); ``` 您可以查看此示例[typeorm/javascript-example](https://github.com/typeorm/javascript-example)以了解更多信息。 From aea27866fdadfef9655362bb1ded749c054b97e3 Mon Sep 17 00:00:00 2001 From: Umed Khudoiberdiev Date: Tue, 12 Jan 2021 17:35:14 +0500 Subject: [PATCH 212/212] version bump --- CHANGELOG.md | 27 +++++++++++++++++++++++++++ package-lock.json | 8 ++++---- package.json | 2 +- 3 files changed, 32 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0ad3a8919b2..57220f04727 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,30 @@ +## [0.2.30](https://github.com/typeorm/typeorm/compare/0.2.29...0.2.30) (2021-01-12) + +### Bug Fixes + +* add missing "comment" field to QB clone method ([#7205](https://github.com/typeorm/typeorm/issues/7205)) ([f019771](https://github.com/typeorm/typeorm/commit/f0197710ab986b474ce0b6c260d57e8234a5bb4f)), closes [#7203](https://github.com/typeorm/typeorm/issues/7203) +* avoid early release of PostgresQueryRunner ([#7109](https://github.com/typeorm/typeorm/issues/7109)) ([#7185](https://github.com/typeorm/typeorm/issues/7185)) ([9abe007](https://github.com/typeorm/typeorm/commit/9abe0076f65afba9034fb48ba3ebd43be7e7557a)) +* Error when sorting by an embedded entity while using join and skip/take ([#7082](https://github.com/typeorm/typeorm/issues/7082)) ([d27dd2a](https://github.com/typeorm/typeorm/commit/d27dd2af2ca320e74a17b3ab273cd3bf55d01923)), closes [#7079](https://github.com/typeorm/typeorm/issues/7079) +* Fix CLI query command TypeError ([#7043](https://github.com/typeorm/typeorm/issues/7043)) ([b35397e](https://github.com/typeorm/typeorm/commit/b35397ea07982a21d3b263cb0b7c04d5aa057d1a)) +* get length attribute of postgres array columns ([#7239](https://github.com/typeorm/typeorm/issues/7239)) ([eb82f78](https://github.com/typeorm/typeorm/commit/eb82f786cbe3244351d5860289dace3169cf473b)), closes [#6990](https://github.com/typeorm/typeorm/issues/6990) +* handle overlapping property / database names in querybuilder ([#7042](https://github.com/typeorm/typeorm/issues/7042)) ([b518fa1](https://github.com/typeorm/typeorm/commit/b518fa15f9b2183545b3c0daa2447ecd38ecc859)), closes [#7030](https://github.com/typeorm/typeorm/issues/7030) +* improve stack traces when using persist executor ([#7218](https://github.com/typeorm/typeorm/issues/7218)) ([0dfe5b8](https://github.com/typeorm/typeorm/commit/0dfe5b83f584c3960cdef28e53d2f0ded3f829ce)) +* order should allow only model fields, not methods ([#7188](https://github.com/typeorm/typeorm/issues/7188)) ([0194193](https://github.com/typeorm/typeorm/commit/01941937df11abd63fad9da082e1b5cf6a1300ce)), closes [#7178](https://github.com/typeorm/typeorm/issues/7178) +* resolve migration for UpdateDateColumn without ON UPDATE clause ([#7057](https://github.com/typeorm/typeorm/issues/7057)) ([ddd8cbc](https://github.com/typeorm/typeorm/commit/ddd8cbcdf6d67b6b1425de581c3da5d264a01167)), closes [#6995](https://github.com/typeorm/typeorm/issues/6995) +* resolves Postgres sequence identifier length error ([#7115](https://github.com/typeorm/typeorm/issues/7115)) ([568ef35](https://github.com/typeorm/typeorm/commit/568ef3546e6da6e73f68437fff418901d6232c51)), closes [#7106](https://github.com/typeorm/typeorm/issues/7106) +* return 'null' (instead of 'undefined') on lazy relations that have no results ([#7146](https://github.com/typeorm/typeorm/issues/7146)) ([#7147](https://github.com/typeorm/typeorm/issues/7147)) ([9b278c9](https://github.com/typeorm/typeorm/commit/9b278c99e52bbcdf0d36ece29168785ee8641687)) +* support MongoDB DNS seed list connection ([#7136](https://github.com/typeorm/typeorm/issues/7136)) ([f730bb9](https://github.com/typeorm/typeorm/commit/f730bb9fc1908a65edacc07e5e364648efb48768)), closes [#3347](https://github.com/typeorm/typeorm/issues/3347) [#3133](https://github.com/typeorm/typeorm/issues/3133) +* **data-api:** Fixed how data api driver uses and reuses a client ([#6869](https://github.com/typeorm/typeorm/issues/6869)) ([6ce65fb](https://github.com/typeorm/typeorm/commit/6ce65fbf6be5e696c3ae907d3f8e63b1e7332a1e)) +* use default import of yargs for --help ([#6986](https://github.com/typeorm/typeorm/issues/6986)) ([6ef8ffe](https://github.com/typeorm/typeorm/commit/6ef8ffe387980c51f9f20e9cc03d6199c7068ac5)) + + +### Features + +* add NOWAIT and SKIP LOCKED lock support for MySQL ([#7236](https://github.com/typeorm/typeorm/issues/7236)) ([9407507](https://github.com/typeorm/typeorm/commit/9407507a742a3fe0ea2a836417d6851cad72e74c)), closes [#6530](https://github.com/typeorm/typeorm/issues/6530) +* closure table custom naming ([#7120](https://github.com/typeorm/typeorm/issues/7120)) ([bcd998b](https://github.com/typeorm/typeorm/commit/bcd998b4f384893679e60914d3c52b3d68e7792e)) +* JavaScript file migrations output ([#7253](https://github.com/typeorm/typeorm/issues/7253)) ([ce9cb87](https://github.com/typeorm/typeorm/commit/ce9cb8732cb70458f29c0976d980d34b0f4fa3d7)) +* relations: Orphaned row action ([#7105](https://github.com/typeorm/typeorm/issues/7105)) ([efc2837](https://github.com/typeorm/typeorm/commit/efc283769ed972d022980e681e294d695087a807)) + ## [0.2.29](https://github.com/typeorm/typeorm/compare/0.2.28...0.2.29) (2020-11-02) ### Bug Fixes diff --git a/package-lock.json b/package-lock.json index c81b332f8b7..b6297edd8cb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "typeorm", - "version": "0.2.29", + "version": "0.2.30", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -7016,7 +7016,7 @@ "dependencies": { "pify": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", "dev": true } @@ -9088,7 +9088,7 @@ "dependencies": { "pify": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", "dev": true } @@ -9589,7 +9589,7 @@ }, "readable-stream": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { diff --git a/package.json b/package.json index bbcd72ab91a..1a900ac4e6d 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "typeorm", "private": true, - "version": "0.2.29", + "version": "0.2.30", "description": "Data-Mapper ORM for TypeScript, ES7, ES6, ES5. Supports MySQL, PostgreSQL, MariaDB, SQLite, MS SQL Server, Oracle, MongoDB databases.", "license": "MIT", "readmeFilename": "README.md",