diff --git a/.eslintrc b/.eslintrc index 1e7268f..2874b03 100644 --- a/.eslintrc +++ b/.eslintrc @@ -13,6 +13,7 @@ "beforeEach": false, "beforeAll": false, "after": false, + "afterEach": false, "afterAll": false, "expect": false, "expectAsync": false, diff --git a/.gitpod.yml b/.gitpod.yml new file mode 100644 index 0000000..9a09b21 --- /dev/null +++ b/.gitpod.yml @@ -0,0 +1,8 @@ +# This configuration file was automatically generated by Gitpod. +# Please adjust to your needs (see https://www.gitpod.io/docs/config-gitpod-file) +# and commit this file to your remote git repository to share the goodness with others. + +tasks: + - init: npm install && npm run build + + diff --git a/package-lock.json b/package-lock.json index d8adbaf..862170b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@themost/mssql", - "version": "2.6.1", + "version": "2.6.2", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -1478,6 +1478,13 @@ } } }, + "@gar/promisify": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", + "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==", + "dev": true, + "optional": true + }, "@humanwhocodes/config-array": { "version": "0.9.5", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.5.tgz", @@ -1522,6 +1529,85 @@ "resolved": "https://registry.npmjs.org/@js-joda/core/-/core-4.3.1.tgz", "integrity": "sha512-oeaetlodcqVsiZDxnEcqsbs+sXBkASxua0mXs5OXuPQXz3/wdPTMlxwfQ4z2HKcOik3S9voW3QJkp/KLWDhvRQ==" }, + "@mapbox/node-pre-gyp": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.9.tgz", + "integrity": "sha512-aDF3S3rK9Q2gey/WAttUlISduDItz5BU3306M9Eyv6/oS40aMprnopshtlKTykxRNIBEZuRMaZAnbrQ4QtKGyw==", + "dev": true, + "requires": { + "detect-libc": "^2.0.0", + "https-proxy-agent": "^5.0.0", + "make-dir": "^3.1.0", + "node-fetch": "^2.6.7", + "nopt": "^5.0.0", + "npmlog": "^5.0.1", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.11" + }, + "dependencies": { + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "requires": { + "semver": "^6.0.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, + "@npmcli/fs": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-1.1.1.tgz", + "integrity": "sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ==", + "dev": true, + "optional": true, + "requires": { + "@gar/promisify": "^1.0.1", + "semver": "^7.3.5" + }, + "dependencies": { + "semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dev": true, + "optional": true, + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, + "@npmcli/move-file": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.1.2.tgz", + "integrity": "sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==", + "dev": true, + "optional": true, + "requires": { + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" + } + }, "@opentelemetry/api": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.0.4.tgz", @@ -1612,6 +1698,28 @@ } } }, + "@themost/sqlite": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/@themost/sqlite/-/sqlite-2.6.4.tgz", + "integrity": "sha512-krrQ6/YgVi5cj69/egCvukkFzx795lOxekmQ7eVjn4KIwq8ma5a1MMBC2jTS8HFnkX6AmdU9burDnWSOa7DyfA==", + "dev": true, + "requires": { + "async": "^2.6.4", + "package-lock-only": "^0.0.4", + "sqlite3": "^5.0.7" + }, + "dependencies": { + "async": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", + "dev": true, + "requires": { + "lodash": "^4.17.14" + } + } + } + }, "@themost/xml": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/@themost/xml/-/xml-2.5.2.tgz", @@ -1695,6 +1803,12 @@ "@types/node": "*" } }, + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true + }, "agent-base": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", @@ -1703,6 +1817,51 @@ "debug": "4" } }, + "agentkeepalive": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.2.1.tgz", + "integrity": "sha512-Zn4cw2NEqd+9fiSVWMscnjyQ1a8Yfoc5oBajLeo5w+YBHgDUcEBY2hS4YpTz6iN5f/2zQiktcuM6tS8x1p9dpA==", + "dev": true, + "optional": true, + "requires": { + "debug": "^4.1.0", + "depd": "^1.1.2", + "humanize-ms": "^1.2.1" + } + }, + "aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "optional": true, + "requires": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + } + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "aproba": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", + "dev": true + }, + "are-we-there-yet": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", + "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", + "dev": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + } + }, "async": { "version": "3.2.3", "resolved": "https://registry.npmjs.org/async/-/async-3.2.3.tgz", @@ -1787,18 +1946,6 @@ "buffer": "^6.0.3", "inherits": "^2.0.4", "readable-stream": "^3.4.0" - }, - "dependencies": { - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - } } }, "brace-expansion": { @@ -1844,6 +1991,33 @@ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "dev": true }, + "cacache": { + "version": "15.3.0", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-15.3.0.tgz", + "integrity": "sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==", + "dev": true, + "optional": true, + "requires": { + "@npmcli/fs": "^1.0.0", + "@npmcli/move-file": "^1.0.1", + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "glob": "^7.1.4", + "infer-owner": "^1.0.4", + "lru-cache": "^6.0.0", + "minipass": "^3.1.1", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.2", + "mkdirp": "^1.0.3", + "p-map": "^4.0.0", + "promise-inflight": "^1.0.1", + "rimraf": "^3.0.2", + "ssri": "^8.0.1", + "tar": "^6.0.2", + "unique-filename": "^1.1.1" + } + }, "call-bind": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", @@ -1891,6 +2065,19 @@ } } }, + "chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "dev": true + }, + "clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true, + "optional": true + }, "clone-deep": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", @@ -1917,6 +2104,12 @@ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", "dev": true }, + "color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "dev": true + }, "colors": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", @@ -1948,6 +2141,12 @@ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true }, + "console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", + "dev": true + }, "convert-source-map": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", @@ -2017,6 +2216,25 @@ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" }, + "delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", + "dev": true + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "dev": true, + "optional": true + }, + "detect-libc": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz", + "integrity": "sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==", + "dev": true + }, "dotenv": { "version": "8.2.0", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz", @@ -2037,6 +2255,36 @@ "integrity": "sha512-VuLNxTIt8sBWIT2sd186xPd18Y8KcK8myLd9nMdSJOYZwFUxxbLVmX/T1VX+qqaytRlrYYQv39myxJdXtu7Ysw==", "dev": true }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "dev": true, + "optional": true, + "requires": { + "iconv-lite": "^0.6.2" + } + }, + "env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, + "optional": true + }, + "err-code": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", + "dev": true, + "optional": true + }, "escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", @@ -2116,12 +2364,6 @@ "uri-js": "^4.2.2" } }, - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true - }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -2342,15 +2584,6 @@ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true }, - "strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.1" - } - }, "strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -2374,15 +2607,6 @@ "requires": { "prelude-ls": "^1.2.1" } - }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } } } }, @@ -2513,6 +2737,15 @@ "mime-types": "^2.1.12" } }, + "fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + } + }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -2538,6 +2771,23 @@ "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", "dev": true }, + "gauge": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", + "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", + "dev": true, + "requires": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.2", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.1", + "object-assign": "^4.1.1", + "signal-exit": "^3.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.2" + } + }, "gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -2584,6 +2834,13 @@ "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", "dev": true }, + "graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "dev": true, + "optional": true + }, "has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", @@ -2614,6 +2871,19 @@ "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", "dev": true }, + "has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", + "dev": true + }, + "http-cache-semantics": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", + "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", + "dev": true, + "optional": true + }, "http-proxy-agent": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", @@ -2633,6 +2903,24 @@ "debug": "4" } }, + "humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha1-xG4xWaKT9riW2ikxbYtv6Lt5u+0=", + "dev": true, + "optional": true, + "requires": { + "ms": "^2.0.0" + } + }, + "iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + }, "ieee754": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", @@ -2662,6 +2950,20 @@ "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", "dev": true }, + "indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "optional": true + }, + "infer-owner": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", + "dev": true, + "optional": true + }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -2677,6 +2979,13 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, + "ip": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.8.tgz", + "integrity": "sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg==", + "dev": true, + "optional": true + }, "is-core-module": { "version": "2.9.0", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz", @@ -2697,6 +3006,12 @@ "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", "dev": true }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, "is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -2706,6 +3021,13 @@ "is-extglob": "^2.1.1" } }, + "is-lambda": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", + "integrity": "sha1-PZh3iZ5qU+/AFgUEzeFfgubwYdU=", + "dev": true, + "optional": true + }, "is-plain-object": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", @@ -2918,6 +3240,15 @@ "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, "magic-string": { "version": "0.26.1", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.26.1.tgz", @@ -2937,6 +3268,31 @@ "semver": "^5.6.0" } }, + "make-fetch-happen": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz", + "integrity": "sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg==", + "dev": true, + "optional": true, + "requires": { + "agentkeepalive": "^4.1.3", + "cacache": "^15.2.0", + "http-cache-semantics": "^4.1.0", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^6.0.0", + "minipass": "^3.1.3", + "minipass-collect": "^1.0.2", + "minipass-fetch": "^1.3.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.2", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^6.0.0", + "ssri": "^8.0.0" + } + }, "mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", @@ -2959,6 +3315,84 @@ "brace-expansion": "^1.1.7" } }, + "minipass": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.6.tgz", + "integrity": "sha512-rty5kpw9/z8SX9dmxblFA6edItUmwJgMeYDZRrwlIVN27i8gysGbznJwUggw2V/FVqFSDdWy040ZPS811DYAqQ==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "minipass-collect": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", + "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", + "dev": true, + "optional": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "minipass-fetch": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-1.4.1.tgz", + "integrity": "sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw==", + "dev": true, + "optional": true, + "requires": { + "encoding": "^0.1.12", + "minipass": "^3.1.0", + "minipass-sized": "^1.0.3", + "minizlib": "^2.0.0" + } + }, + "minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "dev": true, + "optional": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "dev": true, + "optional": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "minipass-sized": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", + "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", + "dev": true, + "optional": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dev": true, + "requires": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + } + }, + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true + }, "module-alias": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/module-alias/-/module-alias-2.2.2.tgz", @@ -3000,11 +3434,24 @@ "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", "dev": true }, + "negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true, + "optional": true + }, "node-abort-controller": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/node-abort-controller/-/node-abort-controller-3.0.1.tgz", "integrity": "sha512-/ujIVxthRs+7q6hsdjHMaj8hRG9NuWmwrz+JdRwZ14jdFoKSkm+vDsCbF9PLpnSqjaWQJuTmVtcWHNLr+vrOFw==" }, + "node-addon-api": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz", + "integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==", + "dev": true + }, "node-cache": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/node-cache/-/node-cache-1.1.0.tgz", @@ -3022,12 +3469,111 @@ "whatwg-url": "^5.0.0" } }, + "node-gyp": { + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-8.4.1.tgz", + "integrity": "sha512-olTJRgUtAb/hOXG0E93wZDs5YiJlgbXxTwQAFHyNlRsXQnYzUaF2aGgujZbw+hR8aF4ZG/rST57bWMWD16jr9w==", + "dev": true, + "optional": true, + "requires": { + "env-paths": "^2.2.0", + "glob": "^7.1.4", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^9.1.0", + "nopt": "^5.0.0", + "npmlog": "^6.0.0", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.2", + "which": "^2.0.2" + }, + "dependencies": { + "are-we-there-yet": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.0.tgz", + "integrity": "sha512-0GWpv50YSOcLXaN6/FAKY3vfRbllXWV2xvfA/oKJF8pzFhWXPV+yjhJXDBbjscDYowv7Yw1A3uigpzn5iEGTyw==", + "dev": true, + "optional": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + } + }, + "gauge": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", + "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", + "dev": true, + "optional": true, + "requires": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.3", + "console-control-strings": "^1.1.0", + "has-unicode": "^2.0.1", + "signal-exit": "^3.0.7", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.5" + } + }, + "npmlog": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", + "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", + "dev": true, + "optional": true, + "requires": { + "are-we-there-yet": "^3.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^4.0.3", + "set-blocking": "^2.0.0" + } + }, + "semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dev": true, + "optional": true, + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, "node-releases": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.3.tgz", "integrity": "sha512-maHFz6OLqYxz+VQyCAtA3PTX4UP/53pa05fyDNc9CwjvJ0yEh6+xBwKsgCxMNhS8taUKBFYxfuiaD9U/55iFaw==", "dev": true }, + "nopt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "dev": true, + "requires": { + "abbrev": "1" + } + }, + "npmlog": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", + "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", + "dev": true, + "requires": { + "are-we-there-yet": "^2.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^3.0.0", + "set-blocking": "^2.0.0" + } + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true + }, "object-keys": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", @@ -3083,12 +3629,31 @@ "p-limit": "^2.0.0" } }, + "p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "optional": true, + "requires": { + "aggregate-error": "^3.0.0" + } + }, "p-try": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "dev": true }, + "package-lock-only": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/package-lock-only/-/package-lock-only-0.0.4.tgz", + "integrity": "sha512-fV1YHeTMWH5LKmdVqfWskm2/SG0iF2IrxJn3ziaPVx9CnpecGJzt8xXtLV+CYINENZwPFMtbxO5qupz0asNz1A==", + "dev": true, + "requires": { + "chalk": "^2.4.1" + } + }, "parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -3174,6 +3739,24 @@ "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=" }, + "promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=", + "dev": true, + "optional": true + }, + "promise-retry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "dev": true, + "optional": true, + "requires": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + } + }, "psl": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", @@ -3190,6 +3773,16 @@ "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=", "dev": true }, + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, "regenerate": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", @@ -3268,6 +3861,13 @@ "supports-preserve-symlinks-flag": "^1.0.0" } }, + "retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=", + "dev": true, + "optional": true + }, "rfdc": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", @@ -3321,6 +3921,12 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true + }, "shallow-clone": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", @@ -3330,6 +3936,42 @@ "kind-of": "^6.0.2" } }, + "signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "dev": true, + "optional": true + }, + "socks": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.6.2.tgz", + "integrity": "sha512-zDZhHhZRY9PxRruRMR7kMhnf3I8hDs4S3f9RecfnGxvcBHQcKcIH/oUcEWffsfl1XxdYlA7nnlGbbTvPz9D8gA==", + "dev": true, + "optional": true, + "requires": { + "ip": "^1.1.5", + "smart-buffer": "^4.2.0" + } + }, + "socks-proxy-agent": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-6.2.0.tgz", + "integrity": "sha512-wWqJhjb32Q6GsrUqzuFkukxb/zzide5quXYcMVpIjxalDBBYy2nqKCFQ/9+Ie4dvOYSQdOk3hUlZSdzZOd3zMQ==", + "dev": true, + "optional": true, + "requires": { + "agent-base": "^6.0.2", + "debug": "^4.3.3", + "socks": "^2.6.2" + } + }, "source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", @@ -3363,14 +4005,46 @@ "sprintf-js": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz", - "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==", - "dev": true + "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==" + }, + "sqlite3": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/sqlite3/-/sqlite3-5.0.8.tgz", + "integrity": "sha512-f2ACsbSyb2D1qFFcqIXPfFscLtPVOWJr5GmUzYxf4W+0qelu5MWrR+FAQE1d5IUArEltBrzSDxDORG8P/IkqyQ==", + "dev": true, + "requires": { + "@mapbox/node-pre-gyp": "^1.0.0", + "node-addon-api": "^4.2.0", + "node-gyp": "8.x", + "tar": "^6.1.11" + } + }, + "ssri": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz", + "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==", + "dev": true, + "optional": true, + "requires": { + "minipass": "^3.1.1" + } }, "stoppable": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/stoppable/-/stoppable-1.1.0.tgz", "integrity": "sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw==" }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, "string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", @@ -3386,6 +4060,15 @@ } } }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, "supports-preserve-symlinks-flag": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", @@ -3398,6 +4081,20 @@ "integrity": "sha1-tvmpANSWpX8CQI8iGYwQndoGMEE=", "dev": true }, + "tar": { + "version": "6.1.11", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.11.tgz", + "integrity": "sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==", + "dev": true, + "requires": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^3.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + } + }, "tarn": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/tarn/-/tarn-3.0.2.tgz", @@ -3420,14 +4117,6 @@ "sprintf-js": "^1.1.2" }, "dependencies": { - "iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "requires": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - } - }, "sprintf-js": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz", @@ -3518,6 +4207,26 @@ "integrity": "sha512-5Zfuy9q/DFr4tfO7ZPeVXb1aPoeQSdeFMLpYuFebehDAhbuevLs5yxSZmIFN1tP5F9Wl4IpJrYojg85/zgyZHQ==", "dev": true }, + "unique-filename": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", + "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", + "dev": true, + "optional": true, + "requires": { + "unique-slug": "^2.0.0" + } + }, + "unique-slug": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", + "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", + "dev": true, + "optional": true, + "requires": { + "imurmurhash": "^0.1.4" + } + }, "universalify": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", @@ -3562,6 +4271,24 @@ "webidl-conversions": "^3.0.0" } }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "dev": true, + "requires": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, "word-wrap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", @@ -3587,6 +4314,12 @@ "version": "11.0.1", "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==" + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true } } } diff --git a/package.json b/package.json index 2cce378..76438dd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@themost/mssql", - "version": "2.6.1", + "version": "2.6.2", "description": "MOST Web Framework MSSQL Data Adapter", "main": "dist/index.js", "module": "dist/index.esm.js", @@ -32,11 +32,12 @@ "homepage": "https://github.com/themost-framework/mssql", "dependencies": { "async": "^3.2.3", - "mssql": "^8.1.0" + "mssql": "^8.1.0", + "sprintf-js": "^1.1.2" }, "peerDependencies": { - "@themost/common": "^2.5.6", - "@themost/query": "^2.5.9" + "@themost/common": "^2", + "@themost/query": "^2" }, "devDependencies": { "@babel/core": "^7.17.9", @@ -46,6 +47,7 @@ "@rollup/plugin-babel": "^5.3.1", "@rollup/plugin-commonjs": "^22.0.0", "@themost/data": "^2.6.32", + "@themost/sqlite": "^2.6.4", "@themost/xml": "^2.5.2", "@types/async": "^3.2.12", "@types/jasmine": "^3.5.14", diff --git a/spec/ArithmeticFunctions.spec.js b/spec/ArithmeticFunctions.spec.js new file mode 100644 index 0000000..f421d34 --- /dev/null +++ b/spec/ArithmeticFunctions.spec.js @@ -0,0 +1,122 @@ +import { TestApplication } from './TestApplication'; + +describe('ArithmeticFunctions', () => { + /** + * @type {TestApplication} + */ + let app; + beforeAll(async () => { + app = new TestApplication(__dirname); + await app.tryCreateDatabase(); + await app.trySetData(); + + }); + beforeEach(async () => { + // + }); + afterAll(async () => { + await app.finalize(); + }); + afterEach(async () => { + // + }); + + + it('should use add()', async () => { + await app.executeInTestTranscaction(async (context) => { + let items = await context.model('Product') + .asQueryable().where('price').add(10.5).greaterThan(100).take(10).getItems(); + expect(items).toBeInstanceOf(Array); + for (const item of items) { + expect(item.price + 10.5).toBeGreaterThan(100); + } + }); + }); + + it('should use subtract()', async () => { + await app.executeInTestTranscaction(async (context) => { + let items = await context.model('Product') + .asQueryable().where('price').subtract(10.5).lowerThan(100).take(10).getItems(); + expect(items).toBeInstanceOf(Array); + for (const item of items) { + expect(item.price - 10.5).toBeLessThan(100); + } + }); + }); + + it('should use multiply()', async () => { + await app.executeInTestTranscaction(async (context) => { + let items = await context.model('Product') + .asQueryable() + .where('category').equal('Laptops') + .and('price').multiply(0.75) + .lowerThan(1000).take(10).getItems(); + expect(items).toBeInstanceOf(Array); + expect(items.length).toBeTruthy(); + for (const item of items) { + expect(item.price * 0.75).toBeLessThan(1000); + } + }); + }); + + it('should use divide()', async () => { + await app.executeInTestTranscaction(async (context) => { + let items = await context.model('Product') + .asQueryable() + .where('category').equal('Laptops') + .and('price').multiply(1.25) + .lowerThan(1000).take(10).getItems(); + expect(items).toBeInstanceOf(Array); + expect(items.length).toBeTruthy(); + for (const item of items) { + expect(item.price / 1.25).toBeLessThan(1000); + } + }); + }); + + it('should use ceil()', async () => { + await app.executeInTestTranscaction(async (context) => { + let items = await context.model('Product') + .asQueryable() + .where('category').equal('Printers') + .and('price').ceil() + .equal(461).getItems(); + expect(items).toBeInstanceOf(Array); + expect(items.length).toBeGreaterThan(0); + for (const item of items) { + expect(Math.ceil(item.price)).toEqual(461); + } + }); + }); + + it('should use round()', async () => { + await app.executeInTestTranscaction(async (context) => { + let items = await context.model('Product') + .asQueryable() + .where('category').equal('Printers') + .and('price').round() + .greaterOrEqual(460).getItems(); + expect(items).toBeInstanceOf(Array); + expect(items.length).toBeGreaterThan(0); + for (const item of items) { + expect(Math.round(item.price)).toBeGreaterThanOrEqual(460); + } + }); + }); + + it('should use floor()', async () => { + await app.executeInTestTranscaction(async (context) => { + let items = await context.model('Product') + .asQueryable() + .where('category').equal('Printers') + .and('price').floor() + .equal(460).getItems(); + expect(items).toBeInstanceOf(Array); + expect(items.length).toBeGreaterThan(0); + for (const item of items) { + expect(Math.floor(item.price)).toEqual(460); + } + }); + }); + +}); \ No newline at end of file diff --git a/spec/DateFunctions.spec.js b/spec/DateFunctions.spec.js new file mode 100644 index 0000000..18a6364 --- /dev/null +++ b/spec/DateFunctions.spec.js @@ -0,0 +1,110 @@ +import { TestApplication } from './TestApplication'; + +describe('DateFunctions', () => { + /** + * @type {TestApplication} + */ + let app; + beforeAll(async () => { + app = new TestApplication(__dirname); + await app.tryCreateDatabase(); + await app.trySetData(); + + }); + beforeEach(async () => { + // + }); + afterAll(async () => { + await app.finalize(); + }); + afterEach(async () => { + // + }); + + it('should use getDate()', async () => { + await app.executeInTestTranscaction(async (context) => { + let items = await context.model('Order') + .asQueryable().where('orderDate').getDate().equal('2019-04-15').silent().getItems(); + expect(items).toBeInstanceOf(Array); + expect(items.length).toBeGreaterThan(0); + for (const item of items) { + expect(item.orderDate.getDate()).toEqual(15); + expect(item.orderDate.getMonth()).toEqual(3); + expect(item.orderDate.getFullYear()).toEqual(2019); + } + }); + }); + + it('should use getDay()', async () => { + await app.executeInTestTranscaction(async (context) => { + let items = await context.model('Order') + .asQueryable().where('orderDate').getDay().equal(15).silent().getItems(); + expect(items).toBeInstanceOf(Array); + expect(items.length).toBeGreaterThan(0); + for (const item of items) { + expect(item.orderDate.getDate()).toEqual(15); + } + }); + }); + + it('should use getMonth()', async () => { + await app.executeInTestTranscaction(async (context) => { + let items = await context.model('Order') + .asQueryable().where('orderDate').getMonth().equal(4).silent().getItems(); + expect(items).toBeInstanceOf(Array); + expect(items.length).toBeGreaterThan(0); + for (const item of items) { + expect(item.orderDate.getMonth()).toEqual(3); + } + }); + }); + + it('should use getFullYear()', async () => { + await app.executeInTestTranscaction(async (context) => { + let items = await context.model('Order') + .asQueryable().where('orderDate').getFullYear().equal(2019).silent().getItems(); + expect(items).toBeInstanceOf(Array); + expect(items.length).toBeGreaterThan(0); + for (const item of items) { + expect(item.orderDate.getFullYear()).toEqual(2019); + } + }); + }); + + it('should use getHours()', async () => { + await app.executeInTestTranscaction(async (context) => { + let items = await context.model('Order') + .asQueryable().where('orderDate').getHours().equal(14).silent().getItems(); + expect(items).toBeInstanceOf(Array); + expect(items.length).toBeGreaterThan(0); + for (const item of items) { + expect(item.orderDate.getHours()).toEqual(14); + } + }); + }); + + it('should use getMinutes()', async () => { + await app.executeInTestTranscaction(async (context) => { + let items = await context.model('Order') + .asQueryable().where('orderDate').getMinutes().equal(45).silent().getItems(); + expect(items).toBeInstanceOf(Array); + expect(items.length).toBeGreaterThan(0); + for (const item of items) { + expect(item.orderDate.getMinutes()).toEqual(45); + } + }); + }); + + it('should use getSeconds()', async () => { + await app.executeInTestTranscaction(async (context) => { + let items = await context.model('Order') + .asQueryable().where('orderDate').getSeconds().equal(42).silent().getItems(); + expect(items).toBeInstanceOf(Array); + expect(items.length).toBeGreaterThan(0); + for (const item of items) { + expect(item.orderDate.getSeconds()).toEqual(42); + } + }); + }); + +}); \ No newline at end of file diff --git a/spec/MSSqlAdapter.spec.js b/spec/MSSqlAdapter.spec.js index cca0fc6..5c00e28 100644 --- a/spec/MSSqlAdapter.spec.js +++ b/spec/MSSqlAdapter.spec.js @@ -1,88 +1,230 @@ -import { MSSqlAdapter, createInstance } from '@themost/mssql'; +import { MSSqlFormatter } from '../src'; import { QueryExpression } from '@themost/query'; -// get options from environment for testing -const testConnectionOptions = { - 'server': process.env.MSSQL_SERVER, - 'port': parseInt(process.env.MSSQL_SERVER_PORT, 10), - 'user': process.env.MSSQL_USER, - 'password': process.env.MSSQL_PASSWORD, - 'database': process.env.MSSQL_DB -}; - -// get options from environment for testing -const masterConnectionOptions = { - 'server': process.env.MSSQL_SERVER, - 'port': parseInt(process.env.MSSQL_SERVER_PORT, 10), - 'user': process.env.MSSQL_USER, - 'password': process.env.MSSQL_PASSWORD, - 'database': 'master' -}; - -describe('MSSqlFormatter', () => { - - it('should create instance', async () => { - const adapter = new MSSqlAdapter(); - expect(adapter).toBeTruthy(); - }); +import { TestApplication } from './TestApplication'; - it('should use createInstance()', async () => { - const adapter = createInstance(); - expect(adapter).toBeTruthy(); - expect(adapter).toBeInstanceOf(MSSqlAdapter); +describe('MSSqlAdapter', () => { + /** + * @type {TestApplication} + */ + let app; + beforeAll(async () => { + app = new TestApplication(__dirname); + await app.tryCreateDatabase(); }); - - it('should use open()', async () => { - /** - * @type {MSSqlAdapter} - */ - const adapter = createInstance(masterConnectionOptions); - await adapter.openAsync(); - expect(adapter.rawConnection).toBeTruthy(); - await adapter.closeAsync(); - expect(adapter.rawConnection).toBeFalsy(); + beforeEach(async () => { + // + }); + afterAll(async () => { + await app.finalize(); + }); + afterEach(async () => { + // + }); + it('should check database', async () => { + await app.executeInTestTranscaction(async (context) => { + let exists = await context.db.database('a_test_database').existsAsync(); + expect(exists).toBeFalsy(); + exists = await context.db.database('test_db').existsAsync(); + expect(exists).toBeTruthy(); + }); }); - it('should use close()', async () => { - /** - * @type {MSSqlAdapter} - */ - const adapter = createInstance(masterConnectionOptions); - await adapter.openAsync(); - await adapter.closeAsync(); - expect(adapter.rawConnection).toBeFalsy(); + it('should check table', async () => { + await app.executeInTestTranscaction(async (context) => { + const exists = await context.db.table('Table1').existsAsync(); + expect(exists).toBeFalsy(); + }); }); - it('should query database', async () => { - // validate and create database - /** - * @type {MSSqlAdapter} - */ - const adapter = createInstance(masterConnectionOptions); - const query = new QueryExpression().from('sys.databases').select('database_id', 'name').where('name').equal(testConnectionOptions.database); - const res = await adapter.executeAsync(query); - expect(res).toBeInstanceOf(Array); - expect(res.length).toBeLessThanOrEqual(1); - await adapter.closeAsync(); + it('should create table', async () => { + await app.executeInTestTranscaction(async (context) => { + const db = context.db; + let exists = await db.table('Table1').existsAsync(); + expect(exists).toBeFalsy(); + await context.db.table('Table1').createAsync([ + { + name: 'id', + type: 'Counter', + primary: true, + nullable: false + }, + { + name: 'name', + type: 'Text', + size: 255, + nullable: false + }, + { + name: 'description', + type: 'Text', + size: 255, + nullable: true + } + ]); + exists = await db.table('Table1').existsAsync(); + expect(exists).toBeTruthy(); + // get columns + const columns = await db.table('Table1').columnsAsync(); + expect(columns).toBeInstanceOf(Array); + let column = columns.find((col) => col.name === 'id'); + expect(column).toBeTruthy(); + expect(column.nullable).toBeFalsy(); + column = columns.find((col) => col.name === 'description'); + expect(column).toBeTruthy(); + expect(column.nullable).toBeTruthy(); + expect(column.size).toBe(255); + await db.executeAsync(`DROP TABLE ${new MSSqlFormatter().escapeName('Table1')}`); + }); }); - it('should use database(string).exists()', async () => { - const adapter = new MSSqlAdapter(masterConnectionOptions); - let exists = await adapter.database(testConnectionOptions.database).existsAsync(); - expect(exists).toBeTrue(); - exists = await adapter.database('other_database').existsAsync(); - expect(exists).toBeFalse(); - await adapter.closeAsync(); + it('should alter table', async () => { + await app.executeInTestTranscaction(async (context) => { + const db = context.db; + let exists = await db.table('Table2').existsAsync(); + expect(exists).toBeFalsy(); + await db.table('Table2').createAsync([ + { + name: 'id', + type: 'Counter', + primary: true, + nullable: false + }, + { + name: 'name', + type: 'Text', + size: 255, + nullable: false + } + ]); + exists = await db.table('Table2').existsAsync(); + expect(exists).toBeTruthy(); + await db.table('Table2').addAsync([ + { + name: 'description', + type: 'Text', + size: 255, + nullable: true + } + ]); + // get columns + let columns = await db.table('Table2').columnsAsync(); + expect(columns).toBeInstanceOf(Array); + let column = columns.find((col) => col.name === 'description'); + expect(column).toBeTruthy(); + + await db.table('Table2').changeAsync([ + { + name: 'description', + type: 'Text', + size: 512, + nullable: true + } + ]); + columns = await db.table('Table2').columnsAsync(); + column = columns.find((col) => col.name === 'description'); + expect(column.size).toEqual(512); + expect(column.nullable).toBeTruthy(); + await db.executeAsync(`DROP TABLE ${new MSSqlFormatter().escapeName('Table2')}`); + }); + }); - it('should use database(string).create()', async () => { - const adapter = new MSSqlAdapter(masterConnectionOptions); - await adapter.database('test_create_a_database').createAsync(); - let exists = await adapter.database('test_create_a_database').existsAsync(); - expect(exists).toBeTrue(); - await adapter.executeAsync('DROP DATABASE test_create_a_database;'); - exists = await adapter.database('test_create_a_database').existsAsync(); - expect(exists).toBeFalse(); - await adapter.closeAsync(); + + it('should create view', async () => { + + await app.executeInTestTranscaction(async (context) => { + const db = context.db; + let exists = await db.table('Table1').existsAsync(); + expect(exists).toBeFalsy(); + await db.table('Table1').createAsync([ + { + name: 'id', + type: 'Counter', + primary: true, + nullable: false + }, + { + name: 'name', + type: 'Text', + size: 255, + nullable: false + }, + { + name: 'description', + type: 'Text', + size: 255, + nullable: true + } + ]); + exists = await db.table('Table1').existsAsync(); + expect(exists).toBeTruthy(); + + exists = await db.view('View1').existsAsync(); + expect(exists).toBeFalsy(); + + const query = new QueryExpression().select('id', 'name', 'description').from('Table1'); + await db.view('View1').createAsync(query); + + exists = await db.view('View1').existsAsync(); + expect(exists).toBeTruthy(); + + await db.view('View1').dropAsync(); + + exists = await db.view('View1').existsAsync(); + expect(exists).toBeFalsy(); + await db.executeAsync(`DROP TABLE ${new MSSqlFormatter().escapeName('Table1')}`); + }); }); + it('should create index', async () => { + await app.executeInTestTranscaction(async (context) => { + const db = context.db; + let exists = await db.table('Table1').existsAsync(); + expect(exists).toBeFalsy(); + await db.table('Table1').createAsync([ + { + name: 'id', + type: 'Counter', + primary: true, + nullable: false + }, + { + name: 'name', + type: 'Text', + size: 255, + nullable: false + }, + { + name: 'description', + type: 'Text', + size: 255, + nullable: true + } + ]); + exists = await db.table('Table1').existsAsync(); + expect(exists).toBeTruthy(); + + let list = await db.indexes('Table1').listAsync(); + expect(list).toBeInstanceOf(Array); + exists = list.findIndex((index) => index.name === 'idx_name') < 0; + + await db.indexes('Table1').createAsync('idx_name', [ + 'name' + ]); + + list = await db.indexes('Table1').listAsync(); + expect(list).toBeInstanceOf(Array); + exists = list.findIndex((index) => index.name === 'idx_name') >= 0; + expect(exists).toBeTruthy(); + + await db.indexes('Table1').dropAsync('idx_name'); + + list = await db.indexes('Table1').listAsync(); + expect(list).toBeInstanceOf(Array); + exists = list.findIndex((index) => index.name === 'idx_name') >= 0; + expect(exists).toBeFalsy(); + + await db.executeAsync(`DROP TABLE ${new MSSqlFormatter().escapeName('Table1')}`); + }); + }); }); \ No newline at end of file diff --git a/spec/MSSqlFormatter.spec.js b/spec/MSSqlFormatter.spec.js index 16c5e1f..90545c9 100644 --- a/spec/MSSqlFormatter.spec.js +++ b/spec/MSSqlFormatter.spec.js @@ -1,41 +1,49 @@ -import {MSSqlFormatter} from '@themost/mssql'; -import {TestApplication} from './TestApplication'; -import path from 'path'; -// eslint-disable-next-line no-unused-vars -import { DataContext } from '@themost/data'; +import { MSSqlFormatter } from '../src'; +import { TestApplication } from './TestApplication'; describe('MSSqlFormatter', () => { - /** * @type {TestApplication} */ let app; beforeAll(async () => { - app = new TestApplication(path.resolve(__dirname)); + app = new TestApplication(__dirname); await app.tryCreateDatabase(); + await app.trySetData(); + + }); + beforeEach(async () => { + // }); - afterAll(async () => { await app.finalize(); - }) + }); + afterEach(async () => { + // + }); - it('should create instance', async () => { - const formatter = new MSSqlFormatter(); - expect(formatter).toBeTruthy(); + it('should get data', async () => { + await app.executeInTestTranscaction(async (context) => { + const items = await context.model('ActionStatusType').silent().getItems(); + expect(items).toBeInstanceOf(Array); + expect(items.length).toBeTruthy(); + }); }); - it('should should use select', async () => { - /** - * @type {DataContext} - */ - const context = app.createContext(); - expect(context).toBeTruthy(); - const item = await context.model('ActionStatusType') - .where('alternateName').equal('ActiveActionStatus') - .getItem(); - expect(item).toBeTruthy(); - expect(item.alternateName).toEqual('ActiveActionStatus'); - await context.finalizeAsync(); + it('should query data', async () => { + await app.executeInTestTranscaction(async (context) => { + const item = await context.model('ActionStatusType') + .where('alternateName').equal('ActiveActionStatus').silent().getItem(); + expect(item).toBeTruthy(); + expect(item.alternateName).toEqual('ActiveActionStatus'); + }); + }); + + it('should escape constant', async () => { + const formatter = new MSSqlFormatter(); + expect(formatter.escapeConstant(10.45)).toEqual('10.45'); + expect(formatter.escapeConstant('test')).toEqual('\'test\''); + expect(formatter.escapeConstant(true)).toEqual('1'); }); it('should should use limit select', async () => { @@ -88,21 +96,6 @@ describe('MSSqlFormatter', () => { }); }); - it('should use update', async () => { - await app.executeInTestTranscaction(async (context) => { - const insertUser = { - name: 'user1@example.com', - description: 'Test User' - }; - await context.model('User').silent().insert(insertUser); - let newUser = await context.model('User').where('name').equal('user1@example.com').silent().getItem(); - newUser.description = 'Updated Test User'; - await context.model('User').silent().save(newUser); - newUser = await context.model('User').where('name').equal('user1@example.com').silent().getItem(); - expect(newUser.description).toEqual('Updated Test User'); - }); - }); - it('should use count', async () => { await app.executeInTestTranscaction(async (context) => { diff --git a/spec/Promise.sequence.spec.js b/spec/Promise.sequence.spec.js deleted file mode 100644 index 90a18bf..0000000 --- a/spec/Promise.sequence.spec.js +++ /dev/null @@ -1,53 +0,0 @@ -function func1() { - return new Promise(function(resolve) { - setTimeout(function() { - return resolve(1); - },1500); - }); -} - -function func2() { - return new Promise(function(resolve) { - setTimeout(function() { - return resolve(2); - },500); - }); -} - -function func3() { - return new Promise(function(resolve, reject) { - setTimeout(function() { - return reject('The operation cancelled by the user'); - },1000); - }); -} -/** - * - * @param {*} promises - * @returns Promise> - */ -function promiseSequence(sources) { - return sources.reduce((promise, func) => ( - promise.then((result) => ( - func().then(Array.prototype.concat.bind(result)) - )) - ), Promise.resolve([])); -} - -describe('Promise.sequence', () => { - it('should execute promise sequence', async() => { - const results = await promiseSequence([ - () => func1(), - () => func2() - ]); - expect(results).toBeInstanceOf(Array); - expect(results[0]).toEqual(1); - expect(results[1]).toEqual(2); - - await expectAsync(promiseSequence([ - () => func1(), - () => func3() - ])).toBeRejected(); - - }); -}); diff --git a/spec/StringFunctions.spec.js b/spec/StringFunctions.spec.js new file mode 100644 index 0000000..5c63076 --- /dev/null +++ b/spec/StringFunctions.spec.js @@ -0,0 +1,126 @@ +import { TestApplication } from './TestApplication'; + +describe('StringFunctions', () => { + /** + * @type {TestApplication} + */ + let app; + beforeAll(async () => { + app = new TestApplication(__dirname); + await app.tryCreateDatabase(); + await app.trySetData(); + + }); + beforeEach(async () => { + // + }); + afterAll(async () => { + await app.finalize(); + }); + afterEach(async () => { + // + }); + + it('should use indexOf()', async () => { + await app.executeInTestTranscaction(async (context) => { + let items = await context.model('Product') + .asQueryable().where('name').substr(0, 2).equal('Ap').getItems(); + expect(items).toBeInstanceOf(Array); + for (const item of items) { + expect(item.name.substr(0, 2)).toEqual('Ap'); + } + }); + }); + + it('should use startsWith()', async () => { + await app.executeInTestTranscaction(async (context) => { + let items = await context.model('Product') + .asQueryable().where('name').startsWith('Apple').equal(true).getItems(); + expect(items).toBeInstanceOf(Array); + for (const item of items) { + expect(item.name.startsWith('Apple')).toBeTruthy(); + } + }); + }); + + it('should use lower()', async () => { + await app.executeInTestTranscaction(async (context) => { + let items = await context.model('Product') + .asQueryable().where('name').toLowerCase().equal('apple ipad air').getItems(); + expect(items).toBeInstanceOf(Array); + expect(items.length).toBeGreaterThan(0); + for (const item of items) { + expect(item.name.toLowerCase()).toEqual('apple ipad air'); + } + }); + }); + + it('should use upper()', async () => { + await app.executeInTestTranscaction(async (context) => { + let items = await context.model('Product') + .asQueryable().where('name').toUpperCase().equal('APPLE IPAD AIR').getItems(); + expect(items).toBeInstanceOf(Array); + expect(items.length).toBeGreaterThan(0); + for (const item of items) { + expect(item.name.toUpperCase()).toEqual('APPLE IPAD AIR'); + } + }); + }); + + it('should use endsWith()', async () => { + await app.executeInTestTranscaction(async (context) => { + let items = await context.model('Product') + .asQueryable().where('name').endsWith('Touch').equal(true).getItems(); + expect(items).toBeInstanceOf(Array); + for (const item of items) { + expect(item.name.endsWith('Touch')).toBeTruthy(); + } + }); + }); + + it('should use length()', async () => { + await app.executeInTestTranscaction(async (context) => { + let items = await context.model('Product') + .asQueryable().where('name').length().equal(14).getItems(); + expect(items).toBeInstanceOf(Array); + for (const item of items) { + expect(item.name.length).toEqual(14); + } + }); + }); + + it('should use substr()', async () => { + await app.executeInTestTranscaction(async (context) => { + let items = await context.model('Product') + .asQueryable().where('name').indexOf('Apple').greaterOrEqual(0).getItems(); + expect(items).toBeInstanceOf(Array); + for (const item of items) { + expect(item.name.indexOf('Apple')).toBeGreaterThanOrEqual(0); + } + }); + }); + + it('should use indexOf()', async () => { + await app.executeInTestTranscaction(async (context) => { + let items = await context.model('Product') + .asQueryable().where('name').substr(0, 2).equal('Ap').getItems(); + expect(items).toBeInstanceOf(Array); + for (const item of items) { + expect(item.name.substr(0, 2)).toEqual('Ap'); + } + }); + }); + + // it('should use contains()', async () => { + // await app.executeInTestTranscaction(async (context) => { + // let items = await context.model('Product') + // .asQueryable().where('name').contains('iMac').equal(true).getItems(); + // expect(items).toBeInstanceOf(Array); + // for (const item of items) { + // expect(item.name.includes('iMac')).toBeTruthy(); + // } + // }); + // }); + + +}); \ No newline at end of file diff --git a/spec/TestApplication.js b/spec/TestApplication.js index 9357c54..3dc4384 100644 --- a/spec/TestApplication.js +++ b/spec/TestApplication.js @@ -1,23 +1,41 @@ // eslint-disable-next-line no-unused-vars -import {DataApplication, DataConfigurationStrategy, NamedDataContext, DataCacheStrategy, DataContext} from '@themost/data'; -import { createInstance } from '@themost/mssql'; +import {DataApplication, DataConfigurationStrategy, NamedDataContext, DataCacheStrategy, DataContext, ODataModelBuilder, ODataConventionModelBuilder} from '@themost/data'; +import { createInstance, MSSqlFormatter } from '../src'; +import { TraceUtils, LangUtils } from '@themost/common'; import { QueryExpression } from '@themost/query'; +import { SqliteAdapter } from '@themost/sqlite'; +import path from 'path'; + const testConnectionOptions = { - 'server': process.env.MSSQL_SERVER, - 'port': parseInt(process.env.MSSQL_SERVER_PORT, 10), - 'user': process.env.MSSQL_USER, - 'password': process.env.MSSQL_PASSWORD, - 'database': process.env.MSSQL_DB + 'server': process.env.DB_HOST, + 'port': parseInt(process.env.DB_PORT, 10), + 'user': process.env.DB_USER, + 'database': 'test_db' }; +if (process.env.DB_PASSWORD) { + Object.assign(testConnectionOptions, { + password: process.env.DB_PASSWORD + }); +} + const masterConnectionOptions = { - 'server': process.env.MSSQL_SERVER, - 'port': parseInt(process.env.MSSQL_SERVER_PORT, 10), - 'user': process.env.MSSQL_USER, - 'password': process.env.MSSQL_PASSWORD, + 'server': process.env.DB_HOST, + 'port': parseInt(process.env.DB_PORT, 10), + 'user': process.env.DB_USER, 'database': 'master' }; +if (process.env.DB_PASSWORD) { + Object.assign(masterConnectionOptions, { + password: process.env.DB_PASSWORD + }); +} + +const sourceConnectionOptions = { + database: path.resolve(__dirname, 'db/local.db') +}; + class CancelTransactionError extends Error { constructor() { super(); @@ -62,9 +80,8 @@ class TestApplication extends DataApplication { context.getConfiguration = () => { return this.configuration; }; - const query = new QueryExpression().from('sys.databases').select('database_id', 'name').where('name').equal(testConnectionOptions.database); - const res = await context.db.executeAsync(query); - if (res.length === 0) { + const exists = await context.db.database(testConnectionOptions.database).existsAsync(); + if (exists === false) { await context.db.executeAsync(`CREATE DATABASE ${testConnectionOptions.database};`); } await context.db.closeAsync(); @@ -119,20 +136,141 @@ class TestApplication extends DataApplication { return cb(err); } }, (err) => { - // if error is an instance of CancelTransactionError - if (err && err instanceof CancelTransactionError) { + context.finalizeAsync().finally(() => { + // if error is an instance of CancelTransactionError + if (err && err instanceof CancelTransactionError) { + return resolve(); + } + if (err) { + return reject(err); + } + // exit return resolve(); - } - if (err) { - return reject(err); - } - // exit - return resolve(); + }); }); }); }); + } + + async tryUpgrade() { + let context; + try { + this.configuration.useStrategy(ODataModelBuilder, ODataConventionModelBuilder); + context = this.createContext(); + const builder = this.configuration.getStrategy(ODataModelBuilder); + const schema = await builder.getEdm(); + const entityTypes = schema.entityType.filter((item) => { + return item.abstract ? false : true; + }); + await context.executeInTransactionAsync(async () => { + for (let entityType of entityTypes) { + TraceUtils.debug(`Upgrading ${entityType.name}`); + await new Promise((resolve, reject) => { + const model = context.model(entityType.name); + if (model.abstract) { + return resolve(); + } + model.migrate(function (err) { + if (err) { + return reject(err); + } + return resolve(); + }); + }); + } + }); + await context.finalizeAsync(); + } catch (error) { + if (context) { + await context.finalizeAsync(); + } + throw error; + } + } - + async trySetData() { + let context; + try { + this.configuration.useStrategy(ODataModelBuilder, ODataConventionModelBuilder); + context = this.createContext(); + // validate if the operation has been already run + const exists1 = await context.db.table('migrations').existsAsync(); + if (exists1 === true) { + const alreadyApplied = await context.db.executeAsync( + new QueryExpression().select('version').from('migrations') + .where('appliesTo').equal('SetData').and('version').equal('1.0') + ); + if (alreadyApplied.length > 0) { + return; + } + } + const builder = this.configuration.getStrategy(ODataModelBuilder); + const schema = await builder.getEdm(); + const entityTypes = schema.entityType.filter((item) => { + return item.abstract ? false : true; + }); + const sourceAdapter = new SqliteAdapter(sourceConnectionOptions); + const formatter = new MSSqlFormatter(); + for (let entityType of entityTypes) { + TraceUtils.log(`Upgrading ${entityType.name}`); + await new Promise((resolve, reject) => { + const model = context.model(entityType.name); + if (model.abstract) { + return resolve(); + } + model.migrate(function (err) { + if (err) { + return reject(err); + } + (async function () { + const formatter = new MSSqlFormatter(); + const sourceTableExists = await sourceAdapter.table(model.sourceAdapter).existsAsync(); + if (sourceTableExists) { + const key = model.getAttribute(model.primaryKey); + // get source data + let results = await sourceAdapter.executeAsync(`SELECT * FROM ${formatter.escapeName(model.sourceAdapter)}`); + if (results.length > 0) { + await context.db.executeAsync(`DELETE FROM ${formatter.escapeName(model.sourceAdapter)} WHERE 1=1`); + // get columns of type boolean + // data should be update to true/false + // because of an error occurred while trying to insert an integer value to a field of type boolean + const booleanAttributes = model.attributes.filter((attribute) => attribute.type === 'Boolean'); + for (let result of results) { + // modify data + booleanAttributes.forEach((attribute) => { + if (Object.prototype.hasOwnProperty.call(result, attribute.name)) { + result[attribute.name] = LangUtils.parseBoolean(result[attribute.name]); + } + }); + let sql = ''; + if (key.type === 'Counter') { + sql = `SET IDENTITY_INSERT ${formatter.escapeName(model.sourceAdapter)} ON;` + } + sql += formatter.format(new QueryExpression().insert(result).into(model.sourceAdapter)); + // and execute + await context.db.executeAsync(sql); + } + } + } + })().then(() => { + return resolve(); + }).catch((err) => { + return reject(err); + }); + }); + }); + } + await context.db.executeAsync(new QueryExpression().insert({ + appliesTo: 'SetData', + version: '1.0' + }).into('migrations')); + await context.finalizeAsync(); + } catch (error) { + if (context) { + await context.finalizeAsync(); + } + throw error; + } } } diff --git a/spec/config/app.json b/spec/config/app.json new file mode 100644 index 0000000..e38bdc3 --- /dev/null +++ b/spec/config/app.json @@ -0,0 +1,29 @@ +{ + "settings": { + "crypto": { + "algorithm": "aes256", + "key": "656e675539754a34634b4b4646723972617a483734366d327a433453596248386862434166514c36524164504c345734" + }, + "auth": { + "unattendedExecutionAccount": "Z+mP8SdKPDREuLub" + }, + "i18n": { + "locales": [ + "en" + ], + "defaultLocale": "en" + } + }, + "adapterTypes": [ + ], + "adapters": [ + { + "name": "source", + "invariantName": "sqlite", + "default": false, + "options": { + "database": "db/local.db" + } + } + ] +} diff --git a/spec/config/models/AccessLevelType.json b/spec/config/models/AccessLevelType.json index 6889a38..ac56601 100644 --- a/spec/config/models/AccessLevelType.json +++ b/spec/config/models/AccessLevelType.json @@ -14,7 +14,8 @@ "title": "ID", "description": "The identifier of the item.", "type": "Integer", - "primary": true + "primary": true, + "nullable": false } ], "privileges": [ diff --git a/spec/db/local.db b/spec/db/local.db new file mode 100644 index 0000000..42e72b8 Binary files /dev/null and b/spec/db/local.db differ diff --git a/spec/helpers/module-alias.js b/spec/helpers/module-alias.js deleted file mode 100644 index 73271ad..0000000 --- a/spec/helpers/module-alias.js +++ /dev/null @@ -1,4 +0,0 @@ -import path from 'path'; -require('module-alias').addAliases({ - '@themost/mssql': path.resolve(__dirname, '../../src/index') -}); \ No newline at end of file diff --git a/spec/helpers/reporter.js b/spec/helpers/reporter.js index b648a88..600ef79 100644 --- a/spec/helpers/reporter.js +++ b/spec/helpers/reporter.js @@ -1,10 +1,11 @@ const SpecReporter = require('jasmine-spec-reporter').SpecReporter; jasmine.getEnv().clearReporters(); // remove default reporter logs +// noinspection JSCheckFunctionSignatures jasmine.getEnv().addReporter(new SpecReporter({ // add jasmine-spec-reporter spec: { displayPending: true, displayStacktrace: 'raw' } })); -jasmine.DEFAULT_TIMEOUT_INTERVAL = 30000; \ No newline at end of file +jasmine.DEFAULT_TIMEOUT_INTERVAL = 60000; \ No newline at end of file diff --git a/spec/support/jasmine.json b/spec/support/jasmine.json index 3ea3166..6cb5aa0 100644 --- a/spec/support/jasmine.json +++ b/spec/support/jasmine.json @@ -1,11 +1,13 @@ { "spec_dir": "spec", "spec_files": [ - "**/*[sS]pec.js" + "**/*[sS]pec.?(m)js" ], "helpers": [ - "helpers/**/*.js" + "helpers/**/*.?(m)js" ], - "stopSpecOnExpectationFailure": false, - "random": false + "env": { + "stopSpecOnExpectationFailure": false, + "random": false + } } diff --git a/src/MSSqlAdapter.d.ts b/src/MSSqlAdapter.d.ts index c1ebad4..0f2f40f 100644 --- a/src/MSSqlAdapter.d.ts +++ b/src/MSSqlAdapter.d.ts @@ -1,59 +1,13 @@ -// MOST Web Framework Codename Zero Gravity Copyright (c) 2017-2022, THEMOST LP All rights reserved -export declare interface MSSqlAdapterTable { - create(fields: Array, callback: (err: Error) => void): void; - createAsync(fields: Array): Promise; - add(fields: Array, callback: (err: Error) => void): void; - addAsync(fields: Array): Promise; - change(fields: Array, callback: (err: Error) => void): void; - changeAsync(fields: Array): Promise; - exists(callback: (err: Error, result: boolean) => void): void; - existsAsync(): Promise; - version(callback: (err: Error, result: string) => void): void; - versionAsync(): Promise; - columns(callback: (err: Error, result: Array) => void): void; - columnsAsync(): Promise>; -} +import { DataAdapterBase, DataAdapterBaseHelper, DataAdapterDatabase, DataAdapterIndexes, DataAdapterMigration, DataAdapterTable, DataAdapterView } from '@themost/common'; -export declare interface MSSqlAdapterIndex { - name: string; - columns: Array; -} - -export declare interface MSSqlAdapterIndexes { - create(name: string, columns: Array, callback: (err: Error, res?: number) => void): void; - createAsync(name: string, columns: Array): Promise; - drop(name: string, callback: (err: Error, res?: number) => void): void; - dropAsync(name: string): Promise; - list(callback: (err: Error, res: Array) => void): void; - listAsync(): Promise>; -} - -export declare interface MSSqlAdapterView { - create(query: any, callback: (err: Error) => void): void; - createAsync(query: any): Promise; - exists(callback: (err: Error, result: boolean) => void): void; - existsAsync(): Promise; - drop(callback: (err: Error) => void): void; - dropAsync(): Promise; -} - -export declare interface MSSqlAdapterDatabase { - exists(callback: (err: Error, result: boolean) => void): void; - existsAsync(): Promise; - create(callback: (err: Error) => void): void; - createAsync(): Promise; -} - -export declare interface MSSqlAdapterMigration { - add: Array; - change?: Array; - appliesTo: string; - version: string; -} - -export declare class MSSqlAdapter { +export declare class MSSqlAdapter implements DataAdapterBase, DataAdapterBaseHelper { static formatType(field: any): string; constructor(options?: any); + rawConnection?: any; + options?: any; + selectIdentityAsync(entity: string, attribute: string): Promise; + executeInTransactionAsync(func: () => Promise): Promise; + migrateAsync(obj: DataAdapterMigration): Promise; formatType(field: any): string; open(callback: (err: Error) => void): void; close(callback: (err: Error) => void): void; @@ -62,14 +16,13 @@ export declare class MSSqlAdapter { prepare(query: any, values?: Array): any; createView(name: string, query: any, callback: (err: Error) => void): void; executeInTransaction(func: any, callback: (err: Error) => void): void; - executeInTransactionAsync(func: Promise): Promise; - migrate(obj: MSSqlAdapterMigration, callback: (err: Error) => void): void; + migrate(obj: DataAdapterMigration, callback: (err: Error) => void): void; selectIdentity(entity: string, attribute: string, callback: (err: Error, value: any) => void): void; execute(query: any, values: any, callback: (err: Error, value: any) => void): void; executeAsync(query: any, values: any): Promise; executeAsync(query: any, values: any): Promise>; - table(name: string): MSSqlAdapterTable; - view(name: string): MSSqlAdapterView; - indexes(name: string): MSSqlAdapterIndexes; - database(name: string): MSSqlAdapterDatabase; + table(name: string): DataAdapterTable; + view(name: string): DataAdapterView; + indexes(name: string): DataAdapterIndexes; + database(name: string): DataAdapterDatabase; } \ No newline at end of file diff --git a/src/MSSqlAdapter.js b/src/MSSqlAdapter.js index 1d35e19..2d66e24 100644 --- a/src/MSSqlAdapter.js +++ b/src/MSSqlAdapter.js @@ -2,7 +2,7 @@ import mssql from 'mssql'; import {ConnectionPool} from 'mssql'; import async from 'async'; -import util from 'util'; +import { sprintf } from 'sprintf-js'; import { TraceUtils } from '@themost/common'; import { SqlUtils } from '@themost/query'; import { MSSqlFormatter } from './MSSqlFormatter'; @@ -290,6 +290,22 @@ class MSSqlAdapter { }); } + /** + * @param {string} entity + * @param {string} attribute + * @returns Promise + */ + selectIdentityAsync(entity, attribute) { + return new Promise((resolve, reject) => { + return this.selectIdentity(entity, attribute, (err, res) => { + if (err) { + return reject(err); + } + return resolve(res); + }); + }); + } + /** * @param {*} query * @param {*} values @@ -335,7 +351,7 @@ class MSSqlAdapter { return callback(err); } if (process.env.NODE_ENV === 'development') { - TraceUtils.debug(util.format('SQL (Execution Time:%sms):%s, Parameters:%s', (new Date()).getTime() - startTime, sql, JSON.stringify(values))); + TraceUtils.debug(sprintf('SQL (Execution Time:%sms):%s, Parameters:%s', (new Date()).getTime() - startTime, sql, JSON.stringify(values))); } if (typeof query.$insert === 'undefined') { if (result.recordsets.length === 1) { @@ -426,7 +442,7 @@ class MSSqlAdapter { s = size > 0 ? (size <= 10 ? 'smallmoney' : 'money') : 'money'; break; case 'Decimal': - s = util.format('decimal(%s,%s)', (size > 0 ? size : 19), (scale > 0 ? scale : 4)); + s = sprintf('decimal(%s,%s)', (size > 0 ? size : 19), (scale > 0 ? scale : 4)); break; case 'Date': s = 'date'; @@ -441,23 +457,23 @@ class MSSqlAdapter { s = 'int'; break; case 'Duration': - s = size > 0 ? util.format('varchar(%s)', size) : 'varchar(48)'; + s = size > 0 ? sprintf('varchar(%s)', size) : 'varchar(48)'; break; case 'URL': if (size > 0) - s = util.format('varchar(%s)', size); + s = sprintf('varchar(%s)', size); else s = 'varchar(512)'; break; case 'Text': if (size > 0) - s = util.format('varchar(%s)', size); + s = sprintf('varchar(%s)', size); else s = 'varchar(512)'; break; case 'Note': if (size > 0) - s = util.format('varchar(%s)', size); + s = sprintf('varchar(%s)', size); else s = 'text'; break; @@ -618,10 +634,10 @@ class MSSqlAdapter { return self.format('[%f]', x); }).join(', '); if (strPKFields.length > 0) { - strFields += ', ' + util.format('PRIMARY KEY (%s)', strPKFields); + strFields += ', ' + sprintf('PRIMARY KEY (%s)', strPKFields); } - const strTable = util.format('[%s].[%s]', owner, table); - const sql = util.format('CREATE TABLE %s (%s)', strTable, strFields); + const strTable = sprintf('[%s].[%s]', owner, table); + const sql = sprintf('CREATE TABLE %s (%s)', strTable, strFields); self.execute(sql, null, function (err) { callback(err); }); @@ -653,7 +669,7 @@ class MSSqlAdapter { //do nothing return callback(); } - const strTable = util.format('[%s].[%s]', owner, table); + const strTable = sprintf('[%s].[%s]', owner, table); //generate SQL statement const sql = fields.map((x) => { return self.format('ALTER TABLE ' + strTable + ' ADD [%f] %t', x); @@ -689,7 +705,7 @@ class MSSqlAdapter { //do nothing return callback(); } - const strTable = util.format('[%s].[%s]', owner, table); + const strTable = sprintf('[%s].[%s]', owner, table); //generate SQL statement const sql = fields.map((x) => { return self.format('ALTER TABLE ' + strTable + ' ALTER COLUMN [%f] %t', x); @@ -700,7 +716,7 @@ class MSSqlAdapter { }, changeAsync: function (fields) { return new Promise((resolve, reject) => { - this.add(fields, (err, res) => { + this.change(fields, (err, res) => { if (err) { return reject(err); } @@ -771,7 +787,7 @@ class MSSqlAdapter { const exists = (result[0].count > 0); if (exists) { const formatter = new MSSqlFormatter(); - const sql = util.format('DROP VIEW %s.%s', formatter.escapeName(owner), formatter.escapeName(view)); + const sql = sprintf('DROP VIEW %s.%s', formatter.escapeName(owner), formatter.escapeName(view)); self.execute(sql, [], function (err) { if (err) { callback(err); @@ -810,7 +826,7 @@ class MSSqlAdapter { } try { const formatter = new MSSqlFormatter(); - const sql = 'EXECUTE(\'' + util.format('CREATE VIEW %s.%s AS ', formatter.escapeName(owner), formatter.escapeName(view)) + formatter.format(q) + '\')'; + const sql = 'EXECUTE(\'' + sprintf('CREATE VIEW %s.%s AS ', formatter.escapeName(owner), formatter.escapeName(view)) + formatter.format(q) + '\')'; self.execute(sql, [], tr); } catch (e) { @@ -1033,6 +1049,20 @@ class MSSqlAdapter { } }); } + + /** + * @param {DataModelMigration|*} obj - An Object that represents the data model scheme we want to migrate + */ + migrateAsync(obj) { + return new Promise((resolve, reject) => { + return this.migrate(obj, (err, res) => { + if (err) { + return reject(err); + } + return resolve(res); + }); + }); + } /** * A utility for database object * @param {string} name diff --git a/src/MSSqlFormatter.d.ts b/src/MSSqlFormatter.d.ts index fa2a942..3a95d76 100644 --- a/src/MSSqlFormatter.d.ts +++ b/src/MSSqlFormatter.d.ts @@ -1,12 +1,5 @@ // MOST Web Framework Codename Zero Gravity Copyright (c) 2017-2022, THEMOST LP All rights reserved import { SqlFormatter } from "@themost/query"; -/** - * MOST Web Framework 2.0 Codename Blueshift - * Copyright (c) 2014-2020, THEMOST LP themost-framework@themost.io - * - * Use of this source code is governed by an BSD-3-Clause license that can be - * found in the LICENSE file at https://themost.io/license - */ export declare class MSSqlFormatter extends SqlFormatter { } diff --git a/src/MSSqlFormatter.js b/src/MSSqlFormatter.js index d6aa3f6..193a479 100644 --- a/src/MSSqlFormatter.js +++ b/src/MSSqlFormatter.js @@ -1,5 +1,5 @@ // MOST Web Framework Codename Zero Gravity Copyright (c) 2017-2022, THEMOST LP All rights reserved -import util from 'util'; +import { sprintf } from 'sprintf-js'; import { QueryField, SqlUtils, SqlFormatter } from '@themost/query'; function zeroPad(number, length) { @@ -71,7 +71,7 @@ class MSSqlFormatter extends SqlFormatter { fields.push(field.as() || field.getName()); } }); - sql = util.format('SELECT %s FROM (%s) [t0] WHERE [__RowIndex] BETWEEN %s AND %s', fields.map((x) => { + sql = sprintf('SELECT %s FROM (%s) [t0] WHERE [__RowIndex] BETWEEN %s AND %s', fields.map((x) => { return self.format(x, '%f'); }).join(', '), subQuery, parseInt(obj.$skip, 10) + 1, parseInt(obj.$skip, 10) + parseInt(obj.$take, 10)); } @@ -79,13 +79,26 @@ class MSSqlFormatter extends SqlFormatter { } /** * Implements indexOf(str,substr) expression formatter. - * @param {String} p0 The source string - * @param {String} p1 The string to search for + * @param {*} p0 The source string + * @param {*} p1 The string to search for */ $indexof(p0, p1) { + return this.$indexOf(p0, p1); + } + /** + * Implements indexOf(str,substr) expression formatter. + * @param {*} p0 The source string + * @param {*} p1 The string to search for + */ + $indexOf(p0, p1) { p1 = '%' + p1 + '%'; return '(PATINDEX('.concat(this.escape(p1), ',', this.escape(p0), ')-1)'); } + + $length(p0) { + return sprintf('LEN(%s)', this.escape(p0)); + } + /** * Implements simple regular expression formatter. Important Note: MS SQL Server does not provide a core sql function for regular expression matching. * @param {string|*} p0 The source string or field @@ -108,10 +121,10 @@ class MSSqlFormatter extends SqlFormatter { s1 = s1 + '%'; } //use PATINDEX for text searching - return util.format('PATINDEX(%s,%s) >= 1', this.escape(s1), this.escape(p0)); + return sprintf('PATINDEX(%s,%s) >= 1', this.escape(s1), this.escape(p0)); } $date(p0) { - return util.format(' TODATETIMEOFFSET (%s,datepart(TZ,SYSDATETIMEOFFSET()))', this.escape(p0)); + return sprintf('CONVERT(date, %s)', this.escape(p0)); } /** * Escapes an object or a value and returns the equivalent sql value. @@ -160,7 +173,7 @@ class MSSqlFormatter extends SqlFormatter { */ $startswith(p0, p1) { p1 = '%' + p1 + '%'; - return util.format('PATINDEX (%s,%s)', this.escape(p1), this.escape(p0)); + return sprintf('PATINDEX (%s,%s)', this.escape(p1), this.escape(p0)); } /** * Implements contains(a,b) expression formatter. @@ -168,7 +181,7 @@ class MSSqlFormatter extends SqlFormatter { * @param p1 {*} */ $text(p0, p1) { - return util.format('(PATINDEX (%s,%s) - 1)', this.escape('%' + p1 + '%'), this.escape(p0)); + return sprintf('(PATINDEX (%s,%s) - 1)', this.escape('%' + p1 + '%'), this.escape(p0)); } /** * Implements endsWith(a,b) expression formatter. @@ -178,7 +191,7 @@ class MSSqlFormatter extends SqlFormatter { $endswith(p0, p1) { p1 = '%' + p1; // (PATINDEX('%S%', UserData.alternateName)) - return util.format('(CASE WHEN %s LIKE %s THEN 1 ELSE 0 END)', this.escape(p0), this.escape(p1)); + return sprintf('(CASE WHEN %s LIKE %s THEN 1 ELSE 0 END)', this.escape(p0), this.escape(p1)); } /** * Implements substring(str,pos) expression formatter. @@ -189,16 +202,16 @@ class MSSqlFormatter extends SqlFormatter { */ $substring(p0, pos, length) { if (length) - return util.format('SUBSTRING(%s,%s,%s)', this.escape(p0), pos.valueOf() + 1, length.valueOf()); + return sprintf('SUBSTRING(%s,%s,%s)', this.escape(p0), pos.valueOf() + 1, length.valueOf()); else - return util.format('SUBSTRING(%s,%s,%s)', this.escape(p0), pos.valueOf() + 1, 255); + return sprintf('SUBSTRING(%s,%s,%s)', this.escape(p0), pos.valueOf() + 1, 255); } /** * Implements trim(a) expression formatter. * @param p0 {*} */ $trim(p0) { - return util.format('LTRIM(RTRIM((%s)))', this.escape(p0)); + return sprintf('LTRIM(RTRIM((%s)))', this.escape(p0)); } /** * @param {*=} order @@ -208,8 +221,45 @@ class MSSqlFormatter extends SqlFormatter { if (order == null) { return 'ROW_NUMBER() OVER(ORDER BY (SELECT NULL))'; } - return util.format('ROW_NUMBER() OVER(%s)', this.format(order, '%o')); + return sprintf('ROW_NUMBER() OVER(%s)', this.format(order, '%o')); + } + + $year(p0) { + return sprintf('DATEPART(year, %s)', this.escape(p0)); + } + + $month(p0) { + return sprintf('DATEPART(month, %s)', this.escape(p0)); + } + + $dayOfMonth(p0) { + return sprintf('DATEPART(day, %s)', this.escape(p0)); } + + $day(p0) { + return this.$dayOfMonth(p0); + } + + $hour(p0) { + return sprintf('DATEPART(hour, %s)', this.escape(p0)); + } + + $minute(p0) { + return sprintf('DATEPART(minute, %s)', this.escape(p0)); + } + + $minutes(p0) { + return this.$minute(p0); + } + + $second(p0) { + return sprintf('DATEPART(second, %s)', this.escape(p0)); + } + + $seconds(p0) { + return this.$second(p0); + } + } export {