diff --git a/DEVELOPER.md b/DEVELOPER.md index b365fbcda1..b6efa424d3 100644 --- a/DEVELOPER.md +++ b/DEVELOPER.md @@ -93,9 +93,9 @@ Most tests will benefit from using this template as a starting point: ```ts import "reflect-metadata"; -import {createTestingConnections, closeTestingConnections, reloadTestingDatabases} from "../../utils/test-utils"; -import {Connection} from "../../../src/connection/Connection"; -import {expect} from "chai"; +import { createTestingConnections, closeTestingConnections, reloadTestingDatabases } from "../../utils/test-utils"; +import { Connection } from "../../../src/connection/Connection"; +import { expect } from "chai"; describe("github issues > # ", () => { diff --git a/README.md b/README.md index aa40f1cf42..d3fc8216bf 100644 --- a/README.md +++ b/README.md @@ -83,7 +83,7 @@ And more... With TypeORM your models look like this: ```typescript -import {Entity, PrimaryGeneratedColumn, Column} from "typeorm"; +import { Entity, PrimaryGeneratedColumn, Column } from "typeorm"; @Entity() export class User { @@ -124,7 +124,7 @@ await repository.remove(timber); Alternatively, if you prefer to use the `ActiveRecord` implementation, you can use it as well: ```typescript -import {Entity, PrimaryGeneratedColumn, Column, BaseEntity} from "typeorm"; +import { Entity, PrimaryGeneratedColumn, Column, BaseEntity } from "typeorm"; @Entity() export class User extends BaseEntity { @@ -373,7 +373,7 @@ You can load/insert/update/remove and perform other operations with them. Let's make our `Photo` model as an entity: ```typescript -import {Entity} from "typeorm"; +import { Entity } from "typeorm"; @Entity() export class Photo { @@ -396,7 +396,7 @@ To add database columns, you simply need to decorate an entity's properties you with a `@Column` decorator. ```typescript -import {Entity, Column} from "typeorm"; +import { Entity, Column } from "typeorm"; @Entity() export class Photo { @@ -436,7 +436,7 @@ This is a requirement and you can't avoid it. To make a column a primary key, you need to use `@PrimaryColumn` decorator. ```typescript -import {Entity, Column, PrimaryColumn} from "typeorm"; +import { Entity, Column, PrimaryColumn } from "typeorm"; @Entity() export class Photo { @@ -467,7 +467,7 @@ Now, let's say you want your id column to be auto-generated (this is known as au To do that, you need to change the `@PrimaryColumn` decorator to a `@PrimaryGeneratedColumn` decorator: ```typescript -import {Entity, Column, PrimaryGeneratedColumn} from "typeorm"; +import { Entity, Column, PrimaryGeneratedColumn } from "typeorm"; @Entity() export class Photo { @@ -500,7 +500,7 @@ We don't want all our columns to be limited varchars or integers. Let's setup correct data types: ```typescript -import {Entity, Column, PrimaryGeneratedColumn} from "typeorm"; +import { Entity, Column, PrimaryGeneratedColumn } from "typeorm"; @Entity() export class Photo { @@ -537,8 +537,8 @@ Now, when our entity is created, let's create an `index.ts` (or `app.ts` whateve ```typescript import "reflect-metadata"; -import {createConnection} from "typeorm"; -import {Photo} from "./entity/Photo"; +import { createConnection } from "typeorm"; +import { Photo } from "./entity/Photo"; createConnection({ type: "mysql", @@ -574,7 +574,7 @@ Later, when we create more entities we need to add them to the entities in our c This is not very convenient, so instead we can set up the whole directory, from where all entities will be connected and used in our connection: ```typescript -import {createConnection} from "typeorm"; +import { createConnection } from "typeorm"; createConnection({ type: "mysql", @@ -622,8 +622,8 @@ Now if you run your `index.ts`, a connection with database will be initialized a Now let's create a new photo to save it in the database: ```typescript -import {createConnection} from "typeorm"; -import {Photo} from "./entity/Photo"; +import { createConnection } from "typeorm"; +import { Photo } from "./entity/Photo"; createConnection(/*...*/).then(connection => { @@ -652,8 +652,8 @@ It's not a new copy of the object, it modifies its "id" and returns it. Let's take advantage of the latest ES8 (ES2017) features and use async/await syntax instead: ```typescript -import {createConnection} from "typeorm"; -import {Photo} from "./entity/Photo"; +import { createConnection } from "typeorm"; +import { Photo } from "./entity/Photo"; createConnection(/*...*/).then(async connection => { @@ -678,8 +678,8 @@ Using entity manager you can manipulate any entity in your app. For example, let's load our saved entity: ```typescript -import {createConnection} from "typeorm"; -import {Photo} from "./entity/Photo"; +import { createConnection } from "typeorm"; +import { Photo } from "./entity/Photo"; createConnection(/*...*/).then(async connection => { @@ -702,8 +702,8 @@ When you deal with entities a lot, Repositories are more convenient to use than ```typescript -import {createConnection} from "typeorm"; -import {Photo} from "./entity/Photo"; +import { createConnection } from "typeorm"; +import { Photo } from "./entity/Photo"; createConnection(/*...*/).then(async connection => { @@ -732,8 +732,8 @@ Learn more about Repository [here](./docs/working-with-repository.md). Let's try more load operations using the Repository: ```typescript -import {createConnection} from "typeorm"; -import {Photo} from "./entity/Photo"; +import { createConnection } from "typeorm"; +import { Photo } from "./entity/Photo"; createConnection(/*...*/).then(async connection => { @@ -765,8 +765,8 @@ createConnection(/*...*/).then(async connection => { Now let's load a single photo from the database, update it and save it: ```typescript -import {createConnection} from "typeorm"; -import {Photo} from "./entity/Photo"; +import { createConnection } from "typeorm"; +import { Photo } from "./entity/Photo"; createConnection(/*...*/).then(async connection => { @@ -785,8 +785,8 @@ Now photo with `id = 1` will be updated in the database. Now let's remove our photo from the database: ```typescript -import {createConnection} from "typeorm"; -import {Photo} from "./entity/Photo"; +import { createConnection } from "typeorm"; +import { Photo } from "./entity/Photo"; createConnection(/*...*/).then(async connection => { @@ -805,8 +805,8 @@ Let's create a one-to-one relation with another class. Let's create a new class in `PhotoMetadata.ts`. This PhotoMetadata class is supposed to contain our photo's additional meta-information: ```typescript -import {Entity, Column, PrimaryGeneratedColumn, OneToOne, JoinColumn} from "typeorm"; -import {Photo} from "./Photo"; +import { Entity, Column, PrimaryGeneratedColumn, OneToOne, JoinColumn } from "typeorm"; +import { Photo } from "./Photo"; @Entity() export class PhotoMetadata { @@ -867,9 +867,9 @@ If you run the app, you'll see a newly generated table, and it will contain a co Now let's save a photo, its metadata and attach them to each other. ```typescript -import {createConnection} from "typeorm"; -import {Photo} from "./entity/Photo"; -import {PhotoMetadata} from "./entity/PhotoMetadata"; +import { createConnection } from "typeorm"; +import { Photo } from "./entity/Photo"; +import { PhotoMetadata } from "./entity/PhotoMetadata"; createConnection(/*...*/).then(async connection => { @@ -915,8 +915,8 @@ To fix this issue we should add an inverse relation, and make relations between Let's modify our entities: ```typescript -import {Entity, Column, PrimaryGeneratedColumn, OneToOne, JoinColumn} from "typeorm"; -import {Photo} from "./Photo"; +import { Entity, Column, PrimaryGeneratedColumn, OneToOne, JoinColumn } from "typeorm"; +import { Photo } from "./Photo"; @Entity() export class PhotoMetadata { @@ -930,8 +930,8 @@ export class PhotoMetadata { ``` ```typescript -import {Entity, Column, PrimaryGeneratedColumn, OneToOne} from "typeorm"; -import {PhotoMetadata} from "./PhotoMetadata"; +import { Entity, Column, PrimaryGeneratedColumn, OneToOne } from "typeorm"; +import { PhotoMetadata } from "./PhotoMetadata"; @Entity() export class Photo { @@ -960,9 +960,9 @@ Let's use `find*` methods first. `find*` methods allow you to specify an object with the `FindOneOptions` / `FindManyOptions` interface. ```typescript -import {createConnection} from "typeorm"; -import {Photo} from "./entity/Photo"; -import {PhotoMetadata} from "./entity/PhotoMetadata"; +import { createConnection } from "typeorm"; +import { Photo } from "./entity/Photo"; +import { PhotoMetadata } from "./entity/PhotoMetadata"; createConnection(/*...*/).then(async connection => { @@ -980,9 +980,9 @@ Using find options is good and dead simple, but if you need a more complex query `QueryBuilder` allows more complex queries to be used in an elegant way: ```typescript -import {createConnection} from "typeorm"; -import {Photo} from "./entity/Photo"; -import {PhotoMetadata} from "./entity/PhotoMetadata"; +import { createConnection } from "typeorm"; +import { Photo } from "./entity/Photo"; +import { PhotoMetadata } from "./entity/PhotoMetadata"; createConnection(/*...*/).then(async connection => { @@ -1061,8 +1061,8 @@ Let's say a photo has one author, and each author can have many photos. First, let's create an `Author` class: ```typescript -import {Entity, Column, PrimaryGeneratedColumn, OneToMany, JoinColumn} from "typeorm"; -import {Photo} from "./Photo"; +import { Entity, Column, PrimaryGeneratedColumn, OneToMany, JoinColumn } from "typeorm"; +import { Photo } from "./Photo"; @Entity() export class Author { @@ -1084,9 +1084,9 @@ export class Author { Now let's add the owner side of the relation into the Photo entity: ```typescript -import {Entity, Column, PrimaryGeneratedColumn, ManyToOne} from "typeorm"; -import {PhotoMetadata} from "./PhotoMetadata"; -import {Author} from "./Author"; +import { Entity, Column, PrimaryGeneratedColumn, ManyToOne } from "typeorm"; +import { PhotoMetadata } from "./PhotoMetadata"; +import { Author } from "./Author"; @Entity() export class Photo { @@ -1135,7 +1135,7 @@ Let's say a photo can be in many albums, and each album can contain many photos. Let's create an `Album` class: ```typescript -import {Entity, PrimaryGeneratedColumn, Column, ManyToMany, JoinTable} from "typeorm"; +import { Entity, PrimaryGeneratedColumn, Column, ManyToMany, JoinTable } from "typeorm"; @Entity() export class Album { diff --git a/docs/find-options.md b/docs/find-options.md index b506594de2..693494f8d5 100644 --- a/docs/find-options.md +++ b/docs/find-options.md @@ -278,6 +278,22 @@ will execute following query: SELECT * FROM "post" WHERE "title" LIKE '%out #%' ``` +* `ILike` + +```ts +import {ILike} from "typeorm"; + +const loadedPosts = await connection.getRepository(Post).find({ + title: ILike("%out #%") +}); +``` + +will execute following query: + +```sql +SELECT * FROM "post" WHERE "title" ILIKE '%out #%' +``` + * `Between` ```ts diff --git a/docs/migrations.md b/docs/migrations.md index 84e8731a51..2c159bdb3a 100644 --- a/docs/migrations.md +++ b/docs/migrations.md @@ -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, unless you use the `o` flag (see more in [Generating migrations](#generating-migrations)). 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`: ``` @@ -194,8 +194,25 @@ export class PostRefactoringTIMESTAMP implements MigrationInterface { } ``` +Alternatively you can also output your migrations as Javascript files using the `o` (alias for `--outputJs`) flag. This is useful for Javascript only projects in which TypeScript additional packages are not installed. This command, will generate a new migration file `{TIMESTAMP}-PostRefactoring.js` with the following content: + +```javascript +const { MigrationInterface, QueryRunner } = require("typeorm"); + +module.exports = class PostRefactoringTIMESTAMP { + + async up(queryRunner) { + await queryRunner.query(`ALTER TABLE "post" ALTER COLUMN "title" RENAME TO "name"`); + } + + async down(queryRunner) { + await queryRunner.query(`ALTER TABLE "post" ALTER COLUMN "title" RENAME TO "name"`); + } +} +``` + 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. To apply multi-line formatting to your generated migration queries, use the `p` (alias for `--pretty`) flag. +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/docs/using-cli.md b/docs/using-cli.md index 35e193f5ac..46c4f0d639 100644 --- a/docs/using-cli.md +++ b/docs/using-cli.md @@ -35,7 +35,7 @@ npm install -g ts-node Add typeorm command under scripts section in package.json ``` -"scripts" { +"scripts": { ... "typeorm": "node --require ts-node/register ./node_modules/typeorm/cli.js" } diff --git a/docs/zh_CN/find-options.md b/docs/zh_CN/find-options.md index 1b21e6837f..ecf062fd5f 100644 --- a/docs/zh_CN/find-options.md +++ b/docs/zh_CN/find-options.md @@ -261,6 +261,22 @@ const loadedPosts = await connection.getRepository(Post).find({ SELECT * FROM "post" WHERE "title" LIKE '%out #%' ``` +- `ILike` + +```ts +import { ILike } from "typeorm"; + +const loadedPosts = await connection.getRepository(Post).find({ + title: ILike("%out #%") +}); +``` + +将执行以下查询: + +```sql +SELECT * FROM "post" WHERE "title" ILIKE '%out #%' +``` + - `Between` ```ts diff --git a/package-lock.json b/package-lock.json index f209623a3c..1309a8caa1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,24 +1,16 @@ { "name": "@flowaccount/typeorm", - "version": "0.2.34", + "version": "0.2.37", "lockfileVersion": 1, "requires": true, "dependencies": { "@azure/abort-controller": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-1.0.2.tgz", - "integrity": "sha512-XUyTo+bcyxHEf+jlN2MXA7YU9nxVehaubngHV1MIZZaqYmZqykkoeAz/JMMEeR7t3TcyDwbFa3Zw8BZywmIx4g==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-1.0.3.tgz", + "integrity": "sha512-kCibMwqffnwlw3c+e879rCE1Am1I2BfhjOeO54XNA8i/cEuzktnBQbTrzh67XwibHO05YuNgZzSWy9ocVfFAGw==", "dev": true, "requires": { "tslib": "^2.0.0" - }, - "dependencies": { - "tslib": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz", - "integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==", - "dev": true - } } }, "@azure/core-auth": { @@ -29,49 +21,46 @@ "requires": { "@azure/abort-controller": "^1.0.0", "tslib": "^2.0.0" - }, - "dependencies": { - "tslib": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz", - "integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==", - "dev": true - } } }, "@azure/ms-rest-azure-env": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@azure/ms-rest-azure-env/-/ms-rest-azure-env-2.0.0.tgz", - "integrity": "sha512-dG76W7ElfLi+fbTjnZVGj+M9e0BIEJmRxU6fHaUQ12bZBe8EJKYb2GV50YWNaP2uJiVQ5+7nXEVj1VN1UQtaEw==", + "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": "2.2.3", - "resolved": "https://registry.npmjs.org/@azure/ms-rest-js/-/ms-rest-js-2.2.3.tgz", - "integrity": "sha512-sXOhOu/37Tr8428f32Jwuwga975Xw64pYg1UeUwOBMhkNgtn5vUuNRa3fhmem+I6f8EKoi6hOsYDFlaHeZ52jA==", + "version": "1.11.2", + "resolved": "https://registry.npmjs.org/@azure/ms-rest-js/-/ms-rest-js-1.11.2.tgz", + "integrity": "sha512-2AyQ1IKmLGKW7DU3/x3TsTBzZLcbC9YRI+yuDPuXAQrv3zar340K9wsxU413kHFIDjkWNCo9T0w5VtwcyWxhbQ==", "dev": true, "requires": { "@azure/core-auth": "^1.1.4", - "@types/node-fetch": "^2.3.7", - "@types/tunnel": "0.0.1", - "abort-controller": "^3.0.0", - "form-data": "^2.5.0", - "node-fetch": "^2.6.0", - "tough-cookie": "^3.0.1", - "tslib": "^1.10.0", + "axios": "^0.21.1", + "form-data": "^2.3.2", + "tough-cookie": "^2.4.3", + "tslib": "^1.9.2", "tunnel": "0.0.6", - "uuid": "^3.3.2", + "uuid": "^3.2.1", "xml2js": "^0.4.19" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } } }, "@azure/ms-rest-nodeauth": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@azure/ms-rest-nodeauth/-/ms-rest-nodeauth-3.0.6.tgz", - "integrity": "sha512-2twuzsXHdKMzEFI2+Sr82o6yS4ppNGZceYwil8PFo+rJxOZIoBm9e0//YC+dKilV/3F+6K/HuW8LdskDrJEQWA==", + "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": "^2.0.0", - "@azure/ms-rest-js": "^2.0.4", + "@azure/ms-rest-azure-env": "^1.1.2", + "@azure/ms-rest-js": "^1.8.7", "adal-node": "^0.1.28" } }, @@ -91,9 +80,9 @@ "dev": true }, "@babel/highlight": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.12.13.tgz", - "integrity": "sha512-kocDQvIbgMKlWxXe9fof3TQ+gkIPOUSEYhJjqUjvKMez3krV7vbzYCDq39Oj11UAVK7JqPVGQPlgE85dPNlQww==", + "version": "7.13.8", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.13.8.tgz", + "integrity": "sha512-4vrIhfJyfNf+lCtXC2ck1rKSzDwciqF7IWFhXXrSOUC2O5DrVp+w4c6ed4AllTxhTkUP5x2tYj41VaxdVMMRDw==", "dev": true, "requires": { "@babel/helper-validator-identifier": "^7.12.11", @@ -154,9 +143,9 @@ } }, "@eslint/eslintrc": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.3.0.tgz", - "integrity": "sha512-1JTKgrOKAHVivSvOYw+sJOunkBjUOvjqWk1DPja7ZFhIS2mX/4EgTT8M7eTK9jrKhL/FvXXEbQwIs3pg1xp3dg==", + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.0.tgz", + "integrity": "sha512-2ZPCc+uNbjV5ERJr+aKSPRwZgKd2z11x0EgLvb1PURmUrn9QNRXFqje0Ldq454PfAVyaJYyrDvvIKSFP4NnBog==", "dev": true, "requires": { "ajv": "^6.12.4", @@ -166,17 +155,35 @@ "ignore": "^4.0.6", "import-fresh": "^3.2.1", "js-yaml": "^3.13.1", - "lodash": "^4.17.20", "minimatch": "^3.0.4", "strip-json-comments": "^3.1.1" }, "dependencies": { + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, "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 }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, "strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -186,41 +193,32 @@ } }, "@gulp-sourcemaps/identity-map": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@gulp-sourcemaps/identity-map/-/identity-map-1.0.2.tgz", - "integrity": "sha512-ciiioYMLdo16ShmfHBXJBOFm3xPC4AuwO4xeRpFeHz7WK9PYsWCmigagG2XyzZpubK4a3qNKoUBDhbzHfa50LQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@gulp-sourcemaps/identity-map/-/identity-map-2.0.1.tgz", + "integrity": "sha512-Tb+nSISZku+eQ4X1lAkevcQa+jknn/OVUgZ3XCxEKIsLsqYuPoJwJOPQeaOk75X3WPftb29GWY1eqE7GLsXb1Q==", "dev": true, "requires": { - "acorn": "^5.0.3", - "css": "^2.2.1", - "normalize-path": "^2.1.1", + "acorn": "^6.4.1", + "normalize-path": "^3.0.0", + "postcss": "^7.0.16", "source-map": "^0.6.0", - "through2": "^2.0.3" + "through2": "^3.0.1" }, "dependencies": { "acorn": { - "version": "5.7.4", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.4.tgz", - "integrity": "sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg==", + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", + "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==", "dev": true }, - "normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", - "dev": true, - "requires": { - "remove-trailing-separator": "^1.0.1" - } - }, "through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "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": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" + "inherits": "^2.0.4", + "readable-stream": "2 || 3" } } } @@ -256,12 +254,6 @@ } } }, - "@js-joda/core": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/@js-joda/core/-/core-3.2.0.tgz", - "integrity": "sha512-PMqgJ0sw5B7FKb2d5bWYIoxjri+QlW/Pys7+Rw82jSH0QN3rB05jZ/VrrsUdh1w4+i2kw9JOejXGq/KhDOX7Kg==", - "dev": true - }, "@nodelib/fs.scandir": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.4.tgz", @@ -328,12 +320,6 @@ "resolved": "https://registry.npmjs.org/@sqltools/formatter/-/formatter-1.2.2.tgz", "integrity": "sha512-/5O7Fq6Vnv8L6ucmPjaWbVG1XkP4FO+w5glqfkIsq3Xw4oyNAdJddbnYodNDAfjVUvo/rrSCTom4kAND7T1o5Q==" }, - "@tediousjs/connection-string": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@tediousjs/connection-string/-/connection-string-0.3.0.tgz", - "integrity": "sha512-d/keJiNKfpHo+GmSB8QcsAwBx8h+V1UbdozA5TD+eSLXprNY53JAYub47J9evsSKWDdNG5uVj0FiMozLKuzowQ==", - "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", @@ -467,9 +453,9 @@ } }, "@types/js-yaml": { - "version": "3.12.6", - "resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-3.12.6.tgz", - "integrity": "sha512-cK4XqrLvP17X6c0C8n4iTbT59EixqyXL3Fk8/Rsk4dF3oX4dg70gYUXrXVUUHpnsGMPNlTQMqf+TVmNPX6FmSQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.0.tgz", + "integrity": "sha512-4vlpCM5KPCL5CfGmTbpjwVKbISRYhduEJvvUWsH5EB7QInhEj94XPZ3ts/9FPiLZFqYO0xoW4ZL8z2AabTGgJA==", "dev": true }, "@types/json-schema": { @@ -520,29 +506,6 @@ "integrity": "sha512-vFHy/ezP5qI0rFgJ7aQnjDXwAMrG0KqqIH7tQG5PPv3BWBayOPIQNBjVc/P6hhdZfMx51REc6tfDNXHUio893g==", "dev": true }, - "@types/node-fetch": { - "version": "2.5.8", - "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.5.8.tgz", - "integrity": "sha512-fbjI6ja0N5ZA8TV53RUqzsKNkl9fv8Oj3T7zxW7FGv1GSH7gwJaNF8dzCjrqKaxKeUpTz4yT1DaJFq/omNpGfw==", - "dev": true, - "requires": { - "@types/node": "*", - "form-data": "^3.0.0" - }, - "dependencies": { - "form-data": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", - "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", - "dev": true, - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - } - } - } - }, "@types/normalize-package-data": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz", @@ -555,6 +518,16 @@ "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": "3.0.0", "resolved": "https://registry.npmjs.org/@types/rimraf/-/rimraf-3.0.0.tgz", @@ -598,15 +571,6 @@ "source-map": "^0.6.0" } }, - "@types/tunnel": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/@types/tunnel/-/tunnel-0.0.1.tgz", - "integrity": "sha512-AOqu6bQu5MSWwYvehMXLukFHnupHrpZ8nvgae5Ggie9UwzDR1CCwoXgSSWNZJuyOlCdfdsWMA5F2LlmvyoTv8A==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, "@types/undertaker": { "version": "1.2.6", "resolved": "https://registry.npmjs.org/@types/undertaker/-/undertaker-1.2.6.tgz", @@ -655,9 +619,9 @@ } }, "@types/yargs": { - "version": "15.0.13", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.13.tgz", - "integrity": "sha512-kQ5JNTrbDv3Rp5X2n/iUu37IJBDU2gsZ5R/g1/KHOOEc5IKfUFjXT6DENPGduh08I/pamwtEq4oul7gUqKTQDQ==", + "version": "16.0.0", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.0.tgz", + "integrity": "sha512-2nN6AGeMwe8+O6nO9ytQfbMQOJy65oi1yK2y/9oReR08DaXSGtMsrLyCM1ooKqfICpCx4oITaR4LkOmdzz41Ww==", "dev": true, "requires": { "@types/yargs-parser": "*" @@ -669,14 +633,19 @@ "integrity": "sha512-37RSHht+gzzgYeobbG+KWryeAW8J33Nhr69cjTqSYymXVZEN9NbRYWoYlRtDhHKPVT1FyNKwaTPC1NynKZpzRA==", "dev": true }, + "@types/zen-observable": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/@types/zen-observable/-/zen-observable-0.8.2.tgz", + "integrity": "sha512-HrCIVMLjE1MOozVoD86622S7aunluLb2PJdPfb3nYiEtohm8mIB/vyv0Fd37AdeMFrTUQXEunw78YloMA3Qilg==" + }, "@typescript-eslint/eslint-plugin": { - "version": "4.15.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.15.1.tgz", - "integrity": "sha512-yW2epMYZSpNJXZy22Biu+fLdTG8Mn6b22kR3TqblVk50HGNV8Zya15WAXuQCr8tKw4Qf1BL4QtI6kv6PCkLoJw==", + "version": "4.15.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.15.2.tgz", + "integrity": "sha512-uiQQeu9tWl3f1+oK0yoAv9lt/KXO24iafxgQTkIYO/kitruILGx3uH+QtIAHqxFV+yIsdnJH+alel9KuE3J15Q==", "dev": true, "requires": { - "@typescript-eslint/experimental-utils": "4.15.1", - "@typescript-eslint/scope-manager": "4.15.1", + "@typescript-eslint/experimental-utils": "4.15.2", + "@typescript-eslint/scope-manager": "4.15.2", "debug": "^4.1.1", "functional-red-black-tree": "^1.0.1", "lodash": "^4.17.15", @@ -686,55 +655,55 @@ } }, "@typescript-eslint/experimental-utils": { - "version": "4.15.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.15.1.tgz", - "integrity": "sha512-9LQRmOzBRI1iOdJorr4jEnQhadxK4c9R2aEAsm7WE/7dq8wkKD1suaV0S/JucTL8QlYUPU1y2yjqg+aGC0IQBQ==", + "version": "4.15.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.15.2.tgz", + "integrity": "sha512-Fxoshw8+R5X3/Vmqwsjc8nRO/7iTysRtDqx6rlfLZ7HbT8TZhPeQqbPjTyk2RheH3L8afumecTQnUc9EeXxohQ==", "dev": true, "requires": { "@types/json-schema": "^7.0.3", - "@typescript-eslint/scope-manager": "4.15.1", - "@typescript-eslint/types": "4.15.1", - "@typescript-eslint/typescript-estree": "4.15.1", + "@typescript-eslint/scope-manager": "4.15.2", + "@typescript-eslint/types": "4.15.2", + "@typescript-eslint/typescript-estree": "4.15.2", "eslint-scope": "^5.0.0", "eslint-utils": "^2.0.0" } }, "@typescript-eslint/parser": { - "version": "4.15.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.15.1.tgz", - "integrity": "sha512-V8eXYxNJ9QmXi5ETDguB7O9diAXlIyS+e3xzLoP/oVE4WCAjssxLIa0mqCLsCGXulYJUfT+GV70Jv1vHsdKwtA==", + "version": "4.15.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.15.2.tgz", + "integrity": "sha512-SHeF8xbsC6z2FKXsaTb1tBCf0QZsjJ94H6Bo51Y1aVEZ4XAefaw5ZAilMoDPlGghe+qtq7XdTiDlGfVTOmvA+Q==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "4.15.1", - "@typescript-eslint/types": "4.15.1", - "@typescript-eslint/typescript-estree": "4.15.1", + "@typescript-eslint/scope-manager": "4.15.2", + "@typescript-eslint/types": "4.15.2", + "@typescript-eslint/typescript-estree": "4.15.2", "debug": "^4.1.1" } }, "@typescript-eslint/scope-manager": { - "version": "4.15.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.15.1.tgz", - "integrity": "sha512-ibQrTFcAm7yG4C1iwpIYK7vDnFg+fKaZVfvyOm3sNsGAerKfwPVFtYft5EbjzByDJ4dj1WD8/34REJfw/9wdVA==", + "version": "4.15.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.15.2.tgz", + "integrity": "sha512-Zm0tf/MSKuX6aeJmuXexgdVyxT9/oJJhaCkijv0DvJVT3ui4zY6XYd6iwIo/8GEZGy43cd7w1rFMiCLHbRzAPQ==", "dev": true, "requires": { - "@typescript-eslint/types": "4.15.1", - "@typescript-eslint/visitor-keys": "4.15.1" + "@typescript-eslint/types": "4.15.2", + "@typescript-eslint/visitor-keys": "4.15.2" } }, "@typescript-eslint/types": { - "version": "4.15.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.15.1.tgz", - "integrity": "sha512-iGsaUyWFyLz0mHfXhX4zO6P7O3sExQpBJ2dgXB0G5g/8PRVfBBsmQIc3r83ranEQTALLR3Vko/fnCIVqmH+mPw==", + "version": "4.15.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.15.2.tgz", + "integrity": "sha512-r7lW7HFkAarfUylJ2tKndyO9njwSyoy6cpfDKWPX6/ctZA+QyaYscAHXVAfJqtnY6aaTwDYrOhp+ginlbc7HfQ==", "dev": true }, "@typescript-eslint/typescript-estree": { - "version": "4.15.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.15.1.tgz", - "integrity": "sha512-z8MN3CicTEumrWAEB2e2CcoZa3KP9+SMYLIA2aM49XW3cWIaiVSOAGq30ffR5XHxRirqE90fgLw3e6WmNx5uNw==", + "version": "4.15.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.15.2.tgz", + "integrity": "sha512-cGR8C2g5SPtHTQvAymEODeqx90pJHadWsgTtx6GbnTWKqsg7yp6Eaya9nFzUd4KrKhxdYTTFBiYeTPQaz/l8bw==", "dev": true, "requires": { - "@typescript-eslint/types": "4.15.1", - "@typescript-eslint/visitor-keys": "4.15.1", + "@typescript-eslint/types": "4.15.2", + "@typescript-eslint/visitor-keys": "4.15.2", "debug": "^4.1.1", "globby": "^11.0.1", "is-glob": "^4.0.1", @@ -743,12 +712,12 @@ } }, "@typescript-eslint/visitor-keys": { - "version": "4.15.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.15.1.tgz", - "integrity": "sha512-tYzaTP9plooRJY8eNlpAewTOqtWW/4ff/5wBjNVaJ0S0wC4Gpq/zDVRTJa5bq2v1pCNQ08xxMCndcvR+h7lMww==", + "version": "4.15.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.15.2.tgz", + "integrity": "sha512-TME1VgSb7wTwgENN5KVj4Nqg25hP8DisXxNBojM4Nn31rYaNDIocNm5cmjOFfh42n7NVERxWrDFoETO/76ePyg==", "dev": true, "requires": { - "@typescript-eslint/types": "4.15.1", + "@typescript-eslint/types": "4.15.2", "eslint-visitor-keys": "^2.0.0" } }, @@ -774,15 +743,6 @@ "integrity": "sha1-kbR5JYinc4wl813W9jdSovh3YTU=", "dev": true }, - "abort-controller": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", - "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", - "dev": true, - "requires": { - "event-target-shim": "^5.0.0" - } - }, "acorn": { "version": "7.4.1", "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", @@ -1096,12 +1056,9 @@ "dev": true }, "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "requires": { - "sprintf-js": "~1.0.2" - } + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" }, "arr-diff": { "version": "4.0.0", @@ -1325,6 +1282,15 @@ "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==", "dev": true }, + "axios": { + "version": "0.21.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz", + "integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==", + "dev": true, + "requires": { + "follow-redirects": "^1.10.0" + } + }, "bach": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/bach/-/bach-1.2.0.tgz", @@ -1465,6 +1431,16 @@ "readable-stream": "^3.4.0" }, "dependencies": { + "buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, "readable-stream": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", @@ -1519,12 +1495,12 @@ "dev": true }, "buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", "requires": { "base64-js": "^1.3.1", - "ieee754": "^1.1.13" + "ieee754": "^1.2.1" } }, "buffer-equal": { @@ -1767,16 +1743,10 @@ "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", "dev": true }, - "ci-info": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", - "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", - "dev": true - }, "class-transformer": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.3.1.tgz", - "integrity": "sha512-cKFwohpJbuMovS8xVLmn8N2AUbAuc8pVo4zEfsUVo8qgECOogns1WVk/FkOZoxhOPTyTYFckuoH+13FO+MQ8GA==", + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.4.0.tgz", + "integrity": "sha512-ETWD/H2TbWbKEi7m9N4Km5+cw1hNcqJSxlSYhsLsNjQzWWiZIYA1zafxpK9PwVfaZ6AqR5rrjPVUBGESm5tQUA==", "dev": true }, "class-utils": { @@ -1969,12 +1939,6 @@ "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.3.0", "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", @@ -2271,15 +2235,26 @@ } }, "css": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/css/-/css-2.2.4.tgz", - "integrity": "sha512-oUnjmWpy0niI3x/mPL8dVEI1l7MnG3+HHyRPHf+YFSbK+svOhXpmSOcDURUh2aOCgl2grzrOPt1nHLuCVFULLw==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/css/-/css-3.0.0.tgz", + "integrity": "sha512-DG9pFfwOrzc+hawpmqX/dHYHJG+Bsdb0klhyi1sDneOgGOXy9wQIC8hzyVp1e4NRYDBdxcylvywPkkXCHAzTyQ==", "dev": true, "requires": { - "inherits": "^2.0.3", + "inherits": "^2.0.4", "source-map": "^0.6.1", - "source-map-resolve": "^0.5.2", - "urix": "^0.1.0" + "source-map-resolve": "^0.6.0" + }, + "dependencies": { + "source-map-resolve": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.6.0.tgz", + "integrity": "sha512-KXBr9d/fO/bWo97NXsPIAW1bFSBOuCnjbNTBMO7N59hsv5i9yzRDfcYwwt0l04+VqnKC+EwzvJZIP/qkuMgR/w==", + "dev": true, + "requires": { + "atob": "^2.1.2", + "decode-uri-component": "^0.2.0" + } + } } }, "currently-unhandled": { @@ -2515,37 +2490,19 @@ } }, "del": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/del/-/del-5.1.0.tgz", - "integrity": "sha512-wH9xOVHnczo9jN2IW68BabcecVPxacIA3g/7z6vhSU/4stOKQzeCRK0yD0A24WiAAUJmmVpWqrERcTxnLo3AnA==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/del/-/del-6.0.0.tgz", + "integrity": "sha512-1shh9DQ23L16oXSZKB2JxpL7iMy2E0S9d517ptA1P8iw0alkPtQcrKH7ru31rYtKwF499HkTu+DRzq3TCKDFRQ==", "dev": true, "requires": { - "globby": "^10.0.1", - "graceful-fs": "^4.2.2", + "globby": "^11.0.1", + "graceful-fs": "^4.2.4", "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", + "is-path-inside": "^3.0.2", + "p-map": "^4.0.0", + "rimraf": "^3.0.2", "slash": "^3.0.0" - }, - "dependencies": { - "globby": { - "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" - } - } } }, "delayed-stream": { @@ -2591,9 +2548,9 @@ "dev": true }, "diff": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", - "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", "dev": true }, "dir-glob": { @@ -2707,39 +2664,6 @@ "is-arrayish": "^0.2.1" } }, - "es-abstract": { - "version": "1.18.0-next.2", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.2.tgz", - "integrity": "sha512-Ih4ZMFHEtZupnUh6497zEL4y2+w8+1ljnCyaTa+adcoafI1GOvMwFlDjBLfWR7y9VLfrjRJe9ocuHY1PSR9jjw==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2", - "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.2.2", - "is-negative-zero": "^2.0.1", - "is-regex": "^1.1.1", - "object-inspect": "^1.9.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "string.prototype.trimend": "^1.0.3", - "string.prototype.trimstart": "^1.0.3" - } - }, - "es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, "es5-ext": { "version": "0.10.53", "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.53.tgz", @@ -2871,13 +2795,13 @@ } }, "eslint": { - "version": "7.20.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.20.0.tgz", - "integrity": "sha512-qGi0CTcOGP2OtCQBgWZlQjcTuP0XkIpYFj25XtRTQSHC+umNnp7UMshr2G8SLsRFYDdAPFeHOsiteadmMH02Yw==", + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.21.0.tgz", + "integrity": "sha512-W2aJbXpMNofUp0ztQaF40fveSsJBjlSCSWpy//gzfTvwC+USs/nceBrKmlJOiM8r1bLwP2EuYkCqArn/6QTIgg==", "dev": true, "requires": { "@babel/code-frame": "7.12.11", - "@eslint/eslintrc": "^0.3.0", + "@eslint/eslintrc": "^0.4.0", "ajv": "^6.10.0", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", @@ -2890,7 +2814,7 @@ "espree": "^7.3.1", "esquery": "^1.4.0", "esutils": "^2.0.2", - "file-entry-cache": "^6.0.0", + "file-entry-cache": "^6.0.1", "functional-red-black-tree": "^1.0.1", "glob-parent": "^5.0.0", "globals": "^12.1.0", @@ -2924,12 +2848,31 @@ "@babel/highlight": "^7.10.4" } }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, "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 }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, "strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -2993,7 +2936,8 @@ "esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true }, "esquery": { "version": "1.4.0", @@ -3051,26 +2995,20 @@ "es5-ext": "~0.10.14" } }, - "event-target-shim": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", - "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", - "dev": true - }, "execa": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-2.1.0.tgz", - "integrity": "sha512-Y/URAVapfbYy2Xp/gb6A0E7iR8xeqOCXsuuaoMn7A5PzrXUK84E1gyiEfq0wQd/GHA6GsoHWwhNq8anb0mleIw==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.0.0.tgz", + "integrity": "sha512-ov6w/2LCiuyO4RLYGdpFGjkcs0wMTgGE8PrkTHikeUy5iJekXyPIKUjifk5CsE0pt7sMCrMZ3YNqoCj6idQOnQ==", "dev": true, "requires": { - "cross-spawn": "^7.0.0", - "get-stream": "^5.0.0", + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.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", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", "strip-final-newline": "^2.0.0" } }, @@ -3310,9 +3248,9 @@ "dev": true }, "fastq": { - "version": "1.10.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.10.1.tgz", - "integrity": "sha512-AWuv6Ery3pM+dY7LYS8YIaCiQvUaos9OB1RyNgaOWnaX+Tik7Onvcsf8x8c+YtDeT0maYLniBip2hox5KtEXXA==", + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.11.0.tgz", + "integrity": "sha512-7Eczs8gIPDrVzT+EksYBcupqMyxSHXXrHOLRRxU2/DicV8789MRBRR8+Hc2uWzUupOs4YS4JzBmBxjjCVBxD/g==", "dev": true, "requires": { "reusify": "^1.0.4" @@ -3366,15 +3304,6 @@ "path-exists": "^4.0.0" } }, - "find-versions": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/find-versions/-/find-versions-4.0.0.tgz", - "integrity": "sha512-wgpWy002tA+wgmO27buH/9KzyEOQnKsG/R0yrcjPT9BOFm0zRBVQbZ95nRGXWMywS8YR5knRbpohio0bcJABxQ==", - "dev": true, - "requires": { - "semver-regex": "^3.1.2" - } - }, "findup-sync": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-3.0.0.tgz", @@ -3512,21 +3441,10 @@ "dev": true }, "flat": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.1.tgz", - "integrity": "sha512-FmTtBsHskrU6FJ2VxCnsDb84wu9zhmO3cUX2kGFb5tuwhfXxGciiT0oRY+cck35QmG+NmGh5eLz6lLCpWTqwpA==", - "dev": true, - "requires": { - "is-buffer": "~2.0.3" - }, - "dependencies": { - "is-buffer": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", - "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", - "dev": true - } - } + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true }, "flat-cache": { "version": "3.0.4", @@ -3554,6 +3472,12 @@ "readable-stream": "^2.3.6" } }, + "follow-redirects": { + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.3.tgz", + "integrity": "sha512-DUgl6+HDzB0iEptNQEXLx/KhTmDb8tZUHSeLqpnjpknR70H0nC2t9N73BK6fN4hOvJ84pKlIQVQ4k5FFlBedKA==", + "dev": true + }, "for-in": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", @@ -3966,13 +3890,10 @@ "dev": true }, "get-stream": { - "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" - } + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.0.tgz", + "integrity": "sha512-A1B3Bh1UmL0bidM/YX2NsCOTnGJePL9rO/M+Mw3m9f2gUpfokS0hi5Eah0WSUEWZdZhIZtMjkIYS7mDfOqNHbg==", + "dev": true }, "get-value": { "version": "2.0.6", @@ -4463,6 +4384,15 @@ "color-convert": "^1.9.0" } }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, "astral-regex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", @@ -4637,6 +4567,16 @@ "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", "dev": true }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, "levn": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", @@ -4873,314 +4813,26 @@ } }, "gulp-mocha": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/gulp-mocha/-/gulp-mocha-7.0.2.tgz", - "integrity": "sha512-ZXBGN60TXYnFhttr19mfZBOtlHYGx9SvCSc+Kr/m2cMIGloUe176HBPwvPqlakPuQgeTGVRS47NmcdZUereKMQ==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/gulp-mocha/-/gulp-mocha-8.0.0.tgz", + "integrity": "sha512-FdbBydfzszaES/gXfwD6RFq1yJTj4Z6328R1yqsmhf+t7hW2aj9ZD9Hz8boQShjZ9J8/w6tQBM5mePb8K2pbqA==", "dev": true, "requires": { "dargs": "^7.0.0", - "execa": "^2.0.4", - "mocha": "^6.2.0", + "execa": "^5.0.0", + "mocha": "^8.3.0", "plugin-error": "^1.0.1", - "supports-color": "^7.0.0", - "through2": "^3.0.1" + "supports-color": "^8.1.1", + "through2": "^4.0.2" }, "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==", - "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 - }, - "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" - } - }, - "cliui": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", - "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", - "dev": true, - "requires": { - "string-width": "^3.1.0", - "strip-ansi": "^5.2.0", - "wrap-ansi": "^5.1.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "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" - } - }, - "emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", - "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==", - "dev": true, - "requires": { - "locate-path": "^3.0.0" - } - }, - "glob": { - "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", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "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 - }, - "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=", - "dev": true - }, - "js-yaml": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", - "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - }, - "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" - } - }, - "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": "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", - "debug": "3.2.6", - "diff": "3.5.0", - "escape-string-regexp": "1.0.5", - "find-up": "3.0.0", - "glob": "7.1.3", - "growl": "1.10.5", - "he": "1.2.0", - "js-yaml": "3.13.1", - "log-symbols": "2.2.0", - "minimatch": "3.0.4", - "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": { - "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==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", - "dev": true - }, - "object.assign": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", - "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", - "dev": true, - "requires": { - "define-properties": "^1.1.2", - "function-bind": "^1.1.1", - "has-symbols": "^1.0.0", - "object-keys": "^1.0.11" - } - }, - "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 - }, - "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" - } - }, - "which": { - "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" - } - }, - "which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", - "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.1", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.1.tgz", - "integrity": "sha512-wNcy4NvjMYL8gogWWYAO7ZFWFfHcbdbE57tZO8e4cbpj8tfUcwrwqSl3ad8HxpYWCdXcJUCeKKZS62Av1affwQ==", - "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" + "has-flag": "^4.0.0" } } } @@ -5235,32 +4887,38 @@ "inherits": "^2.0.4", "readable-stream": "2 || 3" } + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true } } }, "gulp-sourcemaps": { - "version": "2.6.5", - "resolved": "https://registry.npmjs.org/gulp-sourcemaps/-/gulp-sourcemaps-2.6.5.tgz", - "integrity": "sha512-SYLBRzPTew8T5Suh2U8jCSDKY+4NARua4aqjj8HOysBh2tSgT9u4jc1FYirAdPx1akUxxDeK++fqw6Jg0LkQRg==", - "dev": true, - "requires": { - "@gulp-sourcemaps/identity-map": "1.X", - "@gulp-sourcemaps/map-sources": "1.X", - "acorn": "5.X", - "convert-source-map": "1.X", - "css": "2.X", - "debug-fabulous": "1.X", - "detect-newline": "2.X", - "graceful-fs": "4.X", - "source-map": "~0.6.0", - "strip-bom-string": "1.X", - "through2": "2.X" + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/gulp-sourcemaps/-/gulp-sourcemaps-3.0.0.tgz", + "integrity": "sha512-RqvUckJkuYqy4VaIH60RMal4ZtG0IbQ6PXMNkNsshEGJ9cldUPRb/YCgboYae+CLAs1HQNb4ADTKCx65HInquQ==", + "dev": true, + "requires": { + "@gulp-sourcemaps/identity-map": "^2.0.1", + "@gulp-sourcemaps/map-sources": "^1.0.0", + "acorn": "^6.4.1", + "convert-source-map": "^1.0.0", + "css": "^3.0.0", + "debug-fabulous": "^1.0.0", + "detect-newline": "^2.0.0", + "graceful-fs": "^4.0.0", + "source-map": "^0.6.0", + "strip-bom-string": "^1.0.0", + "through2": "^2.0.0" }, "dependencies": { "acorn": { - "version": "5.7.4", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.4.tgz", - "integrity": "sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg==", + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", + "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==", "dev": true }, "through2": { @@ -5394,9 +5052,9 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" }, "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==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", + "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", "dev": true }, "has-unicode": { @@ -5498,28 +5156,16 @@ } }, "human-signals": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", - "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", "dev": true }, "husky": { - "version": "4.3.8", - "resolved": "https://registry.npmjs.org/husky/-/husky-4.3.8.tgz", - "integrity": "sha512-LCqqsB0PzJQ/AlCgfrfzRe3e3+NvmefAdKQhRYpxS4u6clblBoDdzzvHi8fmxKRzvMxPY/1WZWzomPZww0Anow==", - "dev": true, - "requires": { - "chalk": "^4.0.0", - "ci-info": "^2.0.0", - "compare-versions": "^3.6.0", - "cosmiconfig": "^7.0.0", - "find-versions": "^4.0.0", - "opencollective-postinstall": "^2.0.2", - "pkg-dir": "^5.0.0", - "please-upgrade-node": "^3.2.0", - "slash": "^3.0.0", - "which-pm-runs": "^1.0.0" - } + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/husky/-/husky-5.1.1.tgz", + "integrity": "sha512-80LZ736V0Nr4/st0c2COYaMbEQhHNmAbLMN8J/kLk7/mo0QdUkUGNDjv/7jVkhug377Wh8wfbWyaVXEJ/h2B/Q==", + "dev": true }, "iconv-lite": { "version": "0.4.24", @@ -5625,12 +5271,6 @@ "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=", "dev": true }, - "ip-regex": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", - "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=", - "dev": true - }, "is-absolute": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz", @@ -5682,12 +5322,6 @@ "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", "dev": true }, - "is-callable": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.3.tgz", - "integrity": "sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ==", - "dev": true - }, "is-core-module": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.2.0.tgz", @@ -5717,12 +5351,6 @@ } } }, - "is-date-object": { - "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": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", @@ -5780,12 +5408,6 @@ "integrity": "sha1-aRC8pdqMleeEtXUbl2z1oQ/uNtI=", "dev": true }, - "is-negative-zero": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", - "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==", - "dev": true - }, "is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -5837,16 +5459,6 @@ "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=", "dev": true }, - "is-regex": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.2.tgz", - "integrity": "sha512-axvdhb5pdhEVThqJzYXwMlVuZwC+FF2DpcOhTS+y/8jVq4trxyPgfcwIxIKiyeuLlSQYKkmUaPQJ8ZE4yNKXDg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "has-symbols": "^1.0.1" - } - }, "is-regexp": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", @@ -5868,15 +5480,6 @@ "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", "dev": true }, - "is-symbol": { - "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.1" - } - }, "is-text-path": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-text-path/-/is-text-path-1.0.1.tgz", @@ -5965,6 +5568,15 @@ "wordwrap": "^1.0.0" }, "dependencies": { + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, "esprima": { "version": "2.7.3", "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", @@ -5990,6 +5602,24 @@ "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", "dev": true }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "dependencies": { + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + } + } + }, "mkdirp": { "version": "0.5.5", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", @@ -6053,12 +5683,11 @@ "dev": true }, "js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.0.0.tgz", + "integrity": "sha512-pqon0s+4ScYUvX30wxQi3PogGFAlUyH0awepWvwkj4jD4v+ova3RiYw8bmA6x2rDrEaj8i/oWKoRxpVNW+Re8Q==", "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "argparse": "^2.0.1" } }, "jsbi": { @@ -6275,30 +5904,27 @@ "strip-final-newline": "^2.0.0" } }, - "log-symbols": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.0.0.tgz", - "integrity": "sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA==", + "get-stream": { + "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": { - "chalk": "^4.0.0" + "pump": "^3.0.0" } }, - "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": { - "path-key": "^3.0.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 } } }, "listr2": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/listr2/-/listr2-3.3.2.tgz", - "integrity": "sha512-mGwDWg5Zq2m96Ern+RFTgzh6otSfLtHqhWKhoNvCErr46komaWAs1G8K6Th4VENps3cKySKGJXL1yAiCjmt5IQ==", + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-3.3.4.tgz", + "integrity": "sha512-b0lhLAvXSr63AtPF9Dgn6tyxm8Kiz6JXpVGM0uZJdnDcZp02jt7FehgAnMfA9R7riQimOKjQgLknBTdz2nmXwQ==", "dev": true, "requires": { "chalk": "^4.1.0", @@ -6307,20 +5933,9 @@ "indent-string": "^4.0.0", "log-update": "^4.0.0", "p-map": "^4.0.0", - "rxjs": "^6.6.3", + "rxjs": "^6.6.6", "through": "^2.3.8", "wrap-ansi": "^7.0.0" - }, - "dependencies": { - "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": { - "aggregate-error": "^3.0.0" - } - } } }, "load-json-file": { @@ -6400,64 +6015,12 @@ } }, "log-symbols": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", - "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.0.0.tgz", + "integrity": "sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA==", "dev": true, "requires": { - "chalk": "^2.0.1" - }, - "dependencies": { - "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" - } - }, - "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" - } - }, - "color-convert": { - "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" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "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" - } - } + "chalk": "^4.0.0" } }, "log-update": { @@ -6982,24 +6545,12 @@ "picomatch": "^2.0.4" } }, - "argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, "binary-extensions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", "dev": true }, - "camelcase": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", - "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", - "dev": true - }, "chokidar": { "version": "3.5.1", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.1.tgz", @@ -7016,18 +6567,6 @@ "readdirp": "~3.5.0" } }, - "decamelize": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", - "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", - "dev": true - }, - "diff": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", - "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", - "dev": true - }, "escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", @@ -7044,12 +6583,6 @@ "path-exists": "^4.0.0" } }, - "flat": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", - "dev": true - }, "fsevents": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", @@ -7066,21 +6599,6 @@ "binary-extensions": "^2.0.0" } }, - "is-plain-obj": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", - "dev": true - }, - "js-yaml": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.0.0.tgz", - "integrity": "sha512-pqon0s+4ScYUvX30wxQi3PogGFAlUyH0awepWvwkj4jD4v+ova3RiYw8bmA6x2rDrEaj8i/oWKoRxpVNW+Re8Q==", - "dev": true, - "requires": { - "argparse": "^2.0.1" - } - }, "locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -7090,15 +6608,6 @@ "p-locate": "^5.0.0" } }, - "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": { - "chalk": "^4.0.0" - } - }, "ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -7152,18 +6661,6 @@ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", "dev": true - }, - "yargs-unparser": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", - "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", - "dev": true, - "requires": { - "camelcase": "^6.0.0", - "decamelize": "^4.0.0", - "flat": "^5.0.2", - "is-plain-obj": "^2.1.0" - } } } }, @@ -7205,15 +6702,14 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "mssql": { - "version": "7.0.0-beta.3", - "resolved": "https://registry.npmjs.org/mssql/-/mssql-7.0.0-beta.3.tgz", - "integrity": "sha512-Jn/q64Dg2UjbNTqsBwCHFdMjxs4xIVqgWQ1hmDKvBR0T8ebHfPnGTzfNl4oE/VwqP1m0As+v2CMjyqOi9WneuQ==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/mssql/-/mssql-6.3.1.tgz", + "integrity": "sha512-ammxrhbdDpcBWhiZLiy6miiU7ELt9qFbGvwmPbiufn+tBHAYUFR/AgwE4/v4jzPzbatowscmhFx1U61L91uVzQ==", "dev": true, "requires": { - "@tediousjs/connection-string": "^0.3.0", - "debug": "^4", - "tarn": "^3.0.1", - "tedious": "^9.2.3" + "debug": "^4.3.1", + "tarn": "^1.1.5", + "tedious": "^6.7.0" } }, "mute-stdout": { @@ -7444,30 +6940,6 @@ "integrity": "sha512-flmrDNB06LIl5lywUz7YlNGZH/5p0M7W28k8hzd9Lshtdh1wshD2Y+U4h9LD6KObOy1f+fEVdgprPrEymjM5uw==", "dev": true }, - "node-environment-flags": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.5.tgz", - "integrity": "sha512-VNYPRfGfmZLx0Ye20jWzHUjyTW/c+6Wq+iLhDzUI4XmhrDd9l/FozXV3F2xOaXjvp0co0+v1YSR3CMP6g+VvLQ==", - "dev": true, - "requires": { - "object.getownpropertydescriptors": "^2.0.3", - "semver": "^5.7.0" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } - } - }, - "node-fetch": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", - "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==", - "dev": true - }, "node-gyp": { "version": "3.8.0", "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-3.8.0.tgz", @@ -7712,9 +7184,9 @@ } }, "npm-run-path": { - "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==", + "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": { "path-key": "^3.0.0" @@ -7780,12 +7252,6 @@ } } }, - "object-inspect": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.9.0.tgz", - "integrity": "sha512-i3Bp9iTqwhaLZBxGkRfo5ZbE07BQRT7MGu8+nNgwW9ItGp1TzCTw2DLEoWwjClxBjOFI/hWljTAmYGCEwmtnOw==", - "dev": true - }, "object-keys": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", @@ -7825,17 +7291,6 @@ "isobject": "^3.0.0" } }, - "object.getownpropertydescriptors": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.2.tgz", - "integrity": "sha512-WtxeKSzfBjlzL+F9b7M7hewDzMwy+C8NRssHd1YrNlzHzIDrXcXiNOMrezdAEM4UXixgV+vvnyBeN7Rygl2ttQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.2" - } - }, "object.map": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/object.map/-/object.map-1.0.1.tgz", @@ -7882,12 +7337,6 @@ "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 - }, "optionator": { "version": "0.9.1", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", @@ -7948,12 +7397,6 @@ "os-tmpdir": "^1.0.0" } }, - "p-finally": { - "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": "2.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", @@ -7973,9 +7416,9 @@ } }, "p-map": { - "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==", + "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": { "aggregate-error": "^3.0.0" @@ -8242,66 +7685,18 @@ "dev": true }, "pinkie": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", - "dev": true - }, - "pinkie-promise": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", - "dev": true, - "requires": { - "pinkie": "^2.0.0" - } - }, - "pkg-dir": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-5.0.0.tgz", - "integrity": "sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA==", - "dev": true, - "requires": { - "find-up": "^5.0.0" - }, - "dependencies": { - "find-up": { - "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": "^6.0.0", - "path-exists": "^4.0.0" - } - }, - "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": { - "p-locate": "^5.0.0" - } - }, - "p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "requires": { - "yocto-queue": "^0.1.0" - } - }, - "p-locate": { - "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": "^3.0.2" - } - } + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "dev": true + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "dev": true, + "requires": { + "pinkie": "^2.0.0" } }, "please-upgrade-node": { @@ -8342,6 +7737,80 @@ "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", "dev": true }, + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "dependencies": { + "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" + } + }, + "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" + }, + "dependencies": { + "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" + } + } + } + }, + "color-convert": { + "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" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "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": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, "postgres-array": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", @@ -9016,16 +8485,6 @@ "combined-stream": "^1.0.6", "mime-types": "^2.1.12" } - }, - "tough-cookie": { - "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.28", - "punycode": "^2.1.1" - } } } }, @@ -9158,12 +8617,20 @@ } }, "rxjs": { - "version": "6.6.3", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.3.tgz", - "integrity": "sha512-trsQc+xYYXZ3urjOiJOuCOa5N3jAZ3eiSpQB5hIT8zGlL2QfnHLJ2r7GMkBGuIausdJN1OneaI6gQlsqNHHmZQ==", + "version": "6.6.6", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.6.tgz", + "integrity": "sha512-/oTwee4N4iWzAMAL9xdGKjkEHmIwupR3oXbQjCKywF1BeFohswF3vZdogbmEF6pZkOsXTzWkrZszrWpQTByYVg==", "dev": true, "requires": { "tslib": "^1.9.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } } }, "safe-buffer": { @@ -9225,12 +8692,6 @@ "sver-compat": "^1.5.0" } }, - "semver-regex": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/semver-regex/-/semver-regex-3.1.2.tgz", - "integrity": "sha512-bXWyL6EAKOJa81XG1OZ/Yyuq+oT0b2YLlxx7c+mrdYPaPbnj6WgVULXhinMIeZGufuUBu/eVRqXEhiv4imfwxA==", - "dev": true - }, "seq-queue": { "version": "0.0.5", "resolved": "https://registry.npmjs.org/seq-queue/-/seq-queue-0.0.5.tgz", @@ -9632,7 +9093,8 @@ "sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true }, "sql.js": { "version": "1.4.0", @@ -9720,35 +9182,15 @@ "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==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.1.tgz", + "integrity": "sha512-LL0OLyN6AnfV9xqGQpDBwedT2Rt63737LxvsRxbcwpa2aIeynBApG2Sm//F3TaLHIR1aJBN52DWklc06b94o5Q==", "requires": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.0" } }, - "string.prototype.trimend": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.3.tgz", - "integrity": "sha512-ayH0pB+uf0U28CtjlLvL7NaohvR1amUvVZk+y3DYb0Ey2PUV5zPkkKy9+U1ndVEIXO8hNg18eIv9Jntbii+dKw==", - "dev": true, - "requires": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3" - } - }, - "string.prototype.trimstart": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.3.tgz", - "integrity": "sha512-oBIBUy5lea5tt0ovtOFiEQaBkoBBkyJhZXzJYrSmDo5IUUqbOPvVezuRs/agBIdZ2p2Eo1FD6bD9USyBLfl3xg==", - "dev": true, - "requires": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3" - } - }, "string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", @@ -9940,30 +9382,36 @@ } }, "tarn": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/tarn/-/tarn-3.0.1.tgz", - "integrity": "sha512-6usSlV9KyHsspvwu2duKH+FMUhqJnAh6J5J/4MITl8s94iSUQTLkJggdiewKv4RyARQccnigV48Z+khiuVZDJw==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/tarn/-/tarn-1.1.5.tgz", + "integrity": "sha512-PMtJ3HCLAZeedWjJPgGnCvcphbCOMbtZpjKgLq3qM5Qq9aQud+XHrL0WlrlgnTyS8U+jrjGbEXprFcQrxPy52g==", "dev": true }, "tedious": { - "version": "9.2.3", - "resolved": "https://registry.npmjs.org/tedious/-/tedious-9.2.3.tgz", - "integrity": "sha512-+mI2r/5mqxpTHKBZ/SW+NNH2MK5i3Pwwkw0gF5ZrS2wf2uT/03bLSss8nm7xh604abJXyjx0sirhwH63H328qA==", + "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": "^3.0.6", - "@js-joda/core": "^3.1.0", - "adal-node": "^0.1.28", + "@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.6.2", - "jsbi": "^3.1.3", + "iconv-lite": "^0.5.0", + "jsbi": "^3.1.1", "native-duplexpair": "^1.0.0", "punycode": "^2.1.0", - "readable-stream": "^3.6.0", + "readable-stream": "^3.4.0", "sprintf-js": "^1.1.2" }, "dependencies": { + "@types/node": { + "version": "12.20.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.4.tgz", + "integrity": "sha512-xRCgeE0Q4pT5UZ189TJ3SpYuX/QGl6QIAOAIeDSbAVAd2gX1NxSZup4jNVK7cxIeP8KDSbJgcckun495isP1jQ==", + "dev": true + }, "bl": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/bl/-/bl-3.0.1.tgz", @@ -9974,12 +9422,12 @@ } }, "iconv-lite": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.2.tgz", - "integrity": "sha512-2y91h5OpQlolefMPmUlivelittSWy0rP+oYVpn6A7GwVHNE8AWzoYOBNmlwks3LobaJxgHCYZAnyNo2GgpNRNQ==", + "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.0.0" + "safer-buffer": ">= 2.1.2 < 3" } }, "readable-stream": { @@ -10199,12 +9647,11 @@ } }, "tough-cookie": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-3.0.1.tgz", - "integrity": "sha512-yQyJ0u4pZsv9D4clxO69OEjLWYw+jbgspjTue4lTQZLfV0c5l1VmK2y1JK8E9ahdpltPOaAThPcp5nKPUgSnsg==", + "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": { - "ip-regex": "^2.1.0", "psl": "^1.1.28", "punycode": "^2.1.1" } @@ -10244,9 +9691,9 @@ } }, "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz", + "integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==" }, "tsutils": { "version": "3.20.0", @@ -10255,6 +9702,14 @@ "dev": true, "requires": { "tslib": "^1.8.1" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } } }, "tunnel": { @@ -10321,9 +9776,9 @@ } }, "typescript": { - "version": "3.6.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.6.5.tgz", - "integrity": "sha512-BEjlc0Z06ORZKbtcxGrIvvwYs5hAnuo6TKdNFL55frVDlB+na3z5bsLhFaIxmT+dPWgBIjMo6aNnTOgHHmHgiQ==", + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.2.tgz", + "integrity": "sha512-tbb+NVrLfnsJy3M59lsDgrzWIflR4d4TIUjz+heUnHZwdF7YsrMTKoRERiIvI2lvBG95dfpLxB21WZhys1bgaQ==", "dev": true }, "uglify-js": { @@ -10846,179 +10301,34 @@ "integrity": "sha512-AP1+fQIWSM/sMiET8fyayjx/J+JmTPt2Mr0FkrgqB4todtfa53sOsrSAcIrJRD5XS20bKUwaDIuMkWKCEiQLKA==" }, "yargs-unparser": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.6.0.tgz", - "integrity": "sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", "dev": true, "requires": { - "flat": "^4.1.0", - "lodash": "^4.17.15", - "yargs": "^13.3.0" + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.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 - }, - "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" - } - }, - "cliui": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", - "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", - "dev": true, - "requires": { - "string-width": "^3.1.0", - "strip-ansi": "^5.2.0", - "wrap-ansi": "^5.1.0" - } - }, - "color-convert": { - "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" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "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==", - "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==", - "dev": true, - "requires": { - "locate-path": "^3.0.0" - } - }, - "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=", - "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" - } - }, - "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 - }, - "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==", + "camelcase": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", + "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", "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" - } - }, - "which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", "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.1", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.1.tgz", - "integrity": "sha512-wNcy4NvjMYL8gogWWYAO7ZFWFfHcbdbE57tZO8e4cbpj8tfUcwrwqSl3ad8HxpYWCdXcJUCeKKZS62Av1affwQ==", + "is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", "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" - } } } }, @@ -11033,6 +10343,20 @@ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "dev": true + }, + "zen-observable": { + "version": "0.8.15", + "resolved": "https://registry.npmjs.org/zen-observable/-/zen-observable-0.8.15.tgz", + "integrity": "sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ==" + }, + "zen-observable-ts": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/zen-observable-ts/-/zen-observable-ts-1.0.0.tgz", + "integrity": "sha512-KmWcbz+9kKUeAQ8btY8m1SsEFgBcp7h/Uf3V5quhan7ZWdjGsf0JcGLULQiwOZibbFWnHkYq8Nn2AZbJabovQg==", + "requires": { + "@types/zen-observable": "^0.8.2", + "zen-observable": "^0.8.15" + } } } -} +} \ No newline at end of file diff --git a/package.json b/package.json index cd7acbab47..533f824943 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@flowaccount/typeorm", "private": true, - "version": "0.2.34", + "version": "0.2.37", "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", @@ -58,79 +58,80 @@ ], "devDependencies": { "@types/app-root-path": "^1.2.4", - "@types/chai": "^4.2.0", + "@types/chai": "^4.2.15", "@types/chai-as-promised": "^7.1.3", "@types/debug": "^4.1.5", "@types/dotenv": "^8.2.0", - "@types/js-yaml": "^3.12.5", + "@types/js-yaml": "^4.0.0", "@types/mkdirp": "^1.0.1", - "@types/mocha": "^8.0.3", - "@types/node": "^14.6.4", + "@types/mocha": "^8.2.1", + "@types/node": "^14.14.31", "@types/rimraf": "^3.0.0", "@types/sha.js": "^2.4.0", - "@types/sinon": "^9.0.5", - "@types/source-map-support": "^0.5.1", - "@types/xml2js": "^0.4.5", - "@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", + "@types/sinon": "^9.0.10", + "@types/source-map-support": "^0.5.3", + "@types/xml2js": "^0.4.8", + "@types/yargs": "^16.0.0", + "@typescript-eslint/eslint-plugin": "^4.15.2", + "@typescript-eslint/parser": "^4.15.2", + "better-sqlite3": "^7.1.2", + "chai": "^4.3.0", "chai-as-promised": "^7.1.1", - "class-transformer": "^0.3.1", - "conventional-changelog-angular": "^5.0.11", - "conventional-changelog-cli": "^2.1.0", - "del": "^5.1.0", - "eslint": "^7.8.1", + "class-transformer": "^0.4.0", + "conventional-changelog-angular": "^5.0.12", + "conventional-changelog-cli": "^2.1.1", + "del": "^6.0.0", + "eslint": "^7.20.0", "gulp": "^4.0.2", "gulp-eslint": "^6.0.0", "gulp-istanbul": "^1.1.3", - "gulp-mocha": "^7.0.2", + "gulp-mocha": "^8.0.0", "gulp-rename": "^2.0.0", "gulp-replace": "^1.0.0", "gulp-shell": "^0.8.0", - "gulp-sourcemaps": "^2.6.5", + "gulp-sourcemaps": "^3.0.0", "gulp-typescript": "^6.0.0-alpha.1", "gulpclass": "^0.2.0", - "husky": "^4.2.3", - "lint-staged": "^10.0.8", - "mocha": "^8.1.3", - "mongodb": "^3.5.4", - "mssql": "^7.0.0-beta.3", + "husky": "^5.1.1", + "lint-staged": "^10.5.4", + "mocha": "^8.3.0", + "mongodb": "^3.6.4", + "mssql": "^6.3.1", "mysql": "^2.18.1", - "mysql2": "^2.1.0", - "oracledb": "^5.0.0", - "pg": "^8.3.0", + "mysql2": "^2.2.5", + "oracledb": "^5.1.0", + "pg": "^8.5.1", "pg-query-stream": "^4.0.0", "redis": "^3.0.2", "remap-istanbul": "^0.13.0", "rimraf": "^3.0.2", - "sinon": "^9.0.0", + "sinon": "^9.2.4", "sinon-chai": "^3.5.0", - "source-map-support": "^0.5.16", - "sql.js": "^1.3.2", - "sqlite3": "^5.0.0", - "ts-node": "^9.0.0", + "source-map-support": "^0.5.19", + "sql.js": "^1.4.0", + "sqlite3": "^5.0.2", + "ts-node": "^9.1.1", "typeorm-aurora-data-api-driver": "^1.4.0", - "typescript": "~3.6.0" + "typescript": "^4.2.2" }, "dependencies": { - "@sqltools/formatter": "1.2.2", + "@sqltools/formatter": "^1.2.2", "app-root-path": "^3.0.0", - "buffer": "^5.5.0", + "buffer": "^6.0.3", "chalk": "^4.1.0", "cli-highlight": "^2.1.10", - "debug": "^4.1.1", + "debug": "^4.3.1", "dotenv": "^8.2.0", "glob": "^7.1.6", - "js-yaml": "^3.14.0", + "js-yaml": "^4.0.0", "mkdirp": "^1.0.4", "reflect-metadata": "^0.1.13", "sha.js": "^2.4.11", - "tslib": "^1.13.0", + "tslib": "^2.1.0", "xml2js": "^0.4.23", - "yargonaut": "^1.1.2", - "yargs": "^16.0.3" + "yargonaut": "^1.1.4", + "yargs": "^16.2.0", + "zen-observable-ts": "^1.0.0" }, "lint-staged": { "*.ts": [ diff --git a/sample/sample11-all-types-entity/app.ts b/sample/sample11-all-types-entity/app.ts index efa517364a..a1fc3e8dd7 100644 --- a/sample/sample11-all-types-entity/app.ts +++ b/sample/sample11-all-types-entity/app.ts @@ -44,8 +44,10 @@ createConnection(options).then(connection => { .save(entity) .then(entity => { console.log("EverythingEntity has been saved. Lets insert a new one to update it later"); - delete entity.id; - return postRepository.save(entity); + return postRepository.save({ + ...entity, + id: undefined + }) as Promise; }) .then(entity => { console.log("Second entity has been inserted. Lets update it"); @@ -74,9 +76,10 @@ createConnection(options).then(connection => { }) .then(entity => { console.log("Entity has been updated. Persist once again to make find and remove then"); - - delete entity.id; - return postRepository.save(entity); + return postRepository.save({ + ...entity, + id: undefined + }) as Promise; }) .then(entity => { return postRepository.findOne(entity.id); diff --git a/sample/sample2-one-to-one/entity/Post.ts b/sample/sample2-one-to-one/entity/Post.ts index 310c3bf40f..b34b035a8c 100644 --- a/sample/sample2-one-to-one/entity/Post.ts +++ b/sample/sample2-one-to-one/entity/Post.ts @@ -26,13 +26,13 @@ export class Post { @JoinColumn() category: PostCategory; - // post has relation with details. cascade inserts here means if new PostDetails instance will be set to this + // post has relation with details. cascade inserts here means if new PostDetails instance will be set to this // relation it will be inserted automatically to the db when you save this Post entity @OneToOne(type => PostDetails, details => details.post, { cascade: ["insert"] }) @JoinColumn() - details: PostDetails; + details?: PostDetails; // post has relation with details. cascade update here means if new PostDetail instance will be set to this relation // it will be inserted automatically to the db when you save this Post entity @@ -60,4 +60,4 @@ export class Post { @JoinColumn() author: PostAuthor; -} \ No newline at end of file +} diff --git a/sample/sample3-many-to-one/entity/Post.ts b/sample/sample3-many-to-one/entity/Post.ts index 71fc110366..22d44b2d26 100644 --- a/sample/sample3-many-to-one/entity/Post.ts +++ b/sample/sample3-many-to-one/entity/Post.ts @@ -24,12 +24,12 @@ export class Post { }) category: PostCategory; - // post has relation with details. cascade inserts here means if new PostDetails instance will be set to this + // post has relation with details. cascade inserts here means if new PostDetails instance will be set to this // relation it will be inserted automatically to the db when you save this Post entity @ManyToOne(type => PostDetails, details => details.posts, { cascade: ["insert"] }) - details: PostDetails; + details?: PostDetails; // post has relation with details. cascade update here means if new PostDetail instance will be set to this relation // it will be inserted automatically to the db when you save this Post entity @@ -53,4 +53,4 @@ export class Post { @ManyToOne(type => PostAuthor, author => author.posts) author: PostAuthor; -} \ No newline at end of file +} diff --git a/src/commands/InitCommand.ts b/src/commands/InitCommand.ts index 62922a30df..7ad82b5056 100644 --- a/src/commands/InitCommand.ts +++ b/src/commands/InitCommand.ts @@ -1,8 +1,9 @@ -import {CommandUtils} from "./CommandUtils"; -import {ObjectLiteral} from "../common/ObjectLiteral"; +import { CommandUtils } from "./CommandUtils"; +import { ObjectLiteral } from "../common/ObjectLiteral"; import * as path from "path"; import * as yargs from "yargs"; import chalk from "chalk"; +import { exec } from "child_process"; /** * Generates a new project with TypeORM. @@ -33,6 +34,12 @@ export class InitCommand implements yargs.CommandModule { }) .option("docker", { describe: "Set to true if docker-compose must be generated as well. False by default." + }) + .option("pm", { + alias: "manager", + choices: ["npm", "yarn"], + default: "npm", + describe: "Install packages, expected values are npm or yarn." }); } @@ -43,6 +50,7 @@ export class InitCommand implements yargs.CommandModule { const isDocker = args.docker !== undefined ? true : false; const basePath = process.cwd() + (args.name ? ("/" + args.name) : ""); const projectName = args.name ? path.basename(args.name as any) : undefined; + const installNpm = args.pm === "yarn" ? false : true; await CommandUtils.createFile(basePath + "/package.json", InitCommand.getPackageJsonTemplate(projectName), false); if (isDocker) await CommandUtils.createFile(basePath + "/docker-compose.yml", InitCommand.getDockerComposeTemplate(database), false); @@ -70,6 +78,12 @@ export class InitCommand implements yargs.CommandModule { console.log(chalk.green(`Project created inside current directory.`)); } + if (args.pm && installNpm) { + await InitCommand.executeCommand("npm install"); + } else { + await InitCommand.executeCommand("yarn install"); + } + } catch (err) { console.log(chalk.black.bgRed("Error during project initialization:")); console.error(err); @@ -81,11 +95,22 @@ export class InitCommand implements yargs.CommandModule { // Protected Static Methods // ------------------------------------------------------------------------- + protected static executeCommand(command: string) { + return new Promise((ok, fail) => { + exec(command, (error: any, stdout: any, stderr: any) => { + if (stdout) return ok(stdout); + if (stderr) return fail(stderr); + if (error) return fail(error); + ok(""); + }); + }); + } + /** * Gets contents of the ormconfig file. */ protected static getOrmConfigTemplate(database: string): string { - const options: ObjectLiteral = { }; + const options: ObjectLiteral = {}; switch (database) { case "mysql": Object.assign(options, { diff --git a/src/commands/MigrationGenerateCommand.ts b/src/commands/MigrationGenerateCommand.ts index f10d198497..a24343da81 100644 --- a/src/commands/MigrationGenerateCommand.ts +++ b/src/commands/MigrationGenerateCommand.ts @@ -50,6 +50,18 @@ export class MigrationGenerateCommand implements yargs.CommandModule { type: "boolean", default: false, describe: "Generate a migration file on Javascript instead of Typescript", + }) + .option("dr", { + alias: "dryrun", + type: "boolean", + default: false, + describe: "Prints out the contents of the migration instead of writing it to a file", + }) + .option("ch", { + alias: "check", + type: "boolean", + default: false, + describe: "Verifies that the current database is up to date and that no migrations are needed. Otherwise exits with code 1.", }); } @@ -124,22 +136,36 @@ export class MigrationGenerateCommand implements yargs.CommandModule { await connection.close(); } - if (upSqls.length) { - if (args.name) { - 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); - - console.log(chalk.green(`Migration ${chalk.blue(path)} has been generated successfully.`)); + if (!upSqls.length) { + if (args.check) { + console.log(chalk.green(`No changes in database schema were found`)); + process.exit(0); } else { - console.log(chalk.yellow("Please specify a migration name using the `-n` argument")); + 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); } - } 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`)); + } else if (!args.name) { + console.log(chalk.yellow("Please specify a migration name using the `-n` argument")); process.exit(1); } + + 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; + + if (args.check) { + console.log(chalk.yellow(`Unexpected changes in database schema were found in check mode:\n\n${chalk.white(fileContent)}`)); + process.exit(1); + } + + if (args.dryrun) { + console.log(chalk.green(`Migration ${chalk.blue(path)} has content:\n\n${chalk.white(fileContent)}`)); + } else { + await CommandUtils.createFile(path, fileContent); + + console.log(chalk.green(`Migration ${chalk.blue(path)} has been generated successfully.`)); + } } catch (err) { console.log(chalk.black.bgRed("Error during migration generation:")); console.error(err); diff --git a/src/connection/options-reader/ConnectionOptionsYmlReader.ts b/src/connection/options-reader/ConnectionOptionsYmlReader.ts index f43dd8867e..4b678037ef 100644 --- a/src/connection/options-reader/ConnectionOptionsYmlReader.ts +++ b/src/connection/options-reader/ConnectionOptionsYmlReader.ts @@ -18,7 +18,7 @@ export class ConnectionOptionsYmlReader { const contentsBuffer = PlatformTools.readFileSync(path); const contents = contentsBuffer.toString(); - const config: undefined | string | {[key: string]: any} = ymlParser.safeLoad(contents); + const config: undefined | string | {[key: string]: any} = ymlParser.loadAll(contents); if (typeof config !== 'object') { return []; diff --git a/src/driver/DriverUtils.ts b/src/driver/DriverUtils.ts index 6e04bbcbfc..ddd1a23112 100644 --- a/src/driver/DriverUtils.ts +++ b/src/driver/DriverUtils.ts @@ -134,12 +134,26 @@ export class DriverUtils { let port = undefined; let hostReplicaSet = undefined; let replicaSet = undefined; - // remove mongodb query params + let optionsObject: any = {}; + if (afterBase && afterBase.indexOf("?") !== -1) { - // split params to get replica set + + // split params afterQuestionMark = afterBase.substr((afterBase.indexOf("?") + 1), afterBase.length); - replicaSet = afterQuestionMark.split("=")[1]; + const optionsList = afterQuestionMark.split("&"); + let optionKey: string; + let optionValue: string; + + // create optionsObject for merge with connectionUrl object before return + optionsList.forEach(optionItem => { + optionKey = optionItem.split("=")[0]; + optionValue = optionItem.split("=")[1]; + optionsObject[optionKey] = optionValue; + }); + + // specific replicaSet value to set options about hostReplicaSet + replicaSet = optionsObject["replicaSet"]; afterBase = afterBase.substr(0, afterBase.indexOf("?")); } @@ -155,21 +169,28 @@ export class DriverUtils { password = usernameAndPassword.substr(firstColon + 1); } + // If replicaSet have value set It as hostlist, If not set like standalone host if (replicaSet) { hostReplicaSet = hostAndPort; } else { [host, port] = hostAndPort.split(":"); } - return { + let connectionUrl: any = { type: type, host: host, hostReplicaSet: hostReplicaSet, username: decodeURIComponent(username), password: decodeURIComponent(password), port: port ? parseInt(port) : undefined, - database: afterBase || undefined, - replicaSet: replicaSet || undefined + database: afterBase || undefined }; + + // Loop to set every options in connectionUrl to object + for (const [key, value] of Object.entries(optionsObject)) { + connectionUrl[key] = value; + } + + return connectionUrl; } } diff --git a/src/driver/aurora-data-api/AuroraDataApiDriver.ts b/src/driver/aurora-data-api/AuroraDataApiDriver.ts index 0df90bdbd1..f3648bc20a 100644 --- a/src/driver/aurora-data-api/AuroraDataApiDriver.ts +++ b/src/driver/aurora-data-api/AuroraDataApiDriver.ts @@ -534,6 +534,10 @@ export class AuroraDataApiDriver implements Driver { normalizeDefault(columnMetadata: ColumnMetadata): string | undefined { const defaultValue = columnMetadata.default; + if (defaultValue === null) { + return undefined + } + if ((columnMetadata.type === "enum" || columnMetadata.type === "simple-enum") && defaultValue !== undefined) { return `'${defaultValue}'`; } diff --git a/src/driver/aurora-data-api/AuroraDataApiQueryRunner.ts b/src/driver/aurora-data-api/AuroraDataApiQueryRunner.ts index 87099ddcb5..9de0819d3e 100644 --- a/src/driver/aurora-data-api/AuroraDataApiQueryRunner.ts +++ b/src/driver/aurora-data-api/AuroraDataApiQueryRunner.ts @@ -1333,7 +1333,7 @@ export class AuroraDataApiQueryRunner extends BaseQueryRunner implements QueryRu if (tableColumn.type === "enum" || tableColumn.type === "simple-enum") { const colType = dbColumn["COLUMN_TYPE"]; - const items = colType.substring(colType.indexOf("(") + 1, colType.indexOf(")")).split(","); + const items = colType.substring(colType.indexOf("(") + 1, colType.lastIndexOf(")")).split(","); tableColumn.enum = (items as string[]).map(item => { return item.substring(1, item.length - 1); }); diff --git a/src/driver/mysql/MysqlDriver.ts b/src/driver/mysql/MysqlDriver.ts index 3e55d94fd6..0c97d049f7 100644 --- a/src/driver/mysql/MysqlDriver.ts +++ b/src/driver/mysql/MysqlDriver.ts @@ -582,15 +582,20 @@ export class MysqlDriver implements Driver { normalizeDefault(columnMetadata: ColumnMetadata): string | undefined { const defaultValue = columnMetadata.default; - if ((columnMetadata.type === "enum" || columnMetadata.type === "simple-enum") && defaultValue !== undefined) { + if (defaultValue === null) { + return undefined + + } else if ( + (columnMetadata.type === "enum" + || columnMetadata.type === "simple-enum" + || typeof defaultValue === "string") + && defaultValue !== undefined) { return `'${defaultValue}'`; - } - if ((columnMetadata.type === "set") && defaultValue !== undefined) { + } else if ((columnMetadata.type === "set") && defaultValue !== undefined) { return `'${DateUtils.simpleArrayToString(defaultValue)}'`; - } - if (typeof defaultValue === "number") { + } else if (typeof defaultValue === "number") { return `'${defaultValue.toFixed(columnMetadata.scale)}'`; } else if (typeof defaultValue === "boolean") { @@ -599,12 +604,6 @@ export class MysqlDriver implements Driver { } else if (typeof defaultValue === "function") { return defaultValue(); - } else if (typeof defaultValue === "string") { - return `'${defaultValue}'`; - - } else if (defaultValue === null) { - return undefined; - } else { return defaultValue; } diff --git a/src/driver/mysql/MysqlQueryRunner.ts b/src/driver/mysql/MysqlQueryRunner.ts index c4dce7894e..0ac8846f02 100644 --- a/src/driver/mysql/MysqlQueryRunner.ts +++ b/src/driver/mysql/MysqlQueryRunner.ts @@ -1529,7 +1529,7 @@ export class MysqlQueryRunner extends BaseQueryRunner implements QueryRunner { if (tableColumn.type === "enum" || tableColumn.type === "simple-enum" || tableColumn.type === "set") { const colType = dbColumn["COLUMN_TYPE"]; - const items = colType.substring(colType.indexOf("(") + 1, colType.indexOf(")")).split(","); + const items = colType.substring(colType.indexOf("(") + 1, colType.lastIndexOf(")")).split(","); tableColumn.enum = (items as string[]).map(item => { return item.substring(1, item.length - 1); }); @@ -1861,7 +1861,7 @@ export class MysqlQueryRunner extends BaseQueryRunner implements QueryRunner { const isMariaDb = this.driver.options.type === "mariadb"; if (isMariaDb && column.asExpression && (column.generatedType || "VIRTUAL") === "VIRTUAL") { // do nothing - MariaDB does not support NULL/NOT NULL expressions for VIRTUAL columns - } else { + } else { if (!column.isNullable) c += " NOT NULL"; if (column.isNullable) diff --git a/src/driver/postgres/PostgresDriver.ts b/src/driver/postgres/PostgresDriver.ts index 3b8475eecb..0400c18c01 100644 --- a/src/driver/postgres/PostgresDriver.ts +++ b/src/driver/postgres/PostgresDriver.ts @@ -306,7 +306,7 @@ export class PostgresDriver implements Driver { if (extensionsMetadata.hasExtensions) { await Promise.all([this.master, ...this.slaves].map(pool => { - return new Promise((ok, fail) => { + return new Promise((ok, fail) => { pool.connect(async (err: any, connection: any, release: Function) => { await this.enableExtensions(extensionsMetadata, connection); if (err) return fail(err); @@ -586,21 +586,30 @@ export class PostgresDriver implements Driver { } else if (columnMetadata.type === "enum" || columnMetadata.type === "simple-enum" ) { if (columnMetadata.isArray) { + if (value === "{}") return []; + // manually convert enum array to array of values (pg does not support, see https://github.com/brianc/node-pg-types/issues/56) - value = value !== "{}" ? (value as string).substr(1, (value as string).length - 2).split(",") : []; - // convert to number if that exists in poosible enum options + value = (value as string).substr(1, (value as string).length - 2).split(",").map(val => { + // replace double quotes from the beginning and from the end + if (val.startsWith(`"`) && val.endsWith(`"`)) val = val.slice(1, -1); + // replace double escaped backslash to single escaped e.g. \\\\ -> \\ + val = val.replace(/(\\\\)/g, "\\") + // replace escaped double quotes to non-escaped e.g. \"asd\" -> "asd" + return val.replace(/(\\")/g, '"') + }); + + // convert to number if that exists in possible enum options value = value.map((val: string) => { return !isNaN(+val) && columnMetadata.enum!.indexOf(parseInt(val)) >= 0 ? parseInt(val) : val; }); } else { - // convert to number if that exists in poosible enum options + // convert to number if that exists in possible enum options value = !isNaN(+value) && columnMetadata.enum!.indexOf(parseInt(value)) >= 0 ? parseInt(value) : value; } } if (columnMetadata.transformer) value = ApplyValueTransformers.transformFrom(columnMetadata.transformer, value); - return value; } @@ -719,23 +728,22 @@ export class PostgresDriver implements Driver { /** * Normalizes "default" value of the column. */ - normalizeDefault(columnMetadata: ColumnMetadata): string { + normalizeDefault(columnMetadata: ColumnMetadata): string | undefined { const defaultValue = columnMetadata.default; - const arrayCast = columnMetadata.isArray ? `::${columnMetadata.type}[]` : ""; - if ( - ( - columnMetadata.type === "enum" - || columnMetadata.type === "simple-enum" - ) && defaultValue !== undefined - ) { - if (columnMetadata.isArray && Array.isArray(defaultValue)) { - return `'{${defaultValue.map((val: string) => `${val}`).join(",")}}'`; - } - return `'${defaultValue}'`; - } + if (defaultValue === null) { + return undefined; - if (typeof defaultValue === "number") { + } else if (columnMetadata.isArray && Array.isArray(defaultValue)) { + return `'{${defaultValue.map((val: string) => `${val}`).join(",")}}'`; + + } else if ( + (columnMetadata.type === "enum" + || columnMetadata.type === "simple-enum" + || typeof defaultValue === "number" + || typeof defaultValue === "string") + && defaultValue !== undefined + ) { return `'${defaultValue}'`; } else if (typeof defaultValue === "boolean") { @@ -744,10 +752,7 @@ export class PostgresDriver implements Driver { } else if (typeof defaultValue === "function") { return defaultValue(); - } else if (typeof defaultValue === "string") { - return `'${defaultValue}'${arrayCast}`; - - } else if (typeof defaultValue === "object" && defaultValue !== null) { + } else if (typeof defaultValue === "object") { return `'${JSON.stringify(defaultValue)}'`; } else { @@ -872,6 +877,7 @@ export class PostgresDriver implements Driver { const isColumnChanged = tableColumn.name !== columnMetadata.databaseName || tableColumn.type !== this.normalizeType(columnMetadata) || tableColumn.length !== columnMetadata.length + || tableColumn.isArray !== columnMetadata.isArray || tableColumn.precision !== columnMetadata.precision || (columnMetadata.scale !== undefined && tableColumn.scale !== columnMetadata.scale) || tableColumn.comment !== columnMetadata.comment @@ -879,6 +885,7 @@ export class PostgresDriver implements Driver { || tableColumn.isPrimary !== columnMetadata.isPrimary || tableColumn.isNullable !== columnMetadata.isNullable || tableColumn.isUnique !== this.normalizeIsUnique(columnMetadata) + || tableColumn.enumName !== columnMetadata.enumName || (tableColumn.enum && columnMetadata.enum && !OrmUtils.isArraysEqual(tableColumn.enum, columnMetadata.enum.map(val => val + ""))) // enums in postgres are always strings || tableColumn.isGenerated !== columnMetadata.isGenerated || (tableColumn.spatialFeatureType || "").toLowerCase() !== (columnMetadata.spatialFeatureType || "").toLowerCase() @@ -890,9 +897,11 @@ export class PostgresDriver implements Driver { // console.log("name:", tableColumn.name, columnMetadata.databaseName); // console.log("type:", tableColumn.type, this.normalizeType(columnMetadata)); // console.log("length:", tableColumn.length, columnMetadata.length); + // console.log("isArray:", tableColumn.isArray, columnMetadata.isArray); // console.log("precision:", tableColumn.precision, columnMetadata.precision); // console.log("scale:", tableColumn.scale, columnMetadata.scale); // console.log("comment:", tableColumn.comment, columnMetadata.comment); + // console.log("enumName:", tableColumn.enumName, columnMetadata.enumName); // console.log("enum:", tableColumn.enum && columnMetadata.enum && !OrmUtils.isArraysEqual(tableColumn.enum, columnMetadata.enum.map(val => val + ""))); // console.log("onUpdate:", tableColumn.onUpdate, columnMetadata.onUpdate); // console.log("isPrimary:", tableColumn.isPrimary, columnMetadata.isPrimary); diff --git a/src/driver/postgres/PostgresQueryRunner.ts b/src/driver/postgres/PostgresQueryRunner.ts index 97b71789c0..d640ea2846 100644 --- a/src/driver/postgres/PostgresQueryRunner.ts +++ b/src/driver/postgres/PostgresQueryRunner.ts @@ -349,17 +349,20 @@ export class PostgresQueryRunner extends BaseQueryRunner implements QueryRunner const downQueries: Query[] = []; // if table have column with ENUM type, we must create this type in postgres. - await Promise.all(table.columns - .filter(column => column.type === "enum" || column.type === "simple-enum") - .map(async column => { - const hasEnum = await this.hasEnumType(table, column); - // TODO: Should also check if values of existing type matches expected ones - if (!hasEnum) { - upQueries.push(this.createEnumTypeSql(table, column)); - downQueries.push(this.dropEnumTypeSql(table, column)); - } - return Promise.resolve(); - })); + const enumColumns = table.columns.filter(column => column.type === "enum" || column.type === "simple-enum") + const createdEnumTypes: string[] = [] + for (const column of enumColumns) { + // TODO: Should also check if values of existing type matches expected ones + const hasEnum = await this.hasEnumType(table, column); + const enumName = this.buildEnumName(table, column) + + // if enum with the same "enumName" is defined more then once, me must prevent double creation + if (!hasEnum && createdEnumTypes.indexOf(enumName) === -1) { + createdEnumTypes.push(enumName) + upQueries.push(this.createEnumTypeSql(table, column, enumName)); + downQueries.push(this.dropEnumTypeSql(table, column, enumName)); + } + } upQueries.push(this.createTableSql(table, createForeignKeys)); downQueries.push(this.dropTableSql(table)); @@ -629,6 +632,7 @@ export class PostgresQueryRunner extends BaseQueryRunner implements QueryRunner let clonedTable = table.clone(); const upQueries: Query[] = []; const downQueries: Query[] = []; + let defaultValueChanged = false const oldColumn = oldTableColumnOrName instanceof TableColumn ? oldTableColumnOrName @@ -636,7 +640,7 @@ export class PostgresQueryRunner extends BaseQueryRunner implements QueryRunner if (!oldColumn) throw new Error(`Column "${oldTableColumnOrName}" was not found in the "${table.name}" table.`); - if (oldColumn.type !== newColumn.type || oldColumn.length !== newColumn.length) { + if (oldColumn.type !== newColumn.type || oldColumn.length !== newColumn.length || newColumn.isArray !== oldColumn.isArray) { // To avoid data conversion, we just recreate column await this.dropColumn(table, oldColumn); await this.addColumn(table, newColumn); @@ -753,45 +757,58 @@ export class PostgresQueryRunner extends BaseQueryRunner implements QueryRunner if ( (newColumn.type === "enum" || newColumn.type === "simple-enum") && (oldColumn.type === "enum" || oldColumn.type === "simple-enum") - && !OrmUtils.isArraysEqual(newColumn.enum!, oldColumn.enum!) + && (!OrmUtils.isArraysEqual(newColumn.enum!, oldColumn.enum!) || newColumn.enumName !== oldColumn.enumName) ) { - const enumName = this.buildEnumName(table, newColumn); const arraySuffix = newColumn.isArray ? "[]" : ""; - const oldEnumName = this.buildEnumName(table, newColumn, true, false, true); - const oldEnumNameWithoutSchema = this.buildEnumName(table, newColumn, false, false, true); - const enumTypeBeforeColumnChange = await this.getEnumTypeName(table, oldColumn); + + // "public"."new_enum" + const newEnumName = this.buildEnumName(table, newColumn); + + // "public"."old_enum" + const oldEnumName = this.buildEnumName(table, oldColumn); + + // "old_enum" + const oldEnumNameWithoutSchema = this.buildEnumName(table, oldColumn, false); + + //"public"."old_enum_old" + const oldEnumNameWithSchema_old = this.buildEnumName(table, oldColumn, true, false, true); + + //"old_enum_old" + const oldEnumNameWithoutSchema_old = this.buildEnumName(table, oldColumn, false, false, true); // rename old ENUM - upQueries.push(new Query(`ALTER TYPE "${enumTypeBeforeColumnChange.enumTypeSchema}"."${enumTypeBeforeColumnChange.enumTypeName}" RENAME TO ${oldEnumNameWithoutSchema}`)); - downQueries.push(new Query(`ALTER TYPE ${oldEnumName} RENAME TO "${enumTypeBeforeColumnChange.enumTypeName}"`)); + upQueries.push(new Query(`ALTER TYPE ${oldEnumName} RENAME TO ${oldEnumNameWithoutSchema_old}`)); + downQueries.push(new Query(`ALTER TYPE ${oldEnumNameWithSchema_old} RENAME TO ${oldEnumNameWithoutSchema}`)); // create new ENUM - upQueries.push(this.createEnumTypeSql(table, newColumn)); - downQueries.push(this.dropEnumTypeSql(table, oldColumn)); + upQueries.push(this.createEnumTypeSql(table, newColumn, newEnumName)); + downQueries.push(this.dropEnumTypeSql(table, newColumn, newEnumName)); // if column have default value, we must drop it to avoid issues with type casting - if (newColumn.default !== null && newColumn.default !== undefined) { - upQueries.push(new Query(`ALTER TABLE ${this.escapePath(table)} ALTER COLUMN "${newColumn.name}" DROP DEFAULT`)); - downQueries.push(new Query(`ALTER TABLE ${this.escapePath(table)} ALTER COLUMN "${newColumn.name}" SET DEFAULT ${newColumn.default}`)); + if (oldColumn.default !== null && oldColumn.default !== undefined) { + // mark default as changed to prevent double update + defaultValueChanged = true + upQueries.push(new Query(`ALTER TABLE ${this.escapePath(table)} ALTER COLUMN "${oldColumn.name}" DROP DEFAULT`)); + downQueries.push(new Query(`ALTER TABLE ${this.escapePath(table)} ALTER COLUMN "${oldColumn.name}" SET DEFAULT ${oldColumn.default}`)); } // build column types - const upType = `${enumName}${arraySuffix} USING "${newColumn.name}"::"text"::${enumName}${arraySuffix}`; - const downType = `${oldEnumName}${arraySuffix} USING "${newColumn.name}"::"text"::${oldEnumName}${arraySuffix}`; + const upType = `${newEnumName}${arraySuffix} USING "${newColumn.name}"::"text"::${newEnumName}${arraySuffix}`; + const downType = `${oldEnumNameWithSchema_old}${arraySuffix} USING "${newColumn.name}"::"text"::${oldEnumNameWithSchema_old}${arraySuffix}`; // update column to use new type upQueries.push(new Query(`ALTER TABLE ${this.escapePath(table)} ALTER COLUMN "${newColumn.name}" TYPE ${upType}`)); downQueries.push(new Query(`ALTER TABLE ${this.escapePath(table)} ALTER COLUMN "${newColumn.name}" TYPE ${downType}`)); - // if column have default value and we dropped it before, we must bring it back + // restore column default or create new one if (newColumn.default !== null && newColumn.default !== undefined) { upQueries.push(new Query(`ALTER TABLE ${this.escapePath(table)} ALTER COLUMN "${newColumn.name}" SET DEFAULT ${newColumn.default}`)); downQueries.push(new Query(`ALTER TABLE ${this.escapePath(table)} ALTER COLUMN "${newColumn.name}" DROP DEFAULT`)); } // remove old ENUM - upQueries.push(this.dropEnumTypeSql(table, newColumn, oldEnumName)); - downQueries.push(this.createEnumTypeSql(table, oldColumn, oldEnumName)); + upQueries.push(this.dropEnumTypeSql(table, oldColumn, oldEnumNameWithSchema_old)); + downQueries.push(this.createEnumTypeSql(table, oldColumn, oldEnumNameWithSchema_old)); } if (oldColumn.isNullable !== newColumn.isNullable) { @@ -885,7 +902,8 @@ export class PostgresQueryRunner extends BaseQueryRunner implements QueryRunner } } - if (newColumn.default !== oldColumn.default) { + // the default might have changed when the enum changed + if (newColumn.default !== oldColumn.default && !defaultValueChanged) { if (newColumn.default !== null && newColumn.default !== undefined) { upQueries.push(new Query(`ALTER TABLE ${this.escapePath(table)} ALTER COLUMN "${newColumn.name}" SET DEFAULT ${newColumn.default}`)); @@ -1567,11 +1585,17 @@ export class PostgresQueryRunner extends BaseQueryRunner implements QueryRunner } if (tableColumn.type.indexOf("enum") !== -1) { + // check if `enumName` is specified by user + const { enumTypeName } = await this.getEnumTypeName(table, tableColumn) + const builtEnumName = this.buildEnumName(table, tableColumn, false, true) + if (builtEnumName !== enumTypeName) + tableColumn.enumName = enumTypeName + tableColumn.type = "enum"; const sql = `SELECT "e"."enumlabel" AS "value" FROM "pg_enum" "e" ` + `INNER JOIN "pg_type" "t" ON "t"."oid" = "e"."enumtypid" ` + `INNER JOIN "pg_namespace" "n" ON "n"."oid" = "t"."typnamespace" ` + - `WHERE "n"."nspname" = '${dbTable["table_schema"]}' AND "t"."typname" = '${this.buildEnumName(table, tableColumn.name, false, true)}'`; + `WHERE "n"."nspname" = '${dbTable["table_schema"]}' AND "t"."typname" = '${this.buildEnumName(table, tableColumn, false, true)}'`; const results: ObjectLiteral[] = await this.query(sql); tableColumn.enum = results.map(result => result["value"]); } @@ -1938,8 +1962,7 @@ export class PostgresQueryRunner extends BaseQueryRunner implements QueryRunner * Builds create ENUM type sql. */ protected createEnumTypeSql(table: Table, column: TableColumn, enumName?: string): Query { - if (!enumName) - enumName = this.buildEnumName(table, column); + if (!enumName) enumName = this.buildEnumName(table, column); const enumValues = column.enum!.map(value => `'${value.replace("'", "''")}'`).join(", "); return new Query(`CREATE TYPE ${enumName} AS ENUM(${enumValues})`); } @@ -1948,8 +1971,7 @@ export class PostgresQueryRunner extends BaseQueryRunner implements QueryRunner * Builds create ENUM type sql. */ protected dropEnumTypeSql(table: Table, column: TableColumn, enumName?: string): Query { - if (!enumName) - enumName = this.buildEnumName(table, column); + if (!enumName) enumName = this.buildEnumName(table, column); return new Query(`DROP TYPE ${enumName}`); } @@ -2089,20 +2111,12 @@ export class PostgresQueryRunner extends BaseQueryRunner implements QueryRunner /** * Builds ENUM type name from given table and column. */ - protected buildEnumName(table: Table, columnOrName: TableColumn|string, withSchema: boolean = true, disableEscape?: boolean, toOld?: boolean): string { - /** - * If enumName is specified in column options then use it instead - */ - if (columnOrName instanceof TableColumn && columnOrName.enumName) { - let enumName = columnOrName.enumName; - if (toOld) - enumName = enumName + "_old"; - return disableEscape ? enumName : `"${enumName}"`; - } - const columnName = columnOrName instanceof TableColumn ? columnOrName.name : columnOrName; + protected buildEnumName(table: Table, column: TableColumn, withSchema: boolean = true, disableEscape?: boolean, toOld?: boolean): string { const schema = table.name.indexOf(".") === -1 ? this.driver.options.schema : table.name.split(".")[0]; const tableName = table.name.indexOf(".") === -1 ? table.name : table.name.split(".")[1]; - let enumName = schema && withSchema ? `${schema}.${tableName}_${columnName.toLowerCase()}_enum` : `${tableName}_${columnName.toLowerCase()}_enum`; + let enumName = column.enumName ? column.enumName : `${tableName}_${column.name.toLowerCase()}_enum`; + if (schema && withSchema) + enumName = `${schema}.${enumName}` if (toOld) enumName = enumName + "_old"; return enumName.split(".").map(i => { @@ -2120,9 +2134,19 @@ export class PostgresQueryRunner extends BaseQueryRunner implements QueryRunner } const result = await this.query(`SELECT "udt_schema", "udt_name" ` + `FROM "information_schema"."columns" WHERE "table_schema" = '${schema}' AND "table_name" = '${name}' AND "column_name"='${column.name}'`); + + // docs: https://www.postgresql.org/docs/current/xtypes.html + // When you define a new base type, PostgreSQL automatically provides support for arrays of that type. + // The array type typically has the same name as the base type with the underscore character (_) prepended. + // ---- + // so, we must remove this underscore character from enum type name + let udtName = result[0]["udt_name"] + if (udtName.indexOf("_") === 0) { + udtName = udtName.substr(1, udtName.length) + } return { enumTypeSchema: result[0]["udt_schema"], - enumTypeName: result[0]["udt_name"] + enumTypeName: udtName }; } diff --git a/src/driver/sqlite-abstract/AbstractSqliteDriver.ts b/src/driver/sqlite-abstract/AbstractSqliteDriver.ts index f76dd030fb..ca66771739 100644 --- a/src/driver/sqlite-abstract/AbstractSqliteDriver.ts +++ b/src/driver/sqlite-abstract/AbstractSqliteDriver.ts @@ -565,7 +565,7 @@ export abstract class AbstractSqliteDriver implements Driver { // console.log("precision:", tableColumn.precision, columnMetadata.precision); // console.log("scale:", tableColumn.scale, columnMetadata.scale); // console.log("comment:", tableColumn.comment, columnMetadata.comment); - // console.log("default:", tableColumn.default, columnMetadata.default); + // console.log("default:", this.normalizeDefault(columnMetadata), columnMetadata.default); // console.log("isPrimary:", tableColumn.isPrimary, columnMetadata.isPrimary); // console.log("isNullable:", tableColumn.isNullable, columnMetadata.isNullable); // console.log("isUnique:", tableColumn.isUnique, this.normalizeIsUnique(columnMetadata)); diff --git a/src/driver/sqlite-abstract/AbstractSqliteQueryRunner.ts b/src/driver/sqlite-abstract/AbstractSqliteQueryRunner.ts index ce9eb95796..23260532dc 100644 --- a/src/driver/sqlite-abstract/AbstractSqliteQueryRunner.ts +++ b/src/driver/sqlite-abstract/AbstractSqliteQueryRunner.ts @@ -846,7 +846,6 @@ export abstract class AbstractSqliteQueryRunner extends BaseQueryRunner implemen const enumMatch = sql.match(new RegExp("\"(" + tableColumn.name + ")\" varchar CHECK\\s*\\(\\s*\\1\\s+IN\\s*\\(('[^']+'(?:\\s*,\\s*'[^']+')+)\\s*\\)\\s*\\)")); if (enumMatch) { // This is an enum - tableColumn.type = "simple-enum"; tableColumn.enum = enumMatch[2].substr(1, enumMatch[2].length - 2).split("','"); } } diff --git a/src/driver/sqlserver/SqlServerDriver.ts b/src/driver/sqlserver/SqlServerDriver.ts index a36ee5b4e1..e4ea1b3982 100644 --- a/src/driver/sqlserver/SqlServerDriver.ts +++ b/src/driver/sqlserver/SqlServerDriver.ts @@ -602,20 +602,38 @@ export class SqlServerDriver implements Driver { if (!tableColumn) return false; // we don't need new columns, we only need exist and changed - return tableColumn.name !== columnMetadata.databaseName + const isColumnChanged = tableColumn.name !== columnMetadata.databaseName || tableColumn.type !== this.normalizeType(columnMetadata) || tableColumn.length !== columnMetadata.length || tableColumn.precision !== columnMetadata.precision || tableColumn.scale !== columnMetadata.scale // || tableColumn.comment !== columnMetadata.comment || // todo - || (!tableColumn.isGenerated && this.lowerDefaultValueIfNessesary(this.normalizeDefault(columnMetadata)) !== this.lowerDefaultValueIfNessesary(tableColumn.default)) // we included check for generated here, because generated columns already can have default values + || tableColumn.isGenerated !== columnMetadata.isGenerated + || (!tableColumn.isGenerated && this.lowerDefaultValueIfNecessary(this.normalizeDefault(columnMetadata)) !== this.lowerDefaultValueIfNecessary(tableColumn.default)) // we included check for generated here, because generated columns already can have default values || tableColumn.isPrimary !== columnMetadata.isPrimary || tableColumn.isNullable !== columnMetadata.isNullable - || tableColumn.isUnique !== this.normalizeIsUnique(columnMetadata) - || tableColumn.isGenerated !== columnMetadata.isGenerated; + || tableColumn.isUnique !== this.normalizeIsUnique(columnMetadata); + + // DEBUG SECTION + // if (isColumnChanged) { + // console.log("table:", columnMetadata.entityMetadata.tableName); + // console.log("name:", tableColumn.name, columnMetadata.databaseName); + // console.log("type:", tableColumn.type, this.normalizeType(columnMetadata)); + // console.log("length:", tableColumn.length, columnMetadata.length); + // console.log("precision:", tableColumn.precision, columnMetadata.precision); + // console.log("scale:", tableColumn.scale, columnMetadata.scale); + // console.log("isGenerated:", tableColumn.isGenerated, columnMetadata.isGenerated); + // console.log("isGenerated 2:", !tableColumn.isGenerated && this.lowerDefaultValueIfNecessary(this.normalizeDefault(columnMetadata)) !== this.lowerDefaultValueIfNecessary(tableColumn.default)); + // console.log("isPrimary:", tableColumn.isPrimary, columnMetadata.isPrimary); + // console.log("isNullable:", tableColumn.isNullable, columnMetadata.isNullable); + // console.log("isUnique:", tableColumn.isUnique, this.normalizeIsUnique(columnMetadata)); + // console.log("=========================================="); + // } + + return isColumnChanged }); } - private lowerDefaultValueIfNessesary(value: string | undefined) { + private lowerDefaultValueIfNecessary(value: string | undefined) { // SqlServer saves function calls in default value as lowercase https://github.com/typeorm/typeorm/issues/2733 if (!value) { return value; diff --git a/src/driver/sqlserver/SqlServerQueryRunner.ts b/src/driver/sqlserver/SqlServerQueryRunner.ts index 2e6a7d11aa..e5a70093c1 100644 --- a/src/driver/sqlserver/SqlServerQueryRunner.ts +++ b/src/driver/sqlserver/SqlServerQueryRunner.ts @@ -1710,11 +1710,10 @@ export class SqlServerQueryRunner extends BaseQueryRunner implements QueryRunner // Check if this is an enum const columnCheckConstraints = columnConstraints.filter(constraint => constraint["CONSTRAINT_TYPE"] === "CHECK"); if (columnCheckConstraints.length) { - const isEnumRegexp = new RegExp("^\\(\\[" + tableColumn.name + "\\]='[^']+'(?: OR \\[" + tableColumn.name + "\\]='[^']+')*\\)$"); + // const isEnumRegexp = new RegExp("^\\(\\[" + tableColumn.name + "\\]='[^']+'(?: OR \\[" + tableColumn.name + "\\]='[^']+')*\\)$"); for (const checkConstraint of columnCheckConstraints) { - if (isEnumRegexp.test(checkConstraint["definition"])) { + if (this.isEnumCheckConstraint(checkConstraint["CONSTRAINT_NAME"])) { // This is an enum constraint, make column into an enum - tableColumn.type = "simple-enum"; tableColumn.enum = []; const enumValueRegexp = new RegExp("\\[" + tableColumn.name + "\\]='([^']+)'", "g"); let result; @@ -1775,13 +1774,15 @@ export class SqlServerQueryRunner extends BaseQueryRunner implements QueryRunner && dbConstraint["CONSTRAINT_TYPE"] === "CHECK"; }), dbConstraint => dbConstraint["CONSTRAINT_NAME"]); - table.checks = tableCheckConstraints.map(constraint => { - const checks = dbConstraints.filter(dbC => dbC["CONSTRAINT_NAME"] === constraint["CONSTRAINT_NAME"]); - return new TableCheck({ - name: constraint["CONSTRAINT_NAME"], - columnNames: checks.map(c => c["COLUMN_NAME"]), - expression: constraint["definition"] - }); + table.checks = tableCheckConstraints + .filter(constraint => !this.isEnumCheckConstraint(constraint["CONSTRAINT_NAME"])) + .map(constraint => { + const checks = dbConstraints.filter(dbC => dbC["CONSTRAINT_NAME"] === constraint["CONSTRAINT_NAME"]); + return new TableCheck({ + name: constraint["CONSTRAINT_NAME"], + columnNames: checks.map(c => c["COLUMN_NAME"]), + expression: constraint["definition"] + }); }); // find foreign key constraints of table, group them by constraint name and build TableForeignKey. @@ -2125,8 +2126,11 @@ export class SqlServerQueryRunner extends BaseQueryRunner implements QueryRunner protected buildCreateColumnSql(table: Table, column: TableColumn, skipIdentity: boolean, createDefault: boolean) { let c = `"${column.name}" ${this.connection.driver.createFullType(column)}`; - if (column.enum) - c += " CHECK( " + column.name + " IN (" + column.enum.map(val => "'" + val + "'").join(",") + ") )"; + if (column.enum) { + const expression = column.name + " IN (" + column.enum.map(val => "'" + val + "'").join(",") + ")"; + const checkName = this.connection.namingStrategy.checkConstraintName(table, expression, true) + c += ` CONSTRAINT ${checkName} CHECK(${expression})`; + } if (column.collation) c += " COLLATE " + column.collation; @@ -2151,6 +2155,10 @@ export class SqlServerQueryRunner extends BaseQueryRunner implements QueryRunner return c; } + protected isEnumCheckConstraint(name: string): boolean { + return name.indexOf("CHK_") !== -1 && name.indexOf("_ENUM") !== -1 + } + /** * Converts MssqlParameter into real mssql parameter type. */ diff --git a/src/entity-manager/EntityManager.ts b/src/entity-manager/EntityManager.ts index cc5616b48a..18216930b6 100644 --- a/src/entity-manager/EntityManager.ts +++ b/src/entity-manager/EntityManager.ts @@ -291,13 +291,25 @@ export class EntityManager { * Saves all given entities in the database. * If entities do not exist in the database then inserts, otherwise updates. */ - save>(targetOrEntity: EntityTarget, entities: T[], options?: SaveOptions): Promise; + save>(targetOrEntity: EntityTarget, entities: T[], options: SaveOptions & { reload: false }): Promise; /** * Saves all given entities in the database. * If entities do not exist in the database then inserts, otherwise updates. */ - save>(targetOrEntity: EntityTarget, entity: T, options?: SaveOptions): Promise; + save>(targetOrEntity: EntityTarget, entities: T[], options?: SaveOptions): Promise<(T & Entity)[]>; + + /** + * Saves a given entity in the database. + * If entity does not exist in the database then inserts, otherwise updates. + */ + save>(targetOrEntity: EntityTarget, entity: T, options: SaveOptions & { reload: false }): Promise; + + /** + * Saves a given entity in the database. + * If entity does not exist in the database then inserts, otherwise updates. + */ + save>(targetOrEntity: EntityTarget, entity: T, options?: SaveOptions): Promise; /** * Saves a given entity in the database. diff --git a/src/entity-manager/MongoEntityManager.ts b/src/entity-manager/MongoEntityManager.ts index fec1d5a2e7..a23be20b33 100644 --- a/src/entity-manager/MongoEntityManager.ts +++ b/src/entity-manager/MongoEntityManager.ts @@ -62,6 +62,10 @@ import { BroadcasterResult } from "../subscriber/BroadcasterResult"; */ export class MongoEntityManager extends EntityManager { + get mongoQueryRunner(): MongoQueryRunner { + return (this.connection.driver as MongoDriver).queryRunner as MongoQueryRunner; + } + // ------------------------------------------------------------------------- // Constructor // ------------------------------------------------------------------------- @@ -70,17 +74,6 @@ export class MongoEntityManager extends EntityManager { super(connection); } - // ------------------------------------------------------------------------- - // Overridden Properties - // ------------------------------------------------------------------------- - - /** - * Gets query runner used to execute queries. - */ - get queryRunner(): MongoQueryRunner { - return (this.connection.driver as MongoDriver).queryRunner!; - } - // ------------------------------------------------------------------------- // Overridden Methods // ------------------------------------------------------------------------- @@ -262,7 +255,7 @@ export class MongoEntityManager extends EntityManager { */ createCursor(entityClassOrName: EntityTarget, query?: ObjectLiteral): Cursor { const metadata = this.connection.getMetadata(entityClassOrName); - return this.queryRunner.cursor(metadata.tableName, query); + return this.mongoQueryRunner.cursor(metadata.tableName, query); } /** @@ -281,7 +274,7 @@ export class MongoEntityManager extends EntityManager { */ aggregate(entityClassOrName: EntityTarget, pipeline: ObjectLiteral[], options?: CollectionAggregationOptions): AggregationCursor { const metadata = this.connection.getMetadata(entityClassOrName); - return this.queryRunner.aggregate(metadata.tableName, pipeline, options); + return this.mongoQueryRunner.aggregate(metadata.tableName, pipeline, options); } /** @@ -290,7 +283,7 @@ export class MongoEntityManager extends EntityManager { */ aggregateEntity(entityClassOrName: EntityTarget, pipeline: ObjectLiteral[], options?: CollectionAggregationOptions): AggregationCursor { const metadata = this.connection.getMetadata(entityClassOrName); - const cursor = this.queryRunner.aggregate(metadata.tableName, pipeline, options); + const cursor = this.mongoQueryRunner.aggregate(metadata.tableName, pipeline, options); this.applyEntityTransformationToCursor(metadata, cursor); return cursor; } @@ -300,7 +293,7 @@ export class MongoEntityManager extends EntityManager { */ bulkWrite(entityClassOrName: EntityTarget, operations: ObjectLiteral[], options?: CollectionBulkWriteOptions): Promise { const metadata = this.connection.getMetadata(entityClassOrName); - return this.queryRunner.bulkWrite(metadata.tableName, operations, options); + return this.mongoQueryRunner.bulkWrite(metadata.tableName, operations, options); } /** @@ -308,7 +301,7 @@ export class MongoEntityManager extends EntityManager { */ count(entityClassOrName: EntityTarget, query?: ObjectLiteral, options?: MongoCountPreferences): Promise { const metadata = this.connection.getMetadata(entityClassOrName); - return this.queryRunner.count(metadata.tableName, query, options); + return this.mongoQueryRunner.count(metadata.tableName, query, options); } /** @@ -316,7 +309,7 @@ export class MongoEntityManager extends EntityManager { */ createCollectionIndex(entityClassOrName: EntityTarget, fieldOrSpec: string | any, options?: MongodbIndexOptions): Promise { const metadata = this.connection.getMetadata(entityClassOrName); - return this.queryRunner.createCollectionIndex(metadata.tableName, fieldOrSpec, options); + return this.mongoQueryRunner.createCollectionIndex(metadata.tableName, fieldOrSpec, options); } /** @@ -326,7 +319,7 @@ export class MongoEntityManager extends EntityManager { */ createCollectionIndexes(entityClassOrName: EntityTarget, indexSpecs: ObjectLiteral[]): Promise { const metadata = this.connection.getMetadata(entityClassOrName); - return this.queryRunner.createCollectionIndexes(metadata.tableName, indexSpecs); + return this.mongoQueryRunner.createCollectionIndexes(metadata.tableName, indexSpecs); } /** @@ -334,7 +327,7 @@ export class MongoEntityManager extends EntityManager { */ deleteMany(entityClassOrName: EntityTarget, query: ObjectLiteral, options?: CollectionOptions): Promise { const metadata = this.connection.getMetadata(entityClassOrName); - return this.queryRunner.deleteMany(metadata.tableName, query, options); + return this.mongoQueryRunner.deleteMany(metadata.tableName, query, options); } /** @@ -342,7 +335,7 @@ export class MongoEntityManager extends EntityManager { */ deleteOne(entityClassOrName: EntityTarget, query: ObjectLiteral, options?: CollectionOptions): Promise { const metadata = this.connection.getMetadata(entityClassOrName); - return this.queryRunner.deleteOne(metadata.tableName, query, options); + return this.mongoQueryRunner.deleteOne(metadata.tableName, query, options); } /** @@ -350,7 +343,7 @@ export class MongoEntityManager extends EntityManager { */ 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); + return this.mongoQueryRunner.distinct(metadata.tableName, key, query, options); } /** @@ -358,7 +351,7 @@ export class MongoEntityManager extends EntityManager { */ dropCollectionIndex(entityClassOrName: EntityTarget, indexName: string, options?: CollectionOptions): Promise { const metadata = this.connection.getMetadata(entityClassOrName); - return this.queryRunner.dropCollectionIndex(metadata.tableName, indexName, options); + return this.mongoQueryRunner.dropCollectionIndex(metadata.tableName, indexName, options); } /** @@ -366,7 +359,7 @@ export class MongoEntityManager extends EntityManager { */ dropCollectionIndexes(entityClassOrName: EntityTarget): Promise { const metadata = this.connection.getMetadata(entityClassOrName); - return this.queryRunner.dropCollectionIndexes(metadata.tableName); + return this.mongoQueryRunner.dropCollectionIndexes(metadata.tableName); } /** @@ -374,7 +367,7 @@ export class MongoEntityManager extends EntityManager { */ 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); + return this.mongoQueryRunner.findOneAndDelete(metadata.tableName, query, options); } /** @@ -382,7 +375,7 @@ export class MongoEntityManager extends EntityManager { */ 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); + return this.mongoQueryRunner.findOneAndReplace(metadata.tableName, query, replacement, options); } /** @@ -390,7 +383,7 @@ export class MongoEntityManager extends EntityManager { */ 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); + return this.mongoQueryRunner.findOneAndUpdate(metadata.tableName, query, update, options); } /** @@ -398,7 +391,7 @@ export class MongoEntityManager extends EntityManager { */ 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); + return this.mongoQueryRunner.geoHaystackSearch(metadata.tableName, x, y, options); } /** @@ -406,7 +399,7 @@ export class MongoEntityManager extends EntityManager { */ 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); + return this.mongoQueryRunner.geoNear(metadata.tableName, x, y, options); } /** @@ -414,7 +407,7 @@ export class MongoEntityManager extends EntityManager { */ 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); + return this.mongoQueryRunner.group(metadata.tableName, keys, condition, initial, reduce, finalize, command, options); } /** @@ -422,7 +415,7 @@ export class MongoEntityManager extends EntityManager { */ collectionIndexes(entityClassOrName: EntityTarget): Promise { const metadata = this.connection.getMetadata(entityClassOrName); - return this.queryRunner.collectionIndexes(metadata.tableName); + return this.mongoQueryRunner.collectionIndexes(metadata.tableName); } /** @@ -430,7 +423,7 @@ export class MongoEntityManager extends EntityManager { */ collectionIndexExists(entityClassOrName: EntityTarget, indexes: string | string[]): Promise { const metadata = this.connection.getMetadata(entityClassOrName); - return this.queryRunner.collectionIndexExists(metadata.tableName, indexes); + return this.mongoQueryRunner.collectionIndexExists(metadata.tableName, indexes); } /** @@ -438,7 +431,7 @@ export class MongoEntityManager extends EntityManager { */ collectionIndexInformation(entityClassOrName: EntityTarget, options?: { full: boolean }): Promise { const metadata = this.connection.getMetadata(entityClassOrName); - return this.queryRunner.collectionIndexInformation(metadata.tableName, options); + return this.mongoQueryRunner.collectionIndexInformation(metadata.tableName, options); } /** @@ -446,7 +439,7 @@ export class MongoEntityManager extends EntityManager { */ initializeOrderedBulkOp(entityClassOrName: EntityTarget, options?: CollectionOptions): OrderedBulkOperation { const metadata = this.connection.getMetadata(entityClassOrName); - return this.queryRunner.initializeOrderedBulkOp(metadata.tableName, options); + return this.mongoQueryRunner.initializeOrderedBulkOp(metadata.tableName, options); } /** @@ -454,7 +447,7 @@ export class MongoEntityManager extends EntityManager { */ initializeUnorderedBulkOp(entityClassOrName: EntityTarget, options?: CollectionOptions): UnorderedBulkOperation { const metadata = this.connection.getMetadata(entityClassOrName); - return this.queryRunner.initializeUnorderedBulkOp(metadata.tableName, options); + return this.mongoQueryRunner.initializeUnorderedBulkOp(metadata.tableName, options); } /** @@ -462,7 +455,7 @@ export class MongoEntityManager extends EntityManager { */ insertMany(entityClassOrName: EntityTarget, docs: ObjectLiteral[], options?: CollectionInsertManyOptions): Promise { const metadata = this.connection.getMetadata(entityClassOrName); - return this.queryRunner.insertMany(metadata.tableName, docs, options); + return this.mongoQueryRunner.insertMany(metadata.tableName, docs, options); } /** @@ -470,7 +463,7 @@ export class MongoEntityManager extends EntityManager { */ insertOne(entityClassOrName: EntityTarget, doc: ObjectLiteral, options?: CollectionInsertOneOptions): Promise { const metadata = this.connection.getMetadata(entityClassOrName); - return this.queryRunner.insertOne(metadata.tableName, doc, options); + return this.mongoQueryRunner.insertOne(metadata.tableName, doc, options); } /** @@ -478,7 +471,7 @@ export class MongoEntityManager extends EntityManager { */ isCapped(entityClassOrName: EntityTarget): Promise { const metadata = this.connection.getMetadata(entityClassOrName); - return this.queryRunner.isCapped(metadata.tableName); + return this.mongoQueryRunner.isCapped(metadata.tableName); } /** @@ -486,7 +479,7 @@ export class MongoEntityManager extends EntityManager { */ listCollectionIndexes(entityClassOrName: EntityTarget, options?: { batchSize?: number, readPreference?: ReadPreference | string }): CommandCursor { const metadata = this.connection.getMetadata(entityClassOrName); - return this.queryRunner.listCollectionIndexes(metadata.tableName, options); + return this.mongoQueryRunner.listCollectionIndexes(metadata.tableName, options); } /** @@ -494,7 +487,7 @@ export class MongoEntityManager extends EntityManager { */ 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); + return this.mongoQueryRunner.mapReduce(metadata.tableName, map, reduce, options); } /** @@ -503,7 +496,7 @@ export class MongoEntityManager extends EntityManager { */ parallelCollectionScan(entityClassOrName: EntityTarget, options?: ParallelCollectionScanOptions): Promise[]> { const metadata = this.connection.getMetadata(entityClassOrName); - return this.queryRunner.parallelCollectionScan(metadata.tableName, options); + return this.mongoQueryRunner.parallelCollectionScan(metadata.tableName, options); } /** @@ -511,7 +504,7 @@ export class MongoEntityManager extends EntityManager { */ reIndex(entityClassOrName: EntityTarget): Promise { const metadata = this.connection.getMetadata(entityClassOrName); - return this.queryRunner.reIndex(metadata.tableName); + return this.mongoQueryRunner.reIndex(metadata.tableName); } /** @@ -519,7 +512,7 @@ export class MongoEntityManager extends EntityManager { */ rename(entityClassOrName: EntityTarget, newName: string, options?: { dropTarget?: boolean }): Promise> { const metadata = this.connection.getMetadata(entityClassOrName); - return this.queryRunner.rename(metadata.tableName, newName, options); + return this.mongoQueryRunner.rename(metadata.tableName, newName, options); } /** @@ -527,7 +520,7 @@ export class MongoEntityManager extends EntityManager { */ 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); + return this.mongoQueryRunner.replaceOne(metadata.tableName, query, doc, options); } /** @@ -535,12 +528,12 @@ export class MongoEntityManager extends EntityManager { */ stats(entityClassOrName: EntityTarget, options?: { scale: number }): Promise { const metadata = this.connection.getMetadata(entityClassOrName); - return this.queryRunner.stats(metadata.tableName, options); + return this.mongoQueryRunner.stats(metadata.tableName, options); } watch(entityClassOrName: EntityTarget, pipeline?: Object[], options?: ChangeStreamOptions): ChangeStream { const metadata = this.connection.getMetadata(entityClassOrName); - return this.queryRunner.watch(metadata.tableName, pipeline, options); + return this.mongoQueryRunner.watch(metadata.tableName, pipeline, options); } /** @@ -548,7 +541,7 @@ export class MongoEntityManager extends EntityManager { */ 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); + return this.mongoQueryRunner.updateMany(metadata.tableName, query, update, options); } /** @@ -556,7 +549,7 @@ export class MongoEntityManager extends EntityManager { */ 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); + return this.mongoQueryRunner.updateOne(metadata.tableName, query, update, options); } // ------------------------------------------------------------------------- @@ -664,7 +657,7 @@ export class MongoEntityManager extends EntityManager { */ protected applyEntityTransformationToCursor(metadata: EntityMetadata, cursor: Cursor | AggregationCursor) { const ParentCursor = PlatformTools.load("mongodb").Cursor; - const queryRunner = this.queryRunner; + const queryRunner = this.mongoQueryRunner; cursor.toArray = function (callback?: MongoCallback) { if (callback) { ParentCursor.prototype.toArray.call(this, (error: MongoError, results: Entity[]): void => { diff --git a/src/metadata-builder/EntityMetadataBuilder.ts b/src/metadata-builder/EntityMetadataBuilder.ts index 24c164bcdc..79de051f34 100644 --- a/src/metadata-builder/EntityMetadataBuilder.ts +++ b/src/metadata-builder/EntityMetadataBuilder.ts @@ -666,7 +666,7 @@ export class EntityMetadataBuilder { entityMetadata.relations.forEach(relation => { // compute inverse side (related) entity metadatas for all relation metadatas - const inverseEntityMetadata = entityMetadatas.find(m => m.target === relation.type || (typeof relation.type === "string" && m.targetName === relation.type)); + const inverseEntityMetadata = entityMetadatas.find(m => m.target === relation.type || (typeof relation.type === "string" && (m.targetName === relation.type || m.givenTableName === relation.type))); if (!inverseEntityMetadata) throw new Error("Entity metadata for " + entityMetadata.name + "#" + relation.propertyPath + " was not found. Check if you specified a correct entity object and if it's connected in the connection options."); diff --git a/src/metadata-builder/EntityMetadataValidator.ts b/src/metadata-builder/EntityMetadataValidator.ts index 9e3fe488d5..ef4c7d693c 100644 --- a/src/metadata-builder/EntityMetadataValidator.ts +++ b/src/metadata-builder/EntityMetadataValidator.ts @@ -87,6 +87,8 @@ export class EntityMetadataValidator { throw new DataTypeNotSupportedError(column, normalizedColumn, driver.options.type); if (column.length && driver.withLengthColumnTypes.indexOf(normalizedColumn) === -1) throw new Error(`Column ${column.propertyName} of Entity ${entityMetadata.name} does not support length property.`); + if (column.type === "enum" && !column.enum && !column.enumName) + throw new Error(`Column "${column.propertyName}" of Entity "${entityMetadata.name}" is defined as enum, but missing "enum" or "enumName" properties.`); }); } diff --git a/src/metadata-builder/JunctionEntityMetadataBuilder.ts b/src/metadata-builder/JunctionEntityMetadataBuilder.ts index 961a861734..e0c229b6c9 100644 --- a/src/metadata-builder/JunctionEntityMetadataBuilder.ts +++ b/src/metadata-builder/JunctionEntityMetadataBuilder.ts @@ -83,6 +83,8 @@ export class JunctionEntityMetadataBuilder { collation: referencedColumn.collation, zerofill: referencedColumn.zerofill, unsigned: referencedColumn.zerofill ? true : referencedColumn.unsigned, + enum: referencedColumn.enum, + enumName: referencedColumn.enumName, nullable: false, primary: true, } @@ -121,6 +123,8 @@ export class JunctionEntityMetadataBuilder { collation: inverseReferencedColumn.collation, zerofill: inverseReferencedColumn.zerofill, unsigned: inverseReferencedColumn.zerofill ? true : inverseReferencedColumn.unsigned, + enum: inverseReferencedColumn.enum, + enumName: inverseReferencedColumn.enumName, name: columnName, nullable: false, primary: true, diff --git a/src/metadata-builder/RelationJoinColumnBuilder.ts b/src/metadata-builder/RelationJoinColumnBuilder.ts index 7cdc354880..22c3f7b0ba 100644 --- a/src/metadata-builder/RelationJoinColumnBuilder.ts +++ b/src/metadata-builder/RelationJoinColumnBuilder.ts @@ -159,8 +159,10 @@ export class RelationJoinColumnBuilder { zerofill: referencedColumn.zerofill, unsigned: referencedColumn.unsigned, comment: referencedColumn.comment, + enum: referencedColumn.enum, + enumName: referencedColumn.enumName, primary: relation.isPrimary, - nullable: relation.isNullable + nullable: relation.isNullable, } } }); diff --git a/src/metadata/ColumnMetadata.ts b/src/metadata/ColumnMetadata.ts index 42447ad7ec..a2631768e1 100644 --- a/src/metadata/ColumnMetadata.ts +++ b/src/metadata/ColumnMetadata.ts @@ -544,9 +544,9 @@ export class ColumnMetadata { return Object.keys(map).length > 0 ? map : undefined; } else { // no embeds - no problems. Simply return column property name and its value of the entity - if (this.relationMetadata && entity[this.propertyName] && entity[this.propertyName] instanceof Object) { + if (this.relationMetadata && entity[this.relationMetadata.propertyName] && entity[this.relationMetadata.propertyName] instanceof Object) { const map = this.relationMetadata.joinColumns.reduce((map, joinColumn) => { - const value = joinColumn.referencedColumn!.getEntityValueMap(entity[this.propertyName]); + const value = joinColumn.referencedColumn!.getEntityValueMap(entity[this.relationMetadata!.propertyName]); if (value === undefined) return map; return OrmUtils.mergeDeep(map, value); }, {}); diff --git a/src/naming-strategy/DefaultNamingStrategy.ts b/src/naming-strategy/DefaultNamingStrategy.ts index e34dd792a7..f67e44b0d0 100644 --- a/src/naming-strategy/DefaultNamingStrategy.ts +++ b/src/naming-strategy/DefaultNamingStrategy.ts @@ -29,7 +29,7 @@ export class DefaultNamingStrategy implements NamingStrategyInterface { columnName(propertyName: string, customName: string, embeddedPrefixes: string[]): string { const name = customName || propertyName; - + if (embeddedPrefixes.length) return camelCase(embeddedPrefixes.join("_")) + titleCase(name); @@ -103,11 +103,12 @@ export class DefaultNamingStrategy implements NamingStrategyInterface { return "IDX_" + RandomGenerator.sha1(key).substr(0, 26); } - checkConstraintName(tableOrName: Table|string, expression: string): string { + checkConstraintName(tableOrName: Table|string, expression: string, isEnum?: boolean): string { const tableName = tableOrName instanceof Table ? tableOrName.name : tableOrName; const replacedTableName = tableName.replace(".", "_"); const key = `${replacedTableName}_${expression}`; - return "CHK_" + RandomGenerator.sha1(key).substr(0, 26); + const name = "CHK_" + RandomGenerator.sha1(key).substr(0, 26); + return isEnum ? `${name}_ENUM` : name; } exclusionConstraintName(tableOrName: Table|string, expression: string): string { diff --git a/src/naming-strategy/NamingStrategyInterface.ts b/src/naming-strategy/NamingStrategyInterface.ts index 50342d32b1..c4988a6d92 100644 --- a/src/naming-strategy/NamingStrategyInterface.ts +++ b/src/naming-strategy/NamingStrategyInterface.ts @@ -69,8 +69,13 @@ export interface NamingStrategyInterface { /** * Gets the name of the check constraint. + * + * "isEnum" parameter is used to indicate if this check constraint used + * to handle "simple-enum" type for databases that are not supporting "enum" + * type out of the box. If "true", constraint is ignored during CHECK constraints + * synchronization. */ - checkConstraintName(tableOrName: Table|string, expression: string): string; + checkConstraintName(tableOrName: Table|string, expression: string, isEnum?: boolean): string; /** * Gets the name of the exclusion constraint. diff --git a/src/query-builder/relation-id/RelationIdLoader.ts b/src/query-builder/relation-id/RelationIdLoader.ts index f4a3f42e3c..5f06d27e49 100644 --- a/src/query-builder/relation-id/RelationIdLoader.ts +++ b/src/query-builder/relation-id/RelationIdLoader.ts @@ -32,17 +32,34 @@ export class RelationIdLoader { if (relationIdAttr.queryBuilderFactory) throw new Error("Additional condition can not be used with ManyToOne or OneToOne owner relations."); + const duplicates: Array = []; const results = rawEntities.map(rawEntity => { const result: ObjectLiteral = {}; + const duplicateParts: Array = []; relationIdAttr.relation.joinColumns.forEach(joinColumn => { result[joinColumn.databaseName] = this.connection.driver.prepareHydratedValue(rawEntity[DriverUtils.buildColumnAlias(this.connection.driver, relationIdAttr.parentAlias, joinColumn.databaseName)], joinColumn.referencedColumn!); + const duplicatePart = `${joinColumn.databaseName}:${result[joinColumn.databaseName]}`; + if (duplicateParts.indexOf(duplicatePart) === -1) { + duplicateParts.push(duplicatePart); + } }); relationIdAttr.relation.entityMetadata.primaryColumns.forEach(primaryColumn => { result[primaryColumn.databaseName] = this.connection.driver.prepareHydratedValue(rawEntity[DriverUtils.buildColumnAlias(this.connection.driver, relationIdAttr.parentAlias, primaryColumn.databaseName)], primaryColumn); + const duplicatePart = `${primaryColumn.databaseName}:${result[primaryColumn.databaseName]}`; + if (duplicateParts.indexOf(duplicatePart) === -1) { + duplicateParts.push(duplicatePart); + } }); + + duplicateParts.sort(); + const duplicate = duplicateParts.join("::"); + if (duplicates.indexOf(duplicate) !== -1) { + return null; + } + duplicates.push(duplicate); return result; - }); + }).filter(v => v); return { relationIdAttribute: relationIdAttr, @@ -60,14 +77,31 @@ export class RelationIdLoader { const tableName = relation.inverseEntityMetadata.tableName; // category const tableAlias = relationIdAttr.alias || tableName; // if condition (custom query builder factory) is set then relationIdAttr.alias defined + const duplicates: Array = []; const parameters: ObjectLiteral = {}; const condition = rawEntities.map((rawEntity, index) => { - return joinColumns.map(joinColumn => { + const duplicateParts: Array = []; + const parameterParts: ObjectLiteral = {}; + const queryPart = joinColumns.map(joinColumn => { const parameterName = joinColumn.databaseName + index; - parameters[parameterName] = rawEntity[DriverUtils.buildColumnAlias(this.connection.driver, relationIdAttr.parentAlias, joinColumn.referencedColumn!.databaseName)]; + const parameterValue = rawEntity[DriverUtils.buildColumnAlias(this.connection.driver, relationIdAttr.parentAlias, joinColumn.referencedColumn!.databaseName)]; + const duplicatePart = `${tableAlias}:${joinColumn.propertyPath}:${parameterValue}`; + if (duplicateParts.indexOf(duplicatePart) !== -1) { + return ""; + } + duplicateParts.push(duplicatePart); + parameterParts[parameterName] = parameterValue; return tableAlias + "." + joinColumn.propertyPath + " = :" + parameterName; - }).join(" AND "); - }).map(condition => "(" + condition + ")") + }).filter(v => v).join(" AND "); + duplicateParts.sort(); + const duplicate = duplicateParts.join("::"); + if (duplicates.indexOf(duplicate) !== -1) { + return ""; + } + duplicates.push(duplicate); + Object.assign(parameters, parameterParts); + return queryPart; + }).filter(v => v).map(condition => "(" + condition + ")") .join(" OR "); // ensure we won't perform redundant queries for joined data which was not found in selection @@ -139,13 +173,30 @@ export class RelationIdLoader { return { relationIdAttribute: relationIdAttr, results: [] }; const parameters: ObjectLiteral = {}; + const duplicates: Array = []; const joinColumnConditions = mappedColumns.map((mappedColumn, index) => { - return Object.keys(mappedColumn).map(key => { + const duplicateParts: Array = []; + const parameterParts: ObjectLiteral = {}; + const queryPart = Object.keys(mappedColumn).map(key => { const parameterName = key + index; - parameters[parameterName] = mappedColumn[key]; + const parameterValue = mappedColumn[key]; + const duplicatePart = `${junctionAlias}:${key}:${parameterValue}`; + if (duplicateParts.indexOf(duplicatePart) !== -1) { + return ""; + } + duplicateParts.push(duplicatePart); + parameterParts[parameterName] = parameterValue; return junctionAlias + "." + key + " = :" + parameterName; - }).join(" AND "); - }); + }).filter(s => s).join(" AND "); + duplicateParts.sort(); + const duplicate = duplicateParts.join("::"); + if (duplicates.indexOf(duplicate) !== -1) { + return ""; + } + duplicates.push(duplicate); + Object.assign(parameters, parameterParts); + return queryPart; + }).filter(s => s); const inverseJoinColumnCondition = inverseJoinColumns.map(joinColumn => { return junctionAlias + "." + joinColumn.propertyPath + " = " + inverseSideTableAlias + "." + joinColumn.referencedColumn!.propertyPath; diff --git a/src/query-runner/BaseQueryRunner.ts b/src/query-runner/BaseQueryRunner.ts index 6e73f226e5..9afc083896 100644 --- a/src/query-runner/BaseQueryRunner.ts +++ b/src/query-runner/BaseQueryRunner.ts @@ -97,9 +97,9 @@ export abstract class BaseQueryRunner { // Protected Abstract Methods // ------------------------------------------------------------------------- - protected abstract async loadTables(tablePaths: string[]): Promise; + protected abstract loadTables(tablePaths: string[]): Promise; - protected abstract async loadViews(tablePaths: string[]): Promise; + protected abstract loadViews(tablePaths: string[]): Promise; // ------------------------------------------------------------------------- // Public Methods diff --git a/src/repository/TreeRepository.ts b/src/repository/TreeRepository.ts index 725a947a3d..b263f3e56c 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[this.metadata.primaryColumns[0].propertyName])); + entity[childProperty] = entities.filter(entity => childIds.has(this.metadata.primaryColumns[0].getEntityValue(entity))); entity[childProperty].forEach((childEntity: any) => { this.buildChildrenEntityTree(childEntity, entities, relationMaps); }); @@ -279,7 +279,7 @@ export class TreeRepository extends Repository { if (!parentRelationMap) return false; - return entity[this.metadata.primaryColumns[0].propertyName] === parentRelationMap.parentId; + return this.metadata.primaryColumns[0].getEntityValue(entity) === parentRelationMap.parentId; }); if (parentEntity) { entity[parentProperty] = parentEntity; diff --git a/test/functional/commands/entity/Post.ts b/test/functional/commands/entity/Post.ts new file mode 100644 index 0000000000..94e6f92ea5 --- /dev/null +++ b/test/functional/commands/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/functional/commands/migration-create.ts b/test/functional/commands/migration-create.ts new file mode 100644 index 0000000000..a20970af0c --- /dev/null +++ b/test/functional/commands/migration-create.ts @@ -0,0 +1,122 @@ +import sinon from "sinon"; +import { ConnectionOptions, ConnectionOptionsReader, DatabaseType } from "../../../src"; +import { + setupTestingConnections, + createTestingConnections, + closeTestingConnections, + reloadTestingDatabases +} from "../../utils/test-utils"; +import { CommandUtils } from "../../../src/commands/CommandUtils"; +import { MigrationCreateCommand } from "../../../src/commands/MigrationCreateCommand"; +import { Post } from "./entity/Post"; +import { resultsTemplates } from "./templates/result-templates-create"; + +describe("commands - migration create", () => { + let connectionOptions: ConnectionOptions[]; + let createFileStub: sinon.SinonStub; + let timerStub: sinon.SinonFakeTimers; + let getConnectionOptionsStub: sinon.SinonStub; + let migrationCreateCommand: MigrationCreateCommand; + 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 = setupTestingConnections({ + entities: [Post], + enabledDrivers + }); + connectionOptionsReader = new ConnectionOptionsReader(); + migrationCreateCommand = new MigrationCreateCommand(); + createFileStub = sinon.stub(CommandUtils, "createFile"); + + timerStub = sinon.useFakeTimers(1610975184784); + }); + + after(async () => { + timerStub.restore(); + createFileStub.restore(); + }); + + afterEach(async () => { + getConnectionOptionsStub.restore(); + }); + + it("should write regular empty 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: [Post] + }); + + await migrationCreateCommand.handler(testHandlerArgs({ + "connection": connectionOption.name + })); + + // compare against control test strings in results-templates.ts + sinon.assert.calledWith( + createFileStub, + sinon.match(/test-directory.*test-migration.ts/), + sinon.match(resultsTemplates.control) + ); + + getConnectionOptionsStub.restore(); + } + }); + + it("should write Javascript empty migration file when 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: [Post] + }); + + await migrationCreateCommand.handler(testHandlerArgs({ + "connection": connectionOption.name, + "outputJs": true + })); + + // compare against control test strings in results-templates.ts + sinon.assert.calledWith( + createFileStub, + sinon.match(/test-directory.*test-migration.js/), + sinon.match(resultsTemplates.javascript) + ); + + getConnectionOptionsStub.restore(); + } + }); +}); diff --git a/test/functional/commands/migration-generate.ts b/test/functional/commands/migration-generate.ts new file mode 100644 index 0000000000..3af86c2bdd --- /dev/null +++ b/test/functional/commands/migration-generate.ts @@ -0,0 +1,110 @@ +import sinon from "sinon"; +import { ConnectionOptions, ConnectionOptionsReader, DatabaseType } from "../../../src"; +import { + setupTestingConnections, + createTestingConnections, + closeTestingConnections, + reloadTestingDatabases +} from "../../utils/test-utils"; +import { CommandUtils } from "../../../src/commands/CommandUtils"; +import { MigrationGenerateCommand } from "../../../src/commands/MigrationGenerateCommand"; +import { Post } from "./entity/Post"; +import { resultsTemplates } from "./templates/result-templates-generate"; + +describe("commands - migration generate", () => { + let connectionOptions: ConnectionOptions[]; + let createFileStub: sinon.SinonStub; + let timerStub: sinon.SinonFakeTimers; + let getConnectionOptionsStub: sinon.SinonStub; + let migrationGenerateCommand: MigrationGenerateCommand; + let connectionOptionsReader: ConnectionOptionsReader; + let baseConnectionOptions: ConnectionOptions; + + const enabledDrivers = [ + "mysql", + ] 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 = setupTestingConnections({ + entities: [Post], + enabledDrivers + }); + connectionOptionsReader = new ConnectionOptionsReader(); + migrationGenerateCommand = new MigrationGenerateCommand(); + createFileStub = sinon.stub(CommandUtils, "createFile"); + + timerStub = sinon.useFakeTimers(1610975184784); + }); + + after(async () => { + timerStub.restore(); + 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: [Post] + }); + + await migrationGenerateCommand.handler(testHandlerArgs({ + "connection": connectionOption.name + })); + + // compare against control test strings in results-templates.ts + sinon.assert.calledWith( + createFileStub, + sinon.match(/test-directory.*test-migration.ts/), + sinon.match(resultsTemplates.control) + ); + + getConnectionOptionsStub.restore(); + } + }); + + it("writes Javascript printed file when 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: [Post] + }); + + await migrationGenerateCommand.handler(testHandlerArgs({ + "connection": connectionOption.name, + "outputJs": true + })); + + // compare against "pretty" test strings in results-templates.ts + sinon.assert.calledWith( + createFileStub, + sinon.match(/test-directory.*test-migration.js/), + sinon.match(resultsTemplates.javascript) + ); + getConnectionOptionsStub.restore(); + } + }); +}); diff --git a/test/functional/commands/templates/result-templates-create.ts b/test/functional/commands/templates/result-templates-create.ts new file mode 100644 index 0000000000..044dd40603 --- /dev/null +++ b/test/functional/commands/templates/result-templates-create.ts @@ -0,0 +1,23 @@ +export const resultsTemplates: Record = { + control: `import {MigrationInterface, QueryRunner} from "typeorm"; + +export class testMigration1610975184784 implements MigrationInterface { + + public async up(queryRunner: QueryRunner): Promise { + } + + public async down(queryRunner: QueryRunner): Promise { + } + +}`, + javascript: `const { MigrationInterface, QueryRunner } = require("typeorm"); + +module.exports = class testMigration1610975184784 { + + async up(queryRunner) { + } + + async down(queryRunner) { + } +}` +}; diff --git a/test/functional/commands/templates/result-templates-generate.ts b/test/functional/commands/templates/result-templates-generate.ts new file mode 100644 index 0000000000..548b4d015d --- /dev/null +++ b/test/functional/commands/templates/result-templates-generate.ts @@ -0,0 +1,29 @@ +export const resultsTemplates: Record = { + control: `import {MigrationInterface, QueryRunner} from "typeorm"; + +export class testMigration1610975184784 implements MigrationInterface { + name = 'testMigration1610975184784' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query("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"); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query("DROP TABLE \`post\`"); + } + +}`, + javascript: `const { MigrationInterface, QueryRunner } = require("typeorm"); + +module.exports = class testMigration1610975184784 { + name = 'testMigration1610975184784' + + async up(queryRunner) { + await queryRunner.query("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"); + } + + async down(queryRunner) { + await queryRunner.query("DROP TABLE \`post\`"); + } +}` +}; diff --git a/test/functional/database-schema/column-types/mssql/column-types-mssql.ts b/test/functional/database-schema/column-types/mssql/column-types-mssql.ts index 97a2610bbc..9dac9de6ee 100644 --- a/test/functional/database-schema/column-types/mssql/column-types-mssql.ts +++ b/test/functional/database-schema/column-types/mssql/column-types-mssql.ts @@ -155,11 +155,11 @@ describe("database schema > column types > mssql", () => { // https://github.com table!.findColumnByName("geometry1")!.type.should.be.equal("geometry"); table!.findColumnByName("simpleArray")!.type.should.be.equal("ntext"); table!.findColumnByName("simpleJson")!.type.should.be.equal("ntext"); - table!.findColumnByName("simpleEnum")!.type.should.be.equal("simple-enum"); + table!.findColumnByName("simpleEnum")!.type.should.be.equal("nvarchar"); table!.findColumnByName("simpleEnum")!.enum![0].should.be.equal("A"); table!.findColumnByName("simpleEnum")!.enum![1].should.be.equal("B"); table!.findColumnByName("simpleEnum")!.enum![2].should.be.equal("C"); - table!.findColumnByName("simpleClassEnum1")!.type.should.be.equal("simple-enum"); + table!.findColumnByName("simpleClassEnum1")!.type.should.be.equal("nvarchar"); table!.findColumnByName("simpleClassEnum1")!.enum![0].should.be.equal("apple"); table!.findColumnByName("simpleClassEnum1")!.enum![1].should.be.equal("pineapple"); table!.findColumnByName("simpleClassEnum1")!.enum![2].should.be.equal("banana"); diff --git a/test/functional/database-schema/column-types/postgres-enum/entity/Post.ts b/test/functional/database-schema/column-types/postgres-enum/entity/Post.ts index 9d32a1fc4b..bb310dda31 100644 --- a/test/functional/database-schema/column-types/postgres-enum/entity/Post.ts +++ b/test/functional/database-schema/column-types/postgres-enum/entity/Post.ts @@ -11,9 +11,12 @@ export class Post { @Column("enum", { enum: ["A", "B", "C"] }) enum: string; + @Column("enum", { enum: ["A", "B", "C"], array: true }) + enumArray: string[]; + @Column("simple-enum", { enum: ["A", "B", "C"] }) simpleEnum: string; @Column() name: string; -} \ No newline at end of file +} diff --git a/test/functional/database-schema/column-types/postgres-enum/postgres-enum.ts b/test/functional/database-schema/column-types/postgres-enum/postgres-enum.ts index fef3c5d53a..b2c1985e23 100644 --- a/test/functional/database-schema/column-types/postgres-enum/postgres-enum.ts +++ b/test/functional/database-schema/column-types/postgres-enum/postgres-enum.ts @@ -26,15 +26,19 @@ describe("database schema > column types > postgres-enum", () => { const post = new Post(); post.enum = "A"; + post.enumArray = ["A", "B"]; post.simpleEnum = "A"; post.name = "Post #1"; await postRepository.save(post); const loadedPost = (await postRepository.findOne(1))!; loadedPost.enum.should.be.equal(post.enum); + loadedPost.enumArray.should.be.deep.equal(post.enumArray); loadedPost.simpleEnum.should.be.equal(post.simpleEnum); table!.findColumnByName("enum")!.type.should.be.equal("enum"); + table!.findColumnByName("enumArray")!.type.should.be.equal("enum"); + table!.findColumnByName("enumArray")!.isArray.should.be.true; table!.findColumnByName("simpleEnum")!.type.should.be.equal("enum"); }))); @@ -170,7 +174,30 @@ describe("database schema > column types > postgres-enum", () => { await queryRunner.release(); }))); - it("should change ENUM column and revert change", () => Promise.all(connections.map(async connection => { + it("should change ENUM array column in to non-array and revert change", () => Promise.all(connections.map(async connection => { + + const queryRunner = connection.createQueryRunner(); + let table = await queryRunner.getTable("post"); + let enumColumn = table!.findColumnByName("enumArray")!; + let changedColumn = enumColumn.clone(); + changedColumn.isArray = false; + + await queryRunner.changeColumn(table!, enumColumn, changedColumn); + + table = await queryRunner.getTable("post"); + changedColumn = table!.findColumnByName("enumArray")!; + changedColumn.isArray.should.be.false; + + await queryRunner.executeMemoryDownSql(); + + table = await queryRunner.getTable("post"); + enumColumn = table!.findColumnByName("enumArray")!; + enumColumn.isArray.should.be.true; + + await queryRunner.release(); + }))); + + it("should change ENUM value and revert change", () => Promise.all(connections.map(async connection => { const queryRunner = connection.createQueryRunner(); let table = await queryRunner.getTable("post"); @@ -191,6 +218,94 @@ describe("database schema > column types > postgres-enum", () => { await queryRunner.release(); }))); + it("should change `enumName` and revert change", () => Promise.all(connections.map(async connection => { + const queryRunner = connection.createQueryRunner(); + + // add `enumName` + let table = await queryRunner.getTable("post"); + const column = table!.findColumnByName("enum")!; + const newColumn = column.clone(); + newColumn.enumName = "PostTypeEnum" + + // change column + await queryRunner.changeColumn(table!, column, newColumn) + + // check if `enumName` changed + table = await queryRunner.getTable("post"); + let changedColumn = table!.findColumnByName("enum")!; + expect(changedColumn.enumName).to.equal("PostTypeEnum"); + + // revert changes + await queryRunner.executeMemoryDownSql() + + // check if `enumName` reverted + table = await queryRunner.getTable("post"); + changedColumn = table!.findColumnByName("enum")!; + expect(changedColumn.enumName).to.undefined; + + await queryRunner.release(); + }))); + + it("should not create new type if same `enumName` is used more than once", () => Promise.all(connections.map(async connection => { + const queryRunner = connection.createQueryRunner(); + + const table = new Table({ + name: "my_table", + columns: [ + { + name: "enum1", + type: "enum", + enum: ["Apple", "Banana", "Cherry"], + enumName: "Fruits" + }, + { + name: "enum2", + type: "enum", + enum: ["Apple", "Banana", "Cherry"], + enumName: "Fruits" + }, + { + name: "enum3", + type: "enum", + enumName: "Fruits" + }, + ] + }); + + await queryRunner.createTable(table) + + // revert changes + await queryRunner.executeMemoryDownSql() + + await queryRunner.release(); + }))); + + it("should change both ENUM value and ENUM name and revert change", () => Promise.all(connections.map(async connection => { + + const queryRunner = connection.createQueryRunner(); + let table = await queryRunner.getTable("post"); + const enumColumn = table!.findColumnByName("enum")!; + const changedColumn = enumColumn.clone(); + changedColumn.enum = ["C", "D", "E"]; + changedColumn.enumName = "my_enum_type"; + + await queryRunner.changeColumn(table!, enumColumn, changedColumn); + + table = await queryRunner.getTable("post"); + const columnAfterChange = table!.findColumnByName("enum")! + columnAfterChange.enum!.should.be.eql(["C", "D", "E"]); + columnAfterChange.enumName!.should.be.eql("my_enum_type"); + + await queryRunner.executeMemoryDownSql(); + + table = await queryRunner.getTable("post"); + const columnAfterRevert = table!.findColumnByName("enum")! + columnAfterRevert.enum!.should.be.eql(["A", "B", "C"]); + expect(columnAfterRevert.enumName).to.undefined + + await queryRunner.release(); + }))); + it("should rename ENUM when column renamed and revert rename", () => Promise.all(connections.map(async connection => { const queryRunner = connection.createQueryRunner(); 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 64a2213f22..87e2f79ec2 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 @@ -128,11 +128,11 @@ describe("database schema > column types > sqlite", () => { table!.findColumnByName("datetime")!.type.should.be.equal("datetime"); table!.findColumnByName("simpleArray")!.type.should.be.equal("text"); table!.findColumnByName("simpleJson")!.type.should.be.equal("text"); - table!.findColumnByName("simpleEnum")!.type.should.be.equal("simple-enum"); + table!.findColumnByName("simpleEnum")!.type.should.be.equal("varchar"); table!.findColumnByName("simpleEnum")!.enum![0].should.be.equal("A"); table!.findColumnByName("simpleEnum")!.enum![1].should.be.equal("B"); table!.findColumnByName("simpleEnum")!.enum![2].should.be.equal("C"); - table!.findColumnByName("simpleClassEnum1")!.type.should.be.equal("simple-enum"); + table!.findColumnByName("simpleClassEnum1")!.type.should.be.equal("varchar"); table!.findColumnByName("simpleClassEnum1")!.enum![0].should.be.equal("apple"); table!.findColumnByName("simpleClassEnum1")!.enum![1].should.be.equal("pineapple"); table!.findColumnByName("simpleClassEnum1")!.enum![2].should.be.equal("banana"); diff --git a/test/functional/database-schema/enums/entity/EnumEntity.ts b/test/functional/database-schema/enums/entity/EnumEntity.ts index 14ef116374..005a90f960 100644 --- a/test/functional/database-schema/enums/entity/EnumEntity.ts +++ b/test/functional/database-schema/enums/entity/EnumEntity.ts @@ -86,4 +86,12 @@ export class EnumEntity { }) enumWithoutdefault: StringEnum; + @Column({ + type: 'enum', + enum: StringEnum, + nullable: true, + default: null, + }) + nullableDefaultEnum: StringEnum; + } diff --git a/test/functional/database-schema/enums/enums.ts b/test/functional/database-schema/enums/enums.ts index 18537b7218..1a541e496c 100644 --- a/test/functional/database-schema/enums/enums.ts +++ b/test/functional/database-schema/enums/enums.ts @@ -9,7 +9,7 @@ describe("database schema > enums", () => { before(async () => { connections = await createTestingConnections({ entities: [__dirname + "/entity/*{.js,.ts}"], - enabledDrivers: ["postgres", "mysql"] + enabledDrivers: ["postgres", "mysql", "mariadb"] }); }); beforeEach(() => reloadTestingDatabases(connections)); @@ -60,4 +60,14 @@ describe("database schema > enums", () => { }))); + it("should not generate queries 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); + + }))); + }); diff --git a/test/github-issues/1532/entity/User.ts b/test/github-issues/1532/entity/User.ts new file mode 100644 index 0000000000..2b7dc030d5 --- /dev/null +++ b/test/github-issues/1532/entity/User.ts @@ -0,0 +1,27 @@ +import {PrimaryColumn, Column} from "../../../../src"; +import {Entity} from "../../../../src/decorator/entity/Entity"; + +@Entity() +export class User { + + @PrimaryColumn() + id: number; + + @Column({ type: "varchar", array: true }) + array: string[]; + + @Column({ type: "varchar", array: true, nullable: false }) + nonNullArray: string[]; + + @Column({ type: "varchar", array: true, nullable: false, default: [] }) + emptyArrayDefault: string[]; + + @Column({ type: "varchar", array: true, nullable: false, default: ["a", "b", "c"] }) + filledArrayDefault: string[]; + + @Column({ type: "varchar", array: true, nullable: false, default: "{}" }) + emptyArrayDefaultString: string[]; + + @Column({ type: "varchar", array: true, nullable: false, default: "{a,b,c}" }) + filledArrayDefaultString: string[]; +} diff --git a/test/github-issues/1532/issue-1532.ts b/test/github-issues/1532/issue-1532.ts new file mode 100644 index 0000000000..d4aba89bee --- /dev/null +++ b/test/github-issues/1532/issue-1532.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 > #1532 Array type default value doesnt work. PostgreSQL", () => { + let connections: Connection[]; + before(async () => connections = await createTestingConnections({ + migrations: [], + enabledDrivers: ["postgres"], + 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); + }))); +}); diff --git a/test/github-issues/2758/entity/Party.ts b/test/github-issues/2758/entity/Party.ts new file mode 100644 index 0000000000..65aa88f09d --- /dev/null +++ b/test/github-issues/2758/entity/Party.ts @@ -0,0 +1,7 @@ +import {Entity, PrimaryGeneratedColumn} from "../../../../src"; + +@Entity() +export class Party { + @PrimaryGeneratedColumn("uuid") + id: string; +} diff --git a/test/github-issues/2758/entity/Person.ts b/test/github-issues/2758/entity/Person.ts new file mode 100644 index 0000000000..81df69fe66 --- /dev/null +++ b/test/github-issues/2758/entity/Person.ts @@ -0,0 +1,14 @@ +import {Entity, JoinColumn, OneToOne, PrimaryColumn} from "../../../../src"; +import {Party} from "./Party"; + +@Entity() +export class Person { + + // Party ID also acts as PK for Person (ie. inheritance) + @PrimaryColumn("uuid") + id: string; + + @OneToOne(() => Party, { cascade: true, onDelete: "CASCADE" }) + @JoinColumn({ name: "id" }) + party: Party; +} diff --git a/test/github-issues/2758/entity/User.ts b/test/github-issues/2758/entity/User.ts new file mode 100644 index 0000000000..14e14ff3b0 --- /dev/null +++ b/test/github-issues/2758/entity/User.ts @@ -0,0 +1,15 @@ +import {Column, Entity, OneToOne, PrimaryGeneratedColumn} from "../../../../src"; +import {Person} from "./Person"; + +@Entity() +export class User { + + @PrimaryGeneratedColumn("uuid") + id: string; + + @Column("uuid") + personId: string; + + @OneToOne(() => Person, { cascade: true, onDelete: "CASCADE" }) + person: Person; +} diff --git a/test/github-issues/2758/issue-2758.ts b/test/github-issues/2758/issue-2758.ts new file mode 100644 index 0000000000..f63ca32772 --- /dev/null +++ b/test/github-issues/2758/issue-2758.ts @@ -0,0 +1,66 @@ +import "reflect-metadata"; +import { Connection } from "../../../src/connection/Connection"; +import { closeTestingConnections, createTestingConnections } from "../../utils/test-utils"; +import {Person} from "./entity/Person"; +import {User} from "./entity/User"; + +describe.skip("github issues > #2758 Insert fails when related OneToOne entity's primary key is also a foreign key", () => { + + let connections: Connection[]; + before(async () => { + connections = await createTestingConnections({ + entities: [__dirname + "/entity/*{.js,.ts}"], + enabledDrivers: ["postgres"], + schemaCreate: true, + dropSchema: true, + }); + }); + after(() => closeTestingConnections(connections)); + + it("should insert person with nested new party", () => Promise.all(connections.map(async connection => { + + const repository = connection.getRepository(Person) + await connection.manager.save(repository.create({ + party: { }, + })); + + }))); + + it("should insert user with nested new person", () => Promise.all(connections.map(async connection => { + + const repository = connection.getRepository(User) + await connection.manager.save(repository.create({ + person: { party: { } }, + })) + + }))); + + it("should insert a new user with existing person", () => Promise.all(connections.map(async connection => { + + const personRepository = connection.getRepository(Person) + const person = await connection.manager.save(personRepository.create({ + party: { } + })); + + const userRepository = connection.getRepository(User) + await connection.manager.save(userRepository.create({ + person: person, + })); + + }))); + + it("should insert user with existing personId", () => Promise.all(connections.map(async connection => { + + const personRepository = connection.getRepository(Person) + const person = await connection.manager.save(personRepository.create({ + party: { }, + })); + + const userRepository = connection.getRepository(User) + await connection.manager.save(userRepository.create({ + personId: person.id, + })); + + }))); + +}); diff --git a/test/github-issues/3246/entity/Broker.ts b/test/github-issues/3246/entity/Broker.ts new file mode 100644 index 0000000000..e76afb001c --- /dev/null +++ b/test/github-issues/3246/entity/Broker.ts @@ -0,0 +1,29 @@ +import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn, OneToMany } from "../../../../src"; +import { Order } from "./Order"; + +@Entity() +export class Broker { + + @PrimaryGeneratedColumn() + id: number; + + @Column({ type: "varchar", nullable: true }) + name: string; + + @OneToMany( + (type) => Order, + (order) => order.company, + { + cascade: ["insert", "update"], + onDelete: "CASCADE", + nullable: true, + } + ) + orders?: Order; + + @CreateDateColumn() + createdDate: Date; + + @UpdateDateColumn() + modifiedDate: Date; +} diff --git a/test/github-issues/3246/entity/Order.ts b/test/github-issues/3246/entity/Order.ts new file mode 100644 index 0000000000..cfd434b371 --- /dev/null +++ b/test/github-issues/3246/entity/Order.ts @@ -0,0 +1,44 @@ +import { Entity, PrimaryGeneratedColumn, OneToOne, JoinColumn, Column, CreateDateColumn, UpdateDateColumn, ManyToOne } from "../../../../src"; +import { OrderCustomer } from "./OrderCustomer"; +import { Broker } from "./Broker"; + +@Entity() +export class Order { + + @PrimaryGeneratedColumn() + id: number; + + @Column({ type: "varchar", nullable: true }) + orderReferenceNumber: string; + + @ManyToOne( + () => Broker, + (broker) => broker.orders, + { + cascade: false, + nullable: false // starts working when set to true + } + ) + company?: Broker; + + @OneToOne( + () => OrderCustomer, + (orderCustomer) => orderCustomer.order, + { + cascade: ["insert", "update"], + onDelete: "CASCADE", + nullable: true, + } + ) + @JoinColumn({ name: "orderCustomerId" }) + orderCustomer?: OrderCustomer; + + @Column({ type: "int", nullable: true }) + orderCustomerId?: number; + + @CreateDateColumn() + createdDate: Date; + + @UpdateDateColumn() + modifiedDate: Date; +} diff --git a/test/github-issues/3246/entity/OrderCustomer.ts b/test/github-issues/3246/entity/OrderCustomer.ts new file mode 100644 index 0000000000..b368cf203d --- /dev/null +++ b/test/github-issues/3246/entity/OrderCustomer.ts @@ -0,0 +1,28 @@ +import { Order } from "./Order"; +import { Entity, PrimaryGeneratedColumn, Column, OneToOne, CreateDateColumn, UpdateDateColumn } from "../../../../src"; + +@Entity() +export class OrderCustomer { + + @PrimaryGeneratedColumn() + id: number; + + @Column({ type: "varchar", nullable: false }) + name: string; + + @OneToOne( + (type) => Order, + (order) => order.orderCustomer, + { + cascade: ["insert", "update"], + nullable: true, + }, + ) + order?: Order; + + @CreateDateColumn() + createdDate: Date; + + @UpdateDateColumn() + modifiedDate: Date; +} diff --git a/test/github-issues/3246/issue-3246.ts b/test/github-issues/3246/issue-3246.ts new file mode 100644 index 0000000000..1fb38ae1d5 --- /dev/null +++ b/test/github-issues/3246/issue-3246.ts @@ -0,0 +1,44 @@ +import "reflect-metadata"; +import {createTestingConnections, closeTestingConnections, reloadTestingDatabases} from "../../utils/test-utils"; +import {Connection} from "../../../src/connection/Connection"; +import {expect} from "chai"; +import { Order } from "./entity/Order"; +import { OrderCustomer } from "./entity/OrderCustomer"; +import { OrderRepository } from "./repository/OrderRepository"; +import { Broker } from "./entity/Broker"; +import { BrokerRepository } from "./repository/BrokerRepository"; + +describe("github issues > #3246 Saving an entity with a 1:1 cascading insert does not return id if entity has nullable many:one relationship", () => { + + let connections: Connection[]; + before(async () => connections = await createTestingConnections({ + entities: [Order, OrderCustomer, Broker], + enabledDrivers: ["postgres"], + schemaCreate: true, + dropSchema: true, + })); + + beforeEach(() => reloadTestingDatabases(connections)); + after(() => closeTestingConnections(connections)); + + it("should insert and return the order with id", () => Promise.all(connections.map(async connection => { + let company = new Broker(); + company.name = "Acme Inc."; + + let order = new Order(); + order.orderReferenceNumber = "abcd"; + + const orderCustomer = new OrderCustomer(); + orderCustomer.name = "Dave"; + order.orderCustomer = orderCustomer; + + const myCompanyRepository = connection.manager.getCustomRepository(BrokerRepository); + const createdCompany = await myCompanyRepository.createBroker(company); + const myOrderRepository = connection.manager.getCustomRepository(OrderRepository); + order.company = createdCompany; + + const result = await myOrderRepository.createOrder(order); + + expect(result.id).not.to.be.undefined; + }))); + }); diff --git a/test/github-issues/3246/repository/BrokerRepository.ts b/test/github-issues/3246/repository/BrokerRepository.ts new file mode 100644 index 0000000000..2cfee853d8 --- /dev/null +++ b/test/github-issues/3246/repository/BrokerRepository.ts @@ -0,0 +1,9 @@ +import { EntityRepository, AbstractRepository } from "../../../../src"; +import { Broker } from "../entity/Broker"; + +@EntityRepository(Broker) +export class BrokerRepository extends AbstractRepository { + async createBroker(broker: Broker) { + return this.repository.save(broker); + } +} diff --git a/test/github-issues/3246/repository/OrderRepository.ts b/test/github-issues/3246/repository/OrderRepository.ts new file mode 100644 index 0000000000..5761c78dd0 --- /dev/null +++ b/test/github-issues/3246/repository/OrderRepository.ts @@ -0,0 +1,9 @@ +import { Order } from "../entity/Order"; +import { EntityRepository, AbstractRepository } from "../../../../src"; + +@EntityRepository(Order) +export class OrderRepository extends AbstractRepository { + async createOrder(order: Order) { + return this.repository.save(order); + } +} diff --git a/test/github-issues/4897/entity/SomeEntity.ts b/test/github-issues/4897/entity/SomeEntity.ts new file mode 100644 index 0000000000..92f92af063 --- /dev/null +++ b/test/github-issues/4897/entity/SomeEntity.ts @@ -0,0 +1,33 @@ +import {Column, PrimaryGeneratedColumn} from "../../../../src"; +import {Entity} from "../../../../src"; + +export type UserRoleType = 'user' | 'admin'; +export const userRoles = { + USER: 'user' as UserRoleType, + ADMIN: 'admin' as UserRoleType, +} + +export enum UserRoles { + USER = 'user', + ADMIN = 'admin' +} + +@Entity() +export class SomeEntity { + @PrimaryGeneratedColumn() + id: number; + + @Column({ + type: "simple-enum", + enum: Object.values(userRoles), + default: userRoles.USER, + }) + test: UserRoleType; + + @Column({ + type: "simple-enum", + enum: UserRoles, + default: UserRoles.USER, + }) + test2: UserRoles; +} diff --git a/test/github-issues/4897/issue-4897.ts b/test/github-issues/4897/issue-4897.ts new file mode 100644 index 0000000000..595de18f80 --- /dev/null +++ b/test/github-issues/4897/issue-4897.ts @@ -0,0 +1,30 @@ +import "reflect-metadata"; +import {Connection} from "../../../src"; +import {createTestingConnections, closeTestingConnections} from "../../utils/test-utils"; +import {SomeEntity} from "./entity/SomeEntity"; + +describe("github issues > #4897 [MSSQL] Enum column definition removes and recreates constraint overwritting existing data", () => { + let connections: Connection[]; + before(async () => connections = await createTestingConnections({ + migrations: [], + enabledDrivers: ["mssql", "sqlite"], + schemaCreate: false, + dropSchema: true, + entities: [SomeEntity], + })); + after(() => closeTestingConnections(connections)); + + it("should 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("should not generate queries 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); + }))); +}); diff --git a/test/github-issues/5275/entity/UserEntity.ts b/test/github-issues/5275/entity/UserEntity.ts new file mode 100644 index 0000000000..13b9a64467 --- /dev/null +++ b/test/github-issues/5275/entity/UserEntity.ts @@ -0,0 +1,23 @@ +import {Column, Entity, PrimaryColumn} from "../../../../src"; + +export enum Role { + GuildMaster = "Guild Master", + Officer = "Officer", + Boss = 'BOSS "LEVEL 80"', + Warrior = "Knight\\Rogue", + Number = 1, + PlayerAlt = "Player Alt" +} + + +@Entity() +export class User { + @PrimaryColumn() + id: number; + + @Column({ type: "enum", enum: Role, default: Role.GuildMaster }) + role: Role; + + @Column({ type: "enum", enum: Role, default: [Role.GuildMaster], array: true }) + roles: Role[]; +} diff --git a/test/github-issues/5275/issue-5275.ts b/test/github-issues/5275/issue-5275.ts new file mode 100644 index 0000000000..deb73b4481 --- /dev/null +++ b/test/github-issues/5275/issue-5275.ts @@ -0,0 +1,59 @@ +import "reflect-metadata"; +import { Connection } from "../../../src"; +import { + closeTestingConnections, + createTestingConnections, + reloadTestingDatabases, +} from "../../utils/test-utils"; +import {Role, User} from "./entity/UserEntity"; + +describe("github issues > #5275 Enums with spaces are not converted properly.", () => { + let connections: Connection[]; + before( + async () => + (connections = await createTestingConnections({ + entities: [User], + schemaCreate: true, + dropSchema: true, + enabledDrivers: ["postgres"], + })) + ); + + beforeEach(() => reloadTestingDatabases(connections)); + after(() => closeTestingConnections(connections)); + + it("should correctly parse enums of strings with spaces", () => Promise.all(connections.map(async connection => { + const userRepository = connection.getRepository(User); + await userRepository.save({ + id: 1, + roles: [ + Role.GuildMaster, + Role.Officer, + Role.Boss, + Role.Warrior, + Role.Number, + Role.PlayerAlt, + ], + }); + const user = await userRepository.findOneOrFail(1); + user.roles.should.deep.equal(["Guild Master", "Officer", 'BOSS "LEVEL 80"', "Knight\\Rogue", 1, "Player Alt"]); + }))); + + it("should correctly parse non-array enums with spaces", () => Promise.all(connections.map(async connection => { + const userRepository = connection.getRepository(User); + await userRepository.save([ + { id: 1 }, + { id: 2, role: Role.Boss }, + { id: 3, role: Role.Warrior } + ]); + + const user1 = await userRepository.findOneOrFail(1); + user1.role.should.equal("Guild Master"); + + const user2 = await userRepository.findOneOrFail(2); + user2.role.should.equal('BOSS "LEVEL 80"'); + + const user3 = await userRepository.findOneOrFail(3); + user3.role.should.equal("Knight\\Rogue"); + }))); +}); diff --git a/test/github-issues/5478/entity/UserEntity.ts b/test/github-issues/5478/entity/UserEntity.ts new file mode 100644 index 0000000000..3afe228c29 --- /dev/null +++ b/test/github-issues/5478/entity/UserEntity.ts @@ -0,0 +1,16 @@ +import {Column, PrimaryGeneratedColumn} from "../../../../src"; +import {Entity} from "../../../../src"; + +enum UserType { + ADMIN = "ADMIN", + USER = "USER", +} + +@Entity("user") +export class UserEntity { + @PrimaryGeneratedColumn() + id: number; + + @Column({ type: "enum", enum: UserType }) + userType: UserType; +} diff --git a/test/github-issues/5478/issue-5478.ts b/test/github-issues/5478/issue-5478.ts new file mode 100644 index 0000000000..f734af5ae4 --- /dev/null +++ b/test/github-issues/5478/issue-5478.ts @@ -0,0 +1,45 @@ +import "reflect-metadata"; +import {Connection} from "../../../src"; +import {createTestingConnections, closeTestingConnections} from "../../utils/test-utils"; +import {expect} from "chai"; +import {UserEntity} from "./entity/UserEntity"; + +describe("github issues > #5478 Setting enumName doesn't change how migrations get generated", () => { + let connections: Connection[]; + before(async () => connections = await createTestingConnections({ + migrations: [], + enabledDrivers: ["postgres"], + schemaCreate: true, + dropSchema: true, + entities: [UserEntity], + })); + after(() => closeTestingConnections(connections)); + + it("should correctly rename enum", () => Promise.all(connections.map(async connection => { + const queryRunner = connection.createQueryRunner(); + + // add `enumName` + let table = await queryRunner.getTable("user"); + const column = table!.findColumnByName("userType")!; + const newColumn = column.clone(); + newColumn.enumName = "UserTypeEnum" + + // change column + await queryRunner.changeColumn(table!, column, newColumn) + + // check if `enumName` changed + table = await queryRunner.getTable("user"); + let changedColumn = table!.findColumnByName("userType")!; + expect(changedColumn.enumName).to.equal("UserTypeEnum"); + + // revert changes + await queryRunner.executeMemoryDownSql() + + // check if `enumName` reverted + table = await queryRunner.getTable("user"); + changedColumn = table!.findColumnByName("userType")!; + expect(changedColumn.enumName).to.undefined; + + await queryRunner.release(); + }))); +}); diff --git a/test/github-issues/5691/enity/Child1.ts b/test/github-issues/5691/enity/Child1.ts new file mode 100644 index 0000000000..81a844e36b --- /dev/null +++ b/test/github-issues/5691/enity/Child1.ts @@ -0,0 +1,21 @@ +import {Entity, ManyToOne, OneToMany, PrimaryGeneratedColumn, RelationId} from "../../../../src"; +import {Root} from "./Root"; +import {Shared} from "./Shared"; + +@Entity() +export class Child1 { + @PrimaryGeneratedColumn("uuid") + public id?: string; + + @ManyToOne(() => Root, entity => entity.allChild1) + public root?: Root; + + @RelationId("root") + public rootId?: string; + + @OneToMany(() => Shared, entity => entity.child1) + public allShared?: Array; + + @RelationId("allShared") + public allSharedId?: Array; +} diff --git a/test/github-issues/5691/enity/Child2.ts b/test/github-issues/5691/enity/Child2.ts new file mode 100644 index 0000000000..acff5920bd --- /dev/null +++ b/test/github-issues/5691/enity/Child2.ts @@ -0,0 +1,21 @@ +import {ManyToMany, PrimaryGeneratedColumn, RelationId, OneToMany, Entity} from "../../../../src"; +import {Root} from "./Root"; +import {Shared} from "./Shared"; + +@Entity() +export class Child2 { + @PrimaryGeneratedColumn("uuid") + public id?: string; + + @ManyToMany(() => Root, entity => entity.allChild2) + public allRoot?: Root; + + @RelationId("allRoot") + public allRootId?: Array; + + @OneToMany(() => Shared, entity => entity.child2) + public allShared?: Array; + + @RelationId("allShared") + public allSharedId?: Array; +} diff --git a/test/github-issues/5691/enity/Root.ts b/test/github-issues/5691/enity/Root.ts new file mode 100644 index 0000000000..d45afb79bf --- /dev/null +++ b/test/github-issues/5691/enity/Root.ts @@ -0,0 +1,29 @@ +import {Entity, JoinTable, ManyToMany, OneToMany, PrimaryGeneratedColumn, RelationId} from "../../../../src"; +import {Child1} from "./Child1"; +import {Child2} from "./Child2"; +import {Shared} from "./Shared"; + +@Entity() +export class Root { + @PrimaryGeneratedColumn("uuid") + public id?: string; + + @OneToMany(() => Shared, entity => entity.root) + public allShared?: Array; + + @RelationId("allShared") + public allSharedId?: Array; + + @OneToMany(() => Child1, entity => entity.root) + public allChild1?: Array; + + @RelationId("allChild1") + public allChild1Id?: Array; + + @ManyToMany(() => Child2, entity => entity.allRoot) + @JoinTable() + public allChild2?: Array; + + @RelationId("allChild2") + public allChild2Id?: Array; +} diff --git a/test/github-issues/5691/enity/Shared.ts b/test/github-issues/5691/enity/Shared.ts new file mode 100644 index 0000000000..b15a85906a --- /dev/null +++ b/test/github-issues/5691/enity/Shared.ts @@ -0,0 +1,44 @@ +import {Entity, JoinColumn, ManyToOne, OneToMany, PrimaryGeneratedColumn, RelationId} from "../../../../src"; +import {Child1} from "./Child1"; +import {Child2} from "./Child2"; +import {Root} from "./Root"; + +@Entity() +export class Shared { + @PrimaryGeneratedColumn("uuid") + public id?: string; + + @ManyToOne(() => Root, entity => entity.allShared) + @JoinColumn() + public root?: Root; + + @RelationId("root") + public rootId?: string; + + @ManyToOne(() => Child1, entity => entity.allShared) + @JoinColumn() + public child1?: Child1; + + @RelationId("child1") + public child1Id?: string; + + @ManyToOne(() => Child2, entity => entity.allShared) + @JoinColumn() + public child2?: Child2; + + @RelationId("child2") + public child2Id?: string; + + @ManyToOne(() => Shared, entity => entity.allShared) + @JoinColumn() + public shared?: Shared; + + @RelationId("shared") + public sharedId?: string; + + @OneToMany(() => Shared, entity => entity.shared) + public allShared?: Array; + + @RelationId("allShared") + public allSharedId?: Array; +} diff --git a/test/github-issues/5691/issue-5691.ts b/test/github-issues/5691/issue-5691.ts new file mode 100644 index 0000000000..e2da8285c1 --- /dev/null +++ b/test/github-issues/5691/issue-5691.ts @@ -0,0 +1,125 @@ +import "reflect-metadata"; +import {createTestingConnections, closeTestingConnections, reloadTestingDatabases} from "../../utils/test-utils"; +import {Connection} from "../../../src"; +import {expect} from "chai"; +import {Child1} from "./enity/Child1"; +import {Child2} from "./enity/Child2"; +import {Root} from "./enity/Root"; +import {Shared} from "./enity/Shared"; + +describe("github issues > #5691 RelationId is too slow", () => { + const setupFixtures = async (connection: Connection, allChild2: Array): Promise => { + const root = new Root(); + root.allChild2 = allChild2; + await connection.getRepository(Root).save(root); + + const rootAllShared: Array = []; + for (let indexShared = 0; indexShared < allChild2.length; indexShared ++) { + const rootShared = new Shared(); + rootShared.root = root; + rootAllShared.push(rootShared); + } + await connection.getRepository(Shared).save(rootAllShared); + + const savePromises: Array> = []; + for (let indexChild1 = 0; indexChild1 < allChild2.length; indexChild1 ++) { + const rootChild1 = new Child1(); + rootChild1.root = root; + await connection.getRepository(Child1).save(rootChild1); + + for (const child2 of allChild2) { + const rootChild1Child2 = new Shared(); + rootChild1Child2.root = root; + rootChild1Child2.child1 = rootChild1; + rootChild1Child2.child2 = child2; + savePromises.push(connection.getRepository(Shared).save(rootChild1Child2)); + } + for (const shared of rootAllShared) { + const rootChild1Shared = new Shared(); + rootChild1Shared.root = root; + rootChild1Shared.child1 = rootChild1; + rootChild1Shared.shared = shared; + savePromises.push(connection.getRepository(Shared).save(rootChild1Shared)); + } + } + await Promise.all(savePromises); + }; + + let connections: Connection[]; + before(async () => connections = await createTestingConnections({ + entities: [ + Root, + Child1, + Child2, + Shared, + ], + schemaCreate: true, + dropSchema: true, + })); + beforeEach(() => reloadTestingDatabases(connections)); + after(() => closeTestingConnections(connections)); + + it("should be as fast as separate queries", () => Promise.all(connections.map(async connection => { + const child21 = new Child2(); + const child22 = new Child2(); + const child23 = new Child2(); + const child24 = new Child2(); + const child25 = new Child2(); + await Promise.all([ + connection.getRepository(Child2).save(child21), + connection.getRepository(Child2).save(child22), + connection.getRepository(Child2).save(child23), + connection.getRepository(Child2).save(child24), + connection.getRepository(Child2).save(child25), + ]); + + await Promise.all([ + setupFixtures(connection, [child21, child22, child23]), + // To understand the problem deeper add more fixtures. + // It will take forever. + // setupFixtures(connection, [child22, child23, child24]), + // setupFixtures(connection, [child23, child24, child25]), + // setupFixtures(connection, [child24, child25, child21]), + // setupFixtures(connection, [child25, child21, child22]), + // setupFixtures(connection, [child21, child22, child23]), + // setupFixtures(connection, [child22, child23, child24]), + // setupFixtures(connection, [child23, child24, child25]), + // setupFixtures(connection, [child24, child25, child21]), + // setupFixtures(connection, [child25, child21, child22]), + ]); + + const test1Start = new Date().getTime(); + // 54 rows for 1 root + await connection.getRepository(Root).find({ + relations: [ + "allChild1", + "allChild1.allShared", + "allChild2", + ], + }); + // 21 rows 1 root + await connection.getRepository(Root).find({ + relations: [ + "allShared", + ], + }); + const test1End = new Date().getTime(); + + const test2Start = new Date().getTime(); + // 1134 rows 1 root + await connection.getRepository(Root).find({ + relations: [ + "allChild1", + "allChild1.allShared", + "allChild2", + "allShared", + ], + }); + const test2End = new Date().getTime(); + + expect(test2End - test2Start).to.be.lessThan( + (test1End - test1Start) * 15, // yes, even 15 times slower, because amount of data requires more time. + "a single call should be not as more as 15 times slower than multi calls", + ); + }))); +}); diff --git a/test/github-issues/5871/entity/SomeEntity.ts b/test/github-issues/5871/entity/SomeEntity.ts new file mode 100644 index 0000000000..6e5a600ea6 --- /dev/null +++ b/test/github-issues/5871/entity/SomeEntity.ts @@ -0,0 +1,16 @@ +import {Column, PrimaryGeneratedColumn} from "../../../../src"; +import {Entity} from "../../../../src"; + +enum Test { + TEST1 = 'testing (brackets)', + TEST2 = 'testing (brackers too)', +} + +@Entity() +export class SomeEntity { + @PrimaryGeneratedColumn() + id: number; + + @Column({ type: "enum", enum: Test }) + test: Test; +} diff --git a/test/github-issues/5871/issue-5871.ts b/test/github-issues/5871/issue-5871.ts new file mode 100644 index 0000000000..c76c856199 --- /dev/null +++ b/test/github-issues/5871/issue-5871.ts @@ -0,0 +1,30 @@ +import "reflect-metadata"; +import {Connection} from "../../../src"; +import {createTestingConnections, closeTestingConnections} from "../../utils/test-utils"; +import {SomeEntity} from "./entity/SomeEntity"; + +describe("github issues > #5871 Migration generate does not play well with mysql enum with parentheses in the enum value", () => { + let connections: Connection[]; + before(async () => connections = await createTestingConnections({ + migrations: [], + enabledDrivers: ["mysql"], + schemaCreate: false, + dropSchema: true, + entities: [SomeEntity], + })); + after(() => closeTestingConnections(connections)); + + it("should 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("should not generate queries 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); + }))); +}); diff --git a/test/github-issues/6115/entity/v1/MetricEntity.ts b/test/github-issues/6115/entity/v1/MetricEntity.ts new file mode 100644 index 0000000000..92f6f03091 --- /dev/null +++ b/test/github-issues/6115/entity/v1/MetricEntity.ts @@ -0,0 +1,29 @@ +import { Column, PrimaryGeneratedColumn } from "../../../../../src"; +import { Entity } from "../../../../../src"; + +export enum Operator { + LT = "lt", + LE = "le", + EQ = "eq", + NE = "ne", + GE = "ge", + GT = "gt" +} + +@Entity() +export class Metric { + @PrimaryGeneratedColumn() + id!: number; + + @Column({ type: "enum", enum: Operator, default: Operator.EQ }) + defaultOperator!: string; + + @Column({ type: "enum", enum: Operator }) + defaultOperator2!: string; + + @Column({ type: "enum", enum: Operator, default: Operator.EQ }) + defaultOperator3!: string; + + @Column({ type: "enum", enum: Operator, default: Operator.EQ }) + defaultOperator4!: string; +} diff --git a/test/github-issues/6115/entity/v2/MetricEntity.ts b/test/github-issues/6115/entity/v2/MetricEntity.ts new file mode 100644 index 0000000000..67d2c7a5ef --- /dev/null +++ b/test/github-issues/6115/entity/v2/MetricEntity.ts @@ -0,0 +1,29 @@ +import { Column, PrimaryGeneratedColumn } from "../../../../../src"; +import { Entity } from "../../../../../src"; + +export enum Operator { + LT = "lessthan", + LE = "lessequal", + EQ = "equal", + NE = "notequal", + GE = "greaterequal", + GT = "greaterthan" +} + +@Entity() +export class Metric { + @PrimaryGeneratedColumn() + id!: number; + + @Column({ type: "enum", enum: Operator, default: Operator.EQ }) + defaultOperator!: string; + + @Column({ type: "enum", enum: Operator, default: Operator.EQ }) + defaultOperator2!: string; + + @Column({ type: "enum", enum: Operator }) + defaultOperator3!: string; + + @Column({ type: "enum", enum: Operator, default: Operator.GT }) + defaultOperator4!: string; +} diff --git a/test/github-issues/6115/issue-6115.ts b/test/github-issues/6115/issue-6115.ts new file mode 100644 index 0000000000..f1f80d293f --- /dev/null +++ b/test/github-issues/6115/issue-6115.ts @@ -0,0 +1,87 @@ +import "reflect-metadata"; +import {Connection, createConnection} from "../../../src"; +import {closeTestingConnections, createTestingConnections, setupSingleTestingConnection} from "../../utils/test-utils"; +import {fail} from "assert"; +import {expect} from "chai"; + +describe("github issues > #6115 Down migration for enums with defaults are wrong", () => { + let connections: Connection[]; + before(async () => connections = await createTestingConnections({ + enabledDrivers: ["postgres"], + entities: [__dirname + "/entity/v1/*{.js,.ts}"], + dropSchema: true, + schemaCreate: true + })); + after(() => closeTestingConnections(connections)); + + it("should change schema when enum definition changes", () => 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 + } + ); + if (!options) { + fail(); + return; + } + + const connection = await createConnection(options); + const queryRunner = connection.createQueryRunner(); + + const sqlInMemory = await connection.driver + .createSchemaBuilder() + .log(); + + const upQueries = sqlInMemory.upQueries.map( + query => query.query + ); + const downQueries = sqlInMemory.downQueries.map( + query => query.query + ); + + // update entity + for (const query of upQueries) { + await connection.query(query) + } + + let table = await queryRunner.getTable("metric"); + let defaultOperator = table!.findColumnByName("defaultOperator"); + expect(defaultOperator!.enum).to.deep.equal(["lessthan", "lessequal", "equal", "notequal", "greaterequal", "greaterthan"]); + expect(defaultOperator!.default).to.equal(`'equal'`); + + let defaultOperator2 = table!.findColumnByName("defaultOperator2"); + expect(defaultOperator2!.default).to.equal(`'equal'`); + + let defaultOperator3 = table!.findColumnByName("defaultOperator3"); + expect(defaultOperator3!.default).to.be.undefined + + let defaultOperator4 = table!.findColumnByName("defaultOperator4"); + expect(defaultOperator4!.default).to.equal(`'greaterthan'`); + + // revert update + for (const query of downQueries.reverse()) { + await connection.query(query) + } + + table = await queryRunner.getTable("metric"); + defaultOperator = table!.findColumnByName("defaultOperator"); + expect(defaultOperator!.enum).to.deep.equal(["lt", "le", "eq", "ne", "ge", "gt"]); + expect(defaultOperator!.default).to.equal(`'eq'`); + + defaultOperator2 = table!.findColumnByName("defaultOperator2"); + expect(defaultOperator2!.default).to.be.undefined + + defaultOperator3 = table!.findColumnByName("defaultOperator3"); + expect(defaultOperator3!.default).to.equal(`'eq'`); + + defaultOperator4 = table!.findColumnByName("defaultOperator4"); + expect(defaultOperator4!.default).to.equal(`'eq'`); + + await queryRunner.release(); + await connection.close(); + }))); +}); diff --git a/test/github-issues/6471/entity/SomeEntity.ts b/test/github-issues/6471/entity/SomeEntity.ts new file mode 100644 index 0000000000..102206ecd5 --- /dev/null +++ b/test/github-issues/6471/entity/SomeEntity.ts @@ -0,0 +1,35 @@ +import {Column, Unique, PrimaryGeneratedColumn} from "../../../../src"; +import {Entity} from "../../../../src"; + +export enum CreationMechanism { + SOURCE_A = 'SOURCE_A', + SOURCE_B = 'SOURCE_B', + SOURCE_C = 'SOURCE_C', + SOURCE_D = 'SOURCE_D' +} + +@Entity({ name: 'some_entity' }) +@Unique([ + 'field1', + 'field2', +]) +export class SomeEntity { + @PrimaryGeneratedColumn() + id: number; + + @Column() + field1: string; + + @Column() + field2: string; + + @Column({ + type : 'enum', + enumName : 'creation_mechanism_enum', + enum : CreationMechanism, + }) + creationMechanism: CreationMechanism; + + @Column({ nullable: false, default: () => 'now()' }) + createdAt: Date; +} diff --git a/test/github-issues/6471/issue-6471.ts b/test/github-issues/6471/issue-6471.ts new file mode 100644 index 0000000000..48e3cce46a --- /dev/null +++ b/test/github-issues/6471/issue-6471.ts @@ -0,0 +1,40 @@ +import "reflect-metadata"; +import {Connection} from "../../../src"; +import {createTestingConnections, closeTestingConnections} from "../../utils/test-utils"; +import {SomeEntity} from "./entity/SomeEntity"; + +describe("github issues > #6471 Postgres enum is recreated in every new generated migration", () => { + let connections: Connection[]; + before(async () => connections = await createTestingConnections({ + migrations: [], + enabledDrivers: ["postgres"], + schemaCreate: false, + dropSchema: true, + entities: [SomeEntity], + })); + after(() => closeTestingConnections(connections)); + + it("should 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("should not generate queries 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); + }))); + + it("should handle `enumName` change", () => Promise.all(connections.map(async connection => { + const entityMetadata = connection.getMetadata(SomeEntity) + const columnMetadata = entityMetadata.columns.find(column => column.databaseName === "creationMechanism") + columnMetadata!.enumName = "changed_enum_name" + + const sqlInMemory = await connection.driver.createSchemaBuilder().log(); + sqlInMemory.upQueries.length.should.be.greaterThan(0); + sqlInMemory.downQueries.length.should.be.greaterThan(0); + }))); +}); diff --git a/test/github-issues/7002/entity/Bar.ts b/test/github-issues/7002/entity/Bar.ts new file mode 100644 index 0000000000..275d05f866 --- /dev/null +++ b/test/github-issues/7002/entity/Bar.ts @@ -0,0 +1,19 @@ +import { + Column, + Entity, + OneToOne, + PrimaryGeneratedColumn, +} from "../../../../src"; +import { Foo } from "./Foo"; + +@Entity() +export class Bar { + @PrimaryGeneratedColumn("increment") + id: number; + + @Column() + title: string; + + @OneToOne(() => Foo, foo => foo.bar, { cascade: true, eager: true }) + foo: Foo; +} diff --git a/test/github-issues/7002/entity/Foo.ts b/test/github-issues/7002/entity/Foo.ts new file mode 100644 index 0000000000..455ea41dcf --- /dev/null +++ b/test/github-issues/7002/entity/Foo.ts @@ -0,0 +1,25 @@ +import { + Column, + CreateDateColumn, + Entity, + JoinColumn, + OneToOne, + PrimaryColumn, +} from "../../../../src"; +import { Bar } from "./Bar"; + +@Entity() +export class Foo { + @PrimaryColumn() + id: number; + + @Column() + text: string; + + @OneToOne(() => Bar, b => b.foo, { primary: true }) + @JoinColumn({ name: "id", referencedColumnName: "id" }) + bar: Bar; + + @CreateDateColumn() + d: Date; +} diff --git a/test/github-issues/7002/issue-7002.ts b/test/github-issues/7002/issue-7002.ts new file mode 100644 index 0000000000..ea040a8e4e --- /dev/null +++ b/test/github-issues/7002/issue-7002.ts @@ -0,0 +1,40 @@ +import "reflect-metadata"; + +import { Connection } from "../../../src/connection/Connection"; +import { + closeTestingConnections, + createTestingConnections, + reloadTestingDatabases, +} from "../../utils/test-utils"; +import { Bar } from "./entity/Bar"; +import { Foo } from "./entity/Foo"; + +describe("github issues > #7002 cascade save fails if the child entity has CreateDateColumn and PK as JoinColumn", () => { + let connections: Connection[]; + before( + async () => + (connections = await createTestingConnections({ + entities: [__dirname + "/entity/*{.js,.ts}"], + schemaCreate: true, + dropSchema: true, + enabledDrivers: ["mysql", "postgres"], + })) + ); + beforeEach(() => reloadTestingDatabases(connections)); + after(() => closeTestingConnections(connections)); + + it("save an entity having a child entity with shared PK and CreatedDateColumn by cascade", () => + Promise.all( + connections.map(async (connection) => { + const foo = new Foo(); + foo.text = "This is a feature post"; + + await connection.manager.save( + connection.getRepository(Bar).create({ + title: "Feature Post", + foo, + }) + ); + }) + )); +}); diff --git a/test/github-issues/7217/entity/UserEntity.ts b/test/github-issues/7217/entity/UserEntity.ts new file mode 100644 index 0000000000..dce3c3b05e --- /dev/null +++ b/test/github-issues/7217/entity/UserEntity.ts @@ -0,0 +1,23 @@ +import {Column, Entity, PrimaryGeneratedColumn} from "../../../../src"; + +export enum UserRole { + PLAYER = 'PLAYER', + FULL_GAME = 'FULL_GAME', + SUPERVISOR = 'SUPERVISOR', + REPORTS = 'REPORTS', + ADMIN = 'ADMIN', +} + +@Entity() +export class User { + @PrimaryGeneratedColumn('uuid') + id: string; + + @Column({ + type: 'enum', + enum: UserRole, + array: true, + default: [UserRole.PLAYER], + }) + roles: UserRole[]; +} diff --git a/test/github-issues/7217/issue-7217.ts b/test/github-issues/7217/issue-7217.ts new file mode 100644 index 0000000000..4e7154c8bc --- /dev/null +++ b/test/github-issues/7217/issue-7217.ts @@ -0,0 +1,34 @@ +import "reflect-metadata"; +import {Connection} from "../../../src"; +import {createTestingConnections, closeTestingConnections} from "../../utils/test-utils"; +import {User} from "./entity/UserEntity"; + +describe("github issues > #7217 Modifying enum fails migration if the enum is used in an array column", () => { + let connections: Connection[]; + before(async () => connections = await createTestingConnections({ + migrations: [], + enabledDrivers: ["postgres"], + schemaCreate: false, + dropSchema: true, + entities: [User], + })); + after(() => closeTestingConnections(connections)); + + it("should not generate queries 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); + }))); + + it("should correctly change enum", () => Promise.all(connections.map(async connection => { + const metadata = connection.getMetadata(User) + const columnMetadata = metadata.columns.find(column => column.databaseName === "roles") + columnMetadata!.enum = ["PLAYER", "FULL_GAME"] + + const sqlInMemory = await connection.driver.createSchemaBuilder().log(); + sqlInMemory.upQueries.length.should.be.greaterThan(0); + sqlInMemory.downQueries.length.should.be.greaterThan(0); + }))); +}); diff --git a/test/github-issues/7283/entity/AccessEvent.ts b/test/github-issues/7283/entity/AccessEvent.ts new file mode 100644 index 0000000000..f7c617e199 --- /dev/null +++ b/test/github-issues/7283/entity/AccessEvent.ts @@ -0,0 +1,15 @@ +import {BaseEntity, Entity, JoinTable, ManyToMany, ManyToOne, PrimaryColumn} from "../../../../src"; +import {Employee} from "./Employee"; + +@Entity() +export class AccessEvent extends BaseEntity { + @PrimaryColumn({ type: 'varchar', length: 128 }) + id!: string + + @ManyToOne(() => Employee, (employee) => employee.accessEvents) + employee!: Employee + + @ManyToMany(() => Employee) + @JoinTable() + employees: Employee[]; +} diff --git a/test/github-issues/7283/entity/Employee.ts b/test/github-issues/7283/entity/Employee.ts new file mode 100644 index 0000000000..5928255ed1 --- /dev/null +++ b/test/github-issues/7283/entity/Employee.ts @@ -0,0 +1,16 @@ +import {BaseEntity, Entity, OneToMany, PrimaryColumn} from "../../../../src"; +import {AccessEvent} from "./AccessEvent"; + +enum Providers { + MS_GRAPH = 'msGraph', + ATLASSIAN = 'atlassian' +} + +@Entity() +export class Employee extends BaseEntity { + @PrimaryColumn({ type: 'enum', enum: Providers, enumName: "providerEnum" }) + provider!: Providers + + @OneToMany(() => AccessEvent, (accessEvent) => accessEvent.employee) + accessEvents!: AccessEvent[] +} diff --git a/test/github-issues/7283/issue-7283.ts b/test/github-issues/7283/issue-7283.ts new file mode 100644 index 0000000000..204738e9ef --- /dev/null +++ b/test/github-issues/7283/issue-7283.ts @@ -0,0 +1,35 @@ +import "reflect-metadata"; +import {Connection} from "../../../src"; +import {createTestingConnections, closeTestingConnections} from "../../utils/test-utils"; +import {AccessEvent} from "./entity/AccessEvent"; +import {Employee} from "./entity/Employee"; +import {expect} from "chai"; + +describe("github issues > #7283 Generating Migration on ManyToOne/OneToMany + Primary enum column results in missing enum type in migration output", () => { + let connections: Connection[]; + before(async () => connections = await createTestingConnections({ + migrations: [], + enabledDrivers: ["mysql", "mariadb", "postgres"], + schemaCreate: false, + dropSchema: true, + entities: [AccessEvent, Employee], + })); + after(() => closeTestingConnections(connections)); + + it("should create tables with enum primary column", () => Promise.all(connections.map(async connection => { + await connection.driver.createSchemaBuilder().build(); + const queryRunner = connection.createQueryRunner(); + + // ManyToOne + const table = await queryRunner.getTable("access_event"); + const column = table!.findColumnByName("employeeProvider"); + expect(column!.enum).to.deep.equal([ "msGraph", "atlassian" ]); + + // ManyToMany + const table2 = await queryRunner.getTable("access_event_employees_employee"); + const column2 = table2!.findColumnByName("employeeProvider"); + expect(column2!.enum).to.deep.equal([ "msGraph", "atlassian" ]); + + await queryRunner.release(); + }))); +}); diff --git a/test/github-issues/7401/issue-7401.ts b/test/github-issues/7401/issue-7401.ts new file mode 100644 index 0000000000..45583509bb --- /dev/null +++ b/test/github-issues/7401/issue-7401.ts @@ -0,0 +1,18 @@ +import "reflect-metadata"; +import { DriverUtils } from "../../../src/driver/DriverUtils" +import { expect } from "chai"; + +describe("github issues > #7401 MongoDB replica set connection string not support with method \"parseConnectionUrl\" & \"buildConnectionUrl\"", () => { + + it("should parse replicaSet and host list in ConnectionUrl", () => { + + var options = DriverUtils.buildMongoDBDriverOptions({url: "mongodb://testuser:testpwd@test-primary.example.com:27017,test-secondary-1.example.com:27017,test-secondary-2.example.com:27017/testdb?replicaSet=testreplicaset"}) + + expect((options.hostReplicaSet ? options.hostReplicaSet as string : '')).to.equal('test-primary.example.com:27017,test-secondary-1.example.com:27017,test-secondary-2.example.com:27017'); + expect((options.username ? options.username as string : '')).to.equal('testuser'); + expect((options.password ? options.password as string : '')).to.equal('testpwd'); + expect((options.database ? options.database as string : '')).to.equal('testdb'); + expect((options.replicaSet ? options.replicaSet as string : '')).to.equal('testreplicaset'); + }); + +}); \ No newline at end of file diff --git a/test/github-issues/7415/entity/Category.ts b/test/github-issues/7415/entity/Category.ts new file mode 100644 index 0000000000..a40abf59e0 --- /dev/null +++ b/test/github-issues/7415/entity/Category.ts @@ -0,0 +1,26 @@ +import { + Column, + Entity, + Tree, + TreeChildren, + TreeParent, +} from "../../../../src"; +import { Slug } from "./Slug"; + +@Entity() +@Tree("materialized-path") +export class Category { + @Column((type) => Slug, { prefix: false }) + id: Slug; + + @TreeChildren() + children: Category[]; + + @TreeParent() + parent: Category; + + constructor(slug: string, parent?: Category) { + this.id = new Slug(slug); + if (parent) this.parent = parent; + } +} diff --git a/test/github-issues/7415/entity/Slug.ts b/test/github-issues/7415/entity/Slug.ts new file mode 100644 index 0000000000..d79ab69f4a --- /dev/null +++ b/test/github-issues/7415/entity/Slug.ts @@ -0,0 +1,10 @@ +import { PrimaryColumn } from "../../../../src"; + +export class Slug { + @PrimaryColumn() + slug: string; + + constructor(slug: string) { + this.slug = slug; + } +} diff --git a/test/github-issues/7415/issue-7415.ts b/test/github-issues/7415/issue-7415.ts new file mode 100644 index 0000000000..2e8e25c390 --- /dev/null +++ b/test/github-issues/7415/issue-7415.ts @@ -0,0 +1,87 @@ +import "reflect-metadata"; +import { + createTestingConnections, + closeTestingConnections, + reloadTestingDatabases, +} from "../../utils/test-utils"; +import { Connection } from "../../../src/connection/Connection"; +import { Category } from "./entity/Category"; +import { Slug } from "./entity/Slug"; +import { expect } from "chai"; + +describe("github issues > #7415 Tree entities with embedded primary columns are not built correctly", () => { + 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 build tree entities with embedded primary columns correctly", () => + Promise.all( + connections.map(async (connection) => { + const manager = connection.manager; + + const a1 = new Category("1"); + await manager.save(a1); + + const a2 = new Category("2"); + await manager.save(a2); + + const a11 = new Category("1.1", a1); + await manager.save(a11); + + const a12 = new Category("1.2", a1); + await manager.save(a12); + + const a13 = new Category("1.3", a1); + await manager.save(a13); + + const a121 = new Category("1.2.1", a12); + await manager.save(a121); + + const a122 = new Category("1.2.2", a12); + await manager.save(a122); + + const repository = manager.getTreeRepository(Category); + + const descendantsTree = await repository.findDescendantsTree( + a1 + ); + + const expectedDescendantsTree = { + id: new Slug("1"), + children: [ + { id: new Slug("1.1"), children: [] }, + { + id: new Slug("1.2"), + children: [ + { id: new Slug("1.2.1"), children: [] }, + { id: new Slug("1.2.2"), children: [] }, + ], + }, + { id: new Slug("1.3"), children: [] }, + ], + }; + + expect(descendantsTree).to.be.eql(expectedDescendantsTree); + + const ancestorsTree = await repository.findAncestorsTree(a121); + + const expectedAncestorsTree = { + id: new Slug("1.2.1"), + parent: { + id: new Slug("1.2"), + parent: { id: new Slug("1") }, + }, + }; + + expect(ancestorsTree).to.be.eql(expectedAncestorsTree); + }) + )); +}); diff --git a/test/github-issues/7437/issue-7437.ts b/test/github-issues/7437/issue-7437.ts new file mode 100644 index 0000000000..64eab8e4fa --- /dev/null +++ b/test/github-issues/7437/issue-7437.ts @@ -0,0 +1,22 @@ +import "reflect-metadata"; +import { DriverUtils } from "../../../src/driver/DriverUtils" +import { expect } from "chai"; + +describe("github issues > #7437 MongoDB options never parse in connectionUrl and after my fix was parse incorrect", () => { + + it("should parse options in ConnectionUrl", () => { + + var options = DriverUtils.buildMongoDBDriverOptions({url: "mongodb://testuser:testpwd@test-primary.example.com:27017/testdb?retryWrites=true&w=majority&useUnifiedTopology=true"}) + + expect((options.host ? options.host as string : '')).to.equal('test-primary.example.com'); + expect((options.username ? options.username as string : '')).to.equal('testuser'); + expect((options.password ? options.password as string : '')).to.equal('testpwd'); + expect((options.port ? options.port as number : 0)).to.equal(27017); + expect((options.database ? options.database as string : '')).to.equal('testdb'); + + expect((options.retryWrites ? options.retryWrites as string : '')).to.equal('true'); + expect((options.w ? options.w as string : '')).to.equal('majority'); + expect((options.useUnifiedTopology ? options.useUnifiedTopology as string : '')).to.equal('true'); + }); + +}); \ No newline at end of file diff --git a/test/integration/sample2-one-to-one.ts b/test/integration/sample2-one-to-one.ts index 303d6de028..29d3cb00cd 100644 --- a/test/integration/sample2-one-to-one.ts +++ b/test/integration/sample2-one-to-one.ts @@ -64,7 +64,7 @@ describe("one-to-one", function() { return; let newPost: Post, details: PostDetails, savedPost: Post; - + before(reloadDatabase); before(function() { @@ -72,7 +72,7 @@ describe("one-to-one", function() { details.authorName = "Umed"; details.comment = "this is post"; details.metadata = "post,posting,postman"; - + newPost = new Post(); newPost.text = "Hello post"; newPost.title = "this is post title"; @@ -85,12 +85,12 @@ describe("one-to-one", function() { }); it("should return the same post details instance after its created", function () { - savedPost.details.should.be.equal(newPost.details); + savedPost.details!.should.be.equal(newPost.details); }); it("should have a new generated id after post is created", function () { expect(savedPost.id).not.to.be.undefined; - expect(savedPost.details.id).not.to.be.undefined; + expect(savedPost.details!.id).not.to.be.undefined; }); it("should have inserted post in the database", function() { @@ -100,7 +100,7 @@ describe("one-to-one", function() { expectedPost.id = savedPost.id; expectedPost.text = savedPost.text; expectedPost.title = savedPost.title; - + return postRepository.findOne(savedPost.id).should.eventually.eql(expectedPost); }); @@ -108,12 +108,12 @@ describe("one-to-one", function() { if (!connection) return; const expectedDetails = new PostDetails(); - expectedDetails.id = savedPost.details.id; - expectedDetails.authorName = savedPost.details.authorName; - expectedDetails.comment = savedPost.details.comment; - expectedDetails.metadata = savedPost.details.metadata; + expectedDetails.id = savedPost.details!.id; + expectedDetails.authorName = savedPost.details!.authorName; + expectedDetails.comment = savedPost.details!.comment; + expectedDetails.metadata = savedPost.details!.metadata; - const loadedPostDetails = await postDetailsRepository.findOne(savedPost.details.id); + const loadedPostDetails = await postDetailsRepository.findOne(savedPost.details!.id); loadedPostDetails!.should.be.eql(expectedDetails); }); @@ -125,11 +125,11 @@ describe("one-to-one", function() { expectedPost.text = savedPost.text; expectedPost.title = savedPost.title; expectedPost.details = new PostDetails(); - expectedPost.details.id = savedPost.details.id; - expectedPost.details.authorName = savedPost.details.authorName; - expectedPost.details.comment = savedPost.details.comment; - expectedPost.details.metadata = savedPost.details.metadata; - + expectedPost.details!.id = savedPost.details!.id; + expectedPost.details!.authorName = savedPost.details!.authorName; + expectedPost.details!.comment = savedPost.details!.comment; + expectedPost.details!.metadata = savedPost.details!.metadata; + const post = await postRepository .createQueryBuilder("post") .leftJoinAndSelect("post.details", "details") @@ -146,16 +146,16 @@ describe("one-to-one", function() { return; const expectedDetails = new PostDetails(); - expectedDetails.id = savedPost.details.id; - expectedDetails.authorName = savedPost.details.authorName; - expectedDetails.comment = savedPost.details.comment; - expectedDetails.metadata = savedPost.details.metadata; + expectedDetails.id = savedPost.details!.id; + expectedDetails.authorName = savedPost.details!.authorName; + expectedDetails.comment = savedPost.details!.comment; + expectedDetails.metadata = savedPost.details!.metadata; expectedDetails.post = new Post(); expectedDetails.post.id = savedPost.id; expectedDetails.post.text = savedPost.text; expectedDetails.post.title = savedPost.title; - + return postDetailsRepository .createQueryBuilder("details") .leftJoinAndSelect("details.post", "post") @@ -170,7 +170,7 @@ describe("one-to-one", function() { expectedPost.id = savedPost.id; expectedPost.text = savedPost.text; expectedPost.title = savedPost.title; - + return postRepository .createQueryBuilder("post") .where("post.id=:id", { id: savedPost.id }) @@ -180,11 +180,11 @@ describe("one-to-one", function() { it("should load saved post without details if left joins are not specified", function() { const expectedDetails = new PostDetails(); - expectedDetails.id = savedPost.details.id; - expectedDetails.authorName = savedPost.details.authorName; - expectedDetails.comment = savedPost.details.comment; - expectedDetails.metadata = savedPost.details.metadata; - + expectedDetails.id = savedPost.details!.id; + expectedDetails.authorName = savedPost.details!.authorName; + expectedDetails.comment = savedPost.details!.comment; + expectedDetails.metadata = savedPost.details!.metadata; + return postDetailsRepository .createQueryBuilder("details") .where("details.id=:id", { id: savedPost.id }) @@ -268,7 +268,7 @@ describe("one-to-one", function() { .getSingleResult() .should.be.rejectedWith(Error);*/ // not working, find fix }); - + }); describe("cascade updates should not be executed when cascadeUpdate option is not set", function() { @@ -294,7 +294,7 @@ describe("one-to-one", function() { }); it("should ignore updates in the model and do not update the db when entity is updated", function () { - newPost.details.comment = "i am updated comment"; + newPost.details!.comment = "i am updated comment"; return postRepository.save(newPost).then(updatedPost => { updatedPost.details!.comment!.should.be.equal("i am updated comment"); return postRepository @@ -304,7 +304,7 @@ describe("one-to-one", function() { .setParameter("id", updatedPost.id) .getOne(); }).then(updatedPostReloaded => { - updatedPostReloaded!.details.comment.should.be.equal("this is post"); + updatedPostReloaded!.details!.comment.should.be.equal("this is post"); }); }); // todo: also check that updates throw exception in strict cascades mode }); @@ -343,7 +343,7 @@ describe("one-to-one", function() { .setParameter("id", updatedPost.id) .getOne(); }).then(updatedPostReloaded => { - updatedPostReloaded!.details.comment.should.be.equal("this is post"); + updatedPostReloaded!.details!.comment.should.be.equal("this is post"); }); }); }); @@ -391,7 +391,7 @@ describe("one-to-one", function() { .where("post.id=:id") .setParameter("id", newPost.id) .getOne(); - + }).then(reloadedPost => { reloadedPost!.image.url.should.be.equal("new-logo.png"); }); diff --git a/test/integration/sample3-many-to-one.ts b/test/integration/sample3-many-to-one.ts index e8c96d6b33..3c83681971 100644 --- a/test/integration/sample3-many-to-one.ts +++ b/test/integration/sample3-many-to-one.ts @@ -62,7 +62,7 @@ describe("many-to-one", function() { if (!connection) return; let newPost: Post, details: PostDetails, savedPost: Post; - + before(reloadDatabase); before(function() { @@ -70,7 +70,7 @@ describe("many-to-one", function() { details.authorName = "Umed"; details.comment = "this is post"; details.metadata = "post,posting,postman"; - + newPost = new Post(); newPost.text = "Hello post"; newPost.title = "this is post title"; @@ -83,12 +83,12 @@ describe("many-to-one", function() { }); it("should return the same post details instance after its created", function () { - savedPost.details.should.be.equal(newPost.details); + savedPost.details!.should.be.equal(newPost.details); }); it("should have a new generated id after post is created", function () { expect(savedPost.id).not.to.be.undefined; - expect(savedPost.details.id).not.to.be.undefined; + expect(savedPost.details!.id).not.to.be.undefined; }); it("should have inserted post in the database", function() { @@ -98,7 +98,7 @@ describe("many-to-one", function() { expectedPost.id = savedPost.id; expectedPost.text = savedPost.text; expectedPost.title = savedPost.title; - + return postRepository.findOne(savedPost.id).should.eventually.eql(expectedPost); }); @@ -106,12 +106,12 @@ describe("many-to-one", function() { if (!connection) return; const expectedDetails = new PostDetails(); - expectedDetails.id = savedPost.details.id; - expectedDetails.authorName = savedPost.details.authorName; - expectedDetails.comment = savedPost.details.comment; - expectedDetails.metadata = savedPost.details.metadata; - - return postDetailsRepository.findOne(savedPost.details.id).should.eventually.eql(expectedDetails); + expectedDetails.id = savedPost.details!.id; + expectedDetails.authorName = savedPost.details!.authorName; + expectedDetails.comment = savedPost.details!.comment; + expectedDetails.metadata = savedPost.details!.metadata; + + return postDetailsRepository.findOne(savedPost.details!.id).should.eventually.eql(expectedDetails); }); it("should load post and its details if left join used", function() { @@ -122,11 +122,11 @@ describe("many-to-one", function() { expectedPost.text = savedPost.text; expectedPost.title = savedPost.title; expectedPost.details = new PostDetails(); - expectedPost.details.id = savedPost.details.id; - expectedPost.details.authorName = savedPost.details.authorName; - expectedPost.details.comment = savedPost.details.comment; - expectedPost.details.metadata = savedPost.details.metadata; - + expectedPost.details.id = savedPost.details!.id; + expectedPost.details.authorName = savedPost.details!.authorName; + expectedPost.details.comment = savedPost.details!.comment; + expectedPost.details.metadata = savedPost.details!.metadata; + return postRepository .createQueryBuilder("post") .leftJoinAndSelect("post.details", "details") @@ -141,19 +141,19 @@ describe("many-to-one", function() { return; const expectedDetails = new PostDetails(); - expectedDetails.id = savedPost.details.id; - expectedDetails.authorName = savedPost.details.authorName; - expectedDetails.comment = savedPost.details.comment; - expectedDetails.metadata = savedPost.details.metadata; + expectedDetails.id = savedPost.details!.id; + expectedDetails.authorName = savedPost.details!.authorName; + expectedDetails.comment = savedPost.details!.comment; + expectedDetails.metadata = savedPost.details!.metadata; const expectedPost = new Post(); expectedPost.id = savedPost.id; expectedPost.text = savedPost.text; expectedPost.title = savedPost.title; - + expectedDetails.posts = []; expectedDetails.posts.push(expectedPost); - + return postDetailsRepository .createQueryBuilder("details") .leftJoinAndSelect("details.posts", "posts") @@ -170,7 +170,7 @@ describe("many-to-one", function() { expectedPost.id = savedPost.id; expectedPost.text = savedPost.text; expectedPost.title = savedPost.title; - + return postRepository .createQueryBuilder("post") .where("post.id=:id", { id: savedPost.id }) @@ -182,11 +182,11 @@ describe("many-to-one", function() { if (!connection) return; const expectedDetails = new PostDetails(); - expectedDetails.id = savedPost.details.id; - expectedDetails.authorName = savedPost.details.authorName; - expectedDetails.comment = savedPost.details.comment; - expectedDetails.metadata = savedPost.details.metadata; - + expectedDetails.id = savedPost.details!.id; + expectedDetails.authorName = savedPost.details!.authorName; + expectedDetails.comment = savedPost.details!.comment; + expectedDetails.metadata = savedPost.details!.metadata; + return postDetailsRepository .createQueryBuilder("details") .where("details.id=:id", { id: savedPost.id }) @@ -275,7 +275,7 @@ describe("many-to-one", function() { .getSingleResult() .should.be.rejectedWith(Error);*/ // not working, find fix }); - + }); describe("cascade updates should not be executed when cascadeUpdate option is not set", function() { @@ -301,7 +301,7 @@ describe("many-to-one", function() { }); it("should ignore updates in the model and do not update the db when entity is updated", function () { - newPost.details.comment = "i am updated comment"; + newPost.details!.comment = "i am updated comment"; return postRepository.save(newPost).then(updatedPost => { updatedPost.details!.comment!.should.be.equal("i am updated comment"); return postRepository @@ -311,7 +311,7 @@ describe("many-to-one", function() { .setParameter("id", updatedPost.id) .getOne(); }).then(updatedPostReloaded => { - updatedPostReloaded!.details.comment!.should.be.equal("this is post"); + updatedPostReloaded!.details!.comment!.should.be.equal("this is post"); }); }); // todo: also check that updates throw exception in strict cascades mode }); @@ -348,7 +348,7 @@ describe("many-to-one", function() { .setParameter("id", updatedPost.id) .getOne(); }).then(updatedPostReloaded => { - updatedPostReloaded!.details.comment!.should.be.equal("this is post"); + updatedPostReloaded!.details!.comment!.should.be.equal("this is post"); }); }); }); @@ -395,7 +395,7 @@ describe("many-to-one", function() { .where("post.id=:id") .setParameter("id", newPost.id) .getOne(); - + }).then(reloadedPost => { reloadedPost!.image.url.should.be.equal("new-logo.png"); }); diff --git a/test/other-issues/table-name-relation/entity/Category.ts b/test/other-issues/table-name-relation/entity/Category.ts new file mode 100644 index 0000000000..efc5ee2e8a --- /dev/null +++ b/test/other-issues/table-name-relation/entity/Category.ts @@ -0,0 +1,12 @@ +import {Entity, PrimaryGeneratedColumn, Column} from "../../../../src"; + +@Entity("categories") +export class Category { + + @PrimaryGeneratedColumn() + id: number; + + @Column() + name: string; + +} diff --git a/test/other-issues/table-name-relation/entity/Photo.ts b/test/other-issues/table-name-relation/entity/Photo.ts new file mode 100644 index 0000000000..8c360ea51f --- /dev/null +++ b/test/other-issues/table-name-relation/entity/Photo.ts @@ -0,0 +1,16 @@ +import {Entity, PrimaryGeneratedColumn, Column, ManyToOne} from "../../../../src"; +import {User} from "./User"; + +@Entity("photographs") +export class Photo { + + @PrimaryGeneratedColumn() + id: number; + + @Column() + url: string; + + @ManyToOne("users", "photos") + user: User; + +} diff --git a/test/other-issues/table-name-relation/entity/Profile.ts b/test/other-issues/table-name-relation/entity/Profile.ts new file mode 100644 index 0000000000..6b2871a59d --- /dev/null +++ b/test/other-issues/table-name-relation/entity/Profile.ts @@ -0,0 +1,15 @@ +import {Entity, PrimaryGeneratedColumn, Column} from "../../../../src"; + +@Entity("profiles") +export class Profile { + + @PrimaryGeneratedColumn() + id: number; + + @Column() + gender: string; + + @Column() + photo: string; + +} diff --git a/test/other-issues/table-name-relation/entity/Question.ts b/test/other-issues/table-name-relation/entity/Question.ts new file mode 100644 index 0000000000..cc8f24c00e --- /dev/null +++ b/test/other-issues/table-name-relation/entity/Question.ts @@ -0,0 +1,18 @@ +import {Entity, PrimaryGeneratedColumn, ManyToMany, JoinTable} from "../../../../src"; +import {Column} from "../../../../src/decorator/columns/Column"; +import {Category} from "./Category"; + +@Entity("questions") +export class Question { + + @PrimaryGeneratedColumn() + id: number; + + @Column() + name: string; + + @ManyToMany("categories") + @JoinTable() + categories: Category[]; + +} diff --git a/test/other-issues/table-name-relation/entity/User.ts b/test/other-issues/table-name-relation/entity/User.ts new file mode 100644 index 0000000000..e601e4a2c5 --- /dev/null +++ b/test/other-issues/table-name-relation/entity/User.ts @@ -0,0 +1,21 @@ +import {Entity, PrimaryGeneratedColumn, Column, OneToMany, OneToOne, JoinColumn} from "../../../../src"; +import {Photo} from "./Photo"; +import {Profile} from "./Profile"; + +@Entity("users") +export class User { + + @PrimaryGeneratedColumn() + id: number; + + @Column() + name: string; + + @OneToMany("photographs", "user") + photos: Photo[]; + + @OneToOne("profiles") + @JoinColumn() + profile: Profile; + +} diff --git a/test/other-issues/table-name-relation/table-name-relation.ts b/test/other-issues/table-name-relation/table-name-relation.ts new file mode 100644 index 0000000000..af3c16cfd8 --- /dev/null +++ b/test/other-issues/table-name-relation/table-name-relation.ts @@ -0,0 +1,130 @@ +import "reflect-metadata"; +import {createTestingConnections, closeTestingConnections, reloadTestingDatabases} from "../../utils/test-utils"; +import {Connection} from "../../../src/connection/Connection"; + +import {Photo} from "./entity/Photo"; +import {User} from "./entity/User"; +import {Profile} from "./entity/Profile"; +import {Category} from "./entity/Category"; +import {Question} from "./entity/Question"; + +describe("other issues > Relation decorators: allow to pass given table name string instead of typeFunction or entity name", () => { + + 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 work with one-to-one relations", () => Promise.all(connections.map(async connection => { + + const profile = new Profile(); + profile.gender = "male"; + profile.photo = "me.jpg"; + await connection.manager.save(profile); + + const user = new User(); + user.name = "Joe Smith"; + user.profile = profile; + await connection.manager.save(user); + + const users = await connection.manager.find(User, { relations: ["profile"] }); + + users.should.eql([{ + id: 1, + name: "Joe Smith", + profile: { + id: 1, + gender: "male", + photo: "me.jpg" + } + }]); + + }))); + + it("should work with many-to-one/one-to-many relations", () => Promise.all(connections.map(async connection => { + + const photo1 = new Photo(); + photo1.url = "me.jpg"; + await connection.manager.save(photo1); + + const photo2 = new Photo(); + photo2.url = "me-and-bears.jpg"; + await connection.manager.save(photo2); + + const user = new User(); + user.name = "John"; + user.photos = [photo1, photo2]; + await connection.manager.save(user); + + const users = await connection.manager.find(User, { relations: ["photos"] }); + const photos = await connection.manager.find(Photo, { relations: ["user"] }); + + // Check one-to-many + users[0].photos.should.have.deep.members([ + { + id: 1, + url: "me.jpg" + }, + { + id: 2, + url: "me-and-bears.jpg" + } + ]); + + // Check many-to-one + photos.should.have.deep.members([ + { + id: 1, + url: "me.jpg", + user: { + id: 1, + name: "John" + } + }, + { + id: 2, + url: "me-and-bears.jpg", + user: { + id: 1, + name: "John" + } + } + ]); + + }))); + + it("should work with many-to-many relations", () => Promise.all(connections.map(async connection => { + + const category1 = new Category(); + category1.name = "animals"; + await connection.manager.save(category1); + + const category2 = new Category(); + category2.name = "zoo"; + await connection.manager.save(category2); + + const question = new Question(); + question.name = "About animals"; + question.categories = [category1, category2]; + await connection.manager.save(question); + + const questions = await connection.manager.find(Question, { relations: ["categories"] }); + + questions[0].categories.should.have.deep.members([ + { + id: 1, + name: "animals" + }, + { + id: 2, + name: "zoo" + } + ]); + + }))); + +});