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:
Lucian Mocanu 2025-06-22 11:51:29 +02:00 committed by GitHub
parent abf8863a53
commit 01dddfef97
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
104 changed files with 1950 additions and 2184 deletions

View File

@ -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
View File

@ -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"

View File

@ -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",

View File

@ -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()

View File

@ -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()

View File

@ -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()

View File

@ -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()

View File

@ -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" ||

View File

@ -17,7 +17,7 @@ export class ConnectionOptionsEnvReader {
/**
* Reads connection options from environment variables.
*/
async read(): Promise<DataSourceOptions[]> {
read(): DataSourceOptions[] {
return [
{
type:

View File

@ -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
})
}
/**

View File

@ -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),
)

View File

@ -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
}

View File

@ -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,

View File

@ -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))
}

View File

@ -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

View File

@ -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 }
/**

View File

@ -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

View File

@ -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)

View File

@ -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 (

View File

@ -123,7 +123,7 @@ export class ReactNativeQueryRunner extends AbstractSqliteQueryRunner {
ok(result.raw)
}
},
async (err: any) => {
(err: any) => {
this.driver.connection.logger.logQueryError(
err,
query,

View File

@ -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
})
}
/**

View File

@ -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",
)

View File

@ -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}"`,

View File

@ -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

View File

@ -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":

View File

@ -569,7 +569,7 @@ export class ColumnMetadata {
const extractEmbeddedColumnValue = (
propertyNames: string[],
map: ObjectLiteral,
): any => {
) => {
const propertyName = propertyNames.shift()
if (propertyName) {
map[propertyName] = {}

View File

@ -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,
)

View File

@ -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) {

View File

@ -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)

View File

@ -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,
)
}

View File

@ -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)
}
}

View File

@ -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"]
}

View File

@ -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)
}
}
}

View File

@ -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)
}),
))

View File

@ -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)
}),
)
})
))
})
})

View File

@ -40,7 +40,7 @@ describe("custom repository", () => {
await dataSource.manager.transaction(
async (transactionalManager) => {
const transactionalCustomRepository =
await transactionalManager.withRepository(
transactionalManager.withRepository(
CustomRepository,
)
await transactionalCustomRepository.save({

View File

@ -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,
))!

View File

@ -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", () => {

View File

@ -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)
}
}

View File

@ -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(

View File

@ -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")

View File

@ -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(

View File

@ -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")

View File

@ -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++) {

View File

@ -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"),
)

View File

@ -26,5 +26,5 @@ export class PostgresExample {
createdAt: Date
@Column({ type: "jsonb", nullable: true })
tags: any | null
tags: string[] | null
}

View File

@ -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"),
)
})
})
})

View File

@ -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")
})
})
})

View File

@ -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
})
})
})

View File

@ -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",
})

View File

@ -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
}),
))
})

View File

@ -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,

View File

@ -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",

View File

@ -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", () => {
},
])
}),
)
})
))
})

View File

@ -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",

View File

@ -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
}
}

View File

@ -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)
})
})
})

View File

@ -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
}

View File

@ -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"),
})
}),
))
})
})

View File

@ -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)

View File

@ -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(

View File

@ -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)
}),

View File

@ -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])

View File

@ -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",
]),
)
})
})
})

View File

@ -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)
})
})
})

View File

@ -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 () =>

View File

@ -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
}

View File

@ -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)
})
})
})

View File

@ -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`)
}
}
},
}

View File

@ -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 () =>

View File

@ -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)
})
})
})

View File

@ -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
}
}

View File

@ -11,7 +11,7 @@ export class SimpleAfterLoadSubscriber
return Post
}
async afterLoad(entity: Post) {
afterLoad(entity: Post) {
entity.simpleSubscriberSaw = true
}
}

View File

@ -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)]

View File

@ -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)
})
})
})

View File

@ -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"',
)
}
})
})

View File

@ -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")
}
})
})
})

View File

@ -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)
}
})
})

View File

@ -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()
}),
)
})
))
})

View File

@ -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"))
})
})
})

View File

@ -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)
})
})
})

View File

@ -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([

View File

@ -7,7 +7,7 @@ export class CategorySubscriber implements EntitySubscriberInterface<Category> {
return Category
}
async afterLoad(entity: Category): Promise<any> {
afterLoad(entity: Category) {
entity.addedProp = true
}
}

View File

@ -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)
}
})
}
})
}),
))
})
})
})
})

View File

@ -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(

View File

@ -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,

View File

@ -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)
})
))
})

View File

@ -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",
])
})
})
})

View File

@ -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)
}
})
})

View File

@ -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) {

View File

@ -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")
})
})
})

View File

@ -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()
}
})

View File

@ -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)
}
})
})

View File

@ -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)
}),
))
})

View File

@ -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()
}),
)
})
))
})
})

View File

@ -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 () => {

View File

@ -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 () => {

View File

@ -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

View File

@ -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))
}),
))
})

View File

@ -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