| |
| 'use strict'; |
| |
| var adapters = ['http', 'local']; |
| |
| adapters.forEach(function (adapter) { |
| |
| describe('test.changes.js-' + adapter, function () { |
| |
| var dbs = {}; |
| |
| // if it exists, return the single element |
| // which has the specific id. Else retun null. |
| // useful for finding elements within a _changes feed |
| function findById(array, id) { |
| var result = array.filter(function (i) { |
| return i.id === id; |
| }); |
| |
| // |
| if (result.length === 1) { |
| return result[0]; |
| } |
| } |
| |
| beforeEach(function (done) { |
| dbs.name = testUtils.adapterUrl(adapter, 'testdb'); |
| dbs.remote = testUtils.adapterUrl(adapter, 'test_repl_remote'); |
| testUtils.cleanup([dbs.name, dbs.remote], done); |
| }); |
| |
| after(function (done) { |
| testUtils.cleanup([dbs.name, dbs.remote], done); |
| }); |
| |
| it('All changes', function (done) { |
| var db = new PouchDB(dbs.name); |
| db.post({ test: 'somestuff' }, function (err, info) { |
| var promise = db.changes({ |
| onChange: function (change) { |
| change.should.not.have.property('doc'); |
| change.should.have.property('seq'); |
| done(); |
| } |
| }); |
| should.exist(promise); |
| promise.cancel.should.be.a('function'); |
| }); |
| }); |
| |
| it('Promise resolved when changes cancelled', function (done) { |
| var docs = [ |
| {_id: '0', integer: 0}, |
| {_id: '1', integer: 1}, |
| {_id: '2', integer: 2}, |
| {_id: '3', integer: 3}, |
| {_id: '4', integer: 4}, |
| {_id: '5', integer: 5}, |
| {_id: '6', integer: 6}, |
| {_id: '7', integer: 7}, |
| {_id: '8', integer: 9}, |
| {_id: '9', integer: 9}, |
| {_id: '10', integer: 10}, |
| ]; |
| var db = new PouchDB(dbs.name); |
| db.bulkDocs({ docs: docs }, function (err, info) { |
| var changeCount = 0; |
| var promise = db.changes({ |
| onChange: function (change) { |
| changeCount++; |
| if (changeCount === 5) { |
| promise.cancel(); |
| } |
| } |
| }); |
| should.exist(promise); |
| should.exist(promise.then); |
| promise.then.should.be.a('function'); |
| promise.then( |
| function (result) { |
| changeCount.should.equal(5, 'changeCount'); |
| should.exist(result); |
| result.should.deep.equal({status: 'cancelled'}); |
| done(); |
| }, function (err) { |
| changeCount.should.equal(5, 'changeCount'); |
| should.exist(err); |
| done(); |
| }); |
| }); |
| }); |
| |
| it('Changes Since Old Style', function (done) { |
| var docs1 = [ |
| {_id: '0', integer: 0}, |
| {_id: '1', integer: 1}, |
| {_id: '2', integer: 2}, |
| {_id: '3', integer: 3}, |
| {_id: '4', integer: 4}, |
| {_id: '5', integer: 5}, |
| {_id: '6', integer: 6}, |
| {_id: '7', integer: 7}, |
| {_id: '8', integer: 9}, |
| {_id: '9', integer: 9}, |
| {_id: '10', integer: 10}, |
| {_id: '11', integer: 11} |
| ]; |
| var db = new PouchDB(dbs.name); |
| |
| db.bulkDocs({ docs: docs1 }, function (err, info) { |
| db.info(function (err, info) { |
| var update_seq = info.update_seq; |
| |
| var docs2 = [ |
| {_id: '12', integer: 12}, |
| {_id: '13', integer: 13} |
| ]; |
| |
| db.bulkDocs({ docs: docs2 }, function (err, info) { |
| var promise = db.changes({ |
| since: update_seq, |
| complete: function (err, results) { |
| results.results.length.should.be.at.least(2); |
| done(); |
| } |
| }); |
| should.exist(promise); |
| promise.cancel.should.be.a('function'); |
| }); |
| }); |
| }); |
| }); |
| |
| it('Changes Since New Style', function (done) { |
| var docs1 = [ |
| {_id: '0', integer: 0}, |
| {_id: '1', integer: 1}, |
| {_id: '2', integer: 2}, |
| {_id: '3', integer: 3}, |
| {_id: '4', integer: 4}, |
| {_id: '5', integer: 5}, |
| {_id: '6', integer: 6}, |
| {_id: '7', integer: 7}, |
| {_id: '8', integer: 9}, |
| {_id: '9', integer: 9}, |
| {_id: '10', integer: 10}, |
| {_id: '11', integer: 11} |
| ]; |
| var db = new PouchDB(dbs.name); |
| |
| db.bulkDocs({ docs: docs1 }, function (err, info) { |
| db.info(function (err, info) { |
| var update_seq = info.update_seq; |
| |
| var docs2 = [ |
| {_id: '12', integer: 12}, |
| {_id: '13', integer: 13} |
| ]; |
| |
| db.bulkDocs({ docs: docs2 }, function (err, info) { |
| var promise = db.changes({ |
| since: update_seq |
| }).on('complete', function (results) { |
| results.results.length.should.be.at.least(2); |
| done(); |
| }); |
| should.exist(promise); |
| promise.cancel.should.be.a('function'); |
| }); |
| }); |
| }); |
| }); |
| |
| it('Changes Since and limit Old Style liimt 1', function (done) { |
| var docs1 = [ |
| {_id: '0', integer: 0}, |
| {_id: '1', integer: 1}, |
| {_id: '2', integer: 2} |
| ]; |
| var db = new PouchDB(dbs.name); |
| db.bulkDocs({ docs: docs1 }, function (err, info) { |
| db.info(function (err, info) { |
| var update_seq = info.update_seq; |
| |
| var docs2 = [ |
| {_id: '3', integer: 3}, |
| {_id: '4', integer: 4} |
| ]; |
| |
| db.bulkDocs({ docs: docs2 }, function (err, info) { |
| db.changes({ |
| since: update_seq, |
| limit: 1, |
| complete: function (err, results) { |
| results.results.length.should.equal(1); |
| done(); |
| } |
| }); |
| }); |
| }); |
| }); |
| }); |
| |
| it('Changes Since and limit New Style limit 1', function (done) { |
| var docs1 = [ |
| {_id: '0', integer: 0}, |
| {_id: '1', integer: 1}, |
| {_id: '2', integer: 2} |
| ]; |
| var db = new PouchDB(dbs.name); |
| db.bulkDocs({ docs: docs1 }, function (err, info) { |
| db.info(function (err, info) { |
| var update_seq = info.update_seq; |
| |
| var docs2 = [ |
| {_id: '3', integer: 3}, |
| {_id: '4', integer: 4} |
| ]; |
| |
| db.bulkDocs({ docs: docs2 }, function (err, info) { |
| db.changes({ |
| since: update_seq, |
| limit: 1 |
| }).on('complete', function (results) { |
| results.results.length.should.equal(1); |
| done(); |
| }); |
| }); |
| }); |
| }); |
| }); |
| |
| it('Changes Since and limit Old Style limit 0', function (done) { |
| var docs1 = [ |
| {_id: '0', integer: 0}, |
| {_id: '1', integer: 1}, |
| {_id: '2', integer: 2} |
| ]; |
| var db = new PouchDB(dbs.name); |
| db.bulkDocs({ docs: docs1 }, function (err, info) { |
| db.info(function (err, info) { |
| var update_seq = info.update_seq; |
| |
| var docs2 = [ |
| {_id: '3', integer: 3}, |
| {_id: '4', integer: 4} |
| ]; |
| |
| db.bulkDocs({ docs: docs2 }, function (err, info) { |
| db.changes({ |
| since: update_seq, |
| limit: 0, |
| complete: function (err, results) { |
| results.results.length.should.equal(1); |
| done(); |
| } |
| }); |
| }); |
| }); |
| }); |
| }); |
| |
| it('Changes Since and limit New Style limit 0', function (done) { |
| var docs1 = [ |
| {_id: '0', integer: 0}, |
| {_id: '1', integer: 1}, |
| {_id: '2', integer: 2} |
| ]; |
| var db = new PouchDB(dbs.name); |
| db.bulkDocs({ docs: docs1 }, function (err, info) { |
| db.info(function (err, info) { |
| var update_seq = info.update_seq; |
| |
| var docs2 = [ |
| {_id: '3', integer: 3}, |
| {_id: '4', integer: 4} |
| ]; |
| |
| db.bulkDocs({ docs: docs2 }, function (err, info) { |
| db.changes({ |
| since: update_seq, |
| limit: 0 |
| }).on('complete', function (results) { |
| results.results.length.should.equal(1); |
| done(); |
| }); |
| }); |
| }); |
| }); |
| }); |
| |
| it('Changes limit Old Style', function (done) { |
| var docs1 = [ |
| {_id: '0', integer: 0}, |
| {_id: '1', integer: 1}, |
| {_id: '2', integer: 2}, |
| {_id: '3', integer: 3} |
| ]; |
| var docs2 = [ |
| {_id: '2', integer: 11}, |
| {_id: '3', integer: 12}, |
| ]; |
| var db = new PouchDB(dbs.name); |
| // we use writeDocs since bulkDocs looks to have undefined |
| // order of doing insertions |
| testUtils.writeDocs(db, docs1, function (err, info) { |
| docs2[0]._rev = info[2].rev; |
| docs2[1]._rev = info[3].rev; |
| |
| db.info(function (err, info) { |
| var update_seq = info.update_seq; |
| |
| db.put(docs2[0], function (err, info) { |
| docs2[0]._rev = info.rev; |
| db.put(docs2[1], function (err, info) { |
| docs2[1]._rev = info.rev; |
| db.changes({ |
| limit: 2, |
| since: update_seq, |
| include_docs: true, |
| complete: function (err, results) { |
| results = results.results; |
| results.length.should.equal(2); |
| |
| // order is not guaranteed |
| var first = results[0]; |
| var second = results[1]; |
| if (first.id === '3') { |
| second = first; |
| first = results[1]; |
| } |
| first.id.should.equal('2'); |
| first.doc.integer.should.equal(docs2[0].integer); |
| first.doc._rev.should.equal(docs2[0]._rev); |
| second.id.should.equal('3'); |
| second.doc.integer.should.equal(docs2[1].integer); |
| second.doc._rev.should.equal(docs2[1]._rev); |
| done(); |
| } |
| }); |
| }); |
| }); |
| }); |
| }); |
| }); |
| |
| it('Changes limit New Style', function (done) { |
| var docs1 = [ |
| {_id: '0', integer: 0}, |
| {_id: '1', integer: 1}, |
| {_id: '2', integer: 2}, |
| {_id: '3', integer: 3} |
| ]; |
| var docs2 = [ |
| {_id: '2', integer: 11}, |
| {_id: '3', integer: 12}, |
| ]; |
| var db = new PouchDB(dbs.name); |
| // we use writeDocs since bulkDocs looks to have undefined |
| // order of doing insertions |
| testUtils.writeDocs(db, docs1, function (err, info) { |
| docs2[0]._rev = info[2].rev; |
| docs2[1]._rev = info[3].rev; |
| |
| db.info(function (err, info) { |
| var update_seq = info.update_seq; |
| |
| db.put(docs2[0], function (err, info) { |
| docs2[0]._rev = info.rev; |
| db.put(docs2[1], function (err, info) { |
| docs2[1]._rev = info.rev; |
| db.changes({ |
| limit: 2, |
| since: update_seq, |
| include_docs: true |
| }).on('complete', function (results) { |
| results = results.results; |
| results.length.should.equal(2); |
| |
| // order is not guaranteed |
| var first = results[0]; |
| var second = results[1]; |
| if (first.id === '3') { |
| second = first; |
| first = results[1]; |
| } |
| first.id.should.equal('2'); |
| first.doc.integer.should.equal(docs2[0].integer); |
| first.doc._rev.should.equal(docs2[0]._rev); |
| second.id.should.equal('3'); |
| second.doc.integer.should.equal(docs2[1].integer); |
| second.doc._rev.should.equal(docs2[1]._rev); |
| done(); |
| }); |
| }); |
| }); |
| }); |
| }); |
| }); |
| |
| it('Changes with filter not present in ddoc', function (done) { |
| this.timeout(15000); |
| var docs = [ |
| {_id: '1', integer: 1}, |
| { _id: '_design/foo', |
| integer: 4, |
| filters: { even: 'function (doc) { return doc.integer % 2 === 1; }' } |
| } |
| ]; |
| var db = new PouchDB(dbs.name); |
| testUtils.writeDocs(db, docs, function (err, info) { |
| db.changes({ |
| filter: 'foo/odd', |
| limit: 2, |
| include_docs: true, |
| complete: function (err, results) { |
| err.status.should.equal(PouchDB.Errors.MISSING_DOC.status, |
| 'correct error status returned'); |
| err.message.should.equal(PouchDB.Errors.MISSING_DOC.message, |
| 'correct error message returned'); |
| // todo: does not work in pouchdb-server. |
| // err.reason.should.equal('missing json key: odd'); |
| should.not.exist(results); |
| done(); |
| } |
| }); |
| }); |
| }); |
| |
| it('Changes with `filters` key not present in ddoc', function (done) { |
| var docs = [ |
| {_id: '0', integer: 0}, |
| {_id: '1', integer: 1}, |
| { |
| _id: '_design/foo', |
| integer: 4, |
| views: { |
| even: { |
| map: 'function (doc) { if (doc.integer % 2 === 1)' + |
| ' { emit(doc._id, null) }; }' |
| } |
| } |
| } |
| ]; |
| var db = new PouchDB(dbs.name); |
| testUtils.writeDocs(db, docs, function (err, info) { |
| db.changes({ |
| filter: 'foo/even', |
| limit: 2, |
| include_docs: true, |
| complete: function (err, results) { |
| err.status.should.equal(PouchDB.Errors.MISSING_DOC.status, |
| 'correct error status returned'); |
| err.message.should.equal(PouchDB.Errors.MISSING_DOC.message, |
| 'correct error message returned'); |
| // todo: does not work in pouchdb-server. |
| // err.reason.should.equal('missing json key: filters'); |
| should.not.exist(results); |
| done(); |
| } |
| }); |
| }); |
| }); |
| |
| it('Changes limit and filter', function (done) { |
| var docs1 = [ |
| {_id: '0', integer: 0}, |
| {_id: '1', integer: 1}, |
| {_id: '2', integer: 2} |
| ]; |
| var db = new PouchDB(dbs.name); |
| |
| var docs2 = [ |
| {_id: '3', integer: 3}, |
| {_id: '4', integer: 4}, |
| {_id: '5', integer: 5}, |
| { |
| _id: '_design/foo', |
| integer: 4, |
| filters: { even: 'function (doc) { return doc.integer % 2 === 1; }' } |
| } |
| ]; |
| |
| db.bulkDocs({ docs: docs1 }, function (err, info) { |
| db.info(function (err, info) { |
| var update_seq = info.update_seq; |
| |
| testUtils.writeDocs(db, docs2, function (err, info) { |
| var promise = db.changes({ |
| filter: 'foo/even', |
| limit: 2, |
| since: update_seq, |
| include_docs: true, |
| complete: function (err, results) { |
| results.results.length.should.equal(2); |
| var three = findById(results.results, '3'); |
| three.doc.integer.should.equal(3); |
| var five = findById(results.results, '5'); |
| five.doc.integer.should.equal(5); |
| done(); |
| } |
| }); |
| should.exist(promise); |
| promise.cancel.should.be.a('function'); |
| }); |
| }); |
| }); |
| }); |
| |
| it('Changes with shorthand function name', function (done) { |
| var docs = [ |
| {_id: '0', integer: 0}, |
| {_id: '1', integer: 1}, |
| {_id: '2', integer: 2}, |
| { |
| _id: '_design/even', |
| integer: 3, |
| filters: { even: 'function (doc) { return doc.integer % 2 === 0; }' } |
| } |
| ]; |
| var db = new PouchDB(dbs.name); |
| |
| db.bulkDocs({ docs: docs }, function (err, info) { |
| var promise = db.changes({ |
| filter: 'even', |
| include_docs: true, |
| complete: function (err, results) { |
| results.results.length.should.equal(2); |
| var zero = findById(results.results, '0'); |
| zero.doc.integer.should.equal(0); |
| var two = findById(results.results, '2'); |
| two.doc.integer.should.equal(2); |
| done(); |
| } |
| }); |
| should.exist(promise); |
| promise.cancel.should.be.a('function'); |
| }); |
| }); |
| |
| it('Changes with filter from nonexistent ddoc', function (done) { |
| var docs = [ |
| {_id: '0', integer: 0}, |
| {_id: '1', integer: 1}, |
| ]; |
| var db = new PouchDB(dbs.name); |
| testUtils.writeDocs(db, docs, function (err, info) { |
| db.changes({ |
| filter: 'foobar/odd', |
| complete: function (err, results) { |
| err.status.should.equal(PouchDB.Errors.MISSING_DOC.status, |
| 'correct error status returned'); |
| err.message.should.equal(PouchDB.Errors.MISSING_DOC.message, |
| 'correct error message returned'); |
| should.not.exist(results); |
| done(); |
| } |
| }); |
| }); |
| }); |
| |
| it('Changes with view not present in ddoc', function (done) { |
| var docs = [ |
| {_id: '0', integer: 0}, |
| {_id: '1', integer: 1}, |
| { |
| _id: '_design/foo', |
| integer: 4, |
| views: |
| { even: |
| { map: 'function (doc) { if (doc.integer % 2 === 1) { ' + |
| 'emit(doc._id, null) }; }' } } |
| } |
| ]; |
| var db = new PouchDB(dbs.name); |
| testUtils.writeDocs(db, docs, function (err, info) { |
| db.changes({ |
| filter: '_view', |
| view: 'foo/odd', |
| complete: function (err, results) { |
| err.status.should.equal(PouchDB.Errors.MISSING_DOC.status, |
| 'correct error status returned'); |
| err.message.should.equal(PouchDB.Errors.MISSING_DOC.message, |
| 'correct error message returned'); |
| // todo: does not work in pouchdb-server. |
| // err.reason.should.equal('missing json key: odd'); |
| should.not.exist(results); |
| done(); |
| } |
| }); |
| }); |
| }); |
| |
| it('Changes with `views` key not present in ddoc', function (done) { |
| var docs = [ |
| {_id: '1', integer: 1}, |
| { |
| _id: '_design/foo', |
| integer: 4, |
| filters: { even: 'function (doc) { return doc.integer % 2 === 1; }' } |
| } |
| ]; |
| var db = new PouchDB(dbs.name); |
| testUtils.writeDocs(db, docs, function (err, info) { |
| db.changes({ |
| filter: '_view', |
| view: 'foo/even', |
| complete: function (err, results) { |
| err.status.should.equal(PouchDB.Errors.MISSING_DOC.status, |
| 'correct error status returned'); |
| err.message.should.equal(PouchDB.Errors.MISSING_DOC.message, |
| 'correct error message returned'); |
| // todo: does not work in pouchdb-server. |
| // err.reason.should.equal('missing json key: views', |
| // 'correct error reason returned'); |
| should.not.exist(results); |
| done(); |
| } |
| }); |
| }); |
| }); |
| |
| it('Changes with missing param `view` in request', function (done) { |
| var docs = [ |
| {_id: '0', integer: 0}, |
| {_id: '1', integer: 1}, |
| { |
| _id: '_design/foo', |
| integer: 4, |
| views: { even: { map: 'function (doc) { if (doc.integer % 2 === 1) ' + |
| '{ emit(doc._id, null) }; }' } } |
| } |
| ]; |
| var db = new PouchDB(dbs.name); |
| testUtils.writeDocs(db, docs, function (err, info) { |
| db.changes({ |
| filter: '_view', |
| complete: function (err, results) { |
| err.status.should.equal(PouchDB.Errors.BAD_REQUEST.status, |
| 'correct error status returned'); |
| err.message.should.equal(PouchDB.Errors.BAD_REQUEST.message, |
| 'correct error message returned'); |
| // todo: does not work in pouchdb-server. |
| // err.reason.should |
| // .equal('`view` filter parameter is not provided.', |
| // 'correct error reason returned'); |
| should.not.exist(results); |
| done(); |
| } |
| }); |
| }); |
| }); |
| |
| it('Changes limit and view instead of filter', function (done) { |
| var docs1 = [ |
| {_id: '0', integer: 0}, |
| {_id: '1', integer: 1}, |
| {_id: '2', integer: 2} |
| ]; |
| var db = new PouchDB(dbs.name); |
| db.bulkDocs({ docs: docs1 }, function (err, info) { |
| db.info(function (err, info) { |
| var update_seq = info.update_seq; |
| |
| var docs2 = [ |
| {_id: '3', integer: 3}, |
| {_id: '4', integer: 4}, |
| {_id: '5', integer: 5}, |
| { |
| _id: '_design/foo', |
| integer: 4, |
| views: { even: { map: 'function (doc) ' + |
| '{ if (doc.integer % 2 === 1) ' + |
| '{ emit(doc._id, null) }; }' |
| } |
| } |
| } |
| ]; |
| |
| db.bulkDocs({ docs: docs2 }, function (err, info) { |
| |
| db.changes({ |
| filter: '_view', |
| view: 'foo/even', |
| limit: 2, |
| since: update_seq, |
| include_docs: true, |
| complete: function (err, results) { |
| var changes = results.results; |
| changes.length.should.equal(2); |
| |
| findById(changes, '3') |
| .doc.integer.should.equal(3); |
| |
| findById(changes, '5') |
| .doc.integer.should.equal(5); |
| |
| done(); |
| } |
| }); |
| }); |
| }); |
| }); |
| }); |
| |
| it('Changes last_seq', function (done) { |
| // this test doesn't really make sense for clustered |
| // CouchDB because changes is unordered and last_seq might |
| // not equal the last seq in the _changes feed (although it |
| // should evaluate to the same thing on the server). |
| if (testUtils.isCouchMaster()) { |
| return done(); |
| } |
| |
| var docs = [ |
| {_id: '0', integer: 0}, |
| {_id: '1', integer: 1}, |
| {_id: '2', integer: 2}, |
| {_id: '3', integer: 3}, |
| { |
| _id: '_design/foo', |
| integer: 4, |
| filters: { even: 'function (doc) { return doc.integer % 2 === 1; }' } |
| } |
| ]; |
| var db = new PouchDB(dbs.name); |
| db.changes({ |
| complete: function (err, results) { |
| results.last_seq.should.equal(0); |
| db.bulkDocs({ docs: docs }, function (err, info) { |
| db.changes({ |
| complete: function (err, results) { |
| results.last_seq.should.equal(5); |
| db.changes({ |
| filter: 'foo/even', |
| complete: function (err, results) { |
| results.last_seq.should.equal(5); |
| results.results.length.should.equal(2); |
| done(); |
| } |
| }); |
| } |
| }); |
| }); |
| } |
| }); |
| }); |
| |
| it('Changes last_seq with view instead of filter', function (done) { |
| // this test doesn't really make sense for clustered |
| // CouchDB because changes is unordered and last_seq might |
| // not equal the last seq in the _changes feed (although it |
| // should evaluate to the same thing on the server). |
| if (testUtils.isCouchMaster()) { |
| return done(); |
| } |
| |
| var docs = [ |
| {_id: '0', integer: 0}, |
| {_id: '1', integer: 1}, |
| {_id: '2', integer: 2}, |
| {_id: '3', integer: 3}, |
| { |
| _id: '_design/foo', |
| integer: 4, |
| views: |
| { even: |
| { map: 'function (doc) { if (doc.integer % 2 === 1) { ' + |
| 'emit(doc._id, null) }; }' } } |
| } |
| ]; |
| var db = new PouchDB(dbs.name); |
| db.changes({ |
| complete: function (err, results) { |
| results.last_seq.should.equal(0); |
| db.bulkDocs({ docs: docs }, function (err, info) { |
| db.changes({ |
| complete: function (err, results) { |
| results.last_seq.should.equal(5); |
| db.changes({ |
| filter: '_view', |
| view: 'foo/even', |
| complete: function (err, results) { |
| results.last_seq.should.equal(5); |
| results.results.length.should.equal(2); |
| done(); |
| } |
| }); |
| } |
| }); |
| }); |
| } |
| }); |
| }); |
| |
| it('Changes with style = all_docs', function (done) { |
| var simpleTree = [ |
| [{_id: 'foo', _rev: '1-a', value: 'foo a'}, |
| {_id: 'foo', _rev: '2-b', value: 'foo b'}, |
| {_id: 'foo', _rev: '3-c', value: 'foo c'}], |
| [{_id: 'foo', _rev: '1-a', value: 'foo a'}, |
| {_id: 'foo', _rev: '2-d', value: 'foo d'}, |
| {_id: 'foo', _rev: '3-e', value: 'foo e'}, |
| {_id: 'foo', _rev: '4-f', value: 'foo f'}], |
| [{_id: 'foo', _rev: '1-a', value: 'foo a'}, |
| {_id: 'foo', _rev: '2-g', value: 'foo g', _deleted: true}] |
| ]; |
| var db = new PouchDB(dbs.name); |
| testUtils.putTree(db, simpleTree, function () { |
| db.changes({ |
| complete: function (err, res) { |
| res.results[0].changes.length.should.equal(1); |
| res.results[0].changes[0].rev.should.equal('4-f'); |
| db.changes({ |
| style: 'all_docs', |
| complete: function (err, res) { |
| res.results[0].changes.length.should.equal(3); |
| var changes = res.results[0].changes; |
| changes.sort(function (a, b) { |
| return a.rev < b.rev; |
| }); |
| changes[0].rev.should.equal('4-f'); |
| changes[1].rev.should.equal('3-c'); |
| changes[2].rev.should.equal('2-g'); |
| done(); |
| } |
| }); |
| } |
| }); |
| }); |
| }); |
| |
| it('Changes with style = all_docs and a callback for complete', |
| function (done) { |
| var simpleTree = [ |
| [{_id: 'foo', _rev: '1-a', value: 'foo a'}, |
| {_id: 'foo', _rev: '2-b', value: 'foo b'}, |
| {_id: 'foo', _rev: '3-c', value: 'foo c'}], |
| [{_id: 'foo', _rev: '1-a', value: 'foo a'}, |
| {_id: 'foo', _rev: '2-d', value: 'foo d'}, |
| {_id: 'foo', _rev: '3-e', value: 'foo e'}, |
| {_id: 'foo', _rev: '4-f', value: 'foo f'}], |
| [{_id: 'foo', _rev: '1-a', value: 'foo a'}, |
| {_id: 'foo', _rev: '2-g', value: 'foo g', _deleted: true}] |
| ]; |
| var db = new PouchDB(dbs.name); |
| testUtils.putTree(db, simpleTree, function () { |
| db.changes(function (err, res) { |
| res.results[0].changes.length.should.equal(1); |
| res.results[0].changes[0].rev.should.equal('4-f'); |
| db.changes({ |
| style: 'all_docs', |
| complete: function () { |
| done(new Error('this should never be called')); |
| } |
| }, function (err, res) { |
| res.results[0].changes.length.should.equal(3); |
| var changes = res.results[0].changes; |
| changes.sort(function (a, b) { |
| return a.rev < b.rev; |
| }); |
| changes[0].rev.should.equal('4-f'); |
| changes[1].rev.should.equal('3-c'); |
| changes[2].rev.should.equal('2-g'); |
| done(); |
| }); |
| }); |
| }); |
| }); |
| |
| it('Changes limit = 0', function (done) { |
| var docs = [ |
| {_id: '0', integer: 0}, |
| {_id: '1', integer: 1}, |
| {_id: '2', integer: 2}, |
| {_id: '3', integer: 3}, |
| ]; |
| var db = new PouchDB(dbs.name); |
| db.bulkDocs({ docs: docs }, function (err, info) { |
| db.changes({ |
| limit: 0, |
| complete: function (err, results) { |
| results.results.length.should.equal(1); |
| done(); |
| } |
| }); |
| }); |
| }); |
| |
| // Note for the following test that CouchDB's implementation of /_changes |
| // with `descending=true` ignores any `since` parameter. |
| it('Descending changes', function (done) { |
| // _changes in CouchDB 2.0 does not guarantee order |
| // so skip this test |
| if (testUtils.isCouchMaster()) { |
| return done(); |
| } |
| var db = new PouchDB(dbs.name); |
| db.post({_id: '0', test: 'ing'}, function (err, res) { |
| db.post({_id: '1', test: 'ing'}, function (err, res) { |
| db.post({_id: '2', test: 'ing'}, function (err, res) { |
| db.changes({ |
| descending: true, |
| since: 1, |
| complete: function (err, results) { |
| results.results.length.should.equal(3); |
| var ids = ['2', '1', '0']; |
| results.results.forEach(function (row, i) { |
| row.id.should.equal(ids[i]); |
| }); |
| done(); |
| } |
| }); |
| }); |
| }); |
| }); |
| }); |
| |
| it('Changes doc Old Style', function (done) { |
| var db = new PouchDB(dbs.name); |
| db.post({ test: 'somestuff' }, function (err, info) { |
| db.changes({ |
| include_docs: true, |
| onChange: function (change) { |
| change.doc._id.should.equal(change.id); |
| change.doc._rev.should |
| .equal(change.changes[change.changes.length - 1].rev); |
| done(); |
| } |
| }); |
| }); |
| }); |
| |
| it('Changes doc New Style', function (done) { |
| var db = new PouchDB(dbs.name); |
| db.post({ test: 'somestuff' }, function (err, info) { |
| db.changes({ |
| include_docs: true |
| }).on('change', function (change) { |
| change.doc._id.should.equal(change.id); |
| change.doc._rev.should |
| .equal(change.changes[change.changes.length - 1].rev); |
| done(); |
| }); |
| }); |
| }); |
| |
| // Note for the following test that CouchDB's implementation of /_changes |
| // with `descending=true` ignores any `since` parameter. |
| it('Descending many changes Old Style', function (done) { |
| var db = new PouchDB(dbs.name); |
| var docs = []; |
| var num = 100; |
| for (var i = 0; i < num; i++) { |
| docs.push({ |
| _id: 'doc_' + i, |
| foo: 'bar_' + i |
| }); |
| } |
| var changes = 0; |
| db.bulkDocs({ docs: docs }, function (err, info) { |
| if (err) { |
| return done(err); |
| } |
| db.changes({ |
| descending: true, |
| onChange: function (change) { |
| changes++; |
| }, |
| complete: function (err, results) { |
| if (err) { |
| return done(err); |
| } |
| changes.should.equal(num, 'correct number of changes'); |
| done(); |
| } |
| }); |
| }); |
| }); |
| |
| it('Descending many changes New Style', function (done) { |
| var db = new PouchDB(dbs.name); |
| var docs = []; |
| var num = 100; |
| for (var i = 0; i < num; i++) { |
| docs.push({ |
| _id: 'doc_' + i, |
| foo: 'bar_' + i |
| }); |
| } |
| var changes = 0; |
| db.bulkDocs({ docs: docs }, function (err, info) { |
| if (err) { |
| return done(err); |
| } |
| db.changes({ |
| descending: true |
| }).on('change', function (change) { |
| changes++; |
| }).on('complete', function (results) { |
| changes.should.equal(num, 'correct number of changes'); |
| done(); |
| }).on('error', function (err) { |
| done(err); |
| }); |
| }); |
| }); |
| |
| it('live-changes Old Style', function (done) { |
| var db = new PouchDB(dbs.name); |
| var count = 0; |
| var changes = db.changes({ |
| live: true, |
| complete: function () { |
| count.should.equal(1); |
| done(); |
| }, |
| onChange: function (change) { |
| count += 1; |
| change.should.not.have.property('doc'); |
| count.should.equal(1); |
| changes.cancel(); |
| }, |
| }); |
| db.post({ test: 'adoc' }); |
| }); |
| |
| it('live-changes New Style', function (done) { |
| var db = new PouchDB(dbs.name); |
| var count = 0; |
| var changes = db.changes({ |
| live: true |
| }).on('complete', function () { |
| count.should.equal(1); |
| done(); |
| }).on('change', function (change) { |
| count += 1; |
| change.should.not.have.property('doc'); |
| count.should.equal(1); |
| changes.cancel(); |
| }); |
| db.post({ test: 'adoc' }); |
| }); |
| |
| it('Multiple watchers Old Style', function (done) { |
| var db = new PouchDB(dbs.name); |
| var count = 0; |
| var changes1Complete = false; |
| var changes2Complete = false; |
| function checkCount() { |
| if (changes1Complete && changes2Complete) { |
| count.should.equal(2); |
| done(); |
| } |
| } |
| var changes1 = db.changes({ |
| complete: function () { |
| changes1Complete = true; |
| checkCount(); |
| }, |
| onChange: function (change) { |
| count += 1; |
| changes1.cancel(); |
| changes1 = null; |
| }, |
| live: true |
| }); |
| var changes2 = db.changes({ |
| complete: function () { |
| changes2Complete = true; |
| checkCount(); |
| }, |
| onChange: function (change) { |
| count += 1; |
| changes2.cancel(); |
| changes2 = null; |
| }, |
| live: true |
| }); |
| db.post({test: 'adoc'}); |
| }); |
| |
| it('Multiple watchers New Style', function (done) { |
| var db = new PouchDB(dbs.name); |
| var count = 0; |
| var changes1Complete = false; |
| var changes2Complete = false; |
| function checkCount() { |
| if (changes1Complete && changes2Complete) { |
| count.should.equal(2); |
| done(); |
| } |
| } |
| var changes1 = db.changes({ |
| live: true |
| }).on('complete', function () { |
| changes1Complete = true; |
| checkCount(); |
| }).on('change', function (change) { |
| count += 1; |
| changes1.cancel(); |
| changes1 = null; |
| }); |
| var changes2 = db.changes({ |
| live: true |
| }).on('complete', function () { |
| changes2Complete = true; |
| checkCount(); |
| }).on('change', function (change) { |
| count += 1; |
| changes2.cancel(); |
| changes2 = null; |
| }); |
| db.post({test: 'adoc'}); |
| }); |
| |
| it('Continuous changes doc', function (done) { |
| var db = new PouchDB(dbs.name); |
| var changes = db.changes({ |
| complete: function (err, result) { |
| result.status.should.equal('cancelled'); |
| done(); |
| }, |
| onChange: function (change) { |
| change.should.have.property('doc'); |
| change.doc.should.have.property('_rev'); |
| changes.cancel(); |
| }, |
| live: true, |
| include_docs: true |
| }); |
| db.post({ test: 'adoc' }); |
| }); |
| |
| it('Cancel changes Old Style', function (done) { |
| var db = new PouchDB(dbs.name); |
| var count = 0; |
| var interval; |
| var docPosted = false; |
| |
| // We want to wait for a period of time after the final |
| // document was posted to ensure we didnt see another |
| // change |
| function waitForDocPosted() { |
| if (!docPosted) { |
| return; |
| } |
| clearInterval(interval); |
| setTimeout(function () { |
| count.should.equal(1); |
| done(); |
| }, 200); |
| } |
| |
| var changes = db.changes({ |
| complete: function (err, result) { |
| result.status.should.equal('cancelled'); |
| // This setTimeout ensures that once we cancel a change we dont |
| // recieve subsequent callbacks, so it is needed |
| interval = setInterval(waitForDocPosted, 100); |
| }, |
| onChange: function (change) { |
| count += 1; |
| if (count === 1) { |
| changes.cancel(); |
| db.post({ test: 'another doc' }, function (err, res) { |
| if (err) { |
| return done(err); |
| } |
| docPosted = true; |
| }); |
| } |
| }, |
| live: true |
| }); |
| db.post({ test: 'adoc' }); |
| }); |
| |
| it('Cancel changes New Style', function (done) { |
| var db = new PouchDB(dbs.name); |
| var count = 0; |
| var interval; |
| var docPosted = false; |
| |
| // We want to wait for a period of time after the final |
| // document was posted to ensure we didnt see another |
| // change |
| function waitForDocPosted() { |
| if (!docPosted) { |
| return; |
| } |
| clearInterval(interval); |
| setTimeout(function () { |
| count.should.equal(1); |
| done(); |
| }, 200); |
| } |
| |
| var changes = db.changes({ |
| live: true |
| }).on('complete', function (result) { |
| result.status.should.equal('cancelled'); |
| // This setTimeout ensures that once we cancel a change we dont recieve |
| // subsequent callbacks, so it is needed |
| interval = setInterval(waitForDocPosted, 100); |
| }).on('change', function (change) { |
| count += 1; |
| if (count === 1) { |
| changes.cancel(); |
| db.post({ test: 'another doc' }, function (err, res) { |
| if (err) { |
| return done(err); |
| } |
| docPosted = true; |
| }); |
| } |
| }); |
| db.post({ test: 'adoc' }); |
| }); |
| |
| |
| it("#3579 changes firing 1 too many times", function () { |
| var db = new PouchDB(dbs.name); |
| var Promise = PouchDB.utils.Promise; |
| return db.bulkDocs([{}, {}, {}]).then(function () { |
| var changes = db.changes({ |
| since: 'now', |
| live: true, |
| include_docs: true |
| }); |
| return Promise.all([ |
| new Promise(function (resolve, reject) { |
| changes.on('error', reject); |
| changes.on('change', function (change) { |
| changes.cancel(); |
| resolve(change); |
| }); |
| }), |
| new Promise(function (resolve) { |
| setTimeout(resolve, 50); |
| }).then(function () { |
| return db.put({_id: 'foobar'}); |
| }) |
| ]); |
| }).then(function (result) { |
| var change = result[0]; |
| change.id.should.equal('foobar'); |
| change.doc._id.should.equal('foobar'); |
| }); |
| }); |
| |
| it('Kill database while listening to live changes', function (done) { |
| var db = new PouchDB(dbs.name); |
| var count = 0; |
| db.changes({ |
| complete: function (err, result) { |
| done(); |
| }, |
| onChange: function (change) { |
| count++; |
| if (count === 1) { |
| db.destroy(); |
| } |
| }, |
| live: true |
| }); |
| db.post({ test: 'adoc' }); |
| }); |
| |
| it('#3136 style=all_docs', function () { |
| |
| var db = new PouchDB(dbs.name); |
| |
| var chain = PouchDB.utils.Promise.resolve(); |
| |
| var docIds = ['b', 'c', 'a', 'z', 'd', 'e']; |
| |
| docIds.forEach(function (docId) { |
| chain = chain.then(function () { |
| return db.put({_id: docId}); |
| }); |
| }); |
| |
| return chain.then(function () { |
| return db.changes({style: 'all_docs'}); |
| }).then(function (res) { |
| var ids = res.results.map(function (x) { |
| return x.id; |
| }); |
| ids.should.include.members(docIds); |
| }); |
| }); |
| |
| it('#3136 style=all_docs & include_docs', function () { |
| |
| var db = new PouchDB(dbs.name); |
| |
| var chain = PouchDB.utils.Promise.resolve(); |
| |
| var docIds = ['b', 'c', 'a', 'z', 'd', 'e']; |
| |
| docIds.forEach(function (docId) { |
| chain = chain.then(function () { |
| return db.put({_id: docId}); |
| }); |
| }); |
| |
| return chain.then(function () { |
| return db.changes({ |
| style: 'all_docs', |
| include_docs: true |
| }); |
| }).then(function (res) { |
| var ids = res.results.map(function (x) { |
| return x.id; |
| }); |
| ids.should.include.members(docIds); |
| }); |
| }); |
| |
| it('#3136 tricky changes, limit/descending', function () { |
| if (testUtils.isCouchMaster()) { |
| return true; |
| } |
| |
| var db = new PouchDB(dbs.name); |
| |
| var docs = [ |
| { |
| _id: 'alpha', |
| _rev: '1-a', |
| _revisions: { |
| start: 1, |
| ids: ['a'] |
| } |
| }, { |
| _id: 'beta', |
| _rev: '1-b', |
| _revisions: { |
| start: 1, |
| ids: ['b'] |
| } |
| }, { |
| _id: 'gamma', |
| _rev: '1-b', |
| _revisions: { |
| start: 1, |
| ids: ['b'] |
| } |
| }, { |
| _id: 'alpha', |
| _rev: '2-d', |
| _revisions: { |
| start: 2, |
| ids: ['d', 'a'] |
| } |
| }, { |
| _id: 'beta', |
| _rev: '2-e', |
| _revisions: { |
| start: 2, |
| ids: ['e', 'b'] |
| } |
| }, { |
| _id: 'beta', |
| _rev: '3-f', |
| _deleted: true, |
| _revisions: { |
| start: 3, |
| ids: ['f', 'e', 'b'] |
| } |
| } |
| ]; |
| |
| var chain = PouchDB.utils.Promise.resolve(); |
| var seqs = []; |
| |
| docs.forEach(function (doc) { |
| chain = chain.then(function () { |
| return db.bulkDocs([doc], {new_edits: false}).then(function () { |
| return db.changes({doc_ids: [doc._id]}); |
| }).then(function (res) { |
| seqs.push(res.results[0].seq); |
| }); |
| }); |
| }); |
| |
| function normalizeResult(result) { |
| // order of changes doesn't matter |
| result.results.forEach(function (ch) { |
| ch.changes = ch.changes.sort(function (a, b) { |
| return a.rev < b.rev ? -1 : 1; |
| }); |
| }); |
| } |
| |
| return chain.then(function () { |
| return db.changes(); |
| }).then(function (result) { |
| normalizeResult(result); |
| result.should.deep.equal({ |
| "results": [ |
| { |
| "seq": seqs[2], |
| "id": "gamma", |
| "changes": [{ "rev": "1-b"} |
| ] |
| }, |
| { |
| "seq": seqs[3], |
| "id": "alpha", |
| "changes": [{ "rev": "2-d"} |
| ] |
| }, |
| { |
| "seq": seqs[5], |
| "id": "beta", |
| "deleted": true, |
| "changes": [{ "rev": "3-f"} |
| ] |
| } |
| ], |
| "last_seq": seqs[5] |
| }); |
| return db.changes({limit: 0}); |
| }).then(function (result) { |
| normalizeResult(result); |
| result.should.deep.equal({ |
| "results": [{ |
| "seq": seqs[2], |
| "id": "gamma", |
| "changes": [{"rev": "1-b"}] |
| }], |
| "last_seq": seqs[2] |
| }, '1:' + JSON.stringify(result)); |
| return db.changes({limit: 1}); |
| }).then(function (result) { |
| normalizeResult(result); |
| result.should.deep.equal({ |
| "results": [{ |
| "seq": seqs[2], |
| "id": "gamma", |
| "changes": [{"rev": "1-b"}] |
| }], |
| "last_seq": seqs[2] |
| }, '2:' + JSON.stringify(result)); |
| return db.changes({limit: 2}); |
| }).then(function (result) { |
| normalizeResult(result); |
| result.should.deep.equal({ |
| "results": [{ |
| "seq": seqs[2], |
| "id": "gamma", |
| "changes": [{"rev": "1-b"}] |
| }, {"seq": seqs[3], "id": "alpha", "changes": [{"rev": "2-d"}]}], |
| "last_seq": seqs[3] |
| }, '3:' + JSON.stringify(result)); |
| return db.changes({limit: 1, descending: true}); |
| }).then(function (result) { |
| normalizeResult(result); |
| result.should.deep.equal({ |
| "results": [{ |
| "seq": seqs[5], |
| "id": "beta", |
| "changes": [{"rev": "3-f"}], |
| "deleted": true |
| }], |
| "last_seq": seqs[5] |
| }, '4:' + JSON.stringify(result)); |
| return db.changes({limit: 2, descending: true}); |
| }).then(function (result) { |
| normalizeResult(result); |
| var expected = { |
| "results": [{ |
| "seq": seqs[5], |
| "id": "beta", |
| "changes": [{"rev": "3-f"}], |
| "deleted": true |
| }, {"seq": seqs[3], "id": "alpha", "changes": [{"rev": "2-d"}]}], |
| "last_seq": seqs[3] |
| }; |
| result.should.deep.equal(expected, '5:' + JSON.stringify(result) + |
| ', shoulda got: ' + JSON.stringify(expected)); |
| return db.changes({descending: true}); |
| }).then(function (result) { |
| normalizeResult(result); |
| var expected = { |
| "results": [{ |
| "seq": seqs[5], |
| "id": "beta", |
| "changes": [{"rev": "3-f"}], |
| "deleted": true |
| }, {"seq": seqs[3], "id": "alpha", "changes": [{"rev": "2-d"}]}, { |
| "seq": seqs[2], |
| "id": "gamma", |
| "changes": [{"rev": "1-b"}] |
| }], |
| "last_seq": seqs[2] |
| }; |
| result.should.deep.equal(expected, '6:' + JSON.stringify(result) + |
| ', shoulda got: ' + JSON.stringify(expected)); |
| }); |
| }); |
| |
| it('#3176 winningRev has a lower seq, descending', function () { |
| if (testUtils.isCouchMaster()) { |
| return true; |
| } |
| |
| var db = new PouchDB(dbs.name); |
| var tree = [ |
| [ |
| { |
| _id: 'foo', |
| _rev: '1-a', |
| _revisions: {start: 1, ids: ['a']} |
| }, |
| { |
| _id: 'foo', |
| _rev: '2-e', |
| _deleted: true, |
| _revisions: {start: 2, ids: ['e', 'a']} |
| }, |
| { |
| _id: 'foo', |
| _rev: '3-g', |
| _revisions: {start: 3, ids: ['g', 'e', 'a']} |
| } |
| ], |
| [ |
| { |
| _id: 'foo', |
| _rev: '1-a', |
| _revisions: {start: 1, ids: ['a']} |
| }, |
| { |
| _id: 'foo', |
| _rev: '2-b', |
| _revisions: {start: 2, ids: ['b', 'a']} |
| }, |
| { |
| _id: 'foo', |
| _rev: '3-c', |
| _revisions: {start: 3, ids: ['c', 'b', 'a']} |
| } |
| ] |
| ]; |
| |
| var chain = PouchDB.utils.Promise.resolve(); |
| var seqs = [0]; |
| |
| function getExpected(i) { |
| var expecteds = [ |
| { |
| "results": [ |
| { |
| "seq": seqs[1], |
| "id": "foo", |
| "changes": [{"rev": "3-g"}] |
| } |
| ], |
| "last_seq" : seqs[1] |
| }, |
| { |
| "results": [ |
| { |
| "seq": seqs[2], |
| "id": "foo", |
| "changes": [{"rev": "3-g"}] |
| } |
| ], |
| "last_seq" : seqs[2] |
| } |
| ]; |
| return expecteds[i]; |
| } |
| |
| function normalizeResult(result) { |
| // order of changes doesn't matter |
| result.results.forEach(function (ch) { |
| ch.changes = ch.changes.sort(function (a, b) { |
| return a.rev < b.rev ? -1 : 1; |
| }); |
| }); |
| } |
| |
| tree.forEach(function (docs, i) { |
| chain = chain.then(function () { |
| return db.bulkDocs(docs, {new_edits: false}).then(function () { |
| return db.changes({ |
| descending: true |
| }); |
| }).then(function (result) { |
| seqs.push(result.last_seq); |
| var expected = getExpected(i); |
| normalizeResult(result); |
| result.should.deep.equal(expected, |
| i + ': should get: ' + JSON.stringify(expected) + |
| ', but got: ' + JSON.stringify(result)); |
| }); |
| }); |
| }); |
| return chain; |
| }); |
| |
| it('#3136 winningRev has a lower seq, style=all_docs', function () { |
| if (testUtils.isCouchMaster()) { |
| return true; |
| } |
| |
| var db = new PouchDB(dbs.name); |
| var tree = [ |
| [ |
| { |
| _id: 'foo', |
| _rev: '1-a', |
| _revisions: {start: 1, ids: ['a']} |
| }, |
| { |
| _id: 'foo', |
| _rev: '2-e', |
| _deleted: true, |
| _revisions: {start: 2, ids: ['e', 'a']} |
| }, |
| { |
| _id: 'foo', |
| _rev: '3-g', |
| _revisions: {start: 3, ids: ['g', 'e', 'a']} |
| } |
| ], |
| [ |
| { |
| _id: 'foo', |
| _rev: '1-a', |
| _revisions: {start: 1, ids: ['a']} |
| }, |
| { |
| _id: 'foo', |
| _rev: '2-b', |
| _revisions: {start: 2, ids: ['b', 'a']} |
| }, |
| { |
| _id: 'foo', |
| _rev: '3-c', |
| _revisions: {start: 3, ids: ['c', 'b', 'a']} |
| } |
| ], |
| [ |
| { |
| _id: 'foo', |
| _rev: '1-a', |
| _revisions: {start: 1, ids: ['a']} |
| }, |
| { |
| _id: 'foo', |
| _rev: '2-d', |
| _revisions: {start: 2, ids: ['d', 'a']} |
| }, |
| { |
| _id: 'foo', |
| _rev: '3-h', |
| _revisions: {start: 3, ids: ['h', 'd', 'a']} |
| }, |
| { |
| _id: 'foo', |
| _rev: '4-f', |
| _revisions: {start: 4, ids: ['f', 'h', 'd', 'a']} |
| } |
| ] |
| ]; |
| |
| var chain = PouchDB.utils.Promise.resolve(); |
| var seqs = [0]; |
| |
| function getExpected(i) { |
| var expecteds = [ |
| { |
| "results": [ |
| { |
| "seq": seqs[1], |
| "id": "foo", |
| "changes": [{"rev": "3-g"}], |
| "doc": {"_id": "foo", "_rev": "3-g"} |
| } |
| ], |
| "last_seq" : seqs[1] |
| }, |
| { |
| "results": [ |
| { |
| "seq": seqs[2], |
| "id": "foo", |
| "changes": [{"rev": "3-c"}, {"rev": "3-g"}], |
| "doc": {"_id": "foo", "_rev": "3-g"} |
| } |
| ], |
| "last_seq" : seqs[2] |
| }, |
| { |
| "results": [ |
| { |
| "seq": seqs[3], |
| "id": "foo", |
| "changes": [{"rev": "3-c"}, {"rev": "3-g"}, {"rev": "4-f"}], |
| "doc": {"_id": "foo", "_rev": "4-f"} |
| } |
| ], |
| "last_seq" : seqs[3] |
| } |
| ]; |
| return expecteds[i]; |
| } |
| |
| function normalizeResult(result) { |
| // order of changes doesn't matter |
| result.results.forEach(function (ch) { |
| ch.changes = ch.changes.sort(function (a, b) { |
| return a.rev < b.rev ? -1 : 1; |
| }); |
| }); |
| } |
| |
| tree.forEach(function (docs, i) { |
| chain = chain.then(function () { |
| return db.bulkDocs(docs, {new_edits: false}).then(function () { |
| return db.changes({ |
| style: 'all_docs', |
| since: seqs[seqs.length - 1], |
| include_docs: true |
| }); |
| }).then(function (result) { |
| seqs.push(result.last_seq); |
| var expected = getExpected(i); |
| normalizeResult(result); |
| result.should.deep.equal(expected, |
| i + ': should get: ' + JSON.stringify(expected) + |
| ', but got: ' + JSON.stringify(result)); |
| }); |
| }); |
| }); |
| return chain; |
| }); |
| |
| it('#3136 winningRev has a lower seq, style=all_docs 2', function () { |
| if (testUtils.isCouchMaster()) { |
| return true; |
| } |
| |
| var db = new PouchDB(dbs.name); |
| var tree = [ |
| [ |
| { |
| _id: 'foo', |
| _rev: '1-a', |
| _revisions: {start: 1, ids: ['a']} |
| }, |
| { |
| _id: 'foo', |
| _rev: '2-e', |
| _deleted: true, |
| _revisions: {start: 2, ids: ['e', 'a']} |
| }, |
| { |
| _id: 'foo', |
| _rev: '3-g', |
| _revisions: {start: 3, ids: ['g', 'e', 'a']} |
| } |
| ], [ |
| { |
| _id: 'foo', |
| _rev: '1-a', |
| _revisions: {start: 1, ids: ['a']} |
| }, |
| { |
| _id: 'foo', |
| _rev: '2-b', |
| _revisions: {start: 2, ids: ['b', 'a']} |
| }, |
| { |
| _id: 'foo', |
| _rev: '3-c', |
| _revisions: {start: 3, ids: ['c', 'b', 'a']} |
| }, |
| ], [ |
| { |
| _id: 'bar', |
| _rev: '1-z', |
| _revisions: {start: 1, ids: ['z']} |
| } |
| ] |
| ]; |
| |
| var chain = PouchDB.utils.Promise.resolve(); |
| var seqs = [0]; |
| |
| tree.forEach(function (docs, i) { |
| chain = chain.then(function () { |
| return db.bulkDocs(docs, {new_edits: false}).then(function () { |
| return db.changes(); |
| }).then(function (result) { |
| seqs.push(result.last_seq); |
| }); |
| }); |
| }); |
| |
| return chain.then(function () { |
| |
| var expecteds = [ |
| { |
| "results": [{ |
| "seq": seqs[2], |
| "id": "foo", |
| "changes": [{"rev": "3-c"}, {"rev": "3-g"}] |
| }, {"seq": seqs[3], "id": "bar", "changes": [{"rev": "1-z"}]}], |
| "last_seq": seqs[3] |
| }, |
| { |
| "results": [{ |
| "seq": seqs[2], |
| "id": "foo", |
| "changes": [{"rev": "3-c"}, {"rev": "3-g"}] |
| }, {"seq": seqs[3], "id": "bar", "changes": [{"rev": "1-z"}]}], |
| "last_seq": seqs[3] |
| }, |
| { |
| "results": [{"seq": seqs[3], "id": "bar", |
| "changes": [{"rev": "1-z"}]}], |
| "last_seq": seqs[3] |
| }, |
| {"results": [], "last_seq": seqs[3]} |
| ]; |
| |
| var chain2 = PouchDB.utils.Promise.resolve(); |
| |
| function normalizeResult(result) { |
| // order of changes doesn't matter |
| result.results.forEach(function (ch) { |
| ch.changes = ch.changes.sort(function (a, b) { |
| return a.rev < b.rev ? -1 : 1; |
| }); |
| }); |
| } |
| |
| seqs.forEach(function (seq, i) { |
| chain2 = chain2.then(function () { |
| return db.changes({ |
| since: seq, |
| style: 'all_docs' |
| }).then(function (res) { |
| normalizeResult(res); |
| res.should.deep.equal(expecteds[i], 'since=' + seq + |
| ': got: ' + |
| JSON.stringify(res) + |
| ', shoulda got: ' + |
| JSON.stringify(expecteds[i])); |
| }); |
| }); |
| }); |
| return chain2; |
| }); |
| }); |
| |
| it('#3136 winningRev has a higher seq, using limit', function () { |
| if (testUtils.isCouchMaster()) { |
| return true; |
| } |
| |
| var db = new PouchDB(dbs.name); |
| var tree = [ |
| [ |
| { |
| _id: 'foo', |
| _rev: '1-a', |
| _revisions: {start: 1, ids: ['a']} |
| } |
| ], [ |
| { |
| _id: 'foo', |
| _rev: '2-b', |
| _revisions: {start: 2, ids: ['b', 'a']} |
| } |
| ], [ |
| { |
| _id: 'bar', |
| _rev: '1-x', |
| _revisions: {start: 1, ids: ['x']} |
| } |
| ], [ |
| { |
| _id: 'foo', |
| _rev: '2-c', |
| _deleted: true, |
| _revisions: {start: 2, ids: ['c', 'a']} |
| }, |
| ] |
| ]; |
| |
| var chain = PouchDB.utils.Promise.resolve(); |
| var seqs = [0]; |
| |
| tree.forEach(function (docs, i) { |
| chain = chain.then(function () { |
| return db.bulkDocs(docs, {new_edits: false}).then(function () { |
| return db.changes().then(function (result) { |
| seqs.push(result.last_seq); |
| }); |
| }); |
| }); |
| }); |
| |
| return chain.then(function () { |
| |
| var expecteds = [{ |
| "results": [{ |
| "seq": seqs[3], |
| "id": "bar", |
| "changes": [{"rev": "1-x"}], |
| "doc": {"_id": "bar", "_rev": "1-x"} |
| }], |
| "last_seq": seqs[3] |
| }, |
| { |
| "results": [{ |
| "seq": seqs[3], |
| "id": "bar", |
| "changes": [{"rev": "1-x"}], |
| "doc": {"_id": "bar", "_rev": "1-x"} |
| }], |
| "last_seq": seqs[3] |
| }, |
| { |
| "results": [{ |
| "seq": seqs[3], |
| "id": "bar", |
| "changes": [{"rev": "1-x"}], |
| "doc": {"_id": "bar", "_rev": "1-x"} |
| }], |
| "last_seq": seqs[3] |
| }, |
| { |
| "results": [{ |
| "seq": seqs[4], |
| "id": "foo", |
| "changes": [{"rev": "2-b"}, {"rev": "2-c"}], |
| "doc": {"_id": "foo", "_rev": "2-b"} |
| }], |
| "last_seq": seqs[4] |
| }, |
| {"results": [], "last_seq": seqs[4]} |
| ]; |
| |
| var chain2 = PouchDB.utils.Promise.resolve(); |
| |
| function normalizeResult(result) { |
| // order of changes doesn't matter |
| result.results.forEach(function (ch) { |
| ch.changes = ch.changes.sort(function (a, b) { |
| return a.rev < b.rev ? -1 : 1; |
| }); |
| }); |
| } |
| |
| seqs.forEach(function (seq, i) { |
| chain2 = chain2.then(function () { |
| return db.changes({ |
| style: 'all_docs', |
| since: seq, |
| limit: 1, |
| include_docs: true |
| }); |
| }).then(function (result) { |
| normalizeResult(result); |
| result.should.deep.equal(expecteds[i], |
| i + ': got: ' + JSON.stringify(result) + |
| ', shoulda got: ' + JSON.stringify(expecteds[i])); |
| }); |
| }); |
| return chain2; |
| }); |
| }); |
| |
| it('changes-filter', function (done) { |
| var docs1 = [ |
| {_id: '0', integer: 0}, |
| {_id: '1', integer: 1}, |
| {_id: '2', integer: 2}, |
| {_id: '3', integer: 3}, |
| ]; |
| var docs2 = [ |
| {_id: '4', integer: 4}, |
| {_id: '5', integer: 5}, |
| {_id: '6', integer: 6}, |
| {_id: '7', integer: 7}, |
| ]; |
| var db = new PouchDB(dbs.name); |
| var count = 0; |
| db.bulkDocs({ docs: docs1 }, function (err, info) { |
| var changes = db.changes({ |
| complete: function (err, result) { |
| result.status.should.equal('cancelled'); |
| done(); |
| }, |
| filter: function (doc) { |
| return doc.integer % 2 === 0; |
| }, |
| onChange: function (change) { |
| count += 1; |
| if (count === 4) { |
| changes.cancel(); |
| } |
| }, |
| live: true |
| }); |
| db.bulkDocs({ docs: docs2 }); |
| }); |
| }); |
| |
| it('changes-filter with query params', function (done) { |
| var docs1 = [ |
| {_id: '0', integer: 0}, |
| {_id: '1', integer: 1}, |
| {_id: '2', integer: 2}, |
| {_id: '3', integer: 3}, |
| ]; |
| var docs2 = [ |
| {_id: '4', integer: 4}, |
| {_id: '5', integer: 5}, |
| {_id: '6', integer: 6}, |
| {_id: '7', integer: 7}, |
| ]; |
| var params = { 'abc': true }; |
| var db = new PouchDB(dbs.name); |
| var count = 0; |
| db.bulkDocs({ docs: docs1 }, function (err, info) { |
| var changes = db.changes({ |
| complete: function (err, result) { |
| result.status.should.equal('cancelled'); |
| done(); |
| }, |
| filter: function (doc, req) { |
| if (req.query.abc) { |
| return doc.integer % 2 === 0; |
| } |
| }, |
| query_params: params, |
| onChange: function (change) { |
| count += 1; |
| if (count === 4) { |
| changes.cancel(); |
| } |
| }, |
| live: true |
| }); |
| db.bulkDocs({ docs: docs2 }); |
| }); |
| }); |
| |
| it('Non-live changes filter', function (done) { |
| var docs1 = [ |
| {_id: '0', integer: 0}, |
| {_id: '1', integer: 1}, |
| {_id: '2', integer: 2}, |
| {_id: '3', integer: 3}, |
| ]; |
| var db = new PouchDB(dbs.name); |
| db.bulkDocs({ docs: docs1 }, function (err, info) { |
| db.changes({ |
| complete: function (err, allChanges) { |
| db.changes({ |
| filter: function (doc) { |
| return doc.integer % 2 === 0; |
| }, |
| complete: function (err, filteredChanges) { |
| // Should get docs 0 and 2 if the filter |
| // has been applied correctly. |
| filteredChanges.results.length.should.equal(2); |
| filteredChanges.last_seq.should.deep.equal(allChanges.last_seq); |
| done(); |
| } |
| }); |
| } |
| }); |
| }); |
| }); |
| |
| it('Non-live changes filter, descending', function (done) { |
| var docs1 = [ |
| {_id: '0', integer: 0}, |
| {_id: '1', integer: 1}, |
| {_id: '2', integer: 2}, |
| {_id: '3', integer: 3}, |
| ]; |
| var db = new PouchDB(dbs.name); |
| db.bulkDocs({ docs: docs1 }, function (err, info) { |
| db.changes({ |
| descending: true, |
| complete: function (err, allChanges) { |
| db.changes({ |
| descending: true, |
| filter: function (doc) { |
| return doc.integer > 2; |
| }, |
| complete: function (err, filteredChanges) { |
| // Should get docs 2 and 3 if the filter |
| // has been applied correctly. |
| filteredChanges.results.length.should.equal(1); |
| filteredChanges.last_seq.should.deep.equal(allChanges.last_seq); |
| done(); |
| } |
| }); |
| } |
| }); |
| }); |
| }); |
| |
| it('#2569 Non-live doc_ids filter', function () { |
| var docs = [ |
| {_id: '0'}, |
| {_id: '1'}, |
| {_id: '2'}, |
| {_id: '3'} |
| ]; |
| var db = new PouchDB(dbs.name); |
| return db.bulkDocs(docs).then(function () { |
| return db.changes({ |
| doc_ids: ['1', '3'] |
| }); |
| }).then(function (changes) { |
| var ids = changes.results.map(function (x) { |
| return x.id; |
| }); |
| ids.sort().should.deep.equal(['1', '3']); |
| }); |
| }); |
| |
| it('#2569 Big non-live doc_ids filter', function () { |
| var docs = []; |
| for (var i = 0; i < 5; i++) { |
| var id = ''; |
| for (var j = 0; j < 50; j++) { |
| // make a huge id |
| id += PouchDB.utils.btoa(Math.random().toString()); |
| } |
| docs.push({_id: id}); |
| } |
| var db = new PouchDB(dbs.name); |
| return db.bulkDocs(docs).then(function () { |
| return db.changes({ |
| doc_ids: [docs[1]._id, docs[3]._id] |
| }); |
| }).then(function (changes) { |
| var ids = changes.results.map(function (x) { |
| return x.id; |
| }); |
| var expectedIds = [docs[1]._id, docs[3]._id]; |
| ids.sort().should.deep.equal(expectedIds.sort()); |
| }); |
| }); |
| |
| it('#2569 Live doc_ids filter', function () { |
| var docs = [ |
| {_id: '0'}, |
| {_id: '1'}, |
| {_id: '2'}, |
| {_id: '3'} |
| ]; |
| var db = new PouchDB(dbs.name); |
| return db.bulkDocs(docs).then(function () { |
| return new PouchDB.utils.Promise(function (resolve, reject) { |
| var retChanges = []; |
| var changes = db.changes({ |
| doc_ids: ['1', '3'], |
| live: true |
| }).on('change', function (change) { |
| retChanges.push(change); |
| if (retChanges.length === 2) { |
| changes.cancel(); |
| resolve(retChanges); |
| } |
| }).on('error', reject); |
| }); |
| }).then(function (changes) { |
| var ids = changes.map(function (x) { |
| return x.id; |
| }); |
| var expectedIds = ['1', '3']; |
| ids.sort().should.deep.equal(expectedIds); |
| }); |
| }); |
| |
| it('#2569 Big live doc_ids filter', function () { |
| var docs = []; |
| for (var i = 0; i < 5; i++) { |
| var id = ''; |
| for (var j = 0; j < 50; j++) { |
| // make a huge id |
| id += PouchDB.utils.btoa(Math.random().toString()); |
| } |
| docs.push({_id: id}); |
| } |
| var db = new PouchDB(dbs.name); |
| return db.bulkDocs(docs).then(function () { |
| return new PouchDB.utils.Promise(function (resolve, reject) { |
| var retChanges = []; |
| var changes = db.changes({ |
| doc_ids: [docs[1]._id, docs[3]._id], |
| live: true |
| }).on('change', function (change) { |
| retChanges.push(change); |
| if (retChanges.length === 2) { |
| changes.cancel(); |
| resolve(retChanges); |
| } |
| }).on('error', reject); |
| }); |
| }).then(function (changes) { |
| var ids = changes.map(function (x) { |
| return x.id; |
| }); |
| var expectedIds = [docs[1]._id, docs[3]._id]; |
| ids.sort().should.deep.equal(expectedIds.sort()); |
| }); |
| }); |
| |
| it('#2569 Non-live doc_ids filter with filter=_doc_ids', function () { |
| var docs = [ |
| {_id: '0'}, |
| {_id: '1'}, |
| {_id: '2'}, |
| {_id: '3'} |
| ]; |
| var db = new PouchDB(dbs.name); |
| return db.bulkDocs(docs).then(function () { |
| return db.changes({ |
| filter: '_doc_ids', |
| doc_ids: ['1', '3'] |
| }); |
| }).then(function (changes) { |
| var ids = changes.results.map(function (x) { |
| return x.id; |
| }); |
| ids.sort().should.deep.equal(['1', '3']); |
| }); |
| }); |
| |
| it('#2569 Live doc_ids filter with filter=_doc_ids', function () { |
| var docs = [ |
| {_id: '0'}, |
| {_id: '1'}, |
| {_id: '2'}, |
| {_id: '3'} |
| ]; |
| var db = new PouchDB(dbs.name); |
| return db.bulkDocs(docs).then(function () { |
| return db.changes({ |
| filter: '_doc_ids', |
| doc_ids: ['1', '3'] |
| }); |
| }).then(function (changes) { |
| var ids = changes.results.map(function (x) { |
| return x.id; |
| }); |
| ids.sort().should.deep.equal(['1', '3']); |
| }); |
| }); |
| |
| it('Changes to same doc are grouped', function (done) { |
| var docs1 = [ |
| {_id: '0', integer: 0}, |
| {_id: '1', integer: 1}, |
| {_id: '2', integer: 2}, |
| {_id: '3', integer: 3}, |
| ]; |
| var docs2 = [ |
| {_id: '2', integer: 11}, |
| {_id: '3', integer: 12}, |
| ]; |
| var db = new PouchDB(dbs.name); |
| db.bulkDocs({ docs: docs1 }, function (err, info) { |
| docs2[0]._rev = info[2].rev; |
| docs2[1]._rev = info[3].rev; |
| db.put(docs2[0], function (err, info) { |
| db.put(docs2[1], function (err, info) { |
| db.changes({ |
| include_docs: true, |
| complete: function (err, changes) { |
| changes.results.length.should.equal(4); |
| |
| var second = findById(changes.results, '2'); |
| second.changes.length.should.equal(1); |
| second.doc.integer.should.equal(11); |
| done(); |
| } |
| }); |
| }); |
| }); |
| }); |
| }); |
| |
| it('Changes with conflicts are handled correctly', function (testDone) { |
| var docs1 = [ |
| {_id: '0', integer: 0}, |
| {_id: '1', integer: 1}, |
| {_id: '2', integer: 2}, |
| {_id: '3', integer: 3}, |
| ]; |
| var docs2 = [ |
| {_id: '2', integer: 11}, |
| {_id: '3', integer: 12}, |
| ]; |
| new PouchDB(dbs.name).then(function (localdb) { |
| var remotedb = new PouchDB(dbs.remote); |
| return localdb.bulkDocs({ docs: docs1 }).then(function (info) { |
| docs2[0]._rev = info[2].rev; |
| docs2[1]._rev = info[3].rev; |
| return localdb.put(docs2[0]).then(function (info) { |
| return localdb.put(docs2[1]).then(function (info) { |
| var rev2 = info.rev; |
| return PouchDB.replicate(localdb, remotedb).then(function (done) { |
| // update remote once, local twice, then replicate from |
| // remote to local so the remote losing conflict is later in |
| // the tree |
| return localdb.put({ |
| _id: '3', |
| _rev: rev2, |
| integer: 20 |
| }).then(function (resp) { |
| var rev3Doc = { |
| _id: '3', |
| _rev: resp.rev, |
| integer: 30 |
| }; |
| return localdb.put(rev3Doc).then(function (resp) { |
| var rev4local = resp.rev; |
| var rev4Doc = { |
| _id: '3', |
| _rev: rev2, |
| integer: 100 |
| }; |
| return remotedb.put(rev4Doc).then(function (resp) { |
| var remoterev = resp.rev; |
| return PouchDB.replicate(remotedb, localdb).then( |
| function (done) { |
| return localdb.changes({ |
| include_docs: true, |
| style: 'all_docs', |
| conflicts: true |
| }).on('error', testDone) |
| .then(function (changes) { |
| changes.results.length.should.equal(4); |
| var ch = findById(changes.results, '3'); |
| ch.changes.length.should.equal(2); |
| ch.doc.integer.should.equal(30); |
| ch.doc._rev.should.equal(rev4local); |
| ch.changes.should.deep.equal([ |
| { rev: rev4local }, |
| { rev: remoterev } |
| ]); |
| |
| ch.doc.should.have.property('_conflicts'); |
| ch.doc._conflicts.length.should.equal(1); |
| ch.doc._conflicts[0].should.equal(remoterev); |
| }); |
| }); |
| }); |
| }); |
| }); |
| }); |
| }); |
| }); |
| }).then(function () { |
| testDone(); |
| }, testDone); |
| }); |
| }); |
| |
| it('Change entry for a deleted doc', function (done) { |
| var docs1 = [ |
| {_id: '0', integer: 0}, |
| {_id: '1', integer: 1}, |
| {_id: '2', integer: 2}, |
| {_id: '3', integer: 3} |
| ]; |
| var db = new PouchDB(dbs.name); |
| db.bulkDocs({ docs: docs1 }, function (err, info) { |
| var rev = info[3].rev; |
| db.remove({ |
| _id: '3', |
| _rev: rev |
| }, function (err, info) { |
| db.changes({ |
| include_docs: true, |
| complete: function (err, changes) { |
| changes.results.length.should.equal(4); |
| var ch = findById(changes.results, '3'); |
| // sequence numbers are not incremental in CouchDB 2.0 |
| if (!testUtils.isCouchMaster()) { |
| ch.seq.should.equal(5); |
| } |
| ch.deleted.should.equal(true); |
| done(); |
| } |
| }); |
| }); |
| }); |
| }); |
| |
| it('changes large number of docs', function (done) { |
| var docs = []; |
| var num = 30; |
| for (var i = 0; i < num; i++) { |
| docs.push({ |
| _id: 'doc_' + i, |
| foo: 'bar_' + i |
| }); |
| } |
| var db = new PouchDB(dbs.name); |
| db.bulkDocs({ docs: docs }, function (err, info) { |
| db.changes({ |
| complete: function (err, res) { |
| res.results.length.should.equal(num); |
| done(); |
| } |
| }); |
| }); |
| }); |
| |
| it('Calling db.changes({since: \'now\'})', function (done) { |
| var db = new PouchDB(dbs.name); |
| db.bulkDocs({ docs: [{ foo: 'bar' }] }, function (err, data) { |
| db.info(function (err, info) { |
| var api = db.changes({ |
| since: 'now', |
| complete: function (err, res) { |
| should.not.exist(err); |
| |
| // last_seq and update_seq might be encoded differently |
| // in clustered CouchDB - they cannot be reliably compared. |
| if (!testUtils.isCouchMaster()) { |
| res.last_seq.should.equal(info.update_seq); |
| } |
| done(); |
| } |
| }); |
| api.should.be.an('object'); |
| api.cancel.should.be.an('function'); |
| }); |
| }); |
| }); |
| |
| //Duplicate to make sure both api options work. |
| it('Calling db.changes({since: \'latest\'})', function (done) { |
| var db = new PouchDB(dbs.name); |
| db.bulkDocs({ docs: [{ foo: 'bar' }] }, function (err, data) { |
| db.info(function (err, info) { |
| var api = db.changes({ |
| since: 'latest', |
| complete: function (err, res) { |
| should.not.exist(err); |
| // last_seq and update_seq might be encoded differently |
| // in clustered CouchDB - they cannot be reliably compared. |
| if (!testUtils.isCouchMaster()) { |
| res.last_seq.should.equal(info.update_seq); |
| } |
| done(); |
| } |
| }); |
| api.should.be.an('object'); |
| api.cancel.should.be.an('function'); |
| }); |
| }); |
| }); |
| |
| it('Closing db does not cause a crash if changes cancelled', |
| function (done) { |
| var db = new PouchDB(dbs.name); |
| var called = 0; |
| function checkDone() { |
| called++; |
| if (called === 2) { |
| done(); |
| } |
| } |
| db.bulkDocs({ docs: [{ foo: 'bar' }] }, function (err, data) { |
| var changes = db.changes({ |
| live: true, |
| onChange: function () { }, |
| complete: function (err, result) { |
| result.status.should.equal('cancelled'); |
| checkDone(); |
| } |
| }); |
| should.exist(changes); |
| changes.cancel.should.be.a('function'); |
| changes.cancel(); |
| db.close(function (error) { |
| should.not.exist(error); |
| checkDone(); |
| }); |
| }); |
| }); |
| |
| it('fire-complete-on-cancel', function (done) { |
| var db = new PouchDB(dbs.name); |
| var cancelled = false; |
| var changes = db.changes({ |
| live: true, |
| complete: function (err, result) { |
| cancelled.should.equal(true); |
| should.not.exist(err); |
| should.exist(result); |
| if (result) { |
| result.status.should.equal('cancelled'); |
| } |
| done(); |
| } |
| }); |
| should.exist(changes); |
| changes.cancel.should.be.a('function'); |
| setTimeout(function () { |
| cancelled = true; |
| changes.cancel(); |
| }, 100); |
| }); |
| |
| it('changes are not duplicated', function (done) { |
| var db = new PouchDB(dbs.name); |
| var called = 0; |
| var changes = db.changes({ |
| live: true, |
| onChange: function () { |
| called++; |
| if (called === 1) { |
| setTimeout(function () { |
| changes.cancel(); |
| }, 1000); |
| } |
| }, |
| complete: function (err) { |
| called.should.equal(1); |
| done(); |
| } |
| }); |
| db.post({key: 'value'}); |
| }); |
| function waitASec(fun, time) { |
| return new PouchDB.utils.Promise(function (fulfill) { |
| setTimeout(function () { |
| fulfill(fun()); |
| }, time); |
| }); |
| } |
| it('CRUD events are handled correclty', function (done) { |
| var db = new PouchDB(dbs.name); |
| var changes = db.changes({ |
| live: true, |
| style: 'all_docs' |
| }); |
| var deleted = 0; |
| var updated = 0; |
| var created = 0; |
| function chuckDone() { |
| if ((deleted + updated + created) === 6) { |
| changes.cancel(); |
| } |
| } |
| changes.on('cancel', function () { |
| setTimeout(function () { |
| deleted.should.equal(1, 'correct number of deleted'); |
| created.should.equal(2, 'create number of created'); |
| updated.should.equal(3, 'correct number of updates'); |
| done(); |
| }, 100); |
| }).on('delete', function (change) { |
| deleted++; |
| chuckDone(); |
| }).on('create', function (change) { |
| created++; |
| chuckDone(); |
| }).on('update', function (change) { |
| updated++; |
| chuckDone(); |
| }).on('error', function (err) { |
| done(err); |
| }); |
| var rev1, rev2; |
| db.put({ |
| title: 'Holding On For Life' |
| }, 'currentSong').then(function (resp) { |
| rev1 = resp.rev; |
| return waitASec(function () { |
| return db.put({ |
| title: 'Sushi' |
| }, 'nextSong'); |
| }, 100); |
| }).then(function (resp) { |
| rev2 = resp.rev; |
| return waitASec(function () { |
| return db.put({ |
| title: 'Holding On For Life', |
| artist: 'Broken Bells' |
| }, 'currentSong', rev1); |
| }, 100); |
| }).then(function (resp) { |
| rev1 = resp.rev; |
| return waitASec(function () { |
| return db.put({ |
| title: 'Sushi', |
| artist: 'Kyle Andrews' |
| }, 'nextSong', rev2); |
| }, 100); |
| }).then(function (resp) { |
| rev2 = resp.rev; |
| return waitASec(function () { |
| return db.remove({ |
| _id: 'currentSong', |
| _rev: rev1 |
| }); |
| }, 100); |
| }).then(function (resp) { |
| return db.put({ |
| title: 'Sushi', |
| artist: 'Kyle Andrews', |
| album: 'Real Blasty' |
| }, 'nextSong', rev2); |
| }); |
| }); |
| |
| it('supports returnDocs=false', function (done) { |
| var db = new PouchDB(dbs.name); |
| var docs = []; |
| var num = 10; |
| for (var i = 0; i < num; i++) { |
| docs.push({ _id: 'doc_' + i, }); |
| } |
| var changes = 0; |
| db.bulkDocs({ docs: docs }, function (err, info) { |
| if (err) { |
| return done(err); |
| } |
| db.changes({ |
| descending: true, |
| returnDocs : false |
| }).on('change', function (change) { |
| changes++; |
| }).on('complete', function (results) { |
| results.results.should.have.length(0, '0 results returned'); |
| changes.should.equal(num, 'correct number of changes'); |
| done(); |
| }).on('error', function (err) { |
| done(err); |
| }); |
| }); |
| }); |
| |
| it('should respects limit', function (done) { |
| var docs1 = [ |
| {_id: '_local/foo'}, |
| {_id: 'a', integer: 0}, |
| {_id: 'b', integer: 1}, |
| {_id: 'c', integer: 2}, |
| {_id: 'd', integer: 3} |
| ]; |
| var called = 0; |
| var db = new PouchDB(dbs.name); |
| db.bulkDocs({ docs: docs1 }, function (err, info) { |
| db.changes({ |
| limit: 1 |
| }).on('change', function (ch) { |
| (called++).should.equal(0); |
| }).on('complete', function () { |
| setTimeout(function () { |
| done(); |
| }, 50); |
| }); |
| }); |
| }); |
| |
| it.skip('should respects limit with live replication', function (done) { |
| var docs1 = [ |
| {_id: '_local/foo'}, |
| {_id: 'a', integer: 0}, |
| {_id: 'b', integer: 1}, |
| {_id: 'c', integer: 2}, |
| {_id: 'd', integer: 3} |
| ]; |
| var called = 0; |
| var doneCalled = 0; |
| function calldone() { |
| doneCalled++; |
| if (doneCalled === 2) { |
| done(); |
| } |
| } |
| var db = new PouchDB(dbs.name); |
| db.changes({ |
| limit: 1, |
| live: true |
| }).on('change', function (ch) { |
| ch.id.should.equal('a'); |
| (called++).should.equal(0); |
| }).on('complete', function () { |
| calldone(); |
| }); |
| db.bulkDocs({ docs: docs1 }).then(calldone); |
| }); |
| |
| it('doesn\'t throw if opts.complete is undefined', function (done) { |
| var db = new PouchDB(dbs.name); |
| db.put({_id: 'foo'}).then(function () { |
| db.changes().on('change', function () { |
| done(); |
| }).on('error', function (err) { |
| done(err); |
| }); |
| }, done); |
| }); |
| |
| it('it handles a bunch of individual changes in live replication', |
| function (done) { |
| var db = new PouchDB(dbs.name); |
| var len = 80; |
| var called = 0; |
| var changesDone = false; |
| var changesWritten = 0; |
| var changes = db.changes({live: true}); |
| |
| changes.on('change', function () { |
| called++; |
| if (called === len) { |
| changes.cancel(); |
| } |
| }).on('error', done).on('complete', function () { |
| changesDone = true; |
| maybeDone(); |
| }); |
| |
| var i = -1; |
| |
| function maybeDone() { |
| if (changesDone && changesWritten === len) { |
| done(); |
| } |
| } |
| |
| function after() { |
| changesWritten++; |
| db.listeners('destroyed').should.have.length.lessThan(5); |
| maybeDone(); |
| } |
| |
| while (++i < len) { |
| db.post({}).then(after).catch(done); |
| } |
| |
| }); |
| |
| it('changes-filter without filter', function (done) { |
| var docs1 = [ |
| {_id: '0', integer: 0}, |
| {_id: '1', integer: 1}, |
| {_id: '2', integer: 2}, |
| {_id: '3', integer: 3}, |
| ]; |
| var docs2 = [ |
| {_id: '4', integer: 4}, |
| {_id: '5', integer: 5}, |
| {_id: '6', integer: 6}, |
| {_id: '7', integer: 7}, |
| ]; |
| var db = new PouchDB(dbs.name); |
| var count = 0; |
| db.bulkDocs({ docs: docs1 }, function (err, info) { |
| var changes = db.changes({ |
| complete: function (err, result) { |
| result.status.should.equal('cancelled'); |
| done(); |
| }, |
| onChange: function (change) { |
| count += 1; |
| if (count === 8) { |
| changes.cancel(); |
| } |
| }, |
| live: true |
| }); |
| db.bulkDocs({ docs: docs2 }); |
| }); |
| }); |
| }); |
| }); |
| |
| describe('changes-standalone', function () { |
| |
| it('Changes reports errors', function (done) { |
| this.timeout(2000); |
| var db = new PouchDB('http://infiniterequest.com', { skipSetup: true }); |
| db.changes({ |
| timeout: 1000, |
| complete: function (err, changes) { |
| should.exist(err); |
| done(); |
| } |
| }); |
| }); |
| |
| }); |