diff --git a/doc/7/controllers/document/search/index.md b/doc/7/controllers/document/search/index.md index 7d294e7b4..ff11d3dd6 100644 --- a/doc/7/controllers/document/search/index.md +++ b/doc/7/controllers/document/search/index.md @@ -50,6 +50,12 @@ Additional query options | `from` |
number

(`0`) | Offset of the first document to fetch | | `size` |
number

(`10`) | Maximum number of documents to retrieve per page | | `scroll` |
string

(`""`) | When set, gets a forward-only cursor having its ttl set to the given value (ie `30s`; cf [elasticsearch time limits](https://www.elastic.co/guide/en/elasticsearch/reference/7.3/common-options.html#time-units)) | +| `verb` |
string
| (HTTP only) Forces the verb of the route | + +#### verb + +When instantiated with a HTTP protocol object, the SDK uses the POST API by default for this API route. +You can set the `verb` option to `GET` to force the SDK to use the GET API instead. ## Body properties diff --git a/package-lock.json b/package-lock.json index 707a27796..0e385a416 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1328,9 +1328,9 @@ "dev": true }, "@tootallnate/once": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.0.0.tgz", - "integrity": "sha512-KYyTT/T6ALPkIRd2Ge080X/BsXvy9O0hcWTtMWkPvwAwF99+vn6Dv4GzrFT/Nn1LePr+FFDbRXXlqmsy9lw2zA==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", "dev": true }, "@types/color-name": { @@ -2572,12 +2572,6 @@ "wrap-ansi": "^5.1.0" }, "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, "string-width": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", @@ -2588,15 +2582,6 @@ "is-fullwidth-code-point": "^2.0.0", "strip-ansi": "^5.1.0" } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } } } }, @@ -2613,9 +2598,9 @@ "dev": true }, "codecov": { - "version": "3.6.5", - "resolved": "https://registry.npmjs.org/codecov/-/codecov-3.6.5.tgz", - "integrity": "sha512-v48WuDMUug6JXwmmfsMzhCHRnhUf8O3duqXvltaYJKrO1OekZWpB/eH6iIoaxMl8Qli0+u3OxptdsBOYiD7VAQ==", + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/codecov/-/codecov-3.7.0.tgz", + "integrity": "sha512-uIixKofG099NbUDyzRk1HdGtaG8O+PBUAg3wfmjwXw2+ek+PZp+puRvbTohqrVfuudaezivJHFgTtSC3M8MXww==", "dev": true, "requires": { "argv": "0.0.2", @@ -6244,37 +6229,6 @@ "dev": true, "requires": { "chalk": "^2.4.2" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } } }, "log-update": { @@ -6557,9 +6511,9 @@ } }, "mocha": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-7.1.1.tgz", - "integrity": "sha512-3qQsu3ijNS3GkWcccT5Zw0hf/rWvu1fTN9sPvEd81hlwsr30GX2GcDSSoBxo24IR8FelmrAydGC6/1J5QQP4WA==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-7.2.0.tgz", + "integrity": "sha512-O9CIypScywTVpNaRrCAgoUnJgozpIofjKUYmJhiCIJMiuYnLI6otcb1/kpW9/n/tJODHGZ7i8aLQoDVsMtOKQQ==", "dev": true, "requires": { "ansi-colors": "3.2.3", @@ -6575,7 +6529,7 @@ "js-yaml": "3.13.1", "log-symbols": "3.0.0", "minimatch": "3.0.4", - "mkdirp": "0.5.3", + "mkdirp": "0.5.5", "ms": "2.1.1", "node-environment-flags": "1.0.6", "object.assign": "4.1.0", @@ -6654,9 +6608,9 @@ } }, "fsevents": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.2.tgz", - "integrity": "sha512-R4wDiBwZ0KzpgOWetKDug1FZcYhqYnUYKtfZYt4mD5SBz76q0KR4Q9o7GIPamsVPGmW3EYPPJ0dOOjvx32ldZA==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", + "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", "dev": true, "optional": true }, @@ -6699,9 +6653,9 @@ "dev": true }, "mkdirp": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.3.tgz", - "integrity": "sha512-P+2gwrFqx8lhew375MQHHeTlY8AuOJSrGf0R5ddkEndUkmwpgUob/vQuBD1V22/Cw1/lJr4x+EjllSezBThzBg==", + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", "dev": true, "requires": { "minimist": "^1.2.5" @@ -8890,24 +8844,46 @@ } } }, + "string.prototype.trimend": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz", + "integrity": "sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, "string.prototype.trimleft": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.1.tgz", - "integrity": "sha512-iu2AGd3PuP5Rp7x2kEZCrB2Nf41ehzh+goo8TV7z8/XDBbsvc6HQIlUl9RjkZ4oyrW1XM5UwlGl1oVEaDjg6Ag==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.2.tgz", + "integrity": "sha512-gCA0tza1JBvqr3bfAIFJGqfdRTyPae82+KTnm3coDXkZN9wnuW3HjGgN386D7hfv5CHQYCI022/rJPVlqXyHSw==", "dev": true, "requires": { "define-properties": "^1.1.3", - "function-bind": "^1.1.1" + "es-abstract": "^1.17.5", + "string.prototype.trimstart": "^1.0.0" } }, "string.prototype.trimright": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.1.tgz", - "integrity": "sha512-qFvWL3/+QIgZXVmJBfpHmxLB7xsUXz6HsUmP8+5dRaC3Q7oKUv9Vo6aMCRZC1smrtyECFsIT30PqBJ1gTjAs+g==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.2.tgz", + "integrity": "sha512-ZNRQ7sY3KroTaYjRS6EbNiiHrOkjihL9aQE/8gfQ4DtAC/aEBRHFJa44OmoWxGGqXuJlfKkZW4WcXErGr+9ZFg==", "dev": true, "requires": { "define-properties": "^1.1.3", - "function-bind": "^1.1.1" + "es-abstract": "^1.17.5", + "string.prototype.trimend": "^1.0.0" + } + }, + "string.prototype.trimstart": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz", + "integrity": "sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" } }, "string_decoder": { @@ -9509,9 +9485,9 @@ "dev": true }, "uuid": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", - "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", "dev": true }, "v8-compile-cache": { @@ -9681,21 +9657,6 @@ "strip-ansi": "^5.0.0" }, "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, "string-width": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", @@ -9706,15 +9667,6 @@ "is-fullwidth-code-point": "^2.0.0", "strip-ansi": "^5.1.0" } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } } } }, @@ -9815,12 +9767,6 @@ "yargs-parser": "^13.1.2" }, "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, "get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", @@ -9837,15 +9783,6 @@ "is-fullwidth-code-point": "^2.0.0", "strip-ansi": "^5.1.0" } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } } } }, diff --git a/package.json b/package.json index b4542688f..c2f5d46b9 100644 --- a/package.json +++ b/package.json @@ -45,14 +45,14 @@ "@babel/core": "^7.9.0", "@babel/preset-env": "^7.9.5", "babel-loader": "^8.1.0", - "codecov": "^3.6.5", + "codecov": "^3.7.0", "cucumber": "^6.0.5", "eslint": "^6.8.0", "eslint-friendly-formatter": "^4.0.1", "eslint-loader": "^4.0.0", "kuzdoc": "^1.2.2", "lolex": "^6.0.0", - "mocha": "7.1.1", + "mocha": "7.2.0", "mock-require": "^3.0.3", "nyc": "^15.0.1", "proxyquire": "^2.1.3", diff --git a/src/controllers/Document.js b/src/controllers/Document.js index bf62cacd0..0fdc75ffa 100644 --- a/src/controllers/Document.js +++ b/src/controllers/Document.js @@ -191,16 +191,23 @@ class DocumentController extends BaseController { const request = { index, collection, - body, + body: null, action: 'search', }; - + if ( this.kuzzle.protocol.name === 'http' + && options.verb + && options.verb.toLowerCase() === 'get' + ) { + request.searchBody = body; + } + else { + request.body = body; + } for (const opt of ['from', 'size', 'scroll']) { request[opt] = options[opt]; } - const opts = { verb: 'POST', ...options }; - + const opts = { verb: options.verb || 'POST', ...options }; return this.query(request, opts) .then(response => ({ response, request, opts })); } diff --git a/src/protocols/Http.js b/src/protocols/Http.js index e90da908b..8052773ec 100644 --- a/src/protocols/Http.js +++ b/src/protocols/Http.js @@ -5,7 +5,7 @@ const BaseProtocol = require('./abstract/Base'); class HttpProtocol extends BaseProtocol { constructor(host, options = {}) { - super(host, options); + super(host, options, 'http'); if (typeof host !== 'string' || host === '') { throw new Error('host is required'); @@ -210,6 +210,7 @@ class HttpProtocol extends BaseProtocol { // inject queryString arguments: const queryString = []; + for (const key of Object.keys(queryArgs)) { const value = queryArgs[key]; diff --git a/src/protocols/WebSocket.js b/src/protocols/WebSocket.js index 2f53e3aca..f2d05e1fb 100644 --- a/src/protocols/WebSocket.js +++ b/src/protocols/WebSocket.js @@ -6,7 +6,7 @@ const BaseProtocolRealtime = require('./abstract/Realtime'); class WebSocketProtocol extends BaseProtocolRealtime { constructor(host, options = {}) { - super(host, options); + super(host, options, 'ws'); if (typeof host !== 'string' || host === '') { throw new Error('host is required'); diff --git a/src/protocols/abstract/Base.js b/src/protocols/abstract/Base.js index 81d6a752d..99deb6469 100644 --- a/src/protocols/abstract/Base.js +++ b/src/protocols/abstract/Base.js @@ -6,11 +6,12 @@ const KuzzleEventEmitter = require('../../core/KuzzleEventEmitter'); const PendingRequest = require('./PendingRequest'); class KuzzleAbstractProtocol extends KuzzleEventEmitter { - constructor (host, options = {}) { + constructor (host, options = {}, name = undefined) { super(); this._pendingRequests = new Map(); this._host = host; + this._name = name; const port = parseInt(options.port, 10); this._port = isNaN(port) ? 7512 : port; this._ssl = typeof options.sslConnection === 'boolean' ? options.sslConnection : false; @@ -31,6 +32,10 @@ class KuzzleAbstractProtocol extends KuzzleEventEmitter { return this._host; } + get name () { + return this._name; + } + get port () { return this._port; } diff --git a/src/protocols/routes.json b/src/protocols/routes.json index 1a6836f0d..2fcffb105 100644 --- a/src/protocols/routes.json +++ b/src/protocols/routes.json @@ -76,10 +76,6 @@ "verb": "POST", "url": "/:index/:collection/_create" }, - "search": { - "url": "/:index/:collection", - "verb": "GET" - }, "scroll": { "url": "/_scroll/:scrollId", "verb": "GET" @@ -143,6 +139,10 @@ "validate": { "url": "/:index/:collection/_validate", "verb": "POST" + }, + "search": { + "url": "/:index/:collection/_search", + "verb": "GET" } }, "security": { diff --git a/test/controllers/document.test.js b/test/controllers/document.test.js index 5ab034ef9..df4663109 100644 --- a/test/controllers/document.test.js +++ b/test/controllers/document.test.js @@ -377,7 +377,8 @@ describe('Document Controller', () => { total: 3 }; kuzzle.query.resolves({result}); - + kuzzle.protocol = {}; + kuzzle.protocol.name = 'http'; return kuzzle.document.search('index', 'collection', {foo: 'bar'}, options) .then(res => { should(kuzzle.query) @@ -402,17 +403,57 @@ describe('Document Controller', () => { }); }); - it('should inject the "from", "size", "scroll" options into the request', () => { + it('should call document/search query and return a Promise which resolves a DocumentSearchResult instance', () => { const result = { scrollId: 'scroll-id', hits: [ + {_id: 'document1', _score: 0.9876, _source: {foo: 'bar'}}, {_id: 'document2', _score: 0.6789, _source: {foo: 'barbar'}}, {_id: 'document3', _score: 0.6543, _source: {foo: 'barbaz'}} ], total: 3 }; kuzzle.query.resolves({result}); + kuzzle.protocol = {}; + kuzzle.protocol.name = 'http'; + options.verb = 'GET'; + return kuzzle.document.search('index', 'collection', {foo: 'bar'}, options) + .then(res => { + should(kuzzle.query) + .be.calledOnce() + .be.calledWithMatch({ + controller: 'document', + action: 'search', + index: 'index', + collection: 'collection', + searchBody: {foo: 'bar'}, + body: null, + from: undefined, + size: undefined, + scroll: undefined + }, options); + should(res).be.an.instanceOf(DocumentSearchResult); + should(res._options).match(options); + should(res._options.verb).be.eql('GET'); + should(res._response).be.equal(result); + should(res.fetched).be.equal(3); + should(res.total).be.equal(3); + }); + }); + + it('should inject the "from", "size", "scroll" options into the request', () => { + const result = { + scrollId: 'scroll-id', + hits: [ + {_id: 'document2', _score: 0.6789, _source: {foo: 'barbar'}}, + {_id: 'document3', _score: 0.6543, _source: {foo: 'barbaz'}} + ], + total: 3 + }; + kuzzle.query.resolves({result}); + kuzzle.protocol = {}; + kuzzle.protocol.name = 'http'; return kuzzle.document.search('index', 'collection', {foo: 'bar'}, {from: 1, size: 2, scroll: '10s'}) .then(res => { should(kuzzle.query) @@ -442,7 +483,8 @@ describe('Document Controller', () => { total: 0 }; kuzzle.document.query = sinon.stub().resolves({result}); - + kuzzle.protocol = {}; + kuzzle.protocol.name = 'http'; return kuzzle.document.search('index', 'collection', {}, { size: 0 }) .then(() => { should(kuzzle.document.query).be.calledOnce(); @@ -458,7 +500,8 @@ describe('Document Controller', () => { total: 0 }; kuzzle.document.query = sinon.stub().resolves({result}); - + kuzzle.protocol = {}; + kuzzle.protocol.name = 'http'; return kuzzle.document.search('index', 'collection', {}, { scroll: '42s' }) .then(() => { should(kuzzle.document.query).be.calledOnce(); diff --git a/test/protocol/Http.test.js b/test/protocol/Http.test.js index bf91dbd57..730f21859 100644 --- a/test/protocol/Http.test.js +++ b/test/protocol/Http.test.js @@ -344,7 +344,7 @@ describe('HTTP networking module', () => { protocol.send(data); }); - + it('should inject queryString to the HTTP request', done => { const data = { requestId: 'requestId',