mirror of
https://github.com/typeorm/typeorm.git
synced 2025-12-08 21:26:23 +00:00
fix: add stricter type-checking and improve event loop handling (#11540)
* refactor: minor type improvements * chore: add type-checked eslint rules * fix: enable no-misused-promises * fix: enable no-floating-promises * fix: enable await-thenable * fix: enable require-await * fix: enable no-misused-new * refactor: enable no-namespace * refactor: enable tseslint eslint recommended * code review
This commit is contained in:
parent
abf8863a53
commit
01dddfef97
@ -4,7 +4,13 @@ import globals from "globals"
|
||||
|
||||
export default tseslint.config([
|
||||
{
|
||||
ignores: ["build/**", "node_modules/**", "sample/playground/**", "docs/**"],
|
||||
ignores: [
|
||||
"build/**",
|
||||
"docs/**",
|
||||
"node_modules/**",
|
||||
"sample/playground/**",
|
||||
"temp/**",
|
||||
],
|
||||
},
|
||||
{
|
||||
files: ["**/*.ts"],
|
||||
@ -18,14 +24,15 @@ export default tseslint.config([
|
||||
...globals.node,
|
||||
},
|
||||
},
|
||||
extends: [eslint.configs.recommended, ...tseslint.configs.recommended],
|
||||
extends: [
|
||||
eslint.configs.recommended,
|
||||
...tseslint.configs.recommendedTypeChecked,
|
||||
],
|
||||
rules: {
|
||||
// exceptions
|
||||
// exceptions from typescript-eslint/recommended
|
||||
"@typescript-eslint/ban-ts-comment": "warn",
|
||||
"@typescript-eslint/no-empty-object-type": "warn",
|
||||
"@typescript-eslint/no-explicit-any": "warn",
|
||||
"@typescript-eslint/no-misused-new": "warn",
|
||||
"@typescript-eslint/no-namespace": "warn",
|
||||
"@typescript-eslint/no-require-imports": "warn",
|
||||
"@typescript-eslint/no-this-alias": "warn",
|
||||
"@typescript-eslint/no-unnecessary-type-constraint": "warn",
|
||||
@ -36,21 +43,41 @@ export default tseslint.config([
|
||||
"warn",
|
||||
{ argsIgnorePattern: "^_" },
|
||||
],
|
||||
"@typescript-eslint/no-wrapper-object-types": "warn",
|
||||
"@typescript-eslint/triple-slash-reference": "warn",
|
||||
"@typescript-eslint/no-wrapper-object-types": "off",
|
||||
"prefer-const": ["error", { destructuring: "all" }],
|
||||
|
||||
// exceptions from typescript-eslint/recommended-type-checked
|
||||
"@typescript-eslint/no-base-to-string": "off",
|
||||
"@typescript-eslint/no-misused-promises": [
|
||||
"error",
|
||||
{
|
||||
checksConditionals: false,
|
||||
checksVoidReturn: false,
|
||||
},
|
||||
],
|
||||
"@typescript-eslint/no-redundant-type-constituents": "warn",
|
||||
"@typescript-eslint/no-unnecessary-type-assertion": "off",
|
||||
"@typescript-eslint/no-unsafe-argument": "off",
|
||||
"@typescript-eslint/no-unsafe-assignment": "off",
|
||||
"@typescript-eslint/no-unsafe-call": "off",
|
||||
"@typescript-eslint/no-unsafe-member-access": "off",
|
||||
"@typescript-eslint/no-unsafe-return": "off",
|
||||
"@typescript-eslint/prefer-promise-reject-errors": "off",
|
||||
"@typescript-eslint/require-await": "warn",
|
||||
"@typescript-eslint/restrict-plus-operands": "warn",
|
||||
"@typescript-eslint/restrict-template-expressions": "warn",
|
||||
"@typescript-eslint/unbound-method": [
|
||||
"warn",
|
||||
{ ignoreStatic: true },
|
||||
],
|
||||
|
||||
// exceptions for eslint/recommended
|
||||
"no-async-promise-executor": "warn",
|
||||
"no-control-regex": "warn",
|
||||
"no-empty": "warn",
|
||||
"no-loss-of-precision": "warn",
|
||||
"no-prototype-builtins": "warn",
|
||||
"no-regex-spaces": "warn",
|
||||
|
||||
// custom
|
||||
"prefer-const": "warn",
|
||||
"prefer-rest-params": "warn",
|
||||
"prefer-spread": "warn",
|
||||
// deprecated: stylistic
|
||||
"no-extra-semi": "warn",
|
||||
},
|
||||
},
|
||||
])
|
||||
|
||||
209
package-lock.json
generated
209
package-lock.json
generated
@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "typeorm",
|
||||
"version": "0.3.24",
|
||||
"version": "0.3.25",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "typeorm",
|
||||
"version": "0.3.24",
|
||||
"version": "0.3.25",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@sqltools/formatter": "^1.2.5",
|
||||
@ -30,7 +30,7 @@
|
||||
"typeorm-ts-node-esm": "cli-ts-node-esm.js"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.28.0",
|
||||
"@eslint/js": "^9.29.0",
|
||||
"@sap/hana-client": "^2.25.22",
|
||||
"@tsconfig/node16": "^16.1.4",
|
||||
"@types/chai": "^4.3.20",
|
||||
@ -49,7 +49,7 @@
|
||||
"chai": "^4.5.0",
|
||||
"chai-as-promised": "^7.1.2",
|
||||
"class-transformer": "^0.5.1",
|
||||
"eslint": "^9.28.0",
|
||||
"eslint": "^9.29.0",
|
||||
"globals": "^16.2.0",
|
||||
"gulp": "^4.0.2",
|
||||
"gulp-rename": "^2.0.0",
|
||||
@ -73,6 +73,7 @@
|
||||
"pkg-pr-new": "^0.0.43",
|
||||
"prettier": "^2.8.8",
|
||||
"redis": "^4.7.0",
|
||||
"reflect-metadata": "^0.2.2",
|
||||
"remap-istanbul": "^0.13.0",
|
||||
"rimraf": "^5.0.10",
|
||||
"sinon": "^15.2.0",
|
||||
@ -84,7 +85,7 @@
|
||||
"standard-changelog": "^6.0.0",
|
||||
"ts-node": "^10.9.2",
|
||||
"typescript": "^5.8.3",
|
||||
"typescript-eslint": "^8.33.1"
|
||||
"typescript-eslint": "^8.34.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.13.0"
|
||||
@ -1531,9 +1532,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint/config-array": {
|
||||
"version": "0.20.0",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.20.0.tgz",
|
||||
"integrity": "sha512-fxlS1kkIjx8+vy2SjuCB94q3htSNrufYTXubwiBFeaQHbH6Ipi43gFJq2zCMt6PHhImH3Xmr0NksKDvchWlpQQ==",
|
||||
"version": "0.20.1",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.20.1.tgz",
|
||||
"integrity": "sha512-OL0RJzC/CBzli0DrrR31qzj6d6i6Mm3HByuhflhl4LOBiWxN+3i6/t/ZQQNii4tjksXi8r2CRW1wMpWA2ULUEw==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
@ -1606,9 +1607,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint/js": {
|
||||
"version": "9.28.0",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.28.0.tgz",
|
||||
"integrity": "sha512-fnqSjGWd/CoIp4EXIxWVK/sHA6DOHN4+8Ix2cX5ycOY7LG0UY8nHCU5pIp2eaE1Mc7Qd8kHspYNzYXT2ojPLzg==",
|
||||
"version": "9.29.0",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.29.0.tgz",
|
||||
"integrity": "sha512-3PIF4cBw/y+1u2EazflInpV+lYsSG0aByVIQzAgb1m1MhHFSbqTyNqtBKHgWf/9Ykud+DhILS9EGkmekVhbKoQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@ -3682,17 +3683,17 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||
"version": "8.33.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.33.1.tgz",
|
||||
"integrity": "sha512-TDCXj+YxLgtvxvFlAvpoRv9MAncDLBV2oT9Bd7YBGC/b/sEURoOYuIwLI99rjWOfY3QtDzO+mk0n4AmdFExW8A==",
|
||||
"version": "8.34.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.34.1.tgz",
|
||||
"integrity": "sha512-STXcN6ebF6li4PxwNeFnqF8/2BNDvBupf2OPx2yWNzr6mKNGF7q49VM00Pz5FaomJyqvbXpY6PhO+T9w139YEQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@eslint-community/regexpp": "^4.10.0",
|
||||
"@typescript-eslint/scope-manager": "8.33.1",
|
||||
"@typescript-eslint/type-utils": "8.33.1",
|
||||
"@typescript-eslint/utils": "8.33.1",
|
||||
"@typescript-eslint/visitor-keys": "8.33.1",
|
||||
"@typescript-eslint/scope-manager": "8.34.1",
|
||||
"@typescript-eslint/type-utils": "8.34.1",
|
||||
"@typescript-eslint/utils": "8.34.1",
|
||||
"@typescript-eslint/visitor-keys": "8.34.1",
|
||||
"graphemer": "^1.4.0",
|
||||
"ignore": "^7.0.0",
|
||||
"natural-compare": "^1.4.0",
|
||||
@ -3706,7 +3707,7 @@
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@typescript-eslint/parser": "^8.33.1",
|
||||
"@typescript-eslint/parser": "^8.34.1",
|
||||
"eslint": "^8.57.0 || ^9.0.0",
|
||||
"typescript": ">=4.8.4 <5.9.0"
|
||||
}
|
||||
@ -3722,16 +3723,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/parser": {
|
||||
"version": "8.33.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.33.1.tgz",
|
||||
"integrity": "sha512-qwxv6dq682yVvgKKp2qWwLgRbscDAYktPptK4JPojCwwi3R9cwrvIxS4lvBpzmcqzR4bdn54Z0IG1uHFskW4dA==",
|
||||
"version": "8.34.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.34.1.tgz",
|
||||
"integrity": "sha512-4O3idHxhyzjClSMJ0a29AcoK0+YwnEqzI6oz3vlRf3xw0zbzt15MzXwItOlnr5nIth6zlY2RENLsOPvhyrKAQA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": "8.33.1",
|
||||
"@typescript-eslint/types": "8.33.1",
|
||||
"@typescript-eslint/typescript-estree": "8.33.1",
|
||||
"@typescript-eslint/visitor-keys": "8.33.1",
|
||||
"@typescript-eslint/scope-manager": "8.34.1",
|
||||
"@typescript-eslint/types": "8.34.1",
|
||||
"@typescript-eslint/typescript-estree": "8.34.1",
|
||||
"@typescript-eslint/visitor-keys": "8.34.1",
|
||||
"debug": "^4.3.4"
|
||||
},
|
||||
"engines": {
|
||||
@ -3747,14 +3748,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/project-service": {
|
||||
"version": "8.33.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.33.1.tgz",
|
||||
"integrity": "sha512-DZR0efeNklDIHHGRpMpR5gJITQpu6tLr9lDJnKdONTC7vvzOlLAG/wcfxcdxEWrbiZApcoBCzXqU/Z458Za5Iw==",
|
||||
"version": "8.34.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.34.1.tgz",
|
||||
"integrity": "sha512-nuHlOmFZfuRwLJKDGQOVc0xnQrAmuq1Mj/ISou5044y1ajGNp2BNliIqp7F2LPQ5sForz8lempMFCovfeS1XoA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/tsconfig-utils": "^8.33.1",
|
||||
"@typescript-eslint/types": "^8.33.1",
|
||||
"@typescript-eslint/tsconfig-utils": "^8.34.1",
|
||||
"@typescript-eslint/types": "^8.34.1",
|
||||
"debug": "^4.3.4"
|
||||
},
|
||||
"engines": {
|
||||
@ -3769,14 +3770,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/scope-manager": {
|
||||
"version": "8.33.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.33.1.tgz",
|
||||
"integrity": "sha512-dM4UBtgmzHR9bS0Rv09JST0RcHYearoEoo3pG5B6GoTR9XcyeqX87FEhPo+5kTvVfKCvfHaHrcgeJQc6mrDKrA==",
|
||||
"version": "8.34.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.34.1.tgz",
|
||||
"integrity": "sha512-beu6o6QY4hJAgL1E8RaXNC071G4Kso2MGmJskCFQhRhg8VOH/FDbC8soP8NHN7e/Hdphwp8G8cE6OBzC8o41ZA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "8.33.1",
|
||||
"@typescript-eslint/visitor-keys": "8.33.1"
|
||||
"@typescript-eslint/types": "8.34.1",
|
||||
"@typescript-eslint/visitor-keys": "8.34.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
@ -3787,9 +3788,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/tsconfig-utils": {
|
||||
"version": "8.33.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.33.1.tgz",
|
||||
"integrity": "sha512-STAQsGYbHCF0/e+ShUQ4EatXQ7ceh3fBCXkNU7/MZVKulrlq1usH7t2FhxvCpuCi5O5oi1vmVaAjrGeL71OK1g==",
|
||||
"version": "8.34.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.34.1.tgz",
|
||||
"integrity": "sha512-K4Sjdo4/xF9NEeA2khOb7Y5nY6NSXBnod87uniVYW9kHP+hNlDV8trUSFeynA2uxWam4gIWgWoygPrv9VMWrYg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@ -3804,14 +3805,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/type-utils": {
|
||||
"version": "8.33.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.33.1.tgz",
|
||||
"integrity": "sha512-1cG37d9xOkhlykom55WVwG2QRNC7YXlxMaMzqw2uPeJixBFfKWZgaP/hjAObqMN/u3fr5BrTwTnc31/L9jQ2ww==",
|
||||
"version": "8.34.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.34.1.tgz",
|
||||
"integrity": "sha512-Tv7tCCr6e5m8hP4+xFugcrwTOucB8lshffJ6zf1mF1TbU67R+ntCc6DzLNKM+s/uzDyv8gLq7tufaAhIBYeV8g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/typescript-estree": "8.33.1",
|
||||
"@typescript-eslint/utils": "8.33.1",
|
||||
"@typescript-eslint/typescript-estree": "8.34.1",
|
||||
"@typescript-eslint/utils": "8.34.1",
|
||||
"debug": "^4.3.4",
|
||||
"ts-api-utils": "^2.1.0"
|
||||
},
|
||||
@ -3828,9 +3829,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/types": {
|
||||
"version": "8.33.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.33.1.tgz",
|
||||
"integrity": "sha512-xid1WfizGhy/TKMTwhtVOgalHwPtV8T32MS9MaH50Cwvz6x6YqRIPdD2WvW0XaqOzTV9p5xdLY0h/ZusU5Lokg==",
|
||||
"version": "8.34.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.34.1.tgz",
|
||||
"integrity": "sha512-rjLVbmE7HR18kDsjNIZQHxmv9RZwlgzavryL5Lnj2ujIRTeXlKtILHgRNmQ3j4daw7zd+mQgy+uyt6Zo6I0IGA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@ -3842,16 +3843,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/typescript-estree": {
|
||||
"version": "8.33.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.33.1.tgz",
|
||||
"integrity": "sha512-+s9LYcT8LWjdYWu7IWs7FvUxpQ/DGkdjZeE/GGulHvv8rvYwQvVaUZ6DE+j5x/prADUgSbbCWZ2nPI3usuVeOA==",
|
||||
"version": "8.34.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.34.1.tgz",
|
||||
"integrity": "sha512-rjCNqqYPuMUF5ODD+hWBNmOitjBWghkGKJg6hiCHzUvXRy6rK22Jd3rwbP2Xi+R7oYVvIKhokHVhH41BxPV5mA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/project-service": "8.33.1",
|
||||
"@typescript-eslint/tsconfig-utils": "8.33.1",
|
||||
"@typescript-eslint/types": "8.33.1",
|
||||
"@typescript-eslint/visitor-keys": "8.33.1",
|
||||
"@typescript-eslint/project-service": "8.34.1",
|
||||
"@typescript-eslint/tsconfig-utils": "8.34.1",
|
||||
"@typescript-eslint/types": "8.34.1",
|
||||
"@typescript-eslint/visitor-keys": "8.34.1",
|
||||
"debug": "^4.3.4",
|
||||
"fast-glob": "^3.3.2",
|
||||
"is-glob": "^4.0.3",
|
||||
@ -3887,16 +3888,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/utils": {
|
||||
"version": "8.33.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.33.1.tgz",
|
||||
"integrity": "sha512-52HaBiEQUaRYqAXpfzWSR2U3gxk92Kw006+xZpElaPMg3C4PgM+A5LqwoQI1f9E5aZ/qlxAZxzm42WX+vn92SQ==",
|
||||
"version": "8.34.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.34.1.tgz",
|
||||
"integrity": "sha512-mqOwUdZ3KjtGk7xJJnLbHxTuWVn3GO2WZZuM+Slhkun4+qthLdXx32C8xIXbO1kfCECb3jIs3eoxK3eryk7aoQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.7.0",
|
||||
"@typescript-eslint/scope-manager": "8.33.1",
|
||||
"@typescript-eslint/types": "8.33.1",
|
||||
"@typescript-eslint/typescript-estree": "8.33.1"
|
||||
"@typescript-eslint/scope-manager": "8.34.1",
|
||||
"@typescript-eslint/types": "8.34.1",
|
||||
"@typescript-eslint/typescript-estree": "8.34.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
@ -3911,14 +3912,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/visitor-keys": {
|
||||
"version": "8.33.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.33.1.tgz",
|
||||
"integrity": "sha512-3i8NrFcZeeDHJ+7ZUuDkGT+UHq+XoFGsymNK2jZCOHcfEzRQ0BdpRtdpSx/Iyf3MHLWIcLS0COuOPibKQboIiQ==",
|
||||
"version": "8.34.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.34.1.tgz",
|
||||
"integrity": "sha512-xoh5rJ+tgsRKoXnkBPFRLZ7rjKM0AfVbC68UZ/ECXoDbfggb9RbEySN359acY1vS3qZ0jVTVWzbtfapwm5ztxw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "8.33.1",
|
||||
"eslint-visitor-keys": "^4.2.0"
|
||||
"@typescript-eslint/types": "8.34.1",
|
||||
"eslint-visitor-keys": "^4.2.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
@ -3948,9 +3949,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/acorn": {
|
||||
"version": "8.14.0",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz",
|
||||
"integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==",
|
||||
"version": "8.15.0",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
|
||||
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
@ -4724,9 +4725,10 @@
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/brace-expansion": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
|
||||
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
|
||||
"integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"balanced-match": "^1.0.0"
|
||||
}
|
||||
@ -6258,19 +6260,19 @@
|
||||
}
|
||||
},
|
||||
"node_modules/eslint": {
|
||||
"version": "9.28.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.28.0.tgz",
|
||||
"integrity": "sha512-ocgh41VhRlf9+fVpe7QKzwLj9c92fDiqOj8Y3Sd4/ZmVA4Btx4PlUYPq4pp9JDyupkf1upbEXecxL2mwNV7jPQ==",
|
||||
"version": "9.29.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.29.0.tgz",
|
||||
"integrity": "sha512-GsGizj2Y1rCWDu6XoEekL3RLilp0voSePurjZIkxL3wlm5o5EC9VpgaP7lrCvjnkuLvzFBQWB3vWB3K5KQTveQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.2.0",
|
||||
"@eslint-community/regexpp": "^4.12.1",
|
||||
"@eslint/config-array": "^0.20.0",
|
||||
"@eslint/config-array": "^0.20.1",
|
||||
"@eslint/config-helpers": "^0.2.1",
|
||||
"@eslint/core": "^0.14.0",
|
||||
"@eslint/eslintrc": "^3.3.1",
|
||||
"@eslint/js": "9.28.0",
|
||||
"@eslint/js": "9.29.0",
|
||||
"@eslint/plugin-kit": "^0.3.1",
|
||||
"@humanfs/node": "^0.16.6",
|
||||
"@humanwhocodes/module-importer": "^1.0.1",
|
||||
@ -6282,9 +6284,9 @@
|
||||
"cross-spawn": "^7.0.6",
|
||||
"debug": "^4.3.2",
|
||||
"escape-string-regexp": "^4.0.0",
|
||||
"eslint-scope": "^8.3.0",
|
||||
"eslint-visitor-keys": "^4.2.0",
|
||||
"espree": "^10.3.0",
|
||||
"eslint-scope": "^8.4.0",
|
||||
"eslint-visitor-keys": "^4.2.1",
|
||||
"espree": "^10.4.0",
|
||||
"esquery": "^1.5.0",
|
||||
"esutils": "^2.0.2",
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
@ -6319,9 +6321,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-scope": {
|
||||
"version": "8.3.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.3.0.tgz",
|
||||
"integrity": "sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ==",
|
||||
"version": "8.4.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz",
|
||||
"integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==",
|
||||
"dev": true,
|
||||
"license": "BSD-2-Clause",
|
||||
"dependencies": {
|
||||
@ -6336,9 +6338,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-visitor-keys": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz",
|
||||
"integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==",
|
||||
"version": "4.2.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz",
|
||||
"integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
@ -6370,15 +6372,15 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/espree": {
|
||||
"version": "10.3.0",
|
||||
"resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz",
|
||||
"integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==",
|
||||
"version": "10.4.0",
|
||||
"resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz",
|
||||
"integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==",
|
||||
"dev": true,
|
||||
"license": "BSD-2-Clause",
|
||||
"dependencies": {
|
||||
"acorn": "^8.14.0",
|
||||
"acorn": "^8.15.0",
|
||||
"acorn-jsx": "^5.3.2",
|
||||
"eslint-visitor-keys": "^4.2.0"
|
||||
"eslint-visitor-keys": "^4.2.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
@ -10533,9 +10535,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/minimatch/node_modules/brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
||||
"version": "1.1.12",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
|
||||
"integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@ -13305,10 +13307,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/reflect-metadata": {
|
||||
"version": "0.2.1",
|
||||
"resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.1.tgz",
|
||||
"integrity": "sha512-i5lLI6iw9AU3Uu4szRNPPEkomnkjRTaVt9hy/bn5g/oSzekBSMeLZblcjP74AW0vBabqERLLIrz+gR8QYR54Tw==",
|
||||
"peer": true
|
||||
"version": "0.2.2",
|
||||
"resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz",
|
||||
"integrity": "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/regex-not": {
|
||||
"version": "1.0.2",
|
||||
@ -15440,15 +15443,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/typescript-eslint": {
|
||||
"version": "8.33.1",
|
||||
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.33.1.tgz",
|
||||
"integrity": "sha512-AgRnV4sKkWOiZ0Kjbnf5ytTJXMUZQ0qhSVdQtDNYLPLnjsATEYhaO94GlRQwi4t4gO8FfjM6NnikHeKjUm8D7A==",
|
||||
"version": "8.34.1",
|
||||
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.34.1.tgz",
|
||||
"integrity": "sha512-XjS+b6Vg9oT1BaIUfkW3M3LvqZE++rbzAMEHuccCfO/YkP43ha6w3jTEMilQxMF92nVOYCcdjv1ZUhAa1D/0ow==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/eslint-plugin": "8.33.1",
|
||||
"@typescript-eslint/parser": "8.33.1",
|
||||
"@typescript-eslint/utils": "8.33.1"
|
||||
"@typescript-eslint/eslint-plugin": "8.34.1",
|
||||
"@typescript-eslint/parser": "8.34.1",
|
||||
"@typescript-eslint/utils": "8.34.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
|
||||
11
package.json
11
package.json
@ -20,9 +20,9 @@
|
||||
".": {
|
||||
"types": "./index.d.ts",
|
||||
"node": {
|
||||
"types": "./index.d.ts",
|
||||
"import": "./index.mjs",
|
||||
"require": "./index.js",
|
||||
"types": "./index.d.ts"
|
||||
"require": "./index.js"
|
||||
},
|
||||
"browser": {
|
||||
"require": "./index.js",
|
||||
@ -108,7 +108,7 @@
|
||||
"yargs": "^17.7.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.28.0",
|
||||
"@eslint/js": "^9.29.0",
|
||||
"@sap/hana-client": "^2.25.22",
|
||||
"@tsconfig/node16": "^16.1.4",
|
||||
"@types/chai": "^4.3.20",
|
||||
@ -127,7 +127,7 @@
|
||||
"chai": "^4.5.0",
|
||||
"chai-as-promised": "^7.1.2",
|
||||
"class-transformer": "^0.5.1",
|
||||
"eslint": "^9.28.0",
|
||||
"eslint": "^9.29.0",
|
||||
"globals": "^16.2.0",
|
||||
"gulp": "^4.0.2",
|
||||
"gulp-rename": "^2.0.0",
|
||||
@ -151,6 +151,7 @@
|
||||
"pkg-pr-new": "^0.0.43",
|
||||
"prettier": "^2.8.8",
|
||||
"redis": "^4.7.0",
|
||||
"reflect-metadata": "^0.2.2",
|
||||
"remap-istanbul": "^0.13.0",
|
||||
"rimraf": "^5.0.10",
|
||||
"sinon": "^15.2.0",
|
||||
@ -162,7 +163,7 @@
|
||||
"standard-changelog": "^6.0.0",
|
||||
"ts-node": "^10.9.2",
|
||||
"typescript": "^5.8.3",
|
||||
"typescript-eslint": "^8.33.1"
|
||||
"typescript-eslint": "^8.34.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@google-cloud/spanner": "^5.18.0 || ^6.0.0 || ^7.0.0",
|
||||
|
||||
@ -15,20 +15,31 @@ const options: DataSourceOptions = {
|
||||
entities: [Post],
|
||||
}
|
||||
|
||||
const dataSource = new DataSource(options)
|
||||
dataSource.initialize().then(
|
||||
async (dataSource) => {
|
||||
const post = new Post()
|
||||
post.text = "Hello how are you?"
|
||||
post.title = "hello"
|
||||
post.likesCount = 100
|
||||
async function main() {
|
||||
const dataSource = new DataSource(options)
|
||||
|
||||
const postRepository = dataSource.getRepository(Post)
|
||||
try {
|
||||
await dataSource.initialize()
|
||||
} catch (error) {
|
||||
console.log("Cannot connect: ", error)
|
||||
return
|
||||
}
|
||||
|
||||
postRepository
|
||||
.save(post)
|
||||
.then((post) => console.log("Post has been saved: ", post))
|
||||
.catch((error) => console.log("Cannot save. Error: ", error))
|
||||
},
|
||||
(error) => console.log("Cannot connect: ", error),
|
||||
)
|
||||
const post = new Post()
|
||||
post.text = "Hello how are you?"
|
||||
post.title = "hello"
|
||||
post.likesCount = 100
|
||||
|
||||
const postRepository = dataSource.getRepository(Post)
|
||||
|
||||
try {
|
||||
await postRepository.save(post)
|
||||
console.log("Post has been saved: ", post)
|
||||
} catch (error) {
|
||||
console.log("Cannot save. Error: ", error)
|
||||
}
|
||||
|
||||
await dataSource.destroy()
|
||||
}
|
||||
|
||||
void main()
|
||||
|
||||
@ -15,9 +15,12 @@ const options: DataSourceOptions = {
|
||||
entities: [Post, BasePost],
|
||||
}
|
||||
|
||||
const dataSource = new DataSource(options)
|
||||
dataSource.initialize().then(
|
||||
(dataSource) => {
|
||||
async function main() {
|
||||
const dataSource = new DataSource(options)
|
||||
|
||||
try {
|
||||
await dataSource.initialize()
|
||||
|
||||
const post = new Post()
|
||||
post.text = "Hello how are you?"
|
||||
post.title = "hello"
|
||||
@ -25,9 +28,19 @@ dataSource.initialize().then(
|
||||
|
||||
const postRepository = dataSource.getRepository(Post)
|
||||
|
||||
postRepository
|
||||
.save(post)
|
||||
.then((post) => console.log("Post has been saved"))
|
||||
},
|
||||
(error) => console.log("Cannot connect: ", error),
|
||||
)
|
||||
try {
|
||||
await postRepository.save(post)
|
||||
console.log("Post has been saved")
|
||||
} catch (error) {
|
||||
console.log("Cannot save post: ", error)
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("Cannot connect: ", error)
|
||||
} finally {
|
||||
if (dataSource.isInitialized) {
|
||||
await dataSource.destroy()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void main()
|
||||
|
||||
@ -14,30 +14,35 @@ const options: DataSourceOptions = {
|
||||
entities: [Post],
|
||||
}
|
||||
|
||||
const dataSource = new DataSource(options)
|
||||
dataSource.initialize().then(
|
||||
(dataSource) => {
|
||||
async function main() {
|
||||
const dataSource = new DataSource(options)
|
||||
|
||||
try {
|
||||
await dataSource.initialize()
|
||||
|
||||
const post = new Post()
|
||||
post.text = "Hello how are you?"
|
||||
post.title = "hello"
|
||||
|
||||
const postRepository = dataSource.getRepository(Post)
|
||||
|
||||
postRepository
|
||||
.save(post)
|
||||
.then((post) => {
|
||||
console.log(`Post has been saved: `, post)
|
||||
console.log(
|
||||
`Post's version is ${post.version}. Lets change post's text and update it:`,
|
||||
)
|
||||
post.title = "updating title"
|
||||
return postRepository.save(post)
|
||||
})
|
||||
.then((post) => {
|
||||
console.log(
|
||||
`Post has been updated. Post's version is ${post.version}`,
|
||||
)
|
||||
})
|
||||
},
|
||||
(error) => console.log("Cannot connect: ", error),
|
||||
)
|
||||
await postRepository.save(post)
|
||||
|
||||
console.log(`Post has been saved: `, post)
|
||||
console.log(
|
||||
`Post's version is ${post.version}. Lets change post's text and update it:`,
|
||||
)
|
||||
post.title = "updating title"
|
||||
|
||||
await postRepository.save(post)
|
||||
console.log(`Post has been updated. Post's version is ${post.version}`)
|
||||
} catch (error) {
|
||||
console.log("Cannot connect: ", error)
|
||||
} finally {
|
||||
if (dataSource.isInitialized) {
|
||||
await dataSource.destroy()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void main()
|
||||
|
||||
@ -16,6 +16,7 @@ import { VersionCommand } from "./commands/VersionCommand"
|
||||
import { InitCommand } from "./commands/InitCommand"
|
||||
import { CacheClearCommand } from "./commands/CacheClearCommand"
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
yargs
|
||||
.usage("Usage: $0 <command> [options]")
|
||||
.command(new SchemaSyncCommand())
|
||||
@ -37,4 +38,5 @@ yargs
|
||||
.strict()
|
||||
.alias("v", "version")
|
||||
.help("h")
|
||||
.alias("h", "help").argv
|
||||
.alias("h", "help")
|
||||
.parse()
|
||||
|
||||
@ -138,7 +138,7 @@ export class ConnectionOptionsReader {
|
||||
PlatformTools.getEnvVariable("TYPEORM_CONNECTION") ||
|
||||
PlatformTools.getEnvVariable("TYPEORM_URL")
|
||||
) {
|
||||
connectionOptions = await new ConnectionOptionsEnvReader().read()
|
||||
connectionOptions = new ConnectionOptionsEnvReader().read()
|
||||
} else if (
|
||||
foundFileFormat === "js" ||
|
||||
foundFileFormat === "mjs" ||
|
||||
|
||||
@ -17,7 +17,7 @@ export class ConnectionOptionsEnvReader {
|
||||
/**
|
||||
* Reads connection options from environment variables.
|
||||
*/
|
||||
async read(): Promise<DataSourceOptions[]> {
|
||||
read(): DataSourceOptions[] {
|
||||
return [
|
||||
{
|
||||
type:
|
||||
|
||||
@ -2062,357 +2062,339 @@ export class AuroraMysqlQueryRunner
|
||||
])
|
||||
|
||||
// create tables for loaded tables
|
||||
return Promise.all(
|
||||
dbTables.map(async (dbTable) => {
|
||||
const table = new Table()
|
||||
return dbTables.map((dbTable) => {
|
||||
const table = new Table()
|
||||
|
||||
const dbCollation = dbCollations.find(
|
||||
(coll) => coll["SCHEMA_NAME"] === dbTable["TABLE_SCHEMA"],
|
||||
)!
|
||||
const defaultCollation = dbCollation["COLLATION"]
|
||||
const defaultCharset = dbCollation["CHARSET"]
|
||||
const dbCollation = dbCollations.find(
|
||||
(coll) => coll["SCHEMA_NAME"] === dbTable["TABLE_SCHEMA"],
|
||||
)!
|
||||
const defaultCollation = dbCollation["COLLATION"]
|
||||
const defaultCharset = dbCollation["CHARSET"]
|
||||
|
||||
// We do not need to join database name, when database is by default.
|
||||
const db =
|
||||
dbTable["TABLE_SCHEMA"] === currentDatabase
|
||||
? undefined
|
||||
: dbTable["TABLE_SCHEMA"]
|
||||
table.database = dbTable["TABLE_SCHEMA"]
|
||||
table.name = this.driver.buildTableName(
|
||||
dbTable["TABLE_NAME"],
|
||||
undefined,
|
||||
db,
|
||||
// We do not need to join database name, when database is by default.
|
||||
const db =
|
||||
dbTable["TABLE_SCHEMA"] === currentDatabase
|
||||
? undefined
|
||||
: dbTable["TABLE_SCHEMA"]
|
||||
table.database = dbTable["TABLE_SCHEMA"]
|
||||
table.name = this.driver.buildTableName(
|
||||
dbTable["TABLE_NAME"],
|
||||
undefined,
|
||||
db,
|
||||
)
|
||||
|
||||
// create columns from the loaded columns
|
||||
table.columns = dbColumns
|
||||
.filter(
|
||||
(dbColumn) =>
|
||||
dbColumn["TABLE_NAME"] === dbTable["TABLE_NAME"] &&
|
||||
dbColumn["TABLE_SCHEMA"] === dbTable["TABLE_SCHEMA"],
|
||||
)
|
||||
|
||||
// create columns from the loaded columns
|
||||
table.columns = dbColumns
|
||||
.filter(
|
||||
(dbColumn) =>
|
||||
dbColumn["TABLE_NAME"] === dbTable["TABLE_NAME"] &&
|
||||
dbColumn["TABLE_SCHEMA"] ===
|
||||
dbTable["TABLE_SCHEMA"],
|
||||
)
|
||||
.map((dbColumn) => {
|
||||
const columnUniqueIndices = dbIndices.filter(
|
||||
(dbIndex) => {
|
||||
return (
|
||||
dbIndex["TABLE_NAME"] ===
|
||||
dbTable["TABLE_NAME"] &&
|
||||
dbIndex["TABLE_SCHEMA"] ===
|
||||
dbTable["TABLE_SCHEMA"] &&
|
||||
dbIndex["COLUMN_NAME"] ===
|
||||
dbColumn["COLUMN_NAME"] &&
|
||||
parseInt(dbIndex["NON_UNIQUE"], 10) === 0
|
||||
)
|
||||
},
|
||||
.map((dbColumn) => {
|
||||
const columnUniqueIndices = dbIndices.filter((dbIndex) => {
|
||||
return (
|
||||
dbIndex["TABLE_NAME"] === dbTable["TABLE_NAME"] &&
|
||||
dbIndex["TABLE_SCHEMA"] ===
|
||||
dbTable["TABLE_SCHEMA"] &&
|
||||
dbIndex["COLUMN_NAME"] ===
|
||||
dbColumn["COLUMN_NAME"] &&
|
||||
parseInt(dbIndex["NON_UNIQUE"], 10) === 0
|
||||
)
|
||||
})
|
||||
|
||||
const tableMetadata =
|
||||
this.connection.entityMetadatas.find(
|
||||
(metadata) =>
|
||||
this.getTablePath(table) ===
|
||||
this.getTablePath(metadata),
|
||||
)
|
||||
const hasIgnoredIndex =
|
||||
columnUniqueIndices.length > 0 &&
|
||||
tableMetadata &&
|
||||
tableMetadata.indices.some((index) => {
|
||||
return columnUniqueIndices.some(
|
||||
(uniqueIndex) => {
|
||||
return (
|
||||
index.name ===
|
||||
uniqueIndex["INDEX_NAME"] &&
|
||||
index.synchronize === false
|
||||
)
|
||||
},
|
||||
const tableMetadata = this.connection.entityMetadatas.find(
|
||||
(metadata) =>
|
||||
this.getTablePath(table) ===
|
||||
this.getTablePath(metadata),
|
||||
)
|
||||
const hasIgnoredIndex =
|
||||
columnUniqueIndices.length > 0 &&
|
||||
tableMetadata &&
|
||||
tableMetadata.indices.some((index) => {
|
||||
return columnUniqueIndices.some((uniqueIndex) => {
|
||||
return (
|
||||
index.name === uniqueIndex["INDEX_NAME"] &&
|
||||
index.synchronize === false
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
const isConstraintComposite = columnUniqueIndices.every(
|
||||
(uniqueIndex) => {
|
||||
return dbIndices.some(
|
||||
(dbIndex) =>
|
||||
dbIndex["INDEX_NAME"] ===
|
||||
uniqueIndex["INDEX_NAME"] &&
|
||||
dbIndex["COLUMN_NAME"] !==
|
||||
dbColumn["COLUMN_NAME"],
|
||||
)
|
||||
},
|
||||
)
|
||||
|
||||
const tableColumn = new TableColumn()
|
||||
tableColumn.name = dbColumn["COLUMN_NAME"]
|
||||
tableColumn.type = dbColumn["DATA_TYPE"].toLowerCase()
|
||||
|
||||
// Unsigned columns are handled differently when it comes to width.
|
||||
// Hence, we need to set the unsigned attribute before we check the width.
|
||||
tableColumn.unsigned = tableColumn.zerofill
|
||||
? true
|
||||
: dbColumn["COLUMN_TYPE"].indexOf("unsigned") !== -1
|
||||
|
||||
if (
|
||||
this.driver.withWidthColumnTypes.indexOf(
|
||||
tableColumn.type as ColumnType,
|
||||
) !== -1
|
||||
) {
|
||||
const width = dbColumn["COLUMN_TYPE"].substring(
|
||||
dbColumn["COLUMN_TYPE"].indexOf("(") + 1,
|
||||
dbColumn["COLUMN_TYPE"].indexOf(")"),
|
||||
const isConstraintComposite = columnUniqueIndices.every(
|
||||
(uniqueIndex) => {
|
||||
return dbIndices.some(
|
||||
(dbIndex) =>
|
||||
dbIndex["INDEX_NAME"] ===
|
||||
uniqueIndex["INDEX_NAME"] &&
|
||||
dbIndex["COLUMN_NAME"] !==
|
||||
dbColumn["COLUMN_NAME"],
|
||||
)
|
||||
tableColumn.width =
|
||||
width &&
|
||||
!this.isDefaultColumnWidth(
|
||||
table,
|
||||
tableColumn,
|
||||
parseInt(width),
|
||||
)
|
||||
? parseInt(width)
|
||||
: undefined
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
if (
|
||||
dbColumn["COLUMN_DEFAULT"] === null ||
|
||||
dbColumn["COLUMN_DEFAULT"] === undefined
|
||||
) {
|
||||
tableColumn.default = undefined
|
||||
} else {
|
||||
tableColumn.default =
|
||||
dbColumn["COLUMN_DEFAULT"] ===
|
||||
"CURRENT_TIMESTAMP"
|
||||
? dbColumn["COLUMN_DEFAULT"]
|
||||
: `'${dbColumn["COLUMN_DEFAULT"]}'`
|
||||
}
|
||||
const tableColumn = new TableColumn()
|
||||
tableColumn.name = dbColumn["COLUMN_NAME"]
|
||||
tableColumn.type = dbColumn["DATA_TYPE"].toLowerCase()
|
||||
|
||||
if (dbColumn["EXTRA"].indexOf("on update") !== -1) {
|
||||
tableColumn.onUpdate = dbColumn["EXTRA"].substring(
|
||||
dbColumn["EXTRA"].indexOf("on update") + 10,
|
||||
)
|
||||
}
|
||||
// Unsigned columns are handled differently when it comes to width.
|
||||
// Hence, we need to set the unsigned attribute before we check the width.
|
||||
tableColumn.unsigned = tableColumn.zerofill
|
||||
? true
|
||||
: dbColumn["COLUMN_TYPE"].indexOf("unsigned") !== -1
|
||||
|
||||
if (dbColumn["GENERATION_EXPRESSION"]) {
|
||||
tableColumn.asExpression =
|
||||
dbColumn["GENERATION_EXPRESSION"]
|
||||
tableColumn.generatedType =
|
||||
dbColumn["EXTRA"].indexOf("VIRTUAL") !== -1
|
||||
? "VIRTUAL"
|
||||
: "STORED"
|
||||
}
|
||||
|
||||
tableColumn.isUnique =
|
||||
columnUniqueIndices.length > 0 &&
|
||||
!hasIgnoredIndex &&
|
||||
!isConstraintComposite
|
||||
tableColumn.isNullable =
|
||||
dbColumn["IS_NULLABLE"] === "YES"
|
||||
tableColumn.isPrimary = dbPrimaryKeys.some(
|
||||
(dbPrimaryKey) => {
|
||||
return (
|
||||
dbPrimaryKey["TABLE_NAME"] ===
|
||||
dbColumn["TABLE_NAME"] &&
|
||||
dbPrimaryKey["TABLE_SCHEMA"] ===
|
||||
dbColumn["TABLE_SCHEMA"] &&
|
||||
dbPrimaryKey["COLUMN_NAME"] ===
|
||||
dbColumn["COLUMN_NAME"]
|
||||
)
|
||||
},
|
||||
if (
|
||||
this.driver.withWidthColumnTypes.indexOf(
|
||||
tableColumn.type as ColumnType,
|
||||
) !== -1
|
||||
) {
|
||||
const width = dbColumn["COLUMN_TYPE"].substring(
|
||||
dbColumn["COLUMN_TYPE"].indexOf("(") + 1,
|
||||
dbColumn["COLUMN_TYPE"].indexOf(")"),
|
||||
)
|
||||
tableColumn.zerofill =
|
||||
dbColumn["COLUMN_TYPE"].indexOf("zerofill") !== -1
|
||||
tableColumn.isGenerated =
|
||||
dbColumn["EXTRA"].indexOf("auto_increment") !== -1
|
||||
if (tableColumn.isGenerated)
|
||||
tableColumn.generationStrategy = "increment"
|
||||
|
||||
tableColumn.comment =
|
||||
typeof dbColumn["COLUMN_COMMENT"] === "string" &&
|
||||
dbColumn["COLUMN_COMMENT"].length === 0
|
||||
? undefined
|
||||
: dbColumn["COLUMN_COMMENT"]
|
||||
if (dbColumn["CHARACTER_SET_NAME"])
|
||||
tableColumn.charset =
|
||||
dbColumn["CHARACTER_SET_NAME"] ===
|
||||
defaultCharset
|
||||
? undefined
|
||||
: dbColumn["CHARACTER_SET_NAME"]
|
||||
if (dbColumn["COLLATION_NAME"])
|
||||
tableColumn.collation =
|
||||
dbColumn["COLLATION_NAME"] === defaultCollation
|
||||
? undefined
|
||||
: dbColumn["COLLATION_NAME"]
|
||||
|
||||
// check only columns that have length property
|
||||
if (
|
||||
this.driver.withLengthColumnTypes.indexOf(
|
||||
tableColumn.type as ColumnType,
|
||||
) !== -1 &&
|
||||
dbColumn["CHARACTER_MAXIMUM_LENGTH"]
|
||||
) {
|
||||
const length =
|
||||
dbColumn["CHARACTER_MAXIMUM_LENGTH"].toString()
|
||||
tableColumn.length = !this.isDefaultColumnLength(
|
||||
tableColumn.width =
|
||||
width &&
|
||||
!this.isDefaultColumnWidth(
|
||||
table,
|
||||
tableColumn,
|
||||
length,
|
||||
parseInt(width),
|
||||
)
|
||||
? length
|
||||
: ""
|
||||
}
|
||||
? parseInt(width)
|
||||
: undefined
|
||||
}
|
||||
|
||||
if (
|
||||
tableColumn.type === "decimal" ||
|
||||
tableColumn.type === "double" ||
|
||||
tableColumn.type === "float"
|
||||
) {
|
||||
if (
|
||||
dbColumn["NUMERIC_PRECISION"] !== null &&
|
||||
!this.isDefaultColumnPrecision(
|
||||
table,
|
||||
tableColumn,
|
||||
dbColumn["NUMERIC_PRECISION"],
|
||||
)
|
||||
)
|
||||
tableColumn.precision = parseInt(
|
||||
dbColumn["NUMERIC_PRECISION"],
|
||||
)
|
||||
if (
|
||||
dbColumn["NUMERIC_SCALE"] !== null &&
|
||||
!this.isDefaultColumnScale(
|
||||
table,
|
||||
tableColumn,
|
||||
dbColumn["NUMERIC_SCALE"],
|
||||
)
|
||||
)
|
||||
tableColumn.scale = parseInt(
|
||||
dbColumn["NUMERIC_SCALE"],
|
||||
)
|
||||
}
|
||||
if (
|
||||
dbColumn["COLUMN_DEFAULT"] === null ||
|
||||
dbColumn["COLUMN_DEFAULT"] === undefined
|
||||
) {
|
||||
tableColumn.default = undefined
|
||||
} else {
|
||||
tableColumn.default =
|
||||
dbColumn["COLUMN_DEFAULT"] === "CURRENT_TIMESTAMP"
|
||||
? dbColumn["COLUMN_DEFAULT"]
|
||||
: `'${dbColumn["COLUMN_DEFAULT"]}'`
|
||||
}
|
||||
|
||||
if (
|
||||
tableColumn.type === "enum" ||
|
||||
tableColumn.type === "simple-enum" ||
|
||||
tableColumn.type === "set"
|
||||
) {
|
||||
const colType = dbColumn["COLUMN_TYPE"]
|
||||
const items = colType
|
||||
.substring(
|
||||
colType.indexOf("(") + 1,
|
||||
colType.lastIndexOf(")"),
|
||||
)
|
||||
.split(",")
|
||||
tableColumn.enum = (items as string[]).map(
|
||||
(item) => {
|
||||
return item.substring(1, item.length - 1)
|
||||
},
|
||||
)
|
||||
tableColumn.length = ""
|
||||
}
|
||||
if (dbColumn["EXTRA"].indexOf("on update") !== -1) {
|
||||
tableColumn.onUpdate = dbColumn["EXTRA"].substring(
|
||||
dbColumn["EXTRA"].indexOf("on update") + 10,
|
||||
)
|
||||
}
|
||||
|
||||
if (dbColumn["GENERATION_EXPRESSION"]) {
|
||||
tableColumn.asExpression =
|
||||
dbColumn["GENERATION_EXPRESSION"]
|
||||
tableColumn.generatedType =
|
||||
dbColumn["EXTRA"].indexOf("VIRTUAL") !== -1
|
||||
? "VIRTUAL"
|
||||
: "STORED"
|
||||
}
|
||||
|
||||
tableColumn.isUnique =
|
||||
columnUniqueIndices.length > 0 &&
|
||||
!hasIgnoredIndex &&
|
||||
!isConstraintComposite
|
||||
tableColumn.isNullable = dbColumn["IS_NULLABLE"] === "YES"
|
||||
tableColumn.isPrimary = dbPrimaryKeys.some(
|
||||
(dbPrimaryKey) => {
|
||||
return (
|
||||
dbPrimaryKey["TABLE_NAME"] ===
|
||||
dbColumn["TABLE_NAME"] &&
|
||||
dbPrimaryKey["TABLE_SCHEMA"] ===
|
||||
dbColumn["TABLE_SCHEMA"] &&
|
||||
dbPrimaryKey["COLUMN_NAME"] ===
|
||||
dbColumn["COLUMN_NAME"]
|
||||
)
|
||||
},
|
||||
)
|
||||
tableColumn.zerofill =
|
||||
dbColumn["COLUMN_TYPE"].indexOf("zerofill") !== -1
|
||||
tableColumn.isGenerated =
|
||||
dbColumn["EXTRA"].indexOf("auto_increment") !== -1
|
||||
if (tableColumn.isGenerated)
|
||||
tableColumn.generationStrategy = "increment"
|
||||
|
||||
tableColumn.comment =
|
||||
typeof dbColumn["COLUMN_COMMENT"] === "string" &&
|
||||
dbColumn["COLUMN_COMMENT"].length === 0
|
||||
? undefined
|
||||
: dbColumn["COLUMN_COMMENT"]
|
||||
if (dbColumn["CHARACTER_SET_NAME"])
|
||||
tableColumn.charset =
|
||||
dbColumn["CHARACTER_SET_NAME"] === defaultCharset
|
||||
? undefined
|
||||
: dbColumn["CHARACTER_SET_NAME"]
|
||||
if (dbColumn["COLLATION_NAME"])
|
||||
tableColumn.collation =
|
||||
dbColumn["COLLATION_NAME"] === defaultCollation
|
||||
? undefined
|
||||
: dbColumn["COLLATION_NAME"]
|
||||
|
||||
// check only columns that have length property
|
||||
if (
|
||||
this.driver.withLengthColumnTypes.indexOf(
|
||||
tableColumn.type as ColumnType,
|
||||
) !== -1 &&
|
||||
dbColumn["CHARACTER_MAXIMUM_LENGTH"]
|
||||
) {
|
||||
const length =
|
||||
dbColumn["CHARACTER_MAXIMUM_LENGTH"].toString()
|
||||
tableColumn.length = !this.isDefaultColumnLength(
|
||||
table,
|
||||
tableColumn,
|
||||
length,
|
||||
)
|
||||
? length
|
||||
: ""
|
||||
}
|
||||
|
||||
if (
|
||||
tableColumn.type === "decimal" ||
|
||||
tableColumn.type === "double" ||
|
||||
tableColumn.type === "float"
|
||||
) {
|
||||
if (
|
||||
(tableColumn.type === "datetime" ||
|
||||
tableColumn.type === "time" ||
|
||||
tableColumn.type === "timestamp") &&
|
||||
dbColumn["DATETIME_PRECISION"] !== null &&
|
||||
dbColumn["DATETIME_PRECISION"] !== undefined &&
|
||||
dbColumn["NUMERIC_PRECISION"] !== null &&
|
||||
!this.isDefaultColumnPrecision(
|
||||
table,
|
||||
tableColumn,
|
||||
parseInt(dbColumn["DATETIME_PRECISION"]),
|
||||
dbColumn["NUMERIC_PRECISION"],
|
||||
)
|
||||
) {
|
||||
)
|
||||
tableColumn.precision = parseInt(
|
||||
dbColumn["DATETIME_PRECISION"],
|
||||
dbColumn["NUMERIC_PRECISION"],
|
||||
)
|
||||
if (
|
||||
dbColumn["NUMERIC_SCALE"] !== null &&
|
||||
!this.isDefaultColumnScale(
|
||||
table,
|
||||
tableColumn,
|
||||
dbColumn["NUMERIC_SCALE"],
|
||||
)
|
||||
}
|
||||
|
||||
return tableColumn
|
||||
})
|
||||
|
||||
// find foreign key constraints of table, group them by constraint name and build TableForeignKey.
|
||||
const tableForeignKeyConstraints = OrmUtils.uniq(
|
||||
dbForeignKeys.filter((dbForeignKey) => {
|
||||
return (
|
||||
dbForeignKey["TABLE_NAME"] ===
|
||||
dbTable["TABLE_NAME"] &&
|
||||
dbForeignKey["TABLE_SCHEMA"] ===
|
||||
dbTable["TABLE_SCHEMA"]
|
||||
)
|
||||
}),
|
||||
(dbForeignKey) => dbForeignKey["CONSTRAINT_NAME"],
|
||||
)
|
||||
tableColumn.scale = parseInt(
|
||||
dbColumn["NUMERIC_SCALE"],
|
||||
)
|
||||
}
|
||||
|
||||
table.foreignKeys = tableForeignKeyConstraints.map(
|
||||
(dbForeignKey) => {
|
||||
const foreignKeys = dbForeignKeys.filter(
|
||||
(dbFk) =>
|
||||
dbFk["CONSTRAINT_NAME"] ===
|
||||
dbForeignKey["CONSTRAINT_NAME"],
|
||||
)
|
||||
|
||||
// if referenced table located in currently used db, we don't need to concat db name to table name.
|
||||
const database =
|
||||
dbForeignKey["REFERENCED_TABLE_SCHEMA"] ===
|
||||
currentDatabase
|
||||
? undefined
|
||||
: dbForeignKey["REFERENCED_TABLE_SCHEMA"]
|
||||
const referencedTableName = this.driver.buildTableName(
|
||||
dbForeignKey["REFERENCED_TABLE_NAME"],
|
||||
undefined,
|
||||
database,
|
||||
)
|
||||
|
||||
return new TableForeignKey({
|
||||
name: dbForeignKey["CONSTRAINT_NAME"],
|
||||
columnNames: foreignKeys.map(
|
||||
(dbFk) => dbFk["COLUMN_NAME"],
|
||||
),
|
||||
referencedDatabase:
|
||||
dbForeignKey["REFERENCED_TABLE_SCHEMA"],
|
||||
referencedTableName: referencedTableName,
|
||||
referencedColumnNames: foreignKeys.map(
|
||||
(dbFk) => dbFk["REFERENCED_COLUMN_NAME"],
|
||||
),
|
||||
onDelete: dbForeignKey["ON_DELETE"],
|
||||
onUpdate: dbForeignKey["ON_UPDATE"],
|
||||
if (
|
||||
tableColumn.type === "enum" ||
|
||||
tableColumn.type === "simple-enum" ||
|
||||
tableColumn.type === "set"
|
||||
) {
|
||||
const colType = dbColumn["COLUMN_TYPE"]
|
||||
const items = colType
|
||||
.substring(
|
||||
colType.indexOf("(") + 1,
|
||||
colType.lastIndexOf(")"),
|
||||
)
|
||||
.split(",")
|
||||
tableColumn.enum = (items as string[]).map((item) => {
|
||||
return item.substring(1, item.length - 1)
|
||||
})
|
||||
},
|
||||
)
|
||||
tableColumn.length = ""
|
||||
}
|
||||
|
||||
// find index constraints of table, group them by constraint name and build TableIndex.
|
||||
const tableIndexConstraints = OrmUtils.uniq(
|
||||
dbIndices.filter((dbIndex) => {
|
||||
return (
|
||||
dbIndex["TABLE_NAME"] === dbTable["TABLE_NAME"] &&
|
||||
dbIndex["TABLE_SCHEMA"] === dbTable["TABLE_SCHEMA"]
|
||||
if (
|
||||
(tableColumn.type === "datetime" ||
|
||||
tableColumn.type === "time" ||
|
||||
tableColumn.type === "timestamp") &&
|
||||
dbColumn["DATETIME_PRECISION"] !== null &&
|
||||
dbColumn["DATETIME_PRECISION"] !== undefined &&
|
||||
!this.isDefaultColumnPrecision(
|
||||
table,
|
||||
tableColumn,
|
||||
parseInt(dbColumn["DATETIME_PRECISION"]),
|
||||
)
|
||||
}),
|
||||
(dbIndex) => dbIndex["INDEX_NAME"],
|
||||
)
|
||||
|
||||
table.indices = tableIndexConstraints.map((constraint) => {
|
||||
const indices = dbIndices.filter((index) => {
|
||||
return (
|
||||
index["TABLE_SCHEMA"] ===
|
||||
constraint["TABLE_SCHEMA"] &&
|
||||
index["TABLE_NAME"] === constraint["TABLE_NAME"] &&
|
||||
index["INDEX_NAME"] === constraint["INDEX_NAME"]
|
||||
) {
|
||||
tableColumn.precision = parseInt(
|
||||
dbColumn["DATETIME_PRECISION"],
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
const nonUnique = parseInt(constraint["NON_UNIQUE"], 10)
|
||||
|
||||
return new TableIndex(<TableIndexOptions>{
|
||||
table: table,
|
||||
name: constraint["INDEX_NAME"],
|
||||
columnNames: indices.map((i) => i["COLUMN_NAME"]),
|
||||
isUnique: nonUnique === 0,
|
||||
isSpatial: constraint["INDEX_TYPE"] === "SPATIAL",
|
||||
isFulltext: constraint["INDEX_TYPE"] === "FULLTEXT",
|
||||
})
|
||||
return tableColumn
|
||||
})
|
||||
|
||||
return table
|
||||
}),
|
||||
)
|
||||
// find foreign key constraints of table, group them by constraint name and build TableForeignKey.
|
||||
const tableForeignKeyConstraints = OrmUtils.uniq(
|
||||
dbForeignKeys.filter((dbForeignKey) => {
|
||||
return (
|
||||
dbForeignKey["TABLE_NAME"] === dbTable["TABLE_NAME"] &&
|
||||
dbForeignKey["TABLE_SCHEMA"] === dbTable["TABLE_SCHEMA"]
|
||||
)
|
||||
}),
|
||||
(dbForeignKey) => dbForeignKey["CONSTRAINT_NAME"],
|
||||
)
|
||||
|
||||
table.foreignKeys = tableForeignKeyConstraints.map(
|
||||
(dbForeignKey) => {
|
||||
const foreignKeys = dbForeignKeys.filter(
|
||||
(dbFk) =>
|
||||
dbFk["CONSTRAINT_NAME"] ===
|
||||
dbForeignKey["CONSTRAINT_NAME"],
|
||||
)
|
||||
|
||||
// if referenced table located in currently used db, we don't need to concat db name to table name.
|
||||
const database =
|
||||
dbForeignKey["REFERENCED_TABLE_SCHEMA"] ===
|
||||
currentDatabase
|
||||
? undefined
|
||||
: dbForeignKey["REFERENCED_TABLE_SCHEMA"]
|
||||
const referencedTableName = this.driver.buildTableName(
|
||||
dbForeignKey["REFERENCED_TABLE_NAME"],
|
||||
undefined,
|
||||
database,
|
||||
)
|
||||
|
||||
return new TableForeignKey({
|
||||
name: dbForeignKey["CONSTRAINT_NAME"],
|
||||
columnNames: foreignKeys.map(
|
||||
(dbFk) => dbFk["COLUMN_NAME"],
|
||||
),
|
||||
referencedDatabase:
|
||||
dbForeignKey["REFERENCED_TABLE_SCHEMA"],
|
||||
referencedTableName: referencedTableName,
|
||||
referencedColumnNames: foreignKeys.map(
|
||||
(dbFk) => dbFk["REFERENCED_COLUMN_NAME"],
|
||||
),
|
||||
onDelete: dbForeignKey["ON_DELETE"],
|
||||
onUpdate: dbForeignKey["ON_UPDATE"],
|
||||
})
|
||||
},
|
||||
)
|
||||
|
||||
// find index constraints of table, group them by constraint name and build TableIndex.
|
||||
const tableIndexConstraints = OrmUtils.uniq(
|
||||
dbIndices.filter((dbIndex) => {
|
||||
return (
|
||||
dbIndex["TABLE_NAME"] === dbTable["TABLE_NAME"] &&
|
||||
dbIndex["TABLE_SCHEMA"] === dbTable["TABLE_SCHEMA"]
|
||||
)
|
||||
}),
|
||||
(dbIndex) => dbIndex["INDEX_NAME"],
|
||||
)
|
||||
|
||||
table.indices = tableIndexConstraints.map((constraint) => {
|
||||
const indices = dbIndices.filter((index) => {
|
||||
return (
|
||||
index["TABLE_SCHEMA"] === constraint["TABLE_SCHEMA"] &&
|
||||
index["TABLE_NAME"] === constraint["TABLE_NAME"] &&
|
||||
index["INDEX_NAME"] === constraint["INDEX_NAME"]
|
||||
)
|
||||
})
|
||||
|
||||
const nonUnique = parseInt(constraint["NON_UNIQUE"], 10)
|
||||
|
||||
return new TableIndex({
|
||||
table: table,
|
||||
name: constraint["INDEX_NAME"],
|
||||
columnNames: indices.map((i) => i["COLUMN_NAME"]),
|
||||
isUnique: nonUnique === 0,
|
||||
isSpatial: constraint["INDEX_TYPE"] === "SPATIAL",
|
||||
isFulltext: constraint["INDEX_TYPE"] === "FULLTEXT",
|
||||
} as TableIndexOptions)
|
||||
})
|
||||
|
||||
return table
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -155,7 +155,7 @@ export class BetterSqlite3Driver extends AbstractSqliteDriver {
|
||||
|
||||
// function to run before a database is used in typeorm.
|
||||
if (typeof prepareDatabase === "function") {
|
||||
prepareDatabase(databaseConnection)
|
||||
await prepareDatabase(databaseConnection)
|
||||
}
|
||||
|
||||
// we need to enable foreign keys in sqlite to make sure all foreign key related features
|
||||
@ -198,10 +198,9 @@ export class BetterSqlite3Driver extends AbstractSqliteDriver {
|
||||
*/
|
||||
protected async attachDatabases() {
|
||||
// @todo - possibly check number of databases (but unqueriable at runtime sadly) - https://www.sqlite.org/limits.html#max_attached
|
||||
for await (const {
|
||||
attachHandle,
|
||||
attachFilepathAbsolute,
|
||||
} of Object.values(this.attachedDatabases)) {
|
||||
for (const { attachHandle, attachFilepathAbsolute } of Object.values(
|
||||
this.attachedDatabases,
|
||||
)) {
|
||||
await this.createDatabaseDirectory(
|
||||
path.dirname(attachFilepathAbsolute),
|
||||
)
|
||||
|
||||
@ -77,7 +77,7 @@ export class BetterSqlite3QueryRunner extends AbstractSqliteQueryRunner {
|
||||
*/
|
||||
async query(
|
||||
query: string,
|
||||
parameters?: any[],
|
||||
parameters: any[] = [],
|
||||
useStructuredResult = false,
|
||||
): Promise<any> {
|
||||
if (this.isReleased) throw new QueryRunnerAlreadyReleasedError()
|
||||
@ -100,7 +100,7 @@ export class BetterSqlite3QueryRunner extends AbstractSqliteQueryRunner {
|
||||
const result = new QueryResult()
|
||||
|
||||
if (stmt.reader) {
|
||||
const raw = stmt.all.apply(stmt, parameters)
|
||||
const raw = stmt.all(...parameters)
|
||||
|
||||
result.raw = raw
|
||||
|
||||
@ -108,7 +108,7 @@ export class BetterSqlite3QueryRunner extends AbstractSqliteQueryRunner {
|
||||
result.records = raw
|
||||
}
|
||||
} else {
|
||||
const raw = stmt.run.apply(stmt, parameters)
|
||||
const raw = stmt.run(...parameters)
|
||||
result.affected = raw.changes
|
||||
result.raw = raw.lastInsertRowid
|
||||
}
|
||||
|
||||
@ -61,7 +61,7 @@ export class CordovaQueryRunner extends AbstractSqliteQueryRunner {
|
||||
const queryStartTime = Date.now()
|
||||
|
||||
try {
|
||||
const raw = await new Promise<any>(async (ok, fail) => {
|
||||
const raw = await new Promise<any>((ok, fail) => {
|
||||
databaseConnection.executeSql(
|
||||
query,
|
||||
parameters,
|
||||
|
||||
@ -223,7 +223,7 @@ export class ExpoLegacyQueryRunner extends AbstractSqliteQueryRunner {
|
||||
}
|
||||
|
||||
if (raw?.hasOwnProperty("rows")) {
|
||||
let resultSet = []
|
||||
const resultSet = []
|
||||
for (let i = 0; i < raw.rows.length; i++) {
|
||||
resultSet.push(raw.rows.item(i))
|
||||
}
|
||||
|
||||
@ -99,64 +99,6 @@ export declare interface BinaryExtendedLegacy {
|
||||
/** @public */
|
||||
export declare type BinarySequence = Uint8Array | number[]
|
||||
|
||||
declare namespace BSON {
|
||||
export {
|
||||
setInternalBufferSize,
|
||||
serialize,
|
||||
serializeWithBufferAndIndex,
|
||||
deserialize,
|
||||
calculateObjectSize,
|
||||
deserializeStream,
|
||||
UUIDExtended,
|
||||
BinaryExtended,
|
||||
BinaryExtendedLegacy,
|
||||
BinarySequence,
|
||||
CodeExtended,
|
||||
DBRefLike,
|
||||
Decimal128Extended,
|
||||
DoubleExtended,
|
||||
EJSONOptions,
|
||||
Int32Extended,
|
||||
LongExtended,
|
||||
MaxKeyExtended,
|
||||
MinKeyExtended,
|
||||
ObjectIdExtended,
|
||||
ObjectIdLike,
|
||||
BSONRegExpExtended,
|
||||
BSONRegExpExtendedLegacy,
|
||||
BSONSymbolExtended,
|
||||
LongWithoutOverrides,
|
||||
TimestampExtended,
|
||||
TimestampOverrides,
|
||||
LongWithoutOverridesClass,
|
||||
SerializeOptions,
|
||||
DeserializeOptions,
|
||||
Code,
|
||||
BSONSymbol,
|
||||
DBRef,
|
||||
Binary,
|
||||
ObjectId,
|
||||
UUID,
|
||||
Long,
|
||||
Timestamp,
|
||||
Double,
|
||||
Int32,
|
||||
MinKey,
|
||||
MaxKey,
|
||||
BSONRegExp,
|
||||
Decimal128,
|
||||
BSONValue,
|
||||
BSONError,
|
||||
BSONVersionError,
|
||||
BSONRuntimeError,
|
||||
BSONType,
|
||||
EJSON,
|
||||
Document,
|
||||
CalculateObjectSizeOptions,
|
||||
}
|
||||
}
|
||||
export { BSON }
|
||||
|
||||
/**
|
||||
* @public
|
||||
* @category Error
|
||||
|
||||
@ -1,5 +1,12 @@
|
||||
import type { SrvRecord } from "dns"
|
||||
import type { Socket, TcpNetConnectOpts } from "net"
|
||||
import type {
|
||||
ConnectionOptions as ConnectionOptions_2,
|
||||
TLSSocket,
|
||||
TLSSocketOptions,
|
||||
} from "tls"
|
||||
import { EventEmitter, Readable } from "../../platform/PlatformTools"
|
||||
import {
|
||||
BSON,
|
||||
BSONRegExp,
|
||||
BSONSymbol,
|
||||
BSONType,
|
||||
@ -21,13 +28,7 @@ import {
|
||||
deserialize,
|
||||
serialize,
|
||||
} from "./bson.typings"
|
||||
import type { ConnectionOptions as ConnectionOptions_2 } from "tls"
|
||||
import type { Socket } from "net"
|
||||
import type { SrvRecord } from "dns"
|
||||
import type { TcpNetConnectOpts } from "net"
|
||||
import type { TLSSocket } from "tls"
|
||||
import type { TLSSocketOptions } from "tls"
|
||||
import { Readable, EventEmitter } from "../../platform/PlatformTools"
|
||||
export * as BSON from "./bson.typings"
|
||||
|
||||
/** @public */
|
||||
export declare abstract class AbstractCursor<
|
||||
@ -560,8 +561,8 @@ export declare interface AuthMechanismProperties extends Document {
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export declare interface AutoEncrypter {
|
||||
new (client: MongoClient, options: AutoEncryptionOptions): AutoEncrypter
|
||||
export declare class AutoEncrypter {
|
||||
constructor(client: MongoClient, options: AutoEncryptionOptions)
|
||||
init(cb: Callback): void
|
||||
teardown(force: boolean, callback: Callback): void
|
||||
encrypt(
|
||||
@ -814,8 +815,6 @@ export declare type BitwiseFilter =
|
||||
| Binary /** BinData bit mask */
|
||||
| ReadonlyArray<number>
|
||||
|
||||
export { BSON }
|
||||
|
||||
export { BSONRegExp }
|
||||
|
||||
/**
|
||||
|
||||
@ -208,7 +208,7 @@ export class MysqlQueryRunner extends BaseQueryRunner implements QueryRunner {
|
||||
databaseConnection.query(
|
||||
queryPayload,
|
||||
parameters,
|
||||
async (err: any, raw: any) => {
|
||||
(err: any, raw: any) => {
|
||||
// log slow queries if maxQueryExecution time is set
|
||||
const maxQueryExecutionTime =
|
||||
this.driver.options.maxQueryExecutionTime
|
||||
|
||||
@ -56,7 +56,7 @@ export class NativescriptQueryRunner extends AbstractSqliteQueryRunner {
|
||||
|
||||
const databaseConnection = await this.connect()
|
||||
|
||||
return new Promise(async (ok, fail) => {
|
||||
return new Promise((ok, fail) => {
|
||||
const isInsertQuery = query.substr(0, 11) === "INSERT INTO"
|
||||
connection.logger.logQuery(query, parameters, this)
|
||||
|
||||
|
||||
@ -1003,9 +1003,7 @@ export class PostgresDriver implements Driver {
|
||||
}
|
||||
|
||||
if (columnMetadata.isArray && Array.isArray(defaultValue)) {
|
||||
return `'{${defaultValue
|
||||
.map((val: string) => `${val}`)
|
||||
.join(",")}}'`
|
||||
return `'{${defaultValue.map((val) => String(val)).join(",")}}'`
|
||||
}
|
||||
|
||||
if (
|
||||
|
||||
@ -123,7 +123,7 @@ export class ReactNativeQueryRunner extends AbstractSqliteQueryRunner {
|
||||
ok(result.raw)
|
||||
}
|
||||
},
|
||||
async (err: any) => {
|
||||
(err: any) => {
|
||||
this.driver.connection.logger.logQueryError(
|
||||
err,
|
||||
query,
|
||||
|
||||
@ -2620,339 +2620,311 @@ export class SapQueryRunner extends BaseQueryRunner implements QueryRunner {
|
||||
])
|
||||
|
||||
// create tables for loaded tables
|
||||
return Promise.all(
|
||||
dbTables.map(async (dbTable) => {
|
||||
const table = new Table()
|
||||
const getSchemaFromKey = (dbObject: any, key: string) => {
|
||||
return dbObject[key] === currentSchema &&
|
||||
(!this.driver.options.schema ||
|
||||
this.driver.options.schema === currentSchema)
|
||||
? undefined
|
||||
: dbObject[key]
|
||||
}
|
||||
return dbTables.map((dbTable) => {
|
||||
const table = new Table()
|
||||
const getSchemaFromKey = (dbObject: any, key: string) => {
|
||||
return dbObject[key] === currentSchema &&
|
||||
(!this.driver.options.schema ||
|
||||
this.driver.options.schema === currentSchema)
|
||||
? undefined
|
||||
: dbObject[key]
|
||||
}
|
||||
|
||||
// We do not need to join schema name, when database is by default.
|
||||
const schema = getSchemaFromKey(dbTable, "SCHEMA_NAME")
|
||||
table.database = currentDatabase
|
||||
table.schema = dbTable["SCHEMA_NAME"]
|
||||
table.name = this.driver.buildTableName(
|
||||
dbTable["TABLE_NAME"],
|
||||
schema,
|
||||
// We do not need to join schema name, when database is by default.
|
||||
const schema = getSchemaFromKey(dbTable, "SCHEMA_NAME")
|
||||
table.database = currentDatabase
|
||||
table.schema = dbTable["SCHEMA_NAME"]
|
||||
table.name = this.driver.buildTableName(
|
||||
dbTable["TABLE_NAME"],
|
||||
schema,
|
||||
)
|
||||
|
||||
// create columns from the loaded columns
|
||||
table.columns = dbColumns
|
||||
.filter(
|
||||
(dbColumn) =>
|
||||
dbColumn["TABLE_NAME"] === dbTable["TABLE_NAME"] &&
|
||||
dbColumn["SCHEMA_NAME"] === dbTable["SCHEMA_NAME"],
|
||||
)
|
||||
|
||||
// create columns from the loaded columns
|
||||
table.columns = await Promise.all(
|
||||
dbColumns
|
||||
.filter(
|
||||
(dbColumn) =>
|
||||
dbColumn["TABLE_NAME"] ===
|
||||
dbTable["TABLE_NAME"] &&
|
||||
dbColumn["SCHEMA_NAME"] ===
|
||||
dbTable["SCHEMA_NAME"],
|
||||
)
|
||||
.map(async (dbColumn) => {
|
||||
const columnConstraints = dbConstraints.filter(
|
||||
(dbConstraint) =>
|
||||
dbConstraint["TABLE_NAME"] ===
|
||||
dbColumn["TABLE_NAME"] &&
|
||||
dbConstraint["SCHEMA_NAME"] ===
|
||||
dbColumn["SCHEMA_NAME"] &&
|
||||
dbConstraint["COLUMN_NAME"] ===
|
||||
dbColumn["COLUMN_NAME"],
|
||||
)
|
||||
|
||||
const columnUniqueIndices = dbIndices.filter(
|
||||
(dbIndex) => {
|
||||
return (
|
||||
dbIndex["TABLE_NAME"] ===
|
||||
dbTable["TABLE_NAME"] &&
|
||||
dbIndex["SCHEMA_NAME"] ===
|
||||
dbTable["SCHEMA_NAME"] &&
|
||||
dbIndex["COLUMN_NAME"] ===
|
||||
dbColumn["COLUMN_NAME"] &&
|
||||
dbIndex["CONSTRAINT"] &&
|
||||
dbIndex["CONSTRAINT"].indexOf(
|
||||
"UNIQUE",
|
||||
) !== -1
|
||||
)
|
||||
},
|
||||
)
|
||||
|
||||
const tableMetadata =
|
||||
this.connection.entityMetadatas.find(
|
||||
(metadata) =>
|
||||
this.getTablePath(table) ===
|
||||
this.getTablePath(metadata),
|
||||
)
|
||||
const hasIgnoredIndex =
|
||||
columnUniqueIndices.length > 0 &&
|
||||
tableMetadata &&
|
||||
tableMetadata.indices.some((index) => {
|
||||
return columnUniqueIndices.some(
|
||||
(uniqueIndex) => {
|
||||
return (
|
||||
index.name ===
|
||||
uniqueIndex["INDEX_NAME"] &&
|
||||
index.synchronize === false
|
||||
)
|
||||
},
|
||||
)
|
||||
})
|
||||
|
||||
const isConstraintComposite =
|
||||
columnUniqueIndices.every((uniqueIndex) => {
|
||||
return dbIndices.some(
|
||||
(dbIndex) =>
|
||||
dbIndex["INDEX_NAME"] ===
|
||||
uniqueIndex["INDEX_NAME"] &&
|
||||
dbIndex["COLUMN_NAME"] !==
|
||||
dbColumn["COLUMN_NAME"],
|
||||
)
|
||||
})
|
||||
|
||||
const tableColumn = new TableColumn()
|
||||
tableColumn.name = dbColumn["COLUMN_NAME"]
|
||||
tableColumn.type =
|
||||
dbColumn["DATA_TYPE_NAME"].toLowerCase()
|
||||
|
||||
if (
|
||||
tableColumn.type === "dec" ||
|
||||
tableColumn.type === "decimal"
|
||||
) {
|
||||
// If one of these properties was set, and another was not, Postgres sets '0' in to unspecified property
|
||||
// we set 'undefined' in to unspecified property to avoid changing column on sync
|
||||
if (
|
||||
dbColumn["LENGTH"] !== null &&
|
||||
!this.isDefaultColumnPrecision(
|
||||
table,
|
||||
tableColumn,
|
||||
dbColumn["LENGTH"],
|
||||
)
|
||||
) {
|
||||
tableColumn.precision = dbColumn["LENGTH"]
|
||||
} else if (
|
||||
dbColumn["SCALE"] !== null &&
|
||||
!this.isDefaultColumnScale(
|
||||
table,
|
||||
tableColumn,
|
||||
dbColumn["SCALE"],
|
||||
)
|
||||
) {
|
||||
tableColumn.precision = undefined
|
||||
}
|
||||
if (
|
||||
dbColumn["SCALE"] !== null &&
|
||||
!this.isDefaultColumnScale(
|
||||
table,
|
||||
tableColumn,
|
||||
dbColumn["SCALE"],
|
||||
)
|
||||
) {
|
||||
tableColumn.scale = dbColumn["SCALE"]
|
||||
} else if (
|
||||
dbColumn["LENGTH"] !== null &&
|
||||
!this.isDefaultColumnPrecision(
|
||||
table,
|
||||
tableColumn,
|
||||
dbColumn["LENGTH"],
|
||||
)
|
||||
) {
|
||||
tableColumn.scale = undefined
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
dbColumn["DATA_TYPE_NAME"].toLowerCase() ===
|
||||
"array"
|
||||
) {
|
||||
tableColumn.isArray = true
|
||||
tableColumn.type =
|
||||
dbColumn["CS_DATA_TYPE_NAME"].toLowerCase()
|
||||
}
|
||||
|
||||
// check only columns that have length property
|
||||
if (
|
||||
this.driver.withLengthColumnTypes.indexOf(
|
||||
tableColumn.type as ColumnType,
|
||||
) !== -1 &&
|
||||
dbColumn["LENGTH"]
|
||||
) {
|
||||
const length = dbColumn["LENGTH"].toString()
|
||||
tableColumn.length =
|
||||
!this.isDefaultColumnLength(
|
||||
table,
|
||||
tableColumn,
|
||||
length,
|
||||
)
|
||||
? length
|
||||
: ""
|
||||
}
|
||||
tableColumn.isUnique =
|
||||
columnUniqueIndices.length > 0 &&
|
||||
!hasIgnoredIndex &&
|
||||
!isConstraintComposite
|
||||
tableColumn.isNullable =
|
||||
dbColumn["IS_NULLABLE"] === "TRUE"
|
||||
tableColumn.isPrimary = !!columnConstraints.find(
|
||||
(constraint) =>
|
||||
constraint["IS_PRIMARY_KEY"] === "TRUE",
|
||||
)
|
||||
tableColumn.isGenerated =
|
||||
dbColumn["GENERATION_TYPE"] ===
|
||||
"ALWAYS AS IDENTITY"
|
||||
if (tableColumn.isGenerated)
|
||||
tableColumn.generationStrategy = "increment"
|
||||
|
||||
if (
|
||||
dbColumn["DEFAULT_VALUE"] === null ||
|
||||
dbColumn["DEFAULT_VALUE"] === undefined
|
||||
) {
|
||||
tableColumn.default = undefined
|
||||
} else {
|
||||
if (
|
||||
tableColumn.type === "char" ||
|
||||
tableColumn.type === "nchar" ||
|
||||
tableColumn.type === "varchar" ||
|
||||
tableColumn.type === "nvarchar" ||
|
||||
tableColumn.type === "alphanum" ||
|
||||
tableColumn.type === "shorttext"
|
||||
) {
|
||||
tableColumn.default = `'${dbColumn["DEFAULT_VALUE"]}'`
|
||||
} else if (tableColumn.type === "boolean") {
|
||||
tableColumn.default =
|
||||
dbColumn["DEFAULT_VALUE"] === "1"
|
||||
? "true"
|
||||
: "false"
|
||||
} else {
|
||||
tableColumn.default =
|
||||
dbColumn["DEFAULT_VALUE"]
|
||||
}
|
||||
}
|
||||
if (dbColumn["COMMENTS"]) {
|
||||
tableColumn.comment = dbColumn["COMMENTS"]
|
||||
}
|
||||
return tableColumn
|
||||
}),
|
||||
)
|
||||
|
||||
// find check constraints of table, group them by constraint name and build TableCheck.
|
||||
const tableCheckConstraints = OrmUtils.uniq(
|
||||
dbConstraints.filter(
|
||||
.map((dbColumn) => {
|
||||
const columnConstraints = dbConstraints.filter(
|
||||
(dbConstraint) =>
|
||||
dbConstraint["TABLE_NAME"] ===
|
||||
dbTable["TABLE_NAME"] &&
|
||||
dbColumn["TABLE_NAME"] &&
|
||||
dbConstraint["SCHEMA_NAME"] ===
|
||||
dbTable["SCHEMA_NAME"] &&
|
||||
dbConstraint["CHECK_CONDITION"] !== null &&
|
||||
dbConstraint["CHECK_CONDITION"] !== undefined,
|
||||
),
|
||||
(dbConstraint) => dbConstraint["CONSTRAINT_NAME"],
|
||||
)
|
||||
|
||||
table.checks = tableCheckConstraints.map((constraint) => {
|
||||
const checks = dbConstraints.filter(
|
||||
(dbC) =>
|
||||
dbC["CONSTRAINT_NAME"] ===
|
||||
constraint["CONSTRAINT_NAME"],
|
||||
dbColumn["SCHEMA_NAME"] &&
|
||||
dbConstraint["COLUMN_NAME"] ===
|
||||
dbColumn["COLUMN_NAME"],
|
||||
)
|
||||
return new TableCheck({
|
||||
name: constraint["CONSTRAINT_NAME"],
|
||||
columnNames: checks.map((c) => c["COLUMN_NAME"]),
|
||||
expression: constraint["CHECK_CONDITION"],
|
||||
})
|
||||
})
|
||||
|
||||
// find foreign key constraints of table, group them by constraint name and build TableForeignKey.
|
||||
const tableForeignKeyConstraints = OrmUtils.uniq(
|
||||
dbForeignKeys.filter(
|
||||
(dbForeignKey) =>
|
||||
dbForeignKey["TABLE_NAME"] ===
|
||||
dbTable["TABLE_NAME"] &&
|
||||
dbForeignKey["SCHEMA_NAME"] ===
|
||||
dbTable["SCHEMA_NAME"],
|
||||
),
|
||||
(dbForeignKey) => dbForeignKey["CONSTRAINT_NAME"],
|
||||
)
|
||||
|
||||
table.foreignKeys = tableForeignKeyConstraints.map(
|
||||
(dbForeignKey) => {
|
||||
const foreignKeys = dbForeignKeys.filter(
|
||||
(dbFk) =>
|
||||
dbFk["CONSTRAINT_NAME"] ===
|
||||
dbForeignKey["CONSTRAINT_NAME"],
|
||||
)
|
||||
|
||||
// if referenced table located in currently used schema, we don't need to concat schema name to table name.
|
||||
const schema = getSchemaFromKey(
|
||||
dbForeignKey,
|
||||
"REFERENCED_SCHEMA_NAME",
|
||||
)
|
||||
const referencedTableName = this.driver.buildTableName(
|
||||
dbForeignKey["REFERENCED_TABLE_NAME"],
|
||||
schema,
|
||||
)
|
||||
|
||||
return new TableForeignKey({
|
||||
name: dbForeignKey["CONSTRAINT_NAME"],
|
||||
columnNames: foreignKeys.map(
|
||||
(dbFk) => dbFk["COLUMN_NAME"],
|
||||
),
|
||||
referencedDatabase: table.database,
|
||||
referencedSchema:
|
||||
dbForeignKey["REFERENCED_SCHEMA_NAME"],
|
||||
referencedTableName: referencedTableName,
|
||||
referencedColumnNames: foreignKeys.map(
|
||||
(dbFk) => dbFk["REFERENCED_COLUMN_NAME"],
|
||||
),
|
||||
onDelete:
|
||||
dbForeignKey["DELETE_RULE"] === "RESTRICT"
|
||||
? "NO ACTION"
|
||||
: dbForeignKey["DELETE_RULE"],
|
||||
onUpdate:
|
||||
dbForeignKey["UPDATE_RULE"] === "RESTRICT"
|
||||
? "NO ACTION"
|
||||
: dbForeignKey["UPDATE_RULE"],
|
||||
deferrable: dbForeignKey["CHECK_TIME"].replace(
|
||||
"_",
|
||||
" ",
|
||||
),
|
||||
})
|
||||
},
|
||||
)
|
||||
|
||||
// find index constraints of table, group them by constraint name and build TableIndex.
|
||||
const tableIndexConstraints = OrmUtils.uniq(
|
||||
dbIndices.filter(
|
||||
(dbIndex) =>
|
||||
dbIndex["TABLE_NAME"] === dbTable["TABLE_NAME"] &&
|
||||
dbIndex["SCHEMA_NAME"] === dbTable["SCHEMA_NAME"],
|
||||
),
|
||||
(dbIndex) => dbIndex["INDEX_NAME"],
|
||||
)
|
||||
|
||||
table.indices = tableIndexConstraints.map((constraint) => {
|
||||
const indices = dbIndices.filter((index) => {
|
||||
const columnUniqueIndices = dbIndices.filter((dbIndex) => {
|
||||
return (
|
||||
index["SCHEMA_NAME"] ===
|
||||
constraint["SCHEMA_NAME"] &&
|
||||
index["TABLE_NAME"] === constraint["TABLE_NAME"] &&
|
||||
index["INDEX_NAME"] === constraint["INDEX_NAME"]
|
||||
dbIndex["TABLE_NAME"] === dbTable["TABLE_NAME"] &&
|
||||
dbIndex["SCHEMA_NAME"] === dbTable["SCHEMA_NAME"] &&
|
||||
dbIndex["COLUMN_NAME"] ===
|
||||
dbColumn["COLUMN_NAME"] &&
|
||||
dbIndex["CONSTRAINT"] &&
|
||||
dbIndex["CONSTRAINT"].indexOf("UNIQUE") !== -1
|
||||
)
|
||||
})
|
||||
return new TableIndex(<TableIndexOptions>{
|
||||
table: table,
|
||||
name: constraint["INDEX_NAME"],
|
||||
columnNames: indices.map((i) => i["COLUMN_NAME"]),
|
||||
isUnique:
|
||||
constraint["CONSTRAINT"] &&
|
||||
constraint["CONSTRAINT"].indexOf("UNIQUE") !== -1,
|
||||
isFulltext: constraint["INDEX_TYPE"] === "FULLTEXT",
|
||||
})
|
||||
|
||||
const tableMetadata = this.connection.entityMetadatas.find(
|
||||
(metadata) =>
|
||||
this.getTablePath(table) ===
|
||||
this.getTablePath(metadata),
|
||||
)
|
||||
const hasIgnoredIndex =
|
||||
columnUniqueIndices.length > 0 &&
|
||||
tableMetadata &&
|
||||
tableMetadata.indices.some((index) => {
|
||||
return columnUniqueIndices.some((uniqueIndex) => {
|
||||
return (
|
||||
index.name === uniqueIndex["INDEX_NAME"] &&
|
||||
index.synchronize === false
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
const isConstraintComposite = columnUniqueIndices.every(
|
||||
(uniqueIndex) => {
|
||||
return dbIndices.some(
|
||||
(dbIndex) =>
|
||||
dbIndex["INDEX_NAME"] ===
|
||||
uniqueIndex["INDEX_NAME"] &&
|
||||
dbIndex["COLUMN_NAME"] !==
|
||||
dbColumn["COLUMN_NAME"],
|
||||
)
|
||||
},
|
||||
)
|
||||
|
||||
const tableColumn = new TableColumn()
|
||||
tableColumn.name = dbColumn["COLUMN_NAME"]
|
||||
tableColumn.type = dbColumn["DATA_TYPE_NAME"].toLowerCase()
|
||||
|
||||
if (
|
||||
tableColumn.type === "dec" ||
|
||||
tableColumn.type === "decimal"
|
||||
) {
|
||||
// If one of these properties was set, and another was not, Postgres sets '0' in to unspecified property
|
||||
// we set 'undefined' in to unspecified property to avoid changing column on sync
|
||||
if (
|
||||
dbColumn["LENGTH"] !== null &&
|
||||
!this.isDefaultColumnPrecision(
|
||||
table,
|
||||
tableColumn,
|
||||
dbColumn["LENGTH"],
|
||||
)
|
||||
) {
|
||||
tableColumn.precision = dbColumn["LENGTH"]
|
||||
} else if (
|
||||
dbColumn["SCALE"] !== null &&
|
||||
!this.isDefaultColumnScale(
|
||||
table,
|
||||
tableColumn,
|
||||
dbColumn["SCALE"],
|
||||
)
|
||||
) {
|
||||
tableColumn.precision = undefined
|
||||
}
|
||||
if (
|
||||
dbColumn["SCALE"] !== null &&
|
||||
!this.isDefaultColumnScale(
|
||||
table,
|
||||
tableColumn,
|
||||
dbColumn["SCALE"],
|
||||
)
|
||||
) {
|
||||
tableColumn.scale = dbColumn["SCALE"]
|
||||
} else if (
|
||||
dbColumn["LENGTH"] !== null &&
|
||||
!this.isDefaultColumnPrecision(
|
||||
table,
|
||||
tableColumn,
|
||||
dbColumn["LENGTH"],
|
||||
)
|
||||
) {
|
||||
tableColumn.scale = undefined
|
||||
}
|
||||
}
|
||||
|
||||
if (dbColumn["DATA_TYPE_NAME"].toLowerCase() === "array") {
|
||||
tableColumn.isArray = true
|
||||
tableColumn.type =
|
||||
dbColumn["CS_DATA_TYPE_NAME"].toLowerCase()
|
||||
}
|
||||
|
||||
// check only columns that have length property
|
||||
if (
|
||||
this.driver.withLengthColumnTypes.indexOf(
|
||||
tableColumn.type as ColumnType,
|
||||
) !== -1 &&
|
||||
dbColumn["LENGTH"]
|
||||
) {
|
||||
const length = dbColumn["LENGTH"].toString()
|
||||
tableColumn.length = !this.isDefaultColumnLength(
|
||||
table,
|
||||
tableColumn,
|
||||
length,
|
||||
)
|
||||
? length
|
||||
: ""
|
||||
}
|
||||
tableColumn.isUnique =
|
||||
columnUniqueIndices.length > 0 &&
|
||||
!hasIgnoredIndex &&
|
||||
!isConstraintComposite
|
||||
tableColumn.isNullable = dbColumn["IS_NULLABLE"] === "TRUE"
|
||||
tableColumn.isPrimary = !!columnConstraints.find(
|
||||
(constraint) => constraint["IS_PRIMARY_KEY"] === "TRUE",
|
||||
)
|
||||
tableColumn.isGenerated =
|
||||
dbColumn["GENERATION_TYPE"] === "ALWAYS AS IDENTITY"
|
||||
if (tableColumn.isGenerated)
|
||||
tableColumn.generationStrategy = "increment"
|
||||
|
||||
if (
|
||||
dbColumn["DEFAULT_VALUE"] === null ||
|
||||
dbColumn["DEFAULT_VALUE"] === undefined
|
||||
) {
|
||||
tableColumn.default = undefined
|
||||
} else {
|
||||
if (
|
||||
tableColumn.type === "char" ||
|
||||
tableColumn.type === "nchar" ||
|
||||
tableColumn.type === "varchar" ||
|
||||
tableColumn.type === "nvarchar" ||
|
||||
tableColumn.type === "alphanum" ||
|
||||
tableColumn.type === "shorttext"
|
||||
) {
|
||||
tableColumn.default = `'${dbColumn["DEFAULT_VALUE"]}'`
|
||||
} else if (tableColumn.type === "boolean") {
|
||||
tableColumn.default =
|
||||
dbColumn["DEFAULT_VALUE"] === "1"
|
||||
? "true"
|
||||
: "false"
|
||||
} else {
|
||||
tableColumn.default = dbColumn["DEFAULT_VALUE"]
|
||||
}
|
||||
}
|
||||
if (dbColumn["COMMENTS"]) {
|
||||
tableColumn.comment = dbColumn["COMMENTS"]
|
||||
}
|
||||
return tableColumn
|
||||
})
|
||||
|
||||
return table
|
||||
}),
|
||||
)
|
||||
// find check constraints of table, group them by constraint name and build TableCheck.
|
||||
const tableCheckConstraints = OrmUtils.uniq(
|
||||
dbConstraints.filter(
|
||||
(dbConstraint) =>
|
||||
dbConstraint["TABLE_NAME"] === dbTable["TABLE_NAME"] &&
|
||||
dbConstraint["SCHEMA_NAME"] ===
|
||||
dbTable["SCHEMA_NAME"] &&
|
||||
dbConstraint["CHECK_CONDITION"] !== null &&
|
||||
dbConstraint["CHECK_CONDITION"] !== undefined,
|
||||
),
|
||||
(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["CHECK_CONDITION"],
|
||||
})
|
||||
})
|
||||
|
||||
// find foreign key constraints of table, group them by constraint name and build TableForeignKey.
|
||||
const tableForeignKeyConstraints = OrmUtils.uniq(
|
||||
dbForeignKeys.filter(
|
||||
(dbForeignKey) =>
|
||||
dbForeignKey["TABLE_NAME"] === dbTable["TABLE_NAME"] &&
|
||||
dbForeignKey["SCHEMA_NAME"] === dbTable["SCHEMA_NAME"],
|
||||
),
|
||||
(dbForeignKey) => dbForeignKey["CONSTRAINT_NAME"],
|
||||
)
|
||||
|
||||
table.foreignKeys = tableForeignKeyConstraints.map(
|
||||
(dbForeignKey) => {
|
||||
const foreignKeys = dbForeignKeys.filter(
|
||||
(dbFk) =>
|
||||
dbFk["CONSTRAINT_NAME"] ===
|
||||
dbForeignKey["CONSTRAINT_NAME"],
|
||||
)
|
||||
|
||||
// if referenced table located in currently used schema, we don't need to concat schema name to table name.
|
||||
const schema = getSchemaFromKey(
|
||||
dbForeignKey,
|
||||
"REFERENCED_SCHEMA_NAME",
|
||||
)
|
||||
const referencedTableName = this.driver.buildTableName(
|
||||
dbForeignKey["REFERENCED_TABLE_NAME"],
|
||||
schema,
|
||||
)
|
||||
|
||||
return new TableForeignKey({
|
||||
name: dbForeignKey["CONSTRAINT_NAME"],
|
||||
columnNames: foreignKeys.map(
|
||||
(dbFk) => dbFk["COLUMN_NAME"],
|
||||
),
|
||||
referencedDatabase: table.database,
|
||||
referencedSchema:
|
||||
dbForeignKey["REFERENCED_SCHEMA_NAME"],
|
||||
referencedTableName: referencedTableName,
|
||||
referencedColumnNames: foreignKeys.map(
|
||||
(dbFk) => dbFk["REFERENCED_COLUMN_NAME"],
|
||||
),
|
||||
onDelete:
|
||||
dbForeignKey["DELETE_RULE"] === "RESTRICT"
|
||||
? "NO ACTION"
|
||||
: dbForeignKey["DELETE_RULE"],
|
||||
onUpdate:
|
||||
dbForeignKey["UPDATE_RULE"] === "RESTRICT"
|
||||
? "NO ACTION"
|
||||
: dbForeignKey["UPDATE_RULE"],
|
||||
deferrable: dbForeignKey["CHECK_TIME"].replace(
|
||||
"_",
|
||||
" ",
|
||||
),
|
||||
})
|
||||
},
|
||||
)
|
||||
|
||||
// find index constraints of table, group them by constraint name and build TableIndex.
|
||||
const tableIndexConstraints = OrmUtils.uniq(
|
||||
dbIndices.filter(
|
||||
(dbIndex) =>
|
||||
dbIndex["TABLE_NAME"] === dbTable["TABLE_NAME"] &&
|
||||
dbIndex["SCHEMA_NAME"] === dbTable["SCHEMA_NAME"],
|
||||
),
|
||||
(dbIndex) => dbIndex["INDEX_NAME"],
|
||||
)
|
||||
|
||||
table.indices = tableIndexConstraints.map((constraint) => {
|
||||
const indices = dbIndices.filter((index) => {
|
||||
return (
|
||||
index["SCHEMA_NAME"] === constraint["SCHEMA_NAME"] &&
|
||||
index["TABLE_NAME"] === constraint["TABLE_NAME"] &&
|
||||
index["INDEX_NAME"] === constraint["INDEX_NAME"]
|
||||
)
|
||||
})
|
||||
return new TableIndex(<TableIndexOptions>{
|
||||
table: table,
|
||||
name: constraint["INDEX_NAME"],
|
||||
columnNames: indices.map((i) => i["COLUMN_NAME"]),
|
||||
isUnique:
|
||||
constraint["CONSTRAINT"] &&
|
||||
constraint["CONSTRAINT"].indexOf("UNIQUE") !== -1,
|
||||
isFulltext: constraint["INDEX_TYPE"] === "FULLTEXT",
|
||||
})
|
||||
})
|
||||
|
||||
return table
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -913,7 +913,7 @@ export abstract class AbstractSqliteDriver implements Driver {
|
||||
/**
|
||||
* Creates connection with the database.
|
||||
*/
|
||||
protected createDatabaseConnection() {
|
||||
protected async createDatabaseConnection(): Promise<any> {
|
||||
throw new TypeORMError(
|
||||
"Do not use AbstractSqlite directly, it has to be used with one of the sqlite drivers",
|
||||
)
|
||||
|
||||
@ -214,10 +214,9 @@ export class SqliteDriver extends AbstractSqliteDriver {
|
||||
*/
|
||||
protected async attachDatabases() {
|
||||
// @todo - possibly check number of databases (but unqueriable at runtime sadly) - https://www.sqlite.org/limits.html#max_attached
|
||||
for await (const {
|
||||
attachHandle,
|
||||
attachFilepathAbsolute,
|
||||
} of Object.values(this.attachedDatabases)) {
|
||||
for (const { attachHandle, attachFilepathAbsolute } of Object.values(
|
||||
this.attachedDatabases,
|
||||
)) {
|
||||
await this.createDatabaseDirectory(attachFilepathAbsolute)
|
||||
await this.connection.query(
|
||||
`ATTACH "${attachFilepathAbsolute}" AS "${attachHandle}"`,
|
||||
|
||||
@ -1027,7 +1027,7 @@ export class MongoEntityManager extends EntityManager {
|
||||
const queryRunner = this.mongoQueryRunner
|
||||
|
||||
;(cursor as any)["__to_array_func"] = cursor.toArray
|
||||
cursor.toArray = async () =>
|
||||
cursor.toArray = () =>
|
||||
((cursor as any)["__to_array_func"] as CallableFunction)().then(
|
||||
async (results: Entity[]) => {
|
||||
const transformer = new DocumentToEntityTransformer()
|
||||
@ -1042,7 +1042,7 @@ export class MongoEntityManager extends EntityManager {
|
||||
},
|
||||
)
|
||||
;(cursor as any)["__next_func"] = cursor.next
|
||||
cursor.next = async () =>
|
||||
cursor.next = () =>
|
||||
((cursor as any)["__next_func"] as CallableFunction)().then(
|
||||
async (result: Entity) => {
|
||||
if (!result) {
|
||||
@ -1177,7 +1177,7 @@ export class MongoEntityManager extends EntityManager {
|
||||
this.convertFindManyOptionsOrConditionsToMongodbQuery(
|
||||
optionsOrConditions,
|
||||
)
|
||||
const cursor = await this.createEntityCursor(entityClassOrName, query)
|
||||
const cursor = this.createEntityCursor(entityClassOrName, query)
|
||||
const deleteDateColumn =
|
||||
this.connection.getMetadata(entityClassOrName).deleteDateColumn
|
||||
|
||||
|
||||
@ -25,7 +25,7 @@ export class FormattedConsoleLogger extends AbstractLogger {
|
||||
queryRunner,
|
||||
)
|
||||
|
||||
for (let message of messages) {
|
||||
for (const message of messages) {
|
||||
switch (message.type ?? level) {
|
||||
case "log":
|
||||
case "schema-build":
|
||||
|
||||
@ -569,7 +569,7 @@ export class ColumnMetadata {
|
||||
const extractEmbeddedColumnValue = (
|
||||
propertyNames: string[],
|
||||
map: ObjectLiteral,
|
||||
): any => {
|
||||
) => {
|
||||
const propertyName = propertyNames.shift()
|
||||
if (propertyName) {
|
||||
map[propertyName] = {}
|
||||
|
||||
@ -654,21 +654,16 @@ export class SubjectExecutor {
|
||||
}
|
||||
|
||||
// Run nested set updates one by one
|
||||
const nestedSetPromise = new Promise<void>(async (ok, fail) => {
|
||||
const updateNestSetSubjects = async () => {
|
||||
for (const subject of nestedSetSubjects) {
|
||||
try {
|
||||
await updateSubject(subject)
|
||||
} catch (error) {
|
||||
fail(error)
|
||||
}
|
||||
await updateSubject(subject)
|
||||
}
|
||||
ok()
|
||||
})
|
||||
}
|
||||
|
||||
// Run all remaining subjects in parallel
|
||||
await Promise.all([
|
||||
...remainingSubjects.map(updateSubject),
|
||||
nestedSetPromise,
|
||||
updateNestSetSubjects(),
|
||||
])
|
||||
}
|
||||
|
||||
@ -1117,7 +1112,7 @@ export class SubjectExecutor {
|
||||
// merge into entity all generated values returned by a database
|
||||
if (subject.generatedMap)
|
||||
this.queryRunner.manager.merge(
|
||||
subject.metadata.target as any,
|
||||
subject.metadata.target,
|
||||
subject.entity,
|
||||
subject.generatedMap,
|
||||
)
|
||||
|
||||
@ -177,12 +177,12 @@ export class SubjectTopologicalSorter {
|
||||
|
||||
const nodes = uniqueNodes(edges)
|
||||
let cursor = nodes.length,
|
||||
sorted = new Array(cursor),
|
||||
visited: any = {},
|
||||
i = cursor
|
||||
const sorted = new Array(cursor),
|
||||
visited = new Set<number>()
|
||||
|
||||
while (i--) {
|
||||
if (!visited[i]) visit(nodes[i], i, [])
|
||||
if (!visited.has(i)) visit(nodes[i], i, [])
|
||||
}
|
||||
|
||||
function visit(node: any, i: number, predecessors: any[]) {
|
||||
@ -199,8 +199,8 @@ export class SubjectTopologicalSorter {
|
||||
)
|
||||
}
|
||||
|
||||
if (visited[i]) return
|
||||
visited[i] = true
|
||||
if (visited.has(i)) return
|
||||
visited.add(i)
|
||||
|
||||
// outgoing edges
|
||||
const outgoing = edges.filter(function (edge) {
|
||||
|
||||
@ -403,6 +403,7 @@ export class RelationLoader {
|
||||
delete entity[resolveIndex]
|
||||
delete entity[dataIndex]
|
||||
entity[promiseIndex] = value
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
value.then(
|
||||
// ensure different value is not assigned yet
|
||||
(result) =>
|
||||
@ -441,6 +442,7 @@ export class RelationLoader {
|
||||
set: function (value: any | Promise<any>) {
|
||||
if (value instanceof Promise) {
|
||||
// if set data is a promise then wait for its resolve and save in the object
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
setPromise(this, value)
|
||||
} else {
|
||||
// if its direct data set (non promise, probably not safe-typed)
|
||||
|
||||
@ -589,7 +589,9 @@ export class RawSqlResultsToEntityTransformer {
|
||||
}
|
||||
|
||||
// Calculate the idMaps for the rawRelationIdResult
|
||||
return rawRelationIdResult.results.reduce((agg, result) => {
|
||||
return rawRelationIdResult.results.reduce<{
|
||||
[idHash: string]: any[]
|
||||
}>((agg, result) => {
|
||||
let idMap = columns.reduce((idMap, column) => {
|
||||
let value = result[column.databaseName]
|
||||
if (
|
||||
@ -620,7 +622,7 @@ export class RawSqlResultsToEntityTransformer {
|
||||
) {
|
||||
// if column is a relation
|
||||
value =
|
||||
column.referencedColumn!.referencedColumn!.createValueMap(
|
||||
column.referencedColumn!.referencedColumn.createValueMap(
|
||||
value,
|
||||
)
|
||||
}
|
||||
|
||||
@ -2,7 +2,7 @@ export class QueryLock {
|
||||
private readonly queue: Promise<void>[] = []
|
||||
|
||||
async acquire(): Promise<() => void> {
|
||||
let release: Function
|
||||
let release: () => void
|
||||
const waitingPromise = new Promise<void>((ok) => (release = ok))
|
||||
|
||||
// Get track of everyone we need to wait on..
|
||||
@ -18,6 +18,7 @@ export class QueryLock {
|
||||
release()
|
||||
|
||||
if (this.queue.includes(waitingPromise)) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
this.queue.splice(this.queue.indexOf(waitingPromise), 1)
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,11 +4,12 @@ import { pathToFileURL } from "url"
|
||||
|
||||
export async function importOrRequireFile(
|
||||
filePath: string,
|
||||
): Promise<[result: any, moduleType: "esm" | "commonjs"]> {
|
||||
): Promise<[any, "esm" | "commonjs"]> {
|
||||
const tryToImport = async (): Promise<[any, "esm"]> => {
|
||||
// `Function` is required to make sure the `import` statement wil stay `import` after
|
||||
// transpilation and won't be converted to `require`
|
||||
return [
|
||||
// eslint-disable-next-line @typescript-eslint/no-implied-eval
|
||||
await Function("return filePath => import(filePath)")()(
|
||||
filePath.startsWith("file://")
|
||||
? filePath
|
||||
@ -17,7 +18,7 @@ export async function importOrRequireFile(
|
||||
"esm",
|
||||
]
|
||||
}
|
||||
const tryToRequire = async (): Promise<[any, "commonjs"]> => {
|
||||
const tryToRequire = (): [any, "commonjs"] => {
|
||||
return [require(filePath), "commonjs"]
|
||||
}
|
||||
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { DeepPartial } from "../common/DeepPartial"
|
||||
import { ObjectLiteral } from "../common/ObjectLiteral"
|
||||
import {
|
||||
PrimitiveCriteria,
|
||||
@ -47,11 +48,11 @@ export class OrmUtils {
|
||||
}, [] as Array<{ id: R; items: T[] }>)
|
||||
}
|
||||
|
||||
public static uniq<T>(array: T[], criteria?: (item: T) => any): T[]
|
||||
public static uniq<T>(array: T[], criteria?: (item: T) => unknown): T[]
|
||||
public static uniq<T, K extends keyof T>(array: T[], property: K): T[]
|
||||
public static uniq<T, K extends keyof T>(
|
||||
array: T[],
|
||||
criteriaOrProperty?: ((item: T) => any) | K,
|
||||
criteriaOrProperty?: ((item: T) => unknown) | K,
|
||||
): T[] {
|
||||
return array.reduce((uniqueArray, item) => {
|
||||
let found: boolean = false
|
||||
@ -80,7 +81,10 @@ export class OrmUtils {
|
||||
/**
|
||||
* Deep Object.assign.
|
||||
*/
|
||||
public static mergeDeep(target: any, ...sources: any[]): any {
|
||||
public static mergeDeep<T>(
|
||||
target: T,
|
||||
...sources: (DeepPartial<T> | undefined)[]
|
||||
): T {
|
||||
if (!sources.length) {
|
||||
return target
|
||||
}
|
||||
@ -101,7 +105,7 @@ export class OrmUtils {
|
||||
}
|
||||
|
||||
return Object.assign(
|
||||
Object.create(Object.getPrototypeOf(object)),
|
||||
Object.create(Object.getPrototypeOf(object)) as T,
|
||||
object,
|
||||
)
|
||||
}
|
||||
@ -111,24 +115,24 @@ export class OrmUtils {
|
||||
*
|
||||
* @see http://stackoverflow.com/a/1144249
|
||||
*/
|
||||
public static deepCompare(...args: any[]): boolean {
|
||||
public static deepCompare<T>(...args: T[]): boolean {
|
||||
let i: any, l: any, leftChain: any, rightChain: any
|
||||
|
||||
if (arguments.length < 1) {
|
||||
if (args.length < 1) {
|
||||
return true // Die silently? Don't know how to handle such case, please help...
|
||||
// throw "Need two or more arguments to compare";
|
||||
}
|
||||
|
||||
for (i = 1, l = arguments.length; i < l; i++) {
|
||||
for (i = 1, l = args.length; i < l; i++) {
|
||||
leftChain = [] // Todo: this can be cached
|
||||
rightChain = []
|
||||
|
||||
if (
|
||||
!this.compare2Objects(
|
||||
!OrmUtils.compare2Objects(
|
||||
leftChain,
|
||||
rightChain,
|
||||
arguments[0],
|
||||
arguments[i],
|
||||
args[0],
|
||||
args[i],
|
||||
)
|
||||
) {
|
||||
return false
|
||||
@ -141,7 +145,7 @@ export class OrmUtils {
|
||||
/**
|
||||
* Gets deeper value of object.
|
||||
*/
|
||||
public static deepValue(obj: ObjectLiteral, path: string) {
|
||||
public static deepValue(obj: ObjectLiteral, path: string): any {
|
||||
const segments = path.split(".")
|
||||
for (let i = 0, len = segments.length; i < len; i++) {
|
||||
obj = obj[segments[i]]
|
||||
@ -155,7 +159,7 @@ export class OrmUtils {
|
||||
if (Object.keys(obj[key]).length === 0) {
|
||||
obj[key] = true
|
||||
} else {
|
||||
this.replaceEmptyObjectsWithBooleans(obj[key])
|
||||
OrmUtils.replaceEmptyObjectsWithBooleans(obj[key])
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -185,7 +189,7 @@ export class OrmUtils {
|
||||
}
|
||||
}
|
||||
}
|
||||
this.replaceEmptyObjectsWithBooleans(obj)
|
||||
OrmUtils.replaceEmptyObjectsWithBooleans(obj)
|
||||
return obj
|
||||
}
|
||||
|
||||
@ -233,23 +237,14 @@ export class OrmUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* Composes an object from the given array of keys and values.
|
||||
* Checks if two arrays of unique values contain the same values
|
||||
*/
|
||||
public static zipObject(keys: any[], values: any[]): ObjectLiteral {
|
||||
return keys.reduce((object, column, index) => {
|
||||
object[column] = values[index]
|
||||
return object
|
||||
}, {} as ObjectLiteral)
|
||||
}
|
||||
public static isArraysEqual<T>(arr1: T[], arr2: T[]): boolean {
|
||||
if (arr1.length !== arr2.length) {
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares two arrays.
|
||||
*/
|
||||
public static isArraysEqual(arr1: any[], arr2: any[]): boolean {
|
||||
if (arr1.length !== arr2.length) return false
|
||||
return arr1.every((element) => {
|
||||
return arr2.indexOf(element) !== -1
|
||||
})
|
||||
return arr1.every((element) => arr2.includes(element))
|
||||
}
|
||||
|
||||
public static areMutuallyExclusive<T>(...lists: T[][]): boolean {
|
||||
@ -346,7 +341,8 @@ export class OrmUtils {
|
||||
criteria === null ||
|
||||
criteria === "" ||
|
||||
(Array.isArray(criteria) && criteria.length === 0) ||
|
||||
(this.isPlainObject(criteria) && Object.keys(criteria).length === 0)
|
||||
(OrmUtils.isPlainObject(criteria) &&
|
||||
Object.keys(criteria).length === 0)
|
||||
)
|
||||
}
|
||||
|
||||
@ -372,11 +368,11 @@ export class OrmUtils {
|
||||
): criteria is PrimitiveCriteria {
|
||||
if (Array.isArray(criteria)) {
|
||||
return criteria.every((value) =>
|
||||
this.isSinglePrimitiveCriteria(value),
|
||||
OrmUtils.isSinglePrimitiveCriteria(value),
|
||||
)
|
||||
}
|
||||
|
||||
return this.isSinglePrimitiveCriteria(criteria)
|
||||
return OrmUtils.isSinglePrimitiveCriteria(criteria)
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
@ -467,7 +463,12 @@ export class OrmUtils {
|
||||
rightChain.push(y)
|
||||
|
||||
if (
|
||||
!this.compare2Objects(leftChain, rightChain, x[p], y[p])
|
||||
!OrmUtils.compare2Objects(
|
||||
leftChain,
|
||||
rightChain,
|
||||
x[p],
|
||||
y[p],
|
||||
)
|
||||
) {
|
||||
return false
|
||||
}
|
||||
@ -516,7 +517,7 @@ export class OrmUtils {
|
||||
return
|
||||
}
|
||||
|
||||
if (!this.isPlainObject(value) && !Array.isArray(value)) {
|
||||
if (!OrmUtils.isPlainObject(value) && !Array.isArray(value)) {
|
||||
target[key] = value
|
||||
return
|
||||
}
|
||||
@ -526,7 +527,7 @@ export class OrmUtils {
|
||||
}
|
||||
|
||||
memo.set(value, target[key])
|
||||
this.merge(target[key], value, memo)
|
||||
OrmUtils.merge(target[key], value, memo)
|
||||
memo.delete(value)
|
||||
}
|
||||
|
||||
@ -550,7 +551,7 @@ export class OrmUtils {
|
||||
return
|
||||
}
|
||||
|
||||
if (!this.isPlainObject(value) && !Array.isArray(value)) {
|
||||
if (!OrmUtils.isPlainObject(value) && !Array.isArray(value)) {
|
||||
Object.assign(target, { [key]: value })
|
||||
return
|
||||
}
|
||||
@ -560,25 +561,27 @@ export class OrmUtils {
|
||||
}
|
||||
|
||||
memo.set(value, target[key])
|
||||
this.merge(target[key], value, memo)
|
||||
OrmUtils.merge(target[key], value, memo)
|
||||
memo.delete(value)
|
||||
}
|
||||
|
||||
private static merge(
|
||||
target: any,
|
||||
source: any,
|
||||
private static merge<T>(
|
||||
target: T,
|
||||
source: DeepPartial<T> | undefined,
|
||||
memo: Map<any, any> = new Map(),
|
||||
): any {
|
||||
if (this.isPlainObject(target) && this.isPlainObject(source)) {
|
||||
for (const key of Object.keys(source)) {
|
||||
): void {
|
||||
if (OrmUtils.isPlainObject(target) && OrmUtils.isPlainObject(source)) {
|
||||
for (const [key, value] of Object.entries(
|
||||
source as ObjectLiteral,
|
||||
)) {
|
||||
if (key === "__proto__") continue
|
||||
this.mergeObjectKey(target, key, source[key], memo)
|
||||
OrmUtils.mergeObjectKey(target, key, value, memo)
|
||||
}
|
||||
}
|
||||
|
||||
if (Array.isArray(target) && Array.isArray(source)) {
|
||||
for (let key = 0; key < source.length; key++) {
|
||||
this.mergeArrayKey(target, key, source[key], memo)
|
||||
OrmUtils.mergeArrayKey(target, key, source[key], memo)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -69,7 +69,7 @@ describe("columns > value-transformer functionality", () => {
|
||||
it("should apply three transformers in the right order", () =>
|
||||
Promise.all(
|
||||
connections.map(async (connection) => {
|
||||
const userRepository = await connection.getRepository(User)
|
||||
const userRepository = connection.getRepository(User)
|
||||
const email = `${connection.name}@JOHN.doe`
|
||||
const user = new User()
|
||||
user.email = email
|
||||
@ -77,16 +77,14 @@ describe("columns > value-transformer functionality", () => {
|
||||
await userRepository.save(user)
|
||||
|
||||
const dbUser = await userRepository.findOneBy({ id: user.id })
|
||||
dbUser && dbUser.email.should.be.eql(email.toLocaleLowerCase())
|
||||
expect(dbUser!.email).to.equal(email.toLocaleLowerCase())
|
||||
}),
|
||||
))
|
||||
|
||||
it("should apply all the transformers", () =>
|
||||
Promise.all(
|
||||
connections.map(async (connection) => {
|
||||
const categoryRepository = await connection.getRepository(
|
||||
Category,
|
||||
)
|
||||
const categoryRepository = connection.getRepository(Category)
|
||||
const description = ` ${connection.name}-DESCRIPTION `
|
||||
const category = new Category()
|
||||
category.description = description
|
||||
@ -96,17 +94,16 @@ describe("columns > value-transformer functionality", () => {
|
||||
const dbCategory = await categoryRepository.findOneBy({
|
||||
id: category.id,
|
||||
})
|
||||
dbCategory &&
|
||||
dbCategory.description.should.be.eql(
|
||||
description.toLocaleLowerCase().trim(),
|
||||
)
|
||||
expect(dbCategory!.description).to.equal(
|
||||
description.toLocaleLowerCase().trim(),
|
||||
)
|
||||
}),
|
||||
))
|
||||
|
||||
it("should apply no transformer", () =>
|
||||
Promise.all(
|
||||
connections.map(async (connection) => {
|
||||
const viewRepository = await connection.getRepository(View)
|
||||
const viewRepository = connection.getRepository(View)
|
||||
const title = `${connection.name}`
|
||||
const view = new View()
|
||||
view.title = title
|
||||
@ -114,7 +111,7 @@ describe("columns > value-transformer functionality", () => {
|
||||
await viewRepository.save(view)
|
||||
|
||||
const dbView = await viewRepository.findOneBy({ id: view.id })
|
||||
dbView && dbView.title.should.be.eql(title)
|
||||
expect(dbView!.title).to.equal(title)
|
||||
}),
|
||||
))
|
||||
|
||||
|
||||
@ -1,30 +1,34 @@
|
||||
import "reflect-metadata"
|
||||
import "../../utils/test-setup"
|
||||
import { expect } from "chai"
|
||||
import { Post } from "./entity/Post"
|
||||
import { Guest as GuestV1 } from "./entity/v1/Guest"
|
||||
import { Comment as CommentV1 } from "./entity/v1/Comment"
|
||||
import { Guest as GuestV2 } from "./entity/v2/Guest"
|
||||
import { Comment as CommentV2 } from "./entity/v2/Comment"
|
||||
import { View } from "./entity/View"
|
||||
import { Category } from "./entity/Category"
|
||||
import "reflect-metadata"
|
||||
import {
|
||||
CannotConnectAlreadyConnectedError,
|
||||
CannotExecuteNotConnectedError,
|
||||
} from "../../../src"
|
||||
import { DataSource } from "../../../src/data-source/DataSource"
|
||||
import { PostgresConnectionOptions } from "../../../src/driver/postgres/PostgresConnectionOptions"
|
||||
import { EntityManager } from "../../../src/entity-manager/EntityManager"
|
||||
import { CannotGetEntityManagerNotConnectedError } from "../../../src/error/CannotGetEntityManagerNotConnectedError"
|
||||
import { NoConnectionForRepositoryError } from "../../../src/error/NoConnectionForRepositoryError"
|
||||
import { Repository } from "../../../src/repository/Repository"
|
||||
import { TreeRepository } from "../../../src/repository/TreeRepository"
|
||||
import "../../utils/test-setup"
|
||||
import {
|
||||
closeTestingConnections,
|
||||
createTestingConnections,
|
||||
setupSingleTestingConnection,
|
||||
} from "../../utils/test-utils"
|
||||
import { DataSource } from "../../../src/data-source/DataSource"
|
||||
import { Repository } from "../../../src/repository/Repository"
|
||||
import { TreeRepository } from "../../../src/repository/TreeRepository"
|
||||
import { NoConnectionForRepositoryError } from "../../../src/error/NoConnectionForRepositoryError"
|
||||
import { EntityManager } from "../../../src/entity-manager/EntityManager"
|
||||
import { CannotGetEntityManagerNotConnectedError } from "../../../src/error/CannotGetEntityManagerNotConnectedError"
|
||||
import { PostgresConnectionOptions } from "../../../src/driver/postgres/PostgresConnectionOptions"
|
||||
import { Category } from "./entity/Category"
|
||||
import { Post } from "./entity/Post"
|
||||
import { Comment as CommentV1 } from "./entity/v1/Comment"
|
||||
import { Guest as GuestV1 } from "./entity/v1/Guest"
|
||||
import { Comment as CommentV2 } from "./entity/v2/Comment"
|
||||
import { Guest as GuestV2 } from "./entity/v2/Guest"
|
||||
import { View } from "./entity/View"
|
||||
|
||||
describe("Connection", () => {
|
||||
// const resourceDir = __dirname + "/../../../../../test/functional/connection/";
|
||||
|
||||
describe("before connection is established", function () {
|
||||
describe("before connection is established", () => {
|
||||
let dataSource: DataSource
|
||||
before(async () => {
|
||||
const options = setupSingleTestingConnection("mysql", {
|
||||
@ -36,8 +40,9 @@ describe("Connection", () => {
|
||||
dataSource = new DataSource(options)
|
||||
})
|
||||
after(() => {
|
||||
if (dataSource && dataSource.isInitialized)
|
||||
if (dataSource?.isInitialized) {
|
||||
return dataSource.destroy()
|
||||
}
|
||||
|
||||
return Promise.resolve()
|
||||
})
|
||||
@ -45,7 +50,7 @@ describe("Connection", () => {
|
||||
it("connection.isConnected should be false", () => {
|
||||
if (!dataSource) return
|
||||
|
||||
dataSource.isInitialized.should.be.false
|
||||
expect(dataSource.isInitialized).to.equal(false)
|
||||
})
|
||||
|
||||
it.skip("entity manager and reactive entity manager should not be accessible", () => {
|
||||
@ -69,14 +74,20 @@ describe("Connection", () => {
|
||||
]);
|
||||
});*/
|
||||
|
||||
it("should not be able to close", () => {
|
||||
it("should not be able to close", async () => {
|
||||
if (!dataSource) return
|
||||
return dataSource.close().should.be.rejected // CannotCloseNotConnectedError
|
||||
|
||||
await expect(dataSource.destroy()).to.eventually.be.rejectedWith(
|
||||
CannotExecuteNotConnectedError,
|
||||
)
|
||||
})
|
||||
|
||||
it("should not be able to sync a schema", () => {
|
||||
it("should not be able to sync a schema", async () => {
|
||||
if (!dataSource) return
|
||||
return dataSource.synchronize().should.be.rejected // CannotCloseNotConnectedError
|
||||
|
||||
await expect(
|
||||
dataSource.synchronize(),
|
||||
).to.eventually.be.rejectedWith(CannotExecuteNotConnectedError) // CannotCloseNotConnectedError
|
||||
})
|
||||
|
||||
it.skip("should not be able to use repositories", () => {
|
||||
@ -92,14 +103,15 @@ describe("Connection", () => {
|
||||
// expect(() => connection.getReactiveTreeRepository(Category)).to.throw(NoConnectionForRepositoryError);
|
||||
})
|
||||
|
||||
it("should be able to connect", () => {
|
||||
it("should be able to connect", async () => {
|
||||
if (!dataSource) return
|
||||
return dataSource.connect().should.be.fulfilled
|
||||
|
||||
await expect(dataSource.initialize()).to.eventually.be.fulfilled
|
||||
})
|
||||
})
|
||||
|
||||
describe.skip("establishing connection", function () {
|
||||
it("should throw DriverOptionNotSetError when extra.socketPath and host is missing", function () {
|
||||
describe.skip("establishing connection", () => {
|
||||
it("should throw DriverOptionNotSetError when extra.socketPath and host is missing", () => {
|
||||
expect(() => {
|
||||
new DataSource({
|
||||
type: "mysql",
|
||||
@ -113,7 +125,7 @@ describe("Connection", () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe("after connection is established successfully", function () {
|
||||
describe("after connection is established successfully", () => {
|
||||
let connections: DataSource[]
|
||||
beforeEach(() =>
|
||||
createTestingConnections({
|
||||
@ -126,7 +138,7 @@ describe("Connection", () => {
|
||||
|
||||
it("connection.isConnected should be true", () =>
|
||||
connections.forEach((connection) => {
|
||||
connection.isInitialized.should.be.true
|
||||
expect(connection.isInitialized).to.equal(true)
|
||||
}))
|
||||
|
||||
it("entity manager and reactive entity manager should be accessible", () =>
|
||||
@ -136,19 +148,26 @@ describe("Connection", () => {
|
||||
}))
|
||||
|
||||
it("should not be able to connect again", () =>
|
||||
connections.forEach((connection) => {
|
||||
return connection.connect().should.be.rejected // CannotConnectAlreadyConnectedError
|
||||
}))
|
||||
Promise.all(
|
||||
connections.map(async (connection) => {
|
||||
await expect(
|
||||
connection.initialize(),
|
||||
).to.eventually.be.rejectedWith(
|
||||
CannotConnectAlreadyConnectedError,
|
||||
)
|
||||
}),
|
||||
))
|
||||
|
||||
it("should be able to close a connection", async () =>
|
||||
Promise.all(
|
||||
connections.map((connection) => {
|
||||
return connection.close()
|
||||
connections.map(async (connection) => {
|
||||
await expect(connection.destroy()).to.eventually.be
|
||||
.fulfilled
|
||||
}),
|
||||
))
|
||||
})
|
||||
|
||||
describe("working with repositories after connection is established successfully", function () {
|
||||
describe("working with repositories after connection is established successfully", () => {
|
||||
let connections: DataSource[]
|
||||
before(() =>
|
||||
createTestingConnections({
|
||||
@ -202,7 +221,7 @@ describe("Connection", () => {
|
||||
// }));
|
||||
})
|
||||
|
||||
describe("generate a schema when connection.synchronize is called", function () {
|
||||
describe("generate a schema when connection.synchronize is called", () => {
|
||||
let connections: DataSource[]
|
||||
before(() =>
|
||||
createTestingConnections({
|
||||
@ -228,12 +247,12 @@ describe("Connection", () => {
|
||||
const againLoadedPost = await postRepository.findOneBy({
|
||||
id: post.id,
|
||||
})
|
||||
expect(againLoadedPost).to.be.null
|
||||
expect(againLoadedPost).to.equal(null)
|
||||
}),
|
||||
))
|
||||
})
|
||||
|
||||
describe("log a schema when connection.logSyncSchema is called", function () {
|
||||
describe("log a schema when connection.logSyncSchema is called", () => {
|
||||
let connections: DataSource[]
|
||||
before(
|
||||
async () =>
|
||||
@ -252,34 +271,38 @@ describe("Connection", () => {
|
||||
))
|
||||
})
|
||||
|
||||
describe("after connection is closed successfully", function () {
|
||||
describe("after connection is closed successfully", () => {
|
||||
// open a close connections
|
||||
let connections: DataSource[] = []
|
||||
before(() =>
|
||||
createTestingConnections({
|
||||
before(async () => {
|
||||
connections = await createTestingConnections({
|
||||
entities: [Post],
|
||||
schemaCreate: true,
|
||||
dropSchema: true,
|
||||
}).then((all) => {
|
||||
connections = all
|
||||
return Promise.all(
|
||||
connections.map((connection) => connection.close()),
|
||||
)
|
||||
}),
|
||||
)
|
||||
})
|
||||
await Promise.all(
|
||||
connections.map((connection) => connection.destroy()),
|
||||
)
|
||||
})
|
||||
|
||||
it("should not be able to close already closed connection", () =>
|
||||
connections.forEach((connection) => {
|
||||
return connection.close().should.be.rejected // CannotCloseNotConnectedError
|
||||
}))
|
||||
Promise.all(
|
||||
connections.map(async (connection) => {
|
||||
await expect(
|
||||
connection.destroy(),
|
||||
).to.eventually.be.rejectedWith(
|
||||
CannotExecuteNotConnectedError,
|
||||
)
|
||||
}),
|
||||
))
|
||||
|
||||
it("connection.isConnected should be false", () =>
|
||||
it("connection.isInitialized should be false", () =>
|
||||
connections.forEach((connection) => {
|
||||
connection.isInitialized.should.be.false
|
||||
expect(connection.isInitialized).to.equal(false)
|
||||
}))
|
||||
})
|
||||
|
||||
describe("skip schema generation when synchronize option is set to false", function () {
|
||||
describe("skip schema generation when synchronize option is set to false", () => {
|
||||
let connections: DataSource[]
|
||||
beforeEach(() =>
|
||||
createTestingConnections({
|
||||
@ -288,15 +311,16 @@ describe("Connection", () => {
|
||||
}).then((all) => (connections = all)),
|
||||
)
|
||||
afterEach(() => closeTestingConnections(connections))
|
||||
|
||||
it("database should be empty after schema sync", () =>
|
||||
Promise.all(
|
||||
connections.map(async (connection) => {
|
||||
await connection.synchronize(true)
|
||||
const queryRunner = connection.createQueryRunner()
|
||||
const schema = await queryRunner.getTables(["view"])
|
||||
const tables = await queryRunner.getTables(["view"])
|
||||
const tableNames = tables.map((table) => table.name)
|
||||
await queryRunner.release()
|
||||
expect(schema.some((table) => table.name === "view")).to.be
|
||||
.false
|
||||
expect(tableNames).to.have.length(0)
|
||||
}),
|
||||
))
|
||||
})
|
||||
@ -366,8 +390,8 @@ describe("Connection", () => {
|
||||
})
|
||||
afterEach(() => closeTestingConnections(connections))
|
||||
|
||||
it("schema name can be set", () => {
|
||||
return Promise.all(
|
||||
it("schema name can be set", () =>
|
||||
Promise.all(
|
||||
connections.map(async (connection) => {
|
||||
await connection.synchronize(true)
|
||||
const schemaName = (
|
||||
@ -388,7 +412,6 @@ describe("Connection", () => {
|
||||
await queryRunner.release()
|
||||
expect(rows[0]["context"]).to.be.eq(comment.context)
|
||||
}),
|
||||
)
|
||||
})
|
||||
))
|
||||
})
|
||||
})
|
||||
|
||||
@ -40,7 +40,7 @@ describe("custom repository", () => {
|
||||
await dataSource.manager.transaction(
|
||||
async (transactionalManager) => {
|
||||
const transactionalCustomRepository =
|
||||
await transactionalManager.withRepository(
|
||||
transactionalManager.withRepository(
|
||||
CustomRepository,
|
||||
)
|
||||
await transactionalCustomRepository.save({
|
||||
|
||||
@ -40,7 +40,7 @@ describe("database-schema > vectors > sap", () => {
|
||||
await dataSource.synchronize()
|
||||
|
||||
// Verify column metadata
|
||||
const queryRunner = await dataSource.createQueryRunner()
|
||||
const queryRunner = dataSource.createQueryRunner()
|
||||
const table = (await queryRunner.getTable(
|
||||
dataSource.getMetadata(ArrayEmbedding).tableName,
|
||||
))!
|
||||
|
||||
@ -16,8 +16,8 @@ describe("driver > mysql > connection options > enableQueryTimeout", () => {
|
||||
dropSchema: true,
|
||||
enabledDrivers: ["mysql"],
|
||||
}
|
||||
const timeoutMs = 10
|
||||
const longQueryTimeSec = 0.02
|
||||
const timeoutMs = 150
|
||||
const longQueryTimeSec = 0.2
|
||||
const shortQueryTimeSec = 0.005
|
||||
|
||||
describe("when enableQueryTimeout is true", () => {
|
||||
|
||||
@ -23,33 +23,33 @@ describe("entity subscriber > transaction flow", () => {
|
||||
|
||||
@EventSubscriber()
|
||||
class PostSubscriber implements EntitySubscriberInterface {
|
||||
beforeTransactionStart() {
|
||||
if (beforeTransactionStart) beforeTransactionStart(arguments)
|
||||
beforeTransactionStart(...args: any[]) {
|
||||
if (beforeTransactionStart) beforeTransactionStart(...args)
|
||||
}
|
||||
|
||||
afterTransactionStart() {
|
||||
if (afterTransactionStart) afterTransactionStart(arguments)
|
||||
afterTransactionStart(...args: any[]) {
|
||||
if (afterTransactionStart) afterTransactionStart(...args)
|
||||
}
|
||||
|
||||
afterInsert() {
|
||||
afterInsertQueryRunnerData = arguments[0].queryRunner.data
|
||||
if (afterInsert) afterInsert(arguments)
|
||||
afterInsert(...args: any[]) {
|
||||
afterInsertQueryRunnerData = args[0].queryRunner.data
|
||||
if (afterInsert) afterInsert(...args)
|
||||
}
|
||||
|
||||
beforeTransactionCommit() {
|
||||
if (beforeTransactionCommit) beforeTransactionCommit(arguments)
|
||||
beforeTransactionCommit(...args: any[]) {
|
||||
if (beforeTransactionCommit) beforeTransactionCommit(...args)
|
||||
}
|
||||
|
||||
afterTransactionCommit() {
|
||||
if (afterTransactionCommit) afterTransactionCommit(arguments)
|
||||
afterTransactionCommit(...args: any[]) {
|
||||
if (afterTransactionCommit) afterTransactionCommit(...args)
|
||||
}
|
||||
|
||||
beforeTransactionRollback() {
|
||||
if (beforeTransactionRollback) beforeTransactionRollback(arguments)
|
||||
beforeTransactionRollback(...args: any[]) {
|
||||
if (beforeTransactionRollback) beforeTransactionRollback(...args)
|
||||
}
|
||||
|
||||
afterTransactionRollback() {
|
||||
if (afterTransactionRollback) afterTransactionRollback(arguments)
|
||||
afterTransactionRollback(...args: any[]) {
|
||||
if (afterTransactionRollback) afterTransactionRollback(...args)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -21,52 +21,50 @@ describe("query builder > brackets", () => {
|
||||
beforeEach(() => reloadTestingDatabases(connections))
|
||||
after(() => closeTestingConnections(connections))
|
||||
|
||||
it("should put parentheses in the SQL", () =>
|
||||
Promise.all(
|
||||
connections.map(async (connection) => {
|
||||
const sql = await connection
|
||||
.createQueryBuilder(User, "user")
|
||||
.where("user.isAdmin = :isAdmin", { isAdmin: true })
|
||||
.orWhere(
|
||||
new Brackets((qb) => {
|
||||
qb.where("user.firstName = :firstName1", {
|
||||
firstName1: "Hello",
|
||||
}).andWhere("user.lastName = :lastName1", {
|
||||
lastName1: "Mars",
|
||||
})
|
||||
}),
|
||||
)
|
||||
.orWhere(
|
||||
new Brackets((qb) => {
|
||||
qb.where("user.firstName = :firstName2", {
|
||||
firstName2: "Hello",
|
||||
}).andWhere("user.lastName = :lastName2", {
|
||||
lastName2: "Earth",
|
||||
})
|
||||
}),
|
||||
)
|
||||
.andWhere(
|
||||
new Brackets((qb) => {
|
||||
qb.where(
|
||||
"user.firstName = :firstName3 AND foo = bar",
|
||||
{ firstName3: "Hello" },
|
||||
)
|
||||
}),
|
||||
)
|
||||
.disableEscaping()
|
||||
.getSql()
|
||||
|
||||
expect(sql).to.be.equal(
|
||||
"SELECT user.id AS user_id, user.firstName AS user_firstName, " +
|
||||
"user.lastName AS user_lastName, user.isAdmin AS user_isAdmin " +
|
||||
"FROM user user " +
|
||||
"WHERE user.isAdmin = ? " +
|
||||
"OR (user.firstName = ? AND user.lastName = ?) " +
|
||||
"OR (user.firstName = ? AND user.lastName = ?) " +
|
||||
"AND (user.firstName = ? AND foo = bar)",
|
||||
it("should put parentheses in the SQL", () => {
|
||||
for (const connection of connections) {
|
||||
const sql = connection
|
||||
.createQueryBuilder(User, "user")
|
||||
.where("user.isAdmin = :isAdmin", { isAdmin: true })
|
||||
.orWhere(
|
||||
new Brackets((qb) => {
|
||||
qb.where("user.firstName = :firstName1", {
|
||||
firstName1: "Hello",
|
||||
}).andWhere("user.lastName = :lastName1", {
|
||||
lastName1: "Mars",
|
||||
})
|
||||
}),
|
||||
)
|
||||
}),
|
||||
))
|
||||
.orWhere(
|
||||
new Brackets((qb) => {
|
||||
qb.where("user.firstName = :firstName2", {
|
||||
firstName2: "Hello",
|
||||
}).andWhere("user.lastName = :lastName2", {
|
||||
lastName2: "Earth",
|
||||
})
|
||||
}),
|
||||
)
|
||||
.andWhere(
|
||||
new Brackets((qb) => {
|
||||
qb.where("user.firstName = :firstName3 AND foo = bar", {
|
||||
firstName3: "Hello",
|
||||
})
|
||||
}),
|
||||
)
|
||||
.disableEscaping()
|
||||
.getSql()
|
||||
|
||||
expect(sql).to.be.equal(
|
||||
"SELECT user.id AS user_id, user.firstName AS user_firstName, " +
|
||||
"user.lastName AS user_lastName, user.isAdmin AS user_isAdmin " +
|
||||
"FROM user user " +
|
||||
"WHERE user.isAdmin = ? " +
|
||||
"OR (user.firstName = ? AND user.lastName = ?) " +
|
||||
"OR (user.firstName = ? AND user.lastName = ?) " +
|
||||
"AND (user.firstName = ? AND foo = bar)",
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
it("should put brackets correctly into WHERE expression", () =>
|
||||
Promise.all(
|
||||
|
||||
@ -5,13 +5,13 @@ import {
|
||||
closeTestingConnections,
|
||||
reloadTestingDatabases,
|
||||
} from "../../../utils/test-utils"
|
||||
import { Connection } from "../../../../src/connection/Connection"
|
||||
import { Foo } from "./entity/foo"
|
||||
import { filterByCteCapabilities } from "./helpers"
|
||||
import { QueryBuilderCteOptions } from "../../../../src/query-builder/QueryBuilderCte"
|
||||
import { DataSource } from "../../../../src"
|
||||
|
||||
describe("query builder > cte > materialized", () => {
|
||||
let connections: Connection[]
|
||||
let connections: DataSource[]
|
||||
before(
|
||||
async () =>
|
||||
(connections = await createTestingConnections({
|
||||
@ -49,7 +49,7 @@ describe("query builder > cte > materialized", () => {
|
||||
|
||||
const cteSelection = "qaz.raz"
|
||||
|
||||
const qb = await connection
|
||||
const qb = connection
|
||||
.createQueryBuilder()
|
||||
.addCommonTableExpression(cteQuery, "qaz", cteOptions)
|
||||
.from("qaz", "qaz")
|
||||
@ -88,7 +88,7 @@ describe("query builder > cte > materialized", () => {
|
||||
|
||||
const cteSelection = "qaz.raz"
|
||||
|
||||
const qb = await connection
|
||||
const qb = connection
|
||||
.createQueryBuilder()
|
||||
.addCommonTableExpression(cteQuery, "qaz", cteOptions)
|
||||
.from("qaz", "qaz")
|
||||
@ -126,7 +126,7 @@ describe("query builder > cte > materialized", () => {
|
||||
|
||||
const cteSelection = "qaz.raz"
|
||||
|
||||
const qb = await connection
|
||||
const qb = connection
|
||||
.createQueryBuilder()
|
||||
.addCommonTableExpression(cteQuery, "qaz", cteOptions)
|
||||
.from("qaz", "qaz")
|
||||
|
||||
@ -24,7 +24,7 @@ describe("query builder > not", () => {
|
||||
it("should put negation in the SQL with one condition", () =>
|
||||
Promise.all(
|
||||
connections.map(async (connection) => {
|
||||
const sql = await connection
|
||||
const sql = connection
|
||||
.createQueryBuilder(User, "user")
|
||||
.where("user.isAdmin = :isAdmin", { isAdmin: true })
|
||||
.andWhere(
|
||||
@ -50,7 +50,7 @@ describe("query builder > not", () => {
|
||||
it("should put negation in the SQL with two condition", () =>
|
||||
Promise.all(
|
||||
connections.map(async (connection) => {
|
||||
const sql = await connection
|
||||
const sql = connection
|
||||
.createQueryBuilder(User, "user")
|
||||
.where("user.isAdmin = :isAdmin", { isAdmin: true })
|
||||
.andWhere(
|
||||
|
||||
@ -76,7 +76,7 @@ describe("query builder > sub-query", () => {
|
||||
connections.map(async (connection) => {
|
||||
await prepare(connection)
|
||||
|
||||
const qb = await connection
|
||||
const qb = connection
|
||||
.getRepository(Post)
|
||||
.createQueryBuilder("post")
|
||||
const posts = await qb
|
||||
@ -161,7 +161,7 @@ describe("query builder > sub-query", () => {
|
||||
connections.map(async (connection) => {
|
||||
await prepare(connection)
|
||||
|
||||
const userQb = await connection
|
||||
const userQb = connection
|
||||
.getRepository(User)
|
||||
.createQueryBuilder("usr")
|
||||
.select("usr.name")
|
||||
@ -187,7 +187,7 @@ describe("query builder > sub-query", () => {
|
||||
connections.map(async (connection) => {
|
||||
await prepare(connection)
|
||||
|
||||
const userQb = await connection
|
||||
const userQb = connection
|
||||
.getRepository(User)
|
||||
.createQueryBuilder("usr")
|
||||
.select("usr.name", "name")
|
||||
@ -217,7 +217,7 @@ describe("query builder > sub-query", () => {
|
||||
connections.map(async (connection) => {
|
||||
await prepare(connection)
|
||||
|
||||
const userQb = await connection
|
||||
const userQb = connection
|
||||
.getRepository(User)
|
||||
.createQueryBuilder("usr")
|
||||
.select("usr.name", "name")
|
||||
@ -254,7 +254,7 @@ describe("query builder > sub-query", () => {
|
||||
connections.map(async (connection) => {
|
||||
await prepare(connection)
|
||||
|
||||
const userQb = await connection
|
||||
const userQb = connection
|
||||
.getRepository(User)
|
||||
.createQueryBuilder("usr")
|
||||
.select("usr.name", "name")
|
||||
|
||||
@ -32,7 +32,7 @@ describe("query builder > time-travel-query", () => {
|
||||
it("should execute time travel query without options", () =>
|
||||
Promise.all(
|
||||
connections.map(async (connection) => {
|
||||
const repository = await connection.getRepository(Account)
|
||||
const repository = connection.getRepository(Account)
|
||||
// create account
|
||||
let account = new Account()
|
||||
account.name = "Edna Barath"
|
||||
@ -64,7 +64,7 @@ describe("query builder > time-travel-query", () => {
|
||||
it("should execute time travel query with options", () =>
|
||||
Promise.all(
|
||||
connections.map(async (connection) => {
|
||||
const repository = await connection.getRepository(Account)
|
||||
const repository = connection.getRepository(Account)
|
||||
// create account
|
||||
let account = new Account()
|
||||
account.name = "Edna Barath"
|
||||
@ -96,7 +96,7 @@ describe("query builder > time-travel-query", () => {
|
||||
it("should execute time travel query with 'skip' and 'take' options", () =>
|
||||
Promise.all(
|
||||
connections.map(async (connection) => {
|
||||
const repository = await connection.getRepository(Account)
|
||||
const repository = connection.getRepository(Account)
|
||||
// create accounts
|
||||
for (let i = 1; i < 6; i++) {
|
||||
const account = new Account()
|
||||
@ -148,10 +148,8 @@ describe("query builder > time-travel-query", () => {
|
||||
it("should execute time travel query with JOIN and skip/take options", () =>
|
||||
Promise.all(
|
||||
connections.map(async (connection) => {
|
||||
const accountRepository = await connection.getRepository(
|
||||
Account,
|
||||
)
|
||||
const personRepository = await connection.getRepository(Person)
|
||||
const accountRepository = connection.getRepository(Account)
|
||||
const personRepository = connection.getRepository(Person)
|
||||
|
||||
// create persons and accounts
|
||||
for (let i = 1; i < 6; i++) {
|
||||
@ -210,10 +208,8 @@ describe("query builder > time-travel-query", () => {
|
||||
it("should execute time travel query with JOIN and limit/offset options", () =>
|
||||
Promise.all(
|
||||
connections.map(async (connection) => {
|
||||
const accountRepository = await connection.getRepository(
|
||||
Account,
|
||||
)
|
||||
const personRepository = await connection.getRepository(Person)
|
||||
const accountRepository = connection.getRepository(Account)
|
||||
const personRepository = connection.getRepository(Person)
|
||||
|
||||
// create persons and accounts
|
||||
for (let i = 1; i < 6; i++) {
|
||||
|
||||
@ -14,15 +14,14 @@ import { EntitySchema } from "../../../../../src"
|
||||
* So we run tests only for mysql.
|
||||
*/
|
||||
describe("basic-lazy-relations", () => {
|
||||
let UserSchema: any, ProfileSchema: any
|
||||
const appRoot = require("app-root-path")
|
||||
const resourceDir =
|
||||
appRoot +
|
||||
"/test/functional/relations/lazy-relations/basic-lazy-relation/"
|
||||
UserSchema = new EntitySchema<any>(
|
||||
const UserSchema = new EntitySchema(
|
||||
require(resourceDir + "schema/user.json"),
|
||||
)
|
||||
ProfileSchema = new EntitySchema<any>(
|
||||
const ProfileSchema = new EntitySchema(
|
||||
require(resourceDir + "schema/profile.json"),
|
||||
)
|
||||
|
||||
|
||||
@ -26,5 +26,5 @@ export class PostgresExample {
|
||||
createdAt: Date
|
||||
|
||||
@Column({ type: "jsonb", nullable: true })
|
||||
tags: any | null
|
||||
tags: string[] | null
|
||||
}
|
||||
|
||||
@ -28,12 +28,11 @@ describe("table-inheritance > single-table > database-option-inherited", () => {
|
||||
beforeEach(() => reloadTestingDatabases(connections))
|
||||
after(() => closeTestingConnections(connections))
|
||||
|
||||
it("should correctly inherit database option", () =>
|
||||
Promise.all(
|
||||
connections.map(async (connection) => {
|
||||
connection.entityMetadatas.forEach((metadata) =>
|
||||
metadata.database!.should.equal("test"),
|
||||
)
|
||||
}),
|
||||
))
|
||||
it("should correctly inherit database option", () => {
|
||||
connections.forEach((connection) => {
|
||||
connection.entityMetadatas.forEach((metadata) =>
|
||||
metadata.database!.should.equal("test"),
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -22,114 +22,111 @@ describe("mysql > tree tables > closure-table", () => {
|
||||
beforeEach(() => reloadTestingDatabases(connections))
|
||||
after(() => closeTestingConnections(connections))
|
||||
|
||||
it("foo1 should create closure columns unsigned", () =>
|
||||
Promise.all(
|
||||
connections.map(async (dataSource) => {
|
||||
const fooMetadata = dataSource.entityMetadatas.find(
|
||||
(el) => el.tableName === "foo1",
|
||||
)!
|
||||
it("foo1 should create closure columns unsigned", () => {
|
||||
connections.forEach((dataSource) => {
|
||||
const fooMetadata = dataSource.entityMetadatas.find(
|
||||
(el) => el.tableName === "foo1",
|
||||
)!
|
||||
|
||||
expect(fooMetadata).to.exist
|
||||
expect(fooMetadata).to.exist
|
||||
|
||||
const fooClosureMetadata = dataSource.entityMetadatas.find(
|
||||
(el) => el.tableName === "foo1_closure",
|
||||
)!
|
||||
const fooClosureMetadata = dataSource.entityMetadatas.find(
|
||||
(el) => el.tableName === "foo1_closure",
|
||||
)!
|
||||
|
||||
expect(fooClosureMetadata).to.exist
|
||||
expect(fooClosureMetadata).to.exist
|
||||
|
||||
const ancestorCol = fooClosureMetadata.columns.find(
|
||||
(col) => col.databaseName === "ancestor_id",
|
||||
)!
|
||||
const ancestorCol = fooClosureMetadata.columns.find(
|
||||
(col) => col.databaseName === "ancestor_id",
|
||||
)!
|
||||
|
||||
expect(ancestorCol).to.exist
|
||||
expect(ancestorCol).to.exist
|
||||
|
||||
const descendantCol = fooClosureMetadata.columns.find(
|
||||
(col) => col.databaseName === "descendant_id",
|
||||
)!
|
||||
const descendantCol = fooClosureMetadata.columns.find(
|
||||
(col) => col.databaseName === "descendant_id",
|
||||
)!
|
||||
|
||||
expect(descendantCol).to.exist
|
||||
expect(descendantCol).to.exist
|
||||
|
||||
expect(ancestorCol.unsigned).to.be.true
|
||||
expect(descendantCol.unsigned).to.be.true
|
||||
}),
|
||||
))
|
||||
expect(ancestorCol.unsigned).to.be.true
|
||||
expect(descendantCol.unsigned).to.be.true
|
||||
})
|
||||
})
|
||||
|
||||
it("foo2 should create closure columns with specified zerofill, width, precision and scale", () =>
|
||||
Promise.all(
|
||||
connections.map(async (dataSource) => {
|
||||
const fooMetadata = dataSource.entityMetadatas.find(
|
||||
(el) => el.tableName === "foo2",
|
||||
)!
|
||||
it("foo2 should create closure columns with specified zerofill, width, precision and scale", () => {
|
||||
connections.forEach((dataSource) => {
|
||||
const fooMetadata = dataSource.entityMetadatas.find(
|
||||
(el) => el.tableName === "foo2",
|
||||
)!
|
||||
|
||||
expect(fooMetadata).to.exist
|
||||
expect(fooMetadata).to.exist
|
||||
|
||||
const fooClosureMetadata = dataSource.entityMetadatas.find(
|
||||
(el) => el.tableName === "foo2_closure",
|
||||
)!
|
||||
const fooClosureMetadata = dataSource.entityMetadatas.find(
|
||||
(el) => el.tableName === "foo2_closure",
|
||||
)!
|
||||
|
||||
expect(fooClosureMetadata).to.exist
|
||||
expect(fooClosureMetadata).to.exist
|
||||
|
||||
const ancestorCol = fooClosureMetadata.columns.find(
|
||||
(col) => col.databaseName === "ancestor_id",
|
||||
)!
|
||||
const ancestorCol = fooClosureMetadata.columns.find(
|
||||
(col) => col.databaseName === "ancestor_id",
|
||||
)!
|
||||
|
||||
expect(ancestorCol).to.exist
|
||||
expect(ancestorCol).to.exist
|
||||
|
||||
const descendantCol = fooClosureMetadata.columns.find(
|
||||
(col) => col.databaseName === "descendant_id",
|
||||
)!
|
||||
const descendantCol = fooClosureMetadata.columns.find(
|
||||
(col) => col.databaseName === "descendant_id",
|
||||
)!
|
||||
|
||||
expect(descendantCol).to.exist
|
||||
expect(descendantCol).to.exist
|
||||
|
||||
expect(ancestorCol.zerofill).to.be.true
|
||||
expect(descendantCol.zerofill).to.be.true
|
||||
expect(ancestorCol.zerofill).to.be.true
|
||||
expect(descendantCol.zerofill).to.be.true
|
||||
|
||||
expect(ancestorCol.width).to.be.eq(13)
|
||||
expect(descendantCol.width).to.be.eq(13)
|
||||
expect(ancestorCol.width).to.be.eq(13)
|
||||
expect(descendantCol.width).to.be.eq(13)
|
||||
|
||||
expect(ancestorCol.precision).to.be.eq(9)
|
||||
expect(descendantCol.precision).to.be.eq(9)
|
||||
expect(ancestorCol.precision).to.be.eq(9)
|
||||
expect(descendantCol.precision).to.be.eq(9)
|
||||
|
||||
expect(ancestorCol.scale).to.be.eq(3)
|
||||
expect(descendantCol.scale).to.be.eq(3)
|
||||
}),
|
||||
))
|
||||
expect(ancestorCol.scale).to.be.eq(3)
|
||||
expect(descendantCol.scale).to.be.eq(3)
|
||||
})
|
||||
})
|
||||
|
||||
it("foo3 should create closure columns with specified length, charset and collation", () =>
|
||||
Promise.all(
|
||||
connections.map(async (dataSource) => {
|
||||
const fooMetadata = dataSource.entityMetadatas.find(
|
||||
(el) => el.tableName === "foo3",
|
||||
)!
|
||||
it("foo3 should create closure columns with specified length, charset and collation", () => {
|
||||
connections.forEach((dataSource) => {
|
||||
const fooMetadata = dataSource.entityMetadatas.find(
|
||||
(el) => el.tableName === "foo3",
|
||||
)!
|
||||
|
||||
expect(fooMetadata).to.exist
|
||||
expect(fooMetadata).to.exist
|
||||
|
||||
const fooClosureMetadata = dataSource.entityMetadatas.find(
|
||||
(el) => el.tableName === "foo3_closure",
|
||||
)!
|
||||
const fooClosureMetadata = dataSource.entityMetadatas.find(
|
||||
(el) => el.tableName === "foo3_closure",
|
||||
)!
|
||||
|
||||
expect(fooClosureMetadata).to.exist
|
||||
expect(fooClosureMetadata).to.exist
|
||||
|
||||
const ancestorCol = fooClosureMetadata.columns.find(
|
||||
(col) => col.databaseName === "ancestor_id",
|
||||
)!
|
||||
const ancestorCol = fooClosureMetadata.columns.find(
|
||||
(col) => col.databaseName === "ancestor_id",
|
||||
)!
|
||||
|
||||
expect(ancestorCol).to.exist
|
||||
expect(ancestorCol).to.exist
|
||||
|
||||
const descendantCol = fooClosureMetadata.columns.find(
|
||||
(col) => col.databaseName === "descendant_id",
|
||||
)!
|
||||
const descendantCol = fooClosureMetadata.columns.find(
|
||||
(col) => col.databaseName === "descendant_id",
|
||||
)!
|
||||
|
||||
expect(descendantCol).to.exist
|
||||
expect(descendantCol).to.exist
|
||||
|
||||
expect(ancestorCol.length).to.be.eq("201")
|
||||
expect(descendantCol.length).to.be.eq("201")
|
||||
expect(ancestorCol.length).to.be.eq("201")
|
||||
expect(descendantCol.length).to.be.eq("201")
|
||||
|
||||
expect(ancestorCol.charset).to.be.eq("latin1")
|
||||
expect(descendantCol.charset).to.be.eq("latin1")
|
||||
expect(ancestorCol.charset).to.be.eq("latin1")
|
||||
expect(descendantCol.charset).to.be.eq("latin1")
|
||||
|
||||
expect(ancestorCol.collation).to.be.eq("latin1_bin")
|
||||
expect(descendantCol.collation).to.be.eq("latin1_bin")
|
||||
}),
|
||||
))
|
||||
expect(ancestorCol.collation).to.be.eq("latin1_bin")
|
||||
expect(descendantCol.collation).to.be.eq("latin1_bin")
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -25,18 +25,17 @@ describe("github issues > #10569 Fix type inferencing of EntityManager#create",
|
||||
beforeEach(() => reloadTestingDatabases(dataSources))
|
||||
after(() => closeTestingConnections(dataSources))
|
||||
|
||||
it("should correctly inference entity type", () =>
|
||||
Promise.all(
|
||||
dataSources.map(async (dataSource) => {
|
||||
const createUserContract: CreateUserContract = {
|
||||
name: "John Doe",
|
||||
}
|
||||
it("should correctly inference entity type", () => {
|
||||
dataSources.forEach((dataSource) => {
|
||||
const createUserContract: CreateUserContract = {
|
||||
name: "John Doe",
|
||||
}
|
||||
|
||||
const user = dataSource.manager.create(User, createUserContract)
|
||||
const user = dataSource.manager.create(User, createUserContract)
|
||||
|
||||
user.id = v4()
|
||||
user.id = v4()
|
||||
|
||||
expect(user.id).to.exist
|
||||
}),
|
||||
))
|
||||
expect(user.id).to.exist
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -24,7 +24,7 @@ describe("github issues > #10626 Postgres CREATE INDEX CONCURRENTLY bug", () =>
|
||||
it("has to create INDEX CONCURRENTLY", () =>
|
||||
Promise.all(
|
||||
dataSources.map(async (dataSource) => {
|
||||
await dataSource.setOptions({
|
||||
dataSource.setOptions({
|
||||
...dataSource.options,
|
||||
migrationsTransactionMode: "none",
|
||||
})
|
||||
@ -39,7 +39,7 @@ describe("github issues > #10626 Postgres CREATE INDEX CONCURRENTLY bug", () =>
|
||||
it("has to drop INDEX CONCURRENTLY", () =>
|
||||
Promise.all(
|
||||
dataSources.map(async (dataSource) => {
|
||||
await dataSource.setOptions({
|
||||
dataSource.setOptions({
|
||||
...dataSource.options,
|
||||
migrationsTransactionMode: "none",
|
||||
})
|
||||
|
||||
@ -14,15 +14,16 @@ describe("github issues > #108 Error with constraint names on postgres", () => {
|
||||
entities: [__dirname + "/entity/*{.js,.ts}"],
|
||||
schemaCreate: true,
|
||||
dropSchema: true,
|
||||
driverSpecific: { synchronize: false },
|
||||
})),
|
||||
)
|
||||
after(() => closeTestingConnections(connections))
|
||||
|
||||
it("should sync even when there unqiue constraints placed on similarly named columns", () =>
|
||||
it("should sync even when there unique constraints placed on similarly named columns", () =>
|
||||
Promise.all(
|
||||
connections.map(async (connection) => {
|
||||
// By virtue that we got here means that it must have worked.
|
||||
expect(true).is.true
|
||||
await expect(connection.synchronize()).to.eventually.be
|
||||
.fulfilled
|
||||
}),
|
||||
))
|
||||
})
|
||||
|
||||
@ -26,7 +26,7 @@ describe("github issues > #11085 BeforeQuery promises are not awaited before que
|
||||
it("should find user since beforeQuery promise must be awaited before query execution", async () =>
|
||||
Promise.all(
|
||||
connections.map(async (connection) => {
|
||||
const userRepository = await connection.getRepository(User)
|
||||
const userRepository = connection.getRepository(User)
|
||||
|
||||
const user = await userRepository.findBy({
|
||||
isActive: true,
|
||||
|
||||
@ -6,7 +6,7 @@ import { User } from "../entity/User"
|
||||
export class UserSubscriber implements EntitySubscriberInterface<any> {
|
||||
async beforeQuery(event: BeforeQueryEvent<any>): Promise<void> {
|
||||
if (event.query.includes('FROM "user"')) {
|
||||
const userRepository = await event.manager.getRepository(User)
|
||||
const userRepository = event.manager.getRepository(User)
|
||||
|
||||
await userRepository.insert({
|
||||
firstName: "John",
|
||||
|
||||
@ -21,7 +21,7 @@ describe("github issues > #11440", () => {
|
||||
beforeEach(() => reloadTestingDatabases(dataSources))
|
||||
after(() => closeTestingConnections(dataSources))
|
||||
|
||||
it("should use table or alias name during upsert or doUpdate when both schema name and skipUpdateIfNoValuesChanged supplied", async () => {
|
||||
it("should use table or alias name during upsert or doUpdate when both schema name and skipUpdateIfNoValuesChanged supplied", async () =>
|
||||
Promise.all(
|
||||
dataSources.map(async (dataSource) => {
|
||||
const repository = dataSource.getRepository(Post)
|
||||
@ -82,7 +82,7 @@ describe("github issues > #11440", () => {
|
||||
`VALUES ($1, $2), ($3, $4) ` +
|
||||
`ON CONFLICT ( "id" ) DO UPDATE ` +
|
||||
`SET "title" = EXCLUDED."title" ` +
|
||||
`WHERE ("Post"."title" IS DISTINCT FROM EXCLUDED."title")`,
|
||||
`WHERE "Post"."title" IS DISTINCT FROM EXCLUDED."title"`,
|
||||
)
|
||||
await query.execute()
|
||||
|
||||
@ -105,6 +105,5 @@ describe("github issues > #11440", () => {
|
||||
},
|
||||
])
|
||||
}),
|
||||
)
|
||||
})
|
||||
))
|
||||
})
|
||||
|
||||
@ -39,10 +39,7 @@ describe("github issues > #1369 EntitySubscriber not firing events on abstract c
|
||||
},
|
||||
},
|
||||
)
|
||||
expect(foundEntity).to.not.be.undefined
|
||||
|
||||
const assertObject = Object.assign({}, foundEntity)
|
||||
assertObject!.should.be.eql({
|
||||
expect(foundEntity).to.deep.equal({
|
||||
id: 1,
|
||||
firstname: "Michael",
|
||||
lastname: "Scott",
|
||||
|
||||
@ -13,15 +13,18 @@ export class AbstractEntitySubscriber
|
||||
listenTo() {
|
||||
return AbstractEntity
|
||||
}
|
||||
async beforeInsert(event: InsertEvent<AbstractEntity>) {
|
||||
|
||||
beforeInsert(event: InsertEvent<AbstractEntity>) {
|
||||
this.updateFullName(event.entity)
|
||||
}
|
||||
async beforeUpdate(event: UpdateEvent<AbstractEntity>) {
|
||||
|
||||
beforeUpdate(event: UpdateEvent<AbstractEntity>) {
|
||||
if (event.entity) {
|
||||
this.updateFullName(event.entity)
|
||||
}
|
||||
}
|
||||
updateFullName(o: Partial<AbstractEntity>) {
|
||||
|
||||
private updateFullName(o: Partial<AbstractEntity>) {
|
||||
o.fullname = o.firstname + " " + o.lastname
|
||||
}
|
||||
}
|
||||
|
||||
@ -21,19 +21,18 @@ describe("github issues > #1576 Entities with null as `id` are merged [@next]",
|
||||
beforeEach(() => reloadTestingDatabases(connections))
|
||||
after(() => closeTestingConnections(connections))
|
||||
|
||||
it("should successfully create object", () =>
|
||||
Promise.all(
|
||||
connections.map(async (connection) => {
|
||||
const newpost = new Post()
|
||||
const cat1 = new Category()
|
||||
cat1.name2 = "1"
|
||||
const cat2 = new Category()
|
||||
cat2.name = "2"
|
||||
newpost.categories = [cat1, cat2]
|
||||
it("should successfully create object", () => {
|
||||
connections.forEach((connection) => {
|
||||
const newpost = new Post()
|
||||
const cat1 = new Category()
|
||||
cat1.name2 = "1"
|
||||
const cat2 = new Category()
|
||||
cat2.name = "2"
|
||||
newpost.categories = [cat1, cat2]
|
||||
|
||||
const post = connection.manager.create(Post, newpost)
|
||||
const post = connection.manager.create(Post, newpost)
|
||||
|
||||
expect(post.categories).to.have.length(2)
|
||||
}),
|
||||
))
|
||||
expect(post.categories).to.have.length(2)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -1,16 +0,0 @@
|
||||
import { PrimaryColumn, Entity, Column } from "../../../../src"
|
||||
|
||||
@Entity()
|
||||
export class MariadbEntity {
|
||||
@PrimaryColumn()
|
||||
id: number
|
||||
|
||||
@Column("time")
|
||||
fieldTime: Date
|
||||
|
||||
@Column("timestamp")
|
||||
fieldTimestamp: Date
|
||||
|
||||
@Column("datetime")
|
||||
fieldDatetime: Date
|
||||
}
|
||||
@ -1,18 +1,15 @@
|
||||
import { expect } from "chai"
|
||||
import "reflect-metadata"
|
||||
import { DataSource } from "../../../src/data-source/DataSource"
|
||||
import { DataSourceOptions } from "../../../src/data-source/DataSourceOptions"
|
||||
import {
|
||||
createTestingConnections,
|
||||
closeTestingConnections,
|
||||
createTestingConnections,
|
||||
reloadTestingDatabases,
|
||||
getTypeOrmConfig,
|
||||
} from "../../utils/test-utils"
|
||||
import { expect } from "chai"
|
||||
|
||||
import { PgEntity } from "./entity/pgEntity"
|
||||
import { MysqlEntity } from "./entity/mysqlEntity"
|
||||
import { MariadbEntity } from "./entity/mariadbEntity"
|
||||
import { MssqlEntity } from "./entity/mssqlEntity"
|
||||
import { MysqlEntity } from "./entity/mysqlEntity"
|
||||
import { PgEntity } from "./entity/pgEntity"
|
||||
|
||||
const toISOString = (input: string) => new Date(input).toISOString()
|
||||
|
||||
@ -22,20 +19,8 @@ const convertPropsToISOStrings = (obj: any, props: string[]) => {
|
||||
})
|
||||
}
|
||||
|
||||
const isDriverEnabled = (driver: string) => {
|
||||
const ormConfigConnectionOptionsArray = getTypeOrmConfig()
|
||||
const config = ormConfigConnectionOptionsArray.find(
|
||||
(options: DataSourceOptions) => options.name === driver,
|
||||
)
|
||||
return config && !config.skip
|
||||
}
|
||||
|
||||
describe("github issues > #1716 send timestamp to database without converting it into UTC", () => {
|
||||
describe("postgres", async () => {
|
||||
if (!isDriverEnabled("postgres")) {
|
||||
return
|
||||
}
|
||||
|
||||
describe("postgres", () => {
|
||||
let connections: DataSource[]
|
||||
|
||||
before(async () => {
|
||||
@ -57,74 +42,81 @@ describe("github issues > #1716 send timestamp to database without converting it
|
||||
beforeEach(() => reloadTestingDatabases(connections))
|
||||
after(() => closeTestingConnections(connections))
|
||||
|
||||
it("should persist dates and times correctly", async () => {
|
||||
const manager = connections[0].manager
|
||||
it("should persist dates and times correctly", async () =>
|
||||
Promise.all(
|
||||
connections.map(async (connection) => {
|
||||
const manager = connection.manager
|
||||
|
||||
await manager.save(PgEntity, {
|
||||
id: 1,
|
||||
fieldTime: "14:00:00+05",
|
||||
fieldTimeWithTZ: "14:00:00+05",
|
||||
fieldTimeWithoutTZ: "14:00:00+05",
|
||||
fieldTimestamp: "2018-03-07 14:00:00+05",
|
||||
fieldTimestampWithoutTZ: "2018-03-07 14:00:00+05",
|
||||
fieldTimestampWithTZ: "2018-03-07 14:00:00+05",
|
||||
})
|
||||
await manager.save(PgEntity, {
|
||||
id: 1,
|
||||
fieldTime: "14:00:00+05",
|
||||
fieldTimeWithTZ: "14:00:00+05",
|
||||
fieldTimeWithoutTZ: "14:00:00+05",
|
||||
fieldTimestamp: "2018-03-07 14:00:00+05",
|
||||
fieldTimestampWithoutTZ: "2018-03-07 14:00:00+05",
|
||||
fieldTimestampWithTZ: "2018-03-07 14:00:00+05",
|
||||
})
|
||||
|
||||
const result1 = await manager.findOneBy(PgEntity, {
|
||||
id: 1,
|
||||
})
|
||||
convertPropsToISOStrings(result1, [
|
||||
"fieldTimestamp",
|
||||
"fieldTimestampWithoutTZ",
|
||||
"fieldTimestampWithTZ",
|
||||
])
|
||||
const result1 = await manager.findOneBy(PgEntity, {
|
||||
id: 1,
|
||||
})
|
||||
convertPropsToISOStrings(result1, [
|
||||
"fieldTimestamp",
|
||||
"fieldTimestampWithoutTZ",
|
||||
"fieldTimestampWithTZ",
|
||||
])
|
||||
|
||||
expect(result1).to.deep.equal({
|
||||
id: 1,
|
||||
fieldTime: "14:00:00",
|
||||
fieldTimeWithTZ: "14:00:00+05",
|
||||
fieldTimeWithoutTZ: "14:00:00",
|
||||
fieldTimestamp: toISOString("2018-03-07 14:00:00+05"),
|
||||
fieldTimestampWithoutTZ: toISOString("2018-03-07 14:00:00+05"),
|
||||
fieldTimestampWithTZ: toISOString("2018-03-07 14:00:00+05"),
|
||||
})
|
||||
expect(result1).to.deep.equal({
|
||||
id: 1,
|
||||
fieldTime: "14:00:00",
|
||||
fieldTimeWithTZ: "14:00:00+05",
|
||||
fieldTimeWithoutTZ: "14:00:00",
|
||||
fieldTimestamp: toISOString("2018-03-07 14:00:00+05"),
|
||||
fieldTimestampWithoutTZ: toISOString(
|
||||
"2018-03-07 14:00:00+05",
|
||||
),
|
||||
fieldTimestampWithTZ: toISOString(
|
||||
"2018-03-07 14:00:00+05",
|
||||
),
|
||||
})
|
||||
|
||||
await manager.save(PgEntity, {
|
||||
id: 2,
|
||||
fieldTime: "17:00:00",
|
||||
fieldTimeWithTZ: "17:00:00",
|
||||
fieldTimeWithoutTZ: "17:00:00",
|
||||
fieldTimestamp: "2018-03-07 17:00:00",
|
||||
fieldTimestampWithoutTZ: "2018-03-07 17:00:00",
|
||||
fieldTimestampWithTZ: "2018-03-07 17:00:00",
|
||||
})
|
||||
await manager.save(PgEntity, {
|
||||
id: 2,
|
||||
fieldTime: "17:00:00",
|
||||
fieldTimeWithTZ: "17:00:00",
|
||||
fieldTimeWithoutTZ: "17:00:00",
|
||||
fieldTimestamp: "2018-03-07 17:00:00",
|
||||
fieldTimestampWithoutTZ: "2018-03-07 17:00:00",
|
||||
fieldTimestampWithTZ: "2018-03-07 17:00:00",
|
||||
})
|
||||
|
||||
const result2 = await manager.findOneBy(PgEntity, {
|
||||
id: 2,
|
||||
})
|
||||
convertPropsToISOStrings(result2, [
|
||||
"fieldTimestamp",
|
||||
"fieldTimestampWithoutTZ",
|
||||
"fieldTimestampWithTZ",
|
||||
])
|
||||
const result2 = await manager.findOneBy(PgEntity, {
|
||||
id: 2,
|
||||
})
|
||||
convertPropsToISOStrings(result2, [
|
||||
"fieldTimestamp",
|
||||
"fieldTimestampWithoutTZ",
|
||||
"fieldTimestampWithTZ",
|
||||
])
|
||||
|
||||
expect(result2).to.deep.equal({
|
||||
id: 2,
|
||||
fieldTime: "17:00:00",
|
||||
fieldTimeWithTZ: "17:00:00+00",
|
||||
fieldTimeWithoutTZ: "17:00:00",
|
||||
fieldTimestamp: toISOString("2018-03-07 17:00:00"),
|
||||
fieldTimestampWithoutTZ: toISOString("2018-03-07 17:00:00"),
|
||||
fieldTimestampWithTZ: toISOString("2018-03-07 17:00:00"),
|
||||
})
|
||||
})
|
||||
expect(result2).to.deep.equal({
|
||||
id: 2,
|
||||
fieldTime: "17:00:00",
|
||||
fieldTimeWithTZ: "17:00:00+00",
|
||||
fieldTimeWithoutTZ: "17:00:00",
|
||||
fieldTimestamp: toISOString("2018-03-07 17:00:00"),
|
||||
fieldTimestampWithoutTZ: toISOString(
|
||||
"2018-03-07 17:00:00",
|
||||
),
|
||||
fieldTimestampWithTZ: toISOString(
|
||||
"2018-03-07 17:00:00",
|
||||
),
|
||||
})
|
||||
}),
|
||||
))
|
||||
})
|
||||
|
||||
describe("mysql", async () => {
|
||||
if (!isDriverEnabled("mysql")) {
|
||||
return
|
||||
}
|
||||
|
||||
describe("mysql/mariadb", () => {
|
||||
let connections: DataSource[]
|
||||
|
||||
before(async () => {
|
||||
@ -132,135 +124,66 @@ describe("github issues > #1716 send timestamp to database without converting it
|
||||
entities: [MysqlEntity],
|
||||
schemaCreate: true,
|
||||
dropSchema: true,
|
||||
enabledDrivers: ["mysql"],
|
||||
enabledDrivers: ["mysql", "mariadb"],
|
||||
})
|
||||
})
|
||||
|
||||
beforeEach(() => reloadTestingDatabases(connections))
|
||||
after(() => closeTestingConnections(connections))
|
||||
|
||||
it("should persist dates and times correctly", async () => {
|
||||
const manager = connections[0].manager
|
||||
it("should persist dates and times correctly", () =>
|
||||
Promise.all(
|
||||
connections.map(async (connection) => {
|
||||
const manager = connection.manager
|
||||
|
||||
await manager.save(MysqlEntity, {
|
||||
id: 1,
|
||||
fieldTime: "14:00:00",
|
||||
fieldTimestamp: "2018-03-07 14:00:00+05",
|
||||
fieldDatetime: "2018-03-07 14:00:00+05",
|
||||
})
|
||||
await manager.save(MysqlEntity, {
|
||||
id: 1,
|
||||
fieldTime: "14:00:00",
|
||||
fieldTimestamp: "2018-03-07 14:00:00+05",
|
||||
fieldDatetime: "2018-03-07 14:00:00+05",
|
||||
})
|
||||
|
||||
const result1 = await manager.findOneBy(MysqlEntity, {
|
||||
id: 1,
|
||||
})
|
||||
convertPropsToISOStrings(result1, [
|
||||
"fieldTimestamp",
|
||||
"fieldDatetime",
|
||||
])
|
||||
const result1 = await manager.findOneBy(MysqlEntity, {
|
||||
id: 1,
|
||||
})
|
||||
convertPropsToISOStrings(result1, [
|
||||
"fieldTimestamp",
|
||||
"fieldDatetime",
|
||||
])
|
||||
|
||||
expect(result1).to.deep.equal({
|
||||
id: 1,
|
||||
fieldTime: "14:00:00",
|
||||
fieldTimestamp: toISOString("2018-03-07 14:00:00+05"),
|
||||
fieldDatetime: toISOString("2018-03-07 14:00:00+05"),
|
||||
})
|
||||
expect(result1).to.deep.equal({
|
||||
id: 1,
|
||||
fieldTime: "14:00:00",
|
||||
fieldTimestamp: toISOString("2018-03-07 14:00:00+05"),
|
||||
fieldDatetime: toISOString("2018-03-07 14:00:00+05"),
|
||||
})
|
||||
|
||||
await manager.save(MysqlEntity, {
|
||||
id: 2,
|
||||
fieldTime: "17:00:00",
|
||||
fieldTimestamp: "2018-03-07 17:00:00",
|
||||
fieldDatetime: "2018-03-07 17:00:00",
|
||||
})
|
||||
await manager.save(MysqlEntity, {
|
||||
id: 2,
|
||||
fieldTime: "17:00:00",
|
||||
fieldTimestamp: "2018-03-07 17:00:00",
|
||||
fieldDatetime: "2018-03-07 17:00:00",
|
||||
})
|
||||
|
||||
const result2 = await manager.findOneBy(MysqlEntity, {
|
||||
id: 2,
|
||||
})
|
||||
convertPropsToISOStrings(result2, [
|
||||
"fieldTimestamp",
|
||||
"fieldDatetime",
|
||||
])
|
||||
const result2 = await manager.findOneBy(MysqlEntity, {
|
||||
id: 2,
|
||||
})
|
||||
convertPropsToISOStrings(result2, [
|
||||
"fieldTimestamp",
|
||||
"fieldDatetime",
|
||||
])
|
||||
|
||||
expect(result2).to.deep.equal({
|
||||
id: 2,
|
||||
fieldTime: "17:00:00",
|
||||
fieldTimestamp: toISOString("2018-03-07 17:00:00"),
|
||||
fieldDatetime: toISOString("2018-03-07 17:00:00"),
|
||||
})
|
||||
})
|
||||
expect(result2).to.deep.equal({
|
||||
id: 2,
|
||||
fieldTime: "17:00:00",
|
||||
fieldTimestamp: toISOString("2018-03-07 17:00:00"),
|
||||
fieldDatetime: toISOString("2018-03-07 17:00:00"),
|
||||
})
|
||||
}),
|
||||
))
|
||||
})
|
||||
|
||||
describe("mariadb", async () => {
|
||||
if (!isDriverEnabled("mariadb")) {
|
||||
return
|
||||
}
|
||||
|
||||
let connections: DataSource[]
|
||||
|
||||
before(async () => {
|
||||
connections = await createTestingConnections({
|
||||
entities: [MariadbEntity],
|
||||
schemaCreate: true,
|
||||
dropSchema: true,
|
||||
enabledDrivers: ["mariadb"],
|
||||
})
|
||||
})
|
||||
|
||||
beforeEach(() => reloadTestingDatabases(connections))
|
||||
after(() => closeTestingConnections(connections))
|
||||
|
||||
it("should persist dates and times correctly", async () => {
|
||||
const manager = connections[0].manager
|
||||
|
||||
await manager.save(MariadbEntity, {
|
||||
id: 1,
|
||||
fieldTime: "14:00:00",
|
||||
fieldTimestamp: "2018-03-07 14:00:00+05",
|
||||
fieldDatetime: "2018-03-07 14:00:00+05",
|
||||
})
|
||||
|
||||
const result1 = await manager.findOneBy(MariadbEntity, {
|
||||
id: 1,
|
||||
})
|
||||
convertPropsToISOStrings(result1, [
|
||||
"fieldTimestamp",
|
||||
"fieldDatetime",
|
||||
])
|
||||
|
||||
expect(result1).to.deep.equal({
|
||||
id: 1,
|
||||
fieldTime: "14:00:00",
|
||||
fieldTimestamp: toISOString("2018-03-07 14:00:00+05"),
|
||||
fieldDatetime: toISOString("2018-03-07 14:00:00+05"),
|
||||
})
|
||||
|
||||
await manager.save(MariadbEntity, {
|
||||
id: 2,
|
||||
fieldTime: "17:00:00",
|
||||
fieldTimestamp: "2018-03-07 17:00:00",
|
||||
fieldDatetime: "2018-03-07 17:00:00",
|
||||
})
|
||||
|
||||
const result2 = await manager.findOneBy(MariadbEntity, {
|
||||
id: 2,
|
||||
})
|
||||
convertPropsToISOStrings(result2, [
|
||||
"fieldTimestamp",
|
||||
"fieldDatetime",
|
||||
])
|
||||
|
||||
expect(result2).to.deep.equal({
|
||||
id: 2,
|
||||
fieldTime: "17:00:00",
|
||||
fieldTimestamp: toISOString("2018-03-07 17:00:00"),
|
||||
fieldDatetime: toISOString("2018-03-07 17:00:00"),
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("mssql", async () => {
|
||||
if (!isDriverEnabled("mssql")) {
|
||||
return
|
||||
}
|
||||
|
||||
describe("mssql", () => {
|
||||
let connections: DataSource[]
|
||||
|
||||
before(async () => {
|
||||
@ -275,58 +198,63 @@ describe("github issues > #1716 send timestamp to database without converting it
|
||||
beforeEach(() => reloadTestingDatabases(connections))
|
||||
after(() => closeTestingConnections(connections))
|
||||
|
||||
it("should persist dates and times correctly", async () => {
|
||||
const manager = connections[0].manager
|
||||
it("should persist dates and times correctly", () =>
|
||||
Promise.all(
|
||||
connections.map(async (connection) => {
|
||||
const manager = connection.manager
|
||||
|
||||
await manager.save(MssqlEntity, {
|
||||
id: 1,
|
||||
fieldTime: "14:00:00",
|
||||
fieldDatetime: "2018-03-07 14:00:00+05",
|
||||
fieldDatetime2: "2018-03-07 14:00:00+05",
|
||||
fieldDatetimeoffset: "2018-03-07 14:00:00+05",
|
||||
})
|
||||
await manager.save(MssqlEntity, {
|
||||
id: 1,
|
||||
fieldTime: "14:00:00",
|
||||
fieldDatetime: "2018-03-07 14:00:00+05",
|
||||
fieldDatetime2: "2018-03-07 14:00:00+05",
|
||||
fieldDatetimeoffset: "2018-03-07 14:00:00+05",
|
||||
})
|
||||
|
||||
const result1 = await manager.findOneBy(MssqlEntity, {
|
||||
id: 1,
|
||||
})
|
||||
convertPropsToISOStrings(result1, [
|
||||
"fieldDatetime",
|
||||
"fieldDatetime2",
|
||||
"fieldDatetimeoffset",
|
||||
])
|
||||
const result1 = await manager.findOneBy(MssqlEntity, {
|
||||
id: 1,
|
||||
})
|
||||
convertPropsToISOStrings(result1, [
|
||||
"fieldDatetime",
|
||||
"fieldDatetime2",
|
||||
"fieldDatetimeoffset",
|
||||
])
|
||||
|
||||
expect(result1).to.deep.equal({
|
||||
id: 1,
|
||||
fieldTime: "14:00:00",
|
||||
fieldDatetime: toISOString("2018-03-07 14:00:00+05"),
|
||||
fieldDatetime2: toISOString("2018-03-07 14:00:00+05"),
|
||||
fieldDatetimeoffset: toISOString("2018-03-07 14:00:00+05"),
|
||||
})
|
||||
expect(result1).to.deep.equal({
|
||||
id: 1,
|
||||
fieldTime: "14:00:00",
|
||||
fieldDatetime: toISOString("2018-03-07 14:00:00+05"),
|
||||
fieldDatetime2: toISOString("2018-03-07 14:00:00+05"),
|
||||
fieldDatetimeoffset: toISOString(
|
||||
"2018-03-07 14:00:00+05",
|
||||
),
|
||||
})
|
||||
|
||||
await manager.save(MssqlEntity, {
|
||||
id: 2,
|
||||
fieldTime: "17:00:00",
|
||||
fieldDatetime: "2018-03-07 17:00:00",
|
||||
fieldDatetime2: "2018-03-07 17:00:00",
|
||||
fieldDatetimeoffset: "2018-03-07 17:00:00",
|
||||
})
|
||||
await manager.save(MssqlEntity, {
|
||||
id: 2,
|
||||
fieldTime: "17:00:00",
|
||||
fieldDatetime: "2018-03-07 17:00:00",
|
||||
fieldDatetime2: "2018-03-07 17:00:00",
|
||||
fieldDatetimeoffset: "2018-03-07 17:00:00",
|
||||
})
|
||||
|
||||
const result2 = await manager.findOneBy(MssqlEntity, {
|
||||
id: 2,
|
||||
})
|
||||
convertPropsToISOStrings(result2, [
|
||||
"fieldDatetime",
|
||||
"fieldDatetime2",
|
||||
"fieldDatetimeoffset",
|
||||
])
|
||||
const result2 = await manager.findOneBy(MssqlEntity, {
|
||||
id: 2,
|
||||
})
|
||||
convertPropsToISOStrings(result2, [
|
||||
"fieldDatetime",
|
||||
"fieldDatetime2",
|
||||
"fieldDatetimeoffset",
|
||||
])
|
||||
|
||||
expect(result2).to.deep.equal({
|
||||
id: 2,
|
||||
fieldTime: "17:00:00",
|
||||
fieldDatetime: toISOString("2018-03-07 17:00:00"),
|
||||
fieldDatetime2: toISOString("2018-03-07 17:00:00"),
|
||||
fieldDatetimeoffset: toISOString("2018-03-07 17:00:00"),
|
||||
})
|
||||
})
|
||||
expect(result2).to.deep.equal({
|
||||
id: 2,
|
||||
fieldTime: "17:00:00",
|
||||
fieldDatetime: toISOString("2018-03-07 17:00:00"),
|
||||
fieldDatetime2: toISOString("2018-03-07 17:00:00"),
|
||||
fieldDatetimeoffset: toISOString("2018-03-07 17:00:00"),
|
||||
})
|
||||
}),
|
||||
))
|
||||
})
|
||||
})
|
||||
|
||||
@ -25,9 +25,7 @@ describe("github issues > #1805 bigint PK incorrectly returning as a number (exp
|
||||
const account = new Account()
|
||||
account.id = bigIntId
|
||||
|
||||
const accountRepository = await connection.getRepository(
|
||||
Account,
|
||||
)
|
||||
const accountRepository = connection.getRepository(Account)
|
||||
|
||||
await accountRepository.save(account)
|
||||
|
||||
|
||||
@ -34,21 +34,20 @@ describe("github issues > #2216 - Ability to capture Postgres notifications in l
|
||||
})
|
||||
after(() => closeTestingConnections(connections))
|
||||
|
||||
it("should NOT pass extension setup notices to client", async () =>
|
||||
Promise.all(
|
||||
connections.map(async (connection) => {
|
||||
sinon.assert.neverCalledWith(
|
||||
logInfoStub,
|
||||
"info",
|
||||
`extension "uuid-ossp" already exists, skipping`,
|
||||
)
|
||||
sinon.assert.neverCalledWith(
|
||||
logInfoStub,
|
||||
"info",
|
||||
`extension "citext" already exists, skipping`,
|
||||
)
|
||||
}),
|
||||
))
|
||||
it("should NOT pass extension setup notices to client", () => {
|
||||
connections.forEach((_connection) => {
|
||||
sinon.assert.neverCalledWith(
|
||||
logInfoStub,
|
||||
"info",
|
||||
`extension "uuid-ossp" already exists, skipping`,
|
||||
)
|
||||
sinon.assert.neverCalledWith(
|
||||
logInfoStub,
|
||||
"info",
|
||||
`extension "citext" already exists, skipping`,
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
it("should NOT pass manual notices to client", async () =>
|
||||
Promise.all(
|
||||
@ -93,21 +92,20 @@ describe("github issues > #2216 - Ability to capture Postgres notifications in l
|
||||
})
|
||||
after(() => closeTestingConnections(connections))
|
||||
|
||||
it("should pass extension setup notices to client", async () =>
|
||||
Promise.all(
|
||||
connections.map(async (connection) => {
|
||||
sinon.assert.calledWith(
|
||||
logInfoStub,
|
||||
"info",
|
||||
`extension "uuid-ossp" already exists, skipping`,
|
||||
)
|
||||
sinon.assert.calledWith(
|
||||
logInfoStub,
|
||||
"info",
|
||||
`extension "citext" already exists, skipping`,
|
||||
)
|
||||
}),
|
||||
))
|
||||
it("should pass extension setup notices to client", () => {
|
||||
connections.forEach((_connection) => {
|
||||
sinon.assert.calledWith(
|
||||
logInfoStub,
|
||||
"info",
|
||||
`extension "uuid-ossp" already exists, skipping`,
|
||||
)
|
||||
sinon.assert.calledWith(
|
||||
logInfoStub,
|
||||
"info",
|
||||
`extension "citext" already exists, skipping`,
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
it("should pass manual notices to client", async () =>
|
||||
Promise.all(
|
||||
|
||||
@ -47,10 +47,11 @@ describe("github issues > #2518 TreeRepository.findDescendantsTree does not load
|
||||
parent: root,
|
||||
} as File)
|
||||
expect(child.parentId).to.be.equal(1)
|
||||
const file: File | any = await repo
|
||||
|
||||
const file = (await repo
|
||||
.createQueryBuilder("file")
|
||||
.where("file.id = :id", { id: 1 })
|
||||
.getOne()
|
||||
.getOne())!
|
||||
await repo.findDescendantsTree(file)
|
||||
expect(file.children.length).to.be.greaterThan(0)
|
||||
}),
|
||||
|
||||
@ -26,8 +26,8 @@ describe("github issues > #2965 Reuse preloaded lazy relations", () => {
|
||||
const repoPerson = connection.getRepository(Person)
|
||||
const repoNote = connection.getRepository(Note)
|
||||
|
||||
const personA = await repoPerson.create({ name: "personA" })
|
||||
const personB = await repoPerson.create({ name: "personB" })
|
||||
const personA = repoPerson.create({ name: "personA" })
|
||||
const personB = repoPerson.create({ name: "personB" })
|
||||
|
||||
await repoPerson.save([personA, personB])
|
||||
|
||||
|
||||
@ -18,16 +18,15 @@ describe("github issues > #2984 Discriminator conflict reported even for non-inh
|
||||
beforeEach(() => reloadTestingDatabases(connections))
|
||||
after(() => closeTestingConnections(connections))
|
||||
|
||||
it("should load entities even with the same discriminator", () =>
|
||||
Promise.all(
|
||||
connections.map(async (connection) => {
|
||||
connection.entityMetadatas.should.have.length(5)
|
||||
connection.entityMetadatas.forEach((metadata) =>
|
||||
metadata.discriminatorValue!.should.be.oneOf([
|
||||
"Note",
|
||||
"OwnerNote",
|
||||
]),
|
||||
)
|
||||
}),
|
||||
))
|
||||
it("should load entities even with the same discriminator", () => {
|
||||
connections.forEach((connection) => {
|
||||
connection.entityMetadatas.should.have.length(5)
|
||||
connection.entityMetadatas.forEach((metadata) =>
|
||||
metadata.discriminatorValue!.should.be.oneOf([
|
||||
"Note",
|
||||
"OwnerNote",
|
||||
]),
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -155,26 +155,25 @@ describe("github issues > #3118 shorten alias names (for RDBMS with a limit) whe
|
||||
}),
|
||||
))
|
||||
|
||||
it("should shorten table names which exceed the max length", () =>
|
||||
Promise.all(
|
||||
connections.map(async (connection) => {
|
||||
const shortName =
|
||||
"cat_wit_ver_lon_nam_pos_wit_ver_lon_nam_pos_wit_ver_lon_nam"
|
||||
const normalName =
|
||||
"category_with_very_long_name_posts_with_very_long_name_post_with_very_long_name"
|
||||
const { maxAliasLength } = connection.driver
|
||||
const expectedTableName =
|
||||
maxAliasLength &&
|
||||
maxAliasLength > 0 &&
|
||||
normalName.length > maxAliasLength
|
||||
? shortName
|
||||
: normalName
|
||||
it("should shorten table names which exceed the max length", () => {
|
||||
connections.forEach((connection) => {
|
||||
const shortName =
|
||||
"cat_wit_ver_lon_nam_pos_wit_ver_lon_nam_pos_wit_ver_lon_nam"
|
||||
const normalName =
|
||||
"category_with_very_long_name_posts_with_very_long_name_post_with_very_long_name"
|
||||
const { maxAliasLength } = connection.driver
|
||||
const expectedTableName =
|
||||
maxAliasLength &&
|
||||
maxAliasLength > 0 &&
|
||||
normalName.length > maxAliasLength
|
||||
? shortName
|
||||
: normalName
|
||||
|
||||
expect(
|
||||
connection.entityMetadatas.some(
|
||||
(em) => em.tableName === expectedTableName,
|
||||
),
|
||||
).to.be.true
|
||||
}),
|
||||
))
|
||||
expect(
|
||||
connection.entityMetadatas.some(
|
||||
(em) => em.tableName === expectedTableName,
|
||||
),
|
||||
).to.equal(true)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -7,7 +7,7 @@ import {
|
||||
import { DataSource } from "../../../src/data-source/DataSource"
|
||||
import { expect } from "chai"
|
||||
|
||||
describe("github issues > #3158 Cannot run sync a second time", async () => {
|
||||
describe("github issues > #3158 Cannot run sync a second time", () => {
|
||||
let connections: DataSource[]
|
||||
before(
|
||||
async () =>
|
||||
|
||||
@ -12,11 +12,11 @@ export class PostSubscriber implements EntitySubscriberInterface<Post> {
|
||||
return Post
|
||||
}
|
||||
|
||||
async beforeInsert(event: InsertEvent<Post>) {
|
||||
beforeInsert(event: InsertEvent<Post>) {
|
||||
event.entity.inserted = true
|
||||
}
|
||||
|
||||
async beforeUpdate(event: UpdateEvent<Post>) {
|
||||
beforeUpdate(event: UpdateEvent<Post>) {
|
||||
if (event.entity) {
|
||||
event.entity.updated = true
|
||||
}
|
||||
|
||||
@ -20,28 +20,24 @@ describe("github issues > #3443 @JoinTable on entities without synchronization",
|
||||
beforeEach(() => reloadTestingDatabases(dataSources))
|
||||
after(() => closeTestingConnections(dataSources))
|
||||
|
||||
it("Should set synchronize: false for @JoinTable when passed to options", () =>
|
||||
Promise.all(
|
||||
dataSources.map(async (dataSource) => {
|
||||
const PRODUCT_TABLE_NAME = "product"
|
||||
const CATEGORY_TABLE_NAME = "category"
|
||||
const PRODUCT_CATEGORY_TABLE_NAME = "product_category"
|
||||
it("Should set synchronize: false for @JoinTable when passed to options", () => {
|
||||
dataSources.forEach((dataSource) => {
|
||||
const PRODUCT_TABLE_NAME = "product"
|
||||
const CATEGORY_TABLE_NAME = "category"
|
||||
const PRODUCT_CATEGORY_TABLE_NAME = "product_category"
|
||||
|
||||
expect(() =>
|
||||
dataSource.getMetadata(PRODUCT_TABLE_NAME),
|
||||
).not.to.throw()
|
||||
expect(() =>
|
||||
dataSource.getMetadata(CATEGORY_TABLE_NAME),
|
||||
).not.to.throw()
|
||||
expect(() =>
|
||||
dataSource.getMetadata(PRODUCT_CATEGORY_TABLE_NAME),
|
||||
).not.to.throw()
|
||||
expect(
|
||||
dataSource.getMetadata(PRODUCT_CATEGORY_TABLE_NAME)
|
||||
.synchronize,
|
||||
).to.equal(false)
|
||||
}),
|
||||
))
|
||||
|
||||
// you can add additional tests if needed
|
||||
expect(() =>
|
||||
dataSource.getMetadata(PRODUCT_TABLE_NAME),
|
||||
).not.to.throw()
|
||||
expect(() =>
|
||||
dataSource.getMetadata(CATEGORY_TABLE_NAME),
|
||||
).not.to.throw()
|
||||
expect(() =>
|
||||
dataSource.getMetadata(PRODUCT_CATEGORY_TABLE_NAME),
|
||||
).not.to.throw()
|
||||
expect(
|
||||
dataSource.getMetadata(PRODUCT_CATEGORY_TABLE_NAME).synchronize,
|
||||
).to.equal(false)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
export namespace RegExpStringTransformer {
|
||||
export function to(value: RegExp): string {
|
||||
export const RegExpStringTransformer = {
|
||||
to(value: RegExp): string {
|
||||
return value.toString()
|
||||
}
|
||||
|
||||
export function from(value: string): RegExp {
|
||||
},
|
||||
from(value: string): RegExp {
|
||||
const match = value.match(/^\/(.*)\/(.*)$/)
|
||||
if (match) {
|
||||
const [, pattern, flags] = match
|
||||
@ -11,5 +10,5 @@ export namespace RegExpStringTransformer {
|
||||
} else {
|
||||
throw new Error(`"${value}" is not a regular expression`)
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
@ -7,7 +7,7 @@ import {
|
||||
import { DataSource } from "../../../src/data-source/DataSource"
|
||||
import { expect } from "chai"
|
||||
|
||||
describe("github issues > #3588 Migration:generate issue with onUpdate using mysql 8.0", async () => {
|
||||
describe("github issues > #3588 Migration:generate issue with onUpdate using mysql 8.0", () => {
|
||||
let connections: DataSource[]
|
||||
before(
|
||||
async () =>
|
||||
|
||||
@ -1,12 +1,13 @@
|
||||
import { expect } from "chai"
|
||||
import "reflect-metadata"
|
||||
import { DataSource } from "../../../src"
|
||||
import {
|
||||
createTestingConnections,
|
||||
closeTestingConnections,
|
||||
createTestingConnections,
|
||||
reloadTestingDatabases,
|
||||
} from "../../utils/test-utils"
|
||||
import { DataSource } from "../../../src/data-source/DataSource"
|
||||
import { Person } from "./entity/Person"
|
||||
import { Men } from "./entity/Men"
|
||||
import { Person } from "./entity/Person"
|
||||
import { Women } from "./entity/Women"
|
||||
|
||||
describe("github issues > #3857 Schema inheritance when STI pattern is used", () => {
|
||||
@ -23,18 +24,14 @@ describe("github issues > #3857 Schema inheritance when STI pattern is used", ()
|
||||
beforeEach(() => reloadTestingDatabases(connections))
|
||||
after(() => closeTestingConnections(connections))
|
||||
|
||||
it("Child classes should have same schema as parent", () =>
|
||||
Promise.all(
|
||||
connections.map(async (connection) => {
|
||||
const personMetadata = connection.getMetadata(Person)
|
||||
const menMetadata = connection.getMetadata(Men)
|
||||
const womenMetadata = connection.getMetadata(Women)
|
||||
// @ts-ignore
|
||||
personMetadata.schema.should.be.eq("custom")
|
||||
// @ts-ignore
|
||||
menMetadata.schema.should.be.eq(personMetadata.schema)
|
||||
// @ts-ignore
|
||||
womenMetadata.schema.should.be.eq(personMetadata.schema)
|
||||
}),
|
||||
))
|
||||
it("Child classes should have same schema as parent", () => {
|
||||
connections.map((connection) => {
|
||||
const personMetadata = connection.getMetadata(Person)
|
||||
const menMetadata = connection.getMetadata(Men)
|
||||
const womenMetadata = connection.getMetadata(Women)
|
||||
expect(personMetadata.schema).to.be.equal("custom")
|
||||
expect(menMetadata.schema).to.be.equal(personMetadata.schema)
|
||||
expect(womenMetadata.schema).to.be.equal(personMetadata.schema)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -10,7 +10,7 @@ export class ExtendedAfterLoadSubscriber
|
||||
return Post
|
||||
}
|
||||
|
||||
async afterLoad(entity: Post, event: LoadEvent<Post>) {
|
||||
afterLoad(entity: Post, event: LoadEvent<Post>) {
|
||||
entity.extendedSubscriberSaw = event
|
||||
}
|
||||
}
|
||||
|
||||
@ -11,7 +11,7 @@ export class SimpleAfterLoadSubscriber
|
||||
return Post
|
||||
}
|
||||
|
||||
async afterLoad(entity: Post) {
|
||||
afterLoad(entity: Post) {
|
||||
entity.simpleSubscriberSaw = true
|
||||
}
|
||||
}
|
||||
|
||||
@ -47,7 +47,7 @@ describe("github issues > #4220 Fix the bug when using buffer as the key.", () =
|
||||
"11E9845B852510C0A99EDBC51EED5BB5",
|
||||
]
|
||||
|
||||
const repo = await connection.getRepository(User)
|
||||
const repo = connection.getRepository(User)
|
||||
|
||||
await Promise.all(
|
||||
[...Array(10)]
|
||||
|
||||
@ -19,16 +19,15 @@ describe("github issues > #4842 QueryExpressionMap doesn't clone distinct proper
|
||||
beforeEach(() => reloadTestingDatabases(connections))
|
||||
after(() => closeTestingConnections(connections))
|
||||
|
||||
it("should contain correct distinct value after query builder is cloned", () =>
|
||||
Promise.all(
|
||||
connections.map(async (connection) => {
|
||||
const query = connection.manager
|
||||
.createQueryBuilder(Post, "post")
|
||||
.distinct()
|
||||
.disableEscaping()
|
||||
const sqlWithDistinct = query.getSql()
|
||||
it("should contain correct distinct value after query builder is cloned", () => {
|
||||
connections.forEach((connection) => {
|
||||
const query = connection.manager
|
||||
.createQueryBuilder(Post, "post")
|
||||
.distinct()
|
||||
.disableEscaping()
|
||||
const sqlWithDistinct = query.getSql()
|
||||
|
||||
expect(query.clone().getSql()).to.equal(sqlWithDistinct)
|
||||
}),
|
||||
))
|
||||
expect(query.clone().getSql()).to.equal(sqlWithDistinct)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -20,17 +20,16 @@ describe("github issues > #4958 getRepository returns results from another Repo"
|
||||
beforeEach(() => reloadTestingDatabases(connections))
|
||||
after(() => closeTestingConnections(connections))
|
||||
|
||||
it("sql generated is for correct model", () =>
|
||||
Promise.all(
|
||||
connections.map(async (connection) => {
|
||||
const rawSql = await connection
|
||||
.getRepository(Second)
|
||||
.createQueryBuilder("a")
|
||||
.getSql()
|
||||
it("sql generated is for correct model", () => {
|
||||
for (const connection of connections) {
|
||||
const rawSql = connection
|
||||
.getRepository(Second)
|
||||
.createQueryBuilder("a")
|
||||
.getSql()
|
||||
|
||||
expect(rawSql).to.be.equal(
|
||||
'SELECT "a"."notId" AS "a_notId" FROM "second" "a"',
|
||||
)
|
||||
}),
|
||||
))
|
||||
expect(rawSql).to.be.equal(
|
||||
'SELECT "a"."notId" AS "a_notId" FROM "second" "a"',
|
||||
)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
@ -20,78 +20,72 @@ describe("github issues > #4980 (Postgres) onUpdate: 'CASCADE' doesn't work on m
|
||||
beforeEach(() => reloadTestingDatabases(connections))
|
||||
after(() => closeTestingConnections(connections))
|
||||
|
||||
it("should generate onDelete: CASCADE and onUpdate: CASCADE for 'books' side of many-to-many relation", () =>
|
||||
Promise.all(
|
||||
connections.map(async (connection) => {
|
||||
const booksRelation = connection
|
||||
.getMetadata(Author)
|
||||
.manyToManyRelations.find(
|
||||
(mtm) => mtm.propertyName === "books",
|
||||
)
|
||||
expect(booksRelation).not.to.be.undefined
|
||||
expect(booksRelation!.onDelete).to.be.equal("CASCADE")
|
||||
expect(booksRelation!.onUpdate).to.be.equal("CASCADE")
|
||||
}),
|
||||
))
|
||||
it("should generate onDelete: CASCADE and onUpdate: CASCADE for 'books' side of many-to-many relation", () => {
|
||||
connections.forEach((connection) => {
|
||||
const booksRelation = connection
|
||||
.getMetadata(Author)
|
||||
.manyToManyRelations.find((mtm) => mtm.propertyName === "books")
|
||||
expect(booksRelation).not.to.be.undefined
|
||||
expect(booksRelation!.onDelete).to.be.equal("CASCADE")
|
||||
expect(booksRelation!.onUpdate).to.be.equal("CASCADE")
|
||||
})
|
||||
})
|
||||
|
||||
it("should generate onDelete: NO ACTION and onUpdate: CASCADE for 'authors' side of many-to-many relation", () =>
|
||||
Promise.all(
|
||||
connections.map(async (connection) => {
|
||||
const authorsRelation = connection
|
||||
.getMetadata(Book)
|
||||
.manyToManyRelations.find(
|
||||
(mtm) => mtm.propertyName === "authors",
|
||||
)
|
||||
expect(authorsRelation).not.to.be.undefined
|
||||
expect(authorsRelation!.onDelete).to.be.equal("NO ACTION")
|
||||
expect(authorsRelation!.onUpdate).to.be.equal("CASCADE")
|
||||
}),
|
||||
))
|
||||
|
||||
it("should generate onDelete: NO ACTION and onUpdate: CASCADE for foreign key pointing to Book", () =>
|
||||
Promise.all(
|
||||
connections.map(async (connection) => {
|
||||
const booksRelation = connection
|
||||
.getMetadata(Author)
|
||||
.manyToManyRelations.find(
|
||||
(mtm) => mtm.propertyName === "books",
|
||||
)!
|
||||
const booksFk = booksRelation.foreignKeys.find(
|
||||
(fk) => fk.referencedTablePath === "book",
|
||||
it("should generate onDelete: NO ACTION and onUpdate: CASCADE for 'authors' side of many-to-many relation", () => {
|
||||
connections.forEach((connection) => {
|
||||
const authorsRelation = connection
|
||||
.getMetadata(Book)
|
||||
.manyToManyRelations.find(
|
||||
(mtm) => mtm.propertyName === "authors",
|
||||
)
|
||||
expect(booksFk).not.to.be.undefined
|
||||
expect(booksFk!.onDelete).to.be.equal("NO ACTION")
|
||||
expect(authorsRelation).not.to.be.undefined
|
||||
expect(authorsRelation!.onDelete).to.be.equal("NO ACTION")
|
||||
expect(authorsRelation!.onUpdate).to.be.equal("CASCADE")
|
||||
})
|
||||
})
|
||||
|
||||
// Oracle does not support ON UPDATE clause
|
||||
if (connection.driver.options.type === "oracle") {
|
||||
expect(booksFk!.onUpdate).to.be.equal("NO ACTION")
|
||||
} else {
|
||||
expect(booksFk!.onUpdate).to.be.equal("CASCADE")
|
||||
}
|
||||
}),
|
||||
))
|
||||
it("should generate onDelete: NO ACTION and onUpdate: CASCADE for foreign key pointing to Book", () => {
|
||||
connections.forEach((connection) => {
|
||||
const booksRelation = connection
|
||||
.getMetadata(Author)
|
||||
.manyToManyRelations.find(
|
||||
(mtm) => mtm.propertyName === "books",
|
||||
)!
|
||||
const booksFk = booksRelation.foreignKeys.find(
|
||||
(fk) => fk.referencedTablePath === "book",
|
||||
)
|
||||
expect(booksFk).not.to.be.undefined
|
||||
expect(booksFk!.onDelete).to.be.equal("NO ACTION")
|
||||
|
||||
it("should generate onDelete: CASCADE and onUpdate: CASCADE for foreign key pointing to Author", () =>
|
||||
Promise.all(
|
||||
connections.map(async (connection) => {
|
||||
// take books relation bc foreign keys are on owning side
|
||||
const booksRelation = connection
|
||||
.getMetadata(Author)
|
||||
.manyToManyRelations.find(
|
||||
(mtm) => mtm.propertyName === "books",
|
||||
)!
|
||||
const authorsFk = booksRelation.foreignKeys.find(
|
||||
(fk) => fk.referencedTablePath === "author",
|
||||
)
|
||||
expect(authorsFk).not.to.be.undefined
|
||||
expect(authorsFk!.onDelete).to.be.equal("CASCADE")
|
||||
// Oracle does not support ON UPDATE clause
|
||||
if (connection.driver.options.type === "oracle") {
|
||||
expect(booksFk!.onUpdate).to.be.equal("NO ACTION")
|
||||
} else {
|
||||
expect(booksFk!.onUpdate).to.be.equal("CASCADE")
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
// Oracle does not support ON UPDATE clause
|
||||
if (connection.driver.options.type === "oracle") {
|
||||
expect(authorsFk!.onUpdate).to.be.equal("NO ACTION")
|
||||
} else {
|
||||
expect(authorsFk!.onUpdate).to.be.equal("CASCADE")
|
||||
}
|
||||
}),
|
||||
))
|
||||
it("should generate onDelete: CASCADE and onUpdate: CASCADE for foreign key pointing to Author", () => {
|
||||
connections.forEach((connection) => {
|
||||
// take books relation bc foreign keys are on owning side
|
||||
const booksRelation = connection
|
||||
.getMetadata(Author)
|
||||
.manyToManyRelations.find(
|
||||
(mtm) => mtm.propertyName === "books",
|
||||
)!
|
||||
const authorsFk = booksRelation.foreignKeys.find(
|
||||
(fk) => fk.referencedTablePath === "author",
|
||||
)
|
||||
expect(authorsFk).not.to.be.undefined
|
||||
expect(authorsFk!.onDelete).to.be.equal("CASCADE")
|
||||
|
||||
// Oracle does not support ON UPDATE clause
|
||||
if (connection.driver.options.type === "oracle") {
|
||||
expect(authorsFk!.onUpdate).to.be.equal("NO ACTION")
|
||||
} else {
|
||||
expect(authorsFk!.onUpdate).to.be.equal("CASCADE")
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -16,16 +16,17 @@ describe("github issues > #5067 ORA-00972: identifier is too long", () => {
|
||||
)
|
||||
after(() => closeTestingConnections(connections))
|
||||
|
||||
it("generated parameter name is within the size constraints", () =>
|
||||
Promise.all(
|
||||
connections.map(async (connection) => {
|
||||
const paramName =
|
||||
"output_that_is_really_long_and_must_be_truncated_in_this_driver"
|
||||
const createdParameter =
|
||||
await connection.driver.createParameter(paramName, 0)
|
||||
it("generated parameter name is within the size constraints", () => {
|
||||
for (const connection of connections) {
|
||||
const paramName =
|
||||
"output_that_is_really_long_and_must_be_truncated_in_this_driver"
|
||||
const createdParameter = connection.driver.createParameter(
|
||||
paramName,
|
||||
0,
|
||||
)
|
||||
|
||||
expect(createdParameter).to.be.an("String")
|
||||
expect(createdParameter.length).to.be.lessThan(30)
|
||||
}),
|
||||
))
|
||||
expect(createdParameter).to.be.an("String")
|
||||
expect(createdParameter.length).to.be.lessThan(30)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
@ -6,65 +6,57 @@ import {
|
||||
setupSingleTestingConnection,
|
||||
} from "../../utils/test-utils"
|
||||
import { DataSource } from "../../../src"
|
||||
import { fail } from "assert"
|
||||
|
||||
describe("github issues > #5119 migration with foreign key that changes target", () => {
|
||||
let connections: DataSource[]
|
||||
let dataSources: DataSource[]
|
||||
before(
|
||||
async () =>
|
||||
(connections = await createTestingConnections({
|
||||
(dataSources = await createTestingConnections({
|
||||
entities: [__dirname + "/entity/v1/*{.js,.ts}"],
|
||||
enabledDrivers: ["postgres"],
|
||||
})),
|
||||
)
|
||||
beforeEach(() => reloadTestingDatabases(connections))
|
||||
after(() => closeTestingConnections([...connections]))
|
||||
beforeEach(() => reloadTestingDatabases(dataSources))
|
||||
after(() => closeTestingConnections([...dataSources]))
|
||||
|
||||
it("should generate a drop and create step", async () => {
|
||||
return Promise.all(
|
||||
connections.map(async function (_connection) {
|
||||
it("should generate a drop and create step", () =>
|
||||
Promise.all(
|
||||
dataSources.map(async function (dataSource) {
|
||||
const options = setupSingleTestingConnection(
|
||||
_connection.options.type,
|
||||
dataSource.options.type,
|
||||
{
|
||||
name: `${_connection.name}-v2`,
|
||||
name: `${dataSource.name}-v2`,
|
||||
entities: [__dirname + "/entity/v2/*{.js,.ts}"],
|
||||
dropSchema: false,
|
||||
schemaCreate: false,
|
||||
},
|
||||
)
|
||||
if (!options) {
|
||||
fail()
|
||||
return
|
||||
}
|
||||
const dataSource = new DataSource(options)
|
||||
await dataSource.initialize()
|
||||
try {
|
||||
const sqlInMemory = await dataSource.driver
|
||||
.createSchemaBuilder()
|
||||
.log()
|
||||
)!
|
||||
const newDataSource = new DataSource(options)
|
||||
await newDataSource.initialize()
|
||||
const sqlInMemory = await newDataSource.driver
|
||||
.createSchemaBuilder()
|
||||
.log()
|
||||
|
||||
const upQueries = sqlInMemory.upQueries.map(
|
||||
(query) => query.query,
|
||||
)
|
||||
const downQueries = sqlInMemory.downQueries.map(
|
||||
(query) => query.query,
|
||||
)
|
||||
upQueries.should.eql([
|
||||
`ALTER TABLE "post" DROP CONSTRAINT "FK_4490d00e1925ca046a1f52ddf04"`,
|
||||
`CREATE TABLE "account" ("id" SERIAL NOT NULL, "userId" integer, CONSTRAINT "PK_54115ee388cdb6d86bb4bf5b2ea" PRIMARY KEY ("id"))`,
|
||||
`ALTER TABLE "account" ADD CONSTRAINT "FK_60328bf27019ff5498c4b977421" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`,
|
||||
`ALTER TABLE "post" ADD CONSTRAINT "FK_4490d00e1925ca046a1f52ddf04" FOREIGN KEY ("ownerId") REFERENCES "account"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`,
|
||||
])
|
||||
downQueries.should.eql([
|
||||
`ALTER TABLE "post" ADD CONSTRAINT "FK_4490d00e1925ca046a1f52ddf04" FOREIGN KEY ("ownerId") REFERENCES "user"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`,
|
||||
`DROP TABLE "account"`,
|
||||
`ALTER TABLE "account" DROP CONSTRAINT "FK_60328bf27019ff5498c4b977421"`,
|
||||
`ALTER TABLE "post" DROP CONSTRAINT "FK_4490d00e1925ca046a1f52ddf04"`,
|
||||
])
|
||||
} finally {
|
||||
dataSource.close()
|
||||
}
|
||||
const upQueries = sqlInMemory.upQueries.map(
|
||||
(query) => query.query,
|
||||
)
|
||||
const downQueries = sqlInMemory.downQueries.map(
|
||||
(query) => query.query,
|
||||
)
|
||||
upQueries.should.eql([
|
||||
`ALTER TABLE "post" DROP CONSTRAINT "FK_4490d00e1925ca046a1f52ddf04"`,
|
||||
`CREATE TABLE "account" ("id" SERIAL NOT NULL, "userId" integer, CONSTRAINT "PK_54115ee388cdb6d86bb4bf5b2ea" PRIMARY KEY ("id"))`,
|
||||
`ALTER TABLE "account" ADD CONSTRAINT "FK_60328bf27019ff5498c4b977421" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`,
|
||||
`ALTER TABLE "post" ADD CONSTRAINT "FK_4490d00e1925ca046a1f52ddf04" FOREIGN KEY ("ownerId") REFERENCES "account"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`,
|
||||
])
|
||||
downQueries.should.eql([
|
||||
`ALTER TABLE "post" ADD CONSTRAINT "FK_4490d00e1925ca046a1f52ddf04" FOREIGN KEY ("ownerId") REFERENCES "user"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`,
|
||||
`DROP TABLE "account"`,
|
||||
`ALTER TABLE "account" DROP CONSTRAINT "FK_60328bf27019ff5498c4b977421"`,
|
||||
`ALTER TABLE "post" DROP CONSTRAINT "FK_4490d00e1925ca046a1f52ddf04"`,
|
||||
])
|
||||
|
||||
await newDataSource.destroy()
|
||||
}),
|
||||
)
|
||||
})
|
||||
))
|
||||
})
|
||||
|
||||
@ -1,10 +1,11 @@
|
||||
import { expect } from "chai"
|
||||
import "reflect-metadata"
|
||||
import { DataSource } from "../../../src"
|
||||
import {
|
||||
closeTestingConnections,
|
||||
createTestingConnections,
|
||||
reloadTestingDatabases,
|
||||
} from "../../utils/test-utils"
|
||||
import { DataSource } from "../../../src/data-source/DataSource"
|
||||
import { Post } from "./entity/Post"
|
||||
|
||||
describe("github issues > #512 Table name escaping in UPDATE in QueryBuilder", () => {
|
||||
@ -18,21 +19,20 @@ describe("github issues > #512 Table name escaping in UPDATE in QueryBuilder", (
|
||||
beforeEach(() => reloadTestingDatabases(connections))
|
||||
after(() => closeTestingConnections(connections))
|
||||
|
||||
it("should escape table name using driver's escape function in UPDATE", () =>
|
||||
Promise.all(
|
||||
connections.map(async (connection) => {
|
||||
const driver = connection.driver
|
||||
const queryBuilder = connection.manager.createQueryBuilder(
|
||||
Post,
|
||||
"post",
|
||||
)
|
||||
const query = queryBuilder
|
||||
.update({
|
||||
title: "Some Title",
|
||||
})
|
||||
.getSql()
|
||||
it("should escape table name using driver's escape function in UPDATE", () => {
|
||||
connections.forEach((connection) => {
|
||||
const driver = connection.driver
|
||||
const queryBuilder = connection.manager.createQueryBuilder(
|
||||
Post,
|
||||
"post",
|
||||
)
|
||||
const query = queryBuilder
|
||||
.update({
|
||||
title: "Some Title",
|
||||
})
|
||||
.getSql()
|
||||
|
||||
return query.should.deep.include(driver.escape("Posts"))
|
||||
}),
|
||||
))
|
||||
expect(query).to.deep.contain(driver.escape("Posts"))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -18,23 +18,20 @@ describe("github issues > #521 Attributes in UPDATE in QB arent getting replaced
|
||||
beforeEach(() => reloadTestingDatabases(connections))
|
||||
after(() => closeTestingConnections(connections))
|
||||
|
||||
it("should replace parameters", () =>
|
||||
Promise.all(
|
||||
connections.map(async (connection) => {
|
||||
const qb = connection
|
||||
.getRepository(Car)
|
||||
.createQueryBuilder("car")
|
||||
const [query, parameters] = qb
|
||||
.update({
|
||||
name: "Honda",
|
||||
})
|
||||
.where("name = :name", {
|
||||
name: "Toyota",
|
||||
})
|
||||
.getQueryAndParameters()
|
||||
query.should.not.be.undefined
|
||||
query.should.not.be.eql("")
|
||||
return parameters.length.should.eql(2)
|
||||
}),
|
||||
))
|
||||
it("should replace parameters", () => {
|
||||
connections.forEach((connection) => {
|
||||
const qb = connection.getRepository(Car).createQueryBuilder("car")
|
||||
const [query, parameters] = qb
|
||||
.update({
|
||||
name: "Honda",
|
||||
})
|
||||
.where("name = :name", {
|
||||
name: "Toyota",
|
||||
})
|
||||
.getQueryAndParameters()
|
||||
query.should.not.be.undefined
|
||||
query.should.not.be.eql("")
|
||||
return parameters.length.should.eql(2)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -7,7 +7,7 @@ import { Author, AuthorSchema } from "./entity/Author"
|
||||
import { EntitySchema } from "../../../src"
|
||||
|
||||
describe("github issues > #5444 EntitySchema missing support for multiple joinColumns in relations", () => {
|
||||
it("Update query returns the number of affected rows", async () => {
|
||||
it("Update query returns the number of affected rows", () => {
|
||||
const transformer = new EntitySchemaTransformer()
|
||||
|
||||
const actual = transformer.transform([
|
||||
|
||||
@ -7,7 +7,7 @@ export class CategorySubscriber implements EntitySubscriberInterface<Category> {
|
||||
return Category
|
||||
}
|
||||
|
||||
async afterLoad(entity: Category): Promise<any> {
|
||||
afterLoad(entity: Category) {
|
||||
entity.addedProp = true
|
||||
}
|
||||
}
|
||||
|
||||
@ -19,27 +19,24 @@ describe("github issues > #587 Ordering of fields in composite indexes defined u
|
||||
after(() => closeTestingConnections(connections))
|
||||
|
||||
// this test only works for fields specified as string[]
|
||||
it("should preserve field ordering when fields are specified as string[]", () =>
|
||||
Promise.all(
|
||||
connections.map(async (connection) => {
|
||||
connection.entityMetadatas.forEach((entityMetadata) => {
|
||||
entityMetadata.indices.forEach((index) => {
|
||||
if (
|
||||
index.givenColumnNames &&
|
||||
Array.isArray(index.givenColumnNames)
|
||||
) {
|
||||
for (let i = 0; i < index.columns.length; i++) {
|
||||
const givenColumn = (
|
||||
index.givenColumnNames as string[]
|
||||
)[i]
|
||||
const actualColumn = index.columns[i]
|
||||
actualColumn.propertyName.should.equal(
|
||||
givenColumn,
|
||||
)
|
||||
}
|
||||
it("should preserve field ordering when fields are specified as string[]", () => {
|
||||
connections.forEach((connection) => {
|
||||
connection.entityMetadatas.forEach((entityMetadata) => {
|
||||
entityMetadata.indices.forEach((index) => {
|
||||
if (
|
||||
index.givenColumnNames &&
|
||||
Array.isArray(index.givenColumnNames)
|
||||
) {
|
||||
for (let i = 0; i < index.columns.length; i++) {
|
||||
const givenColumn = (
|
||||
index.givenColumnNames as string[]
|
||||
)[i]
|
||||
const actualColumn = index.columns[i]
|
||||
actualColumn.propertyName.should.equal(givenColumn)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}),
|
||||
))
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -107,12 +107,12 @@ describe("github issues > #6168 fix multiple foreign keys with the same name in
|
||||
|
||||
const questionTable = tables.find(
|
||||
(table) => table.name === questionName,
|
||||
) as Table
|
||||
)!
|
||||
const categoryTable = tables.find(
|
||||
(table) => table.name === categoryName,
|
||||
) as Table
|
||||
)!
|
||||
|
||||
queryRunner.release()
|
||||
await queryRunner.release()
|
||||
|
||||
expect(categoryTable.foreignKeys.length).to.eq(1)
|
||||
expect(categoryTable.foreignKeys[0].name).to.eq(
|
||||
|
||||
@ -11,8 +11,7 @@ import { Session as changedEntity } from "./entity/sessionchanged"
|
||||
|
||||
describe("github issues > #6714 Migration:generate issue with onUpdate using mariadb 10.4", () => {
|
||||
it("dont change anything", async () => {
|
||||
let connections: DataSource[]
|
||||
connections = await createTestingConnections({
|
||||
const connections: DataSource[] = await createTestingConnections({
|
||||
entities: [baseEntity],
|
||||
schemaCreate: false,
|
||||
dropSchema: true,
|
||||
|
||||
@ -10,8 +10,8 @@ import { Block } from "./entity/Block"
|
||||
import { PlanOfRecord } from "./entity/PlanOfRecord"
|
||||
|
||||
describe("github issues > #6752 column name not been find on unique index decorator", () => {
|
||||
it("dont change anything", async () => {
|
||||
let connections: DataSource[]
|
||||
let connections: DataSource[]
|
||||
before(async () => {
|
||||
connections = await createTestingConnections({
|
||||
entities: [Block, PlanOfRecord],
|
||||
schemaCreate: false,
|
||||
@ -19,14 +19,19 @@ describe("github issues > #6752 column name not been find on unique index decora
|
||||
enabledDrivers: ["mssql"],
|
||||
})
|
||||
await reloadTestingDatabases(connections)
|
||||
await Promise.all(
|
||||
})
|
||||
|
||||
after(async () => {
|
||||
await closeTestingConnections(connections)
|
||||
})
|
||||
|
||||
it("don't change anything", async () =>
|
||||
Promise.all(
|
||||
connections.map(async (connection) => {
|
||||
const schemaBuilder = connection.driver.createSchemaBuilder()
|
||||
const syncQueries = await schemaBuilder.log()
|
||||
expect(syncQueries.downQueries).to.be.eql([])
|
||||
expect(syncQueries.upQueries).to.be.eql([])
|
||||
}),
|
||||
)
|
||||
await closeTestingConnections(connections)
|
||||
})
|
||||
))
|
||||
})
|
||||
|
||||
@ -20,27 +20,17 @@ describe("github issues > #6977 Relation columns in embedded entities are not pr
|
||||
beforeEach(() => reloadTestingDatabases(connections))
|
||||
after(() => closeTestingConnections(connections))
|
||||
|
||||
it("should correctly assign foreign key columns in embedded entity", () =>
|
||||
Promise.all(
|
||||
connections.map(async (connection) => {
|
||||
const columns = connection.entityMetadatas.find(
|
||||
(entity) => entity.name === "User",
|
||||
)!.columns
|
||||
expect(columns.length).to.equal(3) // id, embeddedRelationuser1id, embeddedRelationuser2id
|
||||
expect(columns.some((column) => column.databaseName === "id"))
|
||||
.to.be.true
|
||||
expect(
|
||||
columns.some(
|
||||
(column) =>
|
||||
column.databaseName === "embeddedRelationuser1id",
|
||||
),
|
||||
).to.be.true
|
||||
expect(
|
||||
columns.some(
|
||||
(column) =>
|
||||
column.databaseName === "embeddedRelationuser2id",
|
||||
),
|
||||
).to.be.true
|
||||
}),
|
||||
))
|
||||
it("should correctly assign foreign key columns in embedded entity", () => {
|
||||
connections.forEach((connection) => {
|
||||
const columnNames = connection.entityMetadatas
|
||||
.find((entity) => entity.name === "User")!
|
||||
.columns.map((column) => column.databaseName)
|
||||
.sort()
|
||||
expect(columnNames).to.deep.equal([
|
||||
"embeddedRelationuser1id",
|
||||
"embeddedRelationuser2id",
|
||||
"id",
|
||||
])
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -18,17 +18,14 @@ describe("github issues > #7203 QueryExpressionMap doesn't clone comment field",
|
||||
beforeEach(() => reloadTestingDatabases(connections))
|
||||
after(() => closeTestingConnections(connections))
|
||||
|
||||
it("should be able to clone comment field", () =>
|
||||
Promise.all(
|
||||
connections.map(async (connection) => {
|
||||
const comment = "a comment"
|
||||
const queryBuilder = await connection
|
||||
.createQueryBuilder()
|
||||
.comment(comment)
|
||||
const clonedQueryBuilder = queryBuilder.clone()
|
||||
expect(clonedQueryBuilder.expressionMap.comment).to.be.eq(
|
||||
comment,
|
||||
)
|
||||
}),
|
||||
))
|
||||
it("should be able to clone comment field", () => {
|
||||
for (const connection of connections) {
|
||||
const comment = "a comment"
|
||||
const queryBuilder = connection
|
||||
.createQueryBuilder()
|
||||
.comment(comment)
|
||||
const clonedQueryBuilder = queryBuilder.clone()
|
||||
expect(clonedQueryBuilder.expressionMap.comment).to.equal(comment)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
@ -4,6 +4,7 @@ export enum Order {
|
||||
THIRD = "third",
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-namespace
|
||||
export namespace Order {
|
||||
export function from(value: string): Order {
|
||||
switch (value) {
|
||||
|
||||
@ -58,21 +58,20 @@ describe("github issues > #7932 non-ascii characters assigned to var/char colum
|
||||
}),
|
||||
))
|
||||
|
||||
it("should not change char or varchar column types to nchar or nvarchar", () =>
|
||||
Promise.all(
|
||||
connections.map(async (connection) => {
|
||||
const repo = connection.getRepository(Example)
|
||||
it("should not change char or varchar column types to nchar or nvarchar", () => {
|
||||
connections.forEach((connection) => {
|
||||
const repo = connection.getRepository(Example)
|
||||
|
||||
const columnMetadata = repo.metadata.ownColumns
|
||||
const contentColumnType = columnMetadata.find(
|
||||
(m) => m.propertyName === "content",
|
||||
)?.type
|
||||
const fixedLengthContentColumnType = columnMetadata.find(
|
||||
(m) => m.propertyName === "fixedLengthContent",
|
||||
)?.type
|
||||
const columnMetadata = repo.metadata.ownColumns
|
||||
const contentColumnType = columnMetadata.find(
|
||||
(m) => m.propertyName === "content",
|
||||
)?.type
|
||||
const fixedLengthContentColumnType = columnMetadata.find(
|
||||
(m) => m.propertyName === "fixedLengthContent",
|
||||
)?.type
|
||||
|
||||
expect(contentColumnType).to.be.equal("varchar")
|
||||
expect(fixedLengthContentColumnType).to.be.equal("char")
|
||||
}),
|
||||
))
|
||||
expect(contentColumnType).to.be.equal("varchar")
|
||||
expect(fixedLengthContentColumnType).to.be.equal("char")
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -13,9 +13,9 @@ describe("github issues > #799 sqlite: 'database' path should be created", () =>
|
||||
before(() => rimraf(dirname(path)))
|
||||
after(() => rimraf(dirname(path)))
|
||||
|
||||
afterEach(() => {
|
||||
if (dataSource && dataSource.isInitialized) {
|
||||
dataSource.close()
|
||||
afterEach(async () => {
|
||||
if (dataSource?.isInitialized) {
|
||||
await dataSource.destroy()
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@ -22,24 +22,23 @@ describe("github issues > #8026 Inserting a value for a column that has a relati
|
||||
|
||||
after(() => closeTestingConnections(connections))
|
||||
|
||||
it("it should include a related date column in the constructed query", async () =>
|
||||
await Promise.all(
|
||||
connections.map(async (connection) => {
|
||||
const queryBuilder = await connection.createQueryBuilder()
|
||||
it("it should include a related date column in the constructed query", () => {
|
||||
for (const connection of connections) {
|
||||
const queryBuilder = connection.createQueryBuilder()
|
||||
|
||||
const insertValue = {
|
||||
scheduled_departure_time: new Date(),
|
||||
scheduled_arrival_time: new Date(),
|
||||
}
|
||||
const insertValue = {
|
||||
scheduled_departure_time: new Date(),
|
||||
scheduled_arrival_time: new Date(),
|
||||
}
|
||||
|
||||
const [query, params] = await queryBuilder
|
||||
.insert()
|
||||
.into(ScheduledSailing)
|
||||
.values([insertValue])
|
||||
.getQueryAndParameters()
|
||||
const [query, params] = queryBuilder
|
||||
.insert()
|
||||
.into(ScheduledSailing)
|
||||
.values([insertValue])
|
||||
.getQueryAndParameters()
|
||||
|
||||
expect(query.includes("DEFAULT")).to.be.false
|
||||
expect(params).length(2)
|
||||
}),
|
||||
))
|
||||
expect(query).not.to.contain("DEFAULT")
|
||||
expect(params).length(2)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
import "reflect-metadata"
|
||||
import { DataSource, Repository } from "../../../src/index"
|
||||
import {
|
||||
reloadTestingDatabases,
|
||||
createTestingConnections,
|
||||
closeTestingConnections,
|
||||
} from "../../utils/test-utils"
|
||||
import { expect } from "chai"
|
||||
import "reflect-metadata"
|
||||
import { DataSource } from "../../../src"
|
||||
import {
|
||||
closeTestingConnections,
|
||||
createTestingConnections,
|
||||
reloadTestingDatabases,
|
||||
} from "../../utils/test-utils"
|
||||
import { Category } from "./entity/Category"
|
||||
import { Post } from "./entity/Post"
|
||||
|
||||
@ -30,64 +30,50 @@ describe("persistence > delete orphans", () => {
|
||||
// Specifications
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
describe("when a Post is removed from a Category", () => {
|
||||
let categoryRepository: Repository<Category>
|
||||
let postRepository: Repository<Post>
|
||||
let categoryId: number
|
||||
it("removing a Post from a Category", () =>
|
||||
Promise.all(
|
||||
connections.map(async (connection) => {
|
||||
const categoryRepository = connection.getRepository(Category)
|
||||
const postRepository = connection.getRepository(Post)
|
||||
|
||||
beforeEach(async function () {
|
||||
if (connections.length === 0) {
|
||||
this.skip()
|
||||
}
|
||||
const categoryToInsert = await categoryRepository.save(
|
||||
new Category(),
|
||||
)
|
||||
categoryToInsert.posts = [new Post(), new Post()]
|
||||
|
||||
await Promise.all(
|
||||
connections.map(async (connection) => {
|
||||
categoryRepository = connection.getRepository(Category)
|
||||
postRepository = connection.getRepository(Post)
|
||||
}),
|
||||
)
|
||||
await categoryRepository.save(categoryToInsert)
|
||||
const categoryId = categoryToInsert.id
|
||||
|
||||
const categoryToInsert = await categoryRepository.save(
|
||||
new Category(),
|
||||
)
|
||||
categoryToInsert.posts = [new Post(), new Post()]
|
||||
// Keep the first post
|
||||
const categoryToUpdate = (await categoryRepository.findOneBy({
|
||||
id: categoryId,
|
||||
}))!
|
||||
categoryToUpdate.posts = categoryToInsert.posts.filter(
|
||||
(p) => p.id === 1,
|
||||
)
|
||||
await categoryRepository.save(categoryToUpdate)
|
||||
|
||||
await categoryRepository.save(categoryToInsert)
|
||||
categoryId = categoryToInsert.id
|
||||
// should retain a Post on the Category
|
||||
const category = await categoryRepository.findOneBy({
|
||||
id: categoryId,
|
||||
})
|
||||
expect(category).not.to.be.null
|
||||
expect(category!.posts).to.have.lengthOf(1)
|
||||
expect(category!.posts[0].id).to.equal(1)
|
||||
|
||||
const categoryToUpdate = (await categoryRepository.findOneBy({
|
||||
id: categoryId,
|
||||
}))!
|
||||
categoryToUpdate.posts = categoryToInsert.posts.filter(
|
||||
(p) => p.id === 1,
|
||||
) // Keep the first post
|
||||
// should mark orphaned Post as soft-deleted
|
||||
const postCount = await postRepository.count()
|
||||
expect(postCount).to.equal(1)
|
||||
const postCountIncludeDeleted = await postRepository.count({
|
||||
withDeleted: true,
|
||||
})
|
||||
expect(postCountIncludeDeleted).to.equal(2)
|
||||
|
||||
await categoryRepository.save(categoryToUpdate)
|
||||
})
|
||||
|
||||
it("should retain a Post on the Category", async () => {
|
||||
const category = await categoryRepository.findOneBy({
|
||||
id: categoryId,
|
||||
})
|
||||
expect(category).not.to.be.null
|
||||
expect(category!.posts).to.have.lengthOf(1)
|
||||
expect(category!.posts[0].id).to.equal(1)
|
||||
})
|
||||
|
||||
it("should mark orphaned Post as soft-deleted", async () => {
|
||||
const postCount = await postRepository.count()
|
||||
expect(postCount).to.equal(1)
|
||||
const postCountIncludeDeleted = await postRepository.count({
|
||||
withDeleted: true,
|
||||
})
|
||||
expect(postCountIncludeDeleted).to.equal(2)
|
||||
})
|
||||
|
||||
it("should retain foreign keys on remaining Posts", async () => {
|
||||
const postsWithoutForeignKeys = (
|
||||
await postRepository.find()
|
||||
).filter((p) => !p.categoryId)
|
||||
expect(postsWithoutForeignKeys).to.have.lengthOf(0)
|
||||
})
|
||||
})
|
||||
// should retain foreign keys on remaining Posts
|
||||
const postsWithoutForeignKeys = (
|
||||
await postRepository.find()
|
||||
).filter((p) => !p.categoryId)
|
||||
expect(postsWithoutForeignKeys).to.have.lengthOf(0)
|
||||
}),
|
||||
))
|
||||
})
|
||||
|
||||
@ -1,31 +1,23 @@
|
||||
import "../../utils/test-setup"
|
||||
import {
|
||||
createTestingConnections,
|
||||
closeTestingConnections,
|
||||
reloadTestingDatabases,
|
||||
} from "../../utils/test-utils"
|
||||
import { DataSource } from "../../../src/index"
|
||||
import { expect } from "chai"
|
||||
import { User } from "../8832/entity/User"
|
||||
import { Address } from "./entity/Address"
|
||||
import { DataSource } from "../../../src"
|
||||
import { ConnectionMetadataBuilder } from "../../../src/connection/ConnectionMetadataBuilder"
|
||||
import { EntityMetadataValidator } from "../../../src/metadata-builder/EntityMetadataValidator"
|
||||
import "../../utils/test-setup"
|
||||
import {
|
||||
closeTestingConnections,
|
||||
createTestingConnections,
|
||||
reloadTestingDatabases,
|
||||
} from "../../utils/test-utils"
|
||||
import { BadInet4 } from "./badEntity/BadInet4"
|
||||
import { BadInet6 } from "./badEntity/BadInet6"
|
||||
import { BadUuid } from "./badEntity/BadUuid"
|
||||
import { Address } from "./entity/Address"
|
||||
import { User } from "./entity/User"
|
||||
import { UuidEntity } from "./entity/UuidEntity"
|
||||
|
||||
describe("github issues > #8832 Add uuid, inet4, and inet6 types for mariadb", () => {
|
||||
let connections: DataSource[]
|
||||
|
||||
afterEach(() => closeTestingConnections(connections))
|
||||
|
||||
describe("basic use of new maria db types", () => {
|
||||
const newUser: User = {
|
||||
uuid: "ceb2897c-a1cf-11ed-8dbd-040300000000",
|
||||
inet4: "192.0.2.146",
|
||||
inet6: "2001:0db8:0000:0000:0000:ff00:0042:8329",
|
||||
}
|
||||
|
||||
const expectedInet6 = "2001:db8::ff00:42:8329"
|
||||
|
||||
describe("basic use of new mariadb types", () => {
|
||||
let connections: DataSource[]
|
||||
before(
|
||||
async () =>
|
||||
(connections = await createTestingConnections({
|
||||
@ -36,14 +28,18 @@ describe("github issues > #8832 Add uuid, inet4, and inet6 types for mariadb", (
|
||||
})),
|
||||
)
|
||||
beforeEach(() => reloadTestingDatabases(connections))
|
||||
after(() => closeTestingConnections(connections))
|
||||
|
||||
it("should create table with uuid, inet4, and inet6 type set to column for relevant mariadb versions", () =>
|
||||
Promise.all(
|
||||
connections.map(async (connection) => {
|
||||
const userRepository = connection.getRepository(User)
|
||||
|
||||
// seems there is an issue with the persisting id that crosses over from mysql to mariadb
|
||||
await userRepository.save(newUser)
|
||||
const newUser = await userRepository.save({
|
||||
uuid: "ceb2897c-a1cf-11ed-8dbd-040300000000",
|
||||
inet4: "192.0.2.146",
|
||||
inet6: "2001:0db8:0000:0000:0000:ff00:0042:8329",
|
||||
})
|
||||
|
||||
const savedUser = await userRepository.findOneOrFail({
|
||||
where: { uuid: newUser.uuid },
|
||||
@ -56,33 +52,24 @@ describe("github issues > #8832 Add uuid, inet4, and inet6 types for mariadb", (
|
||||
expect(foundUser).to.not.be.null
|
||||
expect(foundUser!.uuid).to.deep.equal(newUser.uuid)
|
||||
expect(foundUser!.inet4).to.deep.equal(newUser.inet4)
|
||||
expect(foundUser!.inet6).to.deep.equal(expectedInet6)
|
||||
expect(foundUser!.inet6).to.deep.equal(
|
||||
"2001:db8::ff00:42:8329",
|
||||
)
|
||||
expect(foundUser!.another_uuid_field).to.not.be.undefined
|
||||
|
||||
const columnTypes: {
|
||||
COLUMN_NAME: string
|
||||
DATA_TYPE: string
|
||||
}[] = await connection.query(
|
||||
`
|
||||
SELECT
|
||||
}[] = await connection.sql`
|
||||
SELECT
|
||||
COLUMN_NAME,
|
||||
DATA_TYPE
|
||||
FROM INFORMATION_SCHEMA.COLUMNS
|
||||
DATA_TYPE
|
||||
FROM INFORMATION_SCHEMA.COLUMNS
|
||||
WHERE
|
||||
TABLE_SCHEMA = ?
|
||||
AND TABLE_NAME = ?
|
||||
AND COLUMN_NAME IN (?, ?, ?, ?)
|
||||
`,
|
||||
[
|
||||
connection.driver.database,
|
||||
"user",
|
||||
"id",
|
||||
"uuid",
|
||||
"inet4",
|
||||
"inet6",
|
||||
"anotherUuid",
|
||||
],
|
||||
)
|
||||
TABLE_SCHEMA = ${connection.driver.database}
|
||||
AND TABLE_NAME = 'user'
|
||||
AND COLUMN_NAME IN ('id', 'uuid', 'inet4', 'inet6', 'anotherUuid')`
|
||||
|
||||
const expectedColumnTypes: Record<string, string> = {
|
||||
id: "uuid",
|
||||
uuid: "uuid",
|
||||
@ -118,10 +105,7 @@ describe("github issues > #8832 Add uuid, inet4, and inet6 types for mariadb", (
|
||||
})
|
||||
|
||||
describe("regression test mysql uuid generation", () => {
|
||||
const uuidEntity: UuidEntity = {
|
||||
id: "ceb2897c-a1cf-11ed-8dbd-040300000000",
|
||||
}
|
||||
|
||||
let connections: DataSource[]
|
||||
before(
|
||||
async () =>
|
||||
(connections = await createTestingConnections({
|
||||
@ -132,6 +116,7 @@ describe("github issues > #8832 Add uuid, inet4, and inet6 types for mariadb", (
|
||||
})),
|
||||
)
|
||||
beforeEach(() => reloadTestingDatabases(connections))
|
||||
after(() => closeTestingConnections(connections))
|
||||
|
||||
it("should create table with with varchar with length 36 when version is mysql", () =>
|
||||
Promise.all(
|
||||
@ -139,24 +124,23 @@ describe("github issues > #8832 Add uuid, inet4, and inet6 types for mariadb", (
|
||||
const uuidRepository = connection.getRepository(UuidEntity)
|
||||
|
||||
// seems there is an issue with the persisting id that crosses over from mysql to mariadb
|
||||
const uuidEntity: UuidEntity = {
|
||||
id: "ceb2897c-a1cf-11ed-8dbd-040300000000",
|
||||
}
|
||||
await uuidRepository.save(uuidEntity)
|
||||
|
||||
const columnTypes: {
|
||||
DATA_TYPE: string
|
||||
CHARACTER_MAXIMUM_LENGTH: string
|
||||
}[] = await connection.query(
|
||||
`
|
||||
SELECT
|
||||
DATA_TYPE,
|
||||
CHARACTER_MAXIMUM_LENGTH
|
||||
FROM INFORMATION_SCHEMA.COLUMNS
|
||||
WHERE
|
||||
TABLE_SCHEMA = ?
|
||||
AND TABLE_NAME = ?
|
||||
AND COLUMN_NAME = ?
|
||||
`,
|
||||
[connection.driver.database, "UuidEntity", "id"],
|
||||
)
|
||||
}[] = await connection.sql`
|
||||
SELECT
|
||||
DATA_TYPE,
|
||||
CHARACTER_MAXIMUM_LENGTH
|
||||
FROM INFORMATION_SCHEMA.COLUMNS
|
||||
WHERE
|
||||
TABLE_SCHEMA = ${connection.driver.database}
|
||||
AND TABLE_NAME = 'UuidEntity'
|
||||
AND COLUMN_NAME = 'id'`
|
||||
|
||||
const isMysql = connection.driver.options.type === "mysql"
|
||||
const expectedType = isMysql ? "varchar" : "uuid"
|
||||
@ -175,20 +159,22 @@ describe("github issues > #8832 Add uuid, inet4, and inet6 types for mariadb", (
|
||||
})
|
||||
|
||||
describe("entity-metadata-validator", () => {
|
||||
it("should throw error if mariadb uuid is supported and length is provided to property", async () => {
|
||||
Promise.all(
|
||||
["BadInet4", "BadInet6", "BadUuid"].map(async (entity) => {
|
||||
const entityLocation = `${__dirname}/badEntity/${entity}{.js,.ts}"`
|
||||
const connection = new DataSource({
|
||||
// dummy connection options, connection won't be established anyway
|
||||
type: "mariadb",
|
||||
host: "localhost",
|
||||
username: "test",
|
||||
password: "test",
|
||||
database: "test",
|
||||
entities: [entityLocation],
|
||||
})
|
||||
let connections: DataSource[]
|
||||
before(
|
||||
async () =>
|
||||
(connections = await createTestingConnections({
|
||||
entities: [],
|
||||
schemaCreate: true,
|
||||
dropSchema: true,
|
||||
enabledDrivers: ["mariadb"],
|
||||
})),
|
||||
)
|
||||
beforeEach(() => reloadTestingDatabases(connections))
|
||||
after(() => closeTestingConnections(connections))
|
||||
|
||||
it("should throw error if mariadb uuid is supported and length is provided to property", async () =>
|
||||
Promise.all(
|
||||
connections.map(async (connection) => {
|
||||
// version supports all the new types
|
||||
connection.driver.version = "10.10.0"
|
||||
|
||||
@ -196,53 +182,22 @@ describe("github issues > #8832 Add uuid, inet4, and inet6 types for mariadb", (
|
||||
new ConnectionMetadataBuilder(connection)
|
||||
const entityMetadatas =
|
||||
await connectionMetadataBuilder.buildEntityMetadatas([
|
||||
entityLocation,
|
||||
BadInet4,
|
||||
BadInet6,
|
||||
BadUuid,
|
||||
])
|
||||
const entityMetadataValidator =
|
||||
new EntityMetadataValidator()
|
||||
expect(() =>
|
||||
entityMetadataValidator.validateMany(
|
||||
entityMetadatas,
|
||||
connection.driver,
|
||||
),
|
||||
).to.throw(Error)
|
||||
}),
|
||||
)
|
||||
})
|
||||
|
||||
it("should not throw error for mysql when uuid is provided and a length property is provided", async () => {
|
||||
Promise.all(
|
||||
["BadInet4", "BadInet6", "BadUuid"].map(async (entity) => {
|
||||
const entityLocation = `${__dirname}/badEntity/${entity}{.js,.ts}"`
|
||||
const connection = new DataSource({
|
||||
// dummy connection options, connection won't be established anyway
|
||||
type: "mysql",
|
||||
host: "localhost",
|
||||
username: "test",
|
||||
password: "test",
|
||||
database: "test",
|
||||
entities: [entityLocation],
|
||||
entityMetadatas.forEach((entityMetadata) => {
|
||||
expect(() =>
|
||||
entityMetadataValidator.validate(
|
||||
entityMetadata,
|
||||
entityMetadatas,
|
||||
connection.driver,
|
||||
),
|
||||
).to.throw(Error)
|
||||
})
|
||||
|
||||
// version supports all the new types
|
||||
connection.driver.version = "10.10.0"
|
||||
|
||||
const connectionMetadataBuilder =
|
||||
new ConnectionMetadataBuilder(connection)
|
||||
const entityMetadatas =
|
||||
await connectionMetadataBuilder.buildEntityMetadatas([
|
||||
entityLocation,
|
||||
])
|
||||
const entityMetadataValidator =
|
||||
new EntityMetadataValidator()
|
||||
expect(() =>
|
||||
entityMetadataValidator.validateMany(
|
||||
entityMetadatas,
|
||||
connection.driver,
|
||||
),
|
||||
).not.to.throw()
|
||||
}),
|
||||
)
|
||||
})
|
||||
))
|
||||
})
|
||||
})
|
||||
|
||||
@ -9,7 +9,7 @@ import { Zip } from "./entity/zip"
|
||||
import { Country } from "./entity/country"
|
||||
import { DataSource } from "../../../src"
|
||||
|
||||
describe('github issues > #8892 ManyToMany relations save throws "Violation of PRIMARY KEY constraint"', async () => {
|
||||
describe('github issues > #8892 ManyToMany relations save throws "Violation of PRIMARY KEY constraint"', () => {
|
||||
let connections: DataSource[]
|
||||
|
||||
beforeEach(async () => {
|
||||
|
||||
@ -8,7 +8,7 @@ import { DataSource } from "../../../src"
|
||||
import { TestEntity } from "./entities/TestEntity"
|
||||
import { expect } from "chai"
|
||||
|
||||
describe("query builder order nulls first/last", async () => {
|
||||
describe("query builder order nulls first/last", () => {
|
||||
let dataSources: DataSource[]
|
||||
|
||||
before(async () => {
|
||||
|
||||
@ -16,14 +16,10 @@ describe("cli init command", () => {
|
||||
"mssql",
|
||||
"mongodb",
|
||||
]
|
||||
const testProjectName = Date.now() + "TestProject"
|
||||
const testProjectPath = `temp/${Date.now()}TestProject`
|
||||
const builtSrcDirectory = "build/compiled/src"
|
||||
|
||||
before(async () => {
|
||||
const chmodCli = async () => {
|
||||
await expect(chmod(cliPath, 0o755)).to.not.be.rejected
|
||||
}
|
||||
|
||||
const copyPackageJson = async () => {
|
||||
// load package.json from the root of the project
|
||||
const packageJson = JSON.parse(
|
||||
@ -38,7 +34,7 @@ describe("cli init command", () => {
|
||||
)
|
||||
}
|
||||
|
||||
await Promise.all([chmodCli(), copyPackageJson()])
|
||||
await Promise.all([chmod(cliPath, 0o755), copyPackageJson()])
|
||||
})
|
||||
|
||||
after(async () => {
|
||||
@ -46,14 +42,14 @@ describe("cli init command", () => {
|
||||
})
|
||||
|
||||
afterEach(async () => {
|
||||
await rmdir(`./${testProjectName}`, { recursive: true })
|
||||
await rmdir(`./${testProjectPath}`, { recursive: true })
|
||||
})
|
||||
|
||||
for (const databaseOption of databaseOptions) {
|
||||
it(`should work with ${databaseOption} option`, (done) => {
|
||||
exec(
|
||||
`node ${cliPath} init --name ${testProjectName} --database ${databaseOption}`,
|
||||
(error, stdout, stderr) => {
|
||||
`node ${cliPath} init --name ${testProjectPath} --database ${databaseOption}`,
|
||||
(error, _stdout, stderr) => {
|
||||
if (error) console.log(error)
|
||||
expect(error).to.not.exist
|
||||
expect(stderr).to.be.empty
|
||||
|
||||
@ -22,21 +22,22 @@ describe("github issues > #9049 mongodb entities with 2 level-nested arrays thro
|
||||
beforeEach(() => reloadTestingDatabases(connections))
|
||||
after(() => closeTestingConnections(connections))
|
||||
|
||||
it("should save entities properly", async () => {
|
||||
for (const connection of connections) {
|
||||
const post = new Post()
|
||||
const comment = new Comment()
|
||||
const value = new Value()
|
||||
it("should save entities properly", () =>
|
||||
Promise.all(
|
||||
connections.map(async (connection) => {
|
||||
const post = new Post()
|
||||
const comment = new Comment()
|
||||
const value = new Value()
|
||||
|
||||
value.description = "description"
|
||||
comment.values = [value]
|
||||
post.comments = [comment]
|
||||
value.description = "description"
|
||||
comment.values = [value]
|
||||
post.comments = [comment]
|
||||
|
||||
await connection.mongoManager.save(post)
|
||||
await connection.mongoManager.save(post)
|
||||
|
||||
const postRepo = await connection.getRepository(Post)
|
||||
const posts = await postRepo.find({})
|
||||
posts.forEach((post) => expect(post).to.be.instanceof(Post))
|
||||
}
|
||||
})
|
||||
const postRepo = connection.getRepository(Post)
|
||||
const posts = await postRepo.find({})
|
||||
posts.forEach((post) => expect(post).to.be.instanceof(Post))
|
||||
}),
|
||||
))
|
||||
})
|
||||
|
||||
@ -24,20 +24,14 @@ describe("github issues > #9318 Change version query from SHOW server_version to
|
||||
beforeEach(() => reloadTestingDatabases(connections))
|
||||
after(() => closeTestingConnections(connections))
|
||||
|
||||
it("should have proper isGeneratedColumnsSupported value for postgres version", () =>
|
||||
Promise.all(
|
||||
connections.map(async (connection) => {
|
||||
const { isGeneratedColumnsSupported } =
|
||||
connection.driver as PostgresDriver
|
||||
const versionGreaterOfEqualTo12 =
|
||||
DriverUtils.isReleaseVersionOrGreater(
|
||||
connection.driver,
|
||||
"12.0",
|
||||
)
|
||||
it("should have proper isGeneratedColumnsSupported value for postgres version", () => {
|
||||
connections.forEach((connection) => {
|
||||
const { isGeneratedColumnsSupported } =
|
||||
connection.driver as PostgresDriver
|
||||
const versionGreaterOfEqualTo12 =
|
||||
DriverUtils.isReleaseVersionOrGreater(connection.driver, "12.0")
|
||||
|
||||
expect(isGeneratedColumnsSupported).to.eq(
|
||||
versionGreaterOfEqualTo12,
|
||||
)
|
||||
}),
|
||||
))
|
||||
expect(isGeneratedColumnsSupported).to.eq(versionGreaterOfEqualTo12)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user