UNPKG

sharedb

Version:
419 lines (398 loc) 15.8 kB
var expect = require('expect.js'); var async = require('async'); var util = require('../util'); module.exports = function() { describe('client query subscribe', function() { it('creating a document updates a subscribed query', function(done) { var connection = this.backend.connect(); var query = connection.createSubscribeQuery('dogs', {}, null, function(err) { if (err) return done(err); connection.get('dogs', 'fido').create({age: 3}); }); query.on('insert', function(docs, index) { expect(util.pluck(docs, 'id')).eql(['fido']); expect(util.pluck(docs, 'data')).eql([{age: 3}]); expect(index).equal(0); expect(util.pluck(query.results, 'id')).eql(['fido']); expect(util.pluck(query.results, 'data')).eql([{age: 3}]); done(); }); }); it('creating an additional document updates a subscribed query', function(done) { var connection = this.backend.connect(); async.parallel([ function(cb) { connection.get('dogs', 'fido').create({age: 3}, cb); }, function(cb) { connection.get('dogs', 'spot').create({age: 5}, cb); } ], function(err) { if (err) return done(err); var query = connection.createSubscribeQuery('dogs', {}, null, function(err) { if (err) return done(err); connection.get('dogs', 'taco').create({age: 2}); }); query.on('insert', function(docs, index) { expect(util.pluck(docs, 'id')).eql(['taco']); expect(util.pluck(docs, 'data')).eql([{age: 2}]); expect(query.results[index]).equal(docs[0]); var results = util.sortById(query.results); expect(util.pluck(results, 'id')).eql(['fido', 'spot', 'taco']); expect(util.pluck(results, 'data')).eql([{age: 3}, {age: 5}, {age: 2}]); done(); }); }); }); it('deleting a document updates a subscribed query', function(done) { var connection = this.backend.connect(); async.parallel([ function(cb) { connection.get('dogs', 'fido').create({age: 3}, cb); }, function(cb) { connection.get('dogs', 'spot').create({age: 5}, cb); } ], function(err) { if (err) return done(err); var query = connection.createSubscribeQuery('dogs', {}, null, function(err) { if (err) return done(err); connection.get('dogs', 'fido').del(); }); query.on('remove', function(docs, index) { expect(util.pluck(docs, 'id')).eql(['fido']); expect(util.pluck(docs, 'data')).eql([undefined]); expect(index).a('number'); var results = util.sortById(query.results); expect(util.pluck(results, 'id')).eql(['spot']); expect(util.pluck(results, 'data')).eql([{age: 5}]); done(); }); }); }); it('subscribed query does not get updated after destroyed', function(done) { var connection = this.backend.connect(); var connection2 = this.backend.connect(); async.parallel([ function(cb) { connection.get('dogs', 'fido').create({age: 3}, cb); }, function(cb) { connection.get('dogs', 'spot').create({age: 5}, cb); } ], function(err) { if (err) return done(err); var query = connection.createSubscribeQuery('dogs', {}, null, function(err) { if (err) return done(err); query.destroy(function(err) { if (err) return done(err); connection2.get('dogs', 'taco').create({age: 2}, done); }); }); query.on('insert', function() { done(); }); }); }); it('subscribed query does not get updated after connection is disconnected', function(done) { var connection = this.backend.connect(); var connection2 = this.backend.connect(); async.parallel([ function(cb) { connection.get('dogs', 'fido').create({age: 3}, cb); }, function(cb) { connection.get('dogs', 'spot').create({age: 5}, cb); } ], function(err) { if (err) return done(err); var query = connection.createSubscribeQuery('dogs', {}, null, function(err) { if (err) return done(err); connection.close(); connection2.get('dogs', 'taco').create({age: 2}, done); }); query.on('insert', function() { done(); }); }); }); it('subscribed query gets update after reconnecting', function(done) { var backend = this.backend; var connection = backend.connect(); var connection2 = backend.connect(); async.parallel([ function(cb) { connection.get('dogs', 'fido').create({age: 3}, cb); }, function(cb) { connection.get('dogs', 'spot').create({age: 5}, cb); } ], function(err) { if (err) return done(err); var query = connection.createSubscribeQuery('dogs', {}, null, function(err) { if (err) return done(err); connection.close(); connection2.get('dogs', 'taco').create({age: 2}); process.nextTick(function() { backend.connect(connection); }); }); query.on('insert', function() { done(); }); }); }); it('subscribed query gets simultaneous insert and remove after reconnecting', function(done) { var backend = this.backend; var connection = backend.connect(); var connection2 = backend.connect(); async.parallel([ function(cb) { connection.get('dogs', 'fido').create({age: 3}, cb); }, function(cb) { connection.get('dogs', 'spot').create({age: 5}, cb); } ], function(err) { if (err) return done(err); var query = connection.createSubscribeQuery('dogs', {}, null, function(err) { if (err) return done(err); connection.close(); connection2.get('dogs', 'fido').fetch(function(err) { if (err) return done(err); connection2.get('dogs', 'fido').del(); connection2.get('dogs', 'taco').create({age: 2}); process.nextTick(function() { backend.connect(connection); }); }); }); var wait = 2; function finish() { if (--wait) return; var results = util.sortById(query.results); expect(util.pluck(results, 'id')).eql(['spot', 'taco']); expect(util.pluck(results, 'data')).eql([{age: 5}, {age: 2}]); done(); } query.on('insert', function(docs) { expect(util.pluck(docs, 'id')).eql(['taco']); expect(util.pluck(docs, 'data')).eql([{age: 2}]); finish(); }); query.on('remove', function(docs) { expect(util.pluck(docs, 'id')).eql(['fido']); expect(util.pluck(docs, 'data')).eql([undefined]); finish(); }); }); }); it('creating an additional document updates a subscribed query', function(done) { var connection = this.backend.connect(); async.parallel([ function(cb) { connection.get('dogs', 'fido').create({age: 3}, cb); }, function(cb) { connection.get('dogs', 'spot').create({age: 5}, cb); } ], function(err) { if (err) return done(err); var query = connection.createSubscribeQuery('dogs', {}, null, function(err) { if (err) return done(err); connection.get('dogs', 'taco').create({age: 2}); }); query.on('insert', function(docs, index) { expect(util.pluck(docs, 'id')).eql(['taco']); expect(util.pluck(docs, 'data')).eql([{age: 2}]); expect(query.results[index]).equal(docs[0]); var results = util.sortById(query.results); expect(util.pluck(results, 'id')).eql(['fido', 'spot', 'taco']); expect(util.pluck(results, 'data')).eql([{age: 3}, {age: 5}, {age: 2}]); done(); }); }); }); it('pollDebounce option reduces subsequent poll interval', function(done) { var connection = this.backend.connect(); this.backend.db.canPollDoc = function() { return false; }; var query = connection.createSubscribeQuery('items', {}, {pollDebounce: 100}); var batchSizes = []; var total = 0; query.on('insert', function(docs) { batchSizes.push(docs.length); total += docs.length; if (total === 10) { // first document is its own batch; then subsequent creates // are debounced until after all other 9 docs are created expect(batchSizes).eql([1, 9]); done(); } }); function createDoc(count) { connection.get('items', count.toString()).create({}, function() { if (--count) { createDoc(count); } }); } createDoc(10); }); it('db.pollDebounce option reduces subsequent poll interval', function(done) { var connection = this.backend.connect(); this.backend.db.canPollDoc = function() { return false; }; this.backend.db.pollDebounce = 100; var query = connection.createSubscribeQuery('items', {}); var batchSizes = []; var total = 0; query.on('insert', function(docs) { batchSizes.push(docs.length); total += docs.length; if (total === 10) { // first document is its own batch; then subsequent creates // are debounced until after all other 9 docs are created expect(batchSizes).eql([1, 9]); done(); } }); function createDoc(count) { connection.get('items', count.toString()).create({}, function() { if (--count) { createDoc(count); } }); } createDoc(10); }); it('pollInterval updates a subscribed query after an unpublished create', function(done) { var connection = this.backend.connect(); this.backend.suppressPublish = true; var query = connection.createSubscribeQuery('dogs', {}, {pollInterval: 50}, function(err) { if (err) return done(err); connection.get('dogs', 'fido').create({}); }); query.on('insert', function(docs, index) { expect(util.pluck(docs, 'id')).eql(['fido']); done(); }); }); it('db.pollInterval updates a subscribed query after an unpublished create', function(done) { var connection = this.backend.connect(); this.backend.suppressPublish = true; this.backend.db.pollInterval = 50; var query = connection.createSubscribeQuery('dogs', {}, null, function(err) { if (err) return done(err); connection.get('dogs', 'fido').create({}); }); query.on('insert', function(docs, index) { expect(util.pluck(docs, 'id')).eql(['fido']); done(); }); }); it('pollInterval captures additional unpublished creates', function(done) { var connection = this.backend.connect(); this.backend.suppressPublish = true; var count = 0; var query = connection.createSubscribeQuery('dogs', {}, {pollInterval: 50}, function(err) { if (err) return done(err); connection.get('dogs', count.toString()).create({}); }); query.on('insert', function() { count++; if (count === 3) return done(); connection.get('dogs', count.toString()).create({}); }); }); it('query extra is returned to client', function(done) { var connection = this.backend.connect(); this.backend.db.query = function(collection, query, fields, options, callback) { process.nextTick(function() { callback(null, [], {colors: ['brown', 'gold']}); }); }; var query = connection.createSubscribeQuery('dogs', {}, null, function(err, results, extra) { if (err) return done(err); expect(results).eql([]); expect(extra).eql({colors: ['brown', 'gold']}); expect(query.extra).eql({colors: ['brown', 'gold']}); done(); }); }); it('query extra is updated on change', function(done) { var connection = this.backend.connect(); this.backend.db.query = function(collection, query, fields, options, callback) { process.nextTick(function() { callback(null, [], 1); }); }; this.backend.db.queryPoll = function(collection, query, options, callback) { process.nextTick(function() { callback(null, [], 2); }); }; this.backend.db.canPollDoc = function() { return false; }; var query = connection.createSubscribeQuery('dogs', {}, null, function(err, results, extra) { if (err) return done(err); expect(extra).eql(1); expect(query.extra).eql(1); }); query.on('extra', function(extra) { expect(extra).eql(2); expect(query.extra).eql(2); done(); }); connection.get('dogs', 'fido').create({age: 3}); }); it('changing a filtered property removes from a subscribed query', function(done) { var connection = this.backend.connect(); async.parallel([ function(cb) { connection.get('dogs', 'fido').create({age: 3}, cb); }, function(cb) { connection.get('dogs', 'spot').create({age: 3}, cb); } ], function(err) { if (err) return done(err); var query = connection.createSubscribeQuery('dogs', {age: 3}, null, function(err, results) { if (err) return done(err); var sorted = util.sortById(results); expect(util.pluck(sorted, 'id')).eql(['fido', 'spot']); expect(util.pluck(sorted, 'data')).eql([{age: 3}, {age: 3}]); connection.get('dogs', 'fido').submitOp({p: ['age'], na: 2}); }); query.on('remove', function(docs, index) { expect(util.pluck(docs, 'id')).eql(['fido']); expect(util.pluck(docs, 'data')).eql([{age: 5}]); expect(index).a('number'); var results = util.sortById(query.results); expect(util.pluck(results, 'id')).eql(['spot']); expect(util.pluck(results, 'data')).eql([{age: 3}]); done(); }); }); }); it('changing a filtered property inserts to a subscribed query', function(done) { var connection = this.backend.connect(); async.parallel([ function(cb) { connection.get('dogs', 'fido').create({age: 3}, cb); }, function(cb) { connection.get('dogs', 'spot').create({age: 5}, cb); } ], function(err) { if (err) return done(err); var query = connection.createSubscribeQuery('dogs', {age: 3}, null, function(err, results) { if (err) return done(err); var sorted = util.sortById(results); expect(util.pluck(sorted, 'id')).eql(['fido']); expect(util.pluck(sorted, 'data')).eql([{age: 3}]); connection.get('dogs', 'spot').submitOp({p: ['age'], na: -2}); }); query.on('insert', function(docs, index) { expect(util.pluck(docs, 'id')).eql(['spot']); expect(util.pluck(docs, 'data')).eql([{age: 3}]); expect(index).a('number'); var results = util.sortById(query.results); expect(util.pluck(results, 'id')).eql(['fido', 'spot']); expect(util.pluck(results, 'data')).eql([{age: 3}, {age: 3}]); done(); }); }); }); it('changing a sorted property moves in a subscribed query', function(done) { var connection = this.backend.connect(); async.parallel([ function(cb) { connection.get('dogs', 'fido').create({age: 3}, cb); }, function(cb) { connection.get('dogs', 'spot').create({age: 5}, cb); } ], function(err) { if (err) return done(err); var query = connection.createSubscribeQuery('dogs', {$orderby: {age: 1}}, null, function(err, results) { if (err) return done(err); expect(util.pluck(results, 'id')).eql(['fido', 'spot']); expect(util.pluck(results, 'data')).eql([{age: 3}, {age: 5}]); connection.get('dogs', 'spot').submitOp({p: ['age'], na: -3}); }); query.on('move', function(docs, from, to) { expect(docs.length).eql(1); expect(from).a('number'); expect(to).a('number'); expect(util.pluck(query.results, 'id')).eql(['spot', 'fido']); expect(util.pluck(query.results, 'data')).eql([{age: 2}, {age: 3}]); done(); }); }); }); }); };