GT2/GT2-Android/node_modules/websql/test/test.mapreduce.js

3249 lines
116 KiB
JavaScript
Raw Normal View History

/* global sum */
'use strict';
var PouchDB = require('./pouchdb');
var should = require('chai').should();
var testUtils = require('./test.utils.js');
var adapters = ['local'];
adapters.forEach(function (adapter) {
var viewTypes = ['persisted', 'temp'];
viewTypes.forEach(function (viewType) {
var suiteName = 'test.mapreduce.js-' + adapter + '-' + viewType;
var dbName = testUtils.adapterUrl(adapter, 'testdb');
tests(suiteName, dbName, adapter, viewType);
});
});
function tests(suiteName, dbName, dbType, viewType) {
describe(suiteName, function () {
var Promise;
var createView;
if (viewType === 'persisted') {
createView = function (db, viewObj) {
var storableViewObj = {
map : viewObj.map.toString()
};
if (viewObj.reduce) {
storableViewObj.reduce = viewObj.reduce.toString();
}
return new Promise(function (resolve, reject) {
db.put({
_id: '_design/theViewDoc',
views: {
'theView' : storableViewObj
}
}, function (err) {
if (err) {
reject(err);
} else {
resolve('theViewDoc/theView');
}
});
});
};
} else {
createView = function (db, viewObj) {
return new Promise(function (resolve) {
setTimeout(function () {
resolve(viewObj);
});
});
};
}
beforeEach(function () {
Promise = PouchDB.utils.Promise;
return new PouchDB(dbName).destroy();
});
afterEach(function () {
return new PouchDB(dbName).destroy();
});
it("Test basic view", function () {
return new PouchDB(dbName).then(function (db) {
return createView(db, {
map: function (doc) {
emit(doc.foo, doc);
}
}).then(function (view) {
return db.bulkDocs({docs: [
{foo: 'bar'},
{ _id: 'volatile', foo: 'baz' }
]}).then(function () {
return db.get('volatile');
}).then(function (doc) {
return db.remove(doc);
}).then(function () {
return db.query(view, {include_docs: true, reduce: false});
}).then(function (res) {
res.rows.should.have.length(1, 'Dont include deleted documents');
res.total_rows.should.equal(1, 'Include total_rows property.');
res.rows.forEach(function (x) {
should.exist(x.id);
should.exist(x.key);
should.exist(x.value);
should.exist(x.value._rev);
should.exist(x.doc);
should.exist(x.doc._rev);
});
});
});
});
});
it("Test basic view, no emitted value", function () {
return new PouchDB(dbName).then(function (db) {
return createView(db, {
map: function (doc) {
emit(doc.foo);
}
}).then(function (view) {
return db.bulkDocs({docs: [
{foo: 'bar'},
{ _id: 'volatile', foo: 'baz' }
]}).then(function () {
return db.get('volatile');
}).then(function (doc) {
return db.remove(doc);
}).then(function () {
return db.query(view, {include_docs: true, reduce: false});
}).then(function (res) {
res.rows.should.have.length(1,
'Dont include deleted documents');
res.total_rows.should.equal(1, 'Include total_rows property.');
res.rows.forEach(function (x) {
should.exist(x.id);
should.exist(x.key);
should.equal(x.value, null);
should.exist(x.doc);
should.exist(x.doc._rev);
});
});
});
});
});
if (dbType === 'local' && viewType === 'temp') {
it("with a closure", function () {
return new PouchDB(dbName).then(function (db) {
return db.bulkDocs({docs: [
{foo: 'bar'},
{ _id: 'volatile', foo: 'baz' }
]}).then(function () {
var queryFun = (function (test) {
return function (doc, emit) {
if (doc._id === test) {
emit(doc.foo);
}
};
}('volatile'));
return db.query(queryFun, {reduce: false});
});
}).should.become({
total_rows: 1,
offset: 0,
rows: [
{
id: 'volatile',
key: 'baz',
value: null
}
]
});
});
}
if (viewType === 'temp') {
it('Test simultaneous temp views', function () {
return new PouchDB(dbName).then(function (db) {
return db.put({_id: '0', foo: 1, bar: 2, baz: 3}).then(function () {
return Promise.all(['foo', 'bar', 'baz'].map(function (key, i) {
var fun = 'function(doc){emit(doc.' + key + ');}';
return db.query({map: fun}).then(function (res) {
res.rows.should.deep.equal([{
id: '0',
key: i + 1,
value: null
}]);
});
}));
});
});
});
it("Test passing just a function", function () {
return new PouchDB(dbName).then(function (db) {
return db.bulkDocs({docs: [
{foo: 'bar'},
{ _id: 'volatile', foo: 'baz' }
]}).then(function () {
return db.get('volatile');
}).then(function (doc) {
return db.remove(doc);
}).then(function () {
return db.query(function (doc) {
emit(doc.foo, doc);
}, {include_docs: true, reduce: false});
}).then(function (res) {
res.rows.should.have.length(1, 'Dont include deleted documents');
res.rows.forEach(function (x) {
should.exist(x.id);
should.exist(x.key);
should.exist(x.value);
should.exist(x.value._rev);
should.exist(x.doc);
should.exist(x.doc._rev);
});
});
});
});
}
it("Test opts.startkey/opts.endkey", function () {
return new PouchDB(dbName).then(function (db) {
return createView(db, {
map: function (doc) {
emit(doc.key, doc);
}
}).then(function (queryFun) {
return db.bulkDocs({docs: [
{key: 'key1'},
{key: 'key2'},
{key: 'key3'},
{key: 'key4'},
{key: 'key5'}
]}).then(function () {
return db.query(queryFun, {reduce: false, startkey: 'key2'});
}).then(function (res) {
res.rows.should.have.length(4, 'Startkey is inclusive');
return db.query(queryFun, {reduce: false, endkey: 'key3'});
}).then(function (res) {
res.rows.should.have.length(3, 'Endkey is inclusive');
return db.query(queryFun, {
reduce: false,
startkey: 'key2',
endkey: 'key3'
});
}).then(function (res) {
res.rows.should.have.length(2, 'Startkey and endkey together');
return db.query(queryFun, {
reduce: false,
startkey: 'key4',
endkey: 'key4'
});
}).then(function (res) {
res.rows.should.have.length(1, 'Startkey=endkey');
});
});
});
});
it("#4154 opts.start_key/opts.end_key are synonyms", function () {
return new PouchDB(dbName).then(function (db) {
return createView(db, {
map: function (doc) {
emit(doc.key, doc);
}
}).then(function (queryFun) {
return db.bulkDocs({docs: [
{key: 'key1'},
{key: 'key2'},
{key: 'key3'},
{key: 'key4'},
{key: 'key5'}
]}).then(function () {
return db.query(queryFun, {reduce: false, start_key: 'key2'});
}).then(function (res) {
res.rows.should.have.length(4, 'Startkey is inclusive');
return db.query(queryFun, {reduce: false, end_key: 'key3'});
}).then(function (res) {
res.rows.should.have.length(3, 'Endkey is inclusive');
return db.query(queryFun, {
reduce: false,
start_key: 'key2',
end_key: 'key3'
});
}).then(function (res) {
res.rows.should.have.length(2, 'Startkey and endkey together');
return db.query(queryFun, {
reduce: false,
start_key: 'key4',
end_key: 'key4'
});
}).then(function (res) {
res.rows.should.have.length(1, 'Startkey=endkey');
});
});
});
});
//TODO: split this to their own tests within a describe block
it("Test opts.inclusive_end = false", function () {
return new PouchDB(dbName).then(function (db) {
return createView(db, {
map: function (doc) {
emit(doc.key, doc);
}
}).then(function (queryFun) {
return db.bulkDocs({docs: [
{key: 'key1'},
{key: 'key2'},
{key: 'key3'},
{key: 'key4'},
{key: 'key4'},
{key: 'key5'}
]}).then(function () {
return db.query(queryFun, {
reduce: false,
endkey: 'key4',
inclusive_end: false
});
}).then(function (resp) {
resp.rows.should.have.length(3, 'endkey=key4 without ' +
'inclusive end');
resp.rows[0].key.should.equal('key1');
resp.rows[2].key.should.equal('key3');
})
.then(function () {
return db.query(queryFun, {
reduce: false,
startkey: 'key3',
endkey: 'key4',
inclusive_end: false
});
}).then(function (resp) {
resp.rows.should.have.length(1, 'startkey=key3, endkey=key4 ' +
'without inclusive end');
resp.rows[0].key.should.equal('key3');
}).then(function () {
return db.query(queryFun, {
reduce: false,
startkey: 'key4',
endkey: 'key1',
descending: true,
inclusive_end: false
});
}).then(function (resp) {
resp.rows.should
.have.length(4, 'startkey=key4, endkey=key1 descending without ' +
'inclusive end');
resp.rows[0].key.should.equal('key4');
});
});
});
});
it("Test opts.key", function () {
return new PouchDB(dbName).then(function (db) {
return createView(db, {
map: function (doc) {
emit(doc.key, doc);
}
}).then(function (queryFun) {
return db.bulkDocs({docs: [
{key: 'key1'},
{key: 'key2'},
{key: 'key3'},
{key: 'key3'}
]}).then(function () {
return db.query(queryFun, {reduce: false, key: 'key2'});
}).then(function (res) {
res.rows.should.have.length(1, 'Doc with key');
return db.query(queryFun, {reduce: false, key: 'key3'});
}).then(function (res) {
res.rows.should.have.length(2, 'Multiple docs with key');
});
});
});
});
it("Test basic view collation", function () {
var values = [];
// special values sort before all other types
values.push(null);
values.push(false);
values.push(true);
// then numbers
values.push(1);
values.push(2);
values.push(3.0);
values.push(4);
// then text, case sensitive
// currently chrome uses ascii ordering and so wont handle caps properly
values.push("a");
//values.push("A");
values.push("aa");
values.push("b");
//values.push("B");
values.push("ba");
values.push("bb");
// then arrays. compared element by element until different.
// Longer arrays sort after their prefixes
values.push(["a"]);
values.push(["b"]);
values.push(["b", "c"]);
values.push(["b", "c", "a"]);
values.push(["b", "d"]);
values.push(["b", "d", "e"]);
// then object, compares each key value in the list until different.
// larger objects sort after their subset objects.
values.push({a: 1});
values.push({a: 2});
values.push({b: 1});
values.push({b: 2});
values.push({b: 2, a: 1}); // Member order does matter for collation.
// CouchDB preserves member order
// but doesn't require that clients will.
// (this test might fail if used with a js engine
// that doesn't preserve order)
values.push({b: 2, c: 2});
return new PouchDB(dbName).then(function (db) {
return createView(db, {
map: function (doc) {
emit(doc.foo);
}
}).then(function (queryFun) {
var docs = values.map(function (x, i) {
return {_id: (i).toString(), foo: x};
});
return db.bulkDocs({docs: docs}).then(function () {
return db.query(queryFun, {reduce: false});
}).then(function (res) {
res.rows.forEach(function (x, i) {
JSON.stringify(x.key).should.equal(JSON.stringify(values[i]),
'keys collate');
});
return db.query(queryFun, {descending: true, reduce: false});
}).then(function (res) {
res.rows.forEach(function (x, i) {
JSON.stringify(x.key).should.equal(JSON.stringify(
values[values.length - 1 - i]),
'keys collate descending');
});
});
});
});
});
it("Test joins", function () {
return new PouchDB(dbName).then(function (db) {
return createView(db, {
map: function (doc) {
if (doc.doc_id) {
emit(doc._id, {_id: doc.doc_id});
}
}
}).then(function (queryFun) {
return db.bulkDocs({docs: [
{_id: 'mydoc', foo: 'bar'},
{ doc_id: 'mydoc' }
]}).then(function () {
return db.query(queryFun, {include_docs: true, reduce: false});
}).then(function (res) {
should.exist(res.rows[0].doc);
return res.rows[0].doc._id;
});
}).should.become('mydoc', 'mydoc included');
});
});
it("No reduce function", function () {
return new PouchDB(dbName).then(function (db) {
return createView(db, {
map: function () {
emit('key', 'val');
}
}).then(function (queryFun) {
return db.post({foo: 'bar'}).then(function () {
return db.query(queryFun);
});
});
}).should.be.fulfilled;
});
it("Query after db.close", function () {
return new PouchDB(dbName).then(function (db) {
return createView(db, {
map: function (doc) {
emit(doc.foo, 'val');
}
}).then(function (queryFun) {
return db.put({_id: 'doc', foo: 'bar'}).then(function () {
return db.query(queryFun);
}).then(function (res) {
res.rows.should.deep.equal([
{
id: 'doc',
key: 'bar',
value: 'val'
}
]);
return db.close();
}).then(function () {
db = new PouchDB(dbName);
return db.query(queryFun).then(function (res) {
res.rows.should.deep.equal([
{
id: 'doc',
key: 'bar',
value: 'val'
}
]);
});
});
});
});
});
it("Built in _sum reduce function", function () {
return new PouchDB(dbName).then(function (db) {
return createView(db, {
map: function (doc) {
emit(doc.val, 1);
},
reduce: "_sum"
}).then(function (queryFun) {
return db.bulkDocs({
docs: [
{ val: 'bar' },
{ val: 'bar' },
{ val: 'baz' }
]
}).then(function () {
return db.query(queryFun, {reduce: true, group_level: 999});
}).then(function (resp) {
return resp.rows.map(function (row) {
return row.value;
});
});
});
}).should.become([2, 1]);
});
it("Built in _count reduce function", function () {
return new PouchDB(dbName).then(function (db) {
return createView(db, {
map: function (doc) {
emit(doc.val, doc.val);
},
reduce: "_count"
}).then(function (queryFun) {
return db.bulkDocs({
docs: [
{ val: 'bar' },
{ val: 'bar' },
{ val: 'baz' }
]
}).then(function () {
return db.query(queryFun, {reduce: true, group_level: 999});
}).then(function (resp) {
return resp.rows.map(function (row) {
return row.value;
});
});
});
}).should.become([2, 1]);
});
it("Built in _stats reduce function", function () {
return new PouchDB(dbName).then(function (db) {
return createView(db, {
map: "function(doc){emit(doc.val, 1);}",
reduce: "_stats"
}).then(function (queryFun) {
return db.bulkDocs({
docs: [
{ val: 'bar' },
{ val: 'bar' },
{ val: 'baz' }
]
}).then(function () {
return db.query(queryFun, {reduce: true, group_level: 999});
}).then(function (res) {
return res.rows[0].value;
});
});
}).should.become({
sum: 2,
count: 2,
min: 1,
max: 1,
sumsqr: 2
});
});
it.skip("Built in _stats reduce function should throw an error with a promise",
function () {
return new PouchDB(dbName).then(function (db) {
return createView(db, {
map: "function(doc){emit(doc.val, 'lala');}",
reduce: "_stats"
}).then(function (queryFun) {
return db.bulkDocs({
docs: [
{ val: 'bar' },
{ val: 'bar' },
{ val: 'baz' }
]
}).then(function () {
return db.query(queryFun, {reduce: true, group_level: 999});
});
});
}).should.be.rejected;
});
it.skip("Built in _sum reduce function should throw an error with a promise",
function () {
return new PouchDB(dbName).then(function (db) {
return createView(db, {
map: "function(doc){emit(null, doc.val);}",
reduce: "_sum"
}).then(function (queryFun) {
return db.bulkDocs({
docs: [
{ val: 1 },
{ val: 2 },
{ val: 'baz' }
]
}).then(function () {
return db.query(queryFun, {reduce: true, group: true});
});
});
}).should.be.rejected;
});
it.skip("Built in _sum reduce function with num arrays should throw an error",
function () {
return new PouchDB(dbName).then(function (db) {
return createView(db, {
map: "function(doc){emit(null, doc.val);}",
reduce: "_sum"
}).then(function (queryFun) {
return db.bulkDocs({
docs: [
{ val: [1, 2, 3] },
{ val: 2 },
{ val: ['baz']}
]
}).then(function () {
return db.query(queryFun, {reduce: true, group: true});
});
});
}).should.be.rejected;
});
it("Built in _sum can be used with lists of numbers", function () {
return new PouchDB(dbName).then(function (db) {
return createView(db, {
map: "function(doc){emit(null, doc.val);}",
reduce: "_sum"
}).then(function (queryFun) {
return db.bulkDocs({
docs: [
{ _id: '1', val: 2 },
{ _id: '2', val: [1, 2, 3, 4] },
{ _id: '3', val: [3, 4] },
{ _id: '4', val: 1 }
]
}).then(function () {
return db.query(queryFun, {reduce: true, group: true});
}).then(function (res) {
res.should.deep.equal({rows : [{
key : null,
value : [7, 6, 3, 4]
}]});
});
});
});
});
if (viewType === 'temp') {
it("No reduce function, passing just a function", function () {
return new PouchDB(dbName).then(function (db) {
return db.post({foo: 'bar'}).then(function () {
var queryFun = function () {
emit('key', 'val');
};
return db.query(queryFun);
});
}).should.be.fulfilled;
});
}
it.skip('Query result should include _conflicts', function () {
var db2name = 'test2b' + Math.random();
var cleanup = function () {
return new PouchDB(db2name).destroy();
};
var doc1 = {_id: '1', foo: 'bar'};
var doc2 = {_id: '1', foo: 'baz'};
return testUtils.fin(new PouchDB(dbName).then(function (db) {
return new PouchDB(db2name).then(function (remote) {
var replicate = testUtils.promisify(db.replicate.from, db.replicate);
return db.post(doc1).then(function () {
return remote.post(doc2);
}).then(function () {
return replicate(remote);
}).then(function () {
return db.query(function (doc) {
if (doc._conflicts) {
emit(doc._conflicts, null);
}
}, {include_docs : true, conflicts: true});
}).then(function (res) {
should.exist(res.rows[0].doc._conflicts);
return db.get(res.rows[0].doc._id, {conflicts: true});
}).then(function (res) {
should.exist(res._conflicts);
});
});
}), cleanup);
});
/* jshint maxlen:false */
var icons = [
"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"
];
/* jshint maxlen:100 */
var iconDigests = [
"md5-Mf8m9ehZnCXC717bPkqkCA==",
"md5-fdEZBYtnvr+nozYVDzzxpA==",
"md5-ImDARszfC+GA3Cv9TVW4HA==",
"md5-hBsgoz3ujHM4ioa72btwow==",
"md5-jDUyV6ySnTVANn2qq3332g=="
];
var iconLengths = [1047, 789, 967, 527, 1108];
it('#190 Query works with attachments=true', function () {
var db = new PouchDB(dbName);
var docs = [];
for (var i = 0; i < 5; i++) {
docs.push({
_id: i.toString(),
_attachments: {
'foo.png': {
data: icons[i],
content_type: 'image/png'
}
}
});
}
return db.bulkDocs(docs).then(function () {
return createView(db, {
map: function (doc) {
emit(doc._id);
}
});
}).then(function (queryFun) {
return db.query(queryFun, {
include_docs: true,
attachments: true
}).then(function (res) {
var attachments = res.rows.map(function (row) {
var doc = row.doc;
delete doc._attachments['foo.png'].revpos;
return doc._attachments;
});
attachments.should.deep.equal(icons.map(function (icon, i) {
return {
"foo.png": {
"content_type": "image/png",
"data": icon,
"digest": iconDigests[i]
}
};
}), 'works with attachments=true');
return db.query(queryFun, {include_docs: true});
}).then(function (res) {
var attachments = res.rows.map(function (row) {
var doc = row.doc;
delete doc._attachments['foo.png'].revpos;
return doc._attachments['foo.png'];
});
attachments.should.deep.equal(icons.map(function (icon, i) {
return {
"content_type": "image/png",
stub: true,
"digest": iconDigests[i],
length: iconLengths[i]
};
}), 'works with attachments=false');
return db.query(queryFun, {attachments: true});
}).then(function (res) {
res.rows.should.have.length(5);
res.rows.forEach(function (row) {
should.not.exist(row.doc, 'ignored if include_docs=false');
});
});
});
});
it('#2858 Query works with attachments=true, binary=true 1', function () {
// Need to avoid the cache to workaround
// https://issues.apache.org/jira/browse/COUCHDB-2880
var db = new PouchDB(dbName, {ajax: {cache: false}});
var docs = [];
for (var i = 0; i < 5; i++) {
docs.push({
_id: i.toString(),
_attachments: {
'foo.png': {
data: icons[i],
content_type: 'image/png'
}
}
});
}
return db.bulkDocs(docs).then(function () {
return createView(db, {
map: function (doc) {
emit(doc._id);
}
});
}).then(function (queryFun) {
return db.query(queryFun, {
include_docs: true,
attachments: true,
binary: true
}).then(function (res) {
res.rows.forEach(function (row) {
var doc = row.doc;
Object.keys(doc._attachments).forEach(function (attName) {
var att = doc._attachments[attName];
should.not.exist(att.stub);
att.data.should.not.be.a('string');
});
});
});
});
});
it('#2858 Query works with attachments=true, binary=true 2', function () {
// Need to avoid the cache to workaround
// https://issues.apache.org/jira/browse/COUCHDB-2880
var db = new PouchDB(dbName, {ajax: {cache: false}});
var docs = [];
for (var i = 0; i < 5; i++) {
docs.push({
_id: i.toString()
});
}
return db.bulkDocs(docs).then(function () {
return createView(db, {
map: function (doc) {
emit(doc._id);
}
});
}).then(function (queryFun) {
return db.query(queryFun, {
include_docs: true,
attachments: true,
binary: true
}).then(function (res) {
res.rows.forEach(function (row) {
var doc = row.doc;
should.not.exist(doc._attachments);
});
});
});
});
it('#242 conflicts at the root level', function () {
var db = new PouchDB(dbName);
return db.bulkDocs([
{
foo: '1',
_id: 'foo',
_rev: '1-w',
_revisions: {start: 1, ids: ['w']}
}
], {new_edits: false}).then(function () {
return createView(db, {
map: function (doc) {
emit(doc.foo);
}
}).then(function (queryFun) {
return db.query(queryFun).then(function (res) {
res.rows[0].key.should.equal('1');
return db.bulkDocs([
{
foo: '2',
_id: 'foo',
_rev: '1-x',
_revisions: {start: 1, ids: ['x']}
}
], {new_edits: false}).then(function () {
return db.query(queryFun);
}).then(function (res) {
res.rows[0].key.should.equal('2');
return db.bulkDocs([
{
foo: '3',
_id: 'foo',
_rev: '1-y',
_deleted: true,
_revisions: {start: 1, ids: ['y']}
}
], {new_edits: false});
}).then(function () {
return db.query(queryFun);
}).then(function (res) {
res.rows[0].key.should.equal('2');
});
});
});
});
});
it('#242 conflicts at the root+1 level', function () {
var db = new PouchDB(dbName);
return db.bulkDocs([
{
foo: '2',
_id: 'foo',
_rev: '1-x',
_revisions: {start: 1, ids: ['x']}
},
{
foo: '3',
_id: 'foo',
_rev: '2-y',
_deleted: true,
_revisions: {start: 2, ids: ['y', 'x']}
}
], {new_edits: false}).then(function () {
return createView(db, {
map: function (doc) {
emit(doc.foo);
}
}).then(function (queryFun) {
return db.query(queryFun).then(function (res) {
res.rows.length.should.equal(0);
return db.bulkDocs([
{
foo: '1',
_id: 'foo',
_rev: '1-w',
_revisions: {start: 1, ids: ['w']}
}
], {new_edits: false}).then(function () {
return db.query(queryFun);
}).then(function (res) {
res.rows[0].key.should.equal('1');
return db.bulkDocs([
{
foo: '4',
_id: 'foo',
_rev: '1-z',
_revisions: {start: 1, ids: ['z']}
}
], {new_edits: false});
}).then(function () {
return db.query(queryFun);
}).then(function (res) {
res.rows[0].key.should.equal('4');
});
});
});
});
});
it('Views should include _conflicts', function () {
var db2name = 'test2' + Math.random();
var cleanup = function () {
return new PouchDB(db2name).destroy();
};
var doc1 = {_id: '1', foo: 'bar'};
var doc2 = {_id: '1', foo: 'baz'};
return testUtils.fin(new PouchDB(dbName).then(function (db) {
return new PouchDB(db2name).then(function (remote) {
return createView(db, {
map : function (doc) {
emit(doc._id, !!doc._conflicts);
}
}).then(function (queryFun) {
var replicate = testUtils.promisify(db.replicate.from, db.replicate);
return db.post(doc1).then(function () {
return remote.post(doc2);
}).then(function () {
return replicate(remote);
}).then(function () {
return db.get(doc1._id, {conflicts: true});
}).then(function (res) {
should.exist(res._conflicts);
return db.query(queryFun);
}).then(function (res) {
res.rows[0].value.should.equal(true);
});
});
});
}), cleanup);
});
it("Test view querying with limit option", function () {
return new PouchDB(dbName).then(function (db) {
return createView(db, {
map : function (doc) {
if (doc.foo === 'bar') {
emit(doc.foo);
}
}
}).then(function (queryFun) {
return db.bulkDocs({
docs: [
{ foo: 'bar' },
{ foo: 'bar' },
{ foo: 'baz' }
]
}).then(function () {
return db.query(queryFun, { limit: 1 });
}).then(function (res) {
res.total_rows.should.equal(2, 'Correctly returns total rows');
res.rows.should.have.length(1, 'Correctly limits returned rows');
});
});
});
});
it("Test view querying with custom reduce function", function () {
return new PouchDB(dbName).then(function (db) {
return createView(db, {
map: function (doc) {
emit(doc.foo);
},
reduce: function(keys) {
return keys.map(function(keyId) {
var key = keyId[0];
// var id = keyId[1];
return key.join('');
});
}
}).then(function (queryFun) {
return db.bulkDocs({
docs: [
{ foo: ['foo', 'bar'] },
{ foo: ['foo', 'bar'] },
{ foo: ['foo', 'bar', 'baz'] },
{ foo: ['baz'] },
{ foo: ['baz', 'bar'] }
]
}).then(function () {
return db.query(queryFun, { reduce: true });
}).then(function (res) {
res.rows.should.have.length(1, 'Correctly reduced returned rows');
should.not.exist(res.rows[0].key, 'Correct, non-existing key');
res.rows[0].value.should.have.length(5);
res.rows[0].value.should.include('foobarbaz');
res.rows[0].value.should.include('foobar'); // twice
res.rows[0].value.should.include('bazbar');
res.rows[0].value.should.include('baz');
return db.query(queryFun, { group_level: 1, reduce: true });
}).then(function (res) {
res.rows.should.have.length(2, 'Correctly group reduced rows');
res.rows[0].key.should.deep.equal(['baz']);
res.rows[0].value.should.have.length(2);
res.rows[0].value.should.include('bazbar');
res.rows[0].value.should.include('baz');
res.rows[1].key.should.deep.equal(['foo']);
res.rows[1].value.should.have.length(3);
res.rows[1].value.should.include('foobarbaz');
res.rows[1].value.should.include('foobar'); // twice
});
});
});
});
it("Test view querying with group_level option and reduce", function () {
return new PouchDB(dbName).then(function (db) {
return createView(db, {
map: function (doc) {
emit(doc.foo);
},
reduce: '_count'
}).then(function (queryFun) {
return db.bulkDocs({
docs: [
{ foo: ['foo', 'bar'] },
{ foo: ['foo', 'bar'] },
{ foo: ['foo', 'bar', 'baz'] },
{ foo: ['baz'] },
{ foo: ['baz', 'bar'] }
]
}).then(function () {
return db.query(queryFun, { group_level: 1, reduce: true});
}).then(function (res) {
res.rows.should.have.length(2, 'Correctly group returned rows');
res.rows[0].key.should.deep.equal(['baz']);
res.rows[0].value.should.equal(2);
res.rows[1].key.should.deep.equal(['foo']);
res.rows[1].value.should.equal(3);
return db.query(queryFun, { group_level: 999, reduce: true});
}).then(function (res) {
res.rows.should.have.length(4, 'Correctly group returned rows');
res.rows[2].key.should.deep.equal(['foo', 'bar']);
res.rows[2].value.should.equal(2);
return db.query(queryFun, { group_level: '999', reduce: true});
}).then(function (res) {
res.rows.should.have.length(4, 'Correctly group returned rows');
res.rows[2].key.should.deep.equal(['foo', 'bar']);
res.rows[2].value.should.equal(2);
return db.query(queryFun, { group_level: 0, reduce: true});
}).then(function (res) {
res.rows.should.have.length(1, 'Correctly group returned rows');
res.rows[0].value.should.equal(5);
});
});
});
});
it("Test view querying with invalid group_level options", function () {
return new PouchDB(dbName).then(function (db) {
return createView(db, {
map: function (doc) {
emit(doc.foo);
},
reduce: '_count'
}).then(function (queryFun) {
return db.query(queryFun, { group_level: -1, reduce: true
}).then(function (res) {
res.should.not.exist('expected error on invalid group_level');
}).catch(function (err) {
err.status.should.equal(400);
err.message.should.be.a('string');
return db.query(queryFun, { group_level: 'exact', reduce: true});
}).then(function (res) {
res.should.not.exist('expected error on invalid group_level');
}).catch(function (err) {
err.status.should.equal(400);
err.message.should.be.a('string');
});
});
});
});
it("Test view querying with limit option and reduce", function () {
return new PouchDB(dbName).then(function (db) {
return createView(db, {
map: function (doc) {
emit(doc.foo);
},
reduce: '_count'
}).then(function (queryFun) {
return db.bulkDocs({
docs: [
{ foo: 'bar' },
{ foo: 'bar' },
{ foo: 'baz' }
]
}).then(function () {
return db.query(queryFun, { limit: 1, group: true, reduce: true});
}).then(function (res) {
res.rows.should.have.length(1, 'Correctly limits returned rows');
res.rows[0].key.should.equal('bar');
res.rows[0].value.should.equal(2);
}).then(function () {
return db.query(queryFun, { limit: '1', group: true, reduce: true});
}).then(function (res) {
res.rows.should.have.length(1, 'Correctly limits returned rows');
res.rows[0].key.should.equal('bar');
res.rows[0].value.should.equal(2);
});
});
});
});
it("Test view querying with invalid limit option and reduce", function () {
return new PouchDB(dbName).then(function (db) {
return createView(db, {
map: function (doc) {
emit(doc.foo);
},
reduce: '_count'
}).then(function (queryFun) {
return db.bulkDocs({
docs: [
{ foo: 'bar' },
{ foo: 'bar' },
{ foo: 'baz' }
]
}).then(function () {
return db.query(queryFun, { limit: -1, group: true, reduce: true});
}).then(function (res) {
res.should.not.exist('expected error on invalid group_level');
}).catch(function (err) {
err.status.should.equal(400);
err.message.should.be.a('string');
return db.query(queryFun, { limit: '1a', group: true, reduce: true});
}).then(function (res) {
res.should.not.exist('expected error on invalid group_level');
}).catch(function (err) {
err.status.should.equal(400);
err.message.should.be.a('string');
});
});
});
});
it('Test unsafe object usage (#244)', function () {
var db = new PouchDB(dbName);
return db.bulkDocs([
{_id: 'constructor'}
]).then(function (res) {
var rev = res[0].rev;
return createView(db, {
map: function (doc) {
emit(doc._id);
}
}).then(function (queryFun) {
return db.query(queryFun, {include_docs: true}).then(function (res) {
res.rows.should.deep.equal([
{
"key": "constructor",
"id": "constructor",
"value": null,
"doc": {
"_id": "constructor",
"_rev": rev
}
}
]);
return db.bulkDocs([
{_id: 'constructor', _rev: rev}
]);
}).then(function (res) {
rev = res[0].rev;
return db.query(queryFun, {include_docs: true});
}).then(function (res) {
res.rows.should.deep.equal([
{
"key": "constructor",
"id": "constructor",
"value": null,
"doc": {
"_id": "constructor",
"_rev": rev
}
}
]);
return db.bulkDocs([
{_id: 'constructor', _rev: rev, _deleted: true}
]);
}).then(function (res) {
rev = res[0].rev;
return db.query(queryFun, {include_docs: true});
}).then(function (res) {
res.rows.should.deep.equal([]);
});
});
});
});
it("Test view querying with a skip option and reduce", function () {
var qf;
return new PouchDB(dbName).then(function (db) {
return createView(db, {
map: function (doc) {
emit(doc.foo);
},
reduce: '_count'
}).then(function (queryFun) {
qf = queryFun;
return db.bulkDocs({
docs: [
{ foo: 'bar' },
{ foo: 'bar' },
{ foo: 'baz' }
]
}).then(function () {
return db.query(queryFun, {skip: 1, group: true, reduce: true});
});
}).then(function (res) {
res.rows.should.have.length(1, 'Correctly limits returned rows');
res.rows[0].key.should.equal('baz');
res.rows[0].value.should.equal(1);
}).then(function () {
return db.query(qf, {skip: '1', group: true, reduce: true});
}).then(function (res) {
res.rows.should.have.length(1, 'Correctly limits returned rows');
res.rows[0].key.should.equal('baz');
res.rows[0].value.should.equal(1);
});
});
});
it("Test view querying with invalid skip option and reduce", function () {
return new PouchDB(dbName).then(function (db) {
return createView(db, {
map: function (doc) {
emit(doc.foo);
},
reduce: '_count'
}).then(function (queryFun) {
return db.bulkDocs({
docs: [
{ foo: 'bar' },
{ foo: 'bar' },
{ foo: 'baz' }
]
}).then(function () {
return db.query(queryFun, { skip: -1, group: true, reduce: true});
}).then(function (res) {
res.should.not.exist('expected error on invalid group_level');
}).catch(function (err) {
err.status.should.equal(400);
err.message.should.be.a('string');
return db.query(queryFun, { skip: '1a', group: true, reduce: true});
}).then(function (res) {
res.should.not.exist('expected error on invalid group_level');
}).catch(function (err) {
err.status.should.equal(400);
err.message.should.be.a('string');
});
});
});
});
it("Special document member _doc_id_rev should never leak outside",
function () {
return new PouchDB(dbName).then(function (db) {
return createView(db, {
map : function (doc) {
if (doc.foo === 'bar') {
emit(doc.foo);
}
}
}).then(function (queryFun) {
return db.bulkDocs({
docs: [
{ foo: 'bar' }
]
}).then(function () {
return db.query(queryFun, { include_docs: true });
}).then(function (res) {
should.not.exist(res.rows[0].doc._doc_id_rev, '_doc_id_rev is leaking but should not');
});
});
});
});
it.skip('multiple view creations and cleanups', function () {
return new PouchDB(dbName).then(function (db) {
var map = function (doc) {
emit(doc.num);
};
function createView(name) {
var storableViewObj = {
map: map.toString()
};
return db.put({
_id: '_design/' + name,
views: {
theView: storableViewObj
}
});
}
return db.bulkDocs({
docs: [
{_id: 'test1'}
]
}).then(function () {
function sequence(name) {
return createView(name).then(function () {
return db.query(name + '/theView').then(function () {
return db.viewCleanup();
});
});
}
var attempts = [];
var numAttempts = 10;
for (var i = 0; i < numAttempts; i++) {
attempts.push(sequence('test' + i));
}
return Promise.all(attempts).then(function () {
var keys = [];
for (var i = 0; i < numAttempts; i++) {
keys.push('_design/test' + i);
}
return db.allDocs({keys : keys, include_docs : true});
}).then(function (res) {
var docs = res.rows.map(function (row) {
row.doc._deleted = true;
return row.doc;
});
return db.bulkDocs({docs : docs});
}).then(function () {
return db.viewCleanup();
}).then(function (res) {
res.ok.should.equal(true);
});
});
});
});
it('If reduce function returns 0, resulting value should not be null', function () {
return new PouchDB(dbName).then(function (db) {
return createView(db, {
map: function (doc) {
emit(doc.foo);
},
reduce: function () {
return 0;
}
}).then(function (queryFun) {
return db.bulkDocs({
docs: [
{ foo: 'bar' }
]
}).then(function () {
return db.query(queryFun).then(function (data) {
should.exist(data.rows[0].value);
});
});
});
});
});
it('Testing skip with a view', function () {
return new PouchDB(dbName).then(function (db) {
return createView(db, {
map : function (doc) {
emit(doc.foo);
}
}).then(function (queryFun) {
return db.bulkDocs({
docs: [
{ foo: 'bar' },
{ foo: 'baz' },
{ foo: 'baf' }
]
}).then(function () {
return db.query(queryFun, {skip: 1});
}).then(function (data) {
data.rows.should.have.length(2);
data.offset.should.equal(1);
data.total_rows.should.equal(3);
});
});
});
});
it('Map documents on 0/null/undefined/empty string', function () {
return new PouchDB(dbName).then(function (db) {
return createView(db, {
map : function (doc) {
emit(doc.num);
}
}).then(function (mapFunction) {
var docs = [
{_id: '0', num: 0},
{_id: '1', num: 1},
{_id: 'undef' /* num is undefined */},
{_id: 'null', num: null},
{_id: 'empty', num: ''},
{_id: 'nan', num: NaN},
{_id: 'inf', num: Infinity},
{_id: 'neginf', num: -Infinity}
];
return db.bulkDocs({docs: docs}).then(function () {
return db.query(mapFunction, {key: 0});
}).then(function (data) {
data.rows.should.have.length(1);
data.rows[0].id.should.equal('0');
return db.query(mapFunction, {key: ''});
}).then(function (data) {
data.rows.should.have.length(1);
data.rows[0].id.should.equal('empty');
return db.query(mapFunction, {key: undefined});
}).then(function (data) {
data.rows.should.have.length(8); // everything
// keys that should all resolve to null
var emptyKeys = [null, NaN, Infinity, -Infinity];
return Promise.all(emptyKeys.map(function (emptyKey) {
return db.query(mapFunction, {key: emptyKey}).then(function (data) {
data.rows.map(function (row) {
return row.id;
}).should.deep.equal(['inf', 'nan', 'neginf', 'null', 'undef']);
});
}));
});
});
});
});
it('Testing query with keys', function () {
return new PouchDB(dbName).then(function (db) {
return createView(db, {
map: function (doc) {
emit(doc.field);
}
}).then(function (queryFun) {
var opts = {include_docs: true};
return db.bulkDocs({
docs: [
{_id: 'doc_0', field: 0},
{_id: 'doc_1', field: 1},
{_id: 'doc_2', field: 2},
{_id: 'doc_empty', field: ''},
{_id: 'doc_null', field: null},
{_id: 'doc_undefined' /* field undefined */},
{_id: 'doc_foo', field: 'foo'}
]
}).then(function () {
return db.query(queryFun, opts);
}).then(function (data) {
data.rows.should.have.length(7, 'returns all docs');
opts.keys = [];
return db.query(queryFun, opts);
}).then(function (data) {
data.rows.should.have.length(0, 'returns 0 docs');
opts.keys = [0];
return db.query(queryFun, opts);
}).then(function (data) {
data.rows.should.have.length(1, 'returns one doc');
data.rows[0].doc._id.should.equal('doc_0');
opts.keys = [2, 'foo', 1, 0, null, ''];
return db.query(queryFun, opts);
}).then(function (data) {
// check that the returned ordering fits opts.keys
data.rows.should.have.length(7, 'returns 7 docs in correct order');
data.rows[0].doc._id.should.equal('doc_2');
data.rows[1].doc._id.should.equal('doc_foo');
data.rows[2].doc._id.should.equal('doc_1');
data.rows[3].doc._id.should.equal('doc_0');
data.rows[4].doc._id.should.equal('doc_null');
data.rows[5].doc._id.should.equal('doc_undefined');
data.rows[6].doc._id.should.equal('doc_empty');
opts.keys = [3, 1, 4, 2];
return db.query(queryFun, opts);
}).then(function (data) {
// nonexistent keys just give us holes in the list
data.rows.should.have.length(2, 'returns 2 non-empty docs');
data.rows[0].key.should.equal(1);
data.rows[0].doc._id.should.equal('doc_1');
data.rows[1].key.should.equal(2);
data.rows[1].doc._id.should.equal('doc_2');
opts.keys = [2, 1, 2, 0, 2, 1];
return db.query(queryFun, opts);
}).then(function (data) {
// with duplicates, we return multiple docs
data.rows.should.have.length(6, 'returns 6 docs with duplicates');
data.rows[0].doc._id.should.equal('doc_2');
data.rows[1].doc._id.should.equal('doc_1');
data.rows[2].doc._id.should.equal('doc_2');
data.rows[3].doc._id.should.equal('doc_0');
data.rows[4].doc._id.should.equal('doc_2');
data.rows[5].doc._id.should.equal('doc_1');
opts.keys = [2, 1, 2, 3, 2];
return db.query(queryFun, opts);
}).then(function (data) {
// duplicates and unknowns at the same time, for maximum weirdness
data.rows.should.have.length(4, 'returns 2 docs with duplicates/unknowns');
data.rows[0].doc._id.should.equal('doc_2');
data.rows[1].doc._id.should.equal('doc_1');
data.rows[2].doc._id.should.equal('doc_2');
data.rows[3].doc._id.should.equal('doc_2');
opts.keys = [3];
return db.query(queryFun, opts);
}).then(function (data) {
data.rows.should.have.length(0, 'returns 0 doc due to unknown key');
opts.include_docs = false;
opts.keys = [3, 2];
return db.query(queryFun, opts);
}).then(function (data) {
data.rows.should.have.length(1, 'returns 1 doc due to unknown key');
data.rows[0].id.should.equal('doc_2');
should.not.exist(data.rows[0].doc, 'no doc, since include_docs=false');
});
});
});
});
it('Testing query with multiple keys, multiple docs', function () {
function ids(row) {
return row.id;
}
var opts = {keys: [0, 1, 2]};
var spec;
return new PouchDB(dbName).then(function (db) {
return createView(db, {
map : function (doc) {
emit(doc.field1);
emit(doc.field2);
}
}).then(function (mapFunction) {
return db.bulkDocs({
docs: [
{_id: '0', field1: 0},
{_id: '1a', field1: 1},
{_id: '1b', field1: 1},
{_id: '1c', field1: 1},
{_id: '2+3', field1: 2, field2: 3},
{_id: '4+5', field1: 4, field2: 5},
{_id: '3+5', field1: 3, field2: 5},
{_id: '3+4', field1: 3, field2: 4}
]
}).then(function () {
spec = ['0', '1a', '1b', '1c', '2+3'];
return db.query(mapFunction, opts);
}).then(function (data) {
data.rows.map(ids).should.deep.equal(spec);
opts.keys = [3, 5, 4, 3];
spec = ['2+3', '3+4', '3+5', '3+5', '4+5', '3+4', '4+5', '2+3', '3+4', '3+5'];
return db.query(mapFunction, opts);
}).then(function (data) {
data.rows.map(ids).should.deep.equal(spec);
});
});
});
});
it('Testing multiple emissions (issue #14)', function () {
return new PouchDB(dbName).then(function (db) {
return createView(db, {
map : function (doc) {
emit(doc.foo);
emit(doc.bar);
emit(doc.foo);
emit(doc.bar, 'multiple values!');
emit(doc.bar, 'crayon!');
}
}).then(function (mapFunction) {
return db.bulkDocs({
docs: [
{_id: 'doc1', foo : 'foo', bar : 'bar'},
{_id: 'doc2', foo : 'foo', bar : 'bar'}
]
}).then(function () {
var opts = {keys: ['foo', 'bar']};
return db.query(mapFunction, opts);
});
}).then(function (data) {
data.rows.should.have.length(10);
data.rows[0].key.should.equal('foo');
data.rows[0].id.should.equal('doc1');
data.rows[1].key.should.equal('foo');
data.rows[1].id.should.equal('doc1');
data.rows[2].key.should.equal('foo');
data.rows[2].id.should.equal('doc2');
data.rows[3].key.should.equal('foo');
data.rows[3].id.should.equal('doc2');
data.rows[4].key.should.equal('bar');
data.rows[4].id.should.equal('doc1');
should.not.exist(data.rows[4].value);
data.rows[5].key.should.equal('bar');
data.rows[5].id.should.equal('doc1');
data.rows[5].value.should.equal('crayon!');
data.rows[6].key.should.equal('bar');
data.rows[6].id.should.equal('doc1');
data.rows[6].value.should.equal('multiple values!');
data.rows[7].key.should.equal('bar');
data.rows[7].id.should.equal('doc2');
should.not.exist(data.rows[7].value);
data.rows[8].key.should.equal('bar');
data.rows[8].id.should.equal('doc2');
data.rows[8].value.should.equal('crayon!');
data.rows[9].key.should.equal('bar');
data.rows[9].id.should.equal('doc2');
data.rows[9].value.should.equal('multiple values!');
});
});
});
it('Testing multiple emissions (complex keys)', function () {
return new PouchDB(dbName).then(function (db) {
return createView(db, {
map: function () {
emit(['a'], 1);
emit(['b'], 3);
emit(['a'], 2);
}
}).then(function (mapFunction) {
return db.bulkDocs({
docs: [
{_id: 'doc1', foo: 'foo', bar: 'bar'}
]
}).then(function () {
return db.query(mapFunction);
});
}).then(function (data) {
data.rows.should.have.length(3);
data.rows[0].key.should.eql(['a']);
data.rows[0].value.should.equal(1);
data.rows[1].key.should.eql(['a']);
data.rows[1].value.should.equal(2);
data.rows[2].key.should.eql(['b']);
data.rows[2].value.should.equal(3);
});
});
});
it('Testing empty startkeys and endkeys', function () {
var opts = {startkey: null, endkey: ''};
function ids(row) {
return row.id;
}
var spec;
return new PouchDB(dbName).then(function (db) {
return createView(db, {
map : function (doc) {
emit(doc.field);
}
}).then(function (mapFunction) {
return db.bulkDocs({
docs: [
{_id: 'doc_empty', field: ''},
{_id: 'doc_null', field: null},
{_id: 'doc_undefined' /* field undefined */},
{_id: 'doc_foo', field: 'foo'}
]
}).then(function () {
spec = ['doc_null', 'doc_undefined', 'doc_empty'];
return db.query(mapFunction, opts);
}).then(function (data) {
data.rows.map(ids).should.deep.equal(spec);
opts = {startkey: '', endkey: 'foo'};
spec = ['doc_empty', 'doc_foo'];
return db.query(mapFunction, opts);
}).then(function (data) {
data.rows.map(ids).should.deep.equal(spec);
opts = {startkey: null, endkey: null};
spec = ['doc_null', 'doc_undefined'];
return db.query(mapFunction, opts);
}).then(function (data) {
data.rows.map(ids).should.deep.equal(spec);
opts.descending = true;
spec.reverse();
return db.query(mapFunction, opts);
}).then(function (data) {
data.rows.map(ids).should.deep.equal(spec);
});
});
});
});
it('#238 later non-winning revisions', function () {
var db = new PouchDB(dbName);
return createView(db, {
map: function (doc) {
emit(doc.name);
}
}).then(function (mapFun) {
return db.bulkDocs([{
_id: 'doc',
name: 'zoot',
_rev: '2-x',
_revisions: {
start: 2,
ids: ['x', 'y']
}
}], {new_edits: false}).then(function () {
return db.query(mapFun);
}).then(function (res) {
res.rows.should.have.length(1);
res.rows[0].id.should.equal('doc');
res.rows[0].key.should.equal('zoot');
return db.bulkDocs([{
_id: 'doc',
name: 'suit',
_rev: '2-w',
_revisions: {
start: 2,
ids: ['w', 'y']
}
}], {new_edits: false});
}).then(function () {
return db.query(mapFun);
}).then(function (res) {
res.rows.should.have.length(1);
res.rows[0].id.should.equal('doc');
res.rows[0].key.should.equal('zoot');
});
});
});
it('#238 later non-winning deleted revisions', function () {
var db = new PouchDB(dbName);
return createView(db, {
map: function (doc) {
emit(doc.name);
}
}).then(function (mapFun) {
return db.bulkDocs([{
_id: 'doc',
name: 'zoot',
_rev: '2-x',
_revisions: {
start: 2,
ids: ['x', 'y']
}
}], {new_edits: false}).then(function () {
return db.query(mapFun);
}).then(function (res) {
res.rows.should.have.length(1);
res.rows[0].id.should.equal('doc');
res.rows[0].key.should.equal('zoot');
return db.bulkDocs([{
_id: 'doc',
name: 'suit',
_deleted: true,
_rev: '2-z',
_revisions: {
start: 2,
ids: ['z', 'y']
}
}], {new_edits: false});
}).then(function () {
return db.query(mapFun);
}).then(function (res) {
res.rows.should.have.length(1);
res.rows[0].id.should.equal('doc');
res.rows[0].key.should.equal('zoot');
});
});
});
it('#238 query with conflicts', function () {
var db = new PouchDB(dbName);
return createView(db, {
map: function (doc) {
emit(doc.name);
}
}).then(function (mapFun) {
return db.bulkDocs([
{
_id: 'doc',
name: 'zab',
_rev: '2-y',
_revisions: {
start: 1,
ids: ['y']
}
}, {
_id: 'doc',
name: 'zoot',
_rev: '2-x',
_revisions: {
start: 2,
ids: ['x', 'y']
}
}
], {new_edits: false}).then(function () {
return db.query(mapFun);
}).then(function (res) {
res.rows.should.have.length(1);
res.rows[0].id.should.equal('doc');
res.rows[0].key.should.equal('zoot');
return db.bulkDocs([
{
_id: 'doc',
name: 'suit',
_rev: '2-w',
_revisions: {
start: 2,
ids: ['w', 'y']
}
}, {
_id: 'doc',
name: 'zorb',
_rev: '2-z',
_revisions: {
start: 2,
ids: ['z', 'y']
}
}
], {new_edits: false});
}).then(function () {
return db.query(mapFun);
}).then(function (res) {
res.rows.should.have.length(1);
res.rows[0].id.should.equal('doc');
res.rows[0].key.should.equal('zorb');
});
});
});
it('Testing ordering with startkey/endkey/key', function () {
var opts = {startkey: '1', endkey: '4'};
function ids(row) {
return row.id;
}
var spec;
return new PouchDB(dbName).then(function (db) {
return createView(db, {
map : function (doc) {
emit(doc.field, null);
}
}).then(function (mapFunction) {
return db.bulkDocs({
docs: [
{_id: 'h', field: '4'},
{_id: 'a', field: '1'},
{_id: 'e', field: '2'},
{_id: 'c', field: '1'},
{_id: 'f', field: '3'},
{_id: 'g', field: '4'},
{_id: 'd', field: '2'},
{_id: 'b', field: '1'}
]
}).then(function () {
spec = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'];
return db.query(mapFunction, opts);
}).then(function (data) {
data.rows.map(ids).should.deep.equal(spec);
opts = {key: '1'};
spec = ['a', 'b', 'c'];
return db.query(mapFunction, opts);
}).then(function (data) {
data.rows.map(ids).should.deep.equal(spec);
opts = {key: '2'};
spec = ['d', 'e'];
return db.query(mapFunction, opts);
}).then(function (data) {
data.rows.map(ids).should.deep.equal(spec);
opts.descending = true;
spec.reverse();
return db.query(mapFunction, opts);
}).then(function (data) {
data.rows.map(ids).should.deep.equal(spec, 'reverse order');
});
});
});
});
it('opts.keys should work with complex keys', function () {
return new PouchDB(dbName).then(function (db) {
return createView(db, {
map : function (doc) {
emit(doc.foo, doc.foo);
}
}).then(function (mapFunction) {
var keys = [
{key: 'missing'},
['test', 1],
{key1: 'value1'},
['missing'],
[0, 0]
];
return db.bulkDocs({
docs: [
{foo: {key2: 'value2'}},
{foo: {key1: 'value1'}},
{foo: [0, 0]},
{foo: ['test', 1]},
{foo: [0, false]}
]
}).then(function () {
var opts = {keys: keys};
return db.query(mapFunction, opts);
}).then(function (data) {
data.rows.should.have.length(3);
data.rows[0].value.should.deep.equal(keys[1]);
data.rows[1].value.should.deep.equal(keys[2]);
data.rows[2].value.should.deep.equal(keys[4]);
});
});
});
});
it('Testing ordering with dates', function () {
function ids(row) {
return row.id;
}
return new PouchDB(dbName).then(function (db) {
return createView(db, {
map : function (doc) {
emit(doc.date, null);
}
}).then(function (mapFunction) {
return db.bulkDocs({
docs: [
{_id: '1969', date: '1969 was when Space Oddity hit'},
{_id: '1971', date : new Date('1971-12-17T00:00:00.000Z')}, // Hunky Dory was released
{_id: '1972', date: '1972 was when Ziggy landed on Earth'},
{_id: '1977', date: new Date('1977-01-14T00:00:00.000Z')}, // Low was released
{_id: '1985', date: '1985+ is better left unmentioned'}
]
}).then(function () {
return db.query(mapFunction);
}).then(function (data) {
data.rows.map(ids).should.deep.equal(['1969', '1971', '1972', '1977', '1985']);
});
});
});
});
it('should work with a joined doc', function () {
function change(row) {
return [row.key, row.doc._id, row.doc.val];
}
return new PouchDB(dbName).then(function (db) {
return createView(db, {
map: function (doc) {
if (doc.join) {
emit(doc.color, {_id : doc.join});
}
}
}).then(function (mapFunction) {
return db.bulkDocs({
docs: [
{_id: 'a', join: 'b', color: 'green'},
{_id: 'b', val: 'c'},
{_id: 'd', join: 'f', color: 'red'}
]
}).then(function () {
return db.query(mapFunction, {include_docs: true});
}).then(function (resp) {
return change(resp.rows[0]).should.deep.equal(['green', 'b', 'c']);
});
});
});
});
it('should query correctly with a variety of criteria', function () {
return new PouchDB(dbName).then(function (db) {
return createView(db, {
map : function (doc) {
emit(doc._id);
}
}).then(function (mapFun) {
var docs = [
{_id : '0'},
{_id : '1'},
{_id : '2'},
{_id : '3'},
{_id : '4'},
{_id : '5'},
{_id : '6'},
{_id : '7'},
{_id : '8'},
{_id : '9'}
];
return db.bulkDocs({docs : docs}).then(function (res) {
docs[3]._deleted = true;
docs[7]._deleted = true;
docs[3]._rev = res[3].rev;
docs[7]._rev = res[7].rev;
return db.remove(docs[3]);
}).then(function () {
return db.remove(docs[7]);
}).then(function () {
return db.query(mapFun, {});
}).then(function (res) {
res.rows.should.have.length(8, 'correctly return rows');
res.total_rows.should.equal(8, 'correctly return total_rows');
return db.query(mapFun, {startkey : '5'});
}).then(function (res) {
res.rows.should.have.length(4, 'correctly return rows');
res.total_rows.should.equal(8, 'correctly return total_rows');
return db.query(mapFun, {startkey : '5', skip : 2, limit : 10});
}).then(function (res) {
res.rows.should.have.length(2, 'correctly return rows');
res.total_rows.should.equal(8, 'correctly return total_rows');
return db.query(mapFun, {startkey : '5', descending : true, skip : 1});
}).then(function (res) {
res.rows.should.have.length(4, 'correctly return rows');
res.total_rows.should.equal(8, 'correctly return total_rows');
return db.query(mapFun, {startkey : '5', endkey : 'z'});
}).then(function (res) {
res.rows.should.have.length(4, 'correctly return rows');
res.total_rows.should.equal(8, 'correctly return total_rows');
return db.query(mapFun, {startkey : '5', endkey : '5'});
}).then(function (res) {
res.rows.should.have.length(1, 'correctly return rows');
res.total_rows.should.equal(8, 'correctly return total_rows');
return db.query(mapFun, {startkey : '5', endkey : '4', descending : true});
}).then(function (res) {
res.rows.should.have.length(2, 'correctly return rows');
res.total_rows.should.equal(8, 'correctly return total_rows');
return db.query(mapFun, {startkey : '3', endkey : '7', descending : false});
}).then(function (res) {
res.rows.should.have.length(3, 'correctly return rows');
res.total_rows.should.equal(8, 'correctly return total_rows');
return db.query(mapFun, {startkey : '7', endkey : '3', descending : true});
}).then(function (res) {
res.rows.should.have.length(3, 'correctly return rows');
res.total_rows.should.equal(8, 'correctly return total_rows');
return db.query(mapFun, {startkey : '', endkey : '0'});
}).then(function (res) {
res.rows.should.have.length(1, 'correctly return rows');
res.total_rows.should.equal(8, 'correctly return total_rows');
return db.query(mapFun, {keys : ['0', '1', '3']});
}).then(function (res) {
res.rows.should.have.length(2, 'correctly return rows');
res.total_rows.should.equal(8, 'correctly return total_rows');
return db.query(mapFun, {keys : ['0', '1', '0', '2', '1', '1']});
}).then(function (res) {
res.rows.should.have.length(6, 'correctly return rows');
res.rows.map(function (row) { return row.key; }).should.deep.equal(
['0', '1', '0', '2', '1', '1']);
res.total_rows.should.equal(8, 'correctly return total_rows');
return db.query(mapFun, {keys : []});
}).then(function (res) {
res.rows.should.have.length(0, 'correctly return rows');
res.total_rows.should.equal(8, 'correctly return total_rows');
return db.query(mapFun, {keys : ['7']});
}).then(function (res) {
res.rows.should.have.length(0, 'correctly return rows');
res.total_rows.should.equal(8, 'correctly return total_rows');
return db.query(mapFun, {key : '3'});
}).then(function (res) {
res.rows.should.have.length(0, 'correctly return rows');
res.total_rows.should.equal(8, 'correctly return total_rows');
return db.query(mapFun, {key : '2'});
}).then(function (res) {
res.rows.should.have.length(1, 'correctly return rows');
res.total_rows.should.equal(8, 'correctly return total_rows');
return db.query(mapFun, {key : 'z'});
}).then(function (res) {
res.rows.should.have.length(0, 'correctly return rows');
res.total_rows.should.equal(8, 'correctly return total_rows');
return db.query(mapFun, {startkey : '5', endkey : '4'}).then(function (res) {
res.should.not.exist('expected error on reversed start/endkey');
}).catch(function (err) {
err.status.should.equal(400);
err.message.should.be.a('string');
});
});
});
});
});
it('should query correctly with skip/limit and multiple keys/values', function () {
var db = new PouchDB(dbName);
var docs = {
docs: [
{_id: 'doc1', foo : 'foo', bar : 'bar'},
{_id: 'doc2', foo : 'foo', bar : 'bar'}
]
};
var getValues = function (res) {
return res.value;
};
var getIds = function (res) {
return res.id;
};
return createView(db, {
map : function (doc) {
emit(doc.foo, 'fooValue');
emit(doc.foo);
emit(doc.bar);
emit(doc.bar, 'crayon!');
emit(doc.bar, 'multiple values!');
emit(doc.bar, 'crayon!');
}
}).then(function (mapFun) {
return db.bulkDocs(docs).then(function () {
return db.query(mapFun, {});
}).then(function (res) {
res.rows.should.have.length(12, 'correctly return rows');
res.total_rows.should.equal(12, 'correctly return total_rows');
res.rows.map(getValues).should.deep.equal(
[null, 'crayon!', 'crayon!', 'multiple values!',
null, 'crayon!', 'crayon!', 'multiple values!',
null, 'fooValue', null, 'fooValue']);
res.rows.map(getIds).should.deep.equal(
['doc1', 'doc1', 'doc1', 'doc1',
'doc2', 'doc2', 'doc2', 'doc2',
'doc1', 'doc1', 'doc2', 'doc2']);
return db.query(mapFun, {startkey : 'foo'});
}).then(function (res) {
res.rows.should.have.length(4, 'correctly return rows');
res.total_rows.should.equal(12, 'correctly return total_rows');
res.rows.map(getValues).should.deep.equal(
[null, 'fooValue', null, 'fooValue']);
res.rows.map(getIds).should.deep.equal(
['doc1', 'doc1', 'doc2', 'doc2']);
return db.query(mapFun, {startkey : 'foo', endkey : 'foo'});
}).then(function (res) {
res.rows.should.have.length(4, 'correctly return rows');
res.total_rows.should.equal(12, 'correctly return total_rows');
return db.query(mapFun, {startkey : 'bar', endkey : 'bar'});
}).then(function (res) {
res.rows.should.have.length(8, 'correctly return rows');
res.total_rows.should.equal(12, 'correctly return total_rows');
return db.query(mapFun, {startkey : 'foo', limit : 1});
}).then(function (res) {
res.rows.should.have.length(1, 'correctly return rows');
res.total_rows.should.equal(12, 'correctly return total_rows');
res.rows.map(getValues).should.deep.equal([null]);
res.rows.map(getIds).should.deep.equal(['doc1']);
return db.query(mapFun, {startkey : 'foo', limit : 2});
}).then(function (res) {
res.rows.should.have.length(2, 'correctly return rows');
res.total_rows.should.equal(12, 'correctly return total_rows');
return db.query(mapFun, {startkey : 'foo', limit : 1000});
}).then(function (res) {
res.rows.should.have.length(4, 'correctly return rows');
res.total_rows.should.equal(12, 'correctly return total_rows');
return db.query(mapFun, {startkey : 'foo', skip : 1});
}).then(function (res) {
res.rows.should.have.length(3, 'correctly return rows');
res.total_rows.should.equal(12, 'correctly return total_rows');
return db.query(mapFun, {startkey : 'foo', skip : 3, limit : 0});
}).then(function (res) {
res.rows.should.have.length(0, 'correctly return rows');
res.total_rows.should.equal(12, 'correctly return total_rows');
return db.query(mapFun, {startkey : 'foo', skip : 3, limit : 1});
}).then(function (res) {
res.rows.should.have.length(1, 'correctly return rows');
res.total_rows.should.equal(12, 'correctly return total_rows');
res.rows.map(getValues).should.deep.equal(['fooValue']);
res.rows.map(getIds).should.deep.equal(['doc2']);
return db.query(mapFun, {startkey : 'quux', skip : 3, limit : 1});
}).then(function (res) {
res.rows.should.have.length(0, 'correctly return rows');
res.total_rows.should.equal(12, 'correctly return total_rows');
return db.query(mapFun, {startkey : 'bar', limit : 2});
}).then(function (res) {
res.rows.should.have.length(2, 'correctly return rows');
res.total_rows.should.equal(12, 'correctly return total_rows');
});
});
});
it('should query correctly with undefined key/values', function () {
var db = new PouchDB(dbName);
var docs = {
docs: [
{_id: 'doc1'},
{_id: 'doc2'}
]
};
return createView(db, {
map : function () {
emit();
}
}).then(function (mapFun) {
return db.bulkDocs(docs).then(function () {
return db.query(mapFun, {});
}).then(function (res) {
res.total_rows.should.equal(2, 'correctly return total_rows');
res.rows.should.deep.equal([
{
key : null,
value : null,
id : 'doc1'
},
{
key : null,
value : null,
id : 'doc2'
}
]);
});
});
});
it('should query correctly with no docs', function () {
return new PouchDB(dbName).then(function (db) {
return createView(db, {
map : function () {
emit();
}
}).then(function (queryFun) {
return db.query(queryFun).then(function (res) {
res.total_rows.should.equal(0, 'total_rows');
res.offset.should.equal(0);
res.rows.should.deep.equal([]);
});
});
});
});
it('should query correctly with no emits', function () {
return new PouchDB(dbName).then(function (db) {
return createView(db, {
map : function () {
}
}).then(function (queryFun) {
return db.bulkDocs({docs : [
{_id : 'foo'},
{_id : 'bar'}
]}).then(function () {
return db.query(queryFun).then(function (res) {
res.total_rows.should.equal(0, 'total_rows');
res.offset.should.equal(0);
res.rows.should.deep.equal([]);
});
});
});
});
});
it('should correctly return results when reducing or not reducing', function () {
function keyValues(row) {
return { key: row.key, value: row.value };
}
function keys(row) {
return row.key;
}
function values(row) {
return row.value;
}
function docIds(row) {
return row.doc._id;
}
return new PouchDB(dbName).then(function (db) {
return createView(db, {
map : function (doc) {
emit(doc.name);
},
reduce : '_count'
}).then(function (queryFun) {
return db.bulkDocs({docs : [
{name : 'foo', _id : '1'},
{name : 'bar', _id : '2'},
{name : 'foo', _id : '3'},
{name : 'quux', _id : '4'},
{name : 'foo', _id : '5'},
{name : 'foo', _id : '6'},
{name : 'foo', _id : '7'}
]}).then(function () {
return db.query(queryFun);
}).then(function (res) {
Object.keys(res.rows[0]).sort().should.deep.equal(['key', 'value'],
'object only have 2 keys');
should.not.exist(res.total_rows, 'no total_rows1');
should.not.exist(res.offset, 'no offset1');
res.rows.map(keyValues).should.deep.equal([
{
key : null,
value : 7
}
]);
return db.query(queryFun, {group : true});
}).then(function (res) {
Object.keys(res.rows[0]).sort().should.deep.equal(['key', 'value'],
'object only have 2 keys');
should.not.exist(res.total_rows, 'no total_rows2');
should.not.exist(res.offset, 'no offset2');
res.rows.map(keyValues).should.deep.equal([
{
key : 'bar',
value : 1
},
{
key : 'foo',
value : 5
},
{
key : 'quux',
value : 1
}
]);
return db.query(queryFun, {reduce : false});
}).then(function (res) {
Object.keys(res.rows[0]).sort().should.deep.equal(['id', 'key', 'value'],
'object only have 3 keys');
res.total_rows.should.equal(7, 'total_rows1');
res.offset.should.equal(0, 'offset1');
res.rows.map(keys).should.deep.equal([
'bar', 'foo', 'foo', 'foo', 'foo', 'foo', 'quux'
]);
res.rows.map(values).should.deep.equal([
null, null, null, null, null, null, null
]);
return db.query(queryFun, {reduce : false, skip : 3});
}).then(function (res) {
Object.keys(res.rows[0]).sort().should.deep.equal(['id', 'key', 'value'],
'object only have 3 keys');
res.total_rows.should.equal(7, 'total_rows2');
res.offset.should.equal(3, 'offset2');
res.rows.map(keys).should.deep.equal([
'foo', 'foo', 'foo', 'quux'
]);
return db.query(queryFun, {reduce : false, include_docs : true});
}).then(function (res) {
Object.keys(res.rows[0]).sort().should.deep.equal(['doc', 'id', 'key', 'value'],
'object only have 4 keys');
res.total_rows.should.equal(7, 'total_rows3');
res.offset.should.equal(0, 'offset3');
res.rows.map(keys).should.deep.equal([
'bar', 'foo', 'foo', 'foo', 'foo', 'foo', 'quux'
]);
res.rows.map(values).should.deep.equal([
null, null, null, null, null, null, null
]);
res.rows.map(docIds).should.deep.equal([
'2', '1', '3', '5', '6', '7', '4'
]);
return db.query(queryFun, {include_docs : true}).then(function (res) {
should.not.exist(res);
}).catch(function (err) {
err.status.should.equal(400);
err.message.should.be.a('string');
// include_docs is invalid for reduce
});
});
});
});
});
it('should query correctly after replicating and other ddoc', function () {
return new PouchDB(dbName).then(function (db) {
return createView(db, {
map : function (doc) {
emit(doc.name);
}
}).then(function (queryFun) {
return db.bulkDocs({docs: [{name: 'foobar'}]}).then(function () {
return db.query(queryFun);
}).then(function (res) {
res.rows.map(function (x) {return x.key; }).should.deep.equal([
'foobar'
], 'test db before replicating');
return new PouchDB('local-other').then(function (db2) {
return db.replicate.to(db2).then(function () {
return db.query(queryFun);
}).then(function (res) {
res.rows.map(function (x) {return x.key; }).should.deep.equal([
'foobar'
], 'test db after replicating');
return db.put({_id: '_design/other_ddoc', views: {
map: "function(doc) { emit(doc._id); }"
}});
}).then(function () {
// the random ddoc adds a single change that we don't
// care about. testing this increases our coverage
return db.query(queryFun);
}).then(function (res) {
res.rows.map(function (x) {return x.key; }).should.deep.equal([
'foobar'
], 'test db after adding random ddoc');
return db2.query(queryFun);
}).then(function (res) {
res.rows.map(function (x) {return x.key; }).should.deep.equal([
'foobar'
], 'test db2');
}).catch(function (err) {
return new PouchDB('local-other').destroy().then(function () {
throw err;
});
}).then(function () {
return new PouchDB('local-other').destroy();
});
});
});
});
});
});
it.skip('should query correctly after many edits', function () {
return new PouchDB(dbName).then(function (db) {
return createView(db, {
map : function (doc) {
emit(doc.name, doc.likes);
}
}).then(function (queryFun) {
var docs = [
{ _id: '1', name: 'leonardo' },
{ _id: '2', name: 'michelangelo' },
{ _id: '3', name: 'donatello' },
{ _id: '4', name: 'rafael' },
{ _id: '5', name: 'april o\'neil' },
{ _id: '6', name: 'splinter' },
{ _id: '7', name: 'shredder' },
{ _id: '8', name: 'krang' },
{ _id: '9', name: 'rocksteady' },
{ _id: 'a', name: 'bebop' },
{ _id: 'b', name: 'casey jones' },
{ _id: 'c', name: 'casey jones' },
{ _id: 'd', name: 'baxter stockman' },
{ _id: 'e', name: 'general chaos' },
{ _id: 'f', name: 'rahzar' },
{ _id: 'g', name: 'tokka' },
{ _id: 'h', name: 'usagi yojimbo' },
{ _id: 'i', name: 'rat king' },
{ _id: 'j', name: 'metalhead' },
{ _id: 'k', name: 'slash' },
{ _id: 'l', name: 'ace duck' }
];
for (var i = 0; i < 100; i++) {
docs.push({
_id: 'z-' + (i + 1000), // for correct string ordering
name: 'random foot soldier #' + i
});
}
function update(res, docFun) {
for (var i = 0; i < res.length; i++) {
docs[i]._rev = res[i].rev;
docFun(docs[i]);
}
return db.bulkDocs({docs : docs});
}
return db.bulkDocs({docs : docs}).then(function (res) {
return update(res, function (doc) { doc.likes = 'pizza'; });
}).then(function (res) {
return update(res, function (doc) { doc.knows = 'kung fu'; });
}).then(function (res) {
return update(res, function (doc) { doc.likes = 'fighting'; });
}).then(function (res) {
return update(res, function (doc) { doc._deleted = true; });
}).then(function (res) {
return update(res, function (doc) { doc._deleted = false; });
}).then(function (res) {
return update(res, function (doc) { doc.name = doc.name + '1'; });
}).then(function (res) {
return update(res, function (doc) { doc.name = doc.name + '2'; });
}).then(function (res) {
return update(res, function (doc) { doc.name = 'nameless'; });
}).then(function (res) {
return update(res, function (doc) { doc._deleted = true; });
}).then(function (res) {
return update(res, function (doc) { doc.likes = 'turtles'; });
}).then(function (res) {
return update(res, function (doc) { doc._deleted = false; });
}).then(function (res) {
return update(res, function (doc) { doc.whatever = 'quux'; });
}).then(function (res) {
return update(res, function (doc) { doc.stuff = 'baz'; });
}).then(function (res) {
return update(res, function (doc) { doc.things = 'foo'; });
}).then(function () {
return db.query(queryFun);
}).then(function (res) {
res.total_rows.should.equal(docs.length, 'expected total_rows');
res.rows.map(function (row) {
return [row.id, row.key, row.value];
}).should.deep.equal(docs.map(function (doc) {
return [doc._id, 'nameless', 'turtles'];
}), 'key values match');
});
});
});
});
it.skip('should query correctly with staggered seqs', function () {
return new PouchDB(dbName).then(function (db) {
return createView(db, {
map : function (doc) {
emit(doc.name);
}
}).then(function (queryFun) {
var docs = [];
for (var i = 0; i < 200; i++) {
docs.push({
_id: 'doc-' + (i + 1000), // for correct string ordering
name: 'gen1'
});
}
return db.bulkDocs({docs: docs}).then(function (infos) {
docs.forEach(function (doc, i) {
doc._rev = infos[i].rev;
doc.name = 'gen2';
});
docs.reverse();
return db.bulkDocs({docs: docs});
}).then(function (infos) {
docs.forEach(function (doc, i) {
doc._rev = infos[i].rev;
doc.name = 'gen-3';
});
docs.reverse();
return db.bulkDocs({docs: docs});
}).then(function (infos) {
docs.forEach(function (doc, i) {
doc._rev = infos[i].rev;
doc.name = 'gen-4-odd';
});
var docsToUpdate = docs.filter(function (doc, i) {
return i % 2 === 1;
});
docsToUpdate.reverse();
return db.bulkDocs({docs: docsToUpdate});
}).then(function () {
return db.query(queryFun);
}).then(function (res) {
var expected = docs.map(function (doc, i) {
var key = i % 2 === 1 ? 'gen-4-odd' : 'gen-3';
return {key: key, id: doc._id, value: null};
});
expected.sort(function (a, b) {
if (a.key !== b.key) {
return a.key < b.key ? -1 : 1;
}
return a.id < b.id ? -1 : 1;
});
res.rows.should.deep.equal(expected);
});
});
});
});
it('should handle removes/undeletes/updates', function () {
var theDoc = {name : 'bar', _id : '1'};
return new PouchDB(dbName).then(function (db) {
return createView(db, {
map : function (doc) {
emit(doc.name);
}
}).then(function (queryFun) {
return db.put(theDoc).then(function (info) {
theDoc._rev = info.rev;
return db.query(queryFun);
}).then(function (res) {
res.rows.length.should.equal(1);
theDoc._deleted = true;
return db.post(theDoc);
}).then(function (info) {
theDoc._rev = info.rev;
return db.query(queryFun);
}).then(function (res) {
res.rows.length.should.equal(0);
theDoc._deleted = false;
return db.post(theDoc);
}).then(function (info) {
theDoc._rev = info.rev;
return db.query(queryFun);
}).then(function (res) {
res.rows.length.should.equal(1);
theDoc.name = 'foo';
return db.post(theDoc);
}).then(function (info) {
theDoc._rev = info.rev;
return db.query(queryFun);
}).then(function (res) {
res.rows.length.should.equal(1);
res.rows[0].key.should.equal('foo');
theDoc._deleted = true;
return db.post(theDoc);
}).then(function (info) {
theDoc._rev = info.rev;
return db.query(queryFun);
}).then(function (res) {
res.rows.length.should.equal(0);
});
});
});
});
it('should return error when multi-key fetch & group=false', function () {
return new PouchDB(dbName).then(function (db) {
return createView(db, {
map: function (doc) { emit(doc._id); },
reduce: '_sum'
}).then(function (queryFun) {
var keys = ['1', '2'];
var opts = {
keys: keys,
group: false
};
return db.query(queryFun, opts).then(function (res) {
should.not.exist(res);
}).catch(function (err) {
err.status.should.equal(400);
opts = {keys: keys};
return db.query(queryFun, opts).then(function (res) {
should.not.exist(res);
}).catch(function (err) {
err.status.should.equal(400);
opts = {keys: keys, reduce : false};
return db.query(queryFun, opts).then(function () {
opts = {keys: keys, group: true};
return db.query(queryFun, opts);
});
});
});
});
});
});
it('should handle user errors in map functions', function () {
return new PouchDB(dbName).then(function (db) {
var err;
db.on('error', function (e) { err = e; });
return createView(db, {
map : function (doc) {
emit(doc.nonexistent.foo);
}
}).then(function (queryFun) {
return db.put({name : 'bar', _id : '1'}).then(function () {
return db.query(queryFun);
}).then(function (res) {
res.rows.should.have.length(0);
if (dbType === 'local') {
should.exist(err);
}
});
});
});
});
it('should handle user errors in reduce functions', function () {
return new PouchDB(dbName).then(function (db) {
var err;
db.on('error', function (e) { err = e; });
return createView(db, {
map : function (doc) {
emit(doc.name);
},
reduce : function (keys) {
return keys[0].foo.bar;
}
}).then(function (queryFun) {
return db.put({name : 'bar', _id : '1'}).then(function () {
return db.query(queryFun, {group: true});
}).then(function (res) {
res.rows.map(function (row) {return row.key; }).should.deep.equal(['bar']);
return db.query(queryFun, {reduce: false});
}).then(function (res) {
res.rows.map(function (row) {return row.key; }).should.deep.equal(['bar']);
if (dbType === 'local') {
should.exist(err);
}
});
});
});
});
it('should handle reduce returning undefined', function () {
return new PouchDB(dbName).then(function (db) {
var err;
db.on('error', function (e) { err = e; });
return createView(db, {
map : function (doc) {
emit(doc.name);
},
reduce : function () {
}
}).then(function (queryFun) {
return db.put({name : 'bar', _id : '1'}).then(function () {
return db.query(queryFun, {group: true});
}).then(function (res) {
res.rows.map(function (row) {return row.key; }).should.deep.equal(['bar']);
return db.query(queryFun, {reduce: false});
}).then(function (res) {
res.rows.map(function (row) {return row.key; }).should.deep.equal(['bar']);
should.not.exist(err);
});
});
});
});
it('should properly query custom reduce functions', function () {
return new PouchDB(dbName).then(function (db) {
return createView(db, {
map : function (doc) {
emit(doc.name, doc.count);
},
reduce : function (keys, values, rereduce) {
// calculate the average count per name
if (!rereduce) {
var result = {
sum : sum(values),
count : values.length
};
result.average = result.sum / result.count;
return result;
} else {
var thisSum = sum(values.map(function (value) {return value.sum; }));
var thisCount = sum(values.map(function (value) {return value.count; }));
return {
sum : thisSum,
count : thisCount,
average : (thisSum / thisCount)
};
}
}
}).then(function (queryFun) {
return db.bulkDocs({docs : [
{name : 'foo', count : 1},
{name : 'bar', count : 7},
{name : 'foo', count : 3},
{name : 'quux', count : 3},
{name : 'foo', count : 3},
{name : 'foo', count : 0},
{name : 'foo', count : 4},
{name : 'baz', count : 3},
{name : 'baz', count : 0},
{name : 'baz', count : 2}
]}).then(function () {
return db.query(queryFun, {group : true});
}).then(function (res) {
res.should.deep.equal({rows : [
{
key : 'bar',
value : { sum: 7, count: 1, average : 7}
},
{
key : 'baz',
value : { sum: 5, count: 3, average: (5 / 3) }
},
{
key : 'foo',
value : { sum: 11, count: 5, average: (11 / 5) }
},
{
key : 'quux',
value : { sum: 3, count: 1, average: 3 }
}
]}, 'all');
return db.query(queryFun, {group : false});
}).then(function (res) {
res.should.deep.equal({rows : [
{
key : null,
value : { sum: 26, count: 10, average: 2.6 }
}
]}, 'group=false');
return db.query(queryFun, {group : true, startkey : 'bar', endkey : 'baz', skip : 1});
}).then(function (res) {
res.should.deep.equal({rows : [
{
key : 'baz',
value : { sum: 5, count: 3, average: (5 / 3) }
}
]}, 'bar-baz skip 1');
return db.query(queryFun, {group : true, endkey : 'baz'});
}).then(function (res) {
res.should.deep.equal({rows : [
{
key : 'bar',
value : { sum: 7, count: 1, average : 7}
},
{
key : 'baz',
value : { sum: 5, count: 3, average: (5 / 3) }
}
]}, '-baz');
return db.query(queryFun, {group : true, startkey : 'foo'});
}).then(function (res) {
res.should.deep.equal({rows : [
{
key : 'foo',
value : { sum: 11, count: 5, average: (11 / 5) }
},
{
key : 'quux',
value : { sum: 3, count: 1, average: 3 }
}
]}, 'foo-');
return db.query(queryFun, {group : true, startkey : 'foo', descending : true});
}).then(function (res) {
res.should.deep.equal({rows : [
{
key : 'foo',
value : { sum: 11, count: 5, average: (11 / 5) }
},
{
key : 'baz',
value : { sum: 5, count: 3, average: (5 / 3) }
},
{
key : 'bar',
value : { sum: 7, count: 1, average : 7}
}
]}, 'foo- descending=true');
return db.query(queryFun, {group : true, startkey : 'quux', skip : 1});
}).then(function (res) {
res.should.deep.equal({rows : [
]}, 'quux skip 1');
return db.query(queryFun, {group : true, startkey : 'quux', limit : 0});
}).then(function (res) {
res.should.deep.equal({rows : [
]}, 'quux limit 0');
return db.query(queryFun, {group : true, startkey : 'bar', endkey : 'baz'});
}).then(function (res) {
res.should.deep.equal({rows : [
{
key : 'bar',
value : { sum: 7, count: 1, average : 7}
},
{
key : 'baz',
value : { sum: 5, count: 3, average: (5 / 3) }
}
]}, 'bar-baz');
return db.query(queryFun, {group : true, keys : ['bar', 'baz'], limit : 1});
}).then(function (res) {
res.should.deep.equal({rows : [
{
key : 'bar',
value : { sum: 7, count: 1, average : 7}
}
]}, 'bar & baz');
return db.query(queryFun, {group : true, keys : ['bar', 'baz'], limit : 0});
}).then(function (res) {
res.should.deep.equal({rows : [
]}, 'bar & baz limit 0');
return db.query(queryFun, {group : true, key : 'bar', limit : 0});
}).then(function (res) {
res.should.deep.equal({rows : [
]}, 'key=bar limit 0');
return db.query(queryFun, {group : true, key : 'bar'});
}).then(function (res) {
res.should.deep.equal({rows : [
{
key : 'bar',
value : { sum: 7, count: 1, average : 7}
}
]}, 'key=bar');
return db.query(queryFun, {group : true, key : 'zork'});
}).then(function (res) {
res.should.deep.equal({rows : [
]}, 'zork');
return db.query(queryFun, {group : true, keys : []});
}).then(function (res) {
res.should.deep.equal({rows : [
]}, 'keys=[]');
return db.query(queryFun, {group : true, key : null});
}).then(function (res) {
res.should.deep.equal({rows : [
]}, 'key=null');
});
});
});
});
it.skip('should handle many doc changes', function () {
var docs = [{_id: '0'}, {_id : '1'}, {_id: '2'}];
var keySets = [
[1],
[2, 3],
[4],
[5],
[6, 7, 3],
[],
[2, 3],
[1, 2],
[],
[9],
[9, 3, 2, 1]
];
return new PouchDB(dbName).then(function (db) {
return createView(db, {
map : function (doc) {
doc.keys.forEach(function (key) {
emit(key);
});
}
}).then(function (mapFun) {
return db.bulkDocs({docs : docs}).then(function () {
var tasks = keySets.map(function (keys, i) {
return function () {
var expectedResponseKeys = [];
return db.allDocs({
keys : ['0', '1', '2'],
include_docs: true
}).then(function (res) {
docs = res.rows.map(function (x) { return x.doc; });
docs.forEach(function (doc, j) {
doc.keys = keySets[(i + j) % keySets.length];
doc.keys.forEach(function (key) {
expectedResponseKeys.push(key);
});
});
expectedResponseKeys.sort();
return db.bulkDocs({docs: docs});
}).then(function () {
return db.query(mapFun);
}).then(function (res) {
var actualKeys = res.rows.map(function (x) {
return x.key;
});
actualKeys.should.deep.equal(expectedResponseKeys);
});
};
});
var chain = tasks.shift()();
function getNext() {
var task = tasks.shift();
return task && function () {
return task().then(getNext());
};
}
return chain.then(getNext());
});
});
});
});
it('should handle many doc changes', function () {
var docs = [{_id: '0'}, {_id : '1'}, {_id: '2'}];
var keySets = [
[1],
[2, 3],
[4],
[5],
[6, 7, 3],
[],
[2, 3],
[1, 2],
[],
[9],
[9, 3, 2, 1]
];
return new PouchDB(dbName).then(function (db) {
return createView(db, {
map : function (doc) {
doc.keys.forEach(function (key) {
emit(key);
});
}
}).then(function (mapFun) {
return db.bulkDocs({docs : docs}).then(function () {
var tasks = keySets.map(function (keys, i) {
return function () {
var expectedResponseKeys = [];
return db.allDocs({
keys : ['0', '1', '2'],
include_docs: true
}).then(function (res) {
docs = res.rows.map(function (x) { return x.doc; });
docs.forEach(function (doc, j) {
doc.keys = keySets[(i + j) % keySets.length];
doc.keys.forEach(function (key) {
expectedResponseKeys.push(key);
});
});
expectedResponseKeys.sort(function (a, b) {
return a - b;
});
return db.bulkDocs({docs: docs});
}).then(function () {
return db.query(mapFun);
}).then(function (res) {
var actualKeys = res.rows.map(function (x) {
return x.key;
});
actualKeys.should.deep.equal(expectedResponseKeys);
});
};
});
function getNext() {
var task = tasks.shift();
if (task) {
return task().then(getNext);
}
}
return getNext();
});
});
});
});
it('should work with post', function () {
return new PouchDB(dbName).then(function (db) {
return createView(db, {
map : function (doc) { emit(doc._id); }.toString()
}).then(function (mapFun) {
return db.bulkDocs({docs: [{_id : 'bazbazbazb'}]}).then(function () {
var i = 300;
var keys = [];
while (i--) {
keys.push('bazbazbazb');
}
return db.query(mapFun, {keys: keys}).then(function (resp) {
resp.total_rows.should.equal(1);
resp.rows.should.have.length(300);
return resp.rows.every(function (row) {
return row.id === 'bazbazbazb' && row.key === 'bazbazbazb';
});
});
}).should.become(true);
});
});
});
it("should accept trailing ';' in a map definition (#178)", function () {
return new PouchDB(dbName).then(function (db) {
return createView(db, {
map: "function(doc){};\n"
}).then(function (queryFun) {
return db.query(queryFun);
}).should.become({
offset: 0,
rows: [],
total_rows: 0
});
});
});
it('should throw a 404 when no funcs found in ddoc (#181)', function () {
return new PouchDB(dbName).then(function (db) {
return db.put({
_id: '_design/test'
}).then(function () {
return db.query('test/unexisting');
}).then(function () {
//shouldn't happen
true.should.equal(false);
}).catch(function (err) {
err.status.should.equal(404);
});
});
});
it.skip('should continue indexing when map eval fails (#214)', function () {
return new PouchDB(dbName).then(function (db) {
var err;
db.on('error', function (e) {
err = e;
});
return createView(db, {
map: function (doc) {
emit(doc.foo.bar, doc);
}
}).then(function (view) {
return db.bulkDocs({docs: [
{
foo: {
bar: "foobar"
}
},
{ notfoo: "thisWillThrow" },
{
foo: {
bar: "otherFoobar"
}
}
]}).then(function () {
return db.query(view);
}).then(function (res) {
if (dbType === 'local') {
should.exist(err);
}
res.rows.should.have.length(2, 'Ignore the wrongly formatted doc');
return db.query(view);
}).then(function (res) {
res.rows.should.have.length(2, 'Ignore the wrongly formatted doc');
});
});
});
});
it.skip('should continue indexing when map eval fails, ' +
'even without a listener (#214)', function () {
return new PouchDB(dbName).then(function (db) {
return createView(db, {
map: function (doc) {
emit(doc.foo.bar, doc);
}
}).then(function (view) {
return db.bulkDocs({docs: [
{
foo: {
bar: "foobar"
}
},
{ notfoo: "thisWillThrow" },
{
foo: {
bar: "otherFoobar"
}
}
]}).then(function () {
return db.query(view);
}).then(function (res) {
res.rows.should.have.length(2, 'Ignore the wrongly formatted doc');
return db.query(view);
}).then(function (res) {
res.rows.should.have.length(2, 'Ignore the wrongly formatted doc');
});
});
});
});
it.skip('should update the emitted value', function () {
return new PouchDB(dbName).then(function (db) {
var docs = [];
for (var i = 0; i < 300; i++) {
docs.push({
_id: i.toString(),
name: 'foo',
count: 1
});
}
return createView(db, {
map: "function(doc){emit(doc.name, doc.count);};\n"
}).then(function (queryFun) {
return db.bulkDocs({docs: docs}).then(function (res) {
for (var i = 0; i < res.length; i++) {
docs[i]._rev = res[i].rev;
}
return db.query(queryFun);
}).then(function (res) {
var values = res.rows.map(function (x) { return x.value; });
values.should.have.length(docs.length);
values[0].should.equal(1);
docs.forEach(function (doc) {
doc.count = 2;
});
return db.bulkDocs({docs: docs});
}).then(function () {
return db.query(queryFun);
}).then(function (res) {
var values = res.rows.map(function (x) { return x.value; });
values.should.have.length(docs.length);
values[0].should.equal(2);
});
});
});
});
});
}