Add support for filters in change feed (#111)

* Add find to doc functions

* Replace const by var

* Merge upstream

* Add support for filtered changes
This commit is contained in:
Andreas Siegel 2019-04-03 15:50:43 +02:00 committed by Geoff Cox
parent b069943b92
commit d07c87fae9
4 changed files with 153 additions and 6 deletions

49
API.md
View file

@ -16,8 +16,8 @@
* unsetIgnoreMissing(path)
* db
* all()
* changes(dbName, params)
* changesArray(dbName, params)
* [changes(dbName, params, filter)](https://github.com/redgeoff/slouch/blob/master/API.md#changesdbname-params-filter)
* [changesArray(dbName, params, filter)](https://github.com/redgeoff/slouch/blob/master/API.md#changesarraydbname-params-filter)
* copy(fromDBName, toDBName)
* create(dbName)
* destroy(dbName)
@ -97,6 +97,51 @@
* toUsername(userId)
* upsertRole(username, role)
### DB
#### changes(dbName, params, filter)
Returns a list of changes in the database. See https://docs.couchdb.org/en/stable/api/database/changes.html for more details.
The function returns an iterator that indefinitely returns changes from the database.
You can use an optional third argument to pass a selector for filtering the change feed.
Example:
```js
slouch.db.changes('myDB', {
include_docs: true,
feed: 'continuous',
heartbeat: true
}, {
selector: {
thing: 'findme'
}
});
```
#### changesArray(dbName, params, filter)
Returns a list of changes in the database. See https://docs.couchdb.org/en/stable/api/database/changes.html for more details.
The function returns an array of changes from the database.
You can use an optional third argument to pass a selector for filtering the change feed.
Example:
```js
slouch.db.changesArray('myDB', {
include_docs: true,
feed: 'continuous',
heartbeat: true
}, {
selector: {
thing: 'findme'
}
});
```
### Doc

4
package-lock.json generated
View file

@ -4128,7 +4128,11 @@
"dependencies": {
"events": {
"version": "1.1.1",
<<<<<<< Updated upstream
"resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz",
=======
"resolved": "http://registry.npmjs.org/events/-/events-1.1.1.tgz",
>>>>>>> Stashed changes
"integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ="
},
"sporks": {

View file

@ -63,7 +63,7 @@ DB.prototype._setSince = function (opts, lastSeq) {
};
// Use a JSONStream so that we don't have to load a large JSON structure into memory
DB.prototype.changes = function (dbName, params) {
DB.prototype.changes = function (dbName, params, filter) {
var self = this,
indefinite = false,
@ -94,10 +94,18 @@ DB.prototype.changes = function (dbName, params) {
request = self._slouch._request;
}
// When a filter object is provided use the key to set the filter query param
// Supported filters include doc_ids or selector
if (filter && Object.keys(filter).length === 1) {
params.filter = '_' + Object.keys(filter)[0];
}
var iterator = new CouchPersistentStreamIterator({
url: self._slouch._url + '/' + dbName + '/_changes',
method: 'GET',
qs: params
method: filter ? 'POST' : 'GET', // don't send a POST request if there is nothing for the body
qs: params,
json: filter,
parseBody: true
}, jsonStreamParseStr, indefinite, request, forceReconnectAfterMilliseconds);
return new FilteredStreamIterator(iterator, function (item) {
@ -108,10 +116,18 @@ DB.prototype.changes = function (dbName, params) {
};
DB.prototype.changesArray = function (dbName, params) {
DB.prototype.changesArray = function (dbName, params, filter) {
// When a filter object is provided use the key to set the filter query param
// Supported filters include doc_ids or selector
if (filter && Object.keys(filter).length === 1) {
params.filter = '_' + Object.keys(filter)[0];
}
return this._slouch._req({
url: this._slouch._url + '/' + encodeURIComponent(dbName) + '/_changes',
method: filter ? 'POST' : 'GET', // don't send a POST request if there is nothing for the body
qs: params,
json: filter,
parseBody: true
});
};

View file

@ -181,6 +181,45 @@ describe('db', function () {
});
});
it('should get changes with a selector', function () {
var changes = {};
return createDocs().then(function () {
return db.changes(utils.createdDB, {
include_docs: true
}, {
selector: {
thing: 'jam'
}
}).each(function (change) {
// Use associative array as order is not guaranteed
changes[change.doc.thing] = true;
});
}).then(function () {
changes.should.eql({
jam: true
});
});
});
it('should get no changes with an unknown selector', function () {
var changes = {};
return createDocs().then(function () {
return db.changes(utils.createdDB, {
include_docs: true
}, {
selector: {
thing: 'does-not-exist'
}
}).each(function (change) {
// Use associative array as order is not guaranteed
changes[change.doc.thing] = true;
});
}).then(function () {
changes.should.eql({});
});
});
it('should get changes array', function () {
var indexedChanges = {};
return createDocs().then(function () {
@ -201,6 +240,49 @@ describe('db', function () {
});
});
it('should get changes array with a selector', function () {
var indexedChanges = {};
return createDocs().then(function () {
return db.changesArray(utils.createdDB, {
include_docs: true
}, {
selector: {
thing: 'jam'
}
});
}).then(function (changes) {
// Order of changes not guaranteed so we will index the values for easy comparison
changes.results.forEach(function (change) {
indexedChanges[change.doc.thing] = true;
});
indexedChanges.should.eql({
jam: true
});
});
});
it('should get no changes array with a unknown selector', function () {
var indexedChanges = {};
return createDocs().then(function () {
return db.changesArray(utils.createdDB, {
include_docs: true
}, {
selector: {
thing: 'does-not-exist'
}
});
}).then(function (changes) {
// Order of changes not guaranteed so we will index the values for easy comparison
changes.results.forEach(function (change) {
indexedChanges[change.doc.thing] = true;
});
indexedChanges.should.eql({});
});
});
var waitForChange = function (thing) {
return sporks.waitFor(function () {
return changes[thing];