diff --git a/.editorconfig b/.editorconfig index 08891d8..3626f17 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,8 +1,15 @@ root = true -[*] +[*.ts] indent_style = space indent_size = 4 end_of_line = lf insert_final_newline = true -trim_trailing_whitespace = true \ No newline at end of file +trim_trailing_whitespace = true + +[*.{json,yml}] +indent_style = space +indent_size = 2 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000..4d6e44e --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,43 @@ +module.exports = { + env: { + node: true + }, + extends: [ + "airbnb-base", + "plugin:@typescript-eslint/recommended", + "prettier", + "prettier/@typescript-eslint" + ], + parser: "@typescript-eslint/parser", + parserOptions: { + project: "./tsconfig.json" + }, + plugins: ["@typescript-eslint"], + rules: { + "@typescript-eslint/explicit-function-return-type": ["off"], + "@typescript-eslint/no-use-before-define": ["error", "nofunc"], + "@typescript-eslint/prefer-interface": ["off"], + "import/no-extraneous-dependencies": [ + "error", + { devDependencies: ["**/*.test.ts"] } + ], + "@typescript-eslint/no-floating-promises": ["error"], + "no-use-before-define": ["error", "nofunc"], + "no-console": ["off"], + "no-plusplus": ["error", { allowForLoopAfterthoughts: true }], + + "@typescript-eslint/no-non-null-assertion": ["off"], + "@typescript-eslint/no-object-literal-type-assertion": ["off"], + + "no-param-reassign": ["off"], + "@typescript-eslint/no-explicit-any": ["off"], + "no-loop-func": ["off"] + }, + settings: { + "import/resolver": { + node: { + extensions: [".js", ".jsx", ".ts", ".tsx"] + } + } + } +}; diff --git a/.gitignore b/.gitignore index 5daaa3c..e3496ca 100644 --- a/.gitignore +++ b/.gitignore @@ -4,13 +4,10 @@ ormconfig.json .vscode .idea typings/ -**/*.js -**/*.js.map output/**/*.* .nyc_output/ coverage/ .env dist *.tgz -!gulpfile.js .tomg-config diff --git a/.npmignore b/.npmignore index 01817ea..1a265b7 100644 --- a/.npmignore +++ b/.npmignore @@ -23,4 +23,4 @@ codecov.yml tsconfig.json typings.json dist/test/ -src/tslint.json +.eslintrc.js diff --git a/package-lock.json b/package-lock.json index 5c5c43c..f9fa7c6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -225,6 +225,12 @@ "@types/chai": "*" } }, + "@types/eslint-visitor-keys": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", + "integrity": "sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag==", + "dev": true + }, "@types/events": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz", @@ -270,6 +276,12 @@ "rxjs": "^6.4.0" } }, + "@types/json-schema": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.3.tgz", + "integrity": "sha512-Il2DtDVRGDcqjDtE+rF8iqg1CArehSK84HZJCT7AMITlyXRBpuPhqGLDQMowraqqu1coEaimg4ZOqggt6L6L+A==", + "dev": true + }, "@types/minimatch": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", @@ -346,6 +358,15 @@ "integrity": "sha512-d7c/C/+H/knZ3L8/cxhicHUiTDxdgap0b/aNJfsmLwFu/iOP17mdgbQsbHA3SJmrzsjD0l3UEE5SN4xxuz5ung==", "dev": true }, + "@types/sqlite3": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/@types/sqlite3/-/sqlite3-3.1.5.tgz", + "integrity": "sha512-upsrd1zEYMa4Y+prurQ+vpo5SN63BUF6tOjeTv3ziF+9W9PHVh4/S5cy0qAqkHvmOEm/AZhEKd7V/0bR2udmFw==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/through": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/through/-/through-0.0.29.tgz", @@ -361,11 +382,77 @@ "integrity": "sha512-UVjo2oH79aRNcsDlFlnQ/iJ67Jd7j6uSg7jUJP/RZ/nUjAh5ElmnwlD5K/6eGgETJUgCHkiWn91B8JjXQ6ubAw==", "dev": true }, + "@typescript-eslint/eslint-plugin": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-1.13.0.tgz", + "integrity": "sha512-WQHCozMnuNADiqMtsNzp96FNox5sOVpU8Xt4meaT4em8lOG1SrOv92/mUbEHQVh90sldKSfcOc/I0FOb/14G1g==", + "dev": true, + "requires": { + "@typescript-eslint/experimental-utils": "1.13.0", + "eslint-utils": "^1.3.1", + "functional-red-black-tree": "^1.0.1", + "regexpp": "^2.0.1", + "tsutils": "^3.7.0" + } + }, + "@typescript-eslint/experimental-utils": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-1.13.0.tgz", + "integrity": "sha512-zmpS6SyqG4ZF64ffaJ6uah6tWWWgZ8m+c54XXgwFtUv0jNz8aJAVx8chMCvnk7yl6xwn8d+d96+tWp7fXzTuDg==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.3", + "@typescript-eslint/typescript-estree": "1.13.0", + "eslint-scope": "^4.0.0" + } + }, + "@typescript-eslint/parser": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-1.13.0.tgz", + "integrity": "sha512-ITMBs52PCPgLb2nGPoeT4iU3HdQZHcPaZVw+7CsFagRJHUhyeTgorEwHXhFf3e7Evzi8oujKNpHc8TONth8AdQ==", + "dev": true, + "requires": { + "@types/eslint-visitor-keys": "^1.0.0", + "@typescript-eslint/experimental-utils": "1.13.0", + "@typescript-eslint/typescript-estree": "1.13.0", + "eslint-visitor-keys": "^1.0.0" + } + }, + "@typescript-eslint/typescript-estree": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-1.13.0.tgz", + "integrity": "sha512-b5rCmd2e6DCC6tCTN9GSUAuxdYwCM/k/2wdjHGrIRGPSJotWMCe/dGpi66u42bhuh8q3QBzqM4TMA1GUUCJvdw==", + "dev": true, + "requires": { + "lodash.unescape": "4.0.1", + "semver": "5.5.0" + }, + "dependencies": { + "semver": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", + "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", + "dev": true + } + } + }, "abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" }, + "acorn": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.2.1.tgz", + "integrity": "sha512-JD0xT5FCRDNyjDda3Lrg/IxFscp9q4tiYtxE1/nOzlKCk7hIRuYjhq1kCNkbPjMRMZuFq20HNQn1I9k8Oj0E+Q==", + "dev": true + }, + "acorn-jsx": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.0.1.tgz", + "integrity": "sha512-HJ7CfNHrfJLlNTzIEUTj43LNWGkqpRLxm3YjAlcD0ACydk9XynzYsCBHxut+iqt+1aBXkx9UP/w/ZqMr13XIzg==", + "dev": true + }, "adal-node": { "version": "0.1.28", "resolved": "https://registry.npmjs.org/adal-node/-/adal-node-0.1.28.tgz", @@ -503,6 +590,16 @@ "integrity": "sha1-z+nYwmYoudxa7MYqn12PHzUsEZU=", "dev": true }, + "array-includes": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.0.3.tgz", + "integrity": "sha1-GEtI9i2S10UrsxsyMWXH+L0CJm0=", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "es-abstract": "^1.7.0" + } + }, "array-union": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", @@ -528,6 +625,12 @@ "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", "dev": true }, + "astral-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "dev": true + }, "async": { "version": "1.5.2", "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", @@ -633,12 +736,6 @@ "resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz", "integrity": "sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==" }, - "builtin-modules": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", - "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", - "dev": true - }, "caching-transform": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-3.0.2.tgz", @@ -988,6 +1085,12 @@ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, + "confusing-browser-globals": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.8.tgz", + "integrity": "sha512-lI7asCibVJ6Qd3FGU7mu4sfG4try4LX3+GVS+Gv8UlrEf2AeW57piecapnog2UHZSbcX/P/1UDWVaTsblowlZg==", + "dev": true + }, "console-control-strings": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", @@ -1002,6 +1105,12 @@ "upper-case": "^1.1.1" } }, + "contains-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", + "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", + "dev": true + }, "convert-source-map": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz", @@ -1122,6 +1231,12 @@ "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" }, + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true + }, "default-require-extensions": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-2.0.0.tgz", @@ -1196,6 +1311,15 @@ } } }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, "dot-case": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-2.1.1.tgz", @@ -1307,11 +1431,451 @@ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" }, + "eslint": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.1.0.tgz", + "integrity": "sha512-QhrbdRD7ofuV09IuE2ySWBz0FyXCq0rriLTZXZqaWSI79CVtHVRdkFuFTViiqzZhkCgfOh9USpriuGN2gIpZDQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "ajv": "^6.10.0", + "chalk": "^2.1.0", + "cross-spawn": "^6.0.5", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "eslint-scope": "^5.0.0", + "eslint-utils": "^1.3.1", + "eslint-visitor-keys": "^1.0.0", + "espree": "^6.0.0", + "esquery": "^1.0.1", + "esutils": "^2.0.2", + "file-entry-cache": "^5.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.0.0", + "globals": "^11.7.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "inquirer": "^6.4.1", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.14", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "optionator": "^0.8.2", + "progress": "^2.0.0", + "regexpp": "^2.0.1", + "semver": "^6.1.2", + "strip-ansi": "^5.2.0", + "strip-json-comments": "^3.0.1", + "table": "^5.2.3", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "eslint-scope": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.0.0.tgz", + "integrity": "sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw==", + "dev": true, + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + }, + "import-fresh": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.1.0.tgz", + "integrity": "sha512-PpuksHKGt8rXfWEr9m9EHIpgyyaltBy8+eF6GJM0QCAxMgxCfucMF3mjecK2QsJr0amJW7gTqh5/wht0z2UhEQ==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + }, + "strip-json-comments": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.0.1.tgz", + "integrity": "sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw==", + "dev": true + } + } + }, + "eslint-config-airbnb-base": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-14.0.0.tgz", + "integrity": "sha512-2IDHobw97upExLmsebhtfoD3NAKhV4H0CJWP3Uprd/uk+cHuWYOczPVxQ8PxLFUAw7o3Th1RAU8u1DoUpr+cMA==", + "dev": true, + "requires": { + "confusing-browser-globals": "^1.0.7", + "object.assign": "^4.1.0", + "object.entries": "^1.1.0" + } + }, + "eslint-config-prettier": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-6.0.0.tgz", + "integrity": "sha512-vDrcCFE3+2ixNT5H83g28bO/uYAwibJxerXPj+E7op4qzBCsAV36QfvdAyVOoNxKAH2Os/e01T/2x++V0LPukA==", + "dev": true, + "requires": { + "get-stdin": "^6.0.0" + }, + "dependencies": { + "get-stdin": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz", + "integrity": "sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==", + "dev": true + } + } + }, + "eslint-import-resolver-node": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.2.tgz", + "integrity": "sha512-sfmTqJfPSizWu4aymbPr4Iidp5yKm8yDkHp+Ir3YiTHiiDfxh69mOUsmiqW6RZ9zRXFaF64GtYmN7e+8GHBv6Q==", + "dev": true, + "requires": { + "debug": "^2.6.9", + "resolve": "^1.5.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "eslint-module-utils": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.4.1.tgz", + "integrity": "sha512-H6DOj+ejw7Tesdgbfs4jeS4YMFrT8uI8xwd1gtQqXssaR0EQ26L+2O/w6wkYFy2MymON0fTwHmXBvvfLNZVZEw==", + "dev": true, + "requires": { + "debug": "^2.6.8", + "pkg-dir": "^2.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true + }, + "pkg-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", + "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", + "dev": true, + "requires": { + "find-up": "^2.1.0" + } + } + } + }, + "eslint-plugin-import": { + "version": "2.18.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.18.2.tgz", + "integrity": "sha512-5ohpsHAiUBRNaBWAF08izwUGlbrJoJJ+W9/TBwsGoR1MnlgfwMIKrFeSjWbt6moabiXW9xNvtFz+97KHRfI4HQ==", + "dev": true, + "requires": { + "array-includes": "^3.0.3", + "contains-path": "^0.1.0", + "debug": "^2.6.9", + "doctrine": "1.5.0", + "eslint-import-resolver-node": "^0.3.2", + "eslint-module-utils": "^2.4.0", + "has": "^1.0.3", + "minimatch": "^3.0.4", + "object.values": "^1.1.0", + "read-pkg-up": "^2.0.0", + "resolve": "^1.11.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "doctrine": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", + "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "isarray": "^1.0.0" + } + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "load-json-file": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", + "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "strip-bom": "^3.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true + }, + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true, + "requires": { + "error-ex": "^1.2.0" + } + }, + "path-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", + "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", + "dev": true, + "requires": { + "pify": "^2.0.0" + } + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + }, + "read-pkg": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", + "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", + "dev": true, + "requires": { + "load-json-file": "^2.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^2.0.0" + } + }, + "read-pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", + "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", + "dev": true, + "requires": { + "find-up": "^2.0.0", + "read-pkg": "^2.0.0" + } + } + } + }, + "eslint-scope": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", + "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", + "dev": true, + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "eslint-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.0.tgz", + "integrity": "sha512-7ehnzPaP5IIEh1r1tkjuIrxqhNkzUJa9z3R92tLJdZIVdWaczEhr3EbhGtsMrVxi1KeR8qA7Off6SWc5WNQqyQ==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.0.0" + } + }, + "eslint-visitor-keys": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", + "integrity": "sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ==", + "dev": true + }, + "espree": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-6.0.0.tgz", + "integrity": "sha512-lJvCS6YbCn3ImT3yKkPe0+tJ+mH6ljhGNjHQH9mRtiO6gjhVAOhVXW1yjnwqGwTkK3bGbye+hb00nFNmu0l/1Q==", + "dev": true, + "requires": { + "acorn": "^6.0.7", + "acorn-jsx": "^5.0.0", + "eslint-visitor-keys": "^1.0.0" + } + }, "esprima": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz", "integrity": "sha512-oftTcaMu/EGrEIu904mWteKIv8vMuOgGYo7EhVJJN00R/EED9DCua/xxHRdYnKtcECzVg7xOWhflvJMnqcFZjw==" }, + "esquery": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz", + "integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==", + "dev": true, + "requires": { + "estraverse": "^4.0.0" + } + }, + "esrecurse": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", + "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", + "dev": true, + "requires": { + "estraverse": "^4.1.0" + } + }, + "estraverse": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", + "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", + "dev": true + }, "esutils": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", @@ -1377,6 +1941,12 @@ "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, "fastq": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.6.0.tgz", @@ -1399,6 +1969,15 @@ "escape-string-regexp": "^1.0.5" } }, + "file-entry-cache": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", + "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", + "dev": true, + "requires": { + "flat-cache": "^2.0.1" + } + }, "fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -1455,6 +2034,23 @@ } } }, + "flat-cache": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", + "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", + "dev": true, + "requires": { + "flatted": "^2.0.0", + "rimraf": "2.6.3", + "write": "1.0.3" + } + }, + "flatted": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.1.tgz", + "integrity": "sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg==", + "dev": true + }, "foreground-child": { "version": "1.5.6", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-1.5.6.tgz", @@ -1528,6 +2124,12 @@ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", "dev": true }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, "gauge": { "version": "2.7.4", "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", @@ -2215,6 +2817,12 @@ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, "json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", @@ -2273,6 +2881,16 @@ "invert-kv": "^2.0.0" } }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, "lines-and-columns": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz", @@ -2532,6 +3150,12 @@ "integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=", "dev": true }, + "lodash.unescape": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.unescape/-/lodash.unescape-4.0.1.tgz", + "integrity": "sha1-vyJJiGzlFM2hEvrpIYzcBlIR/Jw=", + "dev": true + }, "log-symbols": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", @@ -2906,6 +3530,12 @@ "resolved": "https://registry.npmjs.org/native-duplexpair/-/native-duplexpair-1.0.0.tgz", "integrity": "sha1-eJkHjmS/PIo9cyYBs9QP8F21j6A=" }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, "needle": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/needle/-/needle-2.4.0.tgz", @@ -3142,6 +3772,18 @@ "object-keys": "^1.0.11" } }, + "object.entries": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.0.tgz", + "integrity": "sha512-l+H6EQ8qzGRxbkHOd5I/aHRhHDKoQXQ8g0BYt4uSweQU1/J6dZUOyWh9a2Vky35YCKjzmgxOzta2hH6kf9HuXA==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.12.0", + "function-bind": "^1.1.1", + "has": "^1.0.3" + } + }, "object.getownpropertydescriptors": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz", @@ -3152,6 +3794,18 @@ "es-abstract": "^1.5.1" } }, + "object.values": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.0.tgz", + "integrity": "sha512-8mf0nKLAoFX6VlNVdhGj31SVYpaNFtUnuoOXWyFEstsWRgU837AK+JYM0iAxwkSzGRbwn8cbFmgbyxj1j4VbXg==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.12.0", + "function-bind": "^1.1.1", + "has": "^1.0.3" + } + }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -3183,6 +3837,28 @@ "wordwrap": "~0.0.2" } }, + "optionator": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", + "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", + "dev": true, + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.4", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "wordwrap": "~1.0.0" + }, + "dependencies": { + "wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", + "dev": true + } + } + }, "os-homedir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", @@ -3283,6 +3959,23 @@ "no-case": "^2.2.0" } }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + }, + "dependencies": { + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + } + } + }, "parent-require": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/parent-require/-/parent-require-1.0.0.tgz", @@ -3523,12 +4216,24 @@ "xtend": "^4.0.0" } }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true + }, "prettier": { "version": "1.18.2", "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.18.2.tgz", "integrity": "sha512-OeHeMc0JhFE9idD4ZdtNibzY0+TPHSpSSb9h8FqtP+YnoZZ1sl8Vc9b1sasjfymH3SonAF4QcA2+mzHPhMvIiw==", "dev": true }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true + }, "pseudomap": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", @@ -3653,6 +4358,12 @@ "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==" }, + "regexpp": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", + "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", + "dev": true + }, "release-zalgo": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz", @@ -4097,6 +4808,54 @@ "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==", "dev": true }, + "table": { + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/table/-/table-5.4.5.tgz", + "integrity": "sha512-oGa2Hl7CQjfoaogtrOHEJroOcYILTx7BZWLGsJIlzoWmB2zmguhNfPJZsWPKYek/MgCxfco54gEi31d1uN2hFA==", + "dev": true, + "requires": { + "ajv": "^6.10.2", + "lodash": "^4.17.14", + "slice-ansi": "^2.1.0", + "string-width": "^3.0.0" + }, + "dependencies": { + "ajv": { + "version": "6.10.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz", + "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==", + "dev": true, + "requires": { + "fast-deep-equal": "^2.0.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "slice-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", + "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "astral-regex": "^1.0.0", + "is-fullwidth-code-point": "^2.0.0" + } + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + } + } + }, "tar": { "version": "4.4.10", "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.10.tgz", @@ -4174,6 +4933,12 @@ "require-main-filename": "^2.0.0" } }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, "thenify": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.0.tgz", @@ -4278,45 +5043,10 @@ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==" }, - "tslint": { - "version": "5.18.0", - "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.18.0.tgz", - "integrity": "sha512-Q3kXkuDEijQ37nXZZLKErssQVnwCV/+23gFEMROi8IlbaBG6tXqLPQJ5Wjcyt/yHPKBC+hD5SzuGaMora+ZS6w==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "builtin-modules": "^1.1.1", - "chalk": "^2.3.0", - "commander": "^2.12.1", - "diff": "^3.2.0", - "glob": "^7.1.1", - "js-yaml": "^3.13.1", - "minimatch": "^3.0.4", - "mkdirp": "^0.5.1", - "resolve": "^1.3.2", - "semver": "^5.3.0", - "tslib": "^1.8.0", - "tsutils": "^2.29.0" - }, - "dependencies": { - "semver": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", - "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", - "dev": true - } - } - }, - "tslint-config-prettier": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/tslint-config-prettier/-/tslint-config-prettier-1.18.0.tgz", - "integrity": "sha512-xPw9PgNPLG3iKRxmK7DWr+Ea/SzrvfHtjFt5LBl61gk2UBG/DB9kCXRjv+xyIU1rUtnayLeMUVJBcMX8Z17nDg==", - "dev": true - }, "tsutils": { - "version": "2.29.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", - "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", + "version": "3.17.1", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.17.1.tgz", + "integrity": "sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g==", "dev": true, "requires": { "tslib": "^1.8.1" @@ -4335,6 +5065,15 @@ "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2" + } + }, "type-detect": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", @@ -4454,6 +5193,12 @@ "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" }, + "v8-compile-cache": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz", + "integrity": "sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g==", + "dev": true + }, "validate-npm-package-license": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", @@ -4527,6 +5272,15 @@ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, + "write": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", + "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", + "dev": true, + "requires": { + "mkdirp": "^0.5.1" + } + }, "write-file-atomic": { "version": "2.4.3", "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz", diff --git a/package.json b/package.json index 32bdfea..63a5217 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "start": "ts-node ./src/index.ts", "pretest": "tsc --noEmit", "test": "nyc --reporter=lcov ts-node ./node_modules/mocha/bin/_mocha test/**/*.test.ts -- -R spec --bail", + "posttest": "eslint ./src/*.ts ./src/**/*.ts", "clean": "rimraf coverage output", "prettier": "prettier --write ./src/*.ts ./src/**/*.ts" }, @@ -50,12 +51,20 @@ "@types/oracledb": "^3.1.3", "@types/pg": "^7.4.14", "@types/sinon": "^7.0.13", + "@types/sqlite3": "^3.1.5", "@types/yargs": "^12.0.1", + "@typescript-eslint/eslint-plugin": "^1.13.0", + "@typescript-eslint/parser": "^1.13.0", + "@typescript-eslint/typescript-estree": "^1.13.0", "chai": "^4.2.0", "chai-as-promised": "^7.1.1", "chai-subset": "^1.6.0", "codecov": "^3.5.0", "dotenv": "^8.0.0", + "eslint": "^6.1.0", + "eslint-config-airbnb-base": "^14.0.0", + "eslint-config-prettier": "^6.0.0", + "eslint-plugin-import": "^2.18.2", "husky": "^3.0.2", "lint-staged": "^9.2.1", "mocha": "^6.2.0", @@ -63,9 +72,7 @@ "prettier": "^1.18.2", "rimraf": "^2.6.3", "sinon": "^7.3.2", - "sinon-chai": "^3.3.0", - "tslint": "^5.18.0", - "tslint-config-prettier": "^1.18.0" + "sinon-chai": "^3.3.0" }, "husky": { "hooks": { diff --git a/src/AbstractNamingStrategy.ts b/src/AbstractNamingStrategy.ts index ee3b9ee..b2b9783 100644 --- a/src/AbstractNamingStrategy.ts +++ b/src/AbstractNamingStrategy.ts @@ -1,7 +1,7 @@ -import { EntityInfo } from "./models/EntityInfo"; -import { RelationInfo } from "./models/RelationInfo"; +import RelationInfo from "./models/RelationInfo"; +import EntityInfo from "./models/EntityInfo"; -export abstract class AbstractNamingStrategy { +export default abstract class AbstractNamingStrategy { public abstract relationName( columnName: string, relation: RelationInfo, diff --git a/src/Engine.ts b/src/Engine.ts index 6416068..2111e00 100644 --- a/src/Engine.ts +++ b/src/Engine.ts @@ -1,20 +1,21 @@ +import * as Handlebars from "handlebars"; +import { DataTypeDefaults } from "typeorm/driver/types/DataTypeDefaults"; +import * as TomgUtils from "./Utils"; +import AbstractDriver from "./drivers/AbstractDriver"; +import MssqlDriver from "./drivers/MssqlDriver"; +import MariaDbDriver from "./drivers/MariaDbDriver"; +import IConnectionOptions from "./IConnectionOptions"; +import IGenerationOptions from "./IGenerationOptions"; +import EntityInfo from "./models/EntityInfo"; +import PostgresDriver from "./drivers/PostgresDriver"; +import MysqlDriver from "./drivers/MysqlDriver"; +import OracleDriver from "./drivers/OracleDriver"; +import SqliteDriver from "./drivers/SqliteDriver"; +import NamingStrategy from "./NamingStrategy"; + import changeCase = require("change-case"); import fs = require("fs"); -import * as Handlebars from "handlebars"; import path = require("path"); -import { DataTypeDefaults } from "typeorm/driver/types/DataTypeDefaults"; -import { AbstractDriver } from "./drivers/AbstractDriver"; -import { MariaDbDriver } from "./drivers/MariaDbDriver"; -import { MssqlDriver } from "./drivers/MssqlDriver"; -import { MysqlDriver } from "./drivers/MysqlDriver"; -import { OracleDriver } from "./drivers/OracleDriver"; -import { PostgresDriver } from "./drivers/PostgresDriver"; -import { SqliteDriver } from "./drivers/SqliteDriver"; -import { IConnectionOptions } from "./IConnectionOptions"; -import { IGenerationOptions } from "./IGenerationOptions"; -import { EntityInfo } from "./models/EntityInfo"; -import { NamingStrategy } from "./NamingStrategy"; -import * as TomgUtils from "./Utils"; export function createDriver(driverName: string): AbstractDriver { switch (driverName) { @@ -60,7 +61,7 @@ export async function dataCollectionPhase( driver: AbstractDriver, connectionOptions: IConnectionOptions ) { - return await driver.GetDataFromServer(connectionOptions); + return driver.GetDataFromServer(connectionOptions); } export function modelCustomizationPhase( @@ -73,17 +74,17 @@ export function modelCustomizationPhase( generationOptions.customNamingStrategyPath && generationOptions.customNamingStrategyPath !== "" ) { - // tslint:disable-next-line:no-var-requires + // eslint-disable-next-line global-require, import/no-dynamic-require, @typescript-eslint/no-var-requires const req = require(generationOptions.customNamingStrategyPath); namingStrategy = new req.NamingStrategy(); } else { namingStrategy = new NamingStrategy(); } - dbModel = setRelationId(generationOptions, dbModel); - dbModel = applyNamingStrategy(namingStrategy, dbModel); - dbModel = addImportsAndGenerationOptions(dbModel, generationOptions); - dbModel = removeColumnDefaultProperties(dbModel, defaultValues); - return dbModel; + let retVal = setRelationId(generationOptions, dbModel); + retVal = applyNamingStrategy(namingStrategy, retVal); + retVal = addImportsAndGenerationOptions(retVal, generationOptions); + retVal = removeColumnDefaultProperties(retVal, defaultValues); + return retVal; } function removeColumnDefaultProperties( dbModel: EntityInfo[], @@ -155,7 +156,7 @@ function setRelationId( if (generationOptions.relationIds) { model.forEach(ent => { ent.Columns.forEach(col => { - col.relations.map(rel => { + col.relations.forEach(rel => { rel.relationIdField = rel.isOwner; }); }); @@ -202,8 +203,10 @@ export function modelGenerationPhase( case "none": casedFileName = element.tsEntityName; break; + default: + throw new Error("Unknown case style"); } - const resultFilePath = path.resolve(entitesPath, casedFileName + ".ts"); + const resultFilePath = path.resolve(entitesPath, `${casedFileName}.ts`); const rendered = compliedTemplate(element); fs.writeFileSync(resultFilePath, rendered, { encoding: "UTF-8", @@ -226,6 +229,8 @@ function createHandlebarsHelpers(generationOptions: IGenerationOptions) { case "none": retStr = str; break; + default: + throw new Error("Unknown case style"); } return retStr; }); @@ -247,12 +252,14 @@ function createHandlebarsHelpers(generationOptions: IGenerationOptions) { case "none": retStr = str; break; + default: + throw new Error("Unknown case style"); } return retStr; }); Handlebars.registerHelper("printPropertyVisibility", () => generationOptions.propertyVisibility !== "none" - ? generationOptions.propertyVisibility + " " + ? `${generationOptions.propertyVisibility} ` : "" ); Handlebars.registerHelper("toPropertyName", str => { @@ -267,6 +274,8 @@ function createHandlebarsHelpers(generationOptions: IGenerationOptions) { case "none": retStr = str; break; + default: + throw new Error("Unknown case style"); } return retStr; }); @@ -277,9 +286,8 @@ function createHandlebarsHelpers(generationOptions: IGenerationOptions) { Handlebars.registerHelper("toLazy", str => { if (generationOptions.lazy) { return `Promise<${str}>`; - } else { - return str; } + return str; }); Handlebars.registerHelper({ and: (v1, v2) => v1 && v2, @@ -360,10 +368,10 @@ function applyNamingStrategy( namingStrategy: NamingStrategy, dbModel: EntityInfo[] ) { - dbModel = changeRelationNames(dbModel); - dbModel = changeEntityNames(dbModel); - dbModel = changeColumnNames(dbModel); - return dbModel; + let retval = changeRelationNames(dbModel); + retval = changeEntityNames(retval); + retval = changeColumnNames(retval); + return retval; function changeRelationNames(model: EntityInfo[]) { model.forEach(entity => { @@ -398,9 +406,9 @@ function applyNamingStrategy( col => col.name === column.tsName ) - .forEach( - col => (col.name = newName) - ); + .forEach(col => { + col.name = newName; + }); }); } }); @@ -420,7 +428,9 @@ function applyNamingStrategy( entity.Indexes.forEach(index => { index.columns .filter(column2 => column2.name === column.tsName) - .forEach(column2 => (column2.name = newName)); + .forEach(column2 => { + column2.name = newName; + }); }); model.forEach(entity2 => { entity2.Columns.forEach(column2 => { @@ -431,7 +441,9 @@ function applyNamingStrategy( entity.tsEntityName && relation.relatedColumn === column.tsName ) - .map(v => (v.relatedColumn = newName)); + .forEach(v => { + v.relatedColumn = newName; + }); column2.relations .filter( relation => @@ -439,7 +451,9 @@ function applyNamingStrategy( entity.tsEntityName && relation.ownerColumn === column.tsName ) - .map(v => (v.ownerColumn = newName)); + .forEach(v => { + v.ownerColumn = newName; + }); }); }); diff --git a/src/IConnectionOptions.ts b/src/IConnectionOptions.ts index 6da7f91..3cab302 100644 --- a/src/IConnectionOptions.ts +++ b/src/IConnectionOptions.ts @@ -1,11 +1,19 @@ -export class IConnectionOptions { +export default class IConnectionOptions { public host: string = ""; + public port: number = 0; + public databaseName: string = ""; + public user: string = ""; + public password: string = ""; + public databaseType: string = ""; + public schemaName: string = ""; + public ssl: boolean = false; + public timeout?: number; } diff --git a/src/IGenerationOptions.ts b/src/IGenerationOptions.ts index 11a0016..9a825f4 100644 --- a/src/IGenerationOptions.ts +++ b/src/IGenerationOptions.ts @@ -1,14 +1,24 @@ -export class IGenerationOptions { +export default class IGenerationOptions { public resultsPath: string = ""; + public noConfigs: boolean = false; + public convertCaseFile: "pascal" | "param" | "camel" | "none" = "none"; + public convertCaseEntity: "pascal" | "camel" | "none" = "none"; + public convertCaseProperty: "pascal" | "camel" | "none" = "none"; + public propertyVisibility: "public" | "protected" | "private" | "none" = "none"; + public lazy: boolean = false; + public activeRecord: boolean = false; + public generateConstructor: boolean = false; + public customNamingStrategyPath: string = ""; + public relationIds: boolean = false; } diff --git a/src/NamingStrategy.ts b/src/NamingStrategy.ts index 4e814d6..bcdde51 100644 --- a/src/NamingStrategy.ts +++ b/src/NamingStrategy.ts @@ -1,9 +1,11 @@ -import changeCase = require("change-case"); -import { AbstractNamingStrategy } from "./AbstractNamingStrategy"; -import { EntityInfo } from "./models/EntityInfo"; -import { RelationInfo } from "./models/RelationInfo"; +import AbstractNamingStrategy from "./AbstractNamingStrategy"; +import RelationInfo from "./models/RelationInfo"; +import EntityInfo from "./models/EntityInfo"; -export class NamingStrategy extends AbstractNamingStrategy { +import changeCase = require("change-case"); + +/* eslint-disable class-methods-use-this */ +export default class NamingStrategy extends AbstractNamingStrategy { public relationName( columnOldName: string, relation: RelationInfo, @@ -24,10 +26,10 @@ export class NamingStrategy extends AbstractNamingStrategy { columnName.toLowerCase().lastIndexOf("id") ); } - if (!isNaN(parseInt(columnName[columnName.length - 1], 10))) { + if (!Number.isNaN(parseInt(columnName[columnName.length - 1], 10))) { columnName = columnName.substring(0, columnName.length - 1); } - if (!isNaN(parseInt(columnName[columnName.length - 1], 10))) { + if (!Number.isNaN(parseInt(columnName[columnName.length - 1], 10))) { columnName = columnName.substring(0, columnName.length - 1); } columnName += isRelationToMany ? "s" : ""; @@ -37,7 +39,7 @@ export class NamingStrategy extends AbstractNamingStrategy { columnOldName !== columnName ) { if (ownerEntity.Columns.some(v => v.tsName === columnName)) { - columnName = columnName + "_"; + columnName += "_"; for (let i = 2; i <= ownerEntity.Columns.length; i++) { columnName = columnName.substring( @@ -68,3 +70,5 @@ export class NamingStrategy extends AbstractNamingStrategy { return columnName; } } + +/* eslint-enable class-methods-use-this */ diff --git a/src/Utils.ts b/src/Utils.ts index e60fc2c..aebf54d 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -1,9 +1,11 @@ import * as packagejson from "../package.json"; + export function LogError( errText: string, isABug: boolean = true, - errObject?: any + passedError?: any ) { + let errObject = passedError; console.error(errText); console.error(`Error occured in typeorm-model-generator.`); console.error(`${packageVersion()} node@${process.version}`); @@ -12,10 +14,10 @@ export function LogError( (packagejson as any).bugs.url }` ); - if (isABug && !errObject) { + if (isABug && !passedError) { errObject = new Error().stack; } - if (!!errObject) { + if (errObject) { console.error(errObject); } } diff --git a/src/drivers/AbstractDriver.ts b/src/drivers/AbstractDriver.ts index 8fd6431..9bb27cf 100644 --- a/src/drivers/AbstractDriver.ts +++ b/src/drivers/AbstractDriver.ts @@ -4,18 +4,21 @@ import { WithWidthColumnType } from "typeorm/driver/types/ColumnTypes"; import { DataTypeDefaults } from "typeorm/driver/types/DataTypeDefaults"; -import { IConnectionOptions } from "../IConnectionOptions"; -import { ColumnInfo } from "../models/ColumnInfo"; -import { EntityInfo } from "../models/EntityInfo"; -import { IndexInfo } from "../models/IndexInfo"; -import { RelationInfo } from "../models/RelationInfo"; -import { IRelationTempInfo } from "../models/RelationTempInfo"; import * as TomgUtils from "../Utils"; +import EntityInfo from "../models/EntityInfo"; +import RelationInfo from "../models/RelationInfo"; +import ColumnInfo from "../models/ColumnInfo"; +import IConnectionOptions from "../IConnectionOptions"; +import IndexInfo from "../models/IndexInfo"; +import RelationTempInfo from "../models/RelationTempInfo"; -export abstract class AbstractDriver { +export default abstract class AbstractDriver { public abstract standardPort: number; + public abstract standardSchema: string; + public abstract standardUser: string; + public abstract defaultValues: DataTypeDefaults; public ColumnTypesWithWidth: WithWidthColumnType[] = [ @@ -25,6 +28,7 @@ export abstract class AbstractDriver { "int", "bigint" ]; + public ColumnTypesWithPrecision: WithPrecisionColumnType[] = [ "float", "double", @@ -45,6 +49,7 @@ export abstract class AbstractDriver { "timestamp with time zone", "timestamp with local time zone" ]; + public ColumnTypesWithLength: WithLengthColumnType[] = [ "character varying", "varying character", @@ -65,15 +70,16 @@ export abstract class AbstractDriver { schema: string, dbNames: string ) => Promise< - Array<{ + { TABLE_SCHEMA: string; TABLE_NAME: string; DB_NAME: string; - }> + }[] >; - public FindManyToManyRelations(dbModel: EntityInfo[]) { - const manyToManyEntities = dbModel.filter( + public static FindManyToManyRelations(dbModel: EntityInfo[]) { + let retval = dbModel; + const manyToManyEntities = retval.filter( entity => entity.Columns.filter(column => { return ( @@ -83,7 +89,7 @@ export abstract class AbstractDriver { ); }).length === entity.Columns.length ); - manyToManyEntities.map(entity => { + manyToManyEntities.forEach(entity => { let relations: RelationInfo[] = []; relations = entity.Columns.reduce( (prev: RelationInfo[], curr) => prev.concat(curr.relations), @@ -92,9 +98,14 @@ export abstract class AbstractDriver { const namesOfRelatedTables = relations .map(v => v.relatedTable) .filter((v, i, s) => s.indexOf(v) === i); + const [ + firstRelatedTable, + secondRelatedTable + ] = namesOfRelatedTables; + if (namesOfRelatedTables.length === 2) { - const relatedTable1 = dbModel.find( - v => v.tsEntityName === namesOfRelatedTables[0] + const relatedTable1 = retval.find( + v => v.tsEntityName === firstRelatedTable )!; relatedTable1.Columns = relatedTable1.Columns.filter( v => @@ -102,7 +113,7 @@ export abstract class AbstractDriver { .toLowerCase() .startsWith(entity.tsEntityName.toLowerCase()) ); - const relatedTable2 = dbModel.find( + const relatedTable2 = retval.find( v => v.tsEntityName === namesOfRelatedTables[1] )!; relatedTable2.Columns = relatedTable2.Columns.filter( @@ -111,31 +122,31 @@ export abstract class AbstractDriver { .toLowerCase() .startsWith(entity.tsEntityName.toLowerCase()) ); - dbModel = dbModel.filter(ent => { + retval = retval.filter(ent => { return ent.tsEntityName !== entity.tsEntityName; }); const column1 = new ColumnInfo(); - column1.tsName = namesOfRelatedTables[1]; + column1.tsName = secondRelatedTable; column1.options.name = entity.sqlEntityName; const col1Rel = new RelationInfo(); - col1Rel.relatedTable = namesOfRelatedTables[1]; - col1Rel.relatedColumn = namesOfRelatedTables[1]; + col1Rel.relatedTable = secondRelatedTable; + col1Rel.relatedColumn = secondRelatedTable; col1Rel.relationType = "ManyToMany"; col1Rel.isOwner = true; - col1Rel.ownerColumn = namesOfRelatedTables[0]; + col1Rel.ownerColumn = firstRelatedTable; column1.relations.push(col1Rel); relatedTable1.Columns.push(column1); const column2 = new ColumnInfo(); - column2.tsName = namesOfRelatedTables[0]; + column2.tsName = firstRelatedTable; const col2Rel = new RelationInfo(); - col2Rel.relatedTable = namesOfRelatedTables[0]; - col2Rel.relatedColumn = namesOfRelatedTables[1]; + col2Rel.relatedTable = firstRelatedTable; + col2Rel.relatedColumn = secondRelatedTable; col2Rel.relationType = "ManyToMany"; col2Rel.isOwner = false; @@ -143,14 +154,15 @@ export abstract class AbstractDriver { relatedTable2.Columns.push(column2); } }); - return dbModel; + return retval; } + public async GetDataFromServer( connectionOptons: IConnectionOptions ): Promise { let dbModel = [] as EntityInfo[]; await this.ConnectToServer(connectionOptons); - const sqlEscapedSchema = this.escapeCommaSeparatedList( + const sqlEscapedSchema = AbstractDriver.escapeCommaSeparatedList( connectionOptons.schemaName ); dbModel = await this.GetAllTables( @@ -173,8 +185,8 @@ export abstract class AbstractDriver { connectionOptons.databaseName ); await this.DisconnectFromServer(); - dbModel = this.FindManyToManyRelations(dbModel); - this.FindPrimaryColumnsFromIndexes(dbModel); + dbModel = AbstractDriver.FindManyToManyRelations(dbModel); + AbstractDriver.FindPrimaryColumnsFromIndexes(dbModel); return dbModel; } @@ -199,8 +211,8 @@ export abstract class AbstractDriver { return ret; } - public GetRelationsFromRelationTempInfo( - relationsTemp: IRelationTempInfo[], + public static GetRelationsFromRelationTempInfo( + relationsTemp: RelationTempInfo[], entities: EntityInfo[] ) { relationsTemp.forEach(relationTmp => { @@ -275,7 +287,7 @@ export abstract class AbstractDriver { if ( referencedEntity.Columns.some(v => v.tsName === columnName) ) { - columnName = columnName + "_"; + columnName += "_"; for (let i = 2; i <= referencedEntity.Columns.length; i++) { columnName = columnName.substring( @@ -331,23 +343,26 @@ export abstract class AbstractDriver { }); return entities; } + public abstract async GetCoulmnsFromEntity( entities: EntityInfo[], schema: string, dbNames: string ): Promise; + public abstract async GetIndexesFromEntity( entities: EntityInfo[], schema: string, dbNames: string ): Promise; + public abstract async GetRelations( entities: EntityInfo[], schema: string, dbNames: string ): Promise; - public FindPrimaryColumnsFromIndexes(dbModel: EntityInfo[]) { + public static FindPrimaryColumnsFromIndexes(dbModel: EntityInfo[]) { dbModel.forEach(entity => { const primaryIndex = entity.Indexes.find(v => v.isPrimaryKey); entity.Columns.filter( @@ -356,7 +371,10 @@ export abstract class AbstractDriver { primaryIndex.columns.some( cIndex => cIndex.name === col.tsName ) - ).forEach(col => (col.options.primary = true)); + ).forEach(col => { + // eslint-disable-next-line no-param-reassign + col.options.primary = true; + }); if ( !entity.Columns.some(v => { return !!v.options.primary; @@ -366,18 +384,22 @@ export abstract class AbstractDriver { `Table ${entity.tsEntityName} has no PK.`, false ); - return; } }); } + public abstract async DisconnectFromServer(); + public abstract async CreateDB(dbName: string); + public abstract async DropDB(dbName: string); + public abstract async UseDB(dbName: string); + public abstract async CheckIfDBExists(dbName: string): Promise; // TODO: change name - protected escapeCommaSeparatedList(commaSeparatedList: string) { - return "'" + commaSeparatedList.split(",").join("','") + "'"; + protected static escapeCommaSeparatedList(commaSeparatedList: string) { + return `'${commaSeparatedList.split(",").join("','")}'`; } } diff --git a/src/drivers/MariaDbDriver.ts b/src/drivers/MariaDbDriver.ts index 93c587a..71324f2 100644 --- a/src/drivers/MariaDbDriver.ts +++ b/src/drivers/MariaDbDriver.ts @@ -1,5 +1,5 @@ -import { MysqlDriver } from "./MysqlDriver"; +import MysqlDriver from "./MysqlDriver"; -export class MariaDbDriver extends MysqlDriver { +export default class MariaDbDriver extends MysqlDriver { public readonly EngineName: string = "MariaDb"; } diff --git a/src/drivers/MssqlDriver.ts b/src/drivers/MssqlDriver.ts index 4331b08..2aed97b 100644 --- a/src/drivers/MssqlDriver.ts +++ b/src/drivers/MssqlDriver.ts @@ -2,33 +2,37 @@ import * as MSSQL from "mssql"; import { ConnectionOptions } from "typeorm"; import * as TypeormDriver from "typeorm/driver/sqlserver/SqlServerDriver"; import { DataTypeDefaults } from "typeorm/driver/types/DataTypeDefaults"; -import { IConnectionOptions } from "../IConnectionOptions"; -import { ColumnInfo } from "../models/ColumnInfo"; -import { EntityInfo } from "../models/EntityInfo"; -import { IndexColumnInfo } from "../models/IndexColumnInfo"; -import { IndexInfo } from "../models/IndexInfo"; -import { IRelationTempInfo } from "../models/RelationTempInfo"; import * as TomgUtils from "../Utils"; -import { AbstractDriver } from "./AbstractDriver"; +import AbstractDriver from "./AbstractDriver"; +import EntityInfo from "../models/EntityInfo"; +import ColumnInfo from "../models/ColumnInfo"; +import IndexInfo from "../models/IndexInfo"; +import IndexColumnInfo from "../models/IndexColumnInfo"; +import RelationTempInfo from "../models/RelationTempInfo"; +import IConnectionOptions from "../IConnectionOptions"; -export class MssqlDriver extends AbstractDriver { +export default class MssqlDriver extends AbstractDriver { public defaultValues: DataTypeDefaults = new TypeormDriver.SqlServerDriver({ options: { replication: undefined } as ConnectionOptions } as any).dataTypeDefaults; + public readonly standardPort = 1433; + public readonly standardSchema = "dbo"; + public readonly standardUser = "sa"; private Connection: MSSQL.ConnectionPool; + public GetAllTablesQuery = async (schema: string, dbNames: string) => { const request = new MSSQL.Request(this.Connection); - const response: Array<{ + const response: { TABLE_SCHEMA: string; TABLE_NAME: string; DB_NAME: string; - }> = (await request.query( + }[] = (await request.query( `SELECT TABLE_SCHEMA,TABLE_NAME, table_catalog as "DB_NAME" FROM INFORMATION_SCHEMA.TABLES -WHERE TABLE_TYPE='BASE TABLE' and TABLE_SCHEMA in (${schema}) AND TABLE_CATALOG in (${this.escapeCommaSeparatedList( +WHERE TABLE_TYPE='BASE TABLE' and TABLE_SCHEMA in (${schema}) AND TABLE_CATALOG in (${MssqlDriver.escapeCommaSeparatedList( dbNames )})` )).recordset; @@ -41,7 +45,7 @@ WHERE TABLE_TYPE='BASE TABLE' and TABLE_SCHEMA in (${schema}) AND TABLE_CATALOG dbNames: string ): Promise { const request = new MSSQL.Request(this.Connection); - const response: Array<{ + const response: { TABLE_NAME: string; COLUMN_NAME: string; COLUMN_DEFAULT: string; @@ -52,7 +56,7 @@ WHERE TABLE_TYPE='BASE TABLE' and TABLE_SCHEMA in (${schema}) AND TABLE_CATALOG NUMERIC_SCALE: number; IsIdentity: number; IsUnique: number; - }> = (await request.query(`SELECT TABLE_NAME,COLUMN_NAME,COLUMN_DEFAULT,IS_NULLABLE, + }[] = (await request.query(`SELECT TABLE_NAME,COLUMN_NAME,COLUMN_DEFAULT,IS_NULLABLE, DATA_TYPE,CHARACTER_MAXIMUM_LENGTH,NUMERIC_PRECISION,NUMERIC_SCALE, COLUMNPROPERTY(object_id(TABLE_NAME), COLUMN_NAME, 'IsIdentity') IsIdentity, (SELECT count(*) @@ -65,7 +69,7 @@ WHERE TABLE_TYPE='BASE TABLE' and TABLE_SCHEMA in (${schema}) AND TABLE_CATALOG and cu.COLUMN_NAME = c.COLUMN_NAME and tc.TABLE_SCHEMA=c.TABLE_SCHEMA) IsUnique FROM INFORMATION_SCHEMA.COLUMNS c - where TABLE_SCHEMA in (${schema}) AND TABLE_CATALOG in (${this.escapeCommaSeparatedList( + where TABLE_SCHEMA in (${schema}) AND TABLE_CATALOG in (${MssqlDriver.escapeCommaSeparatedList( dbNames )}) order by ordinal_position`)).recordset; @@ -81,7 +85,7 @@ WHERE TABLE_TYPE='BASE TABLE' and TABLE_SCHEMA in (${schema}) AND TABLE_CATALOG colInfo.options.nullable = resp.IS_NULLABLE === "YES"; colInfo.options.generated = resp.IsIdentity === 1; colInfo.options.unique = resp.IsUnique === 1; - colInfo.options.default = this.ReturnDefaultValueFunction( + colInfo.options.default = MssqlDriver.ReturnDefaultValueFunction( resp.COLUMN_DEFAULT ); colInfo.options.type = resp.DATA_TYPE as any; @@ -218,28 +222,30 @@ WHERE TABLE_TYPE='BASE TABLE' and TABLE_SCHEMA in (${schema}) AND TABLE_CATALOG }); return entities; } + public async GetIndexesFromEntity( entities: EntityInfo[], schema: string, dbNames: string ): Promise { const request = new MSSQL.Request(this.Connection); - const response: Array<{ + const response: { TableName: string; IndexName: string; ColumnName: string; is_unique: boolean; is_primary_key: boolean; - }> = []; - for (const dbName of dbNames.split(",")) { - await this.UseDB(dbName); - const resp: Array<{ - TableName: string; - IndexName: string; - ColumnName: string; - is_unique: boolean; - is_primary_key: boolean; - }> = (await request.query(`SELECT + }[] = []; + await Promise.all( + dbNames.split(",").map(async dbName => { + await this.UseDB(dbName); + const resp: { + TableName: string; + IndexName: string; + ColumnName: string; + is_unique: boolean; + is_primary_key: boolean; + }[] = (await request.query(`SELECT TableName = t.name, IndexName = ind.name, ColumnName = col.name, @@ -259,8 +265,9 @@ WHERE TABLE_TYPE='BASE TABLE' and TABLE_SCHEMA in (${schema}) AND TABLE_CATALOG t.is_ms_shipped = 0 and s.name in (${schema}) ORDER BY t.name, ind.name, ind.index_id, ic.key_ordinal;`)).recordset; - response.push(...resp); - } + response.push(...resp); + }) + ); entities.forEach(ent => { response .filter(filterVal => filterVal.TableName === ent.tsEntityName) @@ -272,9 +279,9 @@ WHERE TABLE_TYPE='BASE TABLE' and TABLE_SCHEMA in (${schema}) AND TABLE_CATALOG return filterVal.name === resp.IndexName; }).length > 0 ) { - indexInfo = ent.Indexes.filter(filterVal => { + [indexInfo] = ent.Indexes.filter(filterVal => { return filterVal.name === resp.IndexName; - })[0]; + }); } else { indexInfo.columns = [] as IndexColumnInfo[]; indexInfo.name = resp.IndexName; @@ -289,13 +296,14 @@ WHERE TABLE_TYPE='BASE TABLE' and TABLE_SCHEMA in (${schema}) AND TABLE_CATALOG return entities; } + public async GetRelations( entities: EntityInfo[], schema: string, dbNames: string ): Promise { const request = new MSSQL.Request(this.Connection); - const response: Array<{ + const response: { TableWithForeignKey: string; FK_PartNo: number; ForeignKeyColumn: string; @@ -303,20 +311,21 @@ WHERE TABLE_TYPE='BASE TABLE' and TABLE_SCHEMA in (${schema}) AND TABLE_CATALOG ForeignKeyColumnReferenced: string; onDelete: "RESTRICT" | "CASCADE" | "SET_NULL" | "NO_ACTION"; onUpdate: "RESTRICT" | "CASCADE" | "SET_NULL" | "NO_ACTION"; - object_id: number; - }> = []; - for (const dbName of dbNames.split(",")) { - await this.UseDB(dbName); - const resp: Array<{ - TableWithForeignKey: string; - FK_PartNo: number; - ForeignKeyColumn: string; - TableReferenced: string; - ForeignKeyColumnReferenced: string; - onDelete: "RESTRICT" | "CASCADE" | "SET_NULL" | "NO_ACTION"; - onUpdate: "RESTRICT" | "CASCADE" | "SET_NULL" | "NO_ACTION"; - object_id: number; - }> = (await request.query(`select + objectId: number; + }[] = []; + await Promise.all( + dbNames.split(",").map(async dbName => { + await this.UseDB(dbName); + const resp: { + TableWithForeignKey: string; + FK_PartNo: number; + ForeignKeyColumn: string; + TableReferenced: string; + ForeignKeyColumnReferenced: string; + onDelete: "RESTRICT" | "CASCADE" | "SET_NULL" | "NO_ACTION"; + onUpdate: "RESTRICT" | "CASCADE" | "SET_NULL" | "NO_ACTION"; + objectId: number; + }[] = (await request.query(`select parentTable.name as TableWithForeignKey, fkc.constraint_column_id as FK_PartNo, parentColumn.name as ForeignKeyColumn, @@ -324,7 +333,7 @@ WHERE TABLE_TYPE='BASE TABLE' and TABLE_SCHEMA in (${schema}) AND TABLE_CATALOG referencedColumn.name as ForeignKeyColumnReferenced, fk.delete_referential_action_desc as onDelete, fk.update_referential_action_desc as onUpdate, - fk.object_id + fk.object_id as objectId from sys.foreign_keys fk inner join @@ -343,15 +352,16 @@ where fk.is_disabled=0 and fk.is_ms_shipped=0 and parentSchema.name in (${schema}) order by TableWithForeignKey, FK_PartNo`)).recordset; - response.push(...resp); - } - const relationsTemp: IRelationTempInfo[] = [] as IRelationTempInfo[]; + response.push(...resp); + }) + ); + const relationsTemp: RelationTempInfo[] = [] as RelationTempInfo[]; response.forEach(resp => { let rels = relationsTemp.find( - val => val.object_id === resp.object_id + val => val.objectId === resp.objectId ); if (rels === undefined) { - rels = {} as IRelationTempInfo; + rels = {} as RelationTempInfo; rels.ownerColumnsNames = []; rels.referencedColumnsNames = []; switch (resp.onDelete) { @@ -376,7 +386,7 @@ order by rels.actionOnUpdate = resp.onUpdate; break; } - rels.object_id = resp.object_id; + rels.objectId = resp.objectId; rels.ownerTable = resp.TableWithForeignKey; rels.referencedTable = resp.TableReferenced; relationsTemp.push(rels); @@ -384,17 +394,19 @@ order by rels.ownerColumnsNames.push(resp.ForeignKeyColumn); rels.referencedColumnsNames.push(resp.ForeignKeyColumnReferenced); }); - entities = this.GetRelationsFromRelationTempInfo( + const retVal = MssqlDriver.GetRelationsFromRelationTempInfo( relationsTemp, entities ); - return entities; + return retVal; } + public async DisconnectFromServer() { if (this.Connection) { await this.Connection.close(); } } + public async ConnectToServer(connectionOptons: IConnectionOptions) { const databaseName = connectionOptons.databaseName.split(",")[0]; const config: MSSQL.config = { @@ -427,18 +439,22 @@ order by await promise; } + public async CreateDB(dbName: string) { const request = new MSSQL.Request(this.Connection); await request.query(`CREATE DATABASE ${dbName}; `); } + public async UseDB(dbName: string) { const request = new MSSQL.Request(this.Connection); await request.query(`USE ${dbName}; `); } + public async DropDB(dbName: string) { const request = new MSSQL.Request(this.Connection); await request.query(`DROP DATABASE ${dbName}; `); } + public async CheckIfDBExists(dbName: string): Promise { const request = new MSSQL.Request(this.Connection); const resp = await request.query( @@ -446,16 +462,20 @@ order by ); return resp.recordset.length > 0; } - private ReturnDefaultValueFunction(defVal: string | null): string | null { - if (!defVal) { + + private static ReturnDefaultValueFunction( + defVal: string | null + ): string | null { + let defaultValue = defVal; + if (!defaultValue) { return null; } - if (defVal.startsWith("(") && defVal.endsWith(")")) { - defVal = defVal.slice(1, -1); + if (defaultValue.startsWith("(") && defaultValue.endsWith(")")) { + defaultValue = defaultValue.slice(1, -1); } - if (defVal.startsWith(`'`)) { - return `() => "${defVal}"`; + if (defaultValue.startsWith(`'`)) { + return `() => "${defaultValue}"`; } - return `() => "${defVal}"`; + return `() => "${defaultValue}"`; } } diff --git a/src/drivers/MysqlDriver.ts b/src/drivers/MysqlDriver.ts index f618e34..28ee666 100644 --- a/src/drivers/MysqlDriver.ts +++ b/src/drivers/MysqlDriver.ts @@ -2,22 +2,26 @@ import * as MYSQL from "mysql"; import { ConnectionOptions } from "typeorm"; import * as TypeormDriver from "typeorm/driver/mysql/MysqlDriver"; import { DataTypeDefaults } from "typeorm/driver/types/DataTypeDefaults"; -import { IConnectionOptions } from "../IConnectionOptions"; -import { ColumnInfo } from "../models/ColumnInfo"; -import { EntityInfo } from "../models/EntityInfo"; -import { IndexColumnInfo } from "../models/IndexColumnInfo"; -import { IndexInfo } from "../models/IndexInfo"; -import { IRelationTempInfo } from "../models/RelationTempInfo"; import * as TomgUtils from "../Utils"; -import { AbstractDriver } from "./AbstractDriver"; +import AbstractDriver from "./AbstractDriver"; +import EntityInfo from "../models/EntityInfo"; +import ColumnInfo from "../models/ColumnInfo"; +import IndexInfo from "../models/IndexInfo"; +import IndexColumnInfo from "../models/IndexColumnInfo"; +import RelationTempInfo from "../models/RelationTempInfo"; +import IConnectionOptions from "../IConnectionOptions"; -export class MysqlDriver extends AbstractDriver { +export default class MysqlDriver extends AbstractDriver { public defaultValues: DataTypeDefaults = new TypeormDriver.MysqlDriver({ options: { replication: undefined } as ConnectionOptions } as any).dataTypeDefaults; + public readonly EngineName: string = "MySQL"; + public readonly standardPort = 3306; + public readonly standardUser = "root"; + public readonly standardSchema = ""; private Connection: MYSQL.Connection; @@ -30,7 +34,9 @@ export class MysqlDriver extends AbstractDriver { }>(`SELECT TABLE_SCHEMA, TABLE_NAME, TABLE_SCHEMA as DB_NAME FROM information_schema.tables WHERE table_type='BASE TABLE' - AND table_schema IN (${this.escapeCommaSeparatedList(dbNames)})`); + AND table_schema IN (${MysqlDriver.escapeCommaSeparatedList( + dbNames + )})`); return response; }; @@ -54,7 +60,7 @@ export class MysqlDriver extends AbstractDriver { }>(`SELECT TABLE_NAME,COLUMN_NAME,COLUMN_DEFAULT,IS_NULLABLE, DATA_TYPE,CHARACTER_MAXIMUM_LENGTH,NUMERIC_PRECISION,NUMERIC_SCALE, CASE WHEN EXTRA like '%auto_increment%' THEN 1 ELSE 0 END IsIdentity, COLUMN_TYPE, COLUMN_KEY - FROM INFORMATION_SCHEMA.COLUMNS where TABLE_SCHEMA IN (${this.escapeCommaSeparatedList( + FROM INFORMATION_SCHEMA.COLUMNS where TABLE_SCHEMA IN (${MysqlDriver.escapeCommaSeparatedList( dbNames )}) order by ordinal_position`); @@ -68,7 +74,7 @@ export class MysqlDriver extends AbstractDriver { colInfo.options.nullable = resp.IS_NULLABLE === "YES"; colInfo.options.generated = resp.IsIdentity === 1; colInfo.options.unique = resp.COLUMN_KEY === "UNI"; - colInfo.options.default = this.ReturnDefaultValueFunction( + colInfo.options.default = MysqlDriver.ReturnDefaultValueFunction( resp.COLUMN_DEFAULT ); colInfo.options.type = resp.DATA_TYPE as any; @@ -163,7 +169,7 @@ export class MysqlDriver extends AbstractDriver { colInfo.options.enum = resp.COLUMN_TYPE.substring( 5, resp.COLUMN_TYPE.length - 1 - ).replace(/\'/gi, '"'); + ).replace(/'/gi, '"'); break; case "json": colInfo.tsType = "object"; @@ -244,6 +250,7 @@ export class MysqlDriver extends AbstractDriver { }); return entities; } + public async GetIndexesFromEntity( entities: EntityInfo[], schema: string, @@ -258,7 +265,9 @@ export class MysqlDriver extends AbstractDriver { }>(`SELECT TABLE_NAME TableName,INDEX_NAME IndexName,COLUMN_NAME ColumnName,CASE WHEN NON_UNIQUE=0 THEN 1 ELSE 0 END is_unique, CASE WHEN INDEX_NAME='PRIMARY' THEN 1 ELSE 0 END is_primary_key FROM information_schema.statistics sta - WHERE table_schema IN (${this.escapeCommaSeparatedList(dbNames)})`); + WHERE table_schema IN (${MysqlDriver.escapeCommaSeparatedList( + dbNames + )})`); entities.forEach(ent => { response .filter(filterVal => filterVal.TableName === ent.tsEntityName) @@ -287,6 +296,7 @@ export class MysqlDriver extends AbstractDriver { return entities; } + public async GetRelations( entities: EntityInfo[], schema: string, @@ -316,23 +326,23 @@ export class MysqlDriver extends AbstractDriver { INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS RC ON CU.CONSTRAINT_NAME=RC.CONSTRAINT_NAME AND CU.CONSTRAINT_SCHEMA = RC.CONSTRAINT_SCHEMA WHERE - TABLE_SCHEMA IN (${this.escapeCommaSeparatedList(dbNames)}) + TABLE_SCHEMA IN (${MysqlDriver.escapeCommaSeparatedList(dbNames)}) AND CU.REFERENCED_TABLE_NAME IS NOT NULL; `); - const relationsTemp: IRelationTempInfo[] = [] as IRelationTempInfo[]; + const relationsTemp: RelationTempInfo[] = [] as RelationTempInfo[]; response.forEach(resp => { let rels = relationsTemp.find( - val => val.object_id === resp.object_id + val => val.objectId === resp.object_id ); if (rels === undefined) { - rels = {} as IRelationTempInfo; + rels = {} as RelationTempInfo; rels.ownerColumnsNames = []; rels.referencedColumnsNames = []; rels.actionOnDelete = resp.onDelete === "NO_ACTION" ? null : resp.onDelete; rels.actionOnUpdate = resp.onUpdate === "NO_ACTION" ? null : resp.onUpdate; - rels.object_id = resp.object_id; + rels.objectId = resp.object_id; rels.ownerTable = resp.TableWithForeignKey; rels.referencedTable = resp.TableReferenced; relationsTemp.push(rels); @@ -340,12 +350,13 @@ export class MysqlDriver extends AbstractDriver { rels.ownerColumnsNames.push(resp.ForeignKeyColumn); rels.referencedColumnsNames.push(resp.ForeignKeyColumnReferenced); }); - entities = this.GetRelationsFromRelationTempInfo( + const retVal = MysqlDriver.GetRelationsFromRelationTempInfo( relationsTemp, entities ); - return entities; + return retVal; } + public async DisconnectFromServer() { const promise = new Promise((resolve, reject) => { this.Connection.end(err => { @@ -365,6 +376,7 @@ export class MysqlDriver extends AbstractDriver { await promise; } } + public async ConnectToServer(connectionOptons: IConnectionOptions) { const databaseName = connectionOptons.databaseName.split(",")[0]; let config: MYSQL.ConnectionConfig; @@ -410,21 +422,26 @@ export class MysqlDriver extends AbstractDriver { await promise; } + public async CreateDB(dbName: string) { await this.ExecQuery(`CREATE DATABASE ${dbName}; `); } + public async UseDB(dbName: string) { await this.ExecQuery(`USE ${dbName}; `); } + public async DropDB(dbName: string) { await this.ExecQuery(`DROP DATABASE ${dbName}; `); } + public async CheckIfDBExists(dbName: string): Promise { const resp = await this.ExecQuery( `SHOW DATABASES LIKE '${dbName}' ` ); return resp.length > 0; } + public async ExecQuery(sql: string): Promise { const ret: T[] = []; const query = this.Connection.query(sql); @@ -439,16 +456,23 @@ export class MysqlDriver extends AbstractDriver { await promise; return ret; } - private ReturnDefaultValueFunction(defVal: string | null): string | null { - if (!defVal || defVal === "NULL") { + + private static ReturnDefaultValueFunction( + defVal: string | null + ): string | null { + let defaultValue = defVal; + if (!defaultValue || defaultValue === "NULL") { return null; } - if (defVal.toLowerCase() === "current_timestamp()") { - defVal = "CURRENT_TIMESTAMP"; + if (defaultValue.toLowerCase() === "current_timestamp()") { + defaultValue = "CURRENT_TIMESTAMP"; } - if (defVal === "CURRENT_TIMESTAMP" || defVal.startsWith(`'`)) { - return `() => "${defVal}"`; + if ( + defaultValue === "CURRENT_TIMESTAMP" || + defaultValue.startsWith(`'`) + ) { + return `() => "${defaultValue}"`; } - return `() => "'${defVal}'"`; + return `() => "'${defaultValue}'"`; } } diff --git a/src/drivers/OracleDriver.ts b/src/drivers/OracleDriver.ts index d91d633..27dd884 100644 --- a/src/drivers/OracleDriver.ts +++ b/src/drivers/OracleDriver.ts @@ -1,28 +1,33 @@ import * as TypeormDriver from "typeorm/driver/oracle/OracleDriver"; import { DataTypeDefaults } from "typeorm/driver/types/DataTypeDefaults"; -import { IConnectionOptions } from "../IConnectionOptions"; -import { ColumnInfo } from "../models/ColumnInfo"; -import { EntityInfo } from "../models/EntityInfo"; -import { IndexColumnInfo } from "../models/IndexColumnInfo"; -import { IndexInfo } from "../models/IndexInfo"; -import { IRelationTempInfo } from "../models/RelationTempInfo"; import * as TomgUtils from "../Utils"; -import { AbstractDriver } from "./AbstractDriver"; +import AbstractDriver from "./AbstractDriver"; +import EntityInfo from "../models/EntityInfo"; +import ColumnInfo from "../models/ColumnInfo"; +import IndexInfo from "../models/IndexInfo"; +import IndexColumnInfo from "../models/IndexColumnInfo"; +import RelationTempInfo from "../models/RelationTempInfo"; +import IConnectionOptions from "../IConnectionOptions"; -export class OracleDriver extends AbstractDriver { +export default class OracleDriver extends AbstractDriver { public defaultValues: DataTypeDefaults = new TypeormDriver.OracleDriver({ options: undefined } as any).dataTypeDefaults; + public readonly standardPort = 1521; + public readonly standardUser = "SYS"; + public readonly standardSchema = ""; public Oracle: any; - private Connection: any /*Oracle.IConnection*/; - constructor() { + private Connection: any /* Oracle.IConnection */; + + public constructor() { super(); try { + // eslint-disable-next-line import/no-extraneous-dependencies, global-require this.Oracle = require("oracledb"); this.Oracle.outFormat = this.Oracle.OBJECT; } catch (error) { @@ -31,22 +36,21 @@ export class OracleDriver extends AbstractDriver { } } - public GetAllTablesQuery = async (schema: string) => { - const response: Array<{ + public GetAllTablesQuery = async () => { + const response: { TABLE_SCHEMA: string; TABLE_NAME: string; DB_NAME: string; - }> = (await this.Connection.execute( + }[] = (await this.Connection.execute( ` SELECT NULL AS TABLE_SCHEMA, TABLE_NAME, NULL AS DB_NAME FROM all_tables WHERE owner = (select user from dual)` )).rows!; return response; }; public async GetCoulmnsFromEntity( - entities: EntityInfo[], - schema: string + entities: EntityInfo[] ): Promise { - const response: Array<{ + const response: { TABLE_NAME: string; COLUMN_NAME: string; DATA_DEFAULT: string; @@ -57,7 +61,7 @@ export class OracleDriver extends AbstractDriver { DATA_SCALE: number; IDENTITY_COLUMN: string; IS_UNIQUE: number; - }> = (await this.Connection + }[] = (await this.Connection .execute(`SELECT utc.TABLE_NAME, utc.COLUMN_NAME, DATA_DEFAULT, NULLABLE, DATA_TYPE, DATA_LENGTH, DATA_PRECISION, DATA_SCALE, IDENTITY_COLUMN, (select count(*) from USER_CONS_COLUMNS ucc @@ -77,13 +81,13 @@ export class OracleDriver extends AbstractDriver { colInfo.options.default = !resp.DATA_DEFAULT || resp.DATA_DEFAULT.includes('"') ? null - : this.ReturnDefaultValueFunction( + : OracleDriver.ReturnDefaultValueFunction( resp.DATA_DEFAULT ); colInfo.options.unique = resp.IS_UNIQUE > 0; - resp.DATA_TYPE = resp.DATA_TYPE.replace(/\([0-9]+\)/g, ""); - colInfo.options.type = resp.DATA_TYPE.toLowerCase() as any; - switch (resp.DATA_TYPE.toLowerCase()) { + const DATA_TYPE = resp.DATA_TYPE.replace(/\([0-9]+\)/g, ""); + colInfo.options.type = DATA_TYPE.toLowerCase() as any; + switch (DATA_TYPE.toLowerCase()) { case "char": colInfo.tsType = "string"; break; @@ -173,7 +177,7 @@ export class OracleDriver extends AbstractDriver { break; default: TomgUtils.LogError( - "Unknown column type:" + resp.DATA_TYPE + `Unknown column type:${DATA_TYPE}` ); break; } @@ -201,17 +205,17 @@ export class OracleDriver extends AbstractDriver { }); return entities; } + public async GetIndexesFromEntity( - entities: EntityInfo[], - schema: string + entities: EntityInfo[] ): Promise { - const response: Array<{ + const response: { COLUMN_NAME: string; TABLE_NAME: string; INDEX_NAME: string; UNIQUENESS: string; ISPRIMARYKEY: number; - }> = (await this.Connection + }[] = (await this.Connection .execute(`SELECT ind.TABLE_NAME, ind.INDEX_NAME, col.COLUMN_NAME,ind.UNIQUENESS, CASE WHEN uc.CONSTRAINT_NAME IS NULL THEN 0 ELSE 1 END ISPRIMARYKEY FROM USER_INDEXES ind JOIN USER_IND_COLUMNS col ON ind.INDEX_NAME=col.INDEX_NAME @@ -246,11 +250,9 @@ export class OracleDriver extends AbstractDriver { return entities; } - public async GetRelations( - entities: EntityInfo[], - schema: string - ): Promise { - const response: Array<{ + + public async GetRelations(entities: EntityInfo[]): Promise { + const response: { OWNER_TABLE_NAME: string; OWNER_POSITION: string; OWNER_COLUMN_NAME: string; @@ -258,7 +260,7 @@ export class OracleDriver extends AbstractDriver { CHILD_COLUMN_NAME: string; DELETE_RULE: "RESTRICT" | "CASCADE" | "SET NULL" | "NO ACTION"; CONSTRAINT_NAME: string; - }> = (await this.Connection + }[] = (await this.Connection .execute(`select owner.TABLE_NAME OWNER_TABLE_NAME,ownCol.POSITION OWNER_POSITION,ownCol.COLUMN_NAME OWNER_COLUMN_NAME, child.TABLE_NAME CHILD_TABLE_NAME ,childCol.COLUMN_NAME CHILD_COLUMN_NAME, owner.DELETE_RULE, @@ -270,19 +272,19 @@ export class OracleDriver extends AbstractDriver { ORDER BY OWNER_TABLE_NAME ASC, owner.CONSTRAINT_NAME ASC, OWNER_POSITION ASC`)) .rows!; - const relationsTemp: IRelationTempInfo[] = [] as IRelationTempInfo[]; + const relationsTemp: RelationTempInfo[] = [] as RelationTempInfo[]; response.forEach(resp => { let rels = relationsTemp.find( - val => val.object_id === resp.CONSTRAINT_NAME + val => val.objectId === resp.CONSTRAINT_NAME ); if (rels === undefined) { - rels = {} as IRelationTempInfo; + rels = {} as RelationTempInfo; rels.ownerColumnsNames = []; rels.referencedColumnsNames = []; rels.actionOnDelete = resp.DELETE_RULE === "NO ACTION" ? null : resp.DELETE_RULE; rels.actionOnUpdate = null; - rels.object_id = resp.CONSTRAINT_NAME; + rels.objectId = resp.CONSTRAINT_NAME; rels.ownerTable = resp.OWNER_TABLE_NAME; rels.referencedTable = resp.CHILD_TABLE_NAME; relationsTemp.push(rels); @@ -290,21 +292,23 @@ export class OracleDriver extends AbstractDriver { rels.ownerColumnsNames.push(resp.OWNER_COLUMN_NAME); rels.referencedColumnsNames.push(resp.CHILD_COLUMN_NAME); }); - entities = this.GetRelationsFromRelationTempInfo( + const retVal = OracleDriver.GetRelationsFromRelationTempInfo( relationsTemp, entities ); - return entities; + return retVal; } + public async DisconnectFromServer() { if (this.Connection) { await this.Connection.close(); } } + public async ConnectToServer(connectionOptons: IConnectionOptions) { let config: any; if (connectionOptons.user === String(process.env.ORACLE_UsernameSys)) { - config /*Oracle.IConnectionAttributes*/ = { + config /* Oracle.IConnectionAttributes */ = { connectString: `${connectionOptons.host}:${connectionOptons.port}/${connectionOptons.databaseName}`, externalAuth: connectionOptons.ssl, password: connectionOptons.password, @@ -312,7 +316,7 @@ export class OracleDriver extends AbstractDriver { user: connectionOptons.user }; } else { - config /*Oracle.IConnectionAttributes*/ = { + config /* Oracle.IConnectionAttributes */ = { connectString: `${connectionOptons.host}:${connectionOptons.port}/${connectionOptons.databaseName}`, externalAuth: connectionOptons.ssl, password: connectionOptons.password, @@ -347,28 +351,36 @@ export class OracleDriver extends AbstractDriver { ); await this.Connection.execute(`GRANT CONNECT TO ${dbName}`); } - public async UseDB(dbName: string) { + + // eslint-disable-next-line class-methods-use-this + public async UseDB() { // not supported } + public async DropDB(dbName: string) { await this.Connection.execute(`DROP USER ${dbName} CASCADE`); } + public async CheckIfDBExists(dbName: string): Promise { const x = await this.Connection.execute( `select count(*) as CNT from dba_users where username='${dbName.toUpperCase()}'` ); return x.rows[0][0] > 0 || x.rows[0].CNT; } - private ReturnDefaultValueFunction(defVal: string | null): string | null { - if (!defVal) { + + private static ReturnDefaultValueFunction( + defVal: string | null + ): string | null { + let defaultVal = defVal; + if (!defaultVal) { return null; } - if (defVal.endsWith(" ")) { - defVal = defVal.slice(0, -1); + if (defaultVal.endsWith(" ")) { + defaultVal = defaultVal.slice(0, -1); } - if (defVal.startsWith(`'`)) { - return `() => "${defVal}"`; + if (defaultVal.startsWith(`'`)) { + return `() => "${defaultVal}"`; } - return `() => "${defVal}"`; + return `() => "${defaultVal}"`; } } diff --git a/src/drivers/PostgresDriver.ts b/src/drivers/PostgresDriver.ts index 04ac1d0..5ed4b6c 100644 --- a/src/drivers/PostgresDriver.ts +++ b/src/drivers/PostgresDriver.ts @@ -2,31 +2,34 @@ import * as PG from "pg"; import { ConnectionOptions } from "typeorm"; import * as TypeormDriver from "typeorm/driver/postgres/PostgresDriver"; import { DataTypeDefaults } from "typeorm/driver/types/DataTypeDefaults"; -import { IConnectionOptions } from "../IConnectionOptions"; -import { ColumnInfo } from "../models/ColumnInfo"; -import { EntityInfo } from "../models/EntityInfo"; -import { IndexColumnInfo } from "../models/IndexColumnInfo"; -import { IndexInfo } from "../models/IndexInfo"; -import { IRelationTempInfo } from "../models/RelationTempInfo"; import * as TomgUtils from "../Utils"; -import { AbstractDriver } from "./AbstractDriver"; +import AbstractDriver from "./AbstractDriver"; +import EntityInfo from "../models/EntityInfo"; +import ColumnInfo from "../models/ColumnInfo"; +import IndexInfo from "../models/IndexInfo"; +import IndexColumnInfo from "../models/IndexColumnInfo"; +import RelationTempInfo from "../models/RelationTempInfo"; +import IConnectionOptions from "../IConnectionOptions"; -export class PostgresDriver extends AbstractDriver { +export default class PostgresDriver extends AbstractDriver { public defaultValues: DataTypeDefaults = new TypeormDriver.PostgresDriver({ options: { replication: undefined } as ConnectionOptions } as any).dataTypeDefaults; + public readonly standardPort = 5432; + public readonly standardUser = "postgres"; + public readonly standardSchema = "public"; private Connection: PG.Client; public GetAllTablesQuery = async (schema: string) => { - const response: Array<{ + const response: { TABLE_SCHEMA: string; TABLE_NAME: string; DB_NAME: string; - }> = (await this.Connection.query( + }[] = (await this.Connection.query( `SELECT table_schema as "TABLE_SCHEMA",table_name as "TABLE_NAME", table_catalog as "DB_NAME" FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE='BASE TABLE' AND table_schema in (${schema}) ` )).rows; return response; @@ -36,7 +39,7 @@ export class PostgresDriver extends AbstractDriver { entities: EntityInfo[], schema: string ): Promise { - const response: Array<{ + const response: { table_name: string; column_name: string; udt_name: string; @@ -49,7 +52,7 @@ export class PostgresDriver extends AbstractDriver { isidentity: string; isunique: string; enumvalues: string | null; - }> = (await this.Connection + }[] = (await this.Connection .query(`SELECT table_name,column_name,udt_name,column_default,is_nullable, data_type,character_maximum_length,numeric_precision,numeric_scale, case when column_default LIKE 'nextval%' then 'YES' else 'NO' end isidentity, @@ -84,14 +87,16 @@ WHERE "n"."nspname" = table_schema AND "t"."typname"=udt_name colInfo.options.unique = resp.isunique === "1"; colInfo.options.default = colInfo.options.generated ? null - : this.ReturnDefaultValueFunction(resp.column_default); + : PostgresDriver.ReturnDefaultValueFunction( + resp.column_default + ); const columnTypes = this.MatchColumnTypes( resp.data_type, resp.udt_name, resp.enumvalues ); - if (!columnTypes.sql_type || !columnTypes.ts_type) { + if (!columnTypes.sqlType || !columnTypes.tsType) { if ( resp.data_type === "USER-DEFINED" || resp.data_type === "ARRAY" @@ -106,14 +111,14 @@ WHERE "n"."nspname" = table_schema AND "t"."typname"=udt_name } return; } - colInfo.options.type = columnTypes.sql_type as any; - colInfo.tsType = columnTypes.ts_type; - colInfo.options.array = columnTypes.is_array; + colInfo.options.type = columnTypes.sqlType as any; + colInfo.tsType = columnTypes.tsType; + colInfo.options.array = columnTypes.isArray; colInfo.options.enum = columnTypes.enumValues; if (colInfo.options.array) { colInfo.tsType = colInfo.tsType .split("|") - .map(x => x.replace("|", "").trim() + "[]") + .map(x => `${x.replace("|", "").trim()}[]`) .join(" | ") as any; } @@ -158,8 +163,8 @@ WHERE "n"."nspname" = table_schema AND "t"."typname"=udt_name udtName: string, enumValues: string | null ) { - const ret: { - ts_type: + let ret: { + tsType: | "number" | "string" | "boolean" @@ -170,243 +175,241 @@ WHERE "n"."nspname" = table_schema AND "t"."typname"=udt_name | "string | string[]" | "any" | null; - sql_type: string | null; - is_array: boolean; + sqlType: string | null; + isArray: boolean; enumValues: string[]; - } = { ts_type: null, sql_type: null, is_array: false, enumValues: [] }; - ret.sql_type = dataType; + } = { tsType: null, sqlType: null, isArray: false, enumValues: [] }; + ret.sqlType = dataType; switch (dataType) { case "int2": - ret.ts_type = "number"; + ret.tsType = "number"; break; case "int4": - ret.ts_type = "number"; + ret.tsType = "number"; break; case "int8": - ret.ts_type = "string"; + ret.tsType = "string"; break; case "smallint": - ret.ts_type = "number"; + ret.tsType = "number"; break; case "integer": - ret.ts_type = "number"; + ret.tsType = "number"; break; case "bigint": - ret.ts_type = "string"; + ret.tsType = "string"; break; case "decimal": - ret.ts_type = "string"; + ret.tsType = "string"; break; case "numeric": - ret.ts_type = "string"; + ret.tsType = "string"; break; case "real": - ret.ts_type = "number"; + ret.tsType = "number"; break; case "float": - ret.ts_type = "number"; + ret.tsType = "number"; break; case "float4": - ret.ts_type = "number"; + ret.tsType = "number"; break; case "float8": - ret.ts_type = "number"; + ret.tsType = "number"; break; case "double precision": - ret.ts_type = "number"; + ret.tsType = "number"; break; case "money": - ret.ts_type = "string"; + ret.tsType = "string"; break; case "character varying": - ret.ts_type = "string"; + ret.tsType = "string"; break; case "varchar": - ret.ts_type = "string"; + ret.tsType = "string"; break; case "character": - ret.ts_type = "string"; + ret.tsType = "string"; break; case "char": - ret.ts_type = "string"; + ret.tsType = "string"; break; case "bpchar": - ret.sql_type = "char"; - ret.ts_type = "string"; + ret.sqlType = "char"; + ret.tsType = "string"; break; case "text": - ret.ts_type = "string"; + ret.tsType = "string"; break; case "citext": - ret.ts_type = "string"; + ret.tsType = "string"; break; case "hstore": - ret.ts_type = "string"; + ret.tsType = "string"; break; case "bytea": - ret.ts_type = "Buffer"; + ret.tsType = "Buffer"; break; case "bit": - ret.ts_type = "string"; + ret.tsType = "string"; break; case "varbit": - ret.ts_type = "string"; + ret.tsType = "string"; break; case "bit varying": - ret.ts_type = "string"; + ret.tsType = "string"; break; case "timetz": - ret.ts_type = "string"; + ret.tsType = "string"; break; case "timestamptz": - ret.ts_type = "Date"; + ret.tsType = "Date"; break; case "timestamp": - ret.ts_type = "string"; + ret.tsType = "string"; break; case "timestamp without time zone": - ret.ts_type = "Date"; + ret.tsType = "Date"; break; case "timestamp with time zone": - ret.ts_type = "Date"; + ret.tsType = "Date"; break; case "date": - ret.ts_type = "string"; + ret.tsType = "string"; break; case "time": - ret.ts_type = "string"; + ret.tsType = "string"; break; case "time without time zone": - ret.ts_type = "string"; + ret.tsType = "string"; break; case "time with time zone": - ret.ts_type = "string"; + ret.tsType = "string"; break; case "interval": - ret.ts_type = "any"; + ret.tsType = "any"; break; case "bool": - ret.ts_type = "boolean"; + ret.tsType = "boolean"; break; case "boolean": - ret.ts_type = "boolean"; + ret.tsType = "boolean"; break; case "point": - ret.ts_type = "string | object"; + ret.tsType = "string | object"; break; case "line": - ret.ts_type = "string"; + ret.tsType = "string"; break; case "lseg": - ret.ts_type = "string | string[]"; + ret.tsType = "string | string[]"; break; case "box": - ret.ts_type = "string | object"; + ret.tsType = "string | object"; break; case "path": - ret.ts_type = "string"; + ret.tsType = "string"; break; case "polygon": - ret.ts_type = "string"; + ret.tsType = "string"; break; case "circle": - ret.ts_type = "string | object"; + ret.tsType = "string | object"; break; case "cidr": - ret.ts_type = "string"; + ret.tsType = "string"; break; case "inet": - ret.ts_type = "string"; + ret.tsType = "string"; break; case "macaddr": - ret.ts_type = "string"; + ret.tsType = "string"; break; case "tsvector": - ret.ts_type = "string"; + ret.tsType = "string"; break; case "tsquery": - ret.ts_type = "string"; + ret.tsType = "string"; break; case "uuid": - ret.ts_type = "string"; + ret.tsType = "string"; break; case "xml": - ret.ts_type = "string"; + ret.tsType = "string"; break; case "json": - ret.ts_type = "object"; + ret.tsType = "object"; break; case "jsonb": - ret.ts_type = "object"; + ret.tsType = "object"; break; case "int4range": - ret.ts_type = "string"; + ret.tsType = "string"; break; case "int8range": - ret.ts_type = "string"; + ret.tsType = "string"; break; case "numrange": - ret.ts_type = "string"; + ret.tsType = "string"; break; case "tsrange": - ret.ts_type = "string"; + ret.tsType = "string"; break; case "tstzrange": - ret.ts_type = "string"; + ret.tsType = "string"; break; case "daterange": - ret.ts_type = "string"; + ret.tsType = "string"; break; case "ARRAY": - const z = this.MatchColumnTypes( + ret = this.MatchColumnTypes( udtName.substring(1), udtName, enumValues ); - ret.ts_type = z.ts_type; - ret.sql_type = z.sql_type; - ret.is_array = true; - ret.enumValues = z.enumValues; + ret.isArray = true; break; case "USER-DEFINED": - ret.ts_type = "string"; + ret.tsType = "string"; switch (udtName) { case "citext": case "hstore": case "geometry": - ret.sql_type = udtName; + ret.sqlType = udtName; break; default: if (enumValues) { - ret.sql_type = "enum"; - ret.enumValues = (('"' + - enumValues.split(",").join('","') + - '"') as never) as string[]; + ret.sqlType = "enum"; + ret.enumValues = (`"${enumValues + .split(",") + .join('","')}"` as never) as string[]; } else { - ret.ts_type = null; - ret.sql_type = null; + ret.tsType = null; + ret.sqlType = null; } break; } break; default: - ret.ts_type = null; - ret.sql_type = null; + ret.tsType = null; + ret.sqlType = null; break; } return ret; } + public async GetIndexesFromEntity( entities: EntityInfo[], schema: string ): Promise { - const response: Array<{ + const response: { tablename: string; indexname: string; columnname: string; is_unique: number; is_primary_key: number; - }> = (await this.Connection.query(`SELECT + }[] = (await this.Connection.query(`SELECT c.relname AS tablename, i.relname as indexname, f.attname AS columnname, @@ -461,11 +464,12 @@ WHERE "n"."nspname" = table_schema AND "t"."typname"=udt_name return entities; } + public async GetRelations( entities: EntityInfo[], schema: string ): Promise { - const response: Array<{ + const response: { tablewithforeignkey: string; fk_partno: number; foreignkeycolumn: string; @@ -475,7 +479,7 @@ WHERE "n"."nspname" = table_schema AND "t"."typname"=udt_name onupdate: "RESTRICT" | "CASCADE" | "SET NULL" | "NO ACTION"; object_id: string; // Distinct because of note in https://www.postgresql.org/docs/9.1/information-schema.html - }> = (await this.Connection.query(`SELECT DISTINCT + }[] = (await this.Connection.query(`SELECT DISTINCT con.relname AS tablewithforeignkey, att.attnum as fk_partno, att2.attname AS foreignkeycolumn, @@ -515,20 +519,20 @@ WHERE "n"."nspname" = table_schema AND "t"."typname"=udt_name AND att2.attnum = con.parent AND rc.constraint_name= con.conname AND constraint_catalog=current_database() AND rc.constraint_schema=nspname `)).rows; - const relationsTemp: IRelationTempInfo[] = [] as IRelationTempInfo[]; + const relationsTemp: RelationTempInfo[] = [] as RelationTempInfo[]; response.forEach(resp => { let rels = relationsTemp.find( - val => val.object_id === resp.object_id + val => val.objectId === resp.object_id ); if (rels === undefined) { - rels = {} as IRelationTempInfo; + rels = {} as RelationTempInfo; rels.ownerColumnsNames = []; rels.referencedColumnsNames = []; rels.actionOnDelete = resp.ondelete === "NO ACTION" ? null : resp.ondelete; rels.actionOnUpdate = resp.onupdate === "NO ACTION" ? null : resp.onupdate; - rels.object_id = resp.object_id; + rels.objectId = resp.object_id; rels.ownerTable = resp.tablewithforeignkey; rels.referencedTable = resp.tablereferenced; relationsTemp.push(rels); @@ -536,12 +540,13 @@ WHERE "n"."nspname" = table_schema AND "t"."typname"=udt_name rels.ownerColumnsNames.push(resp.foreignkeycolumn); rels.referencedColumnsNames.push(resp.foreignkeycolumnreferenced); }); - entities = this.GetRelationsFromRelationTempInfo( + const retVal = PostgresDriver.GetRelationsFromRelationTempInfo( relationsTemp, entities ); - return entities; + return retVal; } + public async DisconnectFromServer() { if (this.Connection) { const promise = new Promise((resolve, reject) => { @@ -569,6 +574,7 @@ WHERE "n"."nspname" = table_schema AND "t"."typname"=udt_name password: connectionOptons.password, port: connectionOptons.port, ssl: connectionOptons.ssl, + // eslint-disable-next-line @typescript-eslint/camelcase statement_timeout: connectionOptons.timeout, user: connectionOptons.user }); @@ -594,26 +600,33 @@ WHERE "n"."nspname" = table_schema AND "t"."typname"=udt_name public async CreateDB(dbName: string) { await this.Connection.query(`CREATE DATABASE ${dbName}; `); } + public async UseDB(dbName: string) { await this.Connection.query(`USE ${dbName}; `); } + public async DropDB(dbName: string) { await this.Connection.query(`DROP DATABASE ${dbName}; `); } + public async CheckIfDBExists(dbName: string): Promise { const resp = await this.Connection.query( `SELECT datname FROM pg_database WHERE datname ='${dbName}' ` ); return resp.rowCount > 0; } - private ReturnDefaultValueFunction(defVal: string | null): string | null { - if (!defVal) { + + private static ReturnDefaultValueFunction( + defVal: string | null + ): string | null { + let defaultValue = defVal; + if (!defaultValue) { return null; } - defVal = defVal.replace(/'::[\w ]*/, "'"); - if (defVal.startsWith(`'`)) { - return `() => "${defVal}"`; + defaultValue = defaultValue.replace(/'::[\w ]*/, "'"); + if (defaultValue.startsWith(`'`)) { + return `() => "${defaultValue}"`; } - return `() => "${defVal}"`; + return `() => "${defaultValue}"`; } } diff --git a/src/drivers/SqliteDriver.ts b/src/drivers/SqliteDriver.ts index a86d5b9..5dbadc5 100644 --- a/src/drivers/SqliteDriver.ts +++ b/src/drivers/SqliteDriver.ts @@ -1,29 +1,36 @@ import { ConnectionOptions } from "typeorm"; import * as TypeormDriver from "typeorm/driver/sqlite/SqliteDriver"; import { DataTypeDefaults } from "typeorm/driver/types/DataTypeDefaults"; -import { IConnectionOptions } from "../IConnectionOptions"; -import { ColumnInfo } from "../models/ColumnInfo"; -import { EntityInfo } from "../models/EntityInfo"; -import { IndexColumnInfo } from "../models/IndexColumnInfo"; -import { IndexInfo } from "../models/IndexInfo"; -import { IRelationTempInfo } from "../models/RelationTempInfo"; +import * as sqliteLib from "sqlite3"; import * as TomgUtils from "../Utils"; -import { AbstractDriver } from "./AbstractDriver"; +import AbstractDriver from "./AbstractDriver"; +import EntityInfo from "../models/EntityInfo"; +import ColumnInfo from "../models/ColumnInfo"; +import IndexInfo from "../models/IndexInfo"; +import IndexColumnInfo from "../models/IndexColumnInfo"; +import RelationTempInfo from "../models/RelationTempInfo"; +import IConnectionOptions from "../IConnectionOptions"; -export class SqliteDriver extends AbstractDriver { +export default class SqliteDriver extends AbstractDriver { public defaultValues: DataTypeDefaults = new TypeormDriver.SqliteDriver({ options: { database: "true" } as ConnectionOptions } as any).dataTypeDefaults; + public readonly standardPort = 0; + public readonly standardUser = ""; + public readonly standardSchema = ""; - public sqlite = require("sqlite3").verbose(); + public sqlite = sqliteLib.verbose(); + public db: any; + public tablesWithGeneratedPrimaryKey: string[] = new Array(); + public GetAllTablesQuery: any; - public async GetAllTables(schema: string): Promise { + public async GetAllTables(): Promise { const ret: EntityInfo[] = [] as EntityInfo[]; const rows = await this.ExecQuery<{ tbl_name: string; sql: string }>( `SELECT tbl_name, sql FROM "sqlite_master" WHERE "type" = 'table' AND name NOT LIKE 'sqlite_%'` @@ -40,260 +47,279 @@ export class SqliteDriver extends AbstractDriver { }); return ret; } + public async GetCoulmnsFromEntity( - entities: EntityInfo[], - schema: string + entities: EntityInfo[] ): Promise { - for (const ent of entities) { - const response = await this.ExecQuery<{ - cid: number; - name: string; - type: string; - notnull: number; - dflt_value: string; - pk: number; - }>(`PRAGMA table_info('${ent.tsEntityName}');`); - response.forEach(resp => { - const colInfo: ColumnInfo = new ColumnInfo(); - colInfo.tsName = resp.name; - colInfo.options.name = resp.name; - colInfo.options.nullable = resp.notnull === 0; - colInfo.options.primary = resp.pk > 0; - colInfo.options.default = this.ReturnDefaultValueFunction( - resp.dflt_value - ); - colInfo.options.type = resp.type - .replace(/\([0-9 ,]+\)/g, "") - .toLowerCase() - .trim() as any; - colInfo.options.generated = - colInfo.options.primary && - this.tablesWithGeneratedPrimaryKey.includes( - ent.tsEntityName - ); - switch (colInfo.options.type) { - case "int": - colInfo.tsType = "number"; - break; - case "integer": - colInfo.tsType = "number"; - break; - case "int2": - colInfo.tsType = "number"; - break; - case "int8": - colInfo.tsType = "number"; - break; - case "tinyint": - colInfo.tsType = "number"; - break; - case "smallint": - colInfo.tsType = "number"; - break; - case "mediumint": - colInfo.tsType = "number"; - break; - case "bigint": - colInfo.tsType = "string"; - break; - case "unsigned big int": - colInfo.tsType = "string"; - break; - case "character": - colInfo.tsType = "string"; - break; - case "varchar": - colInfo.tsType = "string"; - break; - case "varying character": - colInfo.tsType = "string"; - break; - case "nchar": - colInfo.tsType = "string"; - break; - case "native character": - colInfo.tsType = "string"; - break; - case "nvarchar": - colInfo.tsType = "string"; - break; - case "text": - colInfo.tsType = "string"; - break; - case "blob": - colInfo.tsType = "Buffer"; - break; - case "clob": - colInfo.tsType = "string"; - break; - case "real": - colInfo.tsType = "number"; - break; - case "double": - colInfo.tsType = "number"; - break; - case "double precision": - colInfo.tsType = "number"; - break; - case "float": - colInfo.tsType = "number"; - break; - case "numeric": - colInfo.tsType = "number"; - break; - case "decimal": - colInfo.tsType = "number"; - break; - case "boolean": - colInfo.tsType = "boolean"; - break; - case "date": - colInfo.tsType = "string"; - break; - case "datetime": - colInfo.tsType = "Date"; - break; - default: - TomgUtils.LogError( - `Unknown column type: ${colInfo.options.type} table name: ${ent.tsEntityName} column name: ${resp.name}` - ); - break; - } - const options = resp.type.match(/\([0-9 ,]+\)/g); - if ( - this.ColumnTypesWithPrecision.some( - v => v === colInfo.options.type - ) && - options - ) { - colInfo.options.precision = options[0] - .substring(1, options[0].length - 1) - .split(",")[0] as any; - colInfo.options.scale = options[0] - .substring(1, options[0].length - 1) - .split(",")[1] as any; - } - if ( - this.ColumnTypesWithLength.some( - v => v === colInfo.options.type - ) && - options - ) { - colInfo.options.length = options[0].substring( - 1, - options[0].length - 1 - ) as any; - } - if ( - this.ColumnTypesWithWidth.some( - v => - v === colInfo.options.type && - colInfo.tsType !== "boolean" - ) && - options - ) { - colInfo.options.width = options[0].substring( - 1, - options[0].length - 1 - ) as any; - } - - if (colInfo.options.type) { - ent.Columns.push(colInfo); - } - }); - } - - return entities; - } - public async GetIndexesFromEntity( - entities: EntityInfo[], - schema: string - ): Promise { - for (const ent of entities) { - const response = await this.ExecQuery<{ - seq: number; - name: string; - unique: number; - origin: string; - partial: number; - }>(`PRAGMA index_list('${ent.tsEntityName}');`); - for (const resp of response) { - const indexColumnsResponse = await this.ExecQuery<{ - seqno: number; + await Promise.all( + entities.map(async ent => { + const response = await this.ExecQuery<{ cid: number; name: string; - }>(`PRAGMA index_info('${resp.name}');`); - indexColumnsResponse.forEach(element => { - let indexInfo: IndexInfo = {} as IndexInfo; - const indexColumnInfo: IndexColumnInfo = {} as IndexColumnInfo; - if ( - ent.Indexes.filter(filterVal => { - return filterVal.name === resp.name; - }).length > 0 - ) { - indexInfo = ent.Indexes.find( - filterVal => filterVal.name === resp.name - )!; - } else { - indexInfo.columns = [] as IndexColumnInfo[]; - indexInfo.name = resp.name; - indexInfo.isUnique = resp.unique === 1; - ent.Indexes.push(indexInfo); + type: string; + notnull: number; + dflt_value: string; + pk: number; + }>(`PRAGMA table_info('${ent.tsEntityName}');`); + response.forEach(resp => { + const colInfo: ColumnInfo = new ColumnInfo(); + colInfo.tsName = resp.name; + colInfo.options.name = resp.name; + colInfo.options.nullable = resp.notnull === 0; + colInfo.options.primary = resp.pk > 0; + colInfo.options.default = SqliteDriver.ReturnDefaultValueFunction( + resp.dflt_value + ); + colInfo.options.type = resp.type + .replace(/\([0-9 ,]+\)/g, "") + .toLowerCase() + .trim() as any; + colInfo.options.generated = + colInfo.options.primary && + this.tablesWithGeneratedPrimaryKey.includes( + ent.tsEntityName + ); + switch (colInfo.options.type) { + case "int": + colInfo.tsType = "number"; + break; + case "integer": + colInfo.tsType = "number"; + break; + case "int2": + colInfo.tsType = "number"; + break; + case "int8": + colInfo.tsType = "number"; + break; + case "tinyint": + colInfo.tsType = "number"; + break; + case "smallint": + colInfo.tsType = "number"; + break; + case "mediumint": + colInfo.tsType = "number"; + break; + case "bigint": + colInfo.tsType = "string"; + break; + case "unsigned big int": + colInfo.tsType = "string"; + break; + case "character": + colInfo.tsType = "string"; + break; + case "varchar": + colInfo.tsType = "string"; + break; + case "varying character": + colInfo.tsType = "string"; + break; + case "nchar": + colInfo.tsType = "string"; + break; + case "native character": + colInfo.tsType = "string"; + break; + case "nvarchar": + colInfo.tsType = "string"; + break; + case "text": + colInfo.tsType = "string"; + break; + case "blob": + colInfo.tsType = "Buffer"; + break; + case "clob": + colInfo.tsType = "string"; + break; + case "real": + colInfo.tsType = "number"; + break; + case "double": + colInfo.tsType = "number"; + break; + case "double precision": + colInfo.tsType = "number"; + break; + case "float": + colInfo.tsType = "number"; + break; + case "numeric": + colInfo.tsType = "number"; + break; + case "decimal": + colInfo.tsType = "number"; + break; + case "boolean": + colInfo.tsType = "boolean"; + break; + case "date": + colInfo.tsType = "string"; + break; + case "datetime": + colInfo.tsType = "Date"; + break; + default: + TomgUtils.LogError( + `Unknown column type: ${colInfo.options.type} table name: ${ent.tsEntityName} column name: ${resp.name}` + ); + break; } - indexColumnInfo.name = element.name; + const options = resp.type.match(/\([0-9 ,]+\)/g); if ( - indexColumnsResponse.length === 1 && - indexInfo.isUnique + this.ColumnTypesWithPrecision.some( + v => v === colInfo.options.type + ) && + options ) { - ent.Columns.filter( - v => v.tsName === indexColumnInfo.name - ).map(v => (v.options.unique = true)); + colInfo.options.precision = options[0] + .substring(1, options[0].length - 1) + .split(",")[0] as any; + colInfo.options.scale = options[0] + .substring(1, options[0].length - 1) + .split(",")[1] as any; + } + if ( + this.ColumnTypesWithLength.some( + v => v === colInfo.options.type + ) && + options + ) { + colInfo.options.length = options[0].substring( + 1, + options[0].length - 1 + ) as any; + } + if ( + this.ColumnTypesWithWidth.some( + v => + v === colInfo.options.type && + colInfo.tsType !== "boolean" + ) && + options + ) { + colInfo.options.width = options[0].substring( + 1, + options[0].length - 1 + ) as any; + } + + if (colInfo.options.type) { + ent.Columns.push(colInfo); } - indexInfo.columns.push(indexColumnInfo); }); - } - } + }) + ); return entities; } - public async GetRelations( - entities: EntityInfo[], - schema: string + + public async GetIndexesFromEntity( + entities: EntityInfo[] ): Promise { - for (const entity of entities) { - const response = await this.ExecQuery<{ - id: number; - seq: number; - table: string; - from: string; - to: string; - on_update: "RESTRICT" | "CASCADE" | "SET NULL" | "NO ACTION"; - on_delete: "RESTRICT" | "CASCADE" | "SET NULL" | "NO ACTION"; - match: string; - }>(`PRAGMA foreign_key_list('${entity.tsEntityName}');`); - const relationsTemp: IRelationTempInfo[] = [] as IRelationTempInfo[]; - response.forEach(resp => { - const rels = {} as IRelationTempInfo; - rels.ownerColumnsNames = []; - rels.referencedColumnsNames = []; - rels.actionOnDelete = - resp.on_delete === "NO ACTION" ? null : resp.on_delete; - rels.actionOnUpdate = - resp.on_update === "NO ACTION" ? null : resp.on_update; - rels.ownerTable = entity.tsEntityName; - rels.referencedTable = resp.table; - relationsTemp.push(rels); - rels.ownerColumnsNames.push(resp.from); - rels.referencedColumnsNames.push(resp.to); - }); - entities = this.GetRelationsFromRelationTempInfo( - relationsTemp, - entities - ); - } + await Promise.all( + entities.map(async ent => { + const response = await this.ExecQuery<{ + seq: number; + name: string; + unique: number; + origin: string; + partial: number; + }>(`PRAGMA index_list('${ent.tsEntityName}');`); + await Promise.all( + response.map(async resp => { + const indexColumnsResponse = await this.ExecQuery<{ + seqno: number; + cid: number; + name: string; + }>(`PRAGMA index_info('${resp.name}');`); + indexColumnsResponse.forEach(element => { + let indexInfo: IndexInfo = {} as IndexInfo; + const indexColumnInfo: IndexColumnInfo = {} as IndexColumnInfo; + if ( + ent.Indexes.filter(filterVal => { + return filterVal.name === resp.name; + }).length > 0 + ) { + indexInfo = ent.Indexes.find( + filterVal => filterVal.name === resp.name + )!; + } else { + indexInfo.columns = [] as IndexColumnInfo[]; + indexInfo.name = resp.name; + indexInfo.isUnique = resp.unique === 1; + ent.Indexes.push(indexInfo); + } + indexColumnInfo.name = element.name; + if ( + indexColumnsResponse.length === 1 && + indexInfo.isUnique + ) { + ent.Columns.filter( + v => v.tsName === indexColumnInfo.name + ).forEach(v => { + // eslint-disable-next-line no-param-reassign + v.options.unique = true; + }); + } + indexInfo.columns.push(indexColumnInfo); + }); + }) + ); + }) + ); + return entities; } + + public async GetRelations(entities: EntityInfo[]): Promise { + let retVal = entities; + await Promise.all( + retVal.map(async entity => { + const response = await this.ExecQuery<{ + id: number; + seq: number; + table: string; + from: string; + to: string; + on_update: + | "RESTRICT" + | "CASCADE" + | "SET NULL" + | "NO ACTION"; + on_delete: + | "RESTRICT" + | "CASCADE" + | "SET NULL" + | "NO ACTION"; + match: string; + }>(`PRAGMA foreign_key_list('${entity.tsEntityName}');`); + const relationsTemp: RelationTempInfo[] = [] as RelationTempInfo[]; + response.forEach(resp => { + const rels = {} as RelationTempInfo; + rels.ownerColumnsNames = []; + rels.referencedColumnsNames = []; + rels.actionOnDelete = + resp.on_delete === "NO ACTION" ? null : resp.on_delete; + rels.actionOnUpdate = + resp.on_update === "NO ACTION" ? null : resp.on_update; + rels.ownerTable = entity.tsEntityName; + rels.referencedTable = resp.table; + relationsTemp.push(rels); + rels.ownerColumnsNames.push(resp.from); + rels.referencedColumnsNames.push(resp.to); + }); + retVal = SqliteDriver.GetRelationsFromRelationTempInfo( + relationsTemp, + retVal + ); + }) + ); + return retVal; + } + public async DisconnectFromServer() { this.db.close(); } @@ -302,9 +328,11 @@ export class SqliteDriver extends AbstractDriver { await this.UseDB(connectionOptons.databaseName); } - public async CreateDB(dbName: string) { + // eslint-disable-next-line class-methods-use-this + public async CreateDB() { // not supported } + public async UseDB(dbName: string) { const promise = new Promise((resolve, reject) => { this.db = new this.sqlite.Database(dbName, err => { @@ -322,10 +350,14 @@ export class SqliteDriver extends AbstractDriver { }); return promise; } - public async DropDB(dbName: string) { + + // eslint-disable-next-line class-methods-use-this + public async DropDB() { // not supported } - public async CheckIfDBExists(dbName: string): Promise { + + // eslint-disable-next-line class-methods-use-this + public async CheckIfDBExists(): Promise { return true; } @@ -351,7 +383,10 @@ export class SqliteDriver extends AbstractDriver { await promise; return ret; } - private ReturnDefaultValueFunction(defVal: string | null): string | null { + + private static ReturnDefaultValueFunction( + defVal: string | null + ): string | null { if (!defVal) { return null; } diff --git a/src/index.ts b/src/index.ts index 1361a20..6bd2858 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,13 +1,15 @@ +import * as Yargs from "yargs"; +import { createDriver, createModelFromDatabase } from "./Engine"; +import * as TomgUtils from "./Utils"; +import AbstractDriver from "./drivers/AbstractDriver"; +import IConnectionOptions from "./IConnectionOptions"; +import IGenerationOptions from "./IGenerationOptions"; + import fs = require("fs-extra"); import inquirer = require("inquirer"); import path = require("path"); -import * as Yargs from "yargs"; -import { AbstractDriver } from "./drivers/AbstractDriver"; -import { createDriver, createModelFromDatabase } from "./Engine"; -import { IConnectionOptions } from "./IConnectionOptions"; -import { IGenerationOptions } from "./IGenerationOptions"; -import * as TomgUtils from "./Utils"; +// eslint-disable-next-line @typescript-eslint/no-floating-promises CliLogic(); async function CliLogic() { @@ -20,41 +22,35 @@ async function CliLogic() { connectionOptions = retVal.connectionOptions; generationOptions = retVal.generationOptions; driver = retVal.driver; + } else if (fs.existsSync(path.resolve(process.cwd(), ".tomg-config"))) { + console.log( + `[${new Date().toLocaleTimeString()}] Using configuration file. [${path.resolve( + process.cwd(), + ".tomg-config" + )}]` + ); + const retVal = await fs.readJson( + path.resolve(process.cwd(), ".tomg-config") + ); + [connectionOptions, generationOptions] = retVal; + driver = createDriver(connectionOptions.databaseType); } else { - if (fs.existsSync(path.resolve(process.cwd(), ".tomg-config"))) { - console.log( - `[${new Date().toLocaleTimeString()}] Using configuration file. [${path.resolve( - process.cwd(), - ".tomg-config" - )}]` - ); - const retVal = await fs.readJson( - path.resolve(process.cwd(), ".tomg-config") - ); - connectionOptions = retVal[0]; - generationOptions = retVal[1]; - driver = createDriver(connectionOptions.databaseType); - } else { - const retVal = await GetUtilParametersByInquirer(); - driver = retVal.driver; - connectionOptions = retVal.connectionOptions; - generationOptions = retVal.generationOptions; - } + const retVal = await GetUtilParametersByInquirer(); + driver = retVal.driver; + connectionOptions = retVal.connectionOptions; + generationOptions = retVal.generationOptions; } console.log( `[${new Date().toLocaleTimeString()}] Starting creation of model classes.` ); - createModelFromDatabase(driver, connectionOptions, generationOptions).then( - () => { - console.info( - `[${new Date().toLocaleTimeString()}] Typeorm model classes created.` - ); - } + await createModelFromDatabase(driver, connectionOptions, generationOptions); + console.info( + `[${new Date().toLocaleTimeString()}] Typeorm model classes created.` ); } function GetUtilParametersByArgs() { - const argv = Yargs.usage( + const { argv } = Yargs.usage( "Usage: typeorm-model-generator -h -d -p [port] -u -x [password] -e [engine]\nYou can also run program without specyfiying any parameters." ) .option("h", { @@ -165,43 +161,40 @@ function GetUtilParametersByArgs() { .option("timeout", { describe: "SQL Query timeout(ms)", number: true - }).argv; + }); const driver = createDriver(argv.e); - const standardPort = driver.standardPort; - const standardSchema = driver.standardSchema; + const { standardPort } = driver; + const { standardSchema } = driver; const standardUser = driver.standardPort; let namingStrategyPath: string; if (argv.namingStrategy && argv.namingStrategy !== "") { - // tslint:disable-next-line:no-var-requires namingStrategyPath = argv.namingStrategy; } else { namingStrategyPath = ""; } const connectionOptions: IConnectionOptions = new IConnectionOptions(); - (connectionOptions.databaseName = argv.d ? argv.d.toString() : null), - (connectionOptions.databaseType = argv.e), - (connectionOptions.host = argv.h), - (connectionOptions.password = argv.x ? argv.x.toString() : null), - (connectionOptions.port = parseInt(argv.p, 10) || standardPort), - (connectionOptions.schemaName = argv.s - ? argv.s.toString() - : standardSchema), - (connectionOptions.ssl = argv.ssl), - (connectionOptions.timeout = argv.timeout), - (connectionOptions.user = argv.u ? argv.u.toString() : standardUser); + connectionOptions.databaseName = argv.d ? argv.d.toString() : null; + connectionOptions.databaseType = argv.e; + connectionOptions.host = argv.h; + connectionOptions.password = argv.x ? argv.x.toString() : null; + connectionOptions.port = parseInt(argv.p, 10) || standardPort; + connectionOptions.schemaName = argv.s ? argv.s.toString() : standardSchema; + connectionOptions.ssl = argv.ssl; + connectionOptions.timeout = argv.timeout; + connectionOptions.user = argv.u ? argv.u.toString() : standardUser; const generationOptions: IGenerationOptions = new IGenerationOptions(); - (generationOptions.activeRecord = argv.a), - (generationOptions.generateConstructor = argv.generateConstructor), - (generationOptions.convertCaseEntity = argv.ce), - (generationOptions.convertCaseFile = argv.cf), - (generationOptions.convertCaseProperty = argv.cp), - (generationOptions.lazy = argv.lazy), - (generationOptions.customNamingStrategyPath = namingStrategyPath), - (generationOptions.noConfigs = argv.noConfig), - (generationOptions.propertyVisibility = argv.pv), - (generationOptions.relationIds = argv.relationIds), - (generationOptions.resultsPath = argv.o ? argv.o.toString() : null); + generationOptions.activeRecord = argv.a; + generationOptions.generateConstructor = argv.generateConstructor; + generationOptions.convertCaseEntity = argv.ce; + generationOptions.convertCaseFile = argv.cf; + generationOptions.convertCaseProperty = argv.cp; + generationOptions.lazy = argv.lazy; + generationOptions.customNamingStrategyPath = namingStrategyPath; + generationOptions.noConfigs = argv.noConfig; + generationOptions.propertyVisibility = argv.pv; + generationOptions.relationIds = argv.relationIds; + generationOptions.resultsPath = argv.o ? argv.o.toString() : null; return { driver, connectionOptions, generationOptions }; } @@ -238,11 +231,11 @@ async function GetUtilParametersByInquirer() { message: "Database port:", name: "port", type: "input", - default(answers: any) { + default() { return driver.standardPort; }, validate(value) { - const valid = !isNaN(parseInt(value, 10)); + const valid = !Number.isNaN(parseInt(value, 10)); return valid || "Please enter a valid port number"; } }, @@ -256,7 +249,7 @@ async function GetUtilParametersByInquirer() { message: "Database user name:", name: "login", type: "input", - default(answers: any) { + default() { return driver.standardUser; } }, @@ -316,35 +309,35 @@ async function GetUtilParametersByInquirer() { connectionOptions.databaseType === "mssql" || connectionOptions.databaseType === "postgres" ) { - const changeRequestTimeout = ((await inquirer.prompt([ + const { changeRequestTimeout } = (await inquirer.prompt([ { default: false, message: "Do you want to change default sql query timeout?", name: "changeRequestTimeout", type: "confirm" } - ])) as any).changeRequestTimeout; + ])) as any; if (changeRequestTimeout) { - const timeout: any = ((await inquirer.prompt({ + const { timeout } = (await inquirer.prompt({ message: "Query timeout(ms):", name: "timeout", type: "input", validate(value) { - const valid = !isNaN(parseInt(value, 10)); + const valid = !Number.isNaN(parseInt(value, 10)); return valid || "Please enter a valid number"; } - })) as any).timeout; + })) as any; connectionOptions.timeout = timeout; } } - const customizeGeneration = ((await inquirer.prompt([ + const { customizeGeneration } = (await inquirer.prompt([ { default: false, message: "Do you want to customize generated model?", name: "customizeGeneration", type: "confirm" } - ])) as any).customizeGeneration; + ])) as any; if (customizeGeneration) { const customizations: string[] = ((await inquirer.prompt([ { @@ -413,7 +406,6 @@ async function GetUtilParametersByInquirer() { ])) as any).namingStrategy; if (namingStrategyPath && namingStrategyPath !== "") { - // tslint:disable-next-line:no-var-requires generationOptions.customNamingStrategyPath = namingStrategyPath; } else { generationOptions.customNamingStrategyPath = ""; @@ -449,14 +441,14 @@ async function GetUtilParametersByInquirer() { generationOptions.convertCaseEntity = namingConventions.entityCase; } } - const saveConfig = ((await inquirer.prompt([ + const { saveConfig } = (await inquirer.prompt([ { default: false, message: "Save configuration to config file?", name: "saveConfig", type: "confirm" } - ])) as any).saveConfig; + ])) as any; if (saveConfig) { await fs.writeJson( path.resolve(process.cwd(), ".tomg-config"), diff --git a/src/models/ColumnInfo.ts b/src/models/ColumnInfo.ts index 6b7f167..28058cc 100644 --- a/src/models/ColumnInfo.ts +++ b/src/models/ColumnInfo.ts @@ -1,9 +1,11 @@ import { ColumnOptions } from "typeorm"; -import { RelationInfo } from "./RelationInfo"; +import RelationInfo from "./RelationInfo"; -export class ColumnInfo { +export default class ColumnInfo { public options: ColumnOptions = {}; + public tsName: string = ""; + public tsType: | "number" | "string" @@ -14,5 +16,6 @@ export class ColumnInfo { | "string | object" | "string | string[]" | "any"; + public relations: RelationInfo[] = []; } diff --git a/src/models/EntityInfo.ts b/src/models/EntityInfo.ts index 50592bc..cdcd06c 100644 --- a/src/models/EntityInfo.ts +++ b/src/models/EntityInfo.ts @@ -1,16 +1,25 @@ -import { ColumnInfo } from "./ColumnInfo"; -import { IndexInfo } from "./IndexInfo"; +import ColumnInfo from "./ColumnInfo"; +import IndexInfo from "./IndexInfo"; -export class EntityInfo { +export default class EntityInfo { public tsEntityName: string; + public sqlEntityName: string; + public Columns: ColumnInfo[]; + public Imports: string[]; + public UniqueImports: string[]; + public Indexes: IndexInfo[]; + public Schema: string; + public GenerateConstructor: boolean; + public IsActiveRecord: boolean; + public Database: string; public relationImports() { diff --git a/src/models/IndexColumnInfo.ts b/src/models/IndexColumnInfo.ts index d04e3a6..f4fa605 100644 --- a/src/models/IndexColumnInfo.ts +++ b/src/models/IndexColumnInfo.ts @@ -1,3 +1,3 @@ -export interface IndexColumnInfo { +export default interface IndexColumnInfo { name: string; } diff --git a/src/models/IndexInfo.ts b/src/models/IndexInfo.ts index 0f557f8..ac94f15 100644 --- a/src/models/IndexInfo.ts +++ b/src/models/IndexInfo.ts @@ -1,6 +1,6 @@ -import { IndexColumnInfo } from "./IndexColumnInfo"; +import IndexColumnInfo from "./IndexColumnInfo"; -export interface IndexInfo { +export default interface IndexInfo { name: string; columns: IndexColumnInfo[]; isUnique: boolean; diff --git a/src/models/RelationInfo.ts b/src/models/RelationInfo.ts index 6dd8b3c..efaa10e 100644 --- a/src/models/RelationInfo.ts +++ b/src/models/RelationInfo.ts @@ -1,10 +1,16 @@ -export class RelationInfo { +export default class RelationInfo { public isOwner: boolean; + public relationType: "OneToOne" | "OneToMany" | "ManyToOne" | "ManyToMany"; + public relatedTable: string; + public relatedColumn: string; + public ownerTable: string; + public ownerColumn: string; + public actionOnDelete: | "RESTRICT" | "CASCADE" @@ -12,24 +18,29 @@ export class RelationInfo { | "DEFAULT" | "NO ACTION" | null; + public actionOnUpdate: | "RESTRICT" | "CASCADE" | "SET NULL" | "DEFAULT" | null; + public relationIdField: boolean = false; - get isOneToMany(): boolean { + public get isOneToMany(): boolean { return this.relationType === "OneToMany"; } - get isManyToMany(): boolean { + + public get isManyToMany(): boolean { return this.relationType === "ManyToMany"; } - get isOneToOne(): boolean { + + public get isOneToOne(): boolean { return this.relationType === "OneToOne"; } - get isManyToOne(): boolean { + + public get isManyToOne(): boolean { return this.relationType === "ManyToOne"; } } diff --git a/src/models/RelationTempInfo.ts b/src/models/RelationTempInfo.ts index 7ac64bb..f6914f8 100644 --- a/src/models/RelationTempInfo.ts +++ b/src/models/RelationTempInfo.ts @@ -1,4 +1,4 @@ -export interface IRelationTempInfo { +export default interface RelationTempInfo { ownerTable: string; ownerColumnsNames: string[]; referencedTable: string; @@ -11,5 +11,5 @@ export interface IRelationTempInfo { | "NO ACTION" | null; actionOnUpdate: "RESTRICT" | "CASCADE" | "SET NULL" | "DEFAULT" | null; - object_id: number | string; + objectId: number | string; } diff --git a/src/tslint.json b/src/tslint.json deleted file mode 100644 index bd2c46b..0000000 --- a/src/tslint.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "defaultSeverity": "error", - "extends": [ - "tslint:recommended", "tslint-config-prettier" - ], - "jsRules": {}, - "rules": { - "no-console":false - }, - "rulesDirectory": [] -} diff --git a/test/drivers/MssqlDriver.test.ts b/test/drivers/MssqlDriver.test.ts index 030e1a8..c9b3640 100644 --- a/test/drivers/MssqlDriver.test.ts +++ b/test/drivers/MssqlDriver.test.ts @@ -1,105 +1,112 @@ import { expect } from "chai"; -import * as MSSQL from 'mssql' +import * as MSSQL from "mssql"; import { IColumnMetadata, Table } from "mssql"; -import * as Sinon from 'sinon' -import { MssqlDriver } from '../../src/drivers/MssqlDriver' -import { ColumnInfo } from '../../src/models/ColumnInfo' -import { EntityInfo } from '../../src/models/EntityInfo' -import { RelationInfo } from '../../src/models/RelationInfo' -import { NamingStrategy } from "../../src/NamingStrategy"; -import { IndexInfo } from "../../src/models/IndexInfo"; +import * as Sinon from "sinon"; +import MssqlDriver from "../../src/drivers/MssqlDriver"; +import EntityInfo from "../../src/models/EntityInfo"; +import ColumnInfo from "../../src/models/ColumnInfo"; +import IndexInfo from "../../src/models/IndexInfo"; +import RelationInfo from "../../src/models/RelationInfo"; -class fakeResponse implements MSSQL.IResult { +class fakeResponse implements MSSQL.IResult { public recordsets: Array>; public recordset: MSSQL.IRecordSet; public rowsAffected: number[]; - public output: { [key: string]: any; }; + public output: { [key: string]: any }; } -class fakeRecordset extends Array implements MSSQL.IRecordSet{ +class fakeRecordset extends Array implements MSSQL.IRecordSet { public columns: IColumnMetadata; public toTable(): Table { return new Table(); } } -describe('MssqlDriver', function () { - let driver: MssqlDriver - const sandbox = Sinon.sandbox.create() +describe("MssqlDriver", function() { + let driver: MssqlDriver; + const sandbox = Sinon.sandbox.create(); beforeEach(() => { driver = new MssqlDriver(); - }) + }); afterEach(() => { - sandbox.restore() - }) + sandbox.restore(); + }); - it('should get tables info', async () => { - sandbox.stub(MSSQL, 'Request') - .returns( - { - query: (q) => { - const response = new fakeResponse(); - response.recordset = new fakeRecordset(); - response.recordset.push({ TABLE_SCHEMA: 'schema', TABLE_NAME: 'name' }) - return response; - } - }) - const result = await driver.GetAllTables('schema', 'db') + it("should get tables info", async () => { + sandbox.stub(MSSQL, "Request").returns({ + query: q => { + const response = new fakeResponse(); + response.recordset = new fakeRecordset(); + response.recordset.push({ + TABLE_SCHEMA: "schema", + TABLE_NAME: "name" + }); + return response; + } + }); + const result = await driver.GetAllTables("schema", "db"); const expectedResult = [] as EntityInfo[]; const y = new EntityInfo(); - y.tsEntityName = 'name' - y.sqlEntityName = 'name' - y.Schema='schema' + y.tsEntityName = "name"; + y.sqlEntityName = "name"; + y.Schema = "schema"; y.Columns = [] as ColumnInfo[]; y.Indexes = [] as IndexInfo[]; y.Database = ""; - expectedResult.push(y) - expect(result).to.be.deep.equal(expectedResult) - }) - it('should get columns info', async () => { - sandbox.stub(MSSQL, 'Request') - .returns( - { - query: (q) => { - const response = new fakeResponse(); - response.recordset = new fakeRecordset(); - response.recordset.push({ - TABLE_NAME: 'name', CHARACTER_MAXIMUM_LENGTH: 0, - COLUMN_DEFAULT: "'a'", COLUMN_NAME: 'name', DATA_TYPE: 'int', - IS_NULLABLE: 'YES', NUMERIC_PRECISION: 0, NUMERIC_SCALE: 0, - IsIdentity: 1 - }) - return response; - } - }) + expectedResult.push(y); + expect(result).to.be.deep.equal(expectedResult); + }); + it("should get columns info", async () => { + sandbox.stub(MSSQL, "Request").returns({ + query: q => { + const response = new fakeResponse(); + response.recordset = new fakeRecordset(); + response.recordset.push({ + TABLE_NAME: "name", + CHARACTER_MAXIMUM_LENGTH: 0, + COLUMN_DEFAULT: "'a'", + COLUMN_NAME: "name", + DATA_TYPE: "int", + IS_NULLABLE: "YES", + NUMERIC_PRECISION: 0, + NUMERIC_SCALE: 0, + IsIdentity: 1 + }); + return response; + } + }); const entities = [] as EntityInfo[]; const y = new EntityInfo(); - y.tsEntityName = 'name' + y.tsEntityName = "name"; y.Columns = [] as ColumnInfo[]; y.Indexes = [] as IndexInfo[]; y.Database = ""; - entities.push(y) + entities.push(y); const expected: EntityInfo[] = JSON.parse(JSON.stringify(entities)); expected[0].Columns.push({ options: { default: `() => "'a'"`, nullable: true, generated: true, - name: 'name', - unique:false, - type: 'int', + name: "name", + unique: false, + type: "int" }, - tsName: 'name', - tsType: 'number', - relations: [] as RelationInfo[], - }) - const result = await driver.GetCoulmnsFromEntity(entities, 'schema','db'); - expect(result).to.be.deep.equal(expected) - }) - it('should find primary indexes') - it('should get indexes info') - it('should get relations info') -}) + tsName: "name", + tsType: "number", + relations: [] as RelationInfo[] + }); + const result = await driver.GetCoulmnsFromEntity( + entities, + "schema", + "db" + ); + expect(result).to.be.deep.equal(expected); + }); + it("should find primary indexes"); + it("should get indexes info"); + it("should get relations info"); +}); diff --git a/test/integration/runTestsFromPath.test.ts b/test/integration/runTestsFromPath.test.ts index 154733d..e6ca1af 100644 --- a/test/integration/runTestsFromPath.test.ts +++ b/test/integration/runTestsFromPath.test.ts @@ -1,53 +1,62 @@ -require('dotenv').config() +require("dotenv").config(); import "reflect-metadata"; import { expect } from "chai"; -import fs = require('fs-extra'); -import path = require('path'); +import fs = require("fs-extra"); +import path = require("path"); import { EntityFileToJson } from "../utils/EntityFileToJson"; -import { createDriver, createModelFromDatabase, dataCollectionPhase, modelCustomizationPhase, modelGenerationPhase } from "../../src/Engine"; +import { + createDriver, + createModelFromDatabase, + dataCollectionPhase, + modelCustomizationPhase, + modelGenerationPhase +} from "../../src/Engine"; import * as ts from "typescript"; -import * as GTU from "../utils/GeneralTestUtils" -import chaiSubset = require('chai-subset'); -import chai = require('chai'); -import { IConnectionOptions } from "../../src/IConnectionOptions"; +import * as GTU from "../utils/GeneralTestUtils"; +import chaiSubset = require("chai-subset"); +import chai = require("chai"); import yn = require("yn"); -import { EntityInfo } from "../../src/models/EntityInfo"; +import EntityInfo from "../../src/models/EntityInfo"; +import IConnectionOptions from "../../src/IConnectionOptions"; chai.use(chaiSubset); -it("Column default values", async function () { - const testPartialPath = 'test/integration/defaultValues' - this.timeout(60000) - this.slow(10000)// compiling created models takes time +it("Column default values", async function() { + const testPartialPath = "test/integration/defaultValues"; + this.timeout(60000); + this.slow(10000); // compiling created models takes time await runTestsFromPath(testPartialPath, true); -}) -it("Platform specyfic types", async function () { - this.timeout(60000) - this.slow(10000)// compiling created models takes time - const testPartialPath = 'test/integration/entityTypes' +}); +it("Platform specyfic types", async function() { + this.timeout(60000); + this.slow(10000); // compiling created models takes time + const testPartialPath = "test/integration/entityTypes"; await runTestsFromPath(testPartialPath, true); -}) -describe("GitHub issues", async function () { - this.timeout(60000) - this.slow(10000)// compiling created models takes time - const testPartialPath = 'test/integration/github-issues' +}); +describe("GitHub issues", async function() { + this.timeout(60000); + this.slow(10000); // compiling created models takes time + const testPartialPath = "test/integration/github-issues"; runTestsFromPath(testPartialPath, false); -}) -describe("TypeOrm examples", async function () { - this.timeout(60000) - this.slow(10000)// compiling created models takes time - const testPartialPath = 'test/integration/examples' +}); +describe("TypeOrm examples", async function() { + this.timeout(60000); + this.slow(10000); // compiling created models takes time + const testPartialPath = "test/integration/examples"; runTestsFromPath(testPartialPath, false); -}) +}); -export async function runTestsFromPath(testPartialPath: string, isDbSpecific: boolean) { - const resultsPath = path.resolve(process.cwd(), `output`) +export async function runTestsFromPath( + testPartialPath: string, + isDbSpecific: boolean +) { + const resultsPath = path.resolve(process.cwd(), `output`); if (!fs.existsSync(resultsPath)) { fs.mkdirSync(resultsPath); } const dbDrivers: string[] = GTU.getEnabledDbDrivers(); for (const dbDriver of dbDrivers) { - const newDirPath = path.resolve(resultsPath, dbDriver) + const newDirPath = path.resolve(resultsPath, dbDriver); if (!fs.existsSync(newDirPath)) { fs.mkdirSync(newDirPath); } @@ -61,69 +70,138 @@ export async function runTestsFromPath(testPartialPath: string, isDbSpecific: bo } } } -function runTestForMultipleDrivers(testName: string, dbDrivers: string[], testPartialPath: string) { - it(testName, async function () { +function runTestForMultipleDrivers( + testName: string, + dbDrivers: string[], + testPartialPath: string +) { + it(testName, async function() { const driversToRun = selectDriversForSpecyficTest(); - const modelGenerationPromises = driversToRun.map(async (dbDriver) => { - const { generationOptions, driver, connectionOptions, resultsPath, filesOrgPathTS } = await prepareTestRuns(testPartialPath, testName, dbDriver); + const modelGenerationPromises = driversToRun.map(async dbDriver => { + const { + generationOptions, + driver, + connectionOptions, + resultsPath, + filesOrgPathTS + } = await prepareTestRuns(testPartialPath, testName, dbDriver); let dbModel: EntityInfo[] = []; switch (testName) { - case '144': - dbModel = await dataCollectionPhase(driver, Object.assign(connectionOptions, { databaseName: 'db1,db2' })); + case "144": + dbModel = await dataCollectionPhase( + driver, + Object.assign(connectionOptions, { + databaseName: "db1,db2" + }) + ); break; default: - dbModel = await dataCollectionPhase(driver, connectionOptions); + dbModel = await dataCollectionPhase( + driver, + connectionOptions + ); break; } - dbModel = modelCustomizationPhase(dbModel, generationOptions, driver.defaultValues); + dbModel = modelCustomizationPhase( + dbModel, + generationOptions, + driver.defaultValues + ); modelGenerationPhase(connectionOptions, generationOptions, dbModel); - const filesGenPath = path.resolve(resultsPath, 'entities'); + const filesGenPath = path.resolve(resultsPath, "entities"); compareGeneratedFiles(filesOrgPathTS, filesGenPath); - return { dbModel, generationOptions, connectionOptions, resultsPath, filesOrgPathTS, dbDriver }; - }) - await Promise.all(modelGenerationPromises) + return { + dbModel, + generationOptions, + connectionOptions, + resultsPath, + filesOrgPathTS, + dbDriver + }; + }); + await Promise.all(modelGenerationPromises); compileGeneratedModel(path.resolve(process.cwd(), `output`), dbDrivers); }); function selectDriversForSpecyficTest() { switch (testName) { - case '39': - return dbDrivers.filter(dbDriver => !['mysql', 'mariadb', 'oracle', 'sqlite'].includes(dbDriver)) - case '144': - return dbDrivers.filter(dbDriver => ['mysql', 'mariadb'].includes(dbDriver)) + case "39": + return dbDrivers.filter( + dbDriver => + !["mysql", "mariadb", "oracle", "sqlite"].includes( + dbDriver + ) + ); + case "144": + return dbDrivers.filter(dbDriver => + ["mysql", "mariadb"].includes(dbDriver) + ); default: return dbDrivers; } } } -async function runTest(dbDrivers: string[], testPartialPath: string, files: string[]) { - - const modelGenerationPromises = dbDrivers.filter(driver => files.includes(driver)) +async function runTest( + dbDrivers: string[], + testPartialPath: string, + files: string[] +) { + const modelGenerationPromises = dbDrivers + .filter(driver => files.includes(driver)) .map(async dbDriver => { - const { generationOptions, driver, connectionOptions, resultsPath, filesOrgPathTS } = await prepareTestRuns(testPartialPath, dbDriver, dbDriver); + const { + generationOptions, + driver, + connectionOptions, + resultsPath, + filesOrgPathTS + } = await prepareTestRuns(testPartialPath, dbDriver, dbDriver); let dbModel = await dataCollectionPhase(driver, connectionOptions); - dbModel = modelCustomizationPhase(dbModel, generationOptions, driver.defaultValues); + dbModel = modelCustomizationPhase( + dbModel, + generationOptions, + driver.defaultValues + ); modelGenerationPhase(connectionOptions, generationOptions, dbModel); - const filesGenPath = path.resolve(resultsPath, 'entities'); + const filesGenPath = path.resolve(resultsPath, "entities"); compareGeneratedFiles(filesOrgPathTS, filesGenPath); - return { dbModel, generationOptions, connectionOptions, resultsPath, filesOrgPathTS, dbDriver }; - }) - await Promise.all(modelGenerationPromises) + return { + dbModel, + generationOptions, + connectionOptions, + resultsPath, + filesOrgPathTS, + dbDriver + }; + }); + await Promise.all(modelGenerationPromises); compileGeneratedModel(path.resolve(process.cwd(), `output`), dbDrivers); } function compareGeneratedFiles(filesOrgPathTS: string, filesGenPath: string) { - const filesOrg = fs.readdirSync(filesOrgPathTS).filter((val) => val.toString().endsWith('.ts')); - const filesGen = fs.readdirSync(filesGenPath).filter((val) => val.toString().endsWith('.ts')); - expect(filesOrg, 'Errors detected in model comparision').to.be.deep.equal(filesGen); + const filesOrg = fs + .readdirSync(filesOrgPathTS) + .filter(val => val.toString().endsWith(".ts")); + const filesGen = fs + .readdirSync(filesGenPath) + .filter(val => val.toString().endsWith(".ts")); + expect(filesOrg, "Errors detected in model comparision").to.be.deep.equal( + filesGen + ); for (const file of filesOrg) { const entftj = new EntityFileToJson(); - const jsonEntityOrg = entftj.convert(fs.readFileSync(path.resolve(filesOrgPathTS, file))); - const jsonEntityGen = entftj.convert(fs.readFileSync(path.resolve(filesGenPath, file))); - expect(jsonEntityGen, `Error in file ${file}`).to.containSubset(jsonEntityOrg); + const jsonEntityOrg = entftj.convert( + fs.readFileSync(path.resolve(filesOrgPathTS, file)) + ); + const jsonEntityGen = entftj.convert( + fs.readFileSync(path.resolve(filesGenPath, file)) + ); + expect(jsonEntityGen, `Error in file ${file}`).to.containSubset( + jsonEntityOrg + ); } } @@ -131,9 +209,17 @@ function compileGeneratedModel(filesGenPath: string, drivers: string[]) { let currentDirectoryFiles: string[] = []; drivers.forEach(driver => { const entitiesPath = path.resolve(filesGenPath, driver, "entities"); - if (fs.existsSync(entitiesPath)){ - currentDirectoryFiles.push(...fs.readdirSync(entitiesPath). - filter(fileName => fileName.length >= 3 && fileName.substr(fileName.length - 3, 3) === ".ts").map(v => path.resolve(filesGenPath, driver, "entities", v))); + if (fs.existsSync(entitiesPath)) { + currentDirectoryFiles.push( + ...fs + .readdirSync(entitiesPath) + .filter( + fileName => + fileName.length >= 3 && + fileName.substr(fileName.length - 3, 3) === ".ts" + ) + .map(v => path.resolve(filesGenPath, driver, "entities", v)) + ); } }); const compileErrors = GTU.compileTsFiles(currentDirectoryFiles, { @@ -144,50 +230,64 @@ function compileGeneratedModel(filesGenPath: string, drivers: string[]) { moduleResolution: ts.ModuleResolutionKind.NodeJs, module: ts.ModuleKind.CommonJS }); - expect(compileErrors, 'Errors detected while compiling generated model').to.be.false; + expect(compileErrors, "Errors detected while compiling generated model").to + .be.false; } -async function prepareTestRuns(testPartialPath: string, testName: string, dbDriver: string) { - const filesOrgPathJS = path.resolve(process.cwd(), testPartialPath, testName, 'entity'); - const filesOrgPathTS = path.resolve(process.cwd(), testPartialPath, testName, 'entity'); +async function prepareTestRuns( + testPartialPath: string, + testName: string, + dbDriver: string +) { + const filesOrgPathJS = path.resolve( + process.cwd(), + testPartialPath, + testName, + "entity" + ); + const filesOrgPathTS = path.resolve( + process.cwd(), + testPartialPath, + testName, + "entity" + ); const resultsPath = path.resolve(process.cwd(), `output`, dbDriver); fs.removeSync(resultsPath); const driver = createDriver(dbDriver); const generationOptions = GTU.getGenerationOptions(resultsPath); switch (testName) { - case '65': + case "65": generationOptions.relationIds = true; break; - case 'sample18-lazy-relations': + case "sample18-lazy-relations": generationOptions.lazy = true; break; - case '144': - + case "144": let connectionOptions: IConnectionOptions; switch (dbDriver) { - case 'mysql': + case "mysql": connectionOptions = { host: String(process.env.MYSQL_Host), port: Number(process.env.MYSQL_Port), databaseName: String(process.env.MYSQL_Database), user: String(process.env.MYSQL_Username), password: String(process.env.MYSQL_Password), - databaseType: 'mysql', - schemaName: 'ignored', - ssl: yn(process.env.MYSQL_SSL), - } + databaseType: "mysql", + schemaName: "ignored", + ssl: yn(process.env.MYSQL_SSL) + }; break; - case 'mariadb': + case "mariadb": connectionOptions = { host: String(process.env.MARIADB_Host), port: Number(process.env.MARIADB_Port), databaseName: String(process.env.MARIADB_Database), user: String(process.env.MARIADB_Username), password: String(process.env.MARIADB_Password), - databaseType: 'mariadb', - schemaName: 'ignored', - ssl: yn(process.env.MARIADB_SSL), - } + databaseType: "mariadb", + schemaName: "ignored", + ssl: yn(process.env.MARIADB_SSL) + }; break; default: @@ -195,18 +295,26 @@ async function prepareTestRuns(testPartialPath: string, testName: string, dbDriv } await driver.ConnectToServer(connectionOptions!); - if (! await driver.CheckIfDBExists('db1')) { - var x = await driver.CreateDB('db1') + if (!(await driver.CheckIfDBExists("db1"))) { + var x = await driver.CreateDB("db1"); } - if (! await driver.CheckIfDBExists('db2')) { - var t = await driver.CreateDB('db2') + if (!(await driver.CheckIfDBExists("db2"))) { + var t = await driver.CreateDB("db2"); } await driver.DisconnectFromServer(); break; default: break; } - const connectionOptions = await GTU.createModelsInDb(dbDriver, filesOrgPathJS); - return { generationOptions, driver, connectionOptions, resultsPath, filesOrgPathTS }; + const connectionOptions = await GTU.createModelsInDb( + dbDriver, + filesOrgPathJS + ); + return { + generationOptions, + driver, + connectionOptions, + resultsPath, + filesOrgPathTS + }; } - diff --git a/test/utils/GeneralTestUtils.ts b/test/utils/GeneralTestUtils.ts index b85b720..9ddc00e 100644 --- a/test/utils/GeneralTestUtils.ts +++ b/test/utils/GeneralTestUtils.ts @@ -1,35 +1,36 @@ -import path = require('path') +import path = require("path"); import { ConnectionOptions, createConnection } from "typeorm"; import * as ts from "typescript"; -import * as yn from "yn" -import { AbstractDriver } from "../../src/drivers/AbstractDriver"; -import { MariaDbDriver } from "../../src/drivers/MariaDbDriver"; -import { MssqlDriver } from "../../src/drivers/MssqlDriver"; -import { MysqlDriver } from "../../src/drivers/MysqlDriver"; -import { OracleDriver } from "../../src/drivers/OracleDriver"; -import { PostgresDriver } from "../../src/drivers/PostgresDriver"; -import { SqliteDriver } from "../../src/drivers/SqliteDriver"; -import { IConnectionOptions } from "../../src/IConnectionOptions"; -import { IGenerationOptions } from "../../src/IGenerationOptions"; +import * as yn from "yn"; +import IGenerationOptions from "../../src/IGenerationOptions"; +import IConnectionOptions from "../../src/IConnectionOptions"; +import AbstractDriver from "../../src/drivers/AbstractDriver"; +import MssqlDriver from "../../src/drivers/MssqlDriver"; +import MariaDbDriver from "../../src/drivers/MariaDbDriver"; +import PostgresDriver from "../../src/drivers/PostgresDriver"; +import SqliteDriver from "../../src/drivers/SqliteDriver"; +import OracleDriver from "../../src/drivers/OracleDriver"; +import MysqlDriver from "../../src/drivers/MysqlDriver"; export function getGenerationOptions(resultsPath: string): IGenerationOptions { return { resultsPath: resultsPath, noConfigs: false, - convertCaseEntity: 'none', - convertCaseFile: 'none', - convertCaseProperty: 'none', - propertyVisibility: 'none', + convertCaseEntity: "none", + convertCaseFile: "none", + convertCaseProperty: "none", + propertyVisibility: "none", lazy: false, generateConstructor: false, customNamingStrategyPath: "", relationIds: false, activeRecord: false - } + }; } -export async function createMSSQLModels(filesOrgPath: string): Promise { - +export async function createMSSQLModels( + filesOrgPath: string +): Promise { let driver: AbstractDriver; driver = new MssqlDriver(); const connectionOptions: IConnectionOptions = { @@ -38,10 +39,10 @@ export async function createMSSQLModels(filesOrgPath: string): Promise { +export async function createPostgresModels( + filesOrgPath: string +): Promise { let driver: AbstractDriver; driver = new PostgresDriver(); const connectionOptions: IConnectionOptions = { @@ -88,10 +91,10 @@ export async function createPostgresModels(filesOrgPath: string): Promise { +export async function createSQLiteModels( + filesOrgPath: string +): Promise { let driver: AbstractDriver; driver = new SqliteDriver(); const connectionOptions: IConnectionOptions = { - host: '', + host: "", port: 0, databaseName: String(process.env.SQLITE_Database), - user: '', - password: '', - databaseType: 'sqlite', - schemaName: '', - ssl: false, - } + user: "", + password: "", + databaseType: "sqlite", + schemaName: "", + ssl: false + }; await driver.ConnectToServer(connectionOptions); if (await driver.CheckIfDBExists(String(process.env.SQLITE_Database))) { @@ -152,24 +157,26 @@ export async function createSQLiteModels(filesOrgPath: string): Promise { +export async function createMysqlModels( + filesOrgPath: string +): Promise { let driver: AbstractDriver; driver = new MysqlDriver(); const connectionOptions: IConnectionOptions = { @@ -178,10 +185,10 @@ export async function createMysqlModels(filesOrgPath: string): Promise { +export async function createMariaDBModels( + filesOrgPath: string +): Promise { let driver: AbstractDriver; driver = new MariaDbDriver(); const connectionOptions: IConnectionOptions = { @@ -219,10 +228,10 @@ export async function createMariaDBModels(filesOrgPath: string): Promise { +export async function createOracleDBModels( + filesOrgPath: string +): Promise { let driver: AbstractDriver; driver = new OracleDriver(); @@ -262,13 +273,13 @@ export async function createOracleDBModels(filesOrgPath: string): Promise { - const lineAndCharacter = diagnostic.file!.getLineAndCharacterOfPosition(diagnostic.start!); - const message = ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n'); - console.log(`${diagnostic.file!.fileName} (${lineAndCharacter.line + 1},${lineAndCharacter.character + 1}): ${message}`); + const lineAndCharacter = diagnostic.file!.getLineAndCharacterOfPosition( + diagnostic.start! + ); + const message = ts.flattenDiagnosticMessageText( + diagnostic.messageText, + "\n" + ); + console.log( + `${diagnostic.file!.fileName} (${lineAndCharacter.line + + 1},${lineAndCharacter.character + 1}): ${message}` + ); compileErrors = true; }); @@ -317,40 +339,43 @@ export function compileTsFiles(fileNames: string[], options: ts.CompilerOptions) export function getEnabledDbDrivers() { const dbDrivers: string[] = []; - if (process.env.SQLITE_Skip == '0') { - dbDrivers.push('sqlite'); + if (process.env.SQLITE_Skip == "0") { + dbDrivers.push("sqlite"); } - if (process.env.POSTGRES_Skip == '0') { - dbDrivers.push('postgres'); + if (process.env.POSTGRES_Skip == "0") { + dbDrivers.push("postgres"); } - if (process.env.MYSQL_Skip == '0') { - dbDrivers.push('mysql'); + if (process.env.MYSQL_Skip == "0") { + dbDrivers.push("mysql"); } - if (process.env.MARIADB_Skip == '0') { - dbDrivers.push('mariadb'); + if (process.env.MARIADB_Skip == "0") { + dbDrivers.push("mariadb"); } - if (process.env.MSSQL_Skip == '0') { - dbDrivers.push('mssql'); + if (process.env.MSSQL_Skip == "0") { + dbDrivers.push("mssql"); } - if (process.env.ORACLE_Skip == '0') { - dbDrivers.push('oracle'); + if (process.env.ORACLE_Skip == "0") { + dbDrivers.push("oracle"); } return dbDrivers; } -export function createModelsInDb(dbDriver: string, filesOrgPathJS: string): Promise { +export function createModelsInDb( + dbDriver: string, + filesOrgPathJS: string +): Promise { switch (dbDriver) { - case 'sqlite': + case "sqlite": return createSQLiteModels(filesOrgPathJS); - case 'postgres': + case "postgres": return createPostgresModels(filesOrgPathJS); - case 'mysql': + case "mysql": return createMysqlModels(filesOrgPathJS); - case 'mariadb': + case "mariadb": return createMariaDBModels(filesOrgPathJS); - case 'mssql': + case "mssql": return createMSSQLModels(filesOrgPathJS); - case 'oracle': + case "oracle": return createOracleDBModels(filesOrgPathJS); default: console.log(`Unknown engine type`);