New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

pouchdb-mapreduce

Package Overview
Dependencies
Maintainers
1
Versions
62
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

pouchdb-mapreduce - npm Package Compare versions

Comparing version

to
0.4.0

.jshintrc

363

index.js

@@ -1,7 +0,5 @@

/*global Pouch: true, pouchCollate: true */
'use strict';
"use strict";
var pouchCollate = require('pouchdb-collate');
var Promise = require('lie');
// This is the first implementation of a basic plugin, we register the

@@ -19,32 +17,105 @@ // plugin object with pouch and it is mixin'd to each database created

function MapReduce(db) {
if(!(this instanceof MapReduce)){
return new MapReduce(db);
function normalize(key) {
// couch considers null === undefined for the purposes of mapreduce indexes
return typeof key === 'undefined' ? null : key;
}
function MapReduceError(name, msg, code) {
this.name = name;
this.message = msg;
this.status = code;
}
MapReduceError.prototype = new Error();
function createKeysLookup(keys) {
// creates a lookup map for the given keys, so that doing
// query() with keys doesn't become an O(n * m) operation
// lookup values are typically integer indexes, but may
// map to a list of integers, since keys can be duplicated
var lookup = {};
for (var i = 0, len = keys.length; i < len; i++) {
var key = normalize(keys[i]);
var val = lookup[key];
if (typeof val === 'undefined') {
lookup[key] = i;
} else if (typeof val === 'number') {
lookup[key] = [val, i];
} else { // array
val.push(i);
}
}
function normalize(key) {
// couch considers null === undefined for the purposes of mapreduce indexes
return typeof key === 'undefined' ? null : key;
return lookup;
}
function sortByIdAndValue(a, b) {
// sort by id, then value
var idCompare = pouchCollate(a.id, b.id);
return idCompare !== 0 ? idCompare : pouchCollate(a.value, b.value);
}
function addAtIndex(idx, result, prelimResults) {
var val = prelimResults[idx];
if (typeof val === 'undefined') {
prelimResults[idx] = result;
} else if (!Array.isArray(val)) {
// same key for multiple docs, need to preserve document order, so create array
prelimResults[idx] = [val, result];
} else { // existing array
val.push(result);
}
}
function createKeysLookup(keys) {
// creates a lookup map for the given keys, so that doing
// query() with keys doesn't become an O(n * m) operation
// lookup values are typically integer indexes, but may
// map to a list of integers, since keys can be duplicated
var lookup = {};
function sum(values) {
return values.reduce(function (a, b) {
return a + b;
}, 0);
}
for (var i = 0, len = keys.length; i < len; i++) {
var key = normalize(keys[i]);
var val = lookup[key];
if (typeof val === 'undefined') {
lookup[key] = i;
} else if (typeof val === 'number') {
lookup[key] = [val, i];
} else { // array
val.push(i);
}
var builtInReduce = {
"_sum": function (keys, values) {
return sum(values);
},
"_count": function (keys, values, rereduce) {
return values.length;
},
"_stats": function (keys, values) {
return {
'sum': sum(values),
'min': Math.min.apply(null, values),
'max': Math.max.apply(null, values),
'count': values.length,
'sumsqr': (function () {
var _sumsqr = 0;
for (var idx in values) {
if (typeof values[idx] === 'number') {
_sumsqr += values[idx] * values[idx];
} else {
return new MapReduceError(
'builtin _stats function requires map values to be numbers',
'invalid_value',
500
);
}
}
return _sumsqr;
})()
};
}
};
function addHttpParam(paramName, opts, params, asJson) {
// add an http param from opts to params, optionally json-encoded
var val = opts[paramName];
if (typeof val !== 'undefined') {
if (asJson) {
val = encodeURIComponent(JSON.stringify(val));
}
params.push(paramName + '=' + val);
}
}
return lookup;
function MapReduce(db) {
if (!(this instanceof MapReduce)) {
return new MapReduce(db);
}

@@ -61,21 +132,9 @@

function addAtIndex(idx, result) {
var val = prelimResults[idx];
if (typeof val === 'undefined') {
prelimResults[idx] = result;
} else if (!Array.isArray(val)) {
// same key for multiple docs, need to preserve document order, so create array
prelimResults[idx] = [val, result];
} else { // existing array
val.push(result);
}
}
inputResults.forEach(function(result) {
inputResults.forEach(function (result) {
var idx = keysLookup[normalize(result.key)];
if (typeof idx === 'number') {
addAtIndex(idx, result);
addAtIndex(idx, result, prelimResults);
} else { // array of indices
idx.forEach(function(subIdx) {
addAtIndex(subIdx, result);
idx.forEach(function (subIdx) {
addAtIndex(subIdx, result, prelimResults);
});

@@ -85,15 +144,9 @@ }

function sortById(a, b) {
return pouchCollate(a.id, b.id);
}
// flatten the array, remove nulls, sort by doc ids
var outputResults = [];
prelimResults.forEach(function(result) {
if (typeof result !== 'undefined') {
if (Array.isArray(result)) {
outputResults = outputResults.concat(result.sort(sortById));
} else { // single result
outputResults.push(result);
}
prelimResults.forEach(function (result) {
if (Array.isArray(result)) {
outputResults = outputResults.concat(result.sort(sortByIdAndValue));
} else { // single result
outputResults.push(result);
}

@@ -105,42 +158,4 @@ });

function sum(values) {
return values.reduce(function (a, b) { return a + b; }, 0);
}
var builtInReduce = {
"_sum": function (keys, values){
return sum(values);
},
"_count": function (keys, values, rereduce){
if (rereduce){
return sum(values);
} else {
return values.length;
}
},
"_stats": function (keys, values, rereduce) {
return {
'sum': sum(values),
'min': Math.min.apply(null, values),
'max': Math.max.apply(null, values),
'count': values.length,
'sumsqr': (function () {
var _sumsqr = 0;
for(var idx in values) {
if (typeof values[idx] === 'number') {
_sumsqr += values[idx] * values[idx];
}
}
return _sumsqr;
})()
};
}
};
function viewQuery(fun, options) {
if (!options.complete) {
return;
}
/*jshint evil: true */

@@ -168,5 +183,11 @@ if (!options.skip) {

if (typeof options.startkey !== 'undefined' && pouchCollate(key, options.startkey) < 0) return;
if (typeof options.endkey !== 'undefined' && pouchCollate(key, options.endkey) > 0) return;
if (typeof options.key !== 'undefined' && pouchCollate(key, options.key) !== 0) return;
if (typeof options.startkey !== 'undefined' && pouchCollate(key, options.startkey) < 0) {
return;
}
if (typeof options.endkey !== 'undefined' && pouchCollate(key, options.endkey) > 0) {
return;
}
if (typeof options.key !== 'undefined' && pouchCollate(key, options.key) !== 0) {
return;
}
if (typeof options.keys !== 'undefined') {

@@ -182,11 +203,11 @@ keysLookup = keysLookup || createKeysLookup(options.keys);

//in this special case, join on _id (issue #106)
if (val && typeof val === 'object' && val._id){
if (val && typeof val === 'object' && val._id) {
db.get(val._id,
function (_, joined_doc){
if (joined_doc) {
viewRow.doc = joined_doc;
}
results.push(viewRow);
checkComplete();
});
function (_, joined_doc) {
if (joined_doc) {
viewRow.doc = joined_doc;
}
results.push(viewRow);
checkComplete();
});
return;

@@ -198,6 +219,6 @@ } else {

results.push(viewRow);
};
}
// ugly way to make sure references to 'emit' in map/reduce bind to the
// above emit
eval('fun.map = ' + fun.map.toString() + ';');

@@ -207,5 +228,5 @@ if (fun.reduce) {

fun.reduce = builtInReduce[fun.reduce];
} else {
eval('fun.reduce = ' + fun.reduce.toString() + ';');
}
eval('fun.reduce = ' + fun.reduce.toString() + ';');
}

@@ -215,6 +236,7 @@

function checkComplete() {
if (completed && results.length == num_started){
var error;
if (completed && results.length === num_started) {
if (typeof options.keys !== 'undefined' && results.length) { // user supplied a keys param, sort by keys
keysLookup = keysLookup || createKeysLookup(options.keys);
if (typeof options.keys !== 'undefined' && results.length) {
// user supplied a keys param, sort by keys
results = mapUsingKeys(results, options.keys, keysLookup);

@@ -242,3 +264,3 @@ } else { // normal sorting

results.forEach(function (e) {
var last = groups[groups.length-1] || null;
var last = groups[groups.length - 1];
if (last && pouchCollate(last.key[0][0], e.key) === 0) {

@@ -249,10 +271,18 @@ last.key.push([e.key, e.id]);

}
groups.push({key: [[e.key, e.id]], value: [e.value]});
groups.push({key: [
[e.key, e.id]
], value: [e.value]});
});
groups.forEach(function (e) {
e.value = fun.reduce(e.key, e.value);
e.value = (typeof e.value === 'undefined') ? null : e.value;
if (e.value.sumsqr && e.value.sumsqr instanceof MapReduceError) {
error = e.value;
return;
}
e.key = e.key[0][0];
});
if (error) {
options.complete(error);
return;
}
options.complete(null, {

@@ -265,3 +295,3 @@ total_rows: groups.length,

}
};
}

@@ -272,3 +302,3 @@ db.changes({

onChange: function (doc) {
if (!('deleted' in doc)) {
if (!('deleted' in doc) && doc.id[0] !== "_") {
current = {doc: doc.doc};

@@ -279,3 +309,3 @@ fun.map.call(this, doc.doc);

complete: function () {
completed= true;
completed = true;
checkComplete();

@@ -286,18 +316,8 @@ }

function addHttpParam(paramName, opts, params, asJson) {
// add an http param from opts to params, optionally json-encoded
var val = opts[paramName];
if (typeof val !== 'undefined') {
if (asJson) {
val = encodeURIComponent(JSON.stringify(val));
}
params.push(paramName + '=' + val);
}
}
function httpQuery(fun, opts) {
var callback = opts.complete;
function httpQuery(fun, opts, callback) {
// List of parameters to add to the PUT request
var params = [];
var body = undefined;
var body;
var method = 'GET';

@@ -325,3 +345,3 @@

if (typeof fun === 'string') {
body = JSON.stringify({keys:opts.keys});
body = JSON.stringify({keys: opts.keys});
} else { // fun is {map : mapfun}, so append to this

@@ -356,3 +376,3 @@ fun.keys = opts.keys;

db.request({
method:'POST',
method: 'POST',
url: '_temp_view' + params,

@@ -363,3 +383,3 @@ body: queryObject

this.query = function(fun, opts, callback) {
this.query = function (fun, opts, callback) {
if (typeof opts === 'function') {

@@ -373,41 +393,56 @@ callback = opts;

}
var realCB = opts.complete;
var promise = new Promise(function (resolve, reject) {
opts.complete = function (err, data) {
if (err) {
reject(err);
} else {
resolve(data);
}
};
if (db.type() === 'http') {
if (typeof fun === 'function'){
return httpQuery({map: fun}, opts, callback);
}
return httpQuery(fun, opts, callback);
}
if (db.type() === 'http') {
if (typeof fun === 'function') {
return httpQuery({map: fun}, opts);
}
return httpQuery(fun, opts);
}
if (typeof fun === 'object') {
return viewQuery(fun, opts);
}
if (typeof fun === 'function') {
return viewQuery({map: fun}, opts);
}
var parts = fun.split('/');
db.get('_design/' + parts[0], function (err, doc) {
if (err) {
if (callback) callback(err);
return;
if (typeof fun === 'object') {
return viewQuery(fun, opts);
}
if (!doc.views[parts[1]]) {
if (callback) callback({ name: 'not_found', message: 'missing_named_view' });
return;
if (typeof fun === 'function') {
return viewQuery({map: fun}, opts);
}
viewQuery({
map: doc.views[parts[1]].map,
reduce: doc.views[parts[1]].reduce
}, opts);
var parts = fun.split('/');
db.get('_design/' + parts[0], function (err, doc) {
if (err) {
opts.complete(err);
return;
}
if (!doc.views[parts[1]]) {
opts.complete({ name: 'not_found', message: 'missing_named_view' });
return;
}
viewQuery({
map: doc.views[parts[1]].map,
reduce: doc.views[parts[1]].reduce
}, opts);
});
});
}
if (realCB) {
promise.then(function (resp) {
realCB(null, resp);
}, realCB);
}
return promise;
};
}
// Deletion is a noop since we dont store the results of the view
MapReduce._delete = function () {
};
// Deletion is a noop since we dont store the results of the view
MapReduce._delete = function () { };
module.exports = MapReduce;
{
"name": "pouchdb-mapreduce",
"version": "0.3.2",
"version": "0.4.0",
"description": "Map Reduce =====",

@@ -11,3 +11,3 @@ "main": "index.js",

"scripts": {
"test": "./node_modules/istanbul/lib/cli.js test ./node_modules/mocha/bin/_mocha test/test.js -- testDB http://localhost:5984/cwmtestdb",
"test": "./node_modules/.bin/jshint -c .jshintrc *.js test/*.js && ./node_modules/istanbul/lib/cli.js test ./node_modules/mocha/bin/_mocha test/test.js -- testDB http://localhost:5984/cwmtestdb",
"build": "mkdir -p dist && browserify index.js -s mapReduce -o dist/pouchdb-mapreduce.js"

@@ -28,3 +28,4 @@ },

"dependencies": {
"pouchdb-collate": "~0.2.0"
"pouchdb-collate": "~0.2.0",
"lie": "~2.5.1"
},

@@ -36,4 +37,8 @@ "devDependencies": {

"pouchdb": "~1.1.0",
"browserify": "~2.36.0"
"browserify": "~2.36.0",
"jshint": "~2.3.0",
"mocha-as-promised": "~2.0.0",
"chai-as-promised": "~4.1.0",
"lie-denodify": "~0.1.2"
}
}

@@ -1,38 +0,50 @@

var Pouch = require('pouchdb');
'use strict';
var pouch = require('pouchdb');
var Mapreduce = require('../');
Pouch.plugin('mapreduce',Mapreduce);
var should = require('chai').should();
describe('local',function(){
pouch.plugin('mapreduce', Mapreduce);
var chai = require('chai');
var should = chai.should();
require("mocha-as-promised")();
chai.use(require("chai-as-promised"));
var denodify = require('lie-denodify');
describe('local', function () {
process.argv.slice(3).forEach(tests);
});
function tests(dbName){
beforeEach(function(done){
Pouch(dbName,function(err,d){
var pouchPromise = denodify(pouch);
function tests(dbName) {
beforeEach(function (done) {
pouch(dbName, function (err, d) {
done();
})
});
});
afterEach(function(done){
Pouch.destroy(dbName,function(){
done();
});
afterEach(function (done) {
pouch.destroy(dbName, function () {
done();
});
});
describe('views',function(){
it("Test basic view", function(done) {
Pouch(dbName, function(err, db) {
db.bulkDocs({docs: [{foo: 'bar'}, { _id: 'volatile', foo: 'baz' }]}, {}, function() {
describe('views', function () {
it("Test basic view", function (done) {
pouch(dbName, function (err, db) {
db.bulkDocs({docs: [
{foo: 'bar'},
{ _id: 'volatile', foo: 'baz' }
]}, {}, function () {
var queryFun = {
map: function(doc) { emit(doc.foo, doc); }
map: function (doc) {
emit(doc.foo, doc);
}
};
db.get('volatile', function(_, doc) {
db.remove(doc, function(_, resp) {
db.query(queryFun, {include_docs: true, reduce: false}, function(_, res) {
db.get('volatile', function (_, doc) {
db.remove(doc, function (_, resp) {
db.query(queryFun, {include_docs: true, reduce: false}, 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, i) {
x.id.should.exist;
x.key.should.exist;
x.value.should.exist;
x.value._rev.should.exist;
x.doc.should.exist;
x.doc._rev.should.exist;
res.rows.forEach(function (x, i) {
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);
});

@@ -47,20 +59,25 @@ done();

it("Test passing just a function", function(done) {
Pouch(dbName, function(err, db) {
db.bulkDocs({docs: [{foo: 'bar'}, { _id: 'volatile', foo: 'baz' }]}, {}, function() {
var queryFun = function(doc) { emit(doc.foo, doc); };
db.get('volatile', function(_, doc) {
db.remove(doc, function(_, resp) {
db.query(queryFun, {include_docs: true, reduce: false}, function(_, res) {
it("Test passing just a function", function (done) {
pouch(dbName, function (err, db) {
db.bulkDocs({docs: [
{foo: 'bar'},
{ _id: 'volatile', foo: 'baz' }
]}, {}, function () {
var queryFun = function (doc) {
emit(doc.foo, doc);
};
db.get('volatile', function (_, doc) {
db.remove(doc, function (_, resp) {
db.query(queryFun, {include_docs: true, reduce: false, complete: function (_, res) {
res.rows.should.have.length(1, 'Dont include deleted documents');
res.rows.forEach(function(x, i) {
x.id.should.exist;
x.key.should.exist;
x.value.should.exist;
x.value._rev.should.exist;
x.doc.should.exist;
x.doc._rev.should.exist;
res.rows.forEach(function (x, i) {
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);
});
done();
});
}});
});

@@ -72,15 +89,31 @@ });

it("Test opts.startkey/opts.endkey", function(done) {
Pouch(dbName, function(err, db) {
db.bulkDocs({docs: [{key: 'key1'},{key: 'key2'},{key: 'key3'},{key: 'key4'},{key: 'key5'}]}, {}, function() {
it("Test opts.startkey/opts.endkey", function (done) {
pouch(dbName, function (err, db) {
db.bulkDocs({docs: [
{key: 'key1'},
{key: 'key2'},
{key: 'key3'},
{key: 'key4'},
{key: 'key5'}
]}, {}, function () {
var queryFun = {
map: function(doc) { emit(doc.key, doc); }
map: function (doc) {
emit(doc.key, doc);
}
};
db.query(queryFun, {reduce: false, startkey: 'key2'}, function(_, res) {
db.query(queryFun, {reduce: false, startkey: 'key2'}, function (_, res) {
res.rows.should.have.length(4, 'Startkey is inclusive');
db.query(queryFun, {reduce: false, endkey: 'key3'}, function(_, res) {
db.query(queryFun, {reduce: false, endkey: 'key3'}, function (_, res) {
res.rows.should.have.length(3, 'Endkey is inclusive');
db.query(queryFun, {reduce: false, startkey: 'key2', endkey: 'key3'}, function(_, res) {
db.query(queryFun, {
reduce: false,
startkey: 'key2',
endkey: 'key3'
}, function (_, res) {
res.rows.should.have.length(2, 'Startkey and endkey together');
db.query(queryFun, {reduce: false, startkey: 'key4', endkey: 'key4'}, function(_, res) {
db.query(queryFun, {
reduce: false,
startkey: 'key4',
endkey: 'key4'
}, function (_, res) {
res.rows.should.have.length(1, 'Startkey=endkey');

@@ -96,11 +129,18 @@ done();

it("Test opts.key", function(done) {
Pouch(dbName, function(err, db) {
db.bulkDocs({docs: [{key: 'key1'},{key: 'key2'},{key: 'key3'},{key: 'key3'}]}, {}, function() {
it("Test opts.key", function (done) {
pouch(dbName, function (err, db) {
db.bulkDocs({docs: [
{key: 'key1'},
{key: 'key2'},
{key: 'key3'},
{key: 'key3'}
]}, {}, function () {
var queryFun = {
map: function(doc) { emit(doc.key, doc); }
map: function (doc) {
emit(doc.key, doc);
}
};
db.query(queryFun, {reduce: false, key: 'key2'}, function(_, res) {
db.query(queryFun, {reduce: false, key: 'key2'}, function (_, res) {
res.rows.should.have.length(1, 'Doc with key');
db.query(queryFun, {reduce: false, key: 'key3'}, function(_, res) {
db.query(queryFun, {reduce: false, key: 'key3'}, function (_, res) {
res.rows.should.have.length(2, 'Multiple docs with key');

@@ -114,3 +154,3 @@ done();

it("Test basic view collation", function(done) {
it("Test basic view collation", function (done) {

@@ -144,14 +184,14 @@ var values = [];

values.push(["b"]);
values.push(["b","c"]);
values.push(["b","c", "a"]);
values.push(["b","d"]);
values.push(["b","d", "e"]);
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.
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

@@ -161,20 +201,22 @@ // but doesn't require that clients will.

// that doesn't preserve order)
values.push({b:2, c:2});
values.push({b: 2, c: 2});
Pouch(dbName, function(err, db) {
var docs = values.map(function(x, i) {
pouch(dbName, function (err, db) {
var docs = values.map(function (x, i) {
return {_id: (i).toString(), foo: x};
});
db.bulkDocs({docs: docs}, {}, function() {
db.bulkDocs({docs: docs}, {}, function () {
var queryFun = {
map: function(doc) { emit(doc.foo, null); }
map: function (doc) {
emit(doc.foo);
}
};
db.query(queryFun, {reduce: false}, function(_, res) {
res.rows.forEach(function(x, i) {
db.query(queryFun, {reduce: false}, function (_, res) {
res.rows.forEach(function (x, i) {
JSON.stringify(x.key).should.equal(JSON.stringify(values[i]), 'keys collate');
});
db.query(queryFun, {descending: true, reduce: false}, function(_, res) {
res.rows.forEach(function(x, i) {
db.query(queryFun, {descending: true, reduce: false}, function (_, res) {
res.rows.forEach(function (x, i) {
JSON.stringify(x.key).should.equal(JSON.stringify(values[values.length - 1 - i]),
'keys collate descending');
'keys collate descending');
});

@@ -188,7 +230,10 @@ done();

it("Test joins", function(done) {
Pouch(dbName, function(err, db) {
db.bulkDocs({docs: [{_id: 'mydoc', foo: 'bar'}, { doc_id: 'mydoc' }]}, {}, function() {
it("Test joins", function (done) {
pouch(dbName, function (err, db) {
db.bulkDocs({docs: [
{_id: 'mydoc', foo: 'bar'},
{ doc_id: 'mydoc' }
]}, {}, function () {
var queryFun = {
map: function(doc) {
map: function (doc) {
if (doc.doc_id) {

@@ -199,4 +244,4 @@ emit(doc._id, {_id: doc.doc_id});

};
db.query(queryFun, {include_docs: true, reduce: false}, function(_, res) {
res.rows[0].doc.should.exist;
db.query(queryFun, {include_docs: true, reduce: false}, function (_, res) {
should.exist(res.rows[0].doc);
res.rows[0].doc._id.should.equal('mydoc', 'mydoc included');

@@ -209,11 +254,11 @@ done();

it("No reduce function", function(done) {
Pouch(dbName, function(err, db) {
db.post({foo: 'bar'}, function(err, res) {
it("No reduce function", function (done) {
pouch(dbName, function (err, db) {
db.post({foo: 'bar'}, function (err, res) {
var queryFun = {
map: function(doc) {
map: function (doc) {
emit('key', 'val');
}
};
db.query(queryFun, function(err, res) {
db.query(queryFun, function (err, res) {
done();

@@ -225,4 +270,4 @@ });

it("Built in _sum reduce function", function(done) {
Pouch(dbName, function(err, db) {
it("Built in _sum reduce function", function (done) {
pouch(dbName, function (err, db) {
db.bulkDocs({

@@ -234,5 +279,5 @@ docs: [

]
}, null, function() {
}, function () {
var queryFun = {
map: function(doc) {
map: function (doc) {
emit(doc.val, 1);

@@ -242,3 +287,3 @@ },

};
db.query(queryFun, {reduce: true, group_level:999}, function(err, res) {
db.query(queryFun, {reduce: true, group_level: 999}, function (err, res) {
res.rows.should.have.length(2);

@@ -253,4 +298,28 @@ res.rows[0].value.should.equal(2);

it("Built in _count reduce function", function(done) {
Pouch(dbName, function(err, db) {
it("Built in _sum reduce function with a promsie", function () {
return pouchPromise(dbName).then(function (db) {
return denodify(db.bulkDocs)({
docs: [
{ val: 'bar' },
{ val: 'bar' },
{ val: 'baz' }
]
}).then(function () {
var queryFun = {
map: function (doc) {
emit(doc.val, 1);
},
reduce: "_sum"
};
return db.query(queryFun, {reduce: true, group_level: 999}).then(function (res) {
return res.rows.map(function (v) {
return v.value;
});
});
});
}).should.become([2, 1]);
});
it("Built in _count reduce function", function (done) {
pouch(dbName, function (err, db) {
db.bulkDocs({

@@ -262,5 +331,5 @@ docs: [

]
}, null, function() {
}, function () {
var queryFun = {
map: function(doc) {
map: function (doc) {
emit(doc.val, doc.val);

@@ -270,3 +339,3 @@ },

};
db.query(queryFun, {reduce: true, group_level:999}, function(err, res) {
db.query(queryFun, {reduce: true, group_level: 999}, function (err, res) {
res.rows.should.have.length(2);

@@ -281,4 +350,4 @@ res.rows[0].value.should.equal(2);

it("Built in _stats reduce function", function(done) {
Pouch(dbName, function(err, db) {
it("Built in _stats reduce function", function (done) {
pouch(dbName, function (err, db) {
db.bulkDocs({

@@ -288,12 +357,15 @@ docs: [

{ val: 'bar' },
{ val: 'baz' }
{ val: 'baz' },
{
_id: "_design/test",
views: {
thing: {
map: "function(doc){emit(doc.val, 1);}",
reduce: "_stats"
}
}
}
]
}, null, function() {
var queryFun = {
map: function(doc) {
emit(doc.val, 1);
},
reduce: "_stats"
};
db.query(queryFun, {reduce: true, group_level:999}, function(err, res) {
}, function (err) {
db.query("test/thing", {reduce: true, group_level: 999}, function (err, res) {
var stats = res.rows[0].value;

@@ -311,7 +383,32 @@ stats.sum.should.equal(2);

it("No reduce function, passing just a function", function(done) {
Pouch(dbName, function(err, db) {
db.post({foo: 'bar'}, function(err, res) {
var queryFun = function(doc) { emit('key', 'val'); };
db.query(queryFun, function(err, res) {
it("Built in _stats reduce function should throw an error with a promise", function (done) {
return pouchPromise(dbName).then(function (db) {
return denodify(db.bulkDocs)({
docs: [
{ val: 'bar' },
{ val: 'bar' },
{ val: 'baz' },
{
_id: "_design/test",
views: {
thing: {
map: "function(doc){emit(doc.val, 'lala');}",
reduce: "_stats"
}
}
}
]
}).then(function () {
return db.query("test/thing", {reduce: true, group_level: 999});
});
}).should.be.rejected;
});
it("No reduce function, passing just a function", function (done) {
pouch(dbName, function (err, db) {
db.post({foo: 'bar'}, function (err, res) {
var queryFun = function (doc) {
emit('key', 'val');
};
db.query(queryFun, function (err, res) {
done();

@@ -324,17 +421,22 @@ });

it('Views should include _conflicts', function(done) {
it('Views should include _conflicts', function (done) {
var self = this;
var doc1 = {_id: '1', foo: 'bar'};
var doc2 = {_id: '1', foo: 'baz'};
var queryFun = function(doc) { emit(doc._id, !!doc._conflicts); };
Pouch(dbName,function(err,db){
Pouch('testdb2', function(err, remote) {
db.post(doc1, function(err, res) {
remote.post(doc2, function(err, res) {
db.replicate.from(remote, function(err, res) {
db.get(doc1._id, {conflicts: true}, function(err, res) {
res._conflicts.should.exist;
db.query(queryFun, function(err, res) {
res.rows[0].value.should.exist;
Pouch.destroy('testdb2',function(){done();});
var queryFun = function (doc) {
emit(doc._id, !!doc._conflicts);
};
pouch(dbName, function (err, db) {
pouch('testdb2', function (err, remote) {
db.post(doc1, function (err, res) {
remote.post(doc2, function (err, res) {
db.replicate.from(remote, function (err, res) {
db.get(doc1._id, {conflicts: true}, function (err, res) {
should.exist(res._conflicts);
db.query(queryFun, function (err, res) {
should.exist(res.rows[0].value);
pouch.destroy('testdb2', function () {
done();
});
});
});

@@ -346,6 +448,6 @@ });

});
});});
});
it("Test view querying with limit option", function(done) {
Pouch(dbName, function(err, db) {
it("Test view querying with limit option", function (done) {
pouch(dbName, function (err, db) {
db.bulkDocs({

@@ -357,3 +459,3 @@ docs: [

]
}, null, function() {
}, function () {

@@ -373,5 +475,55 @@ db.query(function (doc) {

});
it("Test view querying with limit option and reduce", function (done) {
pouch(dbName, function (err, db) {
db.bulkDocs({
docs: [
{ foo: 'bar' },
{ foo: 'bar' },
{ foo: 'baz' }
]
}, function () {
it("Query non existing view returns error", function(done) {
Pouch(dbName, function(err, db) {
db.query({
map: function (doc) {
emit(doc.foo);
},
reduce: '_count'
}, { limit: 1, group: true, reduce: true}, function (err, 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);
done();
});
});
});
});
it("Test view querying with a skip option and reduce", function (done) {
pouch(dbName, function (err, db) {
db.bulkDocs({
docs: [
{ foo: 'bar' },
{ foo: 'bar' },
{ foo: 'baz' }
]
}, function () {
db.query({
map: function (doc) {
emit(doc.foo);
},
reduce: '_count'
}, {skip: 1, group: true, reduce: true}, function (err, 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);
done();
});
});
});
});
it("Query non existing view returns error", function (done) {
pouch(dbName, function (err, db) {
var doc = {

@@ -386,3 +538,3 @@ _id: '_design/barbar',

db.post(doc, function (err, info) {
db.query('barbar/dontExist',{key: 'bar'}, function(err, res) {
db.query('barbar/dontExist', {key: 'bar'}, function (err, res) {
err.name.should.equal('not_found');

@@ -396,4 +548,4 @@ err.message.should.equal('missing_named_view');

it("Special document member _doc_id_rev should never leak outside", function(done) {
Pouch(dbName, function(err, db) {
it("Special document member _doc_id_rev should never leak outside", function (done) {
pouch(dbName, function (err, db) {
db.bulkDocs({

@@ -403,3 +555,3 @@ docs: [

]
}, null, function() {
}, null, function () {

@@ -411,3 +563,3 @@ db.query(function (doc) {

}, { include_docs: true }, function (err, res) {
should.not.exist(res.rows[0].doc._doc_id_rev ,'_doc_id_rev is leaking but should not');
should.not.exist(res.rows[0].doc._doc_id_rev, '_doc_id_rev is leaking but should not');
done();

@@ -420,3 +572,3 @@ });

it('If reduce function returns 0, resulting value should not be null', function (done) {
Pouch(dbName, function(err, db) {
pouch(dbName, function (err, db) {
db.bulkDocs({

@@ -426,3 +578,3 @@ docs: [

]
}, null, function () {
}, function () {
db.query({

@@ -436,3 +588,3 @@ map: function (doc) {

}, function (err, data) {
data.rows[0].value.should.exist;
should.exist(data.rows[0].value);
done();

@@ -445,3 +597,3 @@ });

it('Testing skip with a view', function (done) {
Pouch(dbName, function(err, db) {
pouch(dbName, function (err, db) {
db.bulkDocs({

@@ -453,5 +605,5 @@ docs: [

]
}, null, function () {
}, function () {
db.query(function (doc) {
emit(doc.foo, null);
emit(doc.foo);
}, {skip: 1}, function (err, data) {

@@ -466,29 +618,31 @@ should.not.exist(err, 'Error:' + JSON.stringify(err));

it('Map documents on 0/null/undefined/empty string', function(done) {
Pouch(dbName, function(err, db) {
it('Map documents on 0/null/undefined/empty string', function (done) {
pouch(dbName, function (err, db) {
var docs = [
{_id : 'doc0', num : 0},
{_id : 'doc1', num : 1},
{_id : 'doc2' /* num is undefined */},
{_id : 'doc3', num : null},
{_id : 'doc4', num : ''}
{_id: 'doc0', num: 0},
{_id: 'doc1', num: 1},
{_id: 'doc2' /* num is undefined */},
{_id: 'doc3', num: null},
{_id: 'doc4', num: ''}
];
db.bulkDocs({docs: docs}, function(err){
var mapFunction =function(doc){emit(doc.num, null);};
db.bulkDocs({docs: docs}, function (err) {
var mapFunction = function (doc) {
emit(doc.num);
};
db.query(mapFunction, {key : 0, include_docs : true}, function(err, data){
data.rows.should.have.length( 1);
data.rows[0].doc._id.should.equal( 'doc0');
db.query(mapFunction, {key: 0, include_docs: true}, function (err, data) {
data.rows.should.have.length(1);
data.rows[0].doc._id.should.equal('doc0');
db.query(mapFunction, {key : null, include_docs : true}, function(err, data){
data.rows.should.have.length( 2);
data.rows[0].doc._id.should.equal( 'doc2');
data.rows[1].doc._id.should.equal( 'doc3');
db.query(mapFunction, {key: null, include_docs: true}, function (err, data) {
data.rows.should.have.length(2);
data.rows[0].doc._id.should.equal('doc2');
data.rows[1].doc._id.should.equal('doc3');
db.query(mapFunction, {key : '', include_docs : true}, function(err, data){
data.rows.should.have.length( 1);
data.rows[0].doc._id.should.equal( 'doc4');
db.query(mapFunction, {key: '', include_docs: true}, function (err, data) {
data.rows.should.have.length(1);
data.rows[0].doc._id.should.equal('doc4');
db.query(mapFunction, {key : undefined, include_docs : true}, function(err, data){
data.rows.should.have.length( 5); // everything
db.query(mapFunction, {key: undefined, include_docs: true}, function (err, data) {
data.rows.should.have.length(5); // everything
done();

@@ -503,22 +657,29 @@ });

it('Testing query with keys', function(done) {
Pouch(dbName, function(err, db) {
it('Testing query with keys', function (done) {
pouch(dbName, function (err, db) {
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'}
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'},
{
_id: "_design/test",
views: {
mapFunc: {
map: "function (doc) {emit(doc.field);}"
}
}
}
]
}, function(err) {
var mapFunction =function(doc){emit(doc.field, null);};
var opts = {include_docs : true};
db.query(mapFunction, opts, function(err, data) {
}, function (err) {
var opts = {include_docs: true};
db.query("test/mapFunc", opts, function (err, data) {
data.rows.should.have.length(7, 'returns all docs');
opts.keys = [];
db.query(mapFunction, opts, function(err, data) {
db.query("test/mapFunc", opts, function (err, data) {
// no docs

@@ -528,8 +689,8 @@ data.rows.should.have.length(0, 'returns 0 docs');

opts.keys = [0];
db.query(mapFunction, opts, function(err, data) {
db.query("test/mapFunc", opts, function (err, 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, ''];
db.query(mapFunction, opts, function(err, data) {
opts.keys = [2, 'foo', 1, 0, null, ''];
db.query("test/mapFunc", opts, function (err, data) {
// check that the returned ordering fits opts.keys

@@ -546,3 +707,3 @@ data.rows.should.have.length(7, 'returns 7 docs in correct order');

opts.keys = [3, 1, 4, 2];
db.query(mapFunction, opts, function(err, data) {
db.query("test/mapFunc", opts, function (err, data) {
// nonexistent keys just give us holes in the list

@@ -556,3 +717,3 @@ data.rows.should.have.length(2, 'returns 2 non-empty docs');

opts.keys = [2, 1, 2, 0, 2, 1];
db.query(mapFunction, opts, function(err, data) {
db.query("test/mapFunc", opts, function (err, data) {
// with duplicates, we return multiple docs

@@ -568,3 +729,3 @@ data.rows.should.have.length(6, 'returns 6 docs with duplicates');

opts.keys = [2, 1, 2, 3, 2];
db.query(mapFunction, opts, function(err, data) {
db.query("test/mapFunc", opts, function (err, data) {
// duplicates and unknowns at the same time, for maximum crazy

@@ -578,3 +739,3 @@ data.rows.should.have.length(4, 'returns 2 docs with duplicates/unknowns');

opts.keys = [3];
db.query(mapFunction, opts, function(err, data) {
db.query("test/mapFunc", opts, function (err, data) {
data.rows.should.have.length(0, 'returns 0 doc due to unknown key');

@@ -584,3 +745,3 @@

opts.keys = [3, 2];
db.query(mapFunction, opts, function(err, data) {
db.query("test/mapFunc", opts, function (err, data) {
data.rows.should.have.length(1, 'returns 1 doc due to unknown key');

@@ -599,27 +760,27 @@ data.rows[0].id.should.equal('doc_2');

});
})
});
});
});
it('Testing query with multiple keys, multiple docs', function(done) {
Pouch(dbName, function(err, db) {
it('Testing query with multiple keys, multiple docs', function (done) {
pouch(dbName, function (err, db) {
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}
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}
]
}, function(err) {
var mapFunction = function(doc){
emit(doc.field1, null);
emit(doc.field2, null);
}, function (err) {
var mapFunction = function (doc) {
emit(doc.field1);
emit(doc.field2);
};
var opts = {keys : [0, 1, 2]};
var opts = {keys: [0, 1, 2]};
db.query(mapFunction, opts, function(err, data) {
db.query(mapFunction, opts, function (err, data) {
data.rows.should.have.length(5);

@@ -634,3 +795,3 @@ data.rows[0].id.should.equal('0');

db.query(mapFunction, opts, function(err, data) {
db.query(mapFunction, opts, function (err, data) {
// ordered by m/r key, then doc id

@@ -659,16 +820,73 @@ data.rows.should.have.length(10);

});
it('Testing multiple emissions (issue #14)', function (done) {
pouch(dbName, function (err, db) {
db.bulkDocs({
docs: [
{_id: 'doc1', foo : 'foo', bar : 'bar'},
{_id: 'doc2', foo : 'foo', bar : 'bar'}
]
}, function (err) {
var mapFunction = function (doc) {
emit(doc.foo);
emit(doc.foo);
emit(doc.bar);
emit(doc.bar, 'multiple values!');
emit(doc.bar, 'crazy!');
};
var opts = {keys: ['foo', 'bar']};
it('Testing empty startkeys and endkeys', function(done) {
Pouch(dbName, function(err, db) {
db.query(mapFunction, opts, function (err, 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('crazy!');
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('crazy!');
data.rows[9].key.should.equal('bar');
data.rows[9].id.should.equal('doc2');
data.rows[9].value.should.equal('multiple values!');
done();
});
});
});
});
it('Testing empty startkeys and endkeys', function (done) {
pouch(dbName, function (err, db) {
db.bulkDocs({
docs : [
{_id : 'doc_empty', field : ''},
{_id : 'doc_null', field : null},
{_id : 'doc_undefined' /* field undefined */},
{_id : 'doc_foo', field : 'foo'}
docs: [
{_id: 'doc_empty', field: ''},
{_id: 'doc_null', field: null},
{_id: 'doc_undefined' /* field undefined */},
{_id: 'doc_foo', field: 'foo'}
]
}, function(err) {
var mapFunction = function(doc){emit(doc.field, null);};
var opts = {startkey : null, endkey : ''};
db.query(mapFunction, opts, function(err, data) {
}, function (err) {
var mapFunction = function (doc) {
emit(doc.field);
};
var opts = {startkey: null, endkey: ''};
db.query(mapFunction, opts, function (err, data) {
data.rows.should.have.length(3);

@@ -679,4 +897,4 @@ data.rows[0].id.should.equal('doc_null');

opts = {startkey : '', endkey : 'foo'};
db.query(mapFunction, opts, function(err, data) {
opts = {startkey: '', endkey: 'foo'};
db.query(mapFunction, opts, function (err, data) {
data.rows.should.have.length(2);

@@ -686,4 +904,4 @@ data.rows[0].id.should.equal('doc_empty');

opts = {startkey : null, endkey : null};
db.query(mapFunction, opts, function(err, data) {
opts = {startkey: null, endkey: null};
db.query(mapFunction, opts, function (err, data) {
data.rows.should.have.length(2);

@@ -694,3 +912,3 @@ data.rows[0].id.should.equal('doc_null');

opts.descending = true;
db.query(mapFunction, opts, function(err, data) {
db.query(mapFunction, opts, function (err, data) {
data.rows.should.have.length(2);

@@ -707,19 +925,21 @@ data.rows[0].id.should.equal('doc_undefined');

it('Testing ordering with startkey/endkey/key', function(done) {
Pouch(dbName, function(err, db) {
it('Testing ordering with startkey/endkey/key', function (done) {
pouch(dbName, function (err, db) {
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'}
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'}
]
}, function(err) {
var mapFunction = function(doc){emit(doc.field, null);};
var opts = {startkey : '1', endkey : '4'};
db.query(mapFunction, opts, function(err, data) {
}, function (err) {
var mapFunction = function (doc) {
emit(doc.field);
};
var opts = {startkey: '1', endkey: '4'};
db.query(mapFunction, opts, function (err, data) {
data.rows.should.have.length(8);

@@ -739,4 +959,4 @@ // 1

opts = {key : '1'};
db.query(mapFunction, opts, function(err, data) {
opts = {key: '1'};
db.query(mapFunction, opts, function (err, data) {
data.rows.should.have.length(3);

@@ -747,4 +967,4 @@ data.rows[0].id.should.equal('a');

opts = {key : '2'};
db.query(mapFunction, opts, function(err, data) {
opts = {key: '2'};
db.query(mapFunction, opts, function (err, data) {
data.rows.should.have.length(2);

@@ -755,3 +975,3 @@ data.rows[0].id.should.equal('d');

opts.descending = true;
db.query(mapFunction, opts, function(err, data) {
db.query(mapFunction, opts, function (err, data) {
data.rows.should.have.length(2);

@@ -769,3 +989,37 @@ data.rows[0].id.should.equal('e');

});
it('should error on a fake design', function (done) {
pouch(dbName, function (err, db) {
db.query('fake/thing', function (err) {
var a = err.should.exist;
done();
});
});
});
it('should work with a joined doc', function (done) {
pouch(dbName, function (err, db) {
db.bulkDocs({
docs: [
{_id: 'a', join: 'b', color: 'green'},
{_id: 'b', val: 'c'},
{_id: 'd', join: 'f', color: 'red'},
{
_id: "_design/test",
views: {
mapFunc: {
map: "function (doc) {if(doc.join){emit(doc.color, {_id:doc.join});}}"
}
}
}
]
}, function (err) {
db.query('test/mapFunc', {include_docs: true}, function (err, resp) {
resp.rows[0].key.should.equal('green');
resp.rows[0].doc._id.should.equal('b');
resp.rows[0].doc.val.should.equal('c');
done();
});
});
});
});
});
}