Skip to content

Commit 0406f2c

Browse files
author
David Bengsch
authored
Merge pull request #134 from kuzzleio/develop-implement-scroll
Implement scroll api
2 parents 6211c10 + cbc5bdc commit 0406f2c

File tree

13 files changed

+828
-111
lines changed

13 files changed

+828
-111
lines changed

.eslintignore

Lines changed: 0 additions & 2 deletions
This file was deleted.

.jshintrc

Lines changed: 0 additions & 13 deletions
This file was deleted.

codecov.yml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
coverage:
2+
range: "90...100"
3+
4+
status:
5+
project:
6+
default:
7+
threshold: 1
8+
9+
patch:
10+
default:
11+
branches:
12+
- master

package.json

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
"scripts": {
2121
"test": "npm run --silent lint && npm run unit-testing",
2222
"unit-testing": "istanbul cover _mocha -- --recursive",
23-
"lint": "eslint --max-warnings=0 ./lib ./test",
23+
"lint": "eslint --max-warnings=0 ./src ./test",
2424
"build": "node build.js"
2525
},
2626
"browser": "src/kuzzle.js",
@@ -38,14 +38,8 @@
3838
"webpack": "^1.13.1",
3939
"eslint": "^3.7.1",
4040
"eslint-friendly-formatter": "^2.0.6",
41-
"eslint-loader": "^1.5.0",
4241
"browserify": "13.1.0",
4342
"codecov": "^1.0.1",
44-
"grunt": "1.0.1",
45-
"grunt-browserify": "^5.0.0",
46-
"grunt-contrib-uglify": "2.0.0",
47-
"grunt-webpack": "^1.0.14",
48-
"gruntify-eslint": "^3.0.0",
4943
"istanbul": "0.4.5",
5044
"istanbul-middleware": "0.2.2",
5145
"mocha": "3.1.0",

src/kuzzle.js

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ var
2323
* @param {responseCallback} [cb] - Handles connection response
2424
* @constructor
2525
*/
26-
module.exports = Kuzzle = function (host, options, cb) {
26+
function Kuzzle (host, options, cb) {
2727
var self = this;
2828

2929
if (!(this instanceof Kuzzle)) {
@@ -309,7 +309,7 @@ module.exports = Kuzzle = function (host, options, cb) {
309309
}
310310
});
311311
}
312-
};
312+
}
313313

