pouchdb-mapreduce
Advanced tools
Comparing version
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" | ||
} | ||
} |
736
test/test.js
@@ -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(); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); | ||
} |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
71719
85.99%7
40%2057
104.27%2
100%9
80%2
Infinity%5
150%+ Added
+ Added
+ Added