Close #261
This commit is contained in:
Steve Faulkner 2019-05-21 14:50:54 -04:00 коммит произвёл GitHub
Родитель 9855c8dc4a
Коммит 9bac54c4ac
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
30 изменённых файлов: 931 добавлений и 1566 удалений

216
package-lock.json сгенерированный
Просмотреть файл

@ -12,6 +12,26 @@
"crypto-js": "3.1.9-1"
}
},
"@babel/code-frame": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz",
"integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==",
"dev": true,
"requires": {
"@babel/highlight": "^7.0.0"
}
},
"@babel/highlight": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0.tgz",
"integrity": "sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw==",
"dev": true,
"requires": {
"chalk": "^2.0.0",
"esutils": "^2.0.2",
"js-tokens": "^4.0.0"
}
},
"@microsoft/api-extractor": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/@microsoft/api-extractor/-/api-extractor-6.3.0.tgz",
@ -189,9 +209,9 @@
"dev": true
},
"@types/events": {
"version": "1.2.0",
"resolved": "http://registry.npmjs.org/@types/events/-/events-1.2.0.tgz",
"integrity": "sha512-KEIlhXnIutzKwRbQkGWb/I4HFqBuUykAdHgDED6xqwXJfONCjF5VoE0cXEiurh3XauygxzeDzgtXUqvLkxFzzA==",
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz",
"integrity": "sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==",
"dev": true
},
"@types/fast-json-stable-stringify": {
@ -221,10 +241,13 @@
}
},
"@types/handlebars": {
"version": "4.0.39",
"resolved": "https://registry.npmjs.org/@types/handlebars/-/handlebars-4.0.39.tgz",
"integrity": "sha512-vjaS7Q0dVqFp85QhyPSZqDKnTTCemcSHNHFvDdalO1s0Ifz5KuE64jQD5xoUkfdWwF4WpqdJEl7LsWH8rzhKJA==",
"dev": true
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/@types/handlebars/-/handlebars-4.1.0.tgz",
"integrity": "sha512-gq9YweFKNNB1uFK71eRqsd4niVkXrxHugqWFQkeLRJvGjnxsLr16bYtcsG4tOFwmYi0Bax+wCkbf1reUfdl4kA==",
"dev": true,
"requires": {
"handlebars": "*"
}
},
"@types/highlight.js": {
"version": "9.12.3",
@ -233,9 +256,9 @@
"dev": true
},
"@types/lodash": {
"version": "4.14.117",
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.117.tgz",
"integrity": "sha512-xyf2m6tRbz8qQKcxYZa7PA4SllYcay+eh25DN3jmNYY6gSTL7Htc/bttVdkqj2wfJGbeWlQiX8pIyJpKU+tubw==",
"version": "4.14.129",
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.129.tgz",
"integrity": "sha512-oYaV0eSlnOacOr7i4X1FFdH8ttSlb57gu3I9MuStIv2CYkISEY84dNHYsC3bF6sNH7qYcu1BtVrCtQ8Q4KPTfQ==",
"dev": true
},
"@types/marked": {
@ -284,9 +307,9 @@
"dev": true
},
"@types/shelljs": {
"version": "0.8.0",
"resolved": "https://registry.npmjs.org/@types/shelljs/-/shelljs-0.8.0.tgz",
"integrity": "sha512-vs1hCC8RxLHRu2bwumNyYRNrU3o8BtZhLysH5A4I98iYmA2APl6R3uNQb5ihl+WiwH0xdC9LLO+vRrXLs/Kyxg==",
"version": "0.8.5",
"resolved": "https://registry.npmjs.org/@types/shelljs/-/shelljs-0.8.5.tgz",
"integrity": "sha512-bZgjwIWu9gHCjirKJoOlLzGi5N0QgZ5t7EXEuoqyWCHTuSddURXo3FOBYDyRPNOWzZ6NbkLvZnVkn483Y/tvcQ==",
"dev": true,
"requires": {
"@types/glob": "*",
@ -354,18 +377,6 @@
"es6-promisify": "^5.0.0"
}
},
"ansi-regex": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
"dev": true
},
"ansi-styles": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
"integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
"dev": true
},
"anymatch": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz",
@ -497,32 +508,6 @@
"integrity": "sha1-ri1acpR38onWDdf5amMUoi3Wwio=",
"dev": true
},
"babel-code-frame": {
"version": "6.26.0",
"resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz",
"integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=",
"dev": true,
"requires": {
"chalk": "^1.1.3",
"esutils": "^2.0.2",
"js-tokens": "^3.0.2"
},
"dependencies": {
"chalk": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
"dev": true,
"requires": {
"ansi-styles": "^2.2.1",
"escape-string-regexp": "^1.0.2",
"has-ansi": "^2.0.0",
"strip-ansi": "^3.0.0",
"supports-color": "^2.0.0"
}
}
}
},
"babel-runtime": {
"version": "6.26.0",
"resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
@ -2396,9 +2381,9 @@
"dev": true
},
"handlebars": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.1.1.tgz",
"integrity": "sha512-3Zhi6C0euYZL5sM0Zcy7lInLXKQ+YLcF/olbN010mzGQ4XVm50JeyBnMqofHh696GrciGruC7kCcApPDJvVgwA==",
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.1.2.tgz",
"integrity": "sha512-nvfrjqvt9xQ8Z/w0ijewdD/vvWDTOweBUm96NTr66Wfvo1mJenBLwcYmPs3TIBP5ruzYGD7Hx/DaM9RmhroGPw==",
"dev": true,
"requires": {
"neo-async": "^2.6.0",
@ -2407,15 +2392,6 @@
"uglify-js": "^3.1.4"
}
},
"has-ansi": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
"integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=",
"dev": true,
"requires": {
"ansi-regex": "^2.0.0"
}
},
"has-binary2": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz",
@ -2536,9 +2512,9 @@
"dev": true
},
"highlight.js": {
"version": "9.13.1",
"resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.13.1.tgz",
"integrity": "sha512-Sc28JNQNDzaH6PORtRLMvif9RSn1mYuOoX3omVjnb0+HbpPygU2ALBI0R/wsiqCb4/fcp07Gdo8g+fhtFrQl6A==",
"version": "9.15.6",
"resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.15.6.tgz",
"integrity": "sha512-zozTAWM1D6sozHo8kqhfYgsac+B+q0PmsjXeyDrYIHHcBN0zTVT66+s2GW1GZv7DbyaROdLXKdabwS/WqPyIdQ==",
"dev": true
},
"homedir-polyfill": {
@ -2631,9 +2607,9 @@
"dev": true
},
"interpret": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/interpret/-/interpret-1.1.0.tgz",
"integrity": "sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ=",
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/interpret/-/interpret-1.2.0.tgz",
"integrity": "sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==",
"dev": true
},
"ip": {
@ -2798,15 +2774,15 @@
"dev": true
},
"js-tokens": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz",
"integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=",
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
"dev": true
},
"js-yaml": {
"version": "3.13.0",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.0.tgz",
"integrity": "sha512-pZZoSxcCYco+DIKBTimr67J6Hy+EYGZDY/HCWC+iAEA9h1ByhMXAIVUXMcMFpOCxQ/xjXmPI2MkDL5HRm5eFrQ==",
"version": "3.13.1",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz",
"integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==",
"dev": true,
"requires": {
"argparse": "^1.0.7",
@ -3456,9 +3432,9 @@
"dev": true
},
"neo-async": {
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.0.tgz",
"integrity": "sha512-MFh0d/Wa7vkKO3Y3LlacqAEeHK0mckVqzDieUKTT+KGxi+zIpeVsFxymkIiRpbpDziHc290Xr9A1O4Om7otoRA==",
"version": "2.6.1",
"resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz",
"integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==",
"dev": true
},
"netmask": {
@ -3793,7 +3769,7 @@
"prettier": {
"version": "1.14.3",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-1.14.3.tgz",
"integrity": "sha1-kCON1MBoS37c5fg7D7cyjki9CJU=",
"integrity": "sha512-qZDVnCrnpsRJJq5nSsiHCE3BYMED2OtsI+cmzIzF1QIfqm5ALf8tEJcO27zV1gKNKRPdhjO0dNWnrzssDQ1tFg==",
"dev": true
},
"priorityqueuejs": {
@ -3808,9 +3784,9 @@
"dev": true
},
"progress": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/progress/-/progress-2.0.1.tgz",
"integrity": "sha512-OE+a6vzqazc+K6LxJrX5UPyKFvGnL5CYmq2jFGNIBWHpc4QyE49/YOumcrpQFJpfejmvRtbJzgO1zPmMCqlbBg==",
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
"integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==",
"dev": true
},
"proxy-agent": {
@ -4148,9 +4124,9 @@
"dev": true
},
"shelljs": {
"version": "0.8.2",
"resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.2.tgz",
"integrity": "sha512-pRXeNrCA2Wd9itwhvLp5LZQvPJ0wU6bcjaTMywHHGX5XWhVN2nzSu7WV0q+oUY7mGK3mgSkDDzP3MgjqdyIgbQ==",
"version": "0.8.3",
"resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.3.tgz",
"integrity": "sha512-fc0BKlAWiLpwZljmOvAOTE/gXawtCoNrP5oaY7KIaQbbyHeQVg01pSEuEGvGh3HEdBU4baCD7wQBwADmM/7f7A==",
"dev": true,
"requires": {
"glob": "^7.0.0",
@ -4498,27 +4474,12 @@
"safe-buffer": "~5.1.0"
}
},
"strip-ansi": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
"dev": true,
"requires": {
"ansi-regex": "^2.0.0"
}
},
"strip-eof": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz",
"integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=",
"dev": true
},
"supports-color": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
"integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
"dev": true
},
"thunkify": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/thunkify/-/thunkify-2.1.2.tgz",
@ -4621,23 +4582,24 @@
"integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ=="
},
"tslint": {
"version": "5.11.0",
"resolved": "https://registry.npmjs.org/tslint/-/tslint-5.11.0.tgz",
"integrity": "sha1-mPMMAurjzecAYgHkwzywi0hYHu0=",
"version": "5.16.0",
"resolved": "https://registry.npmjs.org/tslint/-/tslint-5.16.0.tgz",
"integrity": "sha512-UxG2yNxJ5pgGwmMzPMYh/CCnCnh0HfPgtlVRDs1ykZklufFBL1ZoTlWFRz2NQjcoEiDoRp+JyT0lhBbbH/obyA==",
"dev": true,
"requires": {
"babel-code-frame": "^6.22.0",
"@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.7.0",
"js-yaml": "^3.13.0",
"minimatch": "^3.0.4",
"mkdirp": "^0.5.1",
"resolve": "^1.3.2",
"semver": "^5.3.0",
"tslib": "^1.8.0",
"tsutils": "^2.27.2"
"tsutils": "^2.29.0"
}
},
"tslint-config-prettier": {
@ -4681,9 +4643,9 @@
}
},
"typedoc": {
"version": "0.13.0",
"resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.13.0.tgz",
"integrity": "sha512-jQWtvPcV+0fiLZAXFEe70v5gqjDO6pJYJz4mlTtmGJeW2KRoIU/BEfktma6Uj8Xii7UakuZjbxFewl3UYOkU/w==",
"version": "0.14.2",
"resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.14.2.tgz",
"integrity": "sha512-aEbgJXV8/KqaVhcedT7xG6d2r+mOvB5ep3eIz1KuB5sc4fDYXcepEEMdU7XSqLFO5hVPu0nllHi1QxX2h/QlpQ==",
"dev": true,
"requires": {
"@types/fs-extra": "^5.0.3",
@ -4695,26 +4657,20 @@
"@types/shelljs": "^0.8.0",
"fs-extra": "^7.0.0",
"handlebars": "^4.0.6",
"highlight.js": "^9.0.0",
"highlight.js": "^9.13.1",
"lodash": "^4.17.10",
"marked": "^0.4.0",
"minimatch": "^3.0.0",
"progress": "^2.0.0",
"shelljs": "^0.8.2",
"typedoc-default-themes": "^0.5.0",
"typescript": "3.1.x"
"typescript": "3.2.x"
},
"dependencies": {
"lodash": {
"version": "4.17.11",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
"integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==",
"dev": true
},
"typescript": {
"version": "3.1.6",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.1.6.tgz",
"integrity": "sha512-tDMYfVtvpb96msS1lDX9MEdHrW4yOuZ4Kdc4Him9oU796XldPYF/t2+uKoX0BBa0hXXwDlqYQbXY5Rzjzc5hBA==",
"version": "3.2.4",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.2.4.tgz",
"integrity": "sha512-0RNDbSdEokBeEAkgNbxJ+BLwSManFy9TeXz8uW+48j/xhEXv1ePME60olyzw2XzUqUBNAYFeJadIqAgNqIACwg==",
"dev": true
}
}
@ -4726,26 +4682,26 @@
"dev": true
},
"typescript": {
"version": "3.4.1",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.4.1.tgz",
"integrity": "sha512-3NSMb2VzDQm8oBTLH6Nj55VVtUEpe/rgkIzMir0qVoLyjDZlnMBva0U6vDiV3IH+sl/Yu6oP5QwsAQtHPmDd2Q==",
"version": "3.4.5",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.4.5.tgz",
"integrity": "sha512-YycBxUb49UUhdNMU5aJ7z5Ej2XGmaIBL0x34vZ82fn3hGvD+bgrMrVDpatgz2f7YxUMJxMkbWxJZeAvDxVe7Vw==",
"dev": true
},
"uglify-js": {
"version": "3.4.9",
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.9.tgz",
"integrity": "sha512-8CJsbKOtEbnJsTyv6LE6m6ZKniqMiFWmm9sRbopbkGs3gMPPfd3Fh8iIA4Ykv5MgaTbqHr4BaoGLJLZNhsrW1Q==",
"version": "3.5.12",
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.5.12.tgz",
"integrity": "sha512-KeQesOpPiZNgVwJj8Ge3P4JYbQHUdZzpx6Fahy6eKAYRSV4zhVmLXoC+JtOeYxcHCHTve8RG1ZGdTvpeOUM26Q==",
"dev": true,
"optional": true,
"requires": {
"commander": "~2.17.1",
"commander": "~2.20.0",
"source-map": "~0.6.1"
},
"dependencies": {
"commander": {
"version": "2.17.1",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz",
"integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==",
"version": "2.20.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz",
"integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==",
"dev": true,
"optional": true
}

Просмотреть файл

@ -71,10 +71,10 @@
"sinon": "7.2.7",
"source-map-support": "0.5.11",
"ts-node": "^8.0.2",
"tslint": "5.11.0",
"tslint": "5.16.0",
"tslint-config-prettier": "^1.14.0",
"typedoc": "0.13.0",
"typescript": "3.4.1"
"typedoc": "0.14.2",
"typescript": "3.4.5"
},
"dependencies": {
"@azure/cosmos-sign": "1.0.2",

Просмотреть файл

@ -99,7 +99,7 @@ export class Container {
* @example Replace an item
* const {body: replacedItem} = await container.item("<item id>").replace({id: "<item id>", title: "Updated post", authorID: 5});
*/
public item(id: string, partitionKey?: string): Item {
public item(id: string, partitionKey: any): Item {
return new Item(this, id, partitionKey, this.clientContext);
}

Просмотреть файл

@ -1,5 +1,7 @@
import { ClientContext } from "../../ClientContext";
import { Constants, getIdFromLink, getPathFromLink, isResourceValid, ResourceType, StatusCodes } from "../../common";
import { DEFAULT_PARTITION_KEY_PATH } from "../../common/partitionKeys";
import { PartitionKind } from "../../documents";
import { mergeHeaders, SqlQuerySpec } from "../../queryExecutionContext";
import { QueryIterator } from "../../queryIterator";
import { FeedOptions, RequestOptions } from "../../request";
@ -105,6 +107,14 @@ export class Containers {
delete body.throughput;
}
// If they don't specify a partition key, use the default path
if (!body.partitionKey || !body.partitionKey.paths) {
body.partitionKey = {
kind: PartitionKind.Hash,
paths: [DEFAULT_PARTITION_KEY_PATH]
};
}
const response = await this.clientContext.create<ContainerRequest>(body, path, ResourceType.container, id, options);
const ref = new Container(this.database, response.result.id, this.clientContext);
return new ContainerResponse(response.result, response.headers, response.statusCode, ref);

Просмотреть файл

@ -1,6 +1,6 @@
import { ClientContext } from "../../ClientContext";
import { createDocumentUri, getIdFromLink, getPathFromLink, isResourceValid, ResourceType } from "../../common";
import { extractPartitionKey } from "../../extractPartitionKey";
import { extractPartitionKey, undefinedPartitionKey } from "../../extractPartitionKey";
import { RequestOptions } from "../../request";
import { Container } from "../Container";
import { ItemDefinition } from "./ItemDefinition";
@ -32,15 +32,6 @@ export class Item {
private readonly clientContext: ClientContext
) {}
/**
* Read the item's definition.
*
* There is no set schema for JSON items. They may contain any number of custom properties.
*
* @param options Additional options for the request, such as the partition key.
* Note, if you provide a partition key on the options object, it will override the primary key on `this.partitionKey`.
*/
public read(options?: RequestOptions): Promise<ItemResponse<ItemDefinition>>;
/**
* Read the item's definition.
*
@ -66,11 +57,15 @@ export class Item {
* ({body: item} = await item.read<TodoItem>());
* ```
*/
public read<T extends ItemDefinition>(options?: RequestOptions): Promise<ItemResponse<T>>;
public async read<T extends ItemDefinition>(options?: RequestOptions): Promise<ItemResponse<T>> {
public async read<T extends ItemDefinition = any>(options: RequestOptions = {}): Promise<ItemResponse<T>> {
options = options || {};
if ((!options || !options.partitionKey) && this.partitionKey !== undefined) {
options.partitionKey = this.partitionKey;
if (!options.partitionKey) {
if (this.partitionKey !== undefined) {
options.partitionKey = this.partitionKey;
} else {
const { resource: partitionKeyDefinition } = await this.container.getPartitionKeyDefinition();
options.partitionKey = undefinedPartitionKey(partitionKeyDefinition);
}
}
const path = getPathFromLink(this.url);
const id = getIdFromLink(this.url);
@ -100,12 +95,11 @@ export class Item {
* @param options Additional options for the request, such as the partition key.
*/
public replace<T extends ItemDefinition>(body: T, options?: RequestOptions): Promise<ItemResponse<T>>;
public async replace<T extends ItemDefinition>(body: T, options?: RequestOptions): Promise<ItemResponse<T>> {
options = options || {};
public async replace<T extends ItemDefinition>(body: T, options: RequestOptions = {}): Promise<ItemResponse<T>> {
if ((!options || !options.partitionKey) && this.partitionKey !== undefined) {
options.partitionKey = this.partitionKey;
}
if (options.partitionKey === undefined && options.skipGetPartitionKeyDefinition !== true) {
if (options.partitionKey === undefined) {
const { resource: partitionKeyDefinition } = await this.container.getPartitionKeyDefinition();
options.partitionKey = extractPartitionKey(body, partitionKeyDefinition);
}
@ -122,11 +116,6 @@ export class Item {
return new ItemResponse(response.result, response.headers, response.statusCode, this);
}
/**
* Delete the item.
* @param options Additional options for the request, such as the partition key.
*/
public delete(options?: RequestOptions): Promise<ItemResponse<ItemDefinition>>;
/**
* Delete the item.
*
@ -135,12 +124,16 @@ export class Item {
*
* @param options Additional options for the request, such as the partition key.
*/
public delete<T extends ItemDefinition>(options?: RequestOptions): Promise<ItemResponse<T>>;
public async delete<T extends ItemDefinition>(options?: RequestOptions): Promise<ItemResponse<T>> {
options = options || {};
if ((!options || !options.partitionKey) && this.partitionKey !== undefined) {
options.partitionKey = this.partitionKey;
public async delete<T extends ItemDefinition = any>(options: RequestOptions = {}): Promise<ItemResponse<T>> {
if (!options.partitionKey) {
if (this.partitionKey !== undefined) {
options.partitionKey = this.partitionKey;
} else {
const { resource: partitionKeyDefinition } = await this.container.getPartitionKeyDefinition();
options.partitionKey = undefinedPartitionKey(partitionKeyDefinition);
}
}
const path = getPathFromLink(this.url);
const id = getIdFromLink(this.url);

Просмотреть файл

@ -193,7 +193,7 @@ export class Items {
* @param options Used for modifying the request (for instance, specifying the partition key).
*/
public async create<T extends ItemDefinition = any>(body: T, options: RequestOptions = {}): Promise<ItemResponse<T>> {
if (options.partitionKey === undefined && options.skipGetPartitionKeyDefinition !== true) {
if (options.partitionKey === undefined) {
const { resource: partitionKeyDefinition } = await this.container.getPartitionKeyDefinition();
options.partitionKey = extractPartitionKey(body, partitionKeyDefinition);
}
@ -245,7 +245,7 @@ export class Items {
*/
public async upsert<T extends ItemDefinition>(body: T, options?: RequestOptions): Promise<ItemResponse<T>>;
public async upsert<T extends ItemDefinition>(body: T, options: RequestOptions = {}): Promise<ItemResponse<T>> {
if (options.partitionKey === undefined && options.skipGetPartitionKeyDefinition !== true) {
if (options.partitionKey === undefined) {
const { resource: partitionKeyDefinition } = await this.container.getPartitionKeyDefinition();
options.partitionKey = extractPartitionKey(body, partitionKeyDefinition);
}

Просмотреть файл

@ -164,7 +164,7 @@ export const Constants = {
ThrottleRetryCount: "x-ms-throttle-retry-count",
ThrottleRetryWaitTimeInMs: "x-ms-throttle-retry-wait-time-ms",
CurrentVersion: "2018-06-18",
CurrentVersion: "2018-12-31",
SDKName: "azure-cosmos-js",
SDKVersion: "REPLACE_SDK_VERSION",

Просмотреть файл

@ -0,0 +1,6 @@
/**
* The default path for the partition key if the user does not specify one on container create.
* @hidden
* @internal
*/
export const DEFAULT_PARTITION_KEY_PATH = "/_partitionKey";

Просмотреть файл

@ -2,10 +2,6 @@
* Specifies the supported Index types.
*/
export enum IndexKind {
/**
* This is supplied for a path which has no sorting requirement. This kind of an index has better precision than corresponding range index.
*/
Hash = "Hash",
/**
* This is supplied for a path which requires sorting.
*/

Просмотреть файл

@ -1,4 +1,4 @@
import { Point, Range } from "../range";
import { PartitionKeyDefinition } from "./PartitionKeyDefinition";
export type PartitionKey = PartitionKeyDefinition | Point | Range;
export type PartitionKey = PartitionKeyDefinition | Point | Range | {};

Просмотреть файл

@ -4,4 +4,5 @@ export interface PartitionKeyDefinition {
paths: string[];
kind: keyof typeof PartitionKind;
version?: number;
systemKey?: boolean;
}

Просмотреть файл

@ -9,14 +9,24 @@ export function extractPartitionKey(document: any, partitionKeyDefinition: Parti
let obj = document;
for (const part of pathParts) {
if (!(typeof obj === "object" && part in obj)) {
obj = {};
obj = undefined;
break;
}
obj = obj[part];
}
partitionKey.push(obj);
});
if (partitionKey.length === 1 && partitionKey[0] === undefined) {
return undefinedPartitionKey(partitionKeyDefinition);
}
return partitionKey;
}
return undefined;
}
export function undefinedPartitionKey(partitionKeyDefinition: PartitionKeyDefinition) {
if (partitionKeyDefinition.systemKey === true) {
return [];
} else {
return [{}];
}
}

Просмотреть файл

@ -11,7 +11,6 @@ import { Response as CosmosResponse } from "./Response";
import { TimeoutError } from "./TimeoutError";
/** @hidden */
export async function executeRequest(requestContext: RequestContext) {
return executePlugins(requestContext, httpRequest, PluginOn.request);
}

Просмотреть файл

@ -1,16 +1,13 @@
import assert from "assert";
import { Container, CosmosClient, Database, DatabaseDefinition, Item, RequestOptions, Response } from "../../dist-esm";
import { Container, CosmosClient, Database, DatabaseDefinition, RequestOptions, Response } from "../../dist-esm";
import {
ContainerDefinition,
ItemDefinition,
ItemResponse,
PermissionResponse,
Resource,
TriggerResponse,
User,
UserDefinedFunctionResponse
User
} from "../../dist-esm/client";
import { StoredProcedureResponse } from "../../dist-esm/client/StoredProcedure/StoredProcedureResponse";
import { UserResponse } from "../../dist-esm/client/User/UserResponse";
import { endpoint, masterKey } from "./_testConfig";
@ -79,25 +76,27 @@ export async function bulkInsertItems(
);
}
export async function bulkReadItems(container: Container, documents: any[], partitionKey: string) {
export async function bulkReadItems(container: Container, documents: any[], partitionKeyProperty: string) {
return await Promise.all(
documents.map(async document => {
const options =
partitionKey && document.hasOwnProperty(partitionKey)
? { partitionKey: document[partitionKey] }
: { partitionKey: {} };
const partitionKey = document.hasOwnProperty(partitionKeyProperty) ? document[partitionKeyProperty] : undefined;
// TODO: should we block or do all requests in parallel?
const { resource: doc } = await container.item(document.id).read(options);
const { resource: doc } = await container.item(document.id, partitionKey).read();
assert.deepStrictEqual(doc, document);
})
);
}
export async function bulkReplaceItems(container: Container, documents: any[]): Promise<any[]> {
export async function bulkReplaceItems(
container: Container,
documents: any[],
partitionKeyProperty: string
): Promise<any[]> {
return Promise.all(
documents.map(async document => {
const { resource: doc } = await container.item(document.id).replace(document);
const partitionKey = document.hasOwnProperty(partitionKeyProperty) ? document[partitionKeyProperty] : undefined;
const { resource: doc } = await container.item(document.id, partitionKey).replace(document);
const { _etag: _1, _ts: _2, ...expectedModifiedDocument } = document;
const { _etag: _4, _ts: _3, ...actualModifiedDocument } = doc;
assert.deepStrictEqual(expectedModifiedDocument, actualModifiedDocument);
@ -106,15 +105,16 @@ export async function bulkReplaceItems(container: Container, documents: any[]):
);
}
export async function bulkDeleteItems(container: Container, documents: any[], partitionKey: string): Promise<void> {
export async function bulkDeleteItems(
container: Container,
documents: any[],
partitionKeyProperty: string
): Promise<void> {
await Promise.all(
documents.map(async document => {
const options =
partitionKey && document.hasOwnProperty(partitionKey)
? { partitionKey: document[partitionKey] }
: { partitionKey: {} };
const partitionKey = document.hasOwnProperty(partitionKeyProperty) ? document[partitionKeyProperty] : undefined;
await container.item(document.id).delete(options);
await container.item(document.id, partitionKey).delete();
})
);
}
@ -172,7 +172,7 @@ export async function replaceOrUpsertItem(
if (isUpsertTest) {
return container.items.upsert(body, options);
} else {
return container.item(body.id).replace(body, options);
return container.item(body.id, undefined).replace(body, options);
}
}
@ -189,18 +189,6 @@ export function createOrUpsertUser(
return database.users.create(body, options);
}
}
export function replaceOrUpsertUser(
database: Database,
body: any,
options: any,
isUpsertTest: boolean
): Promise<UserResponse> {
if (isUpsertTest) {
return database.users.upsert(body, options);
} else {
return database.user(body.id).replace(body, options);
}
}
export function createOrUpsertPermission(
user: User,
@ -227,81 +215,3 @@ export function replaceOrUpsertPermission(
return user.permission(body.id).replace(body, options);
}
}
// Trigger
export function createOrUpsertTrigger(
container: Container,
body: any,
options: any,
isUpsertTest: boolean
): Promise<TriggerResponse> {
if (isUpsertTest) {
return container.scripts.triggers.upsert(body, options);
} else {
return container.scripts.triggers.create(body, options);
}
}
export function replaceOrUpsertTrigger(
container: Container,
body: any,
options: any,
isUpsertTest: boolean
): Promise<TriggerResponse> {
if (isUpsertTest) {
return container.scripts.triggers.upsert(body, options);
} else {
return container.scripts.trigger(body.id).replace(body, options);
}
}
// User Defined Function
export function createOrUpsertUserDefinedFunction(
container: Container,
body: any,
options: any,
isUpsertTest: boolean
): Promise<UserDefinedFunctionResponse> {
if (isUpsertTest) {
return container.scripts.userDefinedFunctions.upsert(body, options);
} else {
return container.scripts.userDefinedFunctions.create(body, options);
}
}
export function replaceOrUpsertUserDefinedFunction(
container: Container,
body: any,
options: any,
isUpsertTest: boolean
): Promise<UserDefinedFunctionResponse> {
if (isUpsertTest) {
return container.scripts.userDefinedFunctions.upsert(body, options);
} else {
return container.scripts.userDefinedFunction(body.id).replace(body, options);
}
}
// Stored Procedure
export function createOrUpsertStoredProcedure(
container: Container,
body: any,
options: any,
isUpsertTest: boolean
): Promise<StoredProcedureResponse> {
if (isUpsertTest) {
return container.scripts.storedProcedures.upsert(body, options);
} else {
return container.scripts.storedProcedures.create(body, options);
}
}
export function replaceOrUpsertStoredProcedure(
container: Container,
body: any,
options: any,
isUpsertTest: boolean
): Promise<StoredProcedureResponse> {
if (isUpsertTest) {
return container.scripts.storedProcedures.upsert(body, options);
} else {
return container.scripts.storedProcedure(body.id).replace(body, options);
}
}

Просмотреть файл

@ -160,7 +160,7 @@ describe("NodeJS CRUD Tests", function() {
const { resource: successDoc } = await col1Client
.database(entities.database.id)
.container(entities.coll1.id)
.item(entities.doc1.id)
.item(entities.doc1.id, undefined)
.read();
assert(successDoc !== undefined, "error reading document");
assert.equal(successDoc.id, entities.doc1.id, "Expected to read children using parent permissions");

Просмотреть файл

@ -5,166 +5,134 @@ import { ContainerRequest } from "../../dist-esm/client/Container/ContainerReque
import { DataType, Index, IndexedPath, IndexingMode, IndexingPolicy, IndexKind } from "../../dist-esm/documents";
import { getTestDatabase, removeAllDatabases } from "../common/TestHelpers";
describe("NodeJS CRUD Tests", function() {
describe("Containers", function() {
this.timeout(process.env.MOCHA_TIMEOUT || 10000);
beforeEach(async function() {
await removeAllDatabases();
});
describe("Validate Container CRUD", function() {
const containerCRUDTest = async function(hasPartitionKey: boolean) {
describe("Container CRUD", function() {
const containerCRUDTest = async function(partitionKey?: string) {
// create database
const database = await getTestDatabase("Validate Container CRUD");
// create a container
const containerDefinition: ContainerRequest = {
id: "sample container",
indexingPolicy: { indexingMode: IndexingMode.consistent },
throughput: 400
};
if (partitionKey) {
containerDefinition.partitionKey = { paths: [partitionKey], kind: PartitionKind.Hash };
}
const { resource: containerDef } = await database.containers.create(containerDefinition);
const container = database.container(containerDef.id);
assert.equal(containerDefinition.id, containerDef.id);
assert.equal("consistent", containerDef.indexingPolicy.indexingMode);
if (containerDef.partitionKey) {
assert.equal(containerDef.partitionKey.kind, containerDefinition.partitionKey.kind);
assert.deepEqual(containerDef.partitionKey.paths, containerDefinition.partitionKey.paths);
}
// read containers after creation
const { resources: containers } = await database.containers.readAll().fetchAll();
assert.equal(containers.length, 1, "create should increase the number of containers");
// query containers
const querySpec = {
query: "SELECT * FROM root r WHERE r.id=@id",
parameters: [
{
name: "@id",
value: containerDefinition.id
}
]
};
const { resources: results } = await database.containers.query(querySpec).fetchAll();
assert(results.length > 0, "number of results for the query should be > 0");
const { resources: ranges } = await container.readPartitionKeyRanges().fetchAll();
assert(ranges.length > 0, "container should have at least 1 partition");
// Replacing indexing policy is allowed.
containerDef.indexingPolicy.indexingMode = IndexingMode.lazy;
const { resource: replacedContainer } = await container.replace(containerDef);
assert.equal("lazy", replacedContainer.indexingPolicy.indexingMode);
// Replacing partition key is not allowed.
try {
// create database
const database = await getTestDatabase("Validate Container CRUD");
// create a container
const containerDefinition: ContainerRequest = {
id: "sample container",
indexingPolicy: { indexingMode: IndexingMode.consistent },
throughput: 400
};
if (hasPartitionKey) {
containerDefinition.partitionKey = { paths: ["/id"], kind: PartitionKind.Hash };
}
const { resource: containerDef } = await database.containers.create(containerDefinition);
const container = database.container(containerDef.id);
assert.equal(containerDefinition.id, containerDef.id);
assert.equal("consistent", containerDef.indexingPolicy.indexingMode);
if (containerDef.partitionKey) {
assert.equal(containerDef.partitionKey.kind, containerDefinition.partitionKey.kind);
assert.deepEqual(containerDef.partitionKey.paths, containerDefinition.partitionKey.paths);
}
// read containers after creation
const { resources: containers } = await database.containers.readAll().fetchAll();
assert.equal(containers.length, 1, "create should increase the number of containers");
// query containers
const querySpec = {
query: "SELECT * FROM root r WHERE r.id=@id",
parameters: [
{
name: "@id",
value: containerDefinition.id
}
]
};
const { resources: results } = await database.containers.query(querySpec).fetchAll();
assert(results.length > 0, "number of results for the query should be > 0");
const { resources: ranges } = await container.readPartitionKeyRanges().fetchAll();
assert(ranges.length > 0, "container should have at least 1 partition");
// Replacing indexing policy is allowed.
containerDef.indexingPolicy.indexingMode = IndexingMode.lazy;
const { resource: replacedContainer } = await container.replace(containerDef);
assert.equal("lazy", replacedContainer.indexingPolicy.indexingMode);
// Replacing partition key is not allowed.
try {
containerDef.partitionKey = { paths: ["/key"], kind: PartitionKind.Hash };
await container.replace(containerDef);
assert.fail("Replacing paritionkey must throw");
} catch (err) {
const badRequestErrorCode = 400;
assert.equal(err.code, badRequestErrorCode, "response should return error code " + badRequestErrorCode);
} finally {
containerDef.partitionKey = containerDefinition.partitionKey; // Resume partition key
}
// Replacing id is not allowed.
try {
containerDef.id = "try_to_replace_id";
await container.replace(containerDef);
assert.fail("Replacing container id must throw");
} catch (err) {
const notFoundErrorCode = 400;
assert.equal(err.code, notFoundErrorCode, "response should return error code 404");
}
// read container
containerDef.id = containerDefinition.id; // Resume Id.
const { resource: readcontainer } = await container.read();
assert.equal(containerDefinition.id, readcontainer.id);
// delete container
await container.delete();
// read container after deletion
try {
await container.read();
assert.fail("Must fail to read container after delete");
} catch (err) {
const notFoundErrorCode = 404;
assert.equal(err.code, notFoundErrorCode, "response should return error code 404");
}
containerDef.partitionKey = { paths: ["/key"], kind: PartitionKind.Hash };
await container.replace(containerDef);
assert.fail("Replacing paritionkey must throw");
} catch (err) {
throw err;
const badRequestErrorCode = 400;
assert.equal(err.code, badRequestErrorCode, "response should return error code " + badRequestErrorCode);
} finally {
containerDef.partitionKey = containerDefinition.partitionKey; // Resume partition key
}
// Replacing id is not allowed.
try {
containerDef.id = "try_to_replace_id";
await container.replace(containerDef);
assert.fail("Replacing container id must throw");
} catch (err) {
const notFoundErrorCode = 400;
assert.equal(err.code, notFoundErrorCode, "response should return error code 404");
}
// read container
containerDef.id = containerDefinition.id; // Resume Id.
const { resource: readcontainer } = await container.read();
assert.equal(containerDefinition.id, readcontainer.id);
// delete container
await container.delete();
// read container after deletion
try {
await container.read();
assert.fail("Must fail to read container after delete");
} catch (err) {
const notFoundErrorCode = 404;
assert.equal(err.code, notFoundErrorCode, "response should return error code 404");
}
};
const badPartitionKeyDefinitionTest = async function(isNameBased: boolean) {
try {
// create database
const database = await getTestDatabase("container CRUD bad partition key");
// create a container
const badPartitionKeyDefinition: any = {
paths: "/id", // This is invalid. Must be an array.
kind: PartitionKind.Hash
};
const containerDefinition: ContainerDefinition = {
id: "sample container",
indexingPolicy: { indexingMode: IndexingMode.consistent },
partitionKey: badPartitionKeyDefinition // This is invalid, forced using type coersion
};
try {
await database.containers.create(containerDefinition);
} catch (err) {
assert.equal(err.code, 400);
}
} catch (err) {
throw err;
}
};
it("nativeApi Should do container CRUD operations successfully name based", async function() {
try {
await containerCRUDTest(false);
} catch (err) {
throw err;
}
it("Default partition key", async function() {
await containerCRUDTest();
});
it("nativeApi Should do elastic container CRUD operations successfully name based", async function() {
try {
await containerCRUDTest(true);
} catch (err) {
throw err;
}
it("Custom partition key", async function() {
await containerCRUDTest("/id");
});
it("nativeApi container with bad partition key definition name based", async function() {
try {
await badPartitionKeyDefinitionTest(true);
} catch (err) {
throw err;
}
});
it("Bad partition key definition", async function() {
// create database
const database = await getTestDatabase("container CRUD bad partition key");
// create a container
const badPartitionKeyDefinition: any = {
paths: "/id", // This is invalid. Must be an array.
kind: PartitionKind.Hash
};
const containerDefinition: ContainerDefinition = {
id: "sample container",
indexingPolicy: { indexingMode: IndexingMode.consistent },
partitionKey: badPartitionKeyDefinition // This is invalid, forced using type coersion
};
it("nativeApi container with bad partition key definition name based", async function() {
try {
await badPartitionKeyDefinitionTest(false);
await database.containers.create(containerDefinition);
} catch (err) {
throw err;
assert.equal(err.code, 400);
}
});
});
describe("Validate container indexing policy", function() {
it("nativeApi Should create container with correct indexing policy name based", async function() {
describe("Indexing policy", function() {
it("Create container with correct indexing policy", async function() {
// create database
const database = await getTestDatabase("container test database");
@ -223,14 +191,7 @@ describe("NodeJS CRUD Tests", function() {
indexingMode: IndexingMode.consistent,
includedPaths: [
{
path: "/",
indexes: [
{
kind: IndexKind.Hash,
dataType: DataType.Number,
precision: 2
}
]
path: "/*"
}
],
excludedPaths: [
@ -250,12 +211,7 @@ describe("NodeJS CRUD Tests", function() {
"Unexpected includedPaths length"
);
// The first included path is what we created.
assert.equal("/", containerWithIndexingPolicyDef.indexingPolicy.includedPaths[0].path);
// Backend adds a default index
assert(containerWithIndexingPolicyDef.indexingPolicy.includedPaths[0].indexes.length > 1);
assert.equal(IndexKind.Range, containerWithIndexingPolicyDef.indexingPolicy.includedPaths[0].indexes[0].kind);
// The second included path is a timestamp index created by the server.
assert.equal("/*", containerWithIndexingPolicyDef.indexingPolicy.includedPaths[0].path);
// And two excluded paths.
assert.equal(
2,
@ -275,141 +231,113 @@ describe("NodeJS CRUD Tests", function() {
}
assert(rootIncludedPath); // root path should exist.
// In the root path, there should be two indexes. One for Strings and one for Numbers.
assert.equal(2, rootIncludedPath["indexes"].length);
};
it("Create container with default indexing policy", async function() {
// create database
const database = await getTestDatabase("container test database");
const defaultIndexingPolicyTest = async function() {
try {
// create database
const database = await getTestDatabase("container test database");
// create container with no indexing policy specified.
const containerDefinition01: ContainerDefinition = { id: "TestCreateDefaultPolicy01" };
const { resource: containerNoIndexPolicyDef } = await database.containers.create(containerDefinition01);
checkDefaultIndexingPolicyPaths(containerNoIndexPolicyDef["indexingPolicy"]);
// create container with no indexing policy specified.
const containerDefinition01: ContainerDefinition = { id: "TestCreateDefaultPolicy01" };
const { resource: containerNoIndexPolicyDef } = await database.containers.create(containerDefinition01);
checkDefaultIndexingPolicyPaths(containerNoIndexPolicyDef["indexingPolicy"]);
// create container with partial policy specified.
const containerDefinition02: ContainerDefinition = {
id: "TestCreateDefaultPolicy02",
indexingPolicy: {
indexingMode: IndexingMode.lazy,
automatic: true
}
};
// create container with partial policy specified.
const containerDefinition02: ContainerDefinition = {
id: "TestCreateDefaultPolicy02",
indexingPolicy: {
indexingMode: IndexingMode.lazy,
automatic: true
}
};
const { resource: containerWithPartialPolicyDef } = await database.containers.create(containerDefinition02);
checkDefaultIndexingPolicyPaths((containerWithPartialPolicyDef as any)["indexingPolicy"]);
const { resource: containerWithPartialPolicyDef } = await database.containers.create(containerDefinition02);
checkDefaultIndexingPolicyPaths((containerWithPartialPolicyDef as any)["indexingPolicy"]);
// create container with default policy.
const containerDefinition03 = {
id: "TestCreateDefaultPolicy03",
indexingPolicy: {}
};
const { resource: containerDefaultPolicy } = await database.containers.create(containerDefinition03);
checkDefaultIndexingPolicyPaths((containerDefaultPolicy as any)["indexingPolicy"]);
// create container with default policy.
const containerDefinition03 = {
id: "TestCreateDefaultPolicy03",
indexingPolicy: {}
};
const { resource: containerDefaultPolicy } = await database.containers.create(containerDefinition03);
checkDefaultIndexingPolicyPaths((containerDefaultPolicy as any)["indexingPolicy"]);
// create container with indexing policy missing indexes.
const containerDefinition04 = {
id: "TestCreateDefaultPolicy04",
indexingPolicy: {
includedPaths: [
{
path: "/*"
}
]
}
};
const { resource: containerMissingIndexes } = await database.containers.create(containerDefinition04);
checkDefaultIndexingPolicyPaths((containerMissingIndexes as any)["indexingPolicy"]);
// create container with indexing policy missing indexes.
const containerDefinition04 = {
id: "TestCreateDefaultPolicy04",
indexingPolicy: {
includedPaths: [
{
path: "/*"
}
]
}
};
const { resource: containerMissingIndexes } = await database.containers.create(containerDefinition04);
checkDefaultIndexingPolicyPaths((containerMissingIndexes as any)["indexingPolicy"]);
// create container with indexing policy missing precision.
const containerDefinition05 = {
id: "TestCreateDefaultPolicy05",
indexingPolicy: {
includedPaths: [
{
path: "/*",
indexes: [
{
kind: IndexKind.Hash,
dataType: DataType.String
},
{
kind: IndexKind.Range,
dataType: DataType.Number
}
]
}
]
}
};
const { resource: containerMissingPrecision } = await database.containers.create(containerDefinition05);
checkDefaultIndexingPolicyPaths((containerMissingPrecision as any)["indexingPolicy"]);
} catch (err) {
throw err;
}
};
it("nativeApi Should create container with default indexing policy name based", async function() {
try {
await defaultIndexingPolicyTest();
} catch (err) {
throw err;
}
// create container with indexing policy missing precision.
const containerDefinition05 = {
id: "TestCreateDefaultPolicy05",
indexingPolicy: {
includedPaths: [
{
path: "/*",
indexes: [
{
kind: IndexKind.Range,
dataType: DataType.String
},
{
kind: IndexKind.Range,
dataType: DataType.Number
}
]
}
]
}
};
const { resource: containerMissingPrecision } = await database.containers.create(containerDefinition05);
checkDefaultIndexingPolicyPaths((containerMissingPrecision as any)["indexingPolicy"]);
});
});
describe("Validate response headers", function() {
const createThenReadcontainer = async function(database: Database, definition: ContainerDefinition) {
try {
const { container: createdcontainer, headers } = await database.containers.create(definition);
const response = await database.container(createdcontainer.id).read();
return response;
} catch (err) {
throw err;
}
const { container: createdcontainer, headers } = await database.containers.create(definition);
const response = await database.container(createdcontainer.id).read({ populateQuotaInfo: true });
return response;
};
const indexProgressHeadersTest = async function() {
try {
const database = await getTestDatabase("Validate response headers");
const { headers: headers1 } = await createThenReadcontainer(database, { id: "consistent_coll" });
assert.notEqual(headers1[Constants.HttpHeaders.IndexTransformationProgress], undefined);
assert.equal(headers1[Constants.HttpHeaders.LazyIndexingProgress], undefined);
const database = await getTestDatabase("Validate response headers");
const { headers: headers1 } = await createThenReadcontainer(database, { id: "consistent_coll" });
assert.notEqual(headers1[Constants.HttpHeaders.IndexTransformationProgress], undefined);
assert.equal(headers1[Constants.HttpHeaders.LazyIndexingProgress], undefined);
const lazyContainerDefinition = {
id: "lazy_coll",
indexingPolicy: { indexingMode: IndexingMode.lazy }
};
const { headers: headers2 } = await createThenReadcontainer(database, lazyContainerDefinition);
assert.notEqual(headers2[Constants.HttpHeaders.IndexTransformationProgress], undefined);
assert.notEqual(headers2[Constants.HttpHeaders.LazyIndexingProgress], undefined);
const lazyContainerDefinition = {
id: "lazy_coll",
indexingPolicy: { indexingMode: IndexingMode.lazy }
};
const { headers: headers2 } = await createThenReadcontainer(database, lazyContainerDefinition);
assert.notEqual(headers2[Constants.HttpHeaders.IndexTransformationProgress], undefined);
assert.notEqual(headers2[Constants.HttpHeaders.LazyIndexingProgress], undefined);
const noneContainerDefinition = {
id: "none_coll",
indexingPolicy: { indexingMode: IndexingMode.none, automatic: false }
};
const { headers: headers3 } = await createThenReadcontainer(database, noneContainerDefinition);
assert.notEqual(headers3[Constants.HttpHeaders.IndexTransformationProgress], undefined);
assert.equal(headers3[Constants.HttpHeaders.LazyIndexingProgress], undefined);
} catch (err) {
throw err;
}
const noneContainerDefinition = {
id: "none_coll",
indexingPolicy: { indexingMode: IndexingMode.none, automatic: false }
};
const { headers: headers3 } = await createThenReadcontainer(database, noneContainerDefinition);
assert.notEqual(headers3[Constants.HttpHeaders.IndexTransformationProgress], undefined);
assert.equal(headers3[Constants.HttpHeaders.LazyIndexingProgress], undefined);
};
it("nativeApi Validate index progress headers name based", async function() {
try {
await indexProgressHeadersTest();
} catch (err) {
throw err;
}
await indexProgressHeadersTest();
});
});
});
describe("containers.createIfNotExists", function() {
describe("createIfNotExists", function() {
let database: Database;
before(async function() {
// create database

Просмотреть файл

@ -25,170 +25,171 @@ interface TestItem {
replace?: string;
}
describe("NodeJS CRUD Tests", function() {
describe("Item CRUD", function() {
this.timeout(process.env.MOCHA_TIMEOUT || 10000);
beforeEach(async function() {
await removeAllDatabases();
});
const documentCRUDTest = async function(isUpsertTest: boolean) {
// create database
const database = await getTestDatabase("sample 中文 database");
// create container
const { resource: containerdef } = await database.containers.create({ id: "sample container" });
const container: Container = database.container(containerdef.id);
describe("Validate Document CRUD", function() {
const documentCRUDTest = async function(isUpsertTest: boolean) {
// create database
const database = await getTestDatabase("sample 中文 database");
// create container
const { resource: containerdef } = await database.containers.create({ id: "sample container" });
const container: Container = database.container(containerdef.id);
// read items
const { resources: items } = await container.items.readAll().fetchAll();
assert(Array.isArray(items), "Value should be an array");
// read items
const { resources: items } = await container.items.readAll().fetchAll();
assert(Array.isArray(items), "Value should be an array");
// create an item
const beforeCreateDocumentsCount = items.length;
const itemDefinition: TestItem = {
name: "sample document",
foo: "bar",
key: "value",
replace: "new property"
};
try {
await createOrUpsertItem(container, itemDefinition, { disableAutomaticIdGeneration: true }, isUpsertTest);
assert.fail("id generation disabled must throw with invalid id");
} catch (err) {
assert(err !== undefined, "should throw an error because automatic id generation is disabled");
}
const { resource: document } = await createOrUpsertItem(container, itemDefinition, undefined, isUpsertTest);
assert.equal(document.name, itemDefinition.name);
assert(document.id !== undefined);
// read documents after creation
const { resources: documents2 } = await container.items.readAll({ enableCrossPartitionQuery: true }).fetchAll();
assert.equal(documents2.length, beforeCreateDocumentsCount + 1, "create should increase the number of documents");
// query documents
const querySpec = {
query: "SELECT * FROM root r WHERE r.id=@id",
parameters: [
{
name: "@id",
value: document.id
}
]
};
const { resources: results } = await container.items
.query(querySpec, { enableCrossPartitionQuery: true })
.fetchAll();
assert(results.length > 0, "number of results for the query should be > 0");
const { resources: results2 } = await container.items
.query(querySpec, { enableCrossPartitionQuery: true })
.fetchAll();
assert(results2.length > 0, "number of results for the query should be > 0");
// create an item
const beforeCreateDocumentsCount = items.length;
const itemDefinition: TestItem = {
name: "sample document",
foo: "bar",
key: "value",
replace: "new property"
};
try {
await createOrUpsertItem(container, itemDefinition, { disableAutomaticIdGeneration: true }, isUpsertTest);
assert.fail("id generation disabled must throw with invalid id");
} catch (err) {
assert(err !== undefined, "should throw an error because automatic id generation is disabled");
}
const { resource: document } = await createOrUpsertItem(container, itemDefinition, undefined, isUpsertTest);
assert.equal(document.name, itemDefinition.name);
assert(document.id !== undefined);
// read documents after creation
const { resources: documents2 } = await container.items.readAll().fetchAll();
assert.equal(documents2.length, beforeCreateDocumentsCount + 1, "create should increase the number of documents");
// query documents
const querySpec = {
query: "SELECT * FROM root r WHERE r.id=@id",
parameters: [
{
name: "@id",
value: document.id
}
]
};
const { resources: results } = await container.items.query(querySpec).fetchAll();
assert(results.length > 0, "number of results for the query should be > 0");
const { resources: results2 } = await container.items.query(querySpec, { enableScanInQuery: true }).fetchAll();
assert(results2.length > 0, "number of results for the query should be > 0");
// replace document
document.name = "replaced document";
document.foo = "not bar";
const { resource: replacedDocument } = await replaceOrUpsertItem(container, document, undefined, isUpsertTest);
assert.equal(replacedDocument.name, "replaced document", "document name property should change");
assert.equal(replacedDocument.foo, "not bar", "property should have changed");
assert.equal(document.id, replacedDocument.id, "document id should stay the same");
// read document
const { resource: document2 } = await container.item(replacedDocument.id, undefined).read<TestItem>();
assert.equal(replacedDocument.id, document2.id);
// delete document
const { resource: res } = await container.item(replacedDocument.id, undefined).delete();
// replace document
document.name = "replaced document";
document.foo = "not bar";
const { resource: replacedDocument } = await replaceOrUpsertItem(container, document, undefined, isUpsertTest);
assert.equal(replacedDocument.name, "replaced document", "document name property should change");
assert.equal(replacedDocument.foo, "not bar", "property should have changed");
assert.equal(document.id, replacedDocument.id, "document id should stay the same");
// read document
const { resource: document2 } = await container.item(replacedDocument.id).read<TestItem>();
assert.equal(replacedDocument.id, document2.id);
// delete document
const { resource: res } = await container.item(replacedDocument.id).delete();
// read documents after deletion
try {
const { resource: document3 } = await container.item(replacedDocument.id, undefined).read();
assert.fail("must throw if document doesn't exist");
} catch (err) {
const notFoundErrorCode = 404;
assert.equal(err.code, notFoundErrorCode, "response should return error code 404");
}
};
// read documents after deletion
try {
const { resource: document3 } = await container.item(replacedDocument.id).read();
assert.fail("must throw if document doesn't exist");
} catch (err) {
const notFoundErrorCode = 404;
assert.equal(err.code, notFoundErrorCode, "response should return error code 404");
}
it("Should do document CRUD operations successfully", async function() {
await documentCRUDTest(false);
});
it("Should do document CRUD operations successfully with upsert", async function() {
await documentCRUDTest(true);
});
it("Should do document CRUD operations over multiple partitions", async function() {
// create database
const database = await getTestDatabase("db1");
const partitionKey = "key";
// create container
const containerDefinition = {
id: "coll1",
partitionKey: { paths: ["/" + partitionKey], kind: PartitionKind.Hash }
};
it("nativeApi Should do document CRUD operations successfully name based", async function() {
await documentCRUDTest(false);
const { resource: containerdef } = await database.containers.create(containerDefinition, {
offerThroughput: 12000
});
const container = database.container(containerdef.id);
it("nativeApi Should do document CRUD operations successfully name based with upsert", async function() {
await documentCRUDTest(true);
const documents = [
{ id: "document1" },
{ id: "document2", key: null, prop: 1 },
{ id: "document3", key: false, prop: 1 },
{ id: "document4", key: true, prop: 1 },
{ id: "document5", key: 1, prop: 1 },
{ id: "document6", key: "A", prop: 1 },
{ id: "document7", key: "", prop: 1 }
];
let returnedDocuments = await bulkInsertItems(container, documents);
assert.equal(returnedDocuments.length, documents.length);
returnedDocuments.sort(function(doc1, doc2) {
return doc1.id.localeCompare(doc2.id);
});
it("nativeApi Should do document CRUD operations over multiple partitions", async function() {
// create database
const database = await getTestDatabase("db1");
const partitionKey = "key";
// create container
const containerDefinition = {
id: "coll1",
partitionKey: { paths: ["/" + partitionKey], kind: PartitionKind.Hash }
};
const { resource: containerdef } = await database.containers.create(containerDefinition, {
offerThroughput: 12000
});
const container = database.container(containerdef.id);
const documents = [
{ id: "document1" },
{ id: "document2", key: null, prop: 1 },
{ id: "document3", key: false, prop: 1 },
{ id: "document4", key: true, prop: 1 },
{ id: "document5", key: 1, prop: 1 },
{ id: "document6", key: "A", prop: 1 },
{ id: "document7", key: "", prop: 1 }
];
let returnedDocuments = await bulkInsertItems(container, documents);
assert.equal(returnedDocuments.length, documents.length);
returnedDocuments.sort(function(doc1, doc2) {
return doc1.id.localeCompare(doc2.id);
});
await bulkReadItems(container, returnedDocuments, partitionKey);
const { resources: successDocuments } = await container.items.readAll().fetchAll();
assert(successDocuments !== undefined, "error reading documents");
assert.equal(
successDocuments.length,
returnedDocuments.length,
"Expected " + returnedDocuments.length + " documents to be succesfully read"
);
successDocuments.sort(function(doc1, doc2) {
return doc1.id.localeCompare(doc2.id);
});
assert.equal(
JSON.stringify(successDocuments),
JSON.stringify(returnedDocuments),
"Unexpected documents are returned"
);
returnedDocuments.forEach(function(document) {
document.prop ? ++document.prop : null;
});
const newReturnedDocuments = await bulkReplaceItems(container, returnedDocuments);
returnedDocuments = newReturnedDocuments;
await bulkQueryItemsWithPartitionKey(container, returnedDocuments, partitionKey);
const querySpec = {
query: "SELECT * FROM Root"
};
try {
const { resources: badUpdate } = await container.items.query(querySpec, { enableScanInQuery: true }).fetchAll();
assert.fail("Must fail");
} catch (err) {
const badRequestErrorCode = 400;
assert.equal(err.code, badRequestErrorCode, "response should return error code " + badRequestErrorCode);
}
const { resources: results } = await container.items
.query<ItemDefinition>(querySpec, { enableScanInQuery: true, enableCrossPartitionQuery: true })
.fetchAll();
assert(results !== undefined, "error querying documents");
results.sort(function(doc1, doc2) {
return doc1.id.localeCompare(doc2.id);
});
assert.equal(
results.length,
returnedDocuments.length,
"Expected " + returnedDocuments.length + " documents to be succesfully queried"
);
assert.equal(JSON.stringify(results), JSON.stringify(returnedDocuments), "Unexpected query results");
await bulkDeleteItems(container, returnedDocuments, partitionKey);
await bulkReadItems(container, returnedDocuments, partitionKey);
const { resources: successDocuments } = await container.items.readAll().fetchAll();
assert(successDocuments !== undefined, "error reading documents");
assert.equal(
successDocuments.length,
returnedDocuments.length,
"Expected " + returnedDocuments.length + " documents to be succesfully read"
);
successDocuments.sort(function(doc1, doc2) {
return doc1.id.localeCompare(doc2.id);
});
assert.equal(
JSON.stringify(successDocuments),
JSON.stringify(returnedDocuments),
"Unexpected documents are returned"
);
returnedDocuments.forEach(function(document) {
document.prop ? ++document.prop : null;
});
const newReturnedDocuments = await bulkReplaceItems(container, returnedDocuments, partitionKey);
returnedDocuments = newReturnedDocuments;
await bulkQueryItemsWithPartitionKey(container, returnedDocuments, partitionKey);
const querySpec = {
query: "SELECT * FROM Root"
};
try {
const { resources: badUpdate } = await container.items.query(querySpec, { enableScanInQuery: true }).fetchAll();
assert.fail("Must fail");
} catch (err) {
const badRequestErrorCode = 400;
assert.equal(err.code, badRequestErrorCode, "response should return error code " + badRequestErrorCode);
}
const { resources: results } = await container.items
.query<ItemDefinition>(querySpec, { enableScanInQuery: true, enableCrossPartitionQuery: true })
.fetchAll();
assert(results !== undefined, "error querying documents");
results.sort(function(doc1, doc2) {
return doc1.id.localeCompare(doc2.id);
});
assert.equal(
results.length,
returnedDocuments.length,
"Expected " + returnedDocuments.length + " documents to be succesfully queried"
);
assert.equal(JSON.stringify(results), JSON.stringify(returnedDocuments), "Unexpected query results");
await bulkDeleteItems(container, returnedDocuments, partitionKey);
});
});

Просмотреть файл

@ -0,0 +1,97 @@
import assert from "assert";
import { CosmosClient, Constants, Container } from "../../dist-esm";
import { removeAllDatabases, getTestContainer } from "../common/TestHelpers";
import { endpoint, masterKey } from "../common/_testConfig";
import { ResourceType, HTTPMethod } from "../../dist-esm/common";
const legacyClient = new CosmosClient({
endpoint,
key: masterKey,
plugins: [
{
on: "request",
plugin: (context, next) => {
// Intercepts the API request to create a non-partitioned container using an old API version
if (context.resourceType === ResourceType.container && context.method === HTTPMethod.post) {
context.body = JSON.stringify({ id: JSON.parse(context.body).id });
}
context.headers[Constants.HttpHeaders.Version] = "2018-06-18";
return next(context);
}
}
]
});
const client = new CosmosClient({
endpoint,
key: masterKey
});
describe("Non Partitioned Container", function() {
let container: Container;
before(async () => {
await removeAllDatabases();
const npContainer = await getTestContainer("Validate Container CRUD", legacyClient);
container = client.database(npContainer.database.id).container(npContainer.id);
});
it("should handle item CRUD", async () => {
// read items
const { resources: items } = await container.items.readAll().fetchAll();
assert(Array.isArray(items), "Value should be an array");
// create an item
const name = "sample document";
const { resource: item1 } = await container.items.create({
id: "a",
name,
foo: "bar",
key: "value"
});
assert.equal(item1.name, name);
// read an item
const { resource: item2 } = await container.item(item1.id, undefined).read();
assert.equal(item2.id, item1.id);
// upsert an item
const { resource: item3 } = await container.items.upsert({
id: "b",
name: "sample document",
foo: "bar",
key: "value"
});
assert.equal(item3.name, name);
// replace an item
const newProp = "baz";
const { resource: item4 } = await container.item("a", undefined).replace({
id: "a",
newProp
});
assert.equal(item4.newProp, newProp);
// read documents after creation
const { resources: documents } = await container.items.readAll({ enableCrossPartitionQuery: true }).fetchAll();
assert.equal(documents.length, 2, "create should increase the number of documents");
// query documents
const { resources: results } = await container.items
.query("SELECT * FROM root r", { enableCrossPartitionQuery: true })
.fetchAll();
assert(results.length === 2, "Container should contain two items");
// delete a document
await container.item(item1.id, undefined).delete();
// read documents after deletion
try {
await container.item(item1.id, undefined).read();
assert.fail("must throw if document doesn't exist");
} catch (err) {
const notFoundErrorCode = 404;
assert.equal(err.code, notFoundErrorCode, "response should return error code 404");
}
});
});

Просмотреть файл

@ -2,82 +2,68 @@ import assert from "assert";
import { Database, DataType, IndexKind } from "../../dist-esm";
import { createOrUpsertItem, getTestDatabase, removeAllDatabases } from "../common/TestHelpers";
describe("NodeJS CRUD Tests", function() {
describe("Spatial Indexes", function() {
this.timeout(process.env.MOCHA_TIMEOUT || 10000);
beforeEach(async function() {
await removeAllDatabases();
});
describe("Validate spatial index", function() {
const spatialIndexTest = async function(isUpsertTest: boolean) {
try {
// create database
const database: Database = await getTestDatabase("validate spatial index");
const spatialIndexTest = async function(isUpsertTest: boolean) {
// create database
const database: Database = await getTestDatabase("validate spatial index");
// create container using an indexing policy with spatial index.
const indexingPolicy = {
includedPaths: [
// create container using an indexing policy with spatial index.
const indexingPolicy = {
includedPaths: [
{
path: '/"Location"/?',
indexes: [
{
path: '/"Location"/?',
indexes: [
{
kind: IndexKind.Spatial,
dataType: DataType.Point
}
]
},
{
path: "/"
kind: IndexKind.Spatial,
dataType: DataType.Point
}
]
};
const entropy = Math.floor(Math.random() * 10000);
const { resource: containerDef } = await database.containers.create({
id: `sample container${entropy}`,
indexingPolicy
});
const container = database.container(containerDef.id);
},
{
path: "/"
}
]
};
const entropy = Math.floor(Math.random() * 10000);
const { resource: containerDef } = await database.containers.create({
id: `sample container${entropy}`,
indexingPolicy
});
const container = database.container(containerDef.id);
const location1 = {
id: "location1",
Location: {
type: "Point",
coordinates: [20.0, 20.0]
}
};
await createOrUpsertItem(container, location1, undefined, isUpsertTest);
const location2 = {
id: "location2",
Location: {
type: "Point",
coordinates: [100.0, 100.0]
}
};
await createOrUpsertItem(container, location2, undefined, isUpsertTest);
const query =
"SELECT * FROM root WHERE (ST_DISTANCE(root.Location, {type: 'Point', coordinates: [20.1, 20]}) < 20000) ";
const { resources: results } = await container.items.query(query).fetchAll();
assert.equal(1, results.length);
assert.equal("location1", results[0].id);
} catch (err) {
throw err;
const location1 = {
id: "location1",
Location: {
type: "Point",
coordinates: [20.0, 20.0]
}
};
it("nativeApi Should support spatial index name based", async function() {
try {
await spatialIndexTest(false);
} catch (err) {
throw err;
await createOrUpsertItem(container, location1, undefined, isUpsertTest);
const location2 = {
id: "location2",
Location: {
type: "Point",
coordinates: [100.0, 100.0]
}
});
};
await createOrUpsertItem(container, location2, undefined, isUpsertTest);
const query =
"SELECT * FROM root WHERE (ST_DISTANCE(root.Location, {type: 'Point', coordinates: [20.1, 20]}) < 20000) ";
const { resources: results } = await container.items.query(query, { enableCrossPartitionQuery: true }).fetchAll();
assert.equal(1, results.length);
assert.equal("location1", results[0].id);
};
it("nativeApi Should support spatial index name based with upsert", async function() {
try {
await spatialIndexTest(true);
} catch (err) {
throw err;
}
});
it("nativeApi Should support spatial index name based", async function() {
await spatialIndexTest(false);
});
it("nativeApi Should support spatial index name based with upsert", async function() {
await spatialIndexTest(true);
});
});

Просмотреть файл

@ -73,64 +73,6 @@ describe("NodeJS CRUD Tests", function() {
assert.equal(err.code, notFoundErrorCode, "response should return error code 404");
}
});
it("nativeApi Should do sproc CRUD operations successfully name based with upsert", async function() {
// read sprocs
const { resources: sprocs } = await container.scripts.storedProcedures.readAll().fetchAll();
assert.equal(sprocs.constructor, Array, "Value should be an array");
// create a sproc
const beforeCreateSprocsCount = sprocs.length;
const sprocDefinition: StoredProcedureDefinition = {
id: "sample sproc",
// prettier-ignore
body: function () { const x = 10; } // tslint:disable-line:object-literal-shorthand
};
const { resource: sproc } = await container.scripts.storedProcedures.upsert(sprocDefinition);
assert.equal(sproc.id, sprocDefinition.id);
assert.equal(sproc.body, "function () { const x = 10; }");
// read sprocs after creation
const { resources: sprocsAfterCreation } = await container.scripts.storedProcedures.readAll().fetchAll();
assert.equal(
sprocsAfterCreation.length,
beforeCreateSprocsCount + 1,
"create should increase the number of sprocs"
);
// query sprocs
const querySpec = {
query: "SELECT * FROM root r"
};
const { resources: queriedSprocs } = await container.scripts.storedProcedures.query(querySpec).fetchAll();
assert(queriedSprocs.length > 0, "number of sprocs for the query should be > 0");
// replace sproc
// prettier-ignore
sproc.body = function () { const x = 20; };
const { resource: replacedSproc } = await container.scripts.storedProcedures.upsert(sproc);
assert.equal(replacedSproc.id, sproc.id);
assert.equal(replacedSproc.body, "function () { const x = 20; }");
// read sproc
const { resource: sprocAfterReplace } = await container.scripts.storedProcedure(replacedSproc.id).read();
assert.equal(replacedSproc.id, sprocAfterReplace.id);
// delete sproc
await container.scripts.storedProcedure(replacedSproc.id).delete();
// read sprocs after deletion
try {
await container.scripts.storedProcedure(replacedSproc.id).read();
assert.fail("Must fail to read sproc after deletion");
} catch (err) {
const notFoundErrorCode = 404;
assert.equal(err.code, notFoundErrorCode, "response should return error code 404");
}
});
});
describe("Validate stored procedure functionality", function() {
@ -199,67 +141,6 @@ describe("NodeJS CRUD Tests", function() {
.execute([{ temp: "so" }]);
assert.equal(result3, "aso");
});
it("nativeApi Should do stored procedure operations successfully with upsert", async function() {
// tslint:disable:no-var-keyword
// tslint:disable:prefer-const
// tslint:disable:curly
// tslint:disable:no-string-throw
// tslint:disable:object-literal-shorthand
const sproc1: StoredProcedureDefinition = {
id: "storedProcedure1",
body: function() {
for (var i = 0; i < 1000; i++) {
const item = getContext()
.getResponse()
.getBody();
if (i > 0 && item !== i - 1) throw "body mismatch";
getContext()
.getResponse()
.setBody(i);
}
}
};
const sproc2: StoredProcedureDefinition = {
id: "storedProcedure2",
body: function() {
for (var i = 0; i < 10; i++)
getContext()
.getResponse()
.appendValue("Body", i);
}
};
const sproc3: StoredProcedureDefinition = {
id: "storedProcedure3",
// TODO: I put any in here, but not sure how this will work...
body: function(input: any) {
getContext()
.getResponse()
.setBody("a" + input.temp);
}
};
// tslint:enable:no-var-keyword
// tslint:enable:prefer-const
// tslint:enable:curly
// tslint:enable:no-string-throw
// tslint:enable:object-literal-shorthand
const { resource: retrievedSproc } = await container.scripts.storedProcedures.upsert(sproc1);
const { resource: result } = await container.scripts.storedProcedure(retrievedSproc.id).execute();
assert.equal(result, 999);
const { resource: retrievedSproc2 } = await container.scripts.storedProcedures.upsert(sproc2);
const { resource: result2 } = await container.scripts.storedProcedure(retrievedSproc2.id).execute();
assert.equal(result2, 123456789);
const { resource: retrievedSproc3 } = await container.scripts.storedProcedures.upsert(sproc3);
const { resource: result3 } = await container.scripts
.storedProcedure(retrievedSproc3.id)
.execute([{ temp: "so" }]);
assert.equal(result3, "aso");
});
});
it("nativeApi Should execute stored procedure with partition key successfully name based", async function() {

Просмотреть файл

@ -85,74 +85,6 @@ describe("NodeJS CRUD Tests", function() {
assert.equal(err.code, notFoundErrorCode, "response should return error code 404");
}
});
it("nativeApi Should do trigger CRUD operations successfully name based with upsert", async function() {
// read triggers
const { resources: triggers } = await container.scripts.triggers.readAll().fetchAll();
assert.equal(Array.isArray(triggers), true);
// create a trigger
const beforeCreateTriggersCount = triggers.length;
// tslint:disable:no-var-keyword
// tslint:disable:prefer-const
const triggerDefinition: TriggerDefinition = {
id: "sample trigger",
body: "serverScript() { var x = 10; }",
triggerType: TriggerType.Pre,
triggerOperation: TriggerOperation.All
};
// tslint:enable:no-var-keyword
// tslint:enable:prefer-const
const { resource: trigger } = await container.scripts.triggers.upsert(triggerDefinition);
assert.equal(trigger.id, triggerDefinition.id);
assert.equal(trigger.body, "serverScript() { var x = 10; }");
// read triggers after creation
const { resources: triggersAfterCreation } = await container.scripts.triggers.readAll().fetchAll();
assert.equal(
triggersAfterCreation.length,
beforeCreateTriggersCount + 1,
"create should increase the number of triggers"
);
// query triggers
const querySpec = {
query: "SELECT * FROM root r WHERE r.id=@id",
parameters: [
{
name: "@id",
value: triggerDefinition.id
}
]
};
const { resources: results } = await container.scripts.triggers.query(querySpec).fetchAll();
assert(results.length > 0, "number of results for the query should be > 0");
// replace trigger
// prettier-ignore
trigger.body = function () { const x = 20; };
const { resource: replacedTrigger } = await container.scripts.triggers.upsert(trigger);
assert.equal(replacedTrigger.id, trigger.id);
assert.equal(replacedTrigger.body, "function () { const x = 20; }");
// read trigger
const { resource: triggerAfterReplace } = await container.scripts.trigger(replacedTrigger.id).read();
assert.equal(replacedTrigger.id, triggerAfterReplace.id);
// delete trigger
await await container.scripts.trigger(replacedTrigger.id).delete();
// read triggers after deletion
try {
await container.scripts.trigger(replacedTrigger.id).read();
assert.fail("Must fail to read after deletion");
} catch (err) {
assert.equal(err.code, notFoundErrorCode, "response should return error code 404");
}
});
});
describe("validate trigger functionality", function() {
@ -261,43 +193,5 @@ describe("NodeJS CRUD Tests", function() {
assert.equal(err.code, 400, "Must throw when using a DELETE trigger on a CREATE operation");
}
});
it("should do trigger operations successfully with upsert", async function() {
for (const trigger of triggers) {
await container.scripts.triggers.upsert(trigger);
}
// create document
const { resource: document } = await container.items.upsert(
{ id: "doc1", key: "value" },
{ preTriggerInclude: "t1" }
);
assert.equal(document.id, "DOC1t1", "name should be capitalized");
const { resource: document2 } = await container.items.upsert(
{ id: "doc2", key2: "value2" },
{ preTriggerInclude: "t2" }
);
assert.equal(document2.id, "doc2", "name shouldn't change");
const { resource: document3 } = await container.items.upsert(
{ id: "Doc3", prop: "empty" },
{ preTriggerInclude: "t3" }
);
assert.equal(document3.id, "doc3t3");
const { resource: document4 } = await container.items.upsert(
{ id: "testing post trigger" },
{ postTriggerInclude: "response1", preTriggerInclude: "t1" }
);
assert.equal(document4.id, "TESTING POST TRIGGERt1");
const { resource: document5, headers } = await container.items.upsert(
{ id: "responseheaders" },
{ preTriggerInclude: "t1" }
);
assert.equal(document5.id, "RESPONSEHEADERSt1");
try {
await container.items.upsert({ id: "Docoptype" }, { postTriggerInclude: "triggerOpType" });
assert.fail("Must fail");
} catch (err) {
assert.equal(err.code, 400, "Must throw when using a DELETE trigger on a CREATE operation");
}
});
});
});

Просмотреть файл

@ -8,296 +8,273 @@ async function sleep(time: number) {
});
}
describe("NodeJS CRUD Tests", function() {
describe("Container TTL", function() {
this.timeout(process.env.MOCHA_TIMEOUT || 600000);
beforeEach(async function() {
await removeAllDatabases();
});
describe("TTL tests", function() {
async function createcontainerWithInvalidDefaultTtl(
db: Database,
containerDefinition: ContainerDefinition,
collId: any,
defaultTtl: number
) {
containerDefinition.id = collId;
containerDefinition.defaultTtl = defaultTtl;
try {
await db.containers.create(containerDefinition);
} catch (err) {
const badRequestErrorCode = 400;
assert.equal(err.code, badRequestErrorCode, "response should return error code " + badRequestErrorCode);
}
async function createcontainerWithInvalidDefaultTtl(
db: Database,
containerDefinition: ContainerDefinition,
collId: any,
defaultTtl: number
) {
containerDefinition.id = collId;
containerDefinition.defaultTtl = defaultTtl;
try {
await db.containers.create(containerDefinition);
} catch (err) {
const badRequestErrorCode = 400;
assert.equal(err.code, badRequestErrorCode, "response should return error code " + badRequestErrorCode);
}
}
async function createItemWithInvalidTtl(container: Container, itemDefinition: any, itemId: any, ttl: number) {
itemDefinition.id = itemId;
itemDefinition.ttl = ttl;
async function createItemWithInvalidTtl(container: Container, itemDefinition: any, itemId: any, ttl: number) {
itemDefinition.id = itemId;
itemDefinition.ttl = ttl;
try {
await container.items.create(itemDefinition);
assert.fail("Must throw if using invalid TTL");
} catch (err) {
const badRequestErrorCode = 400;
assert.equal(err.code, badRequestErrorCode, "response should return error code " + badRequestErrorCode);
}
try {
await container.items.create(itemDefinition);
assert.fail("Must throw if using invalid TTL");
} catch (err) {
const badRequestErrorCode = 400;
assert.equal(err.code, badRequestErrorCode, "response should return error code " + badRequestErrorCode);
}
}
it("nativeApi Validate container and Item TTL values.", async function() {
try {
const database = await getTestDatabase("ttl test1 database");
it("Validate container and Item TTL values.", async function() {
const database = await getTestDatabase("ttl test1 database");
const containerDefinition = {
id: "sample container1",
defaultTtl: 5
};
const { resource: containerResult } = await database.containers.create(containerDefinition);
const containerDefinition = {
id: "sample container1",
defaultTtl: 5
};
const { resource: containerResult } = await database.containers.create(containerDefinition);
assert.equal(containerDefinition.defaultTtl, containerResult.defaultTtl);
const container = database.container(containerResult.id);
assert.equal(containerDefinition.defaultTtl, containerResult.defaultTtl);
const container = database.container(containerResult.id);
// null, 0, -10 are unsupported value for defaultTtl.Valid values are -1 or a non-zero positive 32-bit integer value
await createcontainerWithInvalidDefaultTtl(database, containerDefinition, "sample container2", null);
await createcontainerWithInvalidDefaultTtl(database, containerDefinition, "sample container3", 0);
await createcontainerWithInvalidDefaultTtl(database, containerDefinition, "sample container4", -10);
// null, 0, -10 are unsupported value for defaultTtl.Valid values are -1 or a non-zero positive 32-bit integer value
await createcontainerWithInvalidDefaultTtl(database, containerDefinition, "sample container2", null);
await createcontainerWithInvalidDefaultTtl(database, containerDefinition, "sample container3", 0);
await createcontainerWithInvalidDefaultTtl(database, containerDefinition, "sample container4", -10);
const itemDefinition = {
id: "doc",
name: "sample Item",
key: "value",
ttl: 2
};
const itemDefinition = {
id: "doc",
name: "sample Item",
key: "value",
ttl: 2
};
// 0, null, -10 are unsupported value for ttl.Valid values are -1 or a non-zero positive 32-bit integer value
await createItemWithInvalidTtl(container, itemDefinition, "doc1", 0);
await createItemWithInvalidTtl(container, itemDefinition, "doc2", null);
await createItemWithInvalidTtl(container, itemDefinition, "doc3", -10);
} catch (err) {
throw err;
}
});
// 0, null, -10 are unsupported value for ttl.Valid values are -1 or a non-zero positive 32-bit integer value
await createItemWithInvalidTtl(container, itemDefinition, "doc1", 0);
await createItemWithInvalidTtl(container, itemDefinition, "doc2", null);
await createItemWithInvalidTtl(container, itemDefinition, "doc3", -10);
});
async function checkItemGone(container: Container, createdItem: any) {
try {
await container.item(createdItem.id).read();
assert.fail("Must throw if the Item isn't there");
} catch (err) {
const badRequestErrorCode = 404;
assert.equal(err.code, badRequestErrorCode, "response should return error code " + badRequestErrorCode);
}
async function checkItemGone(container: Container, createdItem: any) {
try {
await container.item(createdItem.id, undefined).read();
assert.fail("Must throw if the Item isn't there");
} catch (err) {
const badRequestErrorCode = 404;
assert.equal(err.code, badRequestErrorCode, "response should return error code " + badRequestErrorCode);
}
}
async function checkItemExists(container: Container, createdItem: any) {
const { resource: readItem } = await container.item(createdItem.id).read();
assert.equal(readItem.ttl, createdItem.ttl);
}
async function checkItemExists(container: Container, createdItem: any) {
const { resource: readItem } = await container.item(createdItem.id, undefined).read();
assert.equal(readItem.ttl, createdItem.ttl);
}
async function positiveDefaultTtlStep4(container: Container, createdItem: any) {
// the created Item should NOT be gone as it 's ttl value is set to 8 which overrides the containers' s defaultTtl value(5)
await checkItemExists(container, createdItem);
await sleep(4000);
await checkItemGone(container, createdItem);
}
async function positiveDefaultTtlStep4(container: Container, createdItem: any) {
// the created Item should NOT be gone as it 's ttl value is set to 8 which overrides the containers' s defaultTtl value(5)
await checkItemExists(container, createdItem);
await sleep(4000);
await checkItemGone(container, createdItem);
}
async function positiveDefaultTtlStep3(container: Container, createdItem: any, itemDefinition: any) {
// the created Item should be gone now as it 's ttl value is set to 2 which overrides the containers' s defaultTtl value(5)
await checkItemGone(container, createdItem);
itemDefinition.id = "doc4";
itemDefinition.ttl = 8;
async function positiveDefaultTtlStep3(container: Container, createdItem: any, itemDefinition: any) {
// the created Item should be gone now as it 's ttl value is set to 2 which overrides the containers' s defaultTtl value(5)
await checkItemGone(container, createdItem);
itemDefinition.id = "doc4";
itemDefinition.ttl = 8;
const { resource: doc } = await container.items.create(itemDefinition);
await sleep(6000);
await positiveDefaultTtlStep4(container, doc);
}
const { resource: doc } = await container.items.create(itemDefinition);
await sleep(6000);
await positiveDefaultTtlStep4(container, doc);
}
async function positiveDefaultTtlStep2(container: Container, createdItem: any, itemDefinition: any) {
// the created Item should NOT be gone as it 's ttl value is set to -1(never expire) which overrides the containers' s defaultTtl value
await checkItemExists(container, createdItem);
itemDefinition.id = "doc3";
itemDefinition.ttl = 2;
async function positiveDefaultTtlStep2(container: Container, createdItem: any, itemDefinition: any) {
// the created Item should NOT be gone as it 's ttl value is set to -1(never expire) which overrides the containers' s defaultTtl value
await checkItemExists(container, createdItem);
itemDefinition.id = "doc3";
itemDefinition.ttl = 2;
const { resource: doc } = await container.items.create(itemDefinition);
await sleep(4000);
await positiveDefaultTtlStep3(container, doc, itemDefinition);
}
const { resource: doc } = await container.items.create(itemDefinition);
await sleep(4000);
await positiveDefaultTtlStep3(container, doc, itemDefinition);
}
async function positiveDefaultTtlStep1(container: Container, createdItem: any, itemDefinition: any) {
// the created Item should be gone now as it 's ttl value would be same as defaultTtl value of the container
await checkItemGone(container, createdItem);
itemDefinition.id = "doc2";
itemDefinition.ttl = -1;
async function positiveDefaultTtlStep1(container: Container, createdItem: any, itemDefinition: any) {
// the created Item should be gone now as it 's ttl value would be same as defaultTtl value of the container
await checkItemGone(container, createdItem);
itemDefinition.id = "doc2";
itemDefinition.ttl = -1;
const { resource: doc } = await container.items.create(itemDefinition);
await sleep(5000);
await positiveDefaultTtlStep2(container, doc, itemDefinition);
}
const { resource: doc } = await container.items.create(itemDefinition);
await sleep(5000);
await positiveDefaultTtlStep2(container, doc, itemDefinition);
}
it("nativeApi Validate Item TTL with positive defaultTtl.", async function() {
const database = await getTestDatabase("ttl test2 database");
it("Validate Item TTL with positive defaultTtl.", async function() {
const database = await getTestDatabase("ttl test2 database");
const containerDefinition = {
id: "sample container",
defaultTtl: 5
};
const containerDefinition = {
id: "sample container",
defaultTtl: 5
};
const { resource: containerResult } = await database.containers.create(containerDefinition);
const { resource: containerResult } = await database.containers.create(containerDefinition);
const container = await database.container(containerResult.id);
const container = await database.container(containerResult.id);
const itemDefinition = {
id: "doc1",
name: "sample Item",
key: "value"
};
const itemDefinition = {
id: "doc1",
name: "sample Item",
key: "value"
};
const { resource: createdItem } = await container.items.create(itemDefinition);
await sleep(7000);
await positiveDefaultTtlStep1(container, createdItem, itemDefinition);
});
const { resource: createdItem } = await container.items.create(itemDefinition);
await sleep(7000);
await positiveDefaultTtlStep1(container, createdItem, itemDefinition);
});
async function minusOneDefaultTtlStep1(
container: Container,
createdItem1: any,
createdItem2: any,
createdItem3: any
) {
// the created Item should be gone now as it 's ttl value is set to 2 which overrides the containers' s defaultTtl value(-1)
await checkItemGone(container, createdItem3);
async function minusOneDefaultTtlStep1(
container: Container,
createdItem1: any,
createdItem2: any,
createdItem3: any
) {
// the created Item should be gone now as it 's ttl value is set to 2 which overrides the containers' s defaultTtl value(-1)
await checkItemGone(container, createdItem3);
// The Items with id doc1 and doc2 will never expire
const { resource: readItem1 } = await container.item(createdItem1.id).read();
assert.equal(readItem1.id, createdItem1.id);
// The Items with id doc1 and doc2 will never expire
const { resource: readItem1 } = await container.item(createdItem1.id, undefined).read();
assert.equal(readItem1.id, createdItem1.id);
const { resource: readItem2 } = await container.item(createdItem2.id).read();
assert.equal(readItem2.id, createdItem2.id);
}
const { resource: readItem2 } = await container.item(createdItem2.id, undefined).read();
assert.equal(readItem2.id, createdItem2.id);
}
it("nativeApi Validate Item TTL with -1 defaultTtl.", async function() {
const database = await getTestDatabase("ttl test2 database");
it("Validate Item TTL with -1 defaultTtl.", async function() {
const database = await getTestDatabase("ttl test2 database");
const containerDefinition = {
id: "sample container",
defaultTtl: -1
};
const containerDefinition = {
id: "sample container",
defaultTtl: -1
};
const { resource: createdContainer } = await database.containers.create(containerDefinition);
const { resource: createdContainer } = await database.containers.create(containerDefinition);
const container = await database.container(createdContainer.id);
const container = await database.container(createdContainer.id);
const itemDefinition: any = {
id: "doc1",
name: "sample Item",
key: "value"
};
const itemDefinition: any = {
id: "doc1",
name: "sample Item",
key: "value"
};
// the created Item 's ttl value would be -1 inherited from the container' s defaultTtl and this Item will never expire
const { resource: createdItem1 } = await container.items.create(itemDefinition);
// the created Item 's ttl value would be -1 inherited from the container' s defaultTtl and this Item will never expire
const { resource: createdItem1 } = await container.items.create(itemDefinition);
// This Item is also set to never expire explicitly
itemDefinition.id = "doc2";
itemDefinition.ttl = -1;
// This Item is also set to never expire explicitly
itemDefinition.id = "doc2";
itemDefinition.ttl = -1;
const { resource: createdItem2 } = await container.items.create(itemDefinition);
const { resource: createdItem2 } = await container.items.create(itemDefinition);
itemDefinition.id = "doc3";
itemDefinition.ttl = 2;
itemDefinition.id = "doc3";
itemDefinition.ttl = 2;
const { resource: createdItem3 } = await container.items.create(itemDefinition);
await sleep(4000);
await minusOneDefaultTtlStep1(container, createdItem1, createdItem2, createdItem3);
});
const { resource: createdItem3 } = await container.items.create(itemDefinition);
await sleep(4000);
await minusOneDefaultTtlStep1(container, createdItem1, createdItem2, createdItem3);
});
it("nativeApi Validate Item TTL with no defaultTtl.", async function() {
const database = await getTestDatabase("ttl test3 database");
it("Validate Item TTL with no defaultTtl.", async function() {
const database = await getTestDatabase("ttl test3 database");
const containerDefinition = { id: "sample container" };
const containerDefinition = { id: "sample container" };
const { resource: createdContainer } = await database.containers.create(containerDefinition);
const { resource: createdContainer } = await database.containers.create(containerDefinition);
const container = await database.container(createdContainer.id);
const container = await database.container(createdContainer.id);
const itemDefinition = {
id: "doc1",
name: "sample Item",
key: "value",
ttl: 5
};
const itemDefinition = {
id: "doc1",
name: "sample Item",
key: "value",
ttl: 5
};
const { resource: createdItem } = await container.items.create(itemDefinition);
const { resource: createdItem } = await container.items.create(itemDefinition);
// Created Item still exists even after ttl time has passed since the TTL is disabled at container level(no defaultTtl property defined)
await sleep(7000);
await checkItemExists(container, createdItem);
});
// Created Item still exists even after ttl time has passed since the TTL is disabled at container level(no defaultTtl property defined)
await sleep(7000);
await checkItemExists(container, createdItem);
});
async function miscCasesStep4(container: Container, createdItem: any, itemDefinition: any) {
// Created Item still exists even after ttl time has passed since the TTL is disabled at container level
await checkItemExists(container, createdItem);
}
it("Validate Item TTL Misc cases.", async function() {
const database = await getTestDatabase("ttl test4 database");
async function miscCasesStep3(container: Container, upsertedItem: any, itemDefinition: any) {
// the upserted Item should be gone now after 10 secs from the last write(upsert) of the Item
await checkItemGone(container, upsertedItem);
const query = "SELECT * FROM root r";
const { resources: results } = await container.items.query(query).fetchAll();
assert.equal(results.length, 0);
const containerDefinition = {
id: "sample container",
defaultTtl: 8
};
// Use a container definition without defaultTtl to disable ttl at container level
const containerDefinition = { id: container.id };
const { resource: containerResult } = await database.containers.create(containerDefinition);
await container.replace(containerDefinition);
const container = await database.container(containerResult.id);
itemDefinition.id = "doc2";
const itemDefinition = {
id: "doc1",
name: "sample Item",
key: "value"
};
const { resource: createdItem } = await container.items.create(itemDefinition);
await sleep(5000);
await miscCasesStep4(container, createdItem, itemDefinition);
}
const { resource: createdItem } = await container.items.create(itemDefinition);
async function miscCasesStep2(container: Container, itemDefinition: any) {
// Upsert the Item after 3 secs to reset the Item 's ttl
itemDefinition.key = "value2";
const { resource: upsertedItem } = await container.items.upsert(itemDefinition);
await sleep(7000);
// Upserted Item still exists after (3+7)10 secs from Item creation time( with container 's defaultTtl set to 8) since it' s ttl was reset after 3 secs by upserting it
await checkItemExists(container, upsertedItem);
await sleep(3000);
await miscCasesStep3(container, upsertedItem, itemDefinition);
}
await sleep(10000);
// the created Item should be gone now as the ttl time expired
await checkItemGone(container, createdItem);
// We can create a Item with the same id after the ttl time has expired
const { resource: doc } = await container.items.create(itemDefinition);
assert.equal(itemDefinition.id, doc.id);
await sleep(3000);
async function miscCasesStep1(container: Container, createdItem: any, itemDefinition: any) {
// the created Item should be gone now as the ttl time expired
await checkItemGone(container, createdItem);
// We can create a Item with the same id after the ttl time has expired
const { resource: doc } = await container.items.create(itemDefinition);
assert.equal(itemDefinition.id, doc.id);
await sleep(3000);
await miscCasesStep2(container, itemDefinition);
}
// Upsert the Item after 3 secs to reset the Item 's ttl
itemDefinition.key = "value2";
const { resource: upsertedItem } = await container.items.upsert(itemDefinition);
await sleep(7000);
// Upserted Item still exists after (3+7)10 secs from Item creation time( with container 's defaultTtl set to 8) since it' s ttl was reset after 3 secs by upserting it
await checkItemExists(container, upsertedItem);
await sleep(3000);
it("nativeApi Validate Item TTL Misc cases.", async function() {
const database = await getTestDatabase("ttl test4 database");
// the upserted Item should be gone now after 10 secs from the last write(upsert) of the Item
await checkItemGone(container, upsertedItem);
const query = "SELECT * FROM root r";
const { resources: results } = await container.items.query(query, { enableCrossPartitionQuery: true }).fetchAll();
assert.equal(results.length, 0);
const containerDefinition = {
id: "sample container",
defaultTtl: 8
};
await container.replace({ id: container.id, partitionKey: containerResult.partitionKey });
const { resource: containerResult } = await database.containers.create(containerDefinition);
itemDefinition.id = "doc2";
const container = await database.container(containerResult.id);
const { resource: createdItem2 } = await container.items.create(itemDefinition);
await sleep(5000);
const itemDefinition = {
id: "doc1",
name: "sample Item",
key: "value"
};
const { resource: createdItem } = await container.items.create(itemDefinition);
await sleep(10000);
await miscCasesStep1(container, createdItem, itemDefinition);
});
// Created Item still exists even after ttl time has passed since the TTL is disabled at container level
await checkItemExists(container, createdItem2);
});
});

Просмотреть файл

@ -1,138 +1,73 @@
import assert from "assert";
import { UserDefinedFunctionDefinition, Container } from "../../dist-esm/client";
import { getTestDatabase, removeAllDatabases, getTestContainer } from "../common/TestHelpers";
import { removeAllDatabases, getTestContainer } from "../common/TestHelpers";
const containerId = "sample container";
describe("NodeJS CRUD Tests", function() {
describe("User Defined Function", function() {
this.timeout(process.env.MOCHA_TIMEOUT || 10000);
let container: Container;
beforeEach(async function() {
await removeAllDatabases();
// get container
container = await getTestContainer("UDFTests");
});
it("nativeApi Should do UDF CRUD operations successfully", async function() {
const { resources: udfs } = await container.scripts.userDefinedFunctions.readAll().fetchAll();
describe("User Defined Function", function() {
let container: Container;
// create a udf
const beforeCreateUdfsCount = udfs.length;
const udfDefinition: UserDefinedFunctionDefinition = {
id: "sample udf",
body: "function () { const x = 10; }"
};
beforeEach(async function() {
// get container
container = await getTestContainer("UDFTests");
});
it("nativeApi Should do UDF CRUD operations successfully", async function() {
const { resources: udfs } = await container.scripts.userDefinedFunctions.readAll().fetchAll();
// TODO also handle upsert case
const { resource: udf } = await container.scripts.userDefinedFunctions.create(udfDefinition);
// create a udf
const beforeCreateUdfsCount = udfs.length;
const udfDefinition: UserDefinedFunctionDefinition = {
id: "sample udf",
body: "function () { const x = 10; }"
};
assert.equal(udf.id, udfDefinition.id);
assert.equal(udf.body, "function () { const x = 10; }");
// TODO also handle upsert case
const { resource: udf } = await container.scripts.userDefinedFunctions.create(udfDefinition);
// read udfs after creation
const { resources: udfsAfterCreate } = await container.scripts.userDefinedFunctions.readAll().fetchAll();
assert.equal(udfsAfterCreate.length, beforeCreateUdfsCount + 1, "create should increase the number of udfs");
assert.equal(udf.id, udfDefinition.id);
assert.equal(udf.body, "function () { const x = 10; }");
// query udfs
const querySpec = {
query: "SELECT * FROM root r WHERE r.id=@id",
parameters: [
{
name: "@id",
value: udfDefinition.id
}
]
};
const { resources: results } = await container.scripts.userDefinedFunctions.query(querySpec).fetchAll();
assert(results.length > 0, "number of results for the query should be > 0");
// read udfs after creation
const { resources: udfsAfterCreate } = await container.scripts.userDefinedFunctions.readAll().fetchAll();
assert.equal(udfsAfterCreate.length, beforeCreateUdfsCount + 1, "create should increase the number of udfs");
// replace udf
udfDefinition.body = "function () { const x = 10; }";
const { resource: replacedUdf } = await container.scripts
.userDefinedFunction(udfDefinition.id)
.replace(udfDefinition);
// query udfs
const querySpec = {
query: "SELECT * FROM root r WHERE r.id=@id",
parameters: [
{
name: "@id",
value: udfDefinition.id
}
]
};
const { resources: results } = await container.scripts.userDefinedFunctions.query(querySpec).fetchAll();
assert(results.length > 0, "number of results for the query should be > 0");
assert.equal(replacedUdf.id, udfDefinition.id);
assert.equal(replacedUdf.body, "function () { const x = 10; }");
// replace udf
udfDefinition.body = "function () { const x = 10; }";
const { resource: replacedUdf } = await container.scripts
.userDefinedFunction(udfDefinition.id)
.replace(udfDefinition);
// read udf
const { resource: udfAfterReplace } = await container.scripts.userDefinedFunction(replacedUdf.id).read();
assert.equal(replacedUdf.id, udfDefinition.id);
assert.equal(replacedUdf.body, "function () { const x = 10; }");
assert.equal(replacedUdf.id, udfAfterReplace.id);
// read udf
const { resource: udfAfterReplace } = await container.scripts.userDefinedFunction(replacedUdf.id).read();
// delete udf
const { resource: res } = await container.scripts.userDefinedFunction(replacedUdf.id).delete();
assert.equal(replacedUdf.id, udfAfterReplace.id);
// delete udf
const { resource: res } = await container.scripts.userDefinedFunction(replacedUdf.id).delete();
// read udfs after deletion
try {
const { resource: badudf } = await container.scripts.userDefinedFunction(replacedUdf.id).read();
assert.fail("Must fail to read after delete");
} catch (err) {
const notFoundErrorCode = 404;
assert.equal(err.code, notFoundErrorCode, "response should return error code 404");
}
});
it("nativeApi Should do UDF CRUD operations successfully", async function() {
const { resources: udfs } = await container.scripts.userDefinedFunctions.readAll().fetchAll();
// create a udf
const beforeCreateUdfsCount = udfs.length;
const udfDefinition = {
id: "sample udf",
body: "function () { const x = 10; }"
};
const { resource: udf } = await container.scripts.userDefinedFunctions.upsert(udfDefinition);
assert.equal(udf.id, udfDefinition.id);
assert.equal(udf.body, "function () { const x = 10; }");
// read udfs after creation
const { resources: udfsAfterCreate } = await container.scripts.userDefinedFunctions.readAll().fetchAll();
assert.equal(udfsAfterCreate.length, beforeCreateUdfsCount + 1, "create should increase the number of udfs");
// query udfs
const querySpec = {
query: "SELECT * FROM root r WHERE r.id=@id",
parameters: [
{
name: "@id",
value: udfDefinition.id
}
]
};
const { resources: results } = await container.scripts.userDefinedFunctions.query(querySpec).fetchAll();
assert(results.length > 0, "number of results for the query should be > 0");
// replace udf
udfDefinition.body = "function () { const x = 10; }";
const { resource: replacedUdf } = await container.scripts.userDefinedFunctions.upsert(udfDefinition);
assert.equal(replacedUdf.id, udfDefinition.id);
assert.equal(replacedUdf.body, "function () { const x = 10; }");
// read udf
const { resource: udfAfterReplace } = await container.scripts.userDefinedFunction(replacedUdf.id).read();
assert.equal(replacedUdf.id, udfAfterReplace.id);
// delete udf
const { resource: res } = await container.scripts.userDefinedFunction(replacedUdf.id).delete();
// read udfs after deletion
try {
const { resource: badudf } = await container.scripts.userDefinedFunction(replacedUdf.id).read();
assert.fail("Must fail to read after delete");
} catch (err) {
const notFoundErrorCode = 404;
assert.equal(err.code, notFoundErrorCode, "response should return error code 404");
}
});
// read udfs after deletion
try {
const { resource: badudf } = await container.scripts.userDefinedFunction(replacedUdf.id).read();
assert.fail("Must fail to read after delete");
} catch (err) {
const notFoundErrorCode = 404;
assert.equal(err.code, notFoundErrorCode, "response should return error code 404");
}
});
});

Просмотреть файл

@ -25,7 +25,7 @@ describe("NodeJS Aggregate Query Tests", async function() {
path: "/",
indexes: [
{
kind: IndexKind.Hash,
kind: IndexKind.Range,
dataType: DataType.String
},
{

Просмотреть файл

@ -116,7 +116,7 @@ describe("Authorization", function() {
const { resource: readDoc } = await clientReadPermission
.database(database.id)
.container(container.id)
.item(createdDoc.id)
.item(createdDoc.id, undefined)
.read<any>();
assert.equal(readDoc.id, createdDoc.id, "invalid document read");
});

Просмотреть файл

@ -41,7 +41,7 @@ describe("Create And Read Validation", function() {
assert.equal(doc.id, testDoc.id, "invalid document Id");
// Read the container and see if it matches to the initial document
const { resource: resultDoc } = await container.item(doc.id).read<{ id: string; content: string }>();
const { resource: resultDoc } = await container.item(doc.id, undefined).read<{ id: string; content: string }>();
assert.equal(testDoc.content, resultDoc.content, "read document result is different from initial document");
} catch (err) {
throw err;

Просмотреть файл

@ -1,5 +1,4 @@
import assert from "assert";
import { Container } from "../../dist-esm/client";
import { PartitionKind } from "../../dist-esm/documents";
import { extractPartitionKey } from "../../dist-esm/extractPartitionKey";
@ -14,6 +13,7 @@ describe("extractPartitionKey", function() {
describe("With a defined partitionKeyDefinition", function() {
const partitionKeyDefinition = { paths: ["/a/b"], kind: PartitionKind.Hash };
const migratedPartitionKeyDefinition = { paths: ["/_partitionKey"], kind: PartitionKind.Hash, isSystemKey: true };
it("should return [{}] when document has no partition key value", function() {
const document = {};
@ -21,6 +21,12 @@ describe("extractPartitionKey", function() {
assert.deepEqual(result, [{}]);
});
it("should return [] when container is migrated from non-partitioned and document has no partition key value", function() {
const document = {};
const result = extractPartitionKey(document, migratedPartitionKeyDefinition);
assert.deepEqual(result, [{}]);
});
it("should return [null] when document has a null partition key value", function() {
const document: any = { a: { b: null } };
const result = extractPartitionKey(document, partitionKeyDefinition);

Просмотреть файл

@ -1,230 +1,11 @@
import assert from "assert";
import { RequestOptions } from "../../dist-esm";
import { Container, ContainerDefinition } from "../../dist-esm/client";
import { sleep } from "../../dist-esm/common";
import { getTestContainer, removeAllDatabases } from "../common/TestHelpers";
describe("Change Feed Iterator", function() {
this.timeout(process.env.MOCHA_TIMEOUT || 20000);
describe("Non-partitioned", function() {
// delete all databases and create sample database
before(async function() {
await removeAllDatabases();
});
(process.env.TESTS_MULTIREGION ? describe.skip : describe)("Should only find items after start time", function() {
let container: Container;
// create container and two items
before(async function() {
container = await getTestContainer("Newly updated items should be fetched incrementally");
});
after(async function() {
await container.delete();
});
it("should fetch updated items only with start time", async function() {
await container.items.create({ id: "item1" });
const date = new Date();
await sleep(3000);
await container.items.create({ id: "item2" });
const iterator = container.items.readChangeFeed({ startTime: date });
const { result: itemsShouldBeEmpty, etag: initialEtag } = await iterator.executeNext();
assert(initialEtag, "change feed response should have etag header");
const etag = initialEtag;
assert.equal(itemsShouldBeEmpty.length, 0, "Initial request should have empty results");
const { result: items } = await iterator.executeNext();
assert.equal(items.length, 1, "initial number of items should be equal 1");
assert.equal(items[0].id, "item2", "should find the newest item, but not the old");
const item = { id: "item2", name: "xyz" };
const { resource: replaced } = await container.item(item.id).replace(item);
assert.deepEqual(replaced.name, "xyz", "replaced item should be valid");
// Should continue from last etag
const { result: itemsAfterUpdate } = await iterator.executeNext();
assert.equal(itemsAfterUpdate.length, 1, "initial number of items should be equal 1");
assert.equal(itemsAfterUpdate[0].name, "xyz", "fetched item should have 'name: xyz'");
assert.equal(itemsAfterUpdate[0].id, item.id, "fetched item should be valid");
// Equivalent to execute next on other iterator from the previous etag
const iteratorWithContinuation = container.items.readChangeFeed({ continuation: etag });
const { result: itemsWithContinuation } = await iteratorWithContinuation.executeNext();
assert.equal(itemsWithContinuation.length, 1, "initial number of items should be equal 1");
assert.equal(itemsWithContinuation[0].name, "xyz", "fetched item should have 'name: xyz'");
assert.equal(itemsWithContinuation[0].id, item.id, "fetched item should be valid");
const { result: shouldHaveNoItems } = await iterator.executeNext();
assert.equal(shouldHaveNoItems.length, 0, "there should be 0 results");
const hasMoreResults = iterator.hasMoreResults;
assert.equal(hasMoreResults, false, "hasMoreResults should be false when we read the whole page");
});
});
describe("Newly updated items should be fetched incrementally", function() {
let container: Container;
// create container and two items
before(async function() {
container = await getTestContainer("Newly updated items should be fetched incrementally");
await container.items.create({ id: "item1" });
await container.items.create({ id: "item2" });
});
after(async function() {
await container.delete();
});
it("should fetch updated items only", async function() {
const iterator = container.items.readChangeFeed({ startFromBeginning: true });
const { result: items, headers } = await iterator.executeNext();
assert(headers.etag, "change feed response should have etag header");
const etag = headers.etag;
assert.equal(items.length, 2, "initial number of items should be equal 2");
const item = items[1];
item.name = "xyz";
const { resource: replaced } = await container.item(item.id).replace(item);
assert.deepEqual(replaced.name, "xyz", "replaced item should be valid");
// Should continue from last etag
const { result: itemsAfterUpdate } = await iterator.executeNext();
assert.equal(itemsAfterUpdate.length, 1, "initial number of items should be equal 1");
assert.equal(itemsAfterUpdate[0].name, "xyz", "fetched item should have 'name: xyz'");
assert.equal(itemsAfterUpdate[0].id, item.id, "fetched item should be valid");
// Equivalent to execute next on other iterator from the previous etag
const iteratorWithContinuation = container.items.readChangeFeed({ continuation: etag });
const { result: itemsWithContinuation } = await iteratorWithContinuation.executeNext();
assert.equal(itemsWithContinuation.length, 1, "initial number of items should be equal 1");
assert.equal(itemsWithContinuation[0].name, "xyz", "fetched item should have 'name: xyz'");
assert.equal(itemsWithContinuation[0].id, item.id, "fetched item should be valid");
const { result: shouldHaveNoItems } = await iterator.executeNext();
assert.equal(shouldHaveNoItems.length, 0, "there should be 0 results");
const hasMoreResults = iterator.hasMoreResults;
assert.equal(hasMoreResults, false, "hasMoreResults should be false when we read the whole page");
});
});
describe("Async iterator should find items", function() {
let container: Container;
// create container and two items
before(async function() {
container = await getTestContainer("Newly updated items should be fetched incrementally");
await container.items.create({ id: "item1" });
await container.items.create({ id: "item2" });
});
after(async function() {
await container.delete();
});
it("should fetch updated items only", async function() {
const iterator = container.items.readChangeFeed({ startFromBeginning: true });
const items: any[] = [];
for await (const page of iterator.getAsyncIterator()) {
if (page.result.length === 0) {
break;
}
items.push(...page.result);
}
assert.equal(items.length, 2, "initial number of items should be equal 2");
const item = items[1];
item.name = "xyz";
const { resource: replaced } = await container.item(item.id).replace(item);
assert.deepEqual(replaced.name, "xyz", "replaced item should be valid");
// Should continue from last etag
const itemsAfterUpdate: any[] = [];
for await (const page of iterator.getAsyncIterator()) {
if (page.result.length === 0) {
break;
}
itemsAfterUpdate.push(...page.result);
}
assert.equal(itemsAfterUpdate.length, 1, "initial number of items should be equal 1");
assert.equal(itemsAfterUpdate[0].name, "xyz", "fetched item should have 'name: xyz'");
assert.equal(itemsAfterUpdate[0].id, item.id, "fetched item should be valid");
const { result: shouldHaveNoItems } = await iterator.executeNext();
assert.equal(shouldHaveNoItems.length, 0, "there should be 0 results");
const hasMoreResults = iterator.hasMoreResults;
assert.equal(hasMoreResults, false, "hasMoreResults should be false when we read the whole page");
let count = 0;
for await (const page of iterator.getAsyncIterator()) {
++count;
}
assert.equal(count, 0, "async iterator should return any results if there are none left to serve");
});
});
describe("Newly created items should be fetched incrementally", async function() {
let container: Container;
// create container and one item
before(async function() {
container = await getTestContainer("Newly updated items should be fetched incrementally");
await container.items.create({ id: "item1" });
});
after(async function() {
await container.delete();
});
it("should fetch new items only", async function() {
const iterator = container.items.readChangeFeed({});
const { result: items, headers } = await iterator.executeNext();
assert(headers.etag, "change feed response should have etag header");
assert.equal(items.length, 0, "change feed response should have no items on it initially");
const { resource: itemThatWasCreated } = await container.items.create({
id: "item2",
prop: 1
});
const { result: itemsAfterCreate } = await iterator.executeNext();
assert.equal(itemsAfterCreate.length, 1, "should have 1 item from create");
const itemThatWasFound = itemsAfterCreate[0];
assert.notDeepEqual(itemThatWasFound, itemThatWasCreated, "actual should not match with expected value.");
delete itemThatWasFound._lsn;
delete itemThatWasFound._metadata;
assert.deepEqual(itemThatWasFound, itemThatWasCreated, "actual value doesn't match with expected value.");
const { result: itemsShouldBeEmptyWithNoNewCreates } = await iterator.executeNext();
assert.equal(itemsShouldBeEmptyWithNoNewCreates.length, 0, "should be nothing new");
await container.items.create({ id: "item3" });
await container.items.create({ id: "item4" });
const { result: itemsShouldHave2NewItems } = await iterator.executeNext();
assert.equal(itemsShouldHave2NewItems.length, 2, "there should be 2 results");
const { result: shouldHaveNoItems } = await iterator.executeNext();
assert.equal(shouldHaveNoItems.length, 0, "there should be 0 results");
const hasMoreResults = iterator.hasMoreResults;
assert.equal(hasMoreResults, false, "hasMoreResults should be false when we read the whole page");
});
});
});
describe("Partition Key", function() {
// delete all databases and create sample database
before(async function() {
@ -285,7 +66,7 @@ describe("Change Feed Iterator", function() {
const item = items[1];
item.name = "xyz";
const { resource: replaced } = await container.item(item.id).replace(item);
const { resource: replaced } = await container.items.upsert(item);
assert.deepEqual(replaced.name, "xyz", "replaced item should be valid");
const { result: itemsAfterUpdate } = await iterator.executeNext();

Просмотреть файл

@ -1,5 +1,5 @@
import assert from "assert";
import { Constants, FeedOptions } from "../../dist-esm";
import { FeedOptions } from "../../dist-esm";
import { PartitionKind } from "../../dist-esm/documents";
import { getTestContainer, getTestDatabase, removeAllDatabases } from "../common/TestHelpers";
@ -40,7 +40,7 @@ describe("ResourceLink Trimming of leading and trailing slashes", function() {
});
});
describe("Test Query Metrics On Single Partition Collection", function() {
describe("Test Query Metrics", function() {
this.timeout(process.env.MOCHA_TIMEOUT || 20000);
const collectionId = "testCollection2";
@ -58,9 +58,8 @@ describe("Test Query Metrics On Single Partition Collection", function() {
const createdContainer = database.container(createdCollectionDef.id);
await createdContainer.items.create(document);
const collectionLink = "/dbs/" + database.id + "/colls/" + collectionId + "/";
const query = "SELECT * from " + collectionId;
const queryOptions: FeedOptions = { populateQueryMetrics: true };
const queryOptions: FeedOptions = { populateQueryMetrics: true, enableCrossPartitionQuery: true };
const queryIterator = createdContainer.items.query(query, queryOptions);
while (queryIterator.hasMoreResults()) {

Просмотреть файл

@ -201,7 +201,7 @@ describe("Session Token", function() {
resourceType: ResourceType.item,
resourceId: "1"
});
await container.item(document13.id).replace({ id: "1", operation: "replace" }, { partitionKey: "1" });
await container.item(document13.id, "1").replace({ id: "1", operation: "replace" });
assert.equal(
spy.lastCall.args[0].headers[Constants.HttpHeaders.SessionToken],
replaceToken,
@ -281,7 +281,7 @@ describe("Session Token", function() {
for (const [pk, token] of tokens.entries()) {
(token as any).globalLsn = (token as any).globalLsn + 200;
const newToken = token.merge(token);
return `0:${newToken.toString()}`;
return `${pk}:${newToken.toString()}`;
}
}
throw new Error("No valid token found to increase");
@ -296,7 +296,7 @@ describe("Session Token", function() {
});
const applySessionTokenStub = sinon.stub(clientContext as any, "applySessionToken").callsFake(callbackSpy as any);
try {
await container.item("1").read({ partitionKey: "1" });
const resp = await container.item("1", "1").read();
assert.fail("readDocument must throw");
} catch (err) {
assert.equal(err.substatus, 1002, "Substatus should indicate the LSN didn't catchup.");
@ -305,7 +305,7 @@ describe("Session Token", function() {
} finally {
applySessionTokenStub.restore();
}
await container.item("1").read({ partitionKey: "1" });
await container.item("1", "1").read();
});
// TODO: chrande - looks like this might be broken by going name based?
@ -349,16 +349,15 @@ describe("Session Token", function() {
const { resource: createdDocument } = await createdContainer.items.create({
id: "1"
});
const requestOptions = { partitionKey: "1" };
await client2
.database(db.id)
.container(createdContainerDef.id)
.item(createdDocument.id)
.delete(requestOptions);
.item(createdDocument.id, "1")
.delete();
const setSessionTokenSpy = sinon.spy(sessionContainer, "set");
try {
await createdContainer.item(createdDocument.id).read(requestOptions);
await createdContainer.item(createdDocument.id, "1").read();
assert.fail("Must throw");
} catch (err) {
assert.equal(err.code, 404, "expecting 404 (Not found)");