314314
/**
315315
* Connects to a Kuzzle instance using the provided host name.
@@ -517,6 +517,32 @@ Kuzzle.prototype.login = function (strategy) {
517517
});
518518
};
519519

520+
/**
521+
* Create a kuzzle index
522+
*
523+
* @param {string} index
524+
* @param {object} [options]
525+
* @param {responseCallback} cb
526+
* @returns {Kuzzle}
527+
*/
528+
Kuzzle.prototype.createIndex = function (index, options, cb) {
529+
if (!index) {
530+
if (!this.defaultIndex) {
531+
throw new Error('Kuzzle.createIndex: index required');
532+
}
533+
index = this.defaultIndex;
534+
}
535+
536+
if (!cb && typeof options === 'function') {
537+
cb = options;
538+
options = null;
539+
}
540+
541+
this.query({controller: 'admin', action: 'createIndex'}, {index: index}, options, typeof cb !== 'function' ? null : cb);
542+
543+
return this;
544+
};
545+
520546
/**
521547
* Send logout request to kuzzle with jwtToken.
522548
*
@@ -913,7 +939,7 @@ Kuzzle.prototype.getStatistics = function (timestamp, options, cb) {
913939
*
914940
* @param {string} collection - The name of the data collection you want to manipulate
915941
* @param {string} [index] - The name of the data index containing the data collection
916-
* @returns {object} A KuzzleDataCollection instance
942+
* @returns {KuzzleDataCollection} A KuzzleDataCollection instance
917943
*/
918944
Kuzzle.prototype.dataCollectionFactory = function(collection, index) {
919945
this.isValid();
@@ -1459,3 +1485,5 @@ Kuzzle.prototype.stopQueuing = function () {
14591485

14601486
return this;
14611487
};
1488+
1489+
module.exports = Kuzzle;

src/kuzzleDataCollection.js

Lines changed: 170 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
var
2+
KuzzleSearchResult = require('./kuzzleSearchResult'),
23
KuzzleDocument = require('./kuzzleDocument'),
34
KuzzleDataMapping = require('./kuzzleDataMapping'),
45
KuzzleRoom = require('./kuzzleRoom'),
@@ -15,6 +16,11 @@ var
1516
/**
1617
* A data collection is a set of data managed by Kuzzle. It acts like a data table for persistent documents,
1718
* or like a room for pub/sub messages.
19+
*
20+
* @property {string} collection
21+
* @property {string} index
22+
* @property {Kuzzle} kuzzle
23+
* @property {Array.<string>} collection
1824
* @param {object} kuzzle - Kuzzle instance to inherit from
1925
* @param {string} collection - name of the data collection to handle
2026
* @param {string} index - Index containing the data collection
@@ -72,61 +78,6 @@ function KuzzleDataCollection(kuzzle, collection, index) {
7278
return this;
7379
}
7480

75-
/**
76-
* Executes an advanced search on the data collection.
77-
*
78-
* /!\ There is a small delay between documents creation and their existence in our advanced search layer,
79-
* usually a couple of seconds.
80-
* That means that a document that was just been created won’t be returned by this function.
81-
*
82-
* @param {object} filters - Filters in Elasticsearch Query DSL format
83-
* @param {object} [options] - Optional parameters
84-
* @param {responseCallback} cb - Handles the query response
85-
*/
86-
KuzzleDataCollection.prototype.advancedSearch = function (filters, options, cb) {
87-
var
88-
query,
89-
self = this;
90-
91-
if (!cb && typeof options === 'function') {
92-
cb = options;
93-
options = null;
94-
}
95-
96-
self.kuzzle.callbackRequired('KuzzleDataCollection.advancedSearch', cb);
97-
98-
query = self.kuzzle.addHeaders({body: filters}, this.headers);
99-
100-
self.kuzzle.query(this.buildQueryArgs('document', 'search'), query, options, function (error, result) {
101-
var
102-
response,
103-
documents = [];
104-
105-
if (error) {
106-
return cb(error);
107-
}
108-
109-
result.result.hits.forEach(function (doc) {
110-
var newDocument = new KuzzleDocument(self, doc._id, doc._source);
111-
112-
newDocument.version = doc._version;
113-
114-
documents.push(newDocument);
115-
});
116-
117-
response = {
118-
total: result.result.total,
119-
documents: documents
120-
};
121-
122-
if (result.result.aggregations) {
123-
response.aggregations = result.result.aggregations;
124-
}
125-
126-
cb(null, response);
127-
});
128-
};
129-
13081
/**
13182
* Returns the number of documents matching the provided set of filters.
13283
*
@@ -332,16 +283,51 @@ KuzzleDataCollection.prototype.fetchDocument = function (documentId, options, cb
332283
* @param {responseCallback} cb - Handles the query response
333284
*/
334285
KuzzleDataCollection.prototype.fetchAllDocuments = function (options, cb) {
335-
var filters = {};
286+
var
287+
warnEmitted = false,
288+
documents = [],
289+
filters = {};
336290

337291
if (!cb && typeof options === 'function') {
338292
cb = options;
339-
options = null;
293+
options = {};
340294
}
341295

342-
this.kuzzle.callbackRequired('KuzzleDataCollection.fetchAll', cb);
296+
// copying pagination options to the search filter
297+
if (!options) {
298+
options = {};
299+
}
300+
301+
if (!options.from) {
302+
options.from = 0;
303+
}
304+
305+
if (!options.size) {
306+
options.size = 1000;
307+
}
308+
309+
this.kuzzle.callbackRequired('KuzzleDataCollection.fetchAllDocuments', cb);
310+
311+
this.search(filters, options, function getNextDocuments (error, searchResult) {
312+
if (error) {
313+
return cb(error);
314+
}
315+
316+
if (searchResult instanceof KuzzleSearchResult) {
317+
if (searchResult.total > 10000 && !warnEmitted) {
318+
warnEmitted = true;
319+
console.warn('KuzzleDataCollection.fetchAllDocuments may return extremely large amounts of documents, which may cause performance issues. Unless you know what you are doing, consider using KuzzleDataCollection.search or KuzzleDataCollection.scroll instead'); // eslint-disable-line no-console
320+
}
343321

344-
this.advancedSearch(filters, options, cb);
322+
searchResult.documents.forEach(document => {
323+
documents.push(document);
324+
});
325+
searchResult.next(getNextDocuments);
326+
}
327+
else {
328+
cb(null, documents);
329+
}
330+
});
345331
};
346332

347333

@@ -435,6 +421,131 @@ KuzzleDataCollection.prototype.replaceDocument = function (documentId, content,
435421
return this;
436422
};
437423

424+
/**
425+
* Executes an advanced search on the data collection.
426+
*
427+
* /!\ There is a small delay between documents creation and their existence in our advanced search layer,
428+
* usually a couple of seconds.
429+
* That means that a document that was just been created won’t be returned by this function.
430+
*
431+
* @param {object} filters - Filters in Elasticsearch Query DSL format
432+
* @param {object} [options] - Optional parameters
433+
* @param {responseCallback} cb - Handles the query response
434+
*/
435+
436+
KuzzleDataCollection.prototype.search = function (filters, options, cb) {
437+
var
438+
query,
439+
self = this;
440+
441+
if (!cb && typeof options === 'function') {
442+
cb = options;
443+
options = {};
444+
}
445+
446+
self.kuzzle.callbackRequired('KuzzleDataCollection.search', cb);
447+
448+
query = self.kuzzle.addHeaders({body: filters}, this.headers);
449+
450+
451+
self.kuzzle.query(this.buildQueryArgs('document', 'search'), query, options, function (error, result) {
452+
var documents = [];
453+
454+
if (error) {
455+
return cb(error);
456+
}
457+
458+
result.result.hits.forEach(function (doc) {
459+
var newDocument = new KuzzleDocument(self, doc._id, doc._source);
460+
461+
newDocument.version = doc._version;
462+
463+
documents.push(newDocument);
464+
});
465+
466+
if (result.result._scroll_id) {
467+
options.scrollId = result.result._scroll_id;
468+
}
469+
470+
cb(null, new KuzzleSearchResult(
471+
self,
472+
result.result.total,
473+
documents,
474+
result.result.aggregations ? result.result.aggregations : [],
475+
{options: options, filters: filters}
476+
));
477+
});
478+
};
479+
480+
/**
481+
* A "scroll" option can be passed to search queries, creating persistent
482+
* paginated results.
483+
* This method can be used to manually get the next page of a search result,
484+
* instead of using KuzzleSearchResult.next()
485+
*
486+
* @param {string} scrollId
487+
* @param {object} [options]
488+
* @param {object} [filters]
489+
* @param {responseCallback} cb
490+
*/
491+
KuzzleDataCollection.prototype.scroll = function (scrollId, options, filters, cb) {
492+
var
493+
request = {body: {}},
494+
self = this;
495+
496+
if (!scrollId) {
497+
throw new Error('KuzzleDataCollection.scroll: scrollId required');
498+
}
499+
500+
if (!cb) {
501+
cb = filters;
502+
filters = null;
503+
}
504+
505+
if (!cb && typeof options === 'function') {
506+
cb = options;
507+
options = {};
508+
}
509+
510+
if (!options) {
511+
options = {};
512+
}
513+
514+
options.scrollId = scrollId;
515+
516+
this.kuzzle.callbackRequired('KuzzleDataCollection.scroll', cb);
517+
518+
this.kuzzle.query({controller: 'document', action: 'scroll'}, request, options, function (error, result) {
519+
var documents = [];
520+
521+
if (error) {
522+
return cb(error);
523+
}
524+
525+
result.result.hits.forEach(function (doc) {
526+
var newDocument = new KuzzleDocument(self, doc._id, doc._source);
527+
528+
newDocument.version = doc._version;
529+
530+
documents.push(newDocument);
531+
});
532+
533+
if (result.result._scroll_id) {
534+
options.scrollId = result.result._scroll_id;
535+
}
536+
537+
cb(null, new KuzzleSearchResult(
538+
self,
539+
result.result.total,
540+
documents,
541+
result.result.aggregations ? result.result.aggregations : [],
542+
{options: options, filters: filters}
543+
));
544+
});
545+
546+
return this;
547+
};
548+
438549
/**
439550
* Subscribes to this data collection with a set of filters.
440551
* To subscribe to the entire data collection, simply provide an empty filter.

src/kuzzleDataMapping.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
* The KuzzleDataMapping object allow to get the current mapping of a data collection and to modify it if needed.
1717
*
1818
* @param {object} kuzzleDataCollection - Instance of the inherited KuzzleDataCollection object
19-
* @param {object} mapping - mappings
19+
* @param {object} [mapping] - mappings
2020
* @constructor
2121
*/
2222
function KuzzleDataMapping(kuzzleDataCollection, mapping) {

0 commit comments

Comments
 (0)