UNPKG

sharedb

Version:
215 lines (205 loc) 8.22 kB
var expect = require('chai').expect; var async = require('async'); var util = require('../util'); module.exports = function(options) { var getQuery = options.getQuery; describe('client query', function() { before(function() { this.matchAllDbQuery = getQuery({query: {}}); }); ['createFetchQuery', 'createSubscribeQuery'].forEach(function(method) { it(method + ' on an empty collection', function(done) { var connection = this.backend.connect(); connection[method]('dogs', this.matchAllDbQuery, null, function(err, results) { if (err) return done(err); expect(results).eql([]); done(); }); }); it(method + ' on collection with fetched docs', function(done) { var connection = this.backend.connect(); var matchAllDbQuery = this.matchAllDbQuery; async.parallel([ function(cb) { connection.get('dogs', 'fido').create({age: 3}, cb); }, function(cb) { connection.get('dogs', 'spot').create({age: 5}, cb); }, function(cb) { connection.get('cats', 'finn').create({age: 2}, cb); } ], function(err) { if (err) return done(err); connection[method]('dogs', matchAllDbQuery, 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: 5}]); done(); }); }); }); it(method + ' on collection with unfetched docs', function(done) { var connection = this.backend.connect(); var connection2 = this.backend.connect(); var matchAllDbQuery = this.matchAllDbQuery; async.parallel([ function(cb) { connection.get('dogs', 'fido').create({age: 3}, cb); }, function(cb) { connection.get('dogs', 'spot').create({age: 5}, cb); }, function(cb) { connection.get('cats', 'finn').create({age: 2}, cb); } ], function(err) { if (err) return done(err); connection2[method]('dogs', matchAllDbQuery, 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: 5}]); done(); }); }); }); it(method + ' on collection with one fetched doc', function(done) { var connection = this.backend.connect(); var connection2 = this.backend.connect(); var matchAllDbQuery = this.matchAllDbQuery; async.parallel([ function(cb) { connection.get('dogs', 'fido').create({age: 3}, cb); }, function(cb) { connection.get('dogs', 'spot').create({age: 5}, cb); }, function(cb) { connection.get('cats', 'finn').create({age: 2}, cb); } ], function(err) { if (err) return done(err); connection2.get('dogs', 'fido').fetch(function(err) { if (err) return done(err); connection2[method]('dogs', matchAllDbQuery, 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: 5}]); done(); }); }); }); }); it(method + ' on collection with one fetched doc missing an op', function(done) { var connection = this.backend.connect(); var connection2 = this.backend.connect(); var matchAllDbQuery = this.matchAllDbQuery; async.parallel([ function(cb) { connection.get('dogs', 'fido').create({age: 3}, cb); }, function(cb) { connection.get('dogs', 'spot').create({age: 5}, cb); }, function(cb) { connection.get('cats', 'finn').create({age: 2}, cb); } ], function(err) { if (err) return done(err); connection2.get('dogs', 'fido').fetch(function(err) { if (err) return done(err); connection.get('dogs', 'fido').submitOp([{p: ['age'], na: 1}], function(err) { if (err) return done(err); // The results option is meant for making resubscribing more // efficient and has no effect on query fetching var options = { results: [ connection2.get('dogs', 'fido'), connection2.get('dogs', 'spot') ] }; connection2[method]('dogs', matchAllDbQuery, options, 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: 4}, {age: 5}]); done(); }); }); }); }); }); it(method + ' on collection with readSnapshots rejectSnapshotRead', function(done) { var backend = this.backend; var connection = backend.connect(); var connection2 = backend.connect(); var matchAllDbQuery = this.matchAllDbQuery; async.parallel([ function(cb) { connection.get('dogs', 'fido').create({age: 3}, cb); }, function(cb) { connection.get('dogs', 'spot').create({age: 5}, cb); }, function(cb) { connection.get('cats', 'finn').create({age: 2}, cb); } ], function(err) { if (err) return done(err); backend.use('readSnapshots', function(context, cb) { expect(context.snapshots).to.be.an('array').of.length(2); context.rejectSnapshotRead(context.snapshots[0], new Error('Failed to fetch dog')); cb(); }); // Queries have no way of supporting partial readSnapshots rejections, so the entire query // fails if at least one of the snapshots has an error. connection2[method]('dogs', matchAllDbQuery, null, function(err, results) { expect(err).to.be.an('error').with.property('code', 'ERR_SNAPSHOT_READS_REJECTED'); expect(results).to.equal(undefined); done(); }); }); }); }); it('snapshot fetch from query does not advance version of doc with pending ops', function(done) { var backend = this.backend; backend.connect(null, null, function(connection1) { backend.connect(null, null, function(connection2) { var doc = connection1.get('dogs', 'fido'); var doc2 = connection2.get('dogs', 'fido'); doc.create({name: 'kido'}, function(err) { if (err) return done(err); doc2.fetch(function(err) { if (err) return done(err); doc2.submitOp({p: ['name', 0], si: 'f'}, function(err) { if (err) return done(err); expect(doc2.data).eql({name: 'fkido'}); doc.connection.createFetchQuery('dogs', {}, null, function(err) { if (err) return done(err); doc.resume(); }); }); }); }); process.nextTick(function() { doc.pause(); doc.submitOp({p: ['name', 0], sd: 'k'}, function(err) { if (err) return done(err); doc.pause(); doc2.fetch(function(err) { if (err) return done(err); expect(doc2.version).equal(3); expect(doc2.data).eql({name: 'fido'}); done(); }); }); doc.del(); }); }); }); }); }); };