UNPKG

166 kBJavaScriptView Raw
1// pouchdb-find plugin 7.1.1
2// Based on Mango: https://github.com/cloudant/mango
3//
4// (c) 2012-2019 Dale Harvey and the PouchDB team
5// PouchDB may be freely distributed under the Apache license, version 2.0.
6// For all details and documentation:
7// http://pouchdb.com
8(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(_dereq_,module,exports){
9'use strict';
10
11module.exports = argsArray;
12
13function argsArray(fun) {
14 return function () {
15 var len = arguments.length;
16 if (len) {
17 var args = [];
18 var i = -1;
19 while (++i < len) {
20 args[i] = arguments[i];
21 }
22 return fun.call(this, args);
23 } else {
24 return fun.call(this, []);
25 }
26 };
27}
28},{}],2:[function(_dereq_,module,exports){
29// Copyright Joyent, Inc. and other Node contributors.
30//
31// Permission is hereby granted, free of charge, to any person obtaining a
32// copy of this software and associated documentation files (the
33// "Software"), to deal in the Software without restriction, including
34// without limitation the rights to use, copy, modify, merge, publish,
35// distribute, sublicense, and/or sell copies of the Software, and to permit
36// persons to whom the Software is furnished to do so, subject to the
37// following conditions:
38//
39// The above copyright notice and this permission notice shall be included
40// in all copies or substantial portions of the Software.
41//
42// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
43// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
44// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
45// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
46// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
47// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
48// USE OR OTHER DEALINGS IN THE SOFTWARE.
49
50var objectCreate = Object.create || objectCreatePolyfill
51var objectKeys = Object.keys || objectKeysPolyfill
52var bind = Function.prototype.bind || functionBindPolyfill
53
54function EventEmitter() {
55 if (!this._events || !Object.prototype.hasOwnProperty.call(this, '_events')) {
56 this._events = objectCreate(null);
57 this._eventsCount = 0;
58 }
59
60 this._maxListeners = this._maxListeners || undefined;
61}
62module.exports = EventEmitter;
63
64// Backwards-compat with node 0.10.x
65EventEmitter.EventEmitter = EventEmitter;
66
67EventEmitter.prototype._events = undefined;
68EventEmitter.prototype._maxListeners = undefined;
69
70// By default EventEmitters will print a warning if more than 10 listeners are
71// added to it. This is a useful default which helps finding memory leaks.
72var defaultMaxListeners = 10;
73
74var hasDefineProperty;
75try {
76 var o = {};
77 if (Object.defineProperty) Object.defineProperty(o, 'x', { value: 0 });
78 hasDefineProperty = o.x === 0;
79} catch (err) { hasDefineProperty = false }
80if (hasDefineProperty) {
81 Object.defineProperty(EventEmitter, 'defaultMaxListeners', {
82 enumerable: true,
83 get: function() {
84 return defaultMaxListeners;
85 },
86 set: function(arg) {
87 // check whether the input is a positive number (whose value is zero or
88 // greater and not a NaN).
89 if (typeof arg !== 'number' || arg < 0 || arg !== arg)
90 throw new TypeError('"defaultMaxListeners" must be a positive number');
91 defaultMaxListeners = arg;
92 }
93 });
94} else {
95 EventEmitter.defaultMaxListeners = defaultMaxListeners;
96}
97
98// Obviously not all Emitters should be limited to 10. This function allows
99// that to be increased. Set to zero for unlimited.
100EventEmitter.prototype.setMaxListeners = function setMaxListeners(n) {
101 if (typeof n !== 'number' || n < 0 || isNaN(n))
102 throw new TypeError('"n" argument must be a positive number');
103 this._maxListeners = n;
104 return this;
105};
106
107function $getMaxListeners(that) {
108 if (that._maxListeners === undefined)
109 return EventEmitter.defaultMaxListeners;
110 return that._maxListeners;
111}
112
113EventEmitter.prototype.getMaxListeners = function getMaxListeners() {
114 return $getMaxListeners(this);
115};
116
117// These standalone emit* functions are used to optimize calling of event
118// handlers for fast cases because emit() itself often has a variable number of
119// arguments and can be deoptimized because of that. These functions always have
120// the same number of arguments and thus do not get deoptimized, so the code
121// inside them can execute faster.
122function emitNone(handler, isFn, self) {
123 if (isFn)
124 handler.call(self);
125 else {
126 var len = handler.length;
127 var listeners = arrayClone(handler, len);
128 for (var i = 0; i < len; ++i)
129 listeners[i].call(self);
130 }
131}
132function emitOne(handler, isFn, self, arg1) {
133 if (isFn)
134 handler.call(self, arg1);
135 else {
136 var len = handler.length;
137 var listeners = arrayClone(handler, len);
138 for (var i = 0; i < len; ++i)
139 listeners[i].call(self, arg1);
140 }
141}
142function emitTwo(handler, isFn, self, arg1, arg2) {
143 if (isFn)
144 handler.call(self, arg1, arg2);
145 else {
146 var len = handler.length;
147 var listeners = arrayClone(handler, len);
148 for (var i = 0; i < len; ++i)
149 listeners[i].call(self, arg1, arg2);
150 }
151}
152function emitThree(handler, isFn, self, arg1, arg2, arg3) {
153 if (isFn)
154 handler.call(self, arg1, arg2, arg3);
155 else {
156 var len = handler.length;
157 var listeners = arrayClone(handler, len);
158 for (var i = 0; i < len; ++i)
159 listeners[i].call(self, arg1, arg2, arg3);
160 }
161}
162
163function emitMany(handler, isFn, self, args) {
164 if (isFn)
165 handler.apply(self, args);
166 else {
167 var len = handler.length;
168 var listeners = arrayClone(handler, len);
169 for (var i = 0; i < len; ++i)
170 listeners[i].apply(self, args);
171 }
172}
173
174EventEmitter.prototype.emit = function emit(type) {
175 var er, handler, len, args, i, events;
176 var doError = (type === 'error');
177
178 events = this._events;
179 if (events)
180 doError = (doError && events.error == null);
181 else if (!doError)
182 return false;
183
184 // If there is no 'error' event listener then throw.
185 if (doError) {
186 if (arguments.length > 1)
187 er = arguments[1];
188 if (er instanceof Error) {
189 throw er; // Unhandled 'error' event
190 } else {
191 // At least give some kind of context to the user
192 var err = new Error('Unhandled "error" event. (' + er + ')');
193 err.context = er;
194 throw err;
195 }
196 return false;
197 }
198
199 handler = events[type];
200
201 if (!handler)
202 return false;
203
204 var isFn = typeof handler === 'function';
205 len = arguments.length;
206 switch (len) {
207 // fast cases
208 case 1:
209 emitNone(handler, isFn, this);
210 break;
211 case 2:
212 emitOne(handler, isFn, this, arguments[1]);
213 break;
214 case 3:
215 emitTwo(handler, isFn, this, arguments[1], arguments[2]);
216 break;
217 case 4:
218 emitThree(handler, isFn, this, arguments[1], arguments[2], arguments[3]);
219 break;
220 // slower
221 default:
222 args = new Array(len - 1);
223 for (i = 1; i < len; i++)
224 args[i - 1] = arguments[i];
225 emitMany(handler, isFn, this, args);
226 }
227
228 return true;
229};
230
231function _addListener(target, type, listener, prepend) {
232 var m;
233 var events;
234 var existing;
235
236 if (typeof listener !== 'function')
237 throw new TypeError('"listener" argument must be a function');
238
239 events = target._events;
240 if (!events) {
241 events = target._events = objectCreate(null);
242 target._eventsCount = 0;
243 } else {
244 // To avoid recursion in the case that type === "newListener"! Before
245 // adding it to the listeners, first emit "newListener".
246 if (events.newListener) {
247 target.emit('newListener', type,
248 listener.listener ? listener.listener : listener);
249
250 // Re-assign `events` because a newListener handler could have caused the
251 // this._events to be assigned to a new object
252 events = target._events;
253 }
254 existing = events[type];
255 }
256
257 if (!existing) {
258 // Optimize the case of one listener. Don't need the extra array object.
259 existing = events[type] = listener;
260 ++target._eventsCount;
261 } else {
262 if (typeof existing === 'function') {
263 // Adding the second element, need to change to array.
264 existing = events[type] =
265 prepend ? [listener, existing] : [existing, listener];
266 } else {
267 // If we've already got an array, just append.
268 if (prepend) {
269 existing.unshift(listener);
270 } else {
271 existing.push(listener);
272 }
273 }
274
275 // Check for listener leak
276 if (!existing.warned) {
277 m = $getMaxListeners(target);
278 if (m && m > 0 && existing.length > m) {
279 existing.warned = true;
280 var w = new Error('Possible EventEmitter memory leak detected. ' +
281 existing.length + ' "' + String(type) + '" listeners ' +
282 'added. Use emitter.setMaxListeners() to ' +
283 'increase limit.');
284 w.name = 'MaxListenersExceededWarning';
285 w.emitter = target;
286 w.type = type;
287 w.count = existing.length;
288 if (typeof console === 'object' && console.warn) {
289 console.warn('%s: %s', w.name, w.message);
290 }
291 }
292 }
293 }
294
295 return target;
296}
297
298EventEmitter.prototype.addListener = function addListener(type, listener) {
299 return _addListener(this, type, listener, false);
300};
301
302EventEmitter.prototype.on = EventEmitter.prototype.addListener;
303
304EventEmitter.prototype.prependListener =
305 function prependListener(type, listener) {
306 return _addListener(this, type, listener, true);
307 };
308
309function onceWrapper() {
310 if (!this.fired) {
311 this.target.removeListener(this.type, this.wrapFn);
312 this.fired = true;
313 switch (arguments.length) {
314 case 0:
315 return this.listener.call(this.target);
316 case 1:
317 return this.listener.call(this.target, arguments[0]);
318 case 2:
319 return this.listener.call(this.target, arguments[0], arguments[1]);
320 case 3:
321 return this.listener.call(this.target, arguments[0], arguments[1],
322 arguments[2]);
323 default:
324 var args = new Array(arguments.length);
325 for (var i = 0; i < args.length; ++i)
326 args[i] = arguments[i];
327 this.listener.apply(this.target, args);
328 }
329 }
330}
331
332function _onceWrap(target, type, listener) {
333 var state = { fired: false, wrapFn: undefined, target: target, type: type, listener: listener };
334 var wrapped = bind.call(onceWrapper, state);
335 wrapped.listener = listener;
336 state.wrapFn = wrapped;
337 return wrapped;
338}
339
340EventEmitter.prototype.once = function once(type, listener) {
341 if (typeof listener !== 'function')
342 throw new TypeError('"listener" argument must be a function');
343 this.on(type, _onceWrap(this, type, listener));
344 return this;
345};
346
347EventEmitter.prototype.prependOnceListener =
348 function prependOnceListener(type, listener) {
349 if (typeof listener !== 'function')
350 throw new TypeError('"listener" argument must be a function');
351 this.prependListener(type, _onceWrap(this, type, listener));
352 return this;
353 };
354
355// Emits a 'removeListener' event if and only if the listener was removed.
356EventEmitter.prototype.removeListener =
357 function removeListener(type, listener) {
358 var list, events, position, i, originalListener;
359
360 if (typeof listener !== 'function')
361 throw new TypeError('"listener" argument must be a function');
362
363 events = this._events;
364 if (!events)
365 return this;
366
367 list = events[type];
368 if (!list)
369 return this;
370
371 if (list === listener || list.listener === listener) {
372 if (--this._eventsCount === 0)
373 this._events = objectCreate(null);
374 else {
375 delete events[type];
376 if (events.removeListener)
377 this.emit('removeListener', type, list.listener || listener);
378 }
379 } else if (typeof list !== 'function') {
380 position = -1;
381
382 for (i = list.length - 1; i >= 0; i--) {
383 if (list[i] === listener || list[i].listener === listener) {
384 originalListener = list[i].listener;
385 position = i;
386 break;
387 }
388 }
389
390 if (position < 0)
391 return this;
392
393 if (position === 0)
394 list.shift();
395 else
396 spliceOne(list, position);
397
398 if (list.length === 1)
399 events[type] = list[0];
400
401 if (events.removeListener)
402 this.emit('removeListener', type, originalListener || listener);
403 }
404
405 return this;
406 };
407
408EventEmitter.prototype.removeAllListeners =
409 function removeAllListeners(type) {
410 var listeners, events, i;
411
412 events = this._events;
413 if (!events)
414 return this;
415
416 // not listening for removeListener, no need to emit
417 if (!events.removeListener) {
418 if (arguments.length === 0) {
419 this._events = objectCreate(null);
420 this._eventsCount = 0;
421 } else if (events[type]) {
422 if (--this._eventsCount === 0)
423 this._events = objectCreate(null);
424 else
425 delete events[type];
426 }
427 return this;
428 }
429
430 // emit removeListener for all listeners on all events
431 if (arguments.length === 0) {
432 var keys = objectKeys(events);
433 var key;
434 for (i = 0; i < keys.length; ++i) {
435 key = keys[i];
436 if (key === 'removeListener') continue;
437 this.removeAllListeners(key);
438 }
439 this.removeAllListeners('removeListener');
440 this._events = objectCreate(null);
441 this._eventsCount = 0;
442 return this;
443 }
444
445 listeners = events[type];
446
447 if (typeof listeners === 'function') {
448 this.removeListener(type, listeners);
449 } else if (listeners) {
450 // LIFO order
451 for (i = listeners.length - 1; i >= 0; i--) {
452 this.removeListener(type, listeners[i]);
453 }
454 }
455
456 return this;
457 };
458
459function _listeners(target, type, unwrap) {
460 var events = target._events;
461
462 if (!events)
463 return [];
464
465 var evlistener = events[type];
466 if (!evlistener)
467 return [];
468
469 if (typeof evlistener === 'function')
470 return unwrap ? [evlistener.listener || evlistener] : [evlistener];
471
472 return unwrap ? unwrapListeners(evlistener) : arrayClone(evlistener, evlistener.length);
473}
474
475EventEmitter.prototype.listeners = function listeners(type) {
476 return _listeners(this, type, true);
477};
478
479EventEmitter.prototype.rawListeners = function rawListeners(type) {
480 return _listeners(this, type, false);
481};
482
483EventEmitter.listenerCount = function(emitter, type) {
484 if (typeof emitter.listenerCount === 'function') {
485 return emitter.listenerCount(type);
486 } else {
487 return listenerCount.call(emitter, type);
488 }
489};
490
491EventEmitter.prototype.listenerCount = listenerCount;
492function listenerCount(type) {
493 var events = this._events;
494
495 if (events) {
496 var evlistener = events[type];
497
498 if (typeof evlistener === 'function') {
499 return 1;
500 } else if (evlistener) {
501 return evlistener.length;
502 }
503 }
504
505 return 0;
506}
507
508EventEmitter.prototype.eventNames = function eventNames() {
509 return this._eventsCount > 0 ? Reflect.ownKeys(this._events) : [];
510};
511
512// About 1.5x faster than the two-arg version of Array#splice().
513function spliceOne(list, index) {
514 for (var i = index, k = i + 1, n = list.length; k < n; i += 1, k += 1)
515 list[i] = list[k];
516 list.pop();
517}
518
519function arrayClone(arr, n) {
520 var copy = new Array(n);
521 for (var i = 0; i < n; ++i)
522 copy[i] = arr[i];
523 return copy;
524}
525
526function unwrapListeners(arr) {
527 var ret = new Array(arr.length);
528 for (var i = 0; i < ret.length; ++i) {
529 ret[i] = arr[i].listener || arr[i];
530 }
531 return ret;
532}
533
534function objectCreatePolyfill(proto) {
535 var F = function() {};
536 F.prototype = proto;
537 return new F;
538}
539function objectKeysPolyfill(obj) {
540 var keys = [];
541 for (var k in obj) if (Object.prototype.hasOwnProperty.call(obj, k)) {
542 keys.push(k);
543 }
544 return k;
545}
546function functionBindPolyfill(context) {
547 var fn = this;
548 return function () {
549 return fn.apply(context, arguments);
550 };
551}
552
553},{}],3:[function(_dereq_,module,exports){
554(function (global){
555'use strict';
556var Mutation = global.MutationObserver || global.WebKitMutationObserver;
557
558var scheduleDrain;
559
560{
561 if (Mutation) {
562 var called = 0;
563 var observer = new Mutation(nextTick);
564 var element = global.document.createTextNode('');
565 observer.observe(element, {
566 characterData: true
567 });
568 scheduleDrain = function () {
569 element.data = (called = ++called % 2);
570 };
571 } else if (!global.setImmediate && typeof global.MessageChannel !== 'undefined') {
572 var channel = new global.MessageChannel();
573 channel.port1.onmessage = nextTick;
574 scheduleDrain = function () {
575 channel.port2.postMessage(0);
576 };
577 } else if ('document' in global && 'onreadystatechange' in global.document.createElement('script')) {
578 scheduleDrain = function () {
579
580 // Create a <script> element; its readystatechange event will be fired asynchronously once it is inserted
581 // into the document. Do so, thus queuing up the task. Remember to clean up once it's been called.
582 var scriptEl = global.document.createElement('script');
583 scriptEl.onreadystatechange = function () {
584 nextTick();
585
586 scriptEl.onreadystatechange = null;
587 scriptEl.parentNode.removeChild(scriptEl);
588 scriptEl = null;
589 };
590 global.document.documentElement.appendChild(scriptEl);
591 };
592 } else {
593 scheduleDrain = function () {
594 setTimeout(nextTick, 0);
595 };
596 }
597}
598
599var draining;
600var queue = [];
601//named nextTick for less confusing stack traces
602function nextTick() {
603 draining = true;
604 var i, oldQueue;
605 var len = queue.length;
606 while (len) {
607 oldQueue = queue;
608 queue = [];
609 i = -1;
610 while (++i < len) {
611 oldQueue[i]();
612 }
613 len = queue.length;
614 }
615 draining = false;
616}
617
618module.exports = immediate;
619function immediate(task) {
620 if (queue.push(task) === 1 && !draining) {
621 scheduleDrain();
622 }
623}
624
625}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
626},{}],4:[function(_dereq_,module,exports){
627if (typeof Object.create === 'function') {
628 // implementation from standard node.js 'util' module
629 module.exports = function inherits(ctor, superCtor) {
630 ctor.super_ = superCtor
631 ctor.prototype = Object.create(superCtor.prototype, {
632 constructor: {
633 value: ctor,
634 enumerable: false,
635 writable: true,
636 configurable: true
637 }
638 });
639 };
640} else {
641 // old school shim for old browsers
642 module.exports = function inherits(ctor, superCtor) {
643 ctor.super_ = superCtor
644 var TempCtor = function () {}
645 TempCtor.prototype = superCtor.prototype
646 ctor.prototype = new TempCtor()
647 ctor.prototype.constructor = ctor
648 }
649}
650
651},{}],5:[function(_dereq_,module,exports){
652(function (factory) {
653 if (typeof exports === 'object') {
654 // Node/CommonJS
655 module.exports = factory();
656 } else if (typeof define === 'function' && define.amd) {
657 // AMD
658 define(factory);
659 } else {
660 // Browser globals (with support for web workers)
661 var glob;
662
663 try {
664 glob = window;
665 } catch (e) {
666 glob = self;
667 }
668
669 glob.SparkMD5 = factory();
670 }
671}(function (undefined) {
672
673 'use strict';
674
675 /*
676 * Fastest md5 implementation around (JKM md5).
677 * Credits: Joseph Myers
678 *
679 * @see http://www.myersdaily.org/joseph/javascript/md5-text.html
680 * @see http://jsperf.com/md5-shootout/7
681 */
682
683 /* this function is much faster,
684 so if possible we use it. Some IEs
685 are the only ones I know of that
686 need the idiotic second function,
687 generated by an if clause. */
688 var add32 = function (a, b) {
689 return (a + b) & 0xFFFFFFFF;
690 },
691 hex_chr = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'];
692
693
694 function cmn(q, a, b, x, s, t) {
695 a = add32(add32(a, q), add32(x, t));
696 return add32((a << s) | (a >>> (32 - s)), b);
697 }
698
699 function md5cycle(x, k) {
700 var a = x[0],
701 b = x[1],
702 c = x[2],
703 d = x[3];
704
705 a += (b & c | ~b & d) + k[0] - 680876936 | 0;
706 a = (a << 7 | a >>> 25) + b | 0;
707 d += (a & b | ~a & c) + k[1] - 389564586 | 0;
708 d = (d << 12 | d >>> 20) + a | 0;
709 c += (d & a | ~d & b) + k[2] + 606105819 | 0;
710 c = (c << 17 | c >>> 15) + d | 0;
711 b += (c & d | ~c & a) + k[3] - 1044525330 | 0;
712 b = (b << 22 | b >>> 10) + c | 0;
713 a += (b & c | ~b & d) + k[4] - 176418897 | 0;
714 a = (a << 7 | a >>> 25) + b | 0;
715 d += (a & b | ~a & c) + k[5] + 1200080426 | 0;
716 d = (d << 12 | d >>> 20) + a | 0;
717 c += (d & a | ~d & b) + k[6] - 1473231341 | 0;
718 c = (c << 17 | c >>> 15) + d | 0;
719 b += (c & d | ~c & a) + k[7] - 45705983 | 0;
720 b = (b << 22 | b >>> 10) + c | 0;
721 a += (b & c | ~b & d) + k[8] + 1770035416 | 0;
722 a = (a << 7 | a >>> 25) + b | 0;
723 d += (a & b | ~a & c) + k[9] - 1958414417 | 0;
724 d = (d << 12 | d >>> 20) + a | 0;
725 c += (d & a | ~d & b) + k[10] - 42063 | 0;
726 c = (c << 17 | c >>> 15) + d | 0;
727 b += (c & d | ~c & a) + k[11] - 1990404162 | 0;
728 b = (b << 22 | b >>> 10) + c | 0;
729 a += (b & c | ~b & d) + k[12] + 1804603682 | 0;
730 a = (a << 7 | a >>> 25) + b | 0;
731 d += (a & b | ~a & c) + k[13] - 40341101 | 0;
732 d = (d << 12 | d >>> 20) + a | 0;
733 c += (d & a | ~d & b) + k[14] - 1502002290 | 0;
734 c = (c << 17 | c >>> 15) + d | 0;
735 b += (c & d | ~c & a) + k[15] + 1236535329 | 0;
736 b = (b << 22 | b >>> 10) + c | 0;
737
738 a += (b & d | c & ~d) + k[1] - 165796510 | 0;
739 a = (a << 5 | a >>> 27) + b | 0;
740 d += (a & c | b & ~c) + k[6] - 1069501632 | 0;
741 d = (d << 9 | d >>> 23) + a | 0;
742 c += (d & b | a & ~b) + k[11] + 643717713 | 0;
743 c = (c << 14 | c >>> 18) + d | 0;
744 b += (c & a | d & ~a) + k[0] - 373897302 | 0;
745 b = (b << 20 | b >>> 12) + c | 0;
746 a += (b & d | c & ~d) + k[5] - 701558691 | 0;
747 a = (a << 5 | a >>> 27) + b | 0;
748 d += (a & c | b & ~c) + k[10] + 38016083 | 0;
749 d = (d << 9 | d >>> 23) + a | 0;
750 c += (d & b | a & ~b) + k[15] - 660478335 | 0;
751 c = (c << 14 | c >>> 18) + d | 0;
752 b += (c & a | d & ~a) + k[4] - 405537848 | 0;
753 b = (b << 20 | b >>> 12) + c | 0;
754 a += (b & d | c & ~d) + k[9] + 568446438 | 0;
755 a = (a << 5 | a >>> 27) + b | 0;
756 d += (a & c | b & ~c) + k[14] - 1019803690 | 0;
757 d = (d << 9 | d >>> 23) + a | 0;
758 c += (d & b | a & ~b) + k[3] - 187363961 | 0;
759 c = (c << 14 | c >>> 18) + d | 0;
760 b += (c & a | d & ~a) + k[8] + 1163531501 | 0;
761 b = (b << 20 | b >>> 12) + c | 0;
762 a += (b & d | c & ~d) + k[13] - 1444681467 | 0;
763 a = (a << 5 | a >>> 27) + b | 0;
764 d += (a & c | b & ~c) + k[2] - 51403784 | 0;
765 d = (d << 9 | d >>> 23) + a | 0;
766 c += (d & b | a & ~b) + k[7] + 1735328473 | 0;
767 c = (c << 14 | c >>> 18) + d | 0;
768 b += (c & a | d & ~a) + k[12] - 1926607734 | 0;
769 b = (b << 20 | b >>> 12) + c | 0;
770
771 a += (b ^ c ^ d) + k[5] - 378558 | 0;
772 a = (a << 4 | a >>> 28) + b | 0;
773 d += (a ^ b ^ c) + k[8] - 2022574463 | 0;
774 d = (d << 11 | d >>> 21) + a | 0;
775 c += (d ^ a ^ b) + k[11] + 1839030562 | 0;
776 c = (c << 16 | c >>> 16) + d | 0;
777 b += (c ^ d ^ a) + k[14] - 35309556 | 0;
778 b = (b << 23 | b >>> 9) + c | 0;
779 a += (b ^ c ^ d) + k[1] - 1530992060 | 0;
780 a = (a << 4 | a >>> 28) + b | 0;
781 d += (a ^ b ^ c) + k[4] + 1272893353 | 0;
782 d = (d << 11 | d >>> 21) + a | 0;
783 c += (d ^ a ^ b) + k[7] - 155497632 | 0;
784 c = (c << 16 | c >>> 16) + d | 0;
785 b += (c ^ d ^ a) + k[10] - 1094730640 | 0;
786 b = (b << 23 | b >>> 9) + c | 0;
787 a += (b ^ c ^ d) + k[13] + 681279174 | 0;
788 a = (a << 4 | a >>> 28) + b | 0;
789 d += (a ^ b ^ c) + k[0] - 358537222 | 0;
790 d = (d << 11 | d >>> 21) + a | 0;
791 c += (d ^ a ^ b) + k[3] - 722521979 | 0;
792 c = (c << 16 | c >>> 16) + d | 0;
793 b += (c ^ d ^ a) + k[6] + 76029189 | 0;
794 b = (b << 23 | b >>> 9) + c | 0;
795 a += (b ^ c ^ d) + k[9] - 640364487 | 0;
796 a = (a << 4 | a >>> 28) + b | 0;
797 d += (a ^ b ^ c) + k[12] - 421815835 | 0;
798 d = (d << 11 | d >>> 21) + a | 0;
799 c += (d ^ a ^ b) + k[15] + 530742520 | 0;
800 c = (c << 16 | c >>> 16) + d | 0;
801 b += (c ^ d ^ a) + k[2] - 995338651 | 0;
802 b = (b << 23 | b >>> 9) + c | 0;
803
804 a += (c ^ (b | ~d)) + k[0] - 198630844 | 0;
805 a = (a << 6 | a >>> 26) + b | 0;
806 d += (b ^ (a | ~c)) + k[7] + 1126891415 | 0;
807 d = (d << 10 | d >>> 22) + a | 0;
808 c += (a ^ (d | ~b)) + k[14] - 1416354905 | 0;
809 c = (c << 15 | c >>> 17) + d | 0;
810 b += (d ^ (c | ~a)) + k[5] - 57434055 | 0;
811 b = (b << 21 |b >>> 11) + c | 0;
812 a += (c ^ (b | ~d)) + k[12] + 1700485571 | 0;
813 a = (a << 6 | a >>> 26) + b | 0;
814 d += (b ^ (a | ~c)) + k[3] - 1894986606 | 0;
815 d = (d << 10 | d >>> 22) + a | 0;
816 c += (a ^ (d | ~b)) + k[10] - 1051523 | 0;
817 c = (c << 15 | c >>> 17) + d | 0;
818 b += (d ^ (c | ~a)) + k[1] - 2054922799 | 0;
819 b = (b << 21 |b >>> 11) + c | 0;
820 a += (c ^ (b | ~d)) + k[8] + 1873313359 | 0;
821 a = (a << 6 | a >>> 26) + b | 0;
822 d += (b ^ (a | ~c)) + k[15] - 30611744 | 0;
823 d = (d << 10 | d >>> 22) + a | 0;
824 c += (a ^ (d | ~b)) + k[6] - 1560198380 | 0;
825 c = (c << 15 | c >>> 17) + d | 0;
826 b += (d ^ (c | ~a)) + k[13] + 1309151649 | 0;
827 b = (b << 21 |b >>> 11) + c | 0;
828 a += (c ^ (b | ~d)) + k[4] - 145523070 | 0;
829 a = (a << 6 | a >>> 26) + b | 0;
830 d += (b ^ (a | ~c)) + k[11] - 1120210379 | 0;
831 d = (d << 10 | d >>> 22) + a | 0;
832 c += (a ^ (d | ~b)) + k[2] + 718787259 | 0;
833 c = (c << 15 | c >>> 17) + d | 0;
834 b += (d ^ (c | ~a)) + k[9] - 343485551 | 0;
835 b = (b << 21 | b >>> 11) + c | 0;
836
837 x[0] = a + x[0] | 0;
838 x[1] = b + x[1] | 0;
839 x[2] = c + x[2] | 0;
840 x[3] = d + x[3] | 0;
841 }
842
843 function md5blk(s) {
844 var md5blks = [],
845 i; /* Andy King said do it this way. */
846
847 for (i = 0; i < 64; i += 4) {
848 md5blks[i >> 2] = s.charCodeAt(i) + (s.charCodeAt(i + 1) << 8) + (s.charCodeAt(i + 2) << 16) + (s.charCodeAt(i + 3) << 24);
849 }
850 return md5blks;
851 }
852
853 function md5blk_array(a) {
854 var md5blks = [],
855 i; /* Andy King said do it this way. */
856
857 for (i = 0; i < 64; i += 4) {
858 md5blks[i >> 2] = a[i] + (a[i + 1] << 8) + (a[i + 2] << 16) + (a[i + 3] << 24);
859 }
860 return md5blks;
861 }
862
863 function md51(s) {
864 var n = s.length,
865 state = [1732584193, -271733879, -1732584194, 271733878],
866 i,
867 length,
868 tail,
869 tmp,
870 lo,
871 hi;
872
873 for (i = 64; i <= n; i += 64) {
874 md5cycle(state, md5blk(s.substring(i - 64, i)));
875 }
876 s = s.substring(i - 64);
877 length = s.length;
878 tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
879 for (i = 0; i < length; i += 1) {
880 tail[i >> 2] |= s.charCodeAt(i) << ((i % 4) << 3);
881 }
882 tail[i >> 2] |= 0x80 << ((i % 4) << 3);
883 if (i > 55) {
884 md5cycle(state, tail);
885 for (i = 0; i < 16; i += 1) {
886 tail[i] = 0;
887 }
888 }
889
890 // Beware that the final length might not fit in 32 bits so we take care of that
891 tmp = n * 8;
892 tmp = tmp.toString(16).match(/(.*?)(.{0,8})$/);
893 lo = parseInt(tmp[2], 16);
894 hi = parseInt(tmp[1], 16) || 0;
895
896 tail[14] = lo;
897 tail[15] = hi;
898
899 md5cycle(state, tail);
900 return state;
901 }
902
903 function md51_array(a) {
904 var n = a.length,
905 state = [1732584193, -271733879, -1732584194, 271733878],
906 i,
907 length,
908 tail,
909 tmp,
910 lo,
911 hi;
912
913 for (i = 64; i <= n; i += 64) {
914 md5cycle(state, md5blk_array(a.subarray(i - 64, i)));
915 }
916
917 // Not sure if it is a bug, however IE10 will always produce a sub array of length 1
918 // containing the last element of the parent array if the sub array specified starts
919 // beyond the length of the parent array - weird.
920 // https://connect.microsoft.com/IE/feedback/details/771452/typed-array-subarray-issue
921 a = (i - 64) < n ? a.subarray(i - 64) : new Uint8Array(0);
922
923 length = a.length;
924 tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
925 for (i = 0; i < length; i += 1) {
926 tail[i >> 2] |= a[i] << ((i % 4) << 3);
927 }
928
929 tail[i >> 2] |= 0x80 << ((i % 4) << 3);
930 if (i > 55) {
931 md5cycle(state, tail);
932 for (i = 0; i < 16; i += 1) {
933 tail[i] = 0;
934 }
935 }
936
937 // Beware that the final length might not fit in 32 bits so we take care of that
938 tmp = n * 8;
939 tmp = tmp.toString(16).match(/(.*?)(.{0,8})$/);
940 lo = parseInt(tmp[2], 16);
941 hi = parseInt(tmp[1], 16) || 0;
942
943 tail[14] = lo;
944 tail[15] = hi;
945
946 md5cycle(state, tail);
947
948 return state;
949 }
950
951 function rhex(n) {
952 var s = '',
953 j;
954 for (j = 0; j < 4; j += 1) {
955 s += hex_chr[(n >> (j * 8 + 4)) & 0x0F] + hex_chr[(n >> (j * 8)) & 0x0F];
956 }
957 return s;
958 }
959
960 function hex(x) {
961 var i;
962 for (i = 0; i < x.length; i += 1) {
963 x[i] = rhex(x[i]);
964 }
965 return x.join('');
966 }
967
968 // In some cases the fast add32 function cannot be used..
969 if (hex(md51('hello')) !== '5d41402abc4b2a76b9719d911017c592') {
970 add32 = function (x, y) {
971 var lsw = (x & 0xFFFF) + (y & 0xFFFF),
972 msw = (x >> 16) + (y >> 16) + (lsw >> 16);
973 return (msw << 16) | (lsw & 0xFFFF);
974 };
975 }
976
977 // ---------------------------------------------------
978
979 /**
980 * ArrayBuffer slice polyfill.
981 *
982 * @see https://github.com/ttaubert/node-arraybuffer-slice
983 */
984
985 if (typeof ArrayBuffer !== 'undefined' && !ArrayBuffer.prototype.slice) {
986 (function () {
987 function clamp(val, length) {
988 val = (val | 0) || 0;
989
990 if (val < 0) {
991 return Math.max(val + length, 0);
992 }
993
994 return Math.min(val, length);
995 }
996
997 ArrayBuffer.prototype.slice = function (from, to) {
998 var length = this.byteLength,
999 begin = clamp(from, length),
1000 end = length,
1001 num,
1002 target,
1003 targetArray,
1004 sourceArray;
1005
1006 if (to !== undefined) {
1007 end = clamp(to, length);
1008 }
1009
1010 if (begin > end) {
1011 return new ArrayBuffer(0);
1012 }
1013
1014 num = end - begin;
1015 target = new ArrayBuffer(num);
1016 targetArray = new Uint8Array(target);
1017
1018 sourceArray = new Uint8Array(this, begin, num);
1019 targetArray.set(sourceArray);
1020
1021 return target;
1022 };
1023 })();
1024 }
1025
1026 // ---------------------------------------------------
1027
1028 /**
1029 * Helpers.
1030 */
1031
1032 function toUtf8(str) {
1033 if (/[\u0080-\uFFFF]/.test(str)) {
1034 str = unescape(encodeURIComponent(str));
1035 }
1036
1037 return str;
1038 }
1039
1040 function utf8Str2ArrayBuffer(str, returnUInt8Array) {
1041 var length = str.length,
1042 buff = new ArrayBuffer(length),
1043 arr = new Uint8Array(buff),
1044 i;
1045
1046 for (i = 0; i < length; i += 1) {
1047 arr[i] = str.charCodeAt(i);
1048 }
1049
1050 return returnUInt8Array ? arr : buff;
1051 }
1052
1053 function arrayBuffer2Utf8Str(buff) {
1054 return String.fromCharCode.apply(null, new Uint8Array(buff));
1055 }
1056
1057 function concatenateArrayBuffers(first, second, returnUInt8Array) {
1058 var result = new Uint8Array(first.byteLength + second.byteLength);
1059
1060 result.set(new Uint8Array(first));
1061 result.set(new Uint8Array(second), first.byteLength);
1062
1063 return returnUInt8Array ? result : result.buffer;
1064 }
1065
1066 function hexToBinaryString(hex) {
1067 var bytes = [],
1068 length = hex.length,
1069 x;
1070
1071 for (x = 0; x < length - 1; x += 2) {
1072 bytes.push(parseInt(hex.substr(x, 2), 16));
1073 }
1074
1075 return String.fromCharCode.apply(String, bytes);
1076 }
1077
1078 // ---------------------------------------------------
1079
1080 /**
1081 * SparkMD5 OOP implementation.
1082 *
1083 * Use this class to perform an incremental md5, otherwise use the
1084 * static methods instead.
1085 */
1086
1087 function SparkMD5() {
1088 // call reset to init the instance
1089 this.reset();
1090 }
1091
1092 /**
1093 * Appends a string.
1094 * A conversion will be applied if an utf8 string is detected.
1095 *
1096 * @param {String} str The string to be appended
1097 *
1098 * @return {SparkMD5} The instance itself
1099 */
1100 SparkMD5.prototype.append = function (str) {
1101 // Converts the string to utf8 bytes if necessary
1102 // Then append as binary
1103 this.appendBinary(toUtf8(str));
1104
1105 return this;
1106 };
1107
1108 /**
1109 * Appends a binary string.
1110 *
1111 * @param {String} contents The binary string to be appended
1112 *
1113 * @return {SparkMD5} The instance itself
1114 */
1115 SparkMD5.prototype.appendBinary = function (contents) {
1116 this._buff += contents;
1117 this._length += contents.length;
1118
1119 var length = this._buff.length,
1120 i;
1121
1122 for (i = 64; i <= length; i += 64) {
1123 md5cycle(this._hash, md5blk(this._buff.substring(i - 64, i)));
1124 }
1125
1126 this._buff = this._buff.substring(i - 64);
1127
1128 return this;
1129 };
1130
1131 /**
1132 * Finishes the incremental computation, reseting the internal state and
1133 * returning the result.
1134 *
1135 * @param {Boolean} raw True to get the raw string, false to get the hex string
1136 *
1137 * @return {String} The result
1138 */
1139 SparkMD5.prototype.end = function (raw) {
1140 var buff = this._buff,
1141 length = buff.length,
1142 i,
1143 tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
1144 ret;
1145
1146 for (i = 0; i < length; i += 1) {
1147 tail[i >> 2] |= buff.charCodeAt(i) << ((i % 4) << 3);
1148 }
1149
1150 this._finish(tail, length);
1151 ret = hex(this._hash);
1152
1153 if (raw) {
1154 ret = hexToBinaryString(ret);
1155 }
1156
1157 this.reset();
1158
1159 return ret;
1160 };
1161
1162 /**
1163 * Resets the internal state of the computation.
1164 *
1165 * @return {SparkMD5} The instance itself
1166 */
1167 SparkMD5.prototype.reset = function () {
1168 this._buff = '';
1169 this._length = 0;
1170 this._hash = [1732584193, -271733879, -1732584194, 271733878];
1171
1172 return this;
1173 };
1174
1175 /**
1176 * Gets the internal state of the computation.
1177 *
1178 * @return {Object} The state
1179 */
1180 SparkMD5.prototype.getState = function () {
1181 return {
1182 buff: this._buff,
1183 length: this._length,
1184 hash: this._hash
1185 };
1186 };
1187
1188 /**
1189 * Gets the internal state of the computation.
1190 *
1191 * @param {Object} state The state
1192 *
1193 * @return {SparkMD5} The instance itself
1194 */
1195 SparkMD5.prototype.setState = function (state) {
1196 this._buff = state.buff;
1197 this._length = state.length;
1198 this._hash = state.hash;
1199
1200 return this;
1201 };
1202
1203 /**
1204 * Releases memory used by the incremental buffer and other additional
1205 * resources. If you plan to use the instance again, use reset instead.
1206 */
1207 SparkMD5.prototype.destroy = function () {
1208 delete this._hash;
1209 delete this._buff;
1210 delete this._length;
1211 };
1212
1213 /**
1214 * Finish the final calculation based on the tail.
1215 *
1216 * @param {Array} tail The tail (will be modified)
1217 * @param {Number} length The length of the remaining buffer
1218 */
1219 SparkMD5.prototype._finish = function (tail, length) {
1220 var i = length,
1221 tmp,
1222 lo,
1223 hi;
1224
1225 tail[i >> 2] |= 0x80 << ((i % 4) << 3);
1226 if (i > 55) {
1227 md5cycle(this._hash, tail);
1228 for (i = 0; i < 16; i += 1) {
1229 tail[i] = 0;
1230 }
1231 }
1232
1233 // Do the final computation based on the tail and length
1234 // Beware that the final length may not fit in 32 bits so we take care of that
1235 tmp = this._length * 8;
1236 tmp = tmp.toString(16).match(/(.*?)(.{0,8})$/);
1237 lo = parseInt(tmp[2], 16);
1238 hi = parseInt(tmp[1], 16) || 0;
1239
1240 tail[14] = lo;
1241 tail[15] = hi;
1242 md5cycle(this._hash, tail);
1243 };
1244
1245 /**
1246 * Performs the md5 hash on a string.
1247 * A conversion will be applied if utf8 string is detected.
1248 *
1249 * @param {String} str The string
1250 * @param {Boolean} raw True to get the raw string, false to get the hex string
1251 *
1252 * @return {String} The result
1253 */
1254 SparkMD5.hash = function (str, raw) {
1255 // Converts the string to utf8 bytes if necessary
1256 // Then compute it using the binary function
1257 return SparkMD5.hashBinary(toUtf8(str), raw);
1258 };
1259
1260 /**
1261 * Performs the md5 hash on a binary string.
1262 *
1263 * @param {String} content The binary string
1264 * @param {Boolean} raw True to get the raw string, false to get the hex string
1265 *
1266 * @return {String} The result
1267 */
1268 SparkMD5.hashBinary = function (content, raw) {
1269 var hash = md51(content),
1270 ret = hex(hash);
1271
1272 return raw ? hexToBinaryString(ret) : ret;
1273 };
1274
1275 // ---------------------------------------------------
1276
1277 /**
1278 * SparkMD5 OOP implementation for array buffers.
1279 *
1280 * Use this class to perform an incremental md5 ONLY for array buffers.
1281 */
1282 SparkMD5.ArrayBuffer = function () {
1283 // call reset to init the instance
1284 this.reset();
1285 };
1286
1287 /**
1288 * Appends an array buffer.
1289 *
1290 * @param {ArrayBuffer} arr The array to be appended
1291 *
1292 * @return {SparkMD5.ArrayBuffer} The instance itself
1293 */
1294 SparkMD5.ArrayBuffer.prototype.append = function (arr) {
1295 var buff = concatenateArrayBuffers(this._buff.buffer, arr, true),
1296 length = buff.length,
1297 i;
1298
1299 this._length += arr.byteLength;
1300
1301 for (i = 64; i <= length; i += 64) {
1302 md5cycle(this._hash, md5blk_array(buff.subarray(i - 64, i)));
1303 }
1304
1305 this._buff = (i - 64) < length ? new Uint8Array(buff.buffer.slice(i - 64)) : new Uint8Array(0);
1306
1307 return this;
1308 };
1309
1310 /**
1311 * Finishes the incremental computation, reseting the internal state and
1312 * returning the result.
1313 *
1314 * @param {Boolean} raw True to get the raw string, false to get the hex string
1315 *
1316 * @return {String} The result
1317 */
1318 SparkMD5.ArrayBuffer.prototype.end = function (raw) {
1319 var buff = this._buff,
1320 length = buff.length,
1321 tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
1322 i,
1323 ret;
1324
1325 for (i = 0; i < length; i += 1) {
1326 tail[i >> 2] |= buff[i] << ((i % 4) << 3);
1327 }
1328
1329 this._finish(tail, length);
1330 ret = hex(this._hash);
1331
1332 if (raw) {
1333 ret = hexToBinaryString(ret);
1334 }
1335
1336 this.reset();
1337
1338 return ret;
1339 };
1340
1341 /**
1342 * Resets the internal state of the computation.
1343 *
1344 * @return {SparkMD5.ArrayBuffer} The instance itself
1345 */
1346 SparkMD5.ArrayBuffer.prototype.reset = function () {
1347 this._buff = new Uint8Array(0);
1348 this._length = 0;
1349 this._hash = [1732584193, -271733879, -1732584194, 271733878];
1350
1351 return this;
1352 };
1353
1354 /**
1355 * Gets the internal state of the computation.
1356 *
1357 * @return {Object} The state
1358 */
1359 SparkMD5.ArrayBuffer.prototype.getState = function () {
1360 var state = SparkMD5.prototype.getState.call(this);
1361
1362 // Convert buffer to a string
1363 state.buff = arrayBuffer2Utf8Str(state.buff);
1364
1365 return state;
1366 };
1367
1368 /**
1369 * Gets the internal state of the computation.
1370 *
1371 * @param {Object} state The state
1372 *
1373 * @return {SparkMD5.ArrayBuffer} The instance itself
1374 */
1375 SparkMD5.ArrayBuffer.prototype.setState = function (state) {
1376 // Convert string to buffer
1377 state.buff = utf8Str2ArrayBuffer(state.buff, true);
1378
1379 return SparkMD5.prototype.setState.call(this, state);
1380 };
1381
1382 SparkMD5.ArrayBuffer.prototype.destroy = SparkMD5.prototype.destroy;
1383
1384 SparkMD5.ArrayBuffer.prototype._finish = SparkMD5.prototype._finish;
1385
1386 /**
1387 * Performs the md5 hash on an array buffer.
1388 *
1389 * @param {ArrayBuffer} arr The array buffer
1390 * @param {Boolean} raw True to get the raw string, false to get the hex one
1391 *
1392 * @return {String} The result
1393 */
1394 SparkMD5.ArrayBuffer.hash = function (arr, raw) {
1395 var hash = md51_array(new Uint8Array(arr)),
1396 ret = hex(hash);
1397
1398 return raw ? hexToBinaryString(ret) : ret;
1399 };
1400
1401 return SparkMD5;
1402}));
1403
1404},{}],6:[function(_dereq_,module,exports){
1405var v1 = _dereq_(9);
1406var v4 = _dereq_(10);
1407
1408var uuid = v4;
1409uuid.v1 = v1;
1410uuid.v4 = v4;
1411
1412module.exports = uuid;
1413
1414},{"10":10,"9":9}],7:[function(_dereq_,module,exports){
1415/**
1416 * Convert array of 16 byte values to UUID string format of the form:
1417 * XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
1418 */
1419var byteToHex = [];
1420for (var i = 0; i < 256; ++i) {
1421 byteToHex[i] = (i + 0x100).toString(16).substr(1);
1422}
1423
1424function bytesToUuid(buf, offset) {
1425 var i = offset || 0;
1426 var bth = byteToHex;
1427 return bth[buf[i++]] + bth[buf[i++]] +
1428 bth[buf[i++]] + bth[buf[i++]] + '-' +
1429 bth[buf[i++]] + bth[buf[i++]] + '-' +
1430 bth[buf[i++]] + bth[buf[i++]] + '-' +
1431 bth[buf[i++]] + bth[buf[i++]] + '-' +
1432 bth[buf[i++]] + bth[buf[i++]] +
1433 bth[buf[i++]] + bth[buf[i++]] +
1434 bth[buf[i++]] + bth[buf[i++]];
1435}
1436
1437module.exports = bytesToUuid;
1438
1439},{}],8:[function(_dereq_,module,exports){
1440// Unique ID creation requires a high quality random # generator. In the
1441// browser this is a little complicated due to unknown quality of Math.random()
1442// and inconsistent support for the `crypto` API. We do the best we can via
1443// feature-detection
1444
1445// getRandomValues needs to be invoked in a context where "this" is a Crypto implementation.
1446var getRandomValues = (typeof(crypto) != 'undefined' && crypto.getRandomValues.bind(crypto)) ||
1447 (typeof(msCrypto) != 'undefined' && msCrypto.getRandomValues.bind(msCrypto));
1448if (getRandomValues) {
1449 // WHATWG crypto RNG - http://wiki.whatwg.org/wiki/Crypto
1450 var rnds8 = new Uint8Array(16); // eslint-disable-line no-undef
1451
1452 module.exports = function whatwgRNG() {
1453 getRandomValues(rnds8);
1454 return rnds8;
1455 };
1456} else {
1457 // Math.random()-based (RNG)
1458 //
1459 // If all else fails, use Math.random(). It's fast, but is of unspecified
1460 // quality.
1461 var rnds = new Array(16);
1462
1463 module.exports = function mathRNG() {
1464 for (var i = 0, r; i < 16; i++) {
1465 if ((i & 0x03) === 0) r = Math.random() * 0x100000000;
1466 rnds[i] = r >>> ((i & 0x03) << 3) & 0xff;
1467 }
1468
1469 return rnds;
1470 };
1471}
1472
1473},{}],9:[function(_dereq_,module,exports){
1474var rng = _dereq_(8);
1475var bytesToUuid = _dereq_(7);
1476
1477// **`v1()` - Generate time-based UUID**
1478//
1479// Inspired by https://github.com/LiosK/UUID.js
1480// and http://docs.python.org/library/uuid.html
1481
1482var _nodeId;
1483var _clockseq;
1484
1485// Previous uuid creation time
1486var _lastMSecs = 0;
1487var _lastNSecs = 0;
1488
1489// See https://github.com/broofa/node-uuid for API details
1490function v1(options, buf, offset) {
1491 var i = buf && offset || 0;
1492 var b = buf || [];
1493
1494 options = options || {};
1495 var node = options.node || _nodeId;
1496 var clockseq = options.clockseq !== undefined ? options.clockseq : _clockseq;
1497
1498 // node and clockseq need to be initialized to random values if they're not
1499 // specified. We do this lazily to minimize issues related to insufficient
1500 // system entropy. See #189
1501 if (node == null || clockseq == null) {
1502 var seedBytes = rng();
1503 if (node == null) {
1504 // Per 4.5, create and 48-bit node id, (47 random bits + multicast bit = 1)
1505 node = _nodeId = [
1506 seedBytes[0] | 0x01,
1507 seedBytes[1], seedBytes[2], seedBytes[3], seedBytes[4], seedBytes[5]
1508 ];
1509 }
1510 if (clockseq == null) {
1511 // Per 4.2.2, randomize (14 bit) clockseq
1512 clockseq = _clockseq = (seedBytes[6] << 8 | seedBytes[7]) & 0x3fff;
1513 }
1514 }
1515
1516 // UUID timestamps are 100 nano-second units since the Gregorian epoch,
1517 // (1582-10-15 00:00). JSNumbers aren't precise enough for this, so
1518 // time is handled internally as 'msecs' (integer milliseconds) and 'nsecs'
1519 // (100-nanoseconds offset from msecs) since unix epoch, 1970-01-01 00:00.
1520 var msecs = options.msecs !== undefined ? options.msecs : new Date().getTime();
1521
1522 // Per 4.2.1.2, use count of uuid's generated during the current clock
1523 // cycle to simulate higher resolution clock
1524 var nsecs = options.nsecs !== undefined ? options.nsecs : _lastNSecs + 1;
1525
1526 // Time since last uuid creation (in msecs)
1527 var dt = (msecs - _lastMSecs) + (nsecs - _lastNSecs)/10000;
1528
1529 // Per 4.2.1.2, Bump clockseq on clock regression
1530 if (dt < 0 && options.clockseq === undefined) {
1531 clockseq = clockseq + 1 & 0x3fff;
1532 }
1533
1534 // Reset nsecs if clock regresses (new clockseq) or we've moved onto a new
1535 // time interval
1536 if ((dt < 0 || msecs > _lastMSecs) && options.nsecs === undefined) {
1537 nsecs = 0;
1538 }
1539
1540 // Per 4.2.1.2 Throw error if too many uuids are requested
1541 if (nsecs >= 10000) {
1542 throw new Error('uuid.v1(): Can\'t create more than 10M uuids/sec');
1543 }
1544
1545 _lastMSecs = msecs;
1546 _lastNSecs = nsecs;
1547 _clockseq = clockseq;
1548
1549 // Per 4.1.4 - Convert from unix epoch to Gregorian epoch
1550 msecs += 12219292800000;
1551
1552 // `time_low`
1553 var tl = ((msecs & 0xfffffff) * 10000 + nsecs) % 0x100000000;
1554 b[i++] = tl >>> 24 & 0xff;
1555 b[i++] = tl >>> 16 & 0xff;
1556 b[i++] = tl >>> 8 & 0xff;
1557 b[i++] = tl & 0xff;
1558
1559 // `time_mid`
1560 var tmh = (msecs / 0x100000000 * 10000) & 0xfffffff;
1561 b[i++] = tmh >>> 8 & 0xff;
1562 b[i++] = tmh & 0xff;
1563
1564 // `time_high_and_version`
1565 b[i++] = tmh >>> 24 & 0xf | 0x10; // include version
1566 b[i++] = tmh >>> 16 & 0xff;
1567
1568 // `clock_seq_hi_and_reserved` (Per 4.2.2 - include variant)
1569 b[i++] = clockseq >>> 8 | 0x80;
1570
1571 // `clock_seq_low`
1572 b[i++] = clockseq & 0xff;
1573
1574 // `node`
1575 for (var n = 0; n < 6; ++n) {
1576 b[i + n] = node[n];
1577 }
1578
1579 return buf ? buf : bytesToUuid(b);
1580}
1581
1582module.exports = v1;
1583
1584},{"7":7,"8":8}],10:[function(_dereq_,module,exports){
1585var rng = _dereq_(8);
1586var bytesToUuid = _dereq_(7);
1587
1588function v4(options, buf, offset) {
1589 var i = buf && offset || 0;
1590
1591 if (typeof(options) == 'string') {
1592 buf = options === 'binary' ? new Array(16) : null;
1593 options = null;
1594 }
1595 options = options || {};
1596
1597 var rnds = options.random || (options.rng || rng)();
1598
1599 // Per 4.4, set bits for version and `clock_seq_hi_and_reserved`
1600 rnds[6] = (rnds[6] & 0x0f) | 0x40;
1601 rnds[8] = (rnds[8] & 0x3f) | 0x80;
1602
1603 // Copy bytes to buffer, if provided
1604 if (buf) {
1605 for (var ii = 0; ii < 16; ++ii) {
1606 buf[i + ii] = rnds[ii];
1607 }
1608 }
1609
1610 return buf || bytesToUuid(rnds);
1611}
1612
1613module.exports = v4;
1614
1615},{"7":7,"8":8}],11:[function(_dereq_,module,exports){
1616(function (global){
1617'use strict';
1618
1619function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
1620
1621var immediate = _interopDefault(_dereq_(3));
1622var events = _dereq_(2);
1623var uuidV4 = _interopDefault(_dereq_(6));
1624var Md5 = _interopDefault(_dereq_(5));
1625var getArguments = _interopDefault(_dereq_(1));
1626var inherits = _interopDefault(_dereq_(4));
1627
1628function isBinaryObject(object) {
1629 return (typeof ArrayBuffer !== 'undefined' && object instanceof ArrayBuffer) ||
1630 (typeof Blob !== 'undefined' && object instanceof Blob);
1631}
1632
1633function cloneArrayBuffer(buff) {
1634 if (typeof buff.slice === 'function') {
1635 return buff.slice(0);
1636 }
1637 // IE10-11 slice() polyfill
1638 var target = new ArrayBuffer(buff.byteLength);
1639 var targetArray = new Uint8Array(target);
1640 var sourceArray = new Uint8Array(buff);
1641 targetArray.set(sourceArray);
1642 return target;
1643}
1644
1645function cloneBinaryObject(object) {
1646 if (object instanceof ArrayBuffer) {
1647 return cloneArrayBuffer(object);
1648 }
1649 var size = object.size;
1650 var type = object.type;
1651 // Blob
1652 if (typeof object.slice === 'function') {
1653 return object.slice(0, size, type);
1654 }
1655 // PhantomJS slice() replacement
1656 return object.webkitSlice(0, size, type);
1657}
1658
1659// most of this is borrowed from lodash.isPlainObject:
1660// https://github.com/fis-components/lodash.isplainobject/
1661// blob/29c358140a74f252aeb08c9eb28bef86f2217d4a/index.js
1662
1663var funcToString = Function.prototype.toString;
1664var objectCtorString = funcToString.call(Object);
1665
1666function isPlainObject(value) {
1667 var proto = Object.getPrototypeOf(value);
1668 /* istanbul ignore if */
1669 if (proto === null) { // not sure when this happens, but I guess it can
1670 return true;
1671 }
1672 var Ctor = proto.constructor;
1673 return (typeof Ctor == 'function' &&
1674 Ctor instanceof Ctor && funcToString.call(Ctor) == objectCtorString);
1675}
1676
1677function clone(object) {
1678 var newObject;
1679 var i;
1680 var len;
1681
1682 if (!object || typeof object !== 'object') {
1683 return object;
1684 }
1685
1686 if (Array.isArray(object)) {
1687 newObject = [];
1688 for (i = 0, len = object.length; i < len; i++) {
1689 newObject[i] = clone(object[i]);
1690 }
1691 return newObject;
1692 }
1693
1694 // special case: to avoid inconsistencies between IndexedDB
1695 // and other backends, we automatically stringify Dates
1696 if (object instanceof Date) {
1697 return object.toISOString();
1698 }
1699
1700 if (isBinaryObject(object)) {
1701 return cloneBinaryObject(object);
1702 }
1703
1704 if (!isPlainObject(object)) {
1705 return object; // don't clone objects like Workers
1706 }
1707
1708 newObject = {};
1709 for (i in object) {
1710 /* istanbul ignore else */
1711 if (Object.prototype.hasOwnProperty.call(object, i)) {
1712 var value = clone(object[i]);
1713 if (typeof value !== 'undefined') {
1714 newObject[i] = value;
1715 }
1716 }
1717 }
1718 return newObject;
1719}
1720
1721function once(fun) {
1722 var called = false;
1723 return getArguments(function (args) {
1724 /* istanbul ignore if */
1725 if (called) {
1726 // this is a smoke test and should never actually happen
1727 throw new Error('once called more than once');
1728 } else {
1729 called = true;
1730 fun.apply(this, args);
1731 }
1732 });
1733}
1734
1735function toPromise(func) {
1736 //create the function we will be returning
1737 return getArguments(function (args) {
1738 // Clone arguments
1739 args = clone(args);
1740 var self = this;
1741 // if the last argument is a function, assume its a callback
1742 var usedCB = (typeof args[args.length - 1] === 'function') ? args.pop() : false;
1743 var promise = new Promise(function (fulfill, reject) {
1744 var resp;
1745 try {
1746 var callback = once(function (err, mesg) {
1747 if (err) {
1748 reject(err);
1749 } else {
1750 fulfill(mesg);
1751 }
1752 });
1753 // create a callback for this invocation
1754 // apply the function in the orig context
1755 args.push(callback);
1756 resp = func.apply(self, args);
1757 if (resp && typeof resp.then === 'function') {
1758 fulfill(resp);
1759 }
1760 } catch (e) {
1761 reject(e);
1762 }
1763 });
1764 // if there is a callback, call it back
1765 if (usedCB) {
1766 promise.then(function (result) {
1767 usedCB(null, result);
1768 }, usedCB);
1769 }
1770 return promise;
1771 });
1772}
1773
1774function mangle(key) {
1775 return '$' + key;
1776}
1777function unmangle(key) {
1778 return key.substring(1);
1779}
1780function Map$1() {
1781 this._store = {};
1782}
1783Map$1.prototype.get = function (key) {
1784 var mangled = mangle(key);
1785 return this._store[mangled];
1786};
1787Map$1.prototype.set = function (key, value) {
1788 var mangled = mangle(key);
1789 this._store[mangled] = value;
1790 return true;
1791};
1792Map$1.prototype.has = function (key) {
1793 var mangled = mangle(key);
1794 return mangled in this._store;
1795};
1796Map$1.prototype["delete"] = function (key) {
1797 var mangled = mangle(key);
1798 var res = mangled in this._store;
1799 delete this._store[mangled];
1800 return res;
1801};
1802Map$1.prototype.forEach = function (cb) {
1803 var keys = Object.keys(this._store);
1804 for (var i = 0, len = keys.length; i < len; i++) {
1805 var key = keys[i];
1806 var value = this._store[key];
1807 key = unmangle(key);
1808 cb(value, key);
1809 }
1810};
1811Object.defineProperty(Map$1.prototype, 'size', {
1812 get: function () {
1813 return Object.keys(this._store).length;
1814 }
1815});
1816
1817function Set$1(array) {
1818 this._store = new Map$1();
1819
1820 // init with an array
1821 if (array && Array.isArray(array)) {
1822 for (var i = 0, len = array.length; i < len; i++) {
1823 this.add(array[i]);
1824 }
1825 }
1826}
1827Set$1.prototype.add = function (key) {
1828 return this._store.set(key, true);
1829};
1830Set$1.prototype.has = function (key) {
1831 return this._store.has(key);
1832};
1833Set$1.prototype.forEach = function (cb) {
1834 this._store.forEach(function (value, key) {
1835 cb(key);
1836 });
1837};
1838Object.defineProperty(Set$1.prototype, 'size', {
1839 get: function () {
1840 return this._store.size;
1841 }
1842});
1843
1844/* global Map,Set,Symbol */
1845// Based on https://kangax.github.io/compat-table/es6/ we can sniff out
1846// incomplete Map/Set implementations which would otherwise cause our tests to fail.
1847// Notably they fail in IE11 and iOS 8.4, which this prevents.
1848function supportsMapAndSet() {
1849 if (typeof Symbol === 'undefined' || typeof Map === 'undefined' || typeof Set === 'undefined') {
1850 return false;
1851 }
1852 var prop = Object.getOwnPropertyDescriptor(Map, Symbol.species);
1853 return prop && 'get' in prop && Map[Symbol.species] === Map;
1854}
1855
1856// based on https://github.com/montagejs/collections
1857
1858var ExportedSet;
1859var ExportedMap;
1860
1861{
1862 if (supportsMapAndSet()) { // prefer built-in Map/Set
1863 ExportedSet = Set;
1864 ExportedMap = Map;
1865 } else { // fall back to our polyfill
1866 ExportedSet = Set$1;
1867 ExportedMap = Map$1;
1868 }
1869}
1870
1871// like underscore/lodash _.pick()
1872function pick(obj, arr) {
1873 var res = {};
1874 for (var i = 0, len = arr.length; i < len; i++) {
1875 var prop = arr[i];
1876 if (prop in obj) {
1877 res[prop] = obj[prop];
1878 }
1879 }
1880 return res;
1881}
1882
1883var hasLocal;
1884
1885try {
1886 localStorage.setItem('_pouch_check_localstorage', 1);
1887 hasLocal = !!localStorage.getItem('_pouch_check_localstorage');
1888} catch (e) {
1889 hasLocal = false;
1890}
1891
1892function hasLocalStorage() {
1893 return hasLocal;
1894}
1895
1896// Custom nextTick() shim for browsers. In node, this will just be process.nextTick(). We
1897
1898inherits(Changes, events.EventEmitter);
1899
1900/* istanbul ignore next */
1901function attachBrowserEvents(self) {
1902 if (hasLocalStorage()) {
1903 addEventListener("storage", function (e) {
1904 self.emit(e.key);
1905 });
1906 }
1907}
1908
1909function Changes() {
1910 events.EventEmitter.call(this);
1911 this._listeners = {};
1912
1913 attachBrowserEvents(this);
1914}
1915Changes.prototype.addListener = function (dbName, id, db, opts) {
1916 /* istanbul ignore if */
1917 if (this._listeners[id]) {
1918 return;
1919 }
1920 var self = this;
1921 var inprogress = false;
1922 function eventFunction() {
1923 /* istanbul ignore if */
1924 if (!self._listeners[id]) {
1925 return;
1926 }
1927 if (inprogress) {
1928 inprogress = 'waiting';
1929 return;
1930 }
1931 inprogress = true;
1932 var changesOpts = pick(opts, [
1933 'style', 'include_docs', 'attachments', 'conflicts', 'filter',
1934 'doc_ids', 'view', 'since', 'query_params', 'binary', 'return_docs'
1935 ]);
1936
1937 /* istanbul ignore next */
1938 function onError() {
1939 inprogress = false;
1940 }
1941
1942 db.changes(changesOpts).on('change', function (c) {
1943 if (c.seq > opts.since && !opts.cancelled) {
1944 opts.since = c.seq;
1945 opts.onChange(c);
1946 }
1947 }).on('complete', function () {
1948 if (inprogress === 'waiting') {
1949 immediate(eventFunction);
1950 }
1951 inprogress = false;
1952 }).on('error', onError);
1953 }
1954 this._listeners[id] = eventFunction;
1955 this.on(dbName, eventFunction);
1956};
1957
1958Changes.prototype.removeListener = function (dbName, id) {
1959 /* istanbul ignore if */
1960 if (!(id in this._listeners)) {
1961 return;
1962 }
1963 events.EventEmitter.prototype.removeListener.call(this, dbName,
1964 this._listeners[id]);
1965 delete this._listeners[id];
1966};
1967
1968
1969/* istanbul ignore next */
1970Changes.prototype.notifyLocalWindows = function (dbName) {
1971 //do a useless change on a storage thing
1972 //in order to get other windows's listeners to activate
1973 if (hasLocalStorage()) {
1974 localStorage[dbName] = (localStorage[dbName] === "a") ? "b" : "a";
1975 }
1976};
1977
1978Changes.prototype.notify = function (dbName) {
1979 this.emit(dbName);
1980 this.notifyLocalWindows(dbName);
1981};
1982
1983function guardedConsole(method) {
1984 /* istanbul ignore else */
1985 if (typeof console !== 'undefined' && typeof console[method] === 'function') {
1986 var args = Array.prototype.slice.call(arguments, 1);
1987 console[method].apply(console, args);
1988 }
1989}
1990
1991var assign;
1992{
1993 if (typeof Object.assign === 'function') {
1994 assign = Object.assign;
1995 } else {
1996 // lite Object.assign polyfill based on
1997 // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
1998 assign = function (target) {
1999 var to = Object(target);
2000
2001 for (var index = 1; index < arguments.length; index++) {
2002 var nextSource = arguments[index];
2003
2004 if (nextSource != null) { // Skip over if undefined or null
2005 for (var nextKey in nextSource) {
2006 // Avoid bugs when hasOwnProperty is shadowed
2007 if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
2008 to[nextKey] = nextSource[nextKey];
2009 }
2010 }
2011 }
2012 }
2013 return to;
2014 };
2015 }
2016}
2017
2018var $inject_Object_assign = assign;
2019
2020inherits(PouchError, Error);
2021
2022function PouchError(status, error, reason) {
2023 Error.call(this, reason);
2024 this.status = status;
2025 this.name = error;
2026 this.message = reason;
2027 this.error = true;
2028}
2029
2030PouchError.prototype.toString = function () {
2031 return JSON.stringify({
2032 status: this.status,
2033 name: this.name,
2034 message: this.message,
2035 reason: this.reason
2036 });
2037};
2038
2039var UNAUTHORIZED = new PouchError(401, 'unauthorized', "Name or password is incorrect.");
2040var MISSING_BULK_DOCS = new PouchError(400, 'bad_request', "Missing JSON list of 'docs'");
2041var MISSING_DOC = new PouchError(404, 'not_found', 'missing');
2042var REV_CONFLICT = new PouchError(409, 'conflict', 'Document update conflict');
2043var INVALID_ID = new PouchError(400, 'bad_request', '_id field must contain a string');
2044var MISSING_ID = new PouchError(412, 'missing_id', '_id is required for puts');
2045var RESERVED_ID = new PouchError(400, 'bad_request', 'Only reserved document ids may start with underscore.');
2046var NOT_OPEN = new PouchError(412, 'precondition_failed', 'Database not open');
2047var UNKNOWN_ERROR = new PouchError(500, 'unknown_error', 'Database encountered an unknown error');
2048var BAD_ARG = new PouchError(500, 'badarg', 'Some query argument is invalid');
2049var INVALID_REQUEST = new PouchError(400, 'invalid_request', 'Request was invalid');
2050var QUERY_PARSE_ERROR = new PouchError(400, 'query_parse_error', 'Some query parameter is invalid');
2051var DOC_VALIDATION = new PouchError(500, 'doc_validation', 'Bad special document member');
2052var BAD_REQUEST = new PouchError(400, 'bad_request', 'Something wrong with the request');
2053var NOT_AN_OBJECT = new PouchError(400, 'bad_request', 'Document must be a JSON object');
2054var DB_MISSING = new PouchError(404, 'not_found', 'Database not found');
2055var IDB_ERROR = new PouchError(500, 'indexed_db_went_bad', 'unknown');
2056var WSQ_ERROR = new PouchError(500, 'web_sql_went_bad', 'unknown');
2057var LDB_ERROR = new PouchError(500, 'levelDB_went_went_bad', 'unknown');
2058var FORBIDDEN = new PouchError(403, 'forbidden', 'Forbidden by design doc validate_doc_update function');
2059var INVALID_REV = new PouchError(400, 'bad_request', 'Invalid rev format');
2060var FILE_EXISTS = new PouchError(412, 'file_exists', 'The database could not be created, the file already exists.');
2061var MISSING_STUB = new PouchError(412, 'missing_stub', 'A pre-existing attachment stub wasn\'t found');
2062var INVALID_URL = new PouchError(413, 'invalid_url', 'Provided URL is invalid');
2063
2064function generateErrorFromResponse(err) {
2065
2066 if (typeof err !== 'object') {
2067 var data = err;
2068 err = UNKNOWN_ERROR;
2069 err.data = data;
2070 }
2071
2072 if ('error' in err && err.error === 'conflict') {
2073 err.name = 'conflict';
2074 err.status = 409;
2075 }
2076
2077 if (!('name' in err)) {
2078 err.name = err.error || 'unknown';
2079 }
2080
2081 if (!('status' in err)) {
2082 err.status = 500;
2083 }
2084
2085 if (!('message' in err)) {
2086 err.message = err.message || err.reason;
2087 }
2088
2089 return err;
2090}
2091
2092function flatten(arrs) {
2093 var res = [];
2094 for (var i = 0, len = arrs.length; i < len; i++) {
2095 res = res.concat(arrs[i]);
2096 }
2097 return res;
2098}
2099
2100// shim for Function.prototype.name,
2101
2102// Checks if a PouchDB object is "remote" or not. This is
2103
2104function isRemote(db) {
2105 if (typeof db._remote === 'boolean') {
2106 return db._remote;
2107 }
2108 /* istanbul ignore next */
2109 if (typeof db.type === 'function') {
2110 guardedConsole('warn',
2111 'db.type() is deprecated and will be removed in ' +
2112 'a future version of PouchDB');
2113 return db.type() === 'http';
2114 }
2115 /* istanbul ignore next */
2116 return false;
2117}
2118
2119// originally parseUri 1.2.2, now patched by us
2120
2121// Based on https://github.com/alexdavid/scope-eval v0.0.3
2122
2123// this is essentially the "update sugar" function from daleharvey/pouchdb#1388
2124// the diffFun tells us what delta to apply to the doc. it either returns
2125// the doc, or false if it doesn't need to do an update after all
2126function upsert(db, docId, diffFun) {
2127 return new Promise(function (fulfill, reject) {
2128 db.get(docId, function (err, doc) {
2129 if (err) {
2130 /* istanbul ignore next */
2131 if (err.status !== 404) {
2132 return reject(err);
2133 }
2134 doc = {};
2135 }
2136
2137 // the user might change the _rev, so save it for posterity
2138 var docRev = doc._rev;
2139 var newDoc = diffFun(doc);
2140
2141 if (!newDoc) {
2142 // if the diffFun returns falsy, we short-circuit as
2143 // an optimization
2144 return fulfill({updated: false, rev: docRev});
2145 }
2146
2147 // users aren't allowed to modify these values,
2148 // so reset them here
2149 newDoc._id = docId;
2150 newDoc._rev = docRev;
2151 fulfill(tryAndPut(db, newDoc, diffFun));
2152 });
2153 });
2154}
2155
2156function tryAndPut(db, doc, diffFun) {
2157 return db.put(doc).then(function (res) {
2158 return {
2159 updated: true,
2160 rev: res.rev
2161 };
2162 }, function (err) {
2163 /* istanbul ignore next */
2164 if (err.status !== 409) {
2165 throw err;
2166 }
2167 return upsert(db, doc._id, diffFun);
2168 });
2169}
2170
2171var thisAtob = function (str) {
2172 return atob(str);
2173};
2174
2175// Abstracts constructing a Blob object, so it also works in older
2176// browsers that don't support the native Blob constructor (e.g.
2177// old QtWebKit versions, Android < 4.4).
2178function createBlob(parts, properties) {
2179 /* global BlobBuilder,MSBlobBuilder,MozBlobBuilder,WebKitBlobBuilder */
2180 parts = parts || [];
2181 properties = properties || {};
2182 try {
2183 return new Blob(parts, properties);
2184 } catch (e) {
2185 if (e.name !== "TypeError") {
2186 throw e;
2187 }
2188 var Builder = typeof BlobBuilder !== 'undefined' ? BlobBuilder :
2189 typeof MSBlobBuilder !== 'undefined' ? MSBlobBuilder :
2190 typeof MozBlobBuilder !== 'undefined' ? MozBlobBuilder :
2191 WebKitBlobBuilder;
2192 var builder = new Builder();
2193 for (var i = 0; i < parts.length; i += 1) {
2194 builder.append(parts[i]);
2195 }
2196 return builder.getBlob(properties.type);
2197 }
2198}
2199
2200// From http://stackoverflow.com/questions/14967647/ (continues on next line)
2201// encode-decode-image-with-base64-breaks-image (2013-04-21)
2202function binaryStringToArrayBuffer(bin) {
2203 var length = bin.length;
2204 var buf = new ArrayBuffer(length);
2205 var arr = new Uint8Array(buf);
2206 for (var i = 0; i < length; i++) {
2207 arr[i] = bin.charCodeAt(i);
2208 }
2209 return buf;
2210}
2211
2212function binStringToBluffer(binString, type) {
2213 return createBlob([binaryStringToArrayBuffer(binString)], {type: type});
2214}
2215
2216function b64ToBluffer(b64, type) {
2217 return binStringToBluffer(thisAtob(b64), type);
2218}
2219
2220//Can't find original post, but this is close
2221
2222// simplified API. universal browser support is assumed
2223
2224// this is not used in the browser
2225
2226var setImmediateShim = global.setImmediate || global.setTimeout;
2227
2228function stringMd5(string) {
2229 return Md5.hash(string);
2230}
2231
2232var uuid = uuidV4.v4;
2233
2234var h = Headers;
2235
2236// we restucture the supplied JSON considerably, because the official
2237// Mango API is very particular about a lot of this stuff, but we like
2238// to be liberal with what we accept in order to prevent mental
2239// breakdowns in our users
2240function massageCreateIndexRequest(requestDef) {
2241 requestDef = clone(requestDef);
2242
2243 if (!requestDef.index) {
2244 requestDef.index = {};
2245 }
2246
2247 ['type', 'name', 'ddoc'].forEach(function (key) {
2248 if (requestDef.index[key]) {
2249 requestDef[key] = requestDef.index[key];
2250 delete requestDef.index[key];
2251 }
2252 });
2253
2254 if (requestDef.fields) {
2255 requestDef.index.fields = requestDef.fields;
2256 delete requestDef.fields;
2257 }
2258
2259 if (!requestDef.type) {
2260 requestDef.type = 'json';
2261 }
2262 return requestDef;
2263}
2264
2265function dbFetch(db, path, opts, callback) {
2266 var status, ok;
2267 opts.headers = new h({'Content-type': 'application/json'});
2268 db.fetch(path, opts).then(function (response) {
2269 status = response.status;
2270 ok = response.ok;
2271 return response.json();
2272 }).then(function (json) {
2273 if (!ok) {
2274 json.status = status;
2275 var err = generateErrorFromResponse(json);
2276 callback(err);
2277 } else {
2278 callback(null, json);
2279 }
2280 })["catch"](callback);
2281}
2282
2283function createIndex(db, requestDef, callback) {
2284 requestDef = massageCreateIndexRequest(requestDef);
2285 dbFetch(db, '_index', {
2286 method: 'POST',
2287 body: JSON.stringify(requestDef)
2288 }, callback);
2289}
2290
2291function find(db, requestDef, callback) {
2292 dbFetch(db, '_find', {
2293 method: 'POST',
2294 body: JSON.stringify(requestDef)
2295 }, callback);
2296}
2297
2298function explain(db, requestDef, callback) {
2299 dbFetch(db, '_explain', {
2300 method: 'POST',
2301 body: JSON.stringify(requestDef)
2302 }, callback);
2303}
2304
2305function getIndexes(db, callback) {
2306 dbFetch(db, '_index', {
2307 method: 'GET'
2308 }, callback);
2309}
2310
2311function deleteIndex(db, indexDef, callback) {
2312
2313
2314 var ddoc = indexDef.ddoc;
2315 var type = indexDef.type || 'json';
2316 var name = indexDef.name;
2317
2318 if (!ddoc) {
2319 return callback(new Error('you must provide an index\'s ddoc'));
2320 }
2321
2322 if (!name) {
2323 return callback(new Error('you must provide an index\'s name'));
2324 }
2325
2326 var url = '_index/' + [ddoc, type, name].map(encodeURIComponent).join('/');
2327
2328 dbFetch(db, url, {method: 'DELETE'}, callback);
2329}
2330
2331// this would just be "return doc[field]", but fields
2332// can be "deep" due to dot notation
2333function getFieldFromDoc(doc, parsedField) {
2334 var value = doc;
2335 for (var i = 0, len = parsedField.length; i < len; i++) {
2336 var key = parsedField[i];
2337 value = value[key];
2338 if (!value) {
2339 break;
2340 }
2341 }
2342 return value;
2343}
2344
2345function setFieldInDoc(doc, parsedField, value) {
2346 for (var i = 0, len = parsedField.length; i < len-1; i++) {
2347 var elem = parsedField[i];
2348 doc = doc[elem] = {};
2349 }
2350 doc[parsedField[len-1]] = value;
2351}
2352
2353function compare(left, right) {
2354 return left < right ? -1 : left > right ? 1 : 0;
2355}
2356
2357// Converts a string in dot notation to an array of its components, with backslash escaping
2358function parseField(fieldName) {
2359 // fields may be deep (e.g. "foo.bar.baz"), so parse
2360 var fields = [];
2361 var current = '';
2362 for (var i = 0, len = fieldName.length; i < len; i++) {
2363 var ch = fieldName[i];
2364 if (ch === '.') {
2365 if (i > 0 && fieldName[i - 1] === '\\') { // escaped delimiter
2366 current = current.substring(0, current.length - 1) + '.';
2367 } else { // not escaped, so delimiter
2368 fields.push(current);
2369 current = '';
2370 }
2371 } else { // normal character
2372 current += ch;
2373 }
2374 }
2375 fields.push(current);
2376 return fields;
2377}
2378
2379var combinationFields = ['$or', '$nor', '$not'];
2380function isCombinationalField(field) {
2381 return combinationFields.indexOf(field) > -1;
2382}
2383
2384function getKey(obj) {
2385 return Object.keys(obj)[0];
2386}
2387
2388function getValue(obj) {
2389 return obj[getKey(obj)];
2390}
2391
2392
2393// flatten an array of selectors joined by an $and operator
2394function mergeAndedSelectors(selectors) {
2395
2396 // sort to ensure that e.g. if the user specified
2397 // $and: [{$gt: 'a'}, {$gt: 'b'}], then it's collapsed into
2398 // just {$gt: 'b'}
2399 var res = {};
2400
2401 selectors.forEach(function (selector) {
2402 Object.keys(selector).forEach(function (field) {
2403 var matcher = selector[field];
2404 if (typeof matcher !== 'object') {
2405 matcher = {$eq: matcher};
2406 }
2407
2408 if (isCombinationalField(field)) {
2409 if (matcher instanceof Array) {
2410 res[field] = matcher.map(function (m) {
2411 return mergeAndedSelectors([m]);
2412 });
2413 } else {
2414 res[field] = mergeAndedSelectors([matcher]);
2415 }
2416 } else {
2417 var fieldMatchers = res[field] = res[field] || {};
2418 Object.keys(matcher).forEach(function (operator) {
2419 var value = matcher[operator];
2420
2421 if (operator === '$gt' || operator === '$gte') {
2422 return mergeGtGte(operator, value, fieldMatchers);
2423 } else if (operator === '$lt' || operator === '$lte') {
2424 return mergeLtLte(operator, value, fieldMatchers);
2425 } else if (operator === '$ne') {
2426 return mergeNe(value, fieldMatchers);
2427 } else if (operator === '$eq') {
2428 return mergeEq(value, fieldMatchers);
2429 }
2430 fieldMatchers[operator] = value;
2431 });
2432 }
2433 });
2434 });
2435
2436 return res;
2437}
2438
2439
2440
2441// collapse logically equivalent gt/gte values
2442function mergeGtGte(operator, value, fieldMatchers) {
2443 if (typeof fieldMatchers.$eq !== 'undefined') {
2444 return; // do nothing
2445 }
2446 if (typeof fieldMatchers.$gte !== 'undefined') {
2447 if (operator === '$gte') {
2448 if (value > fieldMatchers.$gte) { // more specificity
2449 fieldMatchers.$gte = value;
2450 }
2451 } else { // operator === '$gt'
2452 if (value >= fieldMatchers.$gte) { // more specificity
2453 delete fieldMatchers.$gte;
2454 fieldMatchers.$gt = value;
2455 }
2456 }
2457 } else if (typeof fieldMatchers.$gt !== 'undefined') {
2458 if (operator === '$gte') {
2459 if (value > fieldMatchers.$gt) { // more specificity
2460 delete fieldMatchers.$gt;
2461 fieldMatchers.$gte = value;
2462 }
2463 } else { // operator === '$gt'
2464 if (value > fieldMatchers.$gt) { // more specificity
2465 fieldMatchers.$gt = value;
2466 }
2467 }
2468 } else {
2469 fieldMatchers[operator] = value;
2470 }
2471}
2472
2473// collapse logically equivalent lt/lte values
2474function mergeLtLte(operator, value, fieldMatchers) {
2475 if (typeof fieldMatchers.$eq !== 'undefined') {
2476 return; // do nothing
2477 }
2478 if (typeof fieldMatchers.$lte !== 'undefined') {
2479 if (operator === '$lte') {
2480 if (value < fieldMatchers.$lte) { // more specificity
2481 fieldMatchers.$lte = value;
2482 }
2483 } else { // operator === '$gt'
2484 if (value <= fieldMatchers.$lte) { // more specificity
2485 delete fieldMatchers.$lte;
2486 fieldMatchers.$lt = value;
2487 }
2488 }
2489 } else if (typeof fieldMatchers.$lt !== 'undefined') {
2490 if (operator === '$lte') {
2491 if (value < fieldMatchers.$lt) { // more specificity
2492 delete fieldMatchers.$lt;
2493 fieldMatchers.$lte = value;
2494 }
2495 } else { // operator === '$gt'
2496 if (value < fieldMatchers.$lt) { // more specificity
2497 fieldMatchers.$lt = value;
2498 }
2499 }
2500 } else {
2501 fieldMatchers[operator] = value;
2502 }
2503}
2504
2505// combine $ne values into one array
2506function mergeNe(value, fieldMatchers) {
2507 if ('$ne' in fieldMatchers) {
2508 // there are many things this could "not" be
2509 fieldMatchers.$ne.push(value);
2510 } else { // doesn't exist yet
2511 fieldMatchers.$ne = [value];
2512 }
2513}
2514
2515// add $eq into the mix
2516function mergeEq(value, fieldMatchers) {
2517 // these all have less specificity than the $eq
2518 // TODO: check for user errors here
2519 delete fieldMatchers.$gt;
2520 delete fieldMatchers.$gte;
2521 delete fieldMatchers.$lt;
2522 delete fieldMatchers.$lte;
2523 delete fieldMatchers.$ne;
2524 fieldMatchers.$eq = value;
2525}
2526
2527//#7458: execute function mergeAndedSelectors on nested $and
2528function mergeAndedSelectorsNested(obj) {
2529 for (var prop in obj) {
2530 if (Array.isArray(obj)) {
2531 for (var i in obj) {
2532 if (obj[i]['$and']) {
2533 obj[i] = mergeAndedSelectors(obj[i]['$and']);
2534 }
2535 }
2536 }
2537 var value = obj[prop];
2538 if (typeof value === 'object') {
2539 mergeAndedSelectorsNested(value); // <- recursive call
2540 }
2541 }
2542 return obj;
2543}
2544
2545//#7458: determine id $and is present in selector (at any level)
2546function isAndInSelector(obj, isAnd) {
2547 for (var prop in obj) {
2548 if (prop === '$and') {
2549 isAnd = true;
2550 }
2551 var value = obj[prop];
2552 if (typeof value === 'object') {
2553 isAnd = isAndInSelector(value, isAnd); // <- recursive call
2554 }
2555 }
2556 return isAnd;
2557}
2558
2559//
2560// normalize the selector
2561//
2562function massageSelector(input) {
2563 var result = clone(input);
2564 var wasAnded = false;
2565 //#7458: if $and is present in selector (at any level) merge nested $and
2566 if (isAndInSelector(result, false)) {
2567 result = mergeAndedSelectorsNested(result);
2568 if ('$and' in result) {
2569 result = mergeAndedSelectors(result['$and']);
2570 }
2571 wasAnded = true;
2572 }
2573
2574 ['$or', '$nor'].forEach(function (orOrNor) {
2575 if (orOrNor in result) {
2576 // message each individual selector
2577 // e.g. {foo: 'bar'} becomes {foo: {$eq: 'bar'}}
2578 result[orOrNor].forEach(function (subSelector) {
2579 var fields = Object.keys(subSelector);
2580 for (var i = 0; i < fields.length; i++) {
2581 var field = fields[i];
2582 var matcher = subSelector[field];
2583 if (typeof matcher !== 'object' || matcher === null) {
2584 subSelector[field] = {$eq: matcher};
2585 }
2586 }
2587 });
2588 }
2589 });
2590
2591 if ('$not' in result) {
2592 //This feels a little like forcing, but it will work for now,
2593 //I would like to come back to this and make the merging of selectors a little more generic
2594 result['$not'] = mergeAndedSelectors([result['$not']]);
2595 }
2596
2597 var fields = Object.keys(result);
2598
2599 for (var i = 0; i < fields.length; i++) {
2600 var field = fields[i];
2601 var matcher = result[field];
2602
2603 if (typeof matcher !== 'object' || matcher === null) {
2604 matcher = {$eq: matcher};
2605 } else if ('$ne' in matcher && !wasAnded) {
2606 // I put these in an array, since there may be more than one
2607 // but in the "mergeAnded" operation, I already take care of that
2608 matcher.$ne = [matcher.$ne];
2609 }
2610 result[field] = matcher;
2611 }
2612
2613 return result;
2614}
2615
2616function pad(str, padWith, upToLength) {
2617 var padding = '';
2618 var targetLength = upToLength - str.length;
2619 /* istanbul ignore next */
2620 while (padding.length < targetLength) {
2621 padding += padWith;
2622 }
2623 return padding;
2624}
2625
2626function padLeft(str, padWith, upToLength) {
2627 var padding = pad(str, padWith, upToLength);
2628 return padding + str;
2629}
2630
2631var MIN_MAGNITUDE = -324; // verified by -Number.MIN_VALUE
2632var MAGNITUDE_DIGITS = 3; // ditto
2633var SEP = ''; // set to '_' for easier debugging
2634
2635function collate(a, b) {
2636
2637 if (a === b) {
2638 return 0;
2639 }
2640
2641 a = normalizeKey(a);
2642 b = normalizeKey(b);
2643
2644 var ai = collationIndex(a);
2645 var bi = collationIndex(b);
2646 if ((ai - bi) !== 0) {
2647 return ai - bi;
2648 }
2649 switch (typeof a) {
2650 case 'number':
2651 return a - b;
2652 case 'boolean':
2653 return a < b ? -1 : 1;
2654 case 'string':
2655 return stringCollate(a, b);
2656 }
2657 return Array.isArray(a) ? arrayCollate(a, b) : objectCollate(a, b);
2658}
2659
2660// couch considers null/NaN/Infinity/-Infinity === undefined,
2661// for the purposes of mapreduce indexes. also, dates get stringified.
2662function normalizeKey(key) {
2663 switch (typeof key) {
2664 case 'undefined':
2665 return null;
2666 case 'number':
2667 if (key === Infinity || key === -Infinity || isNaN(key)) {
2668 return null;
2669 }
2670 return key;
2671 case 'object':
2672 var origKey = key;
2673 if (Array.isArray(key)) {
2674 var len = key.length;
2675 key = new Array(len);
2676 for (var i = 0; i < len; i++) {
2677 key[i] = normalizeKey(origKey[i]);
2678 }
2679 /* istanbul ignore next */
2680 } else if (key instanceof Date) {
2681 return key.toJSON();
2682 } else if (key !== null) { // generic object
2683 key = {};
2684 for (var k in origKey) {
2685 if (origKey.hasOwnProperty(k)) {
2686 var val = origKey[k];
2687 if (typeof val !== 'undefined') {
2688 key[k] = normalizeKey(val);
2689 }
2690 }
2691 }
2692 }
2693 }
2694 return key;
2695}
2696
2697function indexify(key) {
2698 if (key !== null) {
2699 switch (typeof key) {
2700 case 'boolean':
2701 return key ? 1 : 0;
2702 case 'number':
2703 return numToIndexableString(key);
2704 case 'string':
2705 // We've to be sure that key does not contain \u0000
2706 // Do order-preserving replacements:
2707 // 0 -> 1, 1
2708 // 1 -> 1, 2
2709 // 2 -> 2, 2
2710 /* eslint-disable no-control-regex */
2711 return key
2712 .replace(/\u0002/g, '\u0002\u0002')
2713 .replace(/\u0001/g, '\u0001\u0002')
2714 .replace(/\u0000/g, '\u0001\u0001');
2715 /* eslint-enable no-control-regex */
2716 case 'object':
2717 var isArray = Array.isArray(key);
2718 var arr = isArray ? key : Object.keys(key);
2719 var i = -1;
2720 var len = arr.length;
2721 var result = '';
2722 if (isArray) {
2723 while (++i < len) {
2724 result += toIndexableString(arr[i]);
2725 }
2726 } else {
2727 while (++i < len) {
2728 var objKey = arr[i];
2729 result += toIndexableString(objKey) +
2730 toIndexableString(key[objKey]);
2731 }
2732 }
2733 return result;
2734 }
2735 }
2736 return '';
2737}
2738
2739// convert the given key to a string that would be appropriate
2740// for lexical sorting, e.g. within a database, where the
2741// sorting is the same given by the collate() function.
2742function toIndexableString(key) {
2743 var zero = '\u0000';
2744 key = normalizeKey(key);
2745 return collationIndex(key) + SEP + indexify(key) + zero;
2746}
2747
2748function parseNumber(str, i) {
2749 var originalIdx = i;
2750 var num;
2751 var zero = str[i] === '1';
2752 if (zero) {
2753 num = 0;
2754 i++;
2755 } else {
2756 var neg = str[i] === '0';
2757 i++;
2758 var numAsString = '';
2759 var magAsString = str.substring(i, i + MAGNITUDE_DIGITS);
2760 var magnitude = parseInt(magAsString, 10) + MIN_MAGNITUDE;
2761 /* istanbul ignore next */
2762 if (neg) {
2763 magnitude = -magnitude;
2764 }
2765 i += MAGNITUDE_DIGITS;
2766 while (true) {
2767 var ch = str[i];
2768 if (ch === '\u0000') {
2769 break;
2770 } else {
2771 numAsString += ch;
2772 }
2773 i++;
2774 }
2775 numAsString = numAsString.split('.');
2776 if (numAsString.length === 1) {
2777 num = parseInt(numAsString, 10);
2778 } else {
2779 /* istanbul ignore next */
2780 num = parseFloat(numAsString[0] + '.' + numAsString[1]);
2781 }
2782 /* istanbul ignore next */
2783 if (neg) {
2784 num = num - 10;
2785 }
2786 /* istanbul ignore next */
2787 if (magnitude !== 0) {
2788 // parseFloat is more reliable than pow due to rounding errors
2789 // e.g. Number.MAX_VALUE would return Infinity if we did
2790 // num * Math.pow(10, magnitude);
2791 num = parseFloat(num + 'e' + magnitude);
2792 }
2793 }
2794 return {num: num, length : i - originalIdx};
2795}
2796
2797// move up the stack while parsing
2798// this function moved outside of parseIndexableString for performance
2799function pop(stack, metaStack) {
2800 var obj = stack.pop();
2801
2802 if (metaStack.length) {
2803 var lastMetaElement = metaStack[metaStack.length - 1];
2804 if (obj === lastMetaElement.element) {
2805 // popping a meta-element, e.g. an object whose value is another object
2806 metaStack.pop();
2807 lastMetaElement = metaStack[metaStack.length - 1];
2808 }
2809 var element = lastMetaElement.element;
2810 var lastElementIndex = lastMetaElement.index;
2811 if (Array.isArray(element)) {
2812 element.push(obj);
2813 } else if (lastElementIndex === stack.length - 2) { // obj with key+value
2814 var key = stack.pop();
2815 element[key] = obj;
2816 } else {
2817 stack.push(obj); // obj with key only
2818 }
2819 }
2820}
2821
2822function parseIndexableString(str) {
2823 var stack = [];
2824 var metaStack = []; // stack for arrays and objects
2825 var i = 0;
2826
2827 /*eslint no-constant-condition: ["error", { "checkLoops": false }]*/
2828 while (true) {
2829 var collationIndex = str[i++];
2830 if (collationIndex === '\u0000') {
2831 if (stack.length === 1) {
2832 return stack.pop();
2833 } else {
2834 pop(stack, metaStack);
2835 continue;
2836 }
2837 }
2838 switch (collationIndex) {
2839 case '1':
2840 stack.push(null);
2841 break;
2842 case '2':
2843 stack.push(str[i] === '1');
2844 i++;
2845 break;
2846 case '3':
2847 var parsedNum = parseNumber(str, i);
2848 stack.push(parsedNum.num);
2849 i += parsedNum.length;
2850 break;
2851 case '4':
2852 var parsedStr = '';
2853 /*eslint no-constant-condition: ["error", { "checkLoops": false }]*/
2854 while (true) {
2855 var ch = str[i];
2856 if (ch === '\u0000') {
2857 break;
2858 }
2859 parsedStr += ch;
2860 i++;
2861 }
2862 // perform the reverse of the order-preserving replacement
2863 // algorithm (see above)
2864 /* eslint-disable no-control-regex */
2865 parsedStr = parsedStr.replace(/\u0001\u0001/g, '\u0000')
2866 .replace(/\u0001\u0002/g, '\u0001')
2867 .replace(/\u0002\u0002/g, '\u0002');
2868 /* eslint-enable no-control-regex */
2869 stack.push(parsedStr);
2870 break;
2871 case '5':
2872 var arrayElement = { element: [], index: stack.length };
2873 stack.push(arrayElement.element);
2874 metaStack.push(arrayElement);
2875 break;
2876 case '6':
2877 var objElement = { element: {}, index: stack.length };
2878 stack.push(objElement.element);
2879 metaStack.push(objElement);
2880 break;
2881 /* istanbul ignore next */
2882 default:
2883 throw new Error(
2884 'bad collationIndex or unexpectedly reached end of input: ' +
2885 collationIndex);
2886 }
2887 }
2888}
2889
2890function arrayCollate(a, b) {
2891 var len = Math.min(a.length, b.length);
2892 for (var i = 0; i < len; i++) {
2893 var sort = collate(a[i], b[i]);
2894 if (sort !== 0) {
2895 return sort;
2896 }
2897 }
2898 return (a.length === b.length) ? 0 :
2899 (a.length > b.length) ? 1 : -1;
2900}
2901function stringCollate(a, b) {
2902 // See: https://github.com/daleharvey/pouchdb/issues/40
2903 // This is incompatible with the CouchDB implementation, but its the
2904 // best we can do for now
2905 return (a === b) ? 0 : ((a > b) ? 1 : -1);
2906}
2907function objectCollate(a, b) {
2908 var ak = Object.keys(a), bk = Object.keys(b);
2909 var len = Math.min(ak.length, bk.length);
2910 for (var i = 0; i < len; i++) {
2911 // First sort the keys
2912 var sort = collate(ak[i], bk[i]);
2913 if (sort !== 0) {
2914 return sort;
2915 }
2916 // if the keys are equal sort the values
2917 sort = collate(a[ak[i]], b[bk[i]]);
2918 if (sort !== 0) {
2919 return sort;
2920 }
2921
2922 }
2923 return (ak.length === bk.length) ? 0 :
2924 (ak.length > bk.length) ? 1 : -1;
2925}
2926// The collation is defined by erlangs ordered terms
2927// the atoms null, true, false come first, then numbers, strings,
2928// arrays, then objects
2929// null/undefined/NaN/Infinity/-Infinity are all considered null
2930function collationIndex(x) {
2931 var id = ['boolean', 'number', 'string', 'object'];
2932 var idx = id.indexOf(typeof x);
2933 //false if -1 otherwise true, but fast!!!!1
2934 if (~idx) {
2935 if (x === null) {
2936 return 1;
2937 }
2938 if (Array.isArray(x)) {
2939 return 5;
2940 }
2941 return idx < 3 ? (idx + 2) : (idx + 3);
2942 }
2943 /* istanbul ignore next */
2944 if (Array.isArray(x)) {
2945 return 5;
2946 }
2947}
2948
2949// conversion:
2950// x yyy zz...zz
2951// x = 0 for negative, 1 for 0, 2 for positive
2952// y = exponent (for negative numbers negated) moved so that it's >= 0
2953// z = mantisse
2954function numToIndexableString(num) {
2955
2956 if (num === 0) {
2957 return '1';
2958 }
2959
2960 // convert number to exponential format for easier and
2961 // more succinct string sorting
2962 var expFormat = num.toExponential().split(/e\+?/);
2963 var magnitude = parseInt(expFormat[1], 10);
2964
2965 var neg = num < 0;
2966
2967 var result = neg ? '0' : '2';
2968
2969 // first sort by magnitude
2970 // it's easier if all magnitudes are positive
2971 var magForComparison = ((neg ? -magnitude : magnitude) - MIN_MAGNITUDE);
2972 var magString = padLeft((magForComparison).toString(), '0', MAGNITUDE_DIGITS);
2973
2974 result += SEP + magString;
2975
2976 // then sort by the factor
2977 var factor = Math.abs(parseFloat(expFormat[0])); // [1..10)
2978 /* istanbul ignore next */
2979 if (neg) { // for negative reverse ordering
2980 factor = 10 - factor;
2981 }
2982
2983 var factorStr = factor.toFixed(20);
2984
2985 // strip zeros from the end
2986 factorStr = factorStr.replace(/\.?0+$/, '');
2987
2988 result += SEP + factorStr;
2989
2990 return result;
2991}
2992
2993// create a comparator based on the sort object
2994function createFieldSorter(sort) {
2995
2996 function getFieldValuesAsArray(doc) {
2997 return sort.map(function (sorting) {
2998 var fieldName = getKey(sorting);
2999 var parsedField = parseField(fieldName);
3000 var docFieldValue = getFieldFromDoc(doc, parsedField);
3001 return docFieldValue;
3002 });
3003 }
3004
3005 return function (aRow, bRow) {
3006 var aFieldValues = getFieldValuesAsArray(aRow.doc);
3007 var bFieldValues = getFieldValuesAsArray(bRow.doc);
3008 var collation = collate(aFieldValues, bFieldValues);
3009 if (collation !== 0) {
3010 return collation;
3011 }
3012 // this is what mango seems to do
3013 return compare(aRow.doc._id, bRow.doc._id);
3014 };
3015}
3016
3017function filterInMemoryFields(rows, requestDef, inMemoryFields) {
3018 rows = rows.filter(function (row) {
3019 return rowFilter(row.doc, requestDef.selector, inMemoryFields);
3020 });
3021
3022 if (requestDef.sort) {
3023 // in-memory sort
3024 var fieldSorter = createFieldSorter(requestDef.sort);
3025 rows = rows.sort(fieldSorter);
3026 if (typeof requestDef.sort[0] !== 'string' &&
3027 getValue(requestDef.sort[0]) === 'desc') {
3028 rows = rows.reverse();
3029 }
3030 }
3031
3032 if ('limit' in requestDef || 'skip' in requestDef) {
3033 // have to do the limit in-memory
3034 var skip = requestDef.skip || 0;
3035 var limit = ('limit' in requestDef ? requestDef.limit : rows.length) + skip;
3036 rows = rows.slice(skip, limit);
3037 }
3038 return rows;
3039}
3040
3041function rowFilter(doc, selector, inMemoryFields) {
3042 return inMemoryFields.every(function (field) {
3043 var matcher = selector[field];
3044 var parsedField = parseField(field);
3045 var docFieldValue = getFieldFromDoc(doc, parsedField);
3046 if (isCombinationalField(field)) {
3047 return matchCominationalSelector(field, matcher, doc);
3048 }
3049
3050 return matchSelector(matcher, doc, parsedField, docFieldValue);
3051 });
3052}
3053
3054function matchSelector(matcher, doc, parsedField, docFieldValue) {
3055 if (!matcher) {
3056 // no filtering necessary; this field is just needed for sorting
3057 return true;
3058 }
3059
3060 // is matcher an object, if so continue recursion
3061 if (typeof matcher === 'object') {
3062 return Object.keys(matcher).every(function (userOperator) {
3063 var userValue = matcher[userOperator];
3064 return match(userOperator, doc, userValue, parsedField, docFieldValue);
3065 });
3066 }
3067
3068 // no more depth, No need to recurse further
3069 return matcher === docFieldValue;
3070}
3071
3072function matchCominationalSelector(field, matcher, doc) {
3073
3074 if (field === '$or') {
3075 return matcher.some(function (orMatchers) {
3076 return rowFilter(doc, orMatchers, Object.keys(orMatchers));
3077 });
3078 }
3079
3080 if (field === '$not') {
3081 return !rowFilter(doc, matcher, Object.keys(matcher));
3082 }
3083
3084 //`$nor`
3085 return !matcher.find(function (orMatchers) {
3086 return rowFilter(doc, orMatchers, Object.keys(orMatchers));
3087 });
3088
3089}
3090
3091function match(userOperator, doc, userValue, parsedField, docFieldValue) {
3092 if (!matchers[userOperator]) {
3093 throw new Error('unknown operator "' + userOperator +
3094 '" - should be one of $eq, $lte, $lt, $gt, $gte, $exists, $ne, $in, ' +
3095 '$nin, $size, $mod, $regex, $elemMatch, $type, $allMatch or $all');
3096 }
3097 return matchers[userOperator](doc, userValue, parsedField, docFieldValue);
3098}
3099
3100function fieldExists(docFieldValue) {
3101 return typeof docFieldValue !== 'undefined' && docFieldValue !== null;
3102}
3103
3104function fieldIsNotUndefined(docFieldValue) {
3105 return typeof docFieldValue !== 'undefined';
3106}
3107
3108function modField(docFieldValue, userValue) {
3109 var divisor = userValue[0];
3110 var mod = userValue[1];
3111 if (divisor === 0) {
3112 throw new Error('Bad divisor, cannot divide by zero');
3113 }
3114
3115 if (parseInt(divisor, 10) !== divisor ) {
3116 throw new Error('Divisor is not an integer');
3117 }
3118
3119 if (parseInt(mod, 10) !== mod ) {
3120 throw new Error('Modulus is not an integer');
3121 }
3122
3123 if (parseInt(docFieldValue, 10) !== docFieldValue) {
3124 return false;
3125 }
3126
3127 return docFieldValue % divisor === mod;
3128}
3129
3130function arrayContainsValue(docFieldValue, userValue) {
3131 return userValue.some(function (val) {
3132 if (docFieldValue instanceof Array) {
3133 return docFieldValue.indexOf(val) > -1;
3134 }
3135
3136 return docFieldValue === val;
3137 });
3138}
3139
3140function arrayContainsAllValues(docFieldValue, userValue) {
3141 return userValue.every(function (val) {
3142 return docFieldValue.indexOf(val) > -1;
3143 });
3144}
3145
3146function arraySize(docFieldValue, userValue) {
3147 return docFieldValue.length === userValue;
3148}
3149
3150function regexMatch(docFieldValue, userValue) {
3151 var re = new RegExp(userValue);
3152
3153 return re.test(docFieldValue);
3154}
3155
3156function typeMatch(docFieldValue, userValue) {
3157
3158 switch (userValue) {
3159 case 'null':
3160 return docFieldValue === null;
3161 case 'boolean':
3162 return typeof (docFieldValue) === 'boolean';
3163 case 'number':
3164 return typeof (docFieldValue) === 'number';
3165 case 'string':
3166 return typeof (docFieldValue) === 'string';
3167 case 'array':
3168 return docFieldValue instanceof Array;
3169 case 'object':
3170 return ({}).toString.call(docFieldValue) === '[object Object]';
3171 }
3172
3173 throw new Error(userValue + ' not supported as a type.' +
3174 'Please use one of object, string, array, number, boolean or null.');
3175
3176}
3177
3178var matchers = {
3179
3180 '$elemMatch': function (doc, userValue, parsedField, docFieldValue) {
3181 if (!Array.isArray(docFieldValue)) {
3182 return false;
3183 }
3184
3185 if (docFieldValue.length === 0) {
3186 return false;
3187 }
3188
3189 if (typeof docFieldValue[0] === 'object') {
3190 return docFieldValue.some(function (val) {
3191 return rowFilter(val, userValue, Object.keys(userValue));
3192 });
3193 }
3194
3195 return docFieldValue.some(function (val) {
3196 return matchSelector(userValue, doc, parsedField, val);
3197 });
3198 },
3199
3200 '$allMatch': function (doc, userValue, parsedField, docFieldValue) {
3201 if (!Array.isArray(docFieldValue)) {
3202 return false;
3203 }
3204
3205 /* istanbul ignore next */
3206 if (docFieldValue.length === 0) {
3207 return false;
3208 }
3209
3210 if (typeof docFieldValue[0] === 'object') {
3211 return docFieldValue.every(function (val) {
3212 return rowFilter(val, userValue, Object.keys(userValue));
3213 });
3214 }
3215
3216 return docFieldValue.every(function (val) {
3217 return matchSelector(userValue, doc, parsedField, val);
3218 });
3219 },
3220
3221 '$eq': function (doc, userValue, parsedField, docFieldValue) {
3222 return fieldIsNotUndefined(docFieldValue) && collate(docFieldValue, userValue) === 0;
3223 },
3224
3225 '$gte': function (doc, userValue, parsedField, docFieldValue) {
3226 return fieldIsNotUndefined(docFieldValue) && collate(docFieldValue, userValue) >= 0;
3227 },
3228
3229 '$gt': function (doc, userValue, parsedField, docFieldValue) {
3230 return fieldIsNotUndefined(docFieldValue) && collate(docFieldValue, userValue) > 0;
3231 },
3232
3233 '$lte': function (doc, userValue, parsedField, docFieldValue) {
3234 return fieldIsNotUndefined(docFieldValue) && collate(docFieldValue, userValue) <= 0;
3235 },
3236
3237 '$lt': function (doc, userValue, parsedField, docFieldValue) {
3238 return fieldIsNotUndefined(docFieldValue) && collate(docFieldValue, userValue) < 0;
3239 },
3240
3241 '$exists': function (doc, userValue, parsedField, docFieldValue) {
3242 //a field that is null is still considered to exist
3243 if (userValue) {
3244 return fieldIsNotUndefined(docFieldValue);
3245 }
3246
3247 return !fieldIsNotUndefined(docFieldValue);
3248 },
3249
3250 '$mod': function (doc, userValue, parsedField, docFieldValue) {
3251 return fieldExists(docFieldValue) && modField(docFieldValue, userValue);
3252 },
3253
3254 '$ne': function (doc, userValue, parsedField, docFieldValue) {
3255 return userValue.every(function (neValue) {
3256 return collate(docFieldValue, neValue) !== 0;
3257 });
3258 },
3259 '$in': function (doc, userValue, parsedField, docFieldValue) {
3260 return fieldExists(docFieldValue) && arrayContainsValue(docFieldValue, userValue);
3261 },
3262
3263 '$nin': function (doc, userValue, parsedField, docFieldValue) {
3264 return fieldExists(docFieldValue) && !arrayContainsValue(docFieldValue, userValue);
3265 },
3266
3267 '$size': function (doc, userValue, parsedField, docFieldValue) {
3268 return fieldExists(docFieldValue) && arraySize(docFieldValue, userValue);
3269 },
3270
3271 '$all': function (doc, userValue, parsedField, docFieldValue) {
3272 return Array.isArray(docFieldValue) && arrayContainsAllValues(docFieldValue, userValue);
3273 },
3274
3275 '$regex': function (doc, userValue, parsedField, docFieldValue) {
3276 return fieldExists(docFieldValue) && regexMatch(docFieldValue, userValue);
3277 },
3278
3279 '$type': function (doc, userValue, parsedField, docFieldValue) {
3280 return typeMatch(docFieldValue, userValue);
3281 }
3282};
3283
3284function getArguments$1(fun) {
3285 return function () {
3286 var len = arguments.length;
3287 var args = new Array(len);
3288 var i = -1;
3289 while (++i < len) {
3290 args[i] = arguments[i];
3291 }
3292 return fun.call(this, args);
3293 };
3294}
3295
3296function callbackify(fun) {
3297 return getArguments$1(function (args) {
3298 var cb = args.pop();
3299 var promise = fun.apply(this, args);
3300 promisedCallback(promise, cb);
3301 return promise;
3302 });
3303}
3304
3305function promisedCallback(promise, callback) {
3306 promise.then(function (res) {
3307 immediate(function () {
3308 callback(null, res);
3309 });
3310 }, function (reason) {
3311 immediate(function () {
3312 callback(reason);
3313 });
3314 });
3315 return promise;
3316}
3317
3318var flatten$1 = getArguments$1(function (args) {
3319 var res = [];
3320 for (var i = 0, len = args.length; i < len; i++) {
3321 var subArr = args[i];
3322 if (Array.isArray(subArr)) {
3323 res = res.concat(flatten$1.apply(null, subArr));
3324 } else {
3325 res.push(subArr);
3326 }
3327 }
3328 return res;
3329});
3330
3331function mergeObjects(arr) {
3332 var res = {};
3333 for (var i = 0, len = arr.length; i < len; i++) {
3334 res = $inject_Object_assign(res, arr[i]);
3335 }
3336 return res;
3337}
3338
3339// Selects a list of fields defined in dot notation from one doc
3340// and copies them to a new doc. Like underscore _.pick but supports nesting.
3341function pick$1(obj, arr) {
3342 var res = {};
3343 for (var i = 0, len = arr.length; i < len; i++) {
3344 var parsedField = parseField(arr[i]);
3345 var value = getFieldFromDoc(obj, parsedField);
3346 if (typeof value !== 'undefined') {
3347 setFieldInDoc(res, parsedField, value);
3348 }
3349 }
3350 return res;
3351}
3352
3353// e.g. ['a'], ['a', 'b'] is true, but ['b'], ['a', 'b'] is false
3354function oneArrayIsSubArrayOfOther(left, right) {
3355
3356 for (var i = 0, len = Math.min(left.length, right.length); i < len; i++) {
3357 if (left[i] !== right[i]) {
3358 return false;
3359 }
3360 }
3361 return true;
3362}
3363
3364// e.g.['a', 'b', 'c'], ['a', 'b'] is false
3365function oneArrayIsStrictSubArrayOfOther(left, right) {
3366
3367 if (left.length > right.length) {
3368 return false;
3369 }
3370
3371 return oneArrayIsSubArrayOfOther(left, right);
3372}
3373
3374// same as above, but treat the left array as an unordered set
3375// e.g. ['b', 'a'], ['a', 'b', 'c'] is true, but ['c'], ['a', 'b', 'c'] is false
3376function oneSetIsSubArrayOfOther(left, right) {
3377 left = left.slice();
3378 for (var i = 0, len = right.length; i < len; i++) {
3379 var field = right[i];
3380 if (!left.length) {
3381 break;
3382 }
3383 var leftIdx = left.indexOf(field);
3384 if (leftIdx === -1) {
3385 return false;
3386 } else {
3387 left.splice(leftIdx, 1);
3388 }
3389 }
3390 return true;
3391}
3392
3393function arrayToObject(arr) {
3394 var res = {};
3395 for (var i = 0, len = arr.length; i < len; i++) {
3396 res[arr[i]] = true;
3397 }
3398 return res;
3399}
3400
3401function max(arr, fun) {
3402 var max = null;
3403 var maxScore = -1;
3404 for (var i = 0, len = arr.length; i < len; i++) {
3405 var element = arr[i];
3406 var score = fun(element);
3407 if (score > maxScore) {
3408 maxScore = score;
3409 max = element;
3410 }
3411 }
3412 return max;
3413}
3414
3415function arrayEquals(arr1, arr2) {
3416 if (arr1.length !== arr2.length) {
3417 return false;
3418 }
3419 for (var i = 0, len = arr1.length; i < len; i++) {
3420 if (arr1[i] !== arr2[i]) {
3421 return false;
3422 }
3423 }
3424 return true;
3425}
3426
3427function uniq(arr) {
3428 var obj = {};
3429 for (var i = 0; i < arr.length; i++) {
3430 obj['$' + arr[i]] = true;
3431 }
3432 return Object.keys(obj).map(function (key) {
3433 return key.substring(1);
3434 });
3435}
3436
3437/*
3438 * Simple task queue to sequentialize actions. Assumes
3439 * callbacks will eventually fire (once).
3440 */
3441
3442
3443function TaskQueue() {
3444 this.promise = new Promise(function (fulfill) {fulfill(); });
3445}
3446TaskQueue.prototype.add = function (promiseFactory) {
3447 this.promise = this.promise["catch"](function () {
3448 // just recover
3449 }).then(function () {
3450 return promiseFactory();
3451 });
3452 return this.promise;
3453};
3454TaskQueue.prototype.finish = function () {
3455 return this.promise;
3456};
3457
3458function stringify(input) {
3459 if (!input) {
3460 return 'undefined'; // backwards compat for empty reduce
3461 }
3462 // for backwards compat with mapreduce, functions/strings are stringified
3463 // as-is. everything else is JSON-stringified.
3464 switch (typeof input) {
3465 case 'function':
3466 // e.g. a mapreduce map
3467 return input.toString();
3468 case 'string':
3469 // e.g. a mapreduce built-in _reduce function
3470 return input.toString();
3471 default:
3472 // e.g. a JSON object in the case of mango queries
3473 return JSON.stringify(input);
3474 }
3475}
3476
3477/* create a string signature for a view so we can cache it and uniq it */
3478function createViewSignature(mapFun, reduceFun) {
3479 // the "undefined" part is for backwards compatibility
3480 return stringify(mapFun) + stringify(reduceFun) + 'undefined';
3481}
3482
3483function createView(sourceDB, viewName, mapFun, reduceFun, temporary, localDocName) {
3484 var viewSignature = createViewSignature(mapFun, reduceFun);
3485
3486 var cachedViews;
3487 if (!temporary) {
3488 // cache this to ensure we don't try to update the same view twice
3489 cachedViews = sourceDB._cachedViews = sourceDB._cachedViews || {};
3490 if (cachedViews[viewSignature]) {
3491 return cachedViews[viewSignature];
3492 }
3493 }
3494
3495 var promiseForView = sourceDB.info().then(function (info) {
3496
3497 var depDbName = info.db_name + '-mrview-' +
3498 (temporary ? 'temp' : stringMd5(viewSignature));
3499
3500 // save the view name in the source db so it can be cleaned up if necessary
3501 // (e.g. when the _design doc is deleted, remove all associated view data)
3502 function diffFunction(doc) {
3503 doc.views = doc.views || {};
3504 var fullViewName = viewName;
3505 if (fullViewName.indexOf('/') === -1) {
3506 fullViewName = viewName + '/' + viewName;
3507 }
3508 var depDbs = doc.views[fullViewName] = doc.views[fullViewName] || {};
3509 /* istanbul ignore if */
3510 if (depDbs[depDbName]) {
3511 return; // no update necessary
3512 }
3513 depDbs[depDbName] = true;
3514 return doc;
3515 }
3516 return upsert(sourceDB, '_local/' + localDocName, diffFunction).then(function () {
3517 return sourceDB.registerDependentDatabase(depDbName).then(function (res) {
3518 var db = res.db;
3519 db.auto_compaction = true;
3520 var view = {
3521 name: depDbName,
3522 db: db,
3523 sourceDB: sourceDB,
3524 adapter: sourceDB.adapter,
3525 mapFun: mapFun,
3526 reduceFun: reduceFun
3527 };
3528 return view.db.get('_local/lastSeq')["catch"](function (err) {
3529 /* istanbul ignore if */
3530 if (err.status !== 404) {
3531 throw err;
3532 }
3533 }).then(function (lastSeqDoc) {
3534 view.seq = lastSeqDoc ? lastSeqDoc.seq : 0;
3535 if (cachedViews) {
3536 view.db.once('destroyed', function () {
3537 delete cachedViews[viewSignature];
3538 });
3539 }
3540 return view;
3541 });
3542 });
3543 });
3544 });
3545
3546 if (cachedViews) {
3547 cachedViews[viewSignature] = promiseForView;
3548 }
3549 return promiseForView;
3550}
3551
3552function QueryParseError(message) {
3553 this.status = 400;
3554 this.name = 'query_parse_error';
3555 this.message = message;
3556 this.error = true;
3557 try {
3558 Error.captureStackTrace(this, QueryParseError);
3559 } catch (e) {}
3560}
3561
3562inherits(QueryParseError, Error);
3563
3564function NotFoundError(message) {
3565 this.status = 404;
3566 this.name = 'not_found';
3567 this.message = message;
3568 this.error = true;
3569 try {
3570 Error.captureStackTrace(this, NotFoundError);
3571 } catch (e) {}
3572}
3573
3574inherits(NotFoundError, Error);
3575
3576function BuiltInError(message) {
3577 this.status = 500;
3578 this.name = 'invalid_value';
3579 this.message = message;
3580 this.error = true;
3581 try {
3582 Error.captureStackTrace(this, BuiltInError);
3583 } catch (e) {}
3584}
3585
3586inherits(BuiltInError, Error);
3587
3588function promisedCallback$1(promise, callback) {
3589 if (callback) {
3590 promise.then(function (res) {
3591 immediate(function () {
3592 callback(null, res);
3593 });
3594 }, function (reason) {
3595 immediate(function () {
3596 callback(reason);
3597 });
3598 });
3599 }
3600 return promise;
3601}
3602
3603function callbackify$1(fun) {
3604 return getArguments(function (args) {
3605 var cb = args.pop();
3606 var promise = fun.apply(this, args);
3607 if (typeof cb === 'function') {
3608 promisedCallback$1(promise, cb);
3609 }
3610 return promise;
3611 });
3612}
3613
3614// Promise finally util similar to Q.finally
3615function fin(promise, finalPromiseFactory) {
3616 return promise.then(function (res) {
3617 return finalPromiseFactory().then(function () {
3618 return res;
3619 });
3620 }, function (reason) {
3621 return finalPromiseFactory().then(function () {
3622 throw reason;
3623 });
3624 });
3625}
3626
3627function sequentialize(queue, promiseFactory) {
3628 return function () {
3629 var args = arguments;
3630 var that = this;
3631 return queue.add(function () {
3632 return promiseFactory.apply(that, args);
3633 });
3634 };
3635}
3636
3637// uniq an array of strings, order not guaranteed
3638// similar to underscore/lodash _.uniq
3639function uniq$1(arr) {
3640 var theSet = new ExportedSet(arr);
3641 var result = new Array(theSet.size);
3642 var index = -1;
3643 theSet.forEach(function (value) {
3644 result[++index] = value;
3645 });
3646 return result;
3647}
3648
3649function mapToKeysArray(map) {
3650 var result = new Array(map.size);
3651 var index = -1;
3652 map.forEach(function (value, key) {
3653 result[++index] = key;
3654 });
3655 return result;
3656}
3657
3658var persistentQueues = {};
3659var tempViewQueue = new TaskQueue();
3660var CHANGES_BATCH_SIZE = 50;
3661
3662function parseViewName(name) {
3663 // can be either 'ddocname/viewname' or just 'viewname'
3664 // (where the ddoc name is the same)
3665 return name.indexOf('/') === -1 ? [name, name] : name.split('/');
3666}
3667
3668function isGenOne(changes) {
3669 // only return true if the current change is 1-
3670 // and there are no other leafs
3671 return changes.length === 1 && /^1-/.test(changes[0].rev);
3672}
3673
3674function emitError(db, e) {
3675 try {
3676 db.emit('error', e);
3677 } catch (err) {
3678 guardedConsole('error',
3679 'The user\'s map/reduce function threw an uncaught error.\n' +
3680 'You can debug this error by doing:\n' +
3681 'myDatabase.on(\'error\', function (err) { debugger; });\n' +
3682 'Please double-check your map/reduce function.');
3683 guardedConsole('error', e);
3684 }
3685}
3686
3687/**
3688 * Returns an "abstract" mapreduce object of the form:
3689 *
3690 * {
3691 * query: queryFun,
3692 * viewCleanup: viewCleanupFun
3693 * }
3694 *
3695 * Arguments are:
3696 *
3697 * localDoc: string
3698 * This is for the local doc that gets saved in order to track the
3699 * "dependent" DBs and clean them up for viewCleanup. It should be
3700 * unique, so that indexer plugins don't collide with each other.
3701 * mapper: function (mapFunDef, emit)
3702 * Returns a map function based on the mapFunDef, which in the case of
3703 * normal map/reduce is just the de-stringified function, but may be
3704 * something else, such as an object in the case of pouchdb-find.
3705 * reducer: function (reduceFunDef)
3706 * Ditto, but for reducing. Modules don't have to support reducing
3707 * (e.g. pouchdb-find).
3708 * ddocValidator: function (ddoc, viewName)
3709 * Throws an error if the ddoc or viewName is not valid.
3710 * This could be a way to communicate to the user that the configuration for the
3711 * indexer is invalid.
3712 */
3713function createAbstractMapReduce(localDocName, mapper, reducer, ddocValidator) {
3714
3715 function tryMap(db, fun, doc) {
3716 // emit an event if there was an error thrown by a map function.
3717 // putting try/catches in a single function also avoids deoptimizations.
3718 try {
3719 fun(doc);
3720 } catch (e) {
3721 emitError(db, e);
3722 }
3723 }
3724
3725 function tryReduce(db, fun, keys, values, rereduce) {
3726 // same as above, but returning the result or an error. there are two separate
3727 // functions to avoid extra memory allocations since the tryCode() case is used
3728 // for custom map functions (common) vs this function, which is only used for
3729 // custom reduce functions (rare)
3730 try {
3731 return {output : fun(keys, values, rereduce)};
3732 } catch (e) {
3733 emitError(db, e);
3734 return {error: e};
3735 }
3736 }
3737
3738 function sortByKeyThenValue(x, y) {
3739 var keyCompare = collate(x.key, y.key);
3740 return keyCompare !== 0 ? keyCompare : collate(x.value, y.value);
3741 }
3742
3743 function sliceResults(results, limit, skip) {
3744 skip = skip || 0;
3745 if (typeof limit === 'number') {
3746 return results.slice(skip, limit + skip);
3747 } else if (skip > 0) {
3748 return results.slice(skip);
3749 }
3750 return results;
3751 }
3752
3753 function rowToDocId(row) {
3754 var val = row.value;
3755 // Users can explicitly specify a joined doc _id, or it
3756 // defaults to the doc _id that emitted the key/value.
3757 var docId = (val && typeof val === 'object' && val._id) || row.id;
3758 return docId;
3759 }
3760
3761 function readAttachmentsAsBlobOrBuffer(res) {
3762 res.rows.forEach(function (row) {
3763 var atts = row.doc && row.doc._attachments;
3764 if (!atts) {
3765 return;
3766 }
3767 Object.keys(atts).forEach(function (filename) {
3768 var att = atts[filename];
3769 atts[filename].data = b64ToBluffer(att.data, att.content_type);
3770 });
3771 });
3772 }
3773
3774 function postprocessAttachments(opts) {
3775 return function (res) {
3776 if (opts.include_docs && opts.attachments && opts.binary) {
3777 readAttachmentsAsBlobOrBuffer(res);
3778 }
3779 return res;
3780 };
3781 }
3782
3783 function addHttpParam(paramName, opts, params, asJson) {
3784 // add an http param from opts to params, optionally json-encoded
3785 var val = opts[paramName];
3786 if (typeof val !== 'undefined') {
3787 if (asJson) {
3788 val = encodeURIComponent(JSON.stringify(val));
3789 }
3790 params.push(paramName + '=' + val);
3791 }
3792 }
3793
3794 function coerceInteger(integerCandidate) {
3795 if (typeof integerCandidate !== 'undefined') {
3796 var asNumber = Number(integerCandidate);
3797 // prevents e.g. '1foo' or '1.1' being coerced to 1
3798 if (!isNaN(asNumber) && asNumber === parseInt(integerCandidate, 10)) {
3799 return asNumber;
3800 } else {
3801 return integerCandidate;
3802 }
3803 }
3804 }
3805
3806 function coerceOptions(opts) {
3807 opts.group_level = coerceInteger(opts.group_level);
3808 opts.limit = coerceInteger(opts.limit);
3809 opts.skip = coerceInteger(opts.skip);
3810 return opts;
3811 }
3812
3813 function checkPositiveInteger(number) {
3814 if (number) {
3815 if (typeof number !== 'number') {
3816 return new QueryParseError('Invalid value for integer: "' +
3817 number + '"');
3818 }
3819 if (number < 0) {
3820 return new QueryParseError('Invalid value for positive integer: ' +
3821 '"' + number + '"');
3822 }
3823 }
3824 }
3825
3826 function checkQueryParseError(options, fun) {
3827 var startkeyName = options.descending ? 'endkey' : 'startkey';
3828 var endkeyName = options.descending ? 'startkey' : 'endkey';
3829
3830 if (typeof options[startkeyName] !== 'undefined' &&
3831 typeof options[endkeyName] !== 'undefined' &&
3832 collate(options[startkeyName], options[endkeyName]) > 0) {
3833 throw new QueryParseError('No rows can match your key range, ' +
3834 'reverse your start_key and end_key or set {descending : true}');
3835 } else if (fun.reduce && options.reduce !== false) {
3836 if (options.include_docs) {
3837 throw new QueryParseError('{include_docs:true} is invalid for reduce');
3838 } else if (options.keys && options.keys.length > 1 &&
3839 !options.group && !options.group_level) {
3840 throw new QueryParseError('Multi-key fetches for reduce views must use ' +
3841 '{group: true}');
3842 }
3843 }
3844 ['group_level', 'limit', 'skip'].forEach(function (optionName) {
3845 var error = checkPositiveInteger(options[optionName]);
3846 if (error) {
3847 throw error;
3848 }
3849 });
3850 }
3851
3852 function httpQuery(db, fun, opts) {
3853 // List of parameters to add to the PUT request
3854 var params = [];
3855 var body;
3856 var method = 'GET';
3857 var ok, status;
3858
3859 // If opts.reduce exists and is defined, then add it to the list
3860 // of parameters.
3861 // If reduce=false then the results are that of only the map function
3862 // not the final result of map and reduce.
3863 addHttpParam('reduce', opts, params);
3864 addHttpParam('include_docs', opts, params);
3865 addHttpParam('attachments', opts, params);
3866 addHttpParam('limit', opts, params);
3867 addHttpParam('descending', opts, params);
3868 addHttpParam('group', opts, params);
3869 addHttpParam('group_level', opts, params);
3870 addHttpParam('skip', opts, params);
3871 addHttpParam('stale', opts, params);
3872 addHttpParam('conflicts', opts, params);
3873 addHttpParam('startkey', opts, params, true);
3874 addHttpParam('start_key', opts, params, true);
3875 addHttpParam('endkey', opts, params, true);
3876 addHttpParam('end_key', opts, params, true);
3877 addHttpParam('inclusive_end', opts, params);
3878 addHttpParam('key', opts, params, true);
3879 addHttpParam('update_seq', opts, params);
3880
3881 // Format the list of parameters into a valid URI query string
3882 params = params.join('&');
3883 params = params === '' ? '' : '?' + params;
3884
3885 // If keys are supplied, issue a POST to circumvent GET query string limits
3886 // see http://wiki.apache.org/couchdb/HTTP_view_API#Querying_Options
3887 if (typeof opts.keys !== 'undefined') {
3888 var MAX_URL_LENGTH = 2000;
3889 // according to http://stackoverflow.com/a/417184/680742,
3890 // the de facto URL length limit is 2000 characters
3891
3892 var keysAsString =
3893 'keys=' + encodeURIComponent(JSON.stringify(opts.keys));
3894 if (keysAsString.length + params.length + 1 <= MAX_URL_LENGTH) {
3895 // If the keys are short enough, do a GET. we do this to work around
3896 // Safari not understanding 304s on POSTs (see pouchdb/pouchdb#1239)
3897 params += (params[0] === '?' ? '&' : '?') + keysAsString;
3898 } else {
3899 method = 'POST';
3900 if (typeof fun === 'string') {
3901 body = {keys: opts.keys};
3902 } else { // fun is {map : mapfun}, so append to this
3903 fun.keys = opts.keys;
3904 }
3905 }
3906 }
3907
3908 // We are referencing a query defined in the design doc
3909 if (typeof fun === 'string') {
3910 var parts = parseViewName(fun);
3911 return db.fetch('_design/' + parts[0] + '/_view/' + parts[1] + params, {
3912 headers: new h({'Content-Type': 'application/json'}),
3913 method: method,
3914 body: JSON.stringify(body)
3915 }).then(function (response) {
3916 ok = response.ok;
3917 status = response.status;
3918 return response.json();
3919 }).then(function (result) {
3920 if (!ok) {
3921 result.status = status;
3922 throw generateErrorFromResponse(result);
3923 }
3924 // fail the entire request if the result contains an error
3925 result.rows.forEach(function (row) {
3926 /* istanbul ignore if */
3927 if (row.value && row.value.error && row.value.error === "builtin_reduce_error") {
3928 throw new Error(row.reason);
3929 }
3930 });
3931 return result;
3932 }).then(postprocessAttachments(opts));
3933 }
3934
3935 // We are using a temporary view, terrible for performance, good for testing
3936 body = body || {};
3937 Object.keys(fun).forEach(function (key) {
3938 if (Array.isArray(fun[key])) {
3939 body[key] = fun[key];
3940 } else {
3941 body[key] = fun[key].toString();
3942 }
3943 });
3944
3945 return db.fetch('_temp_view' + params, {
3946 headers: new h({'Content-Type': 'application/json'}),
3947 method: 'POST',
3948 body: JSON.stringify(body)
3949 }).then(function (response) {
3950 ok = response.ok;
3951 status = response.status;
3952 return response.json();
3953 }).then(function (result) {
3954 if (!ok) {
3955 result.status = status;
3956 throw generateErrorFromResponse(result);
3957 }
3958 return result;
3959 }).then(postprocessAttachments(opts));
3960 }
3961
3962 // custom adapters can define their own api._query
3963 // and override the default behavior
3964 /* istanbul ignore next */
3965 function customQuery(db, fun, opts) {
3966 return new Promise(function (resolve, reject) {
3967 db._query(fun, opts, function (err, res) {
3968 if (err) {
3969 return reject(err);
3970 }
3971 resolve(res);
3972 });
3973 });
3974 }
3975
3976 // custom adapters can define their own api._viewCleanup
3977 // and override the default behavior
3978 /* istanbul ignore next */
3979 function customViewCleanup(db) {
3980 return new Promise(function (resolve, reject) {
3981 db._viewCleanup(function (err, res) {
3982 if (err) {
3983 return reject(err);
3984 }
3985 resolve(res);
3986 });
3987 });
3988 }
3989
3990 function defaultsTo(value) {
3991 return function (reason) {
3992 /* istanbul ignore else */
3993 if (reason.status === 404) {
3994 return value;
3995 } else {
3996 throw reason;
3997 }
3998 };
3999 }
4000
4001 // returns a promise for a list of docs to update, based on the input docId.
4002 // the order doesn't matter, because post-3.2.0, bulkDocs
4003 // is an atomic operation in all three adapters.
4004 function getDocsToPersist(docId, view, docIdsToChangesAndEmits) {
4005 var metaDocId = '_local/doc_' + docId;
4006 var defaultMetaDoc = {_id: metaDocId, keys: []};
4007 var docData = docIdsToChangesAndEmits.get(docId);
4008 var indexableKeysToKeyValues = docData[0];
4009 var changes = docData[1];
4010
4011 function getMetaDoc() {
4012 if (isGenOne(changes)) {
4013 // generation 1, so we can safely assume initial state
4014 // for performance reasons (avoids unnecessary GETs)
4015 return Promise.resolve(defaultMetaDoc);
4016 }
4017 return view.db.get(metaDocId)["catch"](defaultsTo(defaultMetaDoc));
4018 }
4019
4020 function getKeyValueDocs(metaDoc) {
4021 if (!metaDoc.keys.length) {
4022 // no keys, no need for a lookup
4023 return Promise.resolve({rows: []});
4024 }
4025 return view.db.allDocs({
4026 keys: metaDoc.keys,
4027 include_docs: true
4028 });
4029 }
4030
4031 function processKeyValueDocs(metaDoc, kvDocsRes) {
4032 var kvDocs = [];
4033 var oldKeys = new ExportedSet();
4034
4035 for (var i = 0, len = kvDocsRes.rows.length; i < len; i++) {
4036 var row = kvDocsRes.rows[i];
4037 var doc = row.doc;
4038 if (!doc) { // deleted
4039 continue;
4040 }
4041 kvDocs.push(doc);
4042 oldKeys.add(doc._id);
4043 doc._deleted = !indexableKeysToKeyValues.has(doc._id);
4044 if (!doc._deleted) {
4045 var keyValue = indexableKeysToKeyValues.get(doc._id);
4046 if ('value' in keyValue) {
4047 doc.value = keyValue.value;
4048 }
4049 }
4050 }
4051 var newKeys = mapToKeysArray(indexableKeysToKeyValues);
4052 newKeys.forEach(function (key) {
4053 if (!oldKeys.has(key)) {
4054 // new doc
4055 var kvDoc = {
4056 _id: key
4057 };
4058 var keyValue = indexableKeysToKeyValues.get(key);
4059 if ('value' in keyValue) {
4060 kvDoc.value = keyValue.value;
4061 }
4062 kvDocs.push(kvDoc);
4063 }
4064 });
4065 metaDoc.keys = uniq$1(newKeys.concat(metaDoc.keys));
4066 kvDocs.push(metaDoc);
4067
4068 return kvDocs;
4069 }
4070
4071 return getMetaDoc().then(function (metaDoc) {
4072 return getKeyValueDocs(metaDoc).then(function (kvDocsRes) {
4073 return processKeyValueDocs(metaDoc, kvDocsRes);
4074 });
4075 });
4076 }
4077
4078 // updates all emitted key/value docs and metaDocs in the mrview database
4079 // for the given batch of documents from the source database
4080 function saveKeyValues(view, docIdsToChangesAndEmits, seq) {
4081 var seqDocId = '_local/lastSeq';
4082 return view.db.get(seqDocId)[
4083 "catch"](defaultsTo({_id: seqDocId, seq: 0}))
4084 .then(function (lastSeqDoc) {
4085 var docIds = mapToKeysArray(docIdsToChangesAndEmits);
4086 return Promise.all(docIds.map(function (docId) {
4087 return getDocsToPersist(docId, view, docIdsToChangesAndEmits);
4088 })).then(function (listOfDocsToPersist) {
4089 var docsToPersist = flatten(listOfDocsToPersist);
4090 lastSeqDoc.seq = seq;
4091 docsToPersist.push(lastSeqDoc);
4092 // write all docs in a single operation, update the seq once
4093 return view.db.bulkDocs({docs : docsToPersist});
4094 });
4095 });
4096 }
4097
4098 function getQueue(view) {
4099 var viewName = typeof view === 'string' ? view : view.name;
4100 var queue = persistentQueues[viewName];
4101 if (!queue) {
4102 queue = persistentQueues[viewName] = new TaskQueue();
4103 }
4104 return queue;
4105 }
4106
4107 function updateView(view) {
4108 return sequentialize(getQueue(view), function () {
4109 return updateViewInQueue(view);
4110 })();
4111 }
4112
4113 function updateViewInQueue(view) {
4114 // bind the emit function once
4115 var mapResults;
4116 var doc;
4117
4118 function emit(key, value) {
4119 var output = {id: doc._id, key: normalizeKey(key)};
4120 // Don't explicitly store the value unless it's defined and non-null.
4121 // This saves on storage space, because often people don't use it.
4122 if (typeof value !== 'undefined' && value !== null) {
4123 output.value = normalizeKey(value);
4124 }
4125 mapResults.push(output);
4126 }
4127
4128 var mapFun = mapper(view.mapFun, emit);
4129
4130 var currentSeq = view.seq || 0;
4131
4132 function processChange(docIdsToChangesAndEmits, seq) {
4133 return function () {
4134 return saveKeyValues(view, docIdsToChangesAndEmits, seq);
4135 };
4136 }
4137
4138 var queue = new TaskQueue();
4139
4140 function processNextBatch() {
4141 return view.sourceDB.changes({
4142 return_docs: true,
4143 conflicts: true,
4144 include_docs: true,
4145 style: 'all_docs',
4146 since: currentSeq,
4147 limit: CHANGES_BATCH_SIZE
4148 }).then(processBatch);
4149 }
4150
4151 function processBatch(response) {
4152 var results = response.results;
4153 if (!results.length) {
4154 return;
4155 }
4156 var docIdsToChangesAndEmits = createDocIdsToChangesAndEmits(results);
4157 queue.add(processChange(docIdsToChangesAndEmits, currentSeq));
4158 if (results.length < CHANGES_BATCH_SIZE) {
4159 return;
4160 }
4161 return processNextBatch();
4162 }
4163
4164 function createDocIdsToChangesAndEmits(results) {
4165 var docIdsToChangesAndEmits = new ExportedMap();
4166 for (var i = 0, len = results.length; i < len; i++) {
4167 var change = results[i];
4168 if (change.doc._id[0] !== '_') {
4169 mapResults = [];
4170 doc = change.doc;
4171
4172 if (!doc._deleted) {
4173 tryMap(view.sourceDB, mapFun, doc);
4174 }
4175 mapResults.sort(sortByKeyThenValue);
4176
4177 var indexableKeysToKeyValues = createIndexableKeysToKeyValues(mapResults);
4178 docIdsToChangesAndEmits.set(change.doc._id, [
4179 indexableKeysToKeyValues,
4180 change.changes
4181 ]);
4182 }
4183 currentSeq = change.seq;
4184 }
4185 return docIdsToChangesAndEmits;
4186 }
4187
4188 function createIndexableKeysToKeyValues(mapResults) {
4189 var indexableKeysToKeyValues = new ExportedMap();
4190 var lastKey;
4191 for (var i = 0, len = mapResults.length; i < len; i++) {
4192 var emittedKeyValue = mapResults[i];
4193 var complexKey = [emittedKeyValue.key, emittedKeyValue.id];
4194 if (i > 0 && collate(emittedKeyValue.key, lastKey) === 0) {
4195 complexKey.push(i); // dup key+id, so make it unique
4196 }
4197 indexableKeysToKeyValues.set(toIndexableString(complexKey), emittedKeyValue);
4198 lastKey = emittedKeyValue.key;
4199 }
4200 return indexableKeysToKeyValues;
4201 }
4202
4203 return processNextBatch().then(function () {
4204 return queue.finish();
4205 }).then(function () {
4206 view.seq = currentSeq;
4207 });
4208 }
4209
4210 function reduceView(view, results, options) {
4211 if (options.group_level === 0) {
4212 delete options.group_level;
4213 }
4214
4215 var shouldGroup = options.group || options.group_level;
4216
4217 var reduceFun = reducer(view.reduceFun);
4218
4219 var groups = [];
4220 var lvl = isNaN(options.group_level) ? Number.POSITIVE_INFINITY :
4221 options.group_level;
4222 results.forEach(function (e) {
4223 var last = groups[groups.length - 1];
4224 var groupKey = shouldGroup ? e.key : null;
4225
4226 // only set group_level for array keys
4227 if (shouldGroup && Array.isArray(groupKey)) {
4228 groupKey = groupKey.slice(0, lvl);
4229 }
4230
4231 if (last && collate(last.groupKey, groupKey) === 0) {
4232 last.keys.push([e.key, e.id]);
4233 last.values.push(e.value);
4234 return;
4235 }
4236 groups.push({
4237 keys: [[e.key, e.id]],
4238 values: [e.value],
4239 groupKey: groupKey
4240 });
4241 });
4242 results = [];
4243 for (var i = 0, len = groups.length; i < len; i++) {
4244 var e = groups[i];
4245 var reduceTry = tryReduce(view.sourceDB, reduceFun, e.keys, e.values, false);
4246 if (reduceTry.error && reduceTry.error instanceof BuiltInError) {
4247 // CouchDB returns an error if a built-in errors out
4248 throw reduceTry.error;
4249 }
4250 results.push({
4251 // CouchDB just sets the value to null if a non-built-in errors out
4252 value: reduceTry.error ? null : reduceTry.output,
4253 key: e.groupKey
4254 });
4255 }
4256 // no total_rows/offset when reducing
4257 return {rows: sliceResults(results, options.limit, options.skip)};
4258 }
4259
4260 function queryView(view, opts) {
4261 return sequentialize(getQueue(view), function () {
4262 return queryViewInQueue(view, opts);
4263 })();
4264 }
4265
4266 function queryViewInQueue(view, opts) {
4267 var totalRows;
4268 var shouldReduce = view.reduceFun && opts.reduce !== false;
4269 var skip = opts.skip || 0;
4270 if (typeof opts.keys !== 'undefined' && !opts.keys.length) {
4271 // equivalent query
4272 opts.limit = 0;
4273 delete opts.keys;
4274 }
4275
4276 function fetchFromView(viewOpts) {
4277 viewOpts.include_docs = true;
4278 return view.db.allDocs(viewOpts).then(function (res) {
4279 totalRows = res.total_rows;
4280 return res.rows.map(function (result) {
4281
4282 // implicit migration - in older versions of PouchDB,
4283 // we explicitly stored the doc as {id: ..., key: ..., value: ...}
4284 // this is tested in a migration test
4285 /* istanbul ignore next */
4286 if ('value' in result.doc && typeof result.doc.value === 'object' &&
4287 result.doc.value !== null) {
4288 var keys = Object.keys(result.doc.value).sort();
4289 // this detection method is not perfect, but it's unlikely the user
4290 // emitted a value which was an object with these 3 exact keys
4291 var expectedKeys = ['id', 'key', 'value'];
4292 if (!(keys < expectedKeys || keys > expectedKeys)) {
4293 return result.doc.value;
4294 }
4295 }
4296
4297 var parsedKeyAndDocId = parseIndexableString(result.doc._id);
4298 return {
4299 key: parsedKeyAndDocId[0],
4300 id: parsedKeyAndDocId[1],
4301 value: ('value' in result.doc ? result.doc.value : null)
4302 };
4303 });
4304 });
4305 }
4306
4307 function onMapResultsReady(rows) {
4308 var finalResults;
4309 if (shouldReduce) {
4310 finalResults = reduceView(view, rows, opts);
4311 } else {
4312 finalResults = {
4313 total_rows: totalRows,
4314 offset: skip,
4315 rows: rows
4316 };
4317 }
4318 /* istanbul ignore if */
4319 if (opts.update_seq) {
4320 finalResults.update_seq = view.seq;
4321 }
4322 if (opts.include_docs) {
4323 var docIds = uniq$1(rows.map(rowToDocId));
4324
4325 return view.sourceDB.allDocs({
4326 keys: docIds,
4327 include_docs: true,
4328 conflicts: opts.conflicts,
4329 attachments: opts.attachments,
4330 binary: opts.binary
4331 }).then(function (allDocsRes) {
4332 var docIdsToDocs = new ExportedMap();
4333 allDocsRes.rows.forEach(function (row) {
4334 docIdsToDocs.set(row.id, row.doc);
4335 });
4336 rows.forEach(function (row) {
4337 var docId = rowToDocId(row);
4338 var doc = docIdsToDocs.get(docId);
4339 if (doc) {
4340 row.doc = doc;
4341 }
4342 });
4343 return finalResults;
4344 });
4345 } else {
4346 return finalResults;
4347 }
4348 }
4349
4350 if (typeof opts.keys !== 'undefined') {
4351 var keys = opts.keys;
4352 var fetchPromises = keys.map(function (key) {
4353 var viewOpts = {
4354 startkey : toIndexableString([key]),
4355 endkey : toIndexableString([key, {}])
4356 };
4357 /* istanbul ignore if */
4358 if (opts.update_seq) {
4359 viewOpts.update_seq = true;
4360 }
4361 return fetchFromView(viewOpts);
4362 });
4363 return Promise.all(fetchPromises).then(flatten).then(onMapResultsReady);
4364 } else { // normal query, no 'keys'
4365 var viewOpts = {
4366 descending : opts.descending
4367 };
4368 /* istanbul ignore if */
4369 if (opts.update_seq) {
4370 viewOpts.update_seq = true;
4371 }
4372 var startkey;
4373 var endkey;
4374 if ('start_key' in opts) {
4375 startkey = opts.start_key;
4376 }
4377 if ('startkey' in opts) {
4378 startkey = opts.startkey;
4379 }
4380 if ('end_key' in opts) {
4381 endkey = opts.end_key;
4382 }
4383 if ('endkey' in opts) {
4384 endkey = opts.endkey;
4385 }
4386 if (typeof startkey !== 'undefined') {
4387 viewOpts.startkey = opts.descending ?
4388 toIndexableString([startkey, {}]) :
4389 toIndexableString([startkey]);
4390 }
4391 if (typeof endkey !== 'undefined') {
4392 var inclusiveEnd = opts.inclusive_end !== false;
4393 if (opts.descending) {
4394 inclusiveEnd = !inclusiveEnd;
4395 }
4396
4397 viewOpts.endkey = toIndexableString(
4398 inclusiveEnd ? [endkey, {}] : [endkey]);
4399 }
4400 if (typeof opts.key !== 'undefined') {
4401 var keyStart = toIndexableString([opts.key]);
4402 var keyEnd = toIndexableString([opts.key, {}]);
4403 if (viewOpts.descending) {
4404 viewOpts.endkey = keyStart;
4405 viewOpts.startkey = keyEnd;
4406 } else {
4407 viewOpts.startkey = keyStart;
4408 viewOpts.endkey = keyEnd;
4409 }
4410 }
4411 if (!shouldReduce) {
4412 if (typeof opts.limit === 'number') {
4413 viewOpts.limit = opts.limit;
4414 }
4415 viewOpts.skip = skip;
4416 }
4417 return fetchFromView(viewOpts).then(onMapResultsReady);
4418 }
4419 }
4420
4421 function httpViewCleanup(db) {
4422 return db.fetch('_view_cleanup', {
4423 headers: new h({'Content-Type': 'application/json'}),
4424 method: 'POST'
4425 }).then(function (response) {
4426 return response.json();
4427 });
4428 }
4429
4430 function localViewCleanup(db) {
4431 return db.get('_local/' + localDocName).then(function (metaDoc) {
4432 var docsToViews = new ExportedMap();
4433 Object.keys(metaDoc.views).forEach(function (fullViewName) {
4434 var parts = parseViewName(fullViewName);
4435 var designDocName = '_design/' + parts[0];
4436 var viewName = parts[1];
4437 var views = docsToViews.get(designDocName);
4438 if (!views) {
4439 views = new ExportedSet();
4440 docsToViews.set(designDocName, views);
4441 }
4442 views.add(viewName);
4443 });
4444 var opts = {
4445 keys : mapToKeysArray(docsToViews),
4446 include_docs : true
4447 };
4448 return db.allDocs(opts).then(function (res) {
4449 var viewsToStatus = {};
4450 res.rows.forEach(function (row) {
4451 var ddocName = row.key.substring(8); // cuts off '_design/'
4452 docsToViews.get(row.key).forEach(function (viewName) {
4453 var fullViewName = ddocName + '/' + viewName;
4454 /* istanbul ignore if */
4455 if (!metaDoc.views[fullViewName]) {
4456 // new format, without slashes, to support PouchDB 2.2.0
4457 // migration test in pouchdb's browser.migration.js verifies this
4458 fullViewName = viewName;
4459 }
4460 var viewDBNames = Object.keys(metaDoc.views[fullViewName]);
4461 // design doc deleted, or view function nonexistent
4462 var statusIsGood = row.doc && row.doc.views &&
4463 row.doc.views[viewName];
4464 viewDBNames.forEach(function (viewDBName) {
4465 viewsToStatus[viewDBName] =
4466 viewsToStatus[viewDBName] || statusIsGood;
4467 });
4468 });
4469 });
4470 var dbsToDelete = Object.keys(viewsToStatus).filter(
4471 function (viewDBName) { return !viewsToStatus[viewDBName]; });
4472 var destroyPromises = dbsToDelete.map(function (viewDBName) {
4473 return sequentialize(getQueue(viewDBName), function () {
4474 return new db.constructor(viewDBName, db.__opts).destroy();
4475 })();
4476 });
4477 return Promise.all(destroyPromises).then(function () {
4478 return {ok: true};
4479 });
4480 });
4481 }, defaultsTo({ok: true}));
4482 }
4483
4484 function queryPromised(db, fun, opts) {
4485 /* istanbul ignore next */
4486 if (typeof db._query === 'function') {
4487 return customQuery(db, fun, opts);
4488 }
4489 if (isRemote(db)) {
4490 return httpQuery(db, fun, opts);
4491 }
4492
4493 if (typeof fun !== 'string') {
4494 // temp_view
4495 checkQueryParseError(opts, fun);
4496
4497 tempViewQueue.add(function () {
4498 var createViewPromise = createView(
4499 /* sourceDB */ db,
4500 /* viewName */ 'temp_view/temp_view',
4501 /* mapFun */ fun.map,
4502 /* reduceFun */ fun.reduce,
4503 /* temporary */ true,
4504 /* localDocName */ localDocName);
4505 return createViewPromise.then(function (view) {
4506 return fin(updateView(view).then(function () {
4507 return queryView(view, opts);
4508 }), function () {
4509 return view.db.destroy();
4510 });
4511 });
4512 });
4513 return tempViewQueue.finish();
4514 } else {
4515 // persistent view
4516 var fullViewName = fun;
4517 var parts = parseViewName(fullViewName);
4518 var designDocName = parts[0];
4519 var viewName = parts[1];
4520 return db.get('_design/' + designDocName).then(function (doc) {
4521 var fun = doc.views && doc.views[viewName];
4522
4523 if (!fun) {
4524 // basic validator; it's assumed that every subclass would want this
4525 throw new NotFoundError('ddoc ' + doc._id + ' has no view named ' +
4526 viewName);
4527 }
4528
4529 ddocValidator(doc, viewName);
4530 checkQueryParseError(opts, fun);
4531
4532 var createViewPromise = createView(
4533 /* sourceDB */ db,
4534 /* viewName */ fullViewName,
4535 /* mapFun */ fun.map,
4536 /* reduceFun */ fun.reduce,
4537 /* temporary */ false,
4538 /* localDocName */ localDocName);
4539 return createViewPromise.then(function (view) {
4540 if (opts.stale === 'ok' || opts.stale === 'update_after') {
4541 if (opts.stale === 'update_after') {
4542 immediate(function () {
4543 updateView(view);
4544 });
4545 }
4546 return queryView(view, opts);
4547 } else { // stale not ok
4548 return updateView(view).then(function () {
4549 return queryView(view, opts);
4550 });
4551 }
4552 });
4553 });
4554 }
4555 }
4556
4557 function abstractQuery(fun, opts, callback) {
4558 var db = this;
4559 if (typeof opts === 'function') {
4560 callback = opts;
4561 opts = {};
4562 }
4563 opts = opts ? coerceOptions(opts) : {};
4564
4565 if (typeof fun === 'function') {
4566 fun = {map : fun};
4567 }
4568
4569 var promise = Promise.resolve().then(function () {
4570 return queryPromised(db, fun, opts);
4571 });
4572 promisedCallback$1(promise, callback);
4573 return promise;
4574 }
4575
4576 var abstractViewCleanup = callbackify$1(function () {
4577 var db = this;
4578 /* istanbul ignore next */
4579 if (typeof db._viewCleanup === 'function') {
4580 return customViewCleanup(db);
4581 }
4582 if (isRemote(db)) {
4583 return httpViewCleanup(db);
4584 }
4585 return localViewCleanup(db);
4586 });
4587
4588 return {
4589 query: abstractQuery,
4590 viewCleanup: abstractViewCleanup
4591 };
4592}
4593
4594//
4595// One thing about these mappers:
4596//
4597// Per the advice of John-David Dalton (http://youtu.be/NthmeLEhDDM),
4598// what you want to do in this case is optimize for the smallest possible
4599// function, since that's the thing that gets run over and over again.
4600//
4601// This code would be a lot simpler if all the if/elses were inside
4602// the function, but it would also be a lot less performant.
4603//
4604
4605
4606function createDeepMultiMapper(fields, emit) {
4607 return function (doc) {
4608 var toEmit = [];
4609 for (var i = 0, iLen = fields.length; i < iLen; i++) {
4610 var parsedField = parseField(fields[i]);
4611 var value = doc;
4612 for (var j = 0, jLen = parsedField.length; j < jLen; j++) {
4613 var key = parsedField[j];
4614 value = value[key];
4615 if (typeof value === 'undefined') {
4616 return; // don't emit
4617 }
4618 }
4619 toEmit.push(value);
4620 }
4621 emit(toEmit);
4622 };
4623}
4624
4625function createDeepSingleMapper(field, emit) {
4626 var parsedField = parseField(field);
4627 return function (doc) {
4628 var value = doc;
4629 for (var i = 0, len = parsedField.length; i < len; i++) {
4630 var key = parsedField[i];
4631 value = value[key];
4632 if (typeof value === 'undefined') {
4633 return; // do nothing
4634 }
4635 }
4636 emit(value);
4637 };
4638}
4639
4640function createShallowSingleMapper(field, emit) {
4641 return function (doc) {
4642 emit(doc[field]);
4643 };
4644}
4645
4646function createShallowMultiMapper(fields, emit) {
4647 return function (doc) {
4648 var toEmit = [];
4649 for (var i = 0, len = fields.length; i < len; i++) {
4650 toEmit.push(doc[fields[i]]);
4651 }
4652 emit(toEmit);
4653 };
4654}
4655
4656function checkShallow(fields) {
4657 for (var i = 0, len = fields.length; i < len; i++) {
4658 var field = fields[i];
4659 if (field.indexOf('.') !== -1) {
4660 return false;
4661 }
4662 }
4663 return true;
4664}
4665
4666function createMapper(fields, emit) {
4667 var isShallow = checkShallow(fields);
4668 var isSingle = fields.length === 1;
4669
4670 // notice we try to optimize for the most common case,
4671 // i.e. single shallow indexes
4672 if (isShallow) {
4673 if (isSingle) {
4674 return createShallowSingleMapper(fields[0], emit);
4675 } else { // multi
4676 return createShallowMultiMapper(fields, emit);
4677 }
4678 } else { // deep
4679 if (isSingle) {
4680 return createDeepSingleMapper(fields[0], emit);
4681 } else { // multi
4682 return createDeepMultiMapper(fields, emit);
4683 }
4684 }
4685}
4686
4687function mapper(mapFunDef, emit) {
4688 // mapFunDef is a list of fields
4689
4690 var fields = Object.keys(mapFunDef.fields);
4691
4692 return createMapper(fields, emit);
4693}
4694
4695/* istanbul ignore next */
4696function reducer(/*reduceFunDef*/) {
4697 throw new Error('reduce not supported');
4698}
4699
4700function ddocValidator(ddoc, viewName) {
4701 var view = ddoc.views[viewName];
4702 // This doesn't actually need to be here apparently, but
4703 // I feel safer keeping it.
4704 /* istanbul ignore if */
4705 if (!view.map || !view.map.fields) {
4706 throw new Error('ddoc ' + ddoc._id +' with view ' + viewName +
4707 ' doesn\'t have map.fields defined. ' +
4708 'maybe it wasn\'t created by this plugin?');
4709 }
4710}
4711
4712var abstractMapper = createAbstractMapReduce(
4713 /* localDocName */ 'indexes',
4714 mapper,
4715 reducer,
4716 ddocValidator
4717);
4718
4719function abstractMapper$1 (db) {
4720 return db._customFindAbstractMapper || abstractMapper;
4721}
4722
4723// normalize the "sort" value
4724function massageSort(sort) {
4725 if (!Array.isArray(sort)) {
4726 throw new Error('invalid sort json - should be an array');
4727 }
4728 return sort.map(function (sorting) {
4729 if (typeof sorting === 'string') {
4730 var obj = {};
4731 obj[sorting] = 'asc';
4732 return obj;
4733 } else {
4734 return sorting;
4735 }
4736 });
4737}
4738
4739function massageUseIndex(useIndex) {
4740 var cleanedUseIndex = [];
4741 if (typeof useIndex === 'string') {
4742 cleanedUseIndex.push(useIndex);
4743 } else {
4744 cleanedUseIndex = useIndex;
4745 }
4746
4747 return cleanedUseIndex.map(function (name) {
4748 return name.replace('_design/', '');
4749 });
4750}
4751
4752function massageIndexDef(indexDef) {
4753 indexDef.fields = indexDef.fields.map(function (field) {
4754 if (typeof field === 'string') {
4755 var obj = {};
4756 obj[field] = 'asc';
4757 return obj;
4758 }
4759 return field;
4760 });
4761 return indexDef;
4762}
4763
4764function getKeyFromDoc(doc, index) {
4765 var res = [];
4766 for (var i = 0; i < index.def.fields.length; i++) {
4767 var field = getKey(index.def.fields[i]);
4768 res.push(doc[field]);
4769 }
4770 return res;
4771}
4772
4773// have to do this manually because REASONS. I don't know why
4774// CouchDB didn't implement inclusive_start
4775function filterInclusiveStart(rows, targetValue, index) {
4776 var indexFields = index.def.fields;
4777 for (var i = 0, len = rows.length; i < len; i++) {
4778 var row = rows[i];
4779
4780 // shave off any docs at the beginning that are <= the
4781 // target value
4782
4783 var docKey = getKeyFromDoc(row.doc, index);
4784 if (indexFields.length === 1) {
4785 docKey = docKey[0]; // only one field, not multi-field
4786 } else { // more than one field in index
4787 // in the case where e.g. the user is searching {$gt: {a: 1}}
4788 // but the index is [a, b], then we need to shorten the doc key
4789 while (docKey.length > targetValue.length) {
4790 docKey.pop();
4791 }
4792 }
4793 //ABS as we just looking for values that don't match
4794 if (Math.abs(collate(docKey, targetValue)) > 0) {
4795 // no need to filter any further; we're past the key
4796 break;
4797 }
4798 }
4799 return i > 0 ? rows.slice(i) : rows;
4800}
4801
4802function reverseOptions(opts) {
4803 var newOpts = clone(opts);
4804 delete newOpts.startkey;
4805 delete newOpts.endkey;
4806 delete newOpts.inclusive_start;
4807 delete newOpts.inclusive_end;
4808
4809 if ('endkey' in opts) {
4810 newOpts.startkey = opts.endkey;
4811 }
4812 if ('startkey' in opts) {
4813 newOpts.endkey = opts.startkey;
4814 }
4815 if ('inclusive_start' in opts) {
4816 newOpts.inclusive_end = opts.inclusive_start;
4817 }
4818 if ('inclusive_end' in opts) {
4819 newOpts.inclusive_start = opts.inclusive_end;
4820 }
4821 return newOpts;
4822}
4823
4824function validateIndex(index) {
4825 var ascFields = index.fields.filter(function (field) {
4826 return getValue(field) === 'asc';
4827 });
4828 if (ascFields.length !== 0 && ascFields.length !== index.fields.length) {
4829 throw new Error('unsupported mixed sorting');
4830 }
4831}
4832
4833function validateSort(requestDef, index) {
4834 if (index.defaultUsed && requestDef.sort) {
4835 var noneIdSorts = requestDef.sort.filter(function (sortItem) {
4836 return Object.keys(sortItem)[0] !== '_id';
4837 }).map(function (sortItem) {
4838 return Object.keys(sortItem)[0];
4839 });
4840
4841 if (noneIdSorts.length > 0) {
4842 throw new Error('Cannot sort on field(s) "' + noneIdSorts.join(',') +
4843 '" when using the default index');
4844 }
4845 }
4846
4847 if (index.defaultUsed) {
4848 return;
4849 }
4850}
4851
4852function validateFindRequest(requestDef) {
4853 if (typeof requestDef.selector !== 'object') {
4854 throw new Error('you must provide a selector when you find()');
4855 }
4856
4857 /*var selectors = requestDef.selector['$and'] || [requestDef.selector];
4858 for (var i = 0; i < selectors.length; i++) {
4859 var selector = selectors[i];
4860 var keys = Object.keys(selector);
4861 if (keys.length === 0) {
4862 throw new Error('invalid empty selector');
4863 }
4864 //var selection = selector[keys[0]];
4865 /*if (Object.keys(selection).length !== 1) {
4866 throw new Error('invalid selector: ' + JSON.stringify(selection) +
4867 ' - it must have exactly one key/value');
4868 }
4869 }*/
4870}
4871
4872// determine the maximum number of fields
4873// we're going to need to query, e.g. if the user
4874// has selection ['a'] and sorting ['a', 'b'], then we
4875// need to use the longer of the two: ['a', 'b']
4876function getUserFields(selector, sort) {
4877 var selectorFields = Object.keys(selector);
4878 var sortFields = sort? sort.map(getKey) : [];
4879 var userFields;
4880 if (selectorFields.length >= sortFields.length) {
4881 userFields = selectorFields;
4882 } else {
4883 userFields = sortFields;
4884 }
4885
4886 if (sortFields.length === 0) {
4887 return {
4888 fields: userFields
4889 };
4890 }
4891
4892 // sort according to the user's preferred sorting
4893 userFields = userFields.sort(function (left, right) {
4894 var leftIdx = sortFields.indexOf(left);
4895 if (leftIdx === -1) {
4896 leftIdx = Number.MAX_VALUE;
4897 }
4898 var rightIdx = sortFields.indexOf(right);
4899 if (rightIdx === -1) {
4900 rightIdx = Number.MAX_VALUE;
4901 }
4902 return leftIdx < rightIdx ? -1 : leftIdx > rightIdx ? 1 : 0;
4903 });
4904
4905 return {
4906 fields: userFields,
4907 sortOrder: sort.map(getKey)
4908 };
4909}
4910
4911function createIndex$1(db, requestDef) {
4912 requestDef = massageCreateIndexRequest(requestDef);
4913 var originalIndexDef = clone(requestDef.index);
4914 requestDef.index = massageIndexDef(requestDef.index);
4915
4916 validateIndex(requestDef.index);
4917
4918 // calculating md5 is expensive - memoize and only
4919 // run if required
4920 var md5;
4921 function getMd5() {
4922 return md5 || (md5 = stringMd5(JSON.stringify(requestDef)));
4923 }
4924
4925 var viewName = requestDef.name || ('idx-' + getMd5());
4926
4927 var ddocName = requestDef.ddoc || ('idx-' + getMd5());
4928 var ddocId = '_design/' + ddocName;
4929
4930 var hasInvalidLanguage = false;
4931 var viewExists = false;
4932
4933 function updateDdoc(doc) {
4934 if (doc._rev && doc.language !== 'query') {
4935 hasInvalidLanguage = true;
4936 }
4937 doc.language = 'query';
4938 doc.views = doc.views || {};
4939
4940 viewExists = !!doc.views[viewName];
4941
4942 if (viewExists) {
4943 return false;
4944 }
4945
4946 doc.views[viewName] = {
4947 map: {
4948 fields: mergeObjects(requestDef.index.fields)
4949 },
4950 reduce: '_count',
4951 options: {
4952 def: originalIndexDef
4953 }
4954 };
4955
4956 return doc;
4957 }
4958
4959 db.constructor.emit('debug', ['find', 'creating index', ddocId]);
4960
4961 return upsert(db, ddocId, updateDdoc).then(function () {
4962 if (hasInvalidLanguage) {
4963 throw new Error('invalid language for ddoc with id "' +
4964 ddocId +
4965 '" (should be "query")');
4966 }
4967 }).then(function () {
4968 // kick off a build
4969 // TODO: abstract-pouchdb-mapreduce should support auto-updating
4970 // TODO: should also use update_after, but pouchdb/pouchdb#3415 blocks me
4971 var signature = ddocName + '/' + viewName;
4972 return abstractMapper$1(db).query.call(db, signature, {
4973 limit: 0,
4974 reduce: false
4975 }).then(function () {
4976 return {
4977 id: ddocId,
4978 name: viewName,
4979 result: viewExists ? 'exists' : 'created'
4980 };
4981 });
4982 });
4983}
4984
4985function getIndexes$1(db) {
4986 // just search through all the design docs and filter in-memory.
4987 // hopefully there aren't that many ddocs.
4988 return db.allDocs({
4989 startkey: '_design/',
4990 endkey: '_design/\uffff',
4991 include_docs: true
4992 }).then(function (allDocsRes) {
4993 var res = {
4994 indexes: [{
4995 ddoc: null,
4996 name: '_all_docs',
4997 type: 'special',
4998 def: {
4999 fields: [{_id: 'asc'}]
5000 }
5001 }]
5002 };
5003
5004 res.indexes = flatten$1(res.indexes, allDocsRes.rows.filter(function (row) {
5005 return row.doc.language === 'query';
5006 }).map(function (row) {
5007 var viewNames = row.doc.views !== undefined ? Object.keys(row.doc.views) : [];
5008
5009 return viewNames.map(function (viewName) {
5010 var view = row.doc.views[viewName];
5011 return {
5012 ddoc: row.id,
5013 name: viewName,
5014 type: 'json',
5015 def: massageIndexDef(view.options.def)
5016 };
5017 });
5018 }));
5019
5020 // these are sorted by view name for some reason
5021 res.indexes.sort(function (left, right) {
5022 return compare(left.name, right.name);
5023 });
5024 res.total_rows = res.indexes.length;
5025 return res;
5026 });
5027}
5028
5029// couchdb lowest collation value
5030var COLLATE_LO = null;
5031
5032// couchdb highest collation value (TODO: well not really, but close enough amirite)
5033var COLLATE_HI = {"\uffff": {}};
5034
5035// couchdb second-lowest collation value
5036
5037function checkFieldInIndex(index, field) {
5038 var indexFields = index.def.fields.map(getKey);
5039 for (var i = 0, len = indexFields.length; i < len; i++) {
5040 var indexField = indexFields[i];
5041 if (field === indexField) {
5042 return true;
5043 }
5044 }
5045 return false;
5046}
5047
5048// so when you do e.g. $eq/$eq, we can do it entirely in the database.
5049// but when you do e.g. $gt/$eq, the first part can be done
5050// in the database, but the second part has to be done in-memory,
5051// because $gt has forced us to lose precision.
5052// so that's what this determines
5053function userOperatorLosesPrecision(selector, field) {
5054 var matcher = selector[field];
5055 var userOperator = getKey(matcher);
5056
5057 return userOperator !== '$eq';
5058}
5059
5060// sort the user fields by their position in the index,
5061// if they're in the index
5062function sortFieldsByIndex(userFields, index) {
5063 var indexFields = index.def.fields.map(getKey);
5064
5065 return userFields.slice().sort(function (a, b) {
5066 var aIdx = indexFields.indexOf(a);
5067 var bIdx = indexFields.indexOf(b);
5068 if (aIdx === -1) {
5069 aIdx = Number.MAX_VALUE;
5070 }
5071 if (bIdx === -1) {
5072 bIdx = Number.MAX_VALUE;
5073 }
5074 return compare(aIdx, bIdx);
5075 });
5076}
5077
5078// first pass to try to find fields that will need to be sorted in-memory
5079function getBasicInMemoryFields(index, selector, userFields) {
5080
5081 userFields = sortFieldsByIndex(userFields, index);
5082
5083 // check if any of the user selectors lose precision
5084 var needToFilterInMemory = false;
5085 for (var i = 0, len = userFields.length; i < len; i++) {
5086 var field = userFields[i];
5087 if (needToFilterInMemory || !checkFieldInIndex(index, field)) {
5088 return userFields.slice(i);
5089 }
5090 if (i < len - 1 && userOperatorLosesPrecision(selector, field)) {
5091 needToFilterInMemory = true;
5092 }
5093 }
5094 return [];
5095}
5096
5097function getInMemoryFieldsFromNe(selector) {
5098 var fields = [];
5099 Object.keys(selector).forEach(function (field) {
5100 var matcher = selector[field];
5101 Object.keys(matcher).forEach(function (operator) {
5102 if (operator === '$ne') {
5103 fields.push(field);
5104 }
5105 });
5106 });
5107 return fields;
5108}
5109
5110function getInMemoryFields(coreInMemoryFields, index, selector, userFields) {
5111 var result = flatten$1(
5112 // in-memory fields reported as necessary by the query planner
5113 coreInMemoryFields,
5114 // combine with another pass that checks for any we may have missed
5115 getBasicInMemoryFields(index, selector, userFields),
5116 // combine with another pass that checks for $ne's
5117 getInMemoryFieldsFromNe(selector)
5118 );
5119
5120 return sortFieldsByIndex(uniq(result), index);
5121}
5122
5123// check that at least one field in the user's query is represented
5124// in the index. order matters in the case of sorts
5125function checkIndexFieldsMatch(indexFields, sortOrder, fields) {
5126 if (sortOrder) {
5127 // array has to be a strict subarray of index array. furthermore,
5128 // the sortOrder fields need to all be represented in the index
5129 var sortMatches = oneArrayIsStrictSubArrayOfOther(sortOrder, indexFields);
5130 var selectorMatches = oneArrayIsSubArrayOfOther(fields, indexFields);
5131
5132 return sortMatches && selectorMatches;
5133 }
5134
5135 // all of the user's specified fields still need to be
5136 // on the left side of the index array, although the order
5137 // doesn't matter
5138 return oneSetIsSubArrayOfOther(fields, indexFields);
5139}
5140
5141var logicalMatchers = ['$eq', '$gt', '$gte', '$lt', '$lte'];
5142function isNonLogicalMatcher(matcher) {
5143 return logicalMatchers.indexOf(matcher) === -1;
5144}
5145
5146// check all the index fields for usages of '$ne'
5147// e.g. if the user queries {foo: {$ne: 'foo'}, bar: {$eq: 'bar'}},
5148// then we can neither use an index on ['foo'] nor an index on
5149// ['foo', 'bar'], but we can use an index on ['bar'] or ['bar', 'foo']
5150function checkFieldsLogicallySound(indexFields, selector) {
5151 var firstField = indexFields[0];
5152 var matcher = selector[firstField];
5153
5154 if (typeof matcher === 'undefined') {
5155 /* istanbul ignore next */
5156 return true;
5157 }
5158
5159 var isInvalidNe = Object.keys(matcher).length === 1 &&
5160 getKey(matcher) === '$ne';
5161
5162 return !isInvalidNe;
5163}
5164
5165function checkIndexMatches(index, sortOrder, fields, selector) {
5166
5167 var indexFields = index.def.fields.map(getKey);
5168
5169 var fieldsMatch = checkIndexFieldsMatch(indexFields, sortOrder, fields);
5170
5171 if (!fieldsMatch) {
5172 return false;
5173 }
5174
5175 return checkFieldsLogicallySound(indexFields, selector);
5176}
5177
5178//
5179// the algorithm is very simple:
5180// take all the fields the user supplies, and if those fields
5181// are a strict subset of the fields in some index,
5182// then use that index
5183//
5184//
5185function findMatchingIndexes(selector, userFields, sortOrder, indexes) {
5186
5187 return indexes.reduce(function (res, index) {
5188 var indexMatches = checkIndexMatches(index, sortOrder, userFields, selector);
5189 if (indexMatches) {
5190 res.push(index);
5191 }
5192 return res;
5193 }, []);
5194}
5195
5196// find the best index, i.e. the one that matches the most fields
5197// in the user's query
5198function findBestMatchingIndex(selector, userFields, sortOrder, indexes, useIndex) {
5199
5200 var matchingIndexes = findMatchingIndexes(selector, userFields, sortOrder, indexes);
5201
5202 if (matchingIndexes.length === 0) {
5203 if (useIndex) {
5204 throw {
5205 error: "no_usable_index",
5206 message: "There is no index available for this selector."
5207 };
5208 }
5209 //return `all_docs` as a default index;
5210 //I'm assuming that _all_docs is always first
5211 var defaultIndex = indexes[0];
5212 defaultIndex.defaultUsed = true;
5213 return defaultIndex;
5214 }
5215 if (matchingIndexes.length === 1 && !useIndex) {
5216 return matchingIndexes[0];
5217 }
5218
5219 var userFieldsMap = arrayToObject(userFields);
5220
5221 function scoreIndex(index) {
5222 var indexFields = index.def.fields.map(getKey);
5223 var score = 0;
5224 for (var i = 0, len = indexFields.length; i < len; i++) {
5225 var indexField = indexFields[i];
5226 if (userFieldsMap[indexField]) {
5227 score++;
5228 }
5229 }
5230 return score;
5231 }
5232
5233 if (useIndex) {
5234 var useIndexDdoc = '_design/' + useIndex[0];
5235 var useIndexName = useIndex.length === 2 ? useIndex[1] : false;
5236 var index = matchingIndexes.find(function (index) {
5237 if (useIndexName && index.ddoc === useIndexDdoc && useIndexName === index.name) {
5238 return true;
5239 }
5240
5241 if (index.ddoc === useIndexDdoc) {
5242 /* istanbul ignore next */
5243 return true;
5244 }
5245
5246 return false;
5247 });
5248
5249 if (!index) {
5250 throw {
5251 error: "unknown_error",
5252 message: "Could not find that index or could not use that index for the query"
5253 };
5254 }
5255 return index;
5256 }
5257
5258 return max(matchingIndexes, scoreIndex);
5259}
5260
5261function getSingleFieldQueryOptsFor(userOperator, userValue) {
5262 switch (userOperator) {
5263 case '$eq':
5264 return {key: userValue};
5265 case '$lte':
5266 return {endkey: userValue};
5267 case '$gte':
5268 return {startkey: userValue};
5269 case '$lt':
5270 return {
5271 endkey: userValue,
5272 inclusive_end: false
5273 };
5274 case '$gt':
5275 return {
5276 startkey: userValue,
5277 inclusive_start: false
5278 };
5279 }
5280
5281 return {
5282 startkey: COLLATE_LO
5283 };
5284}
5285
5286function getSingleFieldCoreQueryPlan(selector, index) {
5287 var field = getKey(index.def.fields[0]);
5288 //ignoring this because the test to exercise the branch is skipped at the moment
5289 /* istanbul ignore next */
5290 var matcher = selector[field] || {};
5291 var inMemoryFields = [];
5292
5293 var userOperators = Object.keys(matcher);
5294
5295 var combinedOpts;
5296
5297 userOperators.forEach(function (userOperator) {
5298
5299 if (isNonLogicalMatcher(userOperator)) {
5300 inMemoryFields.push(field);
5301 }
5302
5303 var userValue = matcher[userOperator];
5304
5305 var newQueryOpts = getSingleFieldQueryOptsFor(userOperator, userValue);
5306
5307 if (combinedOpts) {
5308 combinedOpts = mergeObjects([combinedOpts, newQueryOpts]);
5309 } else {
5310 combinedOpts = newQueryOpts;
5311 }
5312 });
5313
5314 return {
5315 queryOpts: combinedOpts,
5316 inMemoryFields: inMemoryFields
5317 };
5318}
5319
5320function getMultiFieldCoreQueryPlan(userOperator, userValue) {
5321 switch (userOperator) {
5322 case '$eq':
5323 return {
5324 startkey: userValue,
5325 endkey: userValue
5326 };
5327 case '$lte':
5328 return {
5329 endkey: userValue
5330 };
5331 case '$gte':
5332 return {
5333 startkey: userValue
5334 };
5335 case '$lt':
5336 return {
5337 endkey: userValue,
5338 inclusive_end: false
5339 };
5340 case '$gt':
5341 return {
5342 startkey: userValue,
5343 inclusive_start: false
5344 };
5345 }
5346}
5347
5348function getMultiFieldQueryOpts(selector, index) {
5349
5350 var indexFields = index.def.fields.map(getKey);
5351
5352 var inMemoryFields = [];
5353 var startkey = [];
5354 var endkey = [];
5355 var inclusiveStart;
5356 var inclusiveEnd;
5357
5358
5359 function finish(i) {
5360
5361 if (inclusiveStart !== false) {
5362 startkey.push(COLLATE_LO);
5363 }
5364 if (inclusiveEnd !== false) {
5365 endkey.push(COLLATE_HI);
5366 }
5367 // keep track of the fields where we lost specificity,
5368 // and therefore need to filter in-memory
5369 inMemoryFields = indexFields.slice(i);
5370 }
5371
5372 for (var i = 0, len = indexFields.length; i < len; i++) {
5373 var indexField = indexFields[i];
5374
5375 var matcher = selector[indexField];
5376
5377 if (!matcher || !Object.keys(matcher).length) { // fewer fields in user query than in index
5378 finish(i);
5379 break;
5380 } else if (i > 0) {
5381 if (Object.keys(matcher).some(isNonLogicalMatcher)) { // non-logical are ignored
5382 finish(i);
5383 break;
5384 }
5385 var usingGtlt = (
5386 '$gt' in matcher || '$gte' in matcher ||
5387 '$lt' in matcher || '$lte' in matcher);
5388 var previousKeys = Object.keys(selector[indexFields[i - 1]]);
5389 var previousWasEq = arrayEquals(previousKeys, ['$eq']);
5390 var previousWasSame = arrayEquals(previousKeys, Object.keys(matcher));
5391 var gtltLostSpecificity = usingGtlt && !previousWasEq && !previousWasSame;
5392 if (gtltLostSpecificity) {
5393 finish(i);
5394 break;
5395 }
5396 }
5397
5398 var userOperators = Object.keys(matcher);
5399
5400 var combinedOpts = null;
5401
5402 for (var j = 0; j < userOperators.length; j++) {
5403 var userOperator = userOperators[j];
5404 var userValue = matcher[userOperator];
5405
5406 var newOpts = getMultiFieldCoreQueryPlan(userOperator, userValue);
5407
5408 if (combinedOpts) {
5409 combinedOpts = mergeObjects([combinedOpts, newOpts]);
5410 } else {
5411 combinedOpts = newOpts;
5412 }
5413 }
5414
5415 startkey.push('startkey' in combinedOpts ? combinedOpts.startkey : COLLATE_LO);
5416 endkey.push('endkey' in combinedOpts ? combinedOpts.endkey : COLLATE_HI);
5417 if ('inclusive_start' in combinedOpts) {
5418 inclusiveStart = combinedOpts.inclusive_start;
5419 }
5420 if ('inclusive_end' in combinedOpts) {
5421 inclusiveEnd = combinedOpts.inclusive_end;
5422 }
5423 }
5424
5425 var res = {
5426 startkey: startkey,
5427 endkey: endkey
5428 };
5429
5430 if (typeof inclusiveStart !== 'undefined') {
5431 res.inclusive_start = inclusiveStart;
5432 }
5433 if (typeof inclusiveEnd !== 'undefined') {
5434 res.inclusive_end = inclusiveEnd;
5435 }
5436
5437 return {
5438 queryOpts: res,
5439 inMemoryFields: inMemoryFields
5440 };
5441}
5442
5443function getDefaultQueryPlan(selector) {
5444 //using default index, so all fields need to be done in memory
5445 return {
5446 queryOpts: {startkey: null},
5447 inMemoryFields: [Object.keys(selector)]
5448 };
5449}
5450
5451function getCoreQueryPlan(selector, index) {
5452 if (index.defaultUsed) {
5453 return getDefaultQueryPlan(selector, index);
5454 }
5455
5456 if (index.def.fields.length === 1) {
5457 // one field in index, so the value was indexed as a singleton
5458 return getSingleFieldCoreQueryPlan(selector, index);
5459 }
5460 // else index has multiple fields, so the value was indexed as an array
5461 return getMultiFieldQueryOpts(selector, index);
5462}
5463
5464function planQuery(request, indexes) {
5465
5466 var selector = request.selector;
5467 var sort = request.sort;
5468
5469 var userFieldsRes = getUserFields(selector, sort);
5470
5471 var userFields = userFieldsRes.fields;
5472 var sortOrder = userFieldsRes.sortOrder;
5473 var index = findBestMatchingIndex(selector, userFields, sortOrder, indexes, request.use_index);
5474
5475 var coreQueryPlan = getCoreQueryPlan(selector, index);
5476 var queryOpts = coreQueryPlan.queryOpts;
5477 var coreInMemoryFields = coreQueryPlan.inMemoryFields;
5478
5479 var inMemoryFields = getInMemoryFields(coreInMemoryFields, index, selector, userFields);
5480
5481 var res = {
5482 queryOpts: queryOpts,
5483 index: index,
5484 inMemoryFields: inMemoryFields
5485 };
5486 return res;
5487}
5488
5489function indexToSignature(index) {
5490 // remove '_design/'
5491 return index.ddoc.substring(8) + '/' + index.name;
5492}
5493
5494function doAllDocs(db, originalOpts) {
5495 var opts = clone(originalOpts);
5496
5497 // CouchDB responds in weird ways when you provide a non-string to _id;
5498 // we mimic the behavior for consistency. See issue66 tests for details.
5499
5500 if (opts.descending) {
5501 if ('endkey' in opts && typeof opts.endkey !== 'string') {
5502 opts.endkey = '';
5503 }
5504 if ('startkey' in opts && typeof opts.startkey !== 'string') {
5505 opts.limit = 0;
5506 }
5507 } else {
5508 if ('startkey' in opts && typeof opts.startkey !== 'string') {
5509 opts.startkey = '';
5510 }
5511 if ('endkey' in opts && typeof opts.endkey !== 'string') {
5512 opts.limit = 0;
5513 }
5514 }
5515 if ('key' in opts && typeof opts.key !== 'string') {
5516 opts.limit = 0;
5517 }
5518
5519 return db.allDocs(opts)
5520 .then(function (res) {
5521 // filter out any design docs that _all_docs might return
5522 res.rows = res.rows.filter(function (row) {
5523 return !/^_design\//.test(row.id);
5524 });
5525 return res;
5526 });
5527}
5528
5529function find$1(db, requestDef, explain) {
5530 if (requestDef.selector) {
5531 requestDef.selector = massageSelector(requestDef.selector);
5532 }
5533
5534 if (requestDef.sort) {
5535 requestDef.sort = massageSort(requestDef.sort);
5536 }
5537
5538 if (requestDef.use_index) {
5539 requestDef.use_index = massageUseIndex(requestDef.use_index);
5540 }
5541
5542 validateFindRequest(requestDef);
5543
5544 return getIndexes$1(db).then(function (getIndexesRes) {
5545
5546 db.constructor.emit('debug', ['find', 'planning query', requestDef]);
5547 var queryPlan = planQuery(requestDef, getIndexesRes.indexes);
5548 db.constructor.emit('debug', ['find', 'query plan', queryPlan]);
5549
5550 var indexToUse = queryPlan.index;
5551
5552 validateSort(requestDef, indexToUse);
5553
5554 var opts = $inject_Object_assign({
5555 include_docs: true,
5556 reduce: false
5557 }, queryPlan.queryOpts);
5558
5559 if ('startkey' in opts && 'endkey' in opts &&
5560 collate(opts.startkey, opts.endkey) > 0) {
5561 // can't possibly return any results, startkey > endkey
5562 /* istanbul ignore next */
5563 return {docs: []};
5564 }
5565
5566 var isDescending = requestDef.sort &&
5567 typeof requestDef.sort[0] !== 'string' &&
5568 getValue(requestDef.sort[0]) === 'desc';
5569
5570 if (isDescending) {
5571 // either all descending or all ascending
5572 opts.descending = true;
5573 opts = reverseOptions(opts);
5574 }
5575
5576 if (!queryPlan.inMemoryFields.length) {
5577 // no in-memory filtering necessary, so we can let the
5578 // database do the limit/skip for us
5579 if ('limit' in requestDef) {
5580 opts.limit = requestDef.limit;
5581 }
5582 if ('skip' in requestDef) {
5583 opts.skip = requestDef.skip;
5584 }
5585 }
5586
5587 if (explain) {
5588 return Promise.resolve(queryPlan, opts);
5589 }
5590
5591 return Promise.resolve().then(function () {
5592 if (indexToUse.name === '_all_docs') {
5593 return doAllDocs(db, opts);
5594 } else {
5595 var signature = indexToSignature(indexToUse);
5596 return abstractMapper$1(db).query.call(db, signature, opts);
5597 }
5598 }).then(function (res) {
5599 if (opts.inclusive_start === false) {
5600 // may have to manually filter the first one,
5601 // since couchdb has no true inclusive_start option
5602 res.rows = filterInclusiveStart(res.rows, opts.startkey, indexToUse);
5603 }
5604
5605 if (queryPlan.inMemoryFields.length) {
5606 // need to filter some stuff in-memory
5607 res.rows = filterInMemoryFields(res.rows, requestDef, queryPlan.inMemoryFields);
5608 }
5609
5610 var resp = {
5611 docs: res.rows.map(function (row) {
5612 var doc = row.doc;
5613 if (requestDef.fields) {
5614 return pick$1(doc, requestDef.fields);
5615 }
5616 return doc;
5617 })
5618 };
5619
5620 if (indexToUse.defaultUsed) {
5621 resp.warning = 'no matching index found, create an index to optimize query time';
5622 }
5623
5624 return resp;
5625 });
5626 });
5627}
5628
5629function explain$1(db, requestDef) {
5630 return find$1(db, requestDef, true)
5631 .then(function (queryPlan) {
5632 return {
5633 dbname: db.name,
5634 index: queryPlan.index,
5635 selector: requestDef.selector,
5636 range: {
5637 start_key: queryPlan.queryOpts.startkey,
5638 end_key: queryPlan.queryOpts.endkey
5639 },
5640 opts: {
5641 use_index: requestDef.use_index || [],
5642 bookmark: "nil", //hardcoded to match CouchDB since its not supported,
5643 limit: requestDef.limit,
5644 skip: requestDef.skip,
5645 sort: requestDef.sort || {},
5646 fields: requestDef.fields,
5647 conflicts: false, //hardcoded to match CouchDB since its not supported,
5648 r: [49] // hardcoded to match CouchDB since its not support
5649 },
5650 limit: requestDef.limit,
5651 skip: requestDef.skip || 0,
5652 fields: requestDef.fields
5653 };
5654 });
5655}
5656
5657function deleteIndex$1(db, index) {
5658
5659 if (!index.ddoc) {
5660 throw new Error('you must supply an index.ddoc when deleting');
5661 }
5662
5663 if (!index.name) {
5664 throw new Error('you must supply an index.name when deleting');
5665 }
5666
5667 var docId = index.ddoc;
5668 var viewName = index.name;
5669
5670 function deltaFun(doc) {
5671 if (Object.keys(doc.views).length === 1 && doc.views[viewName]) {
5672 // only one view in this ddoc, delete the whole ddoc
5673 return {_id: docId, _deleted: true};
5674 }
5675 // more than one view here, just remove the view
5676 delete doc.views[viewName];
5677 return doc;
5678 }
5679
5680 return upsert(db, docId, deltaFun).then(function () {
5681 return abstractMapper$1(db).viewCleanup.apply(db);
5682 }).then(function () {
5683 return {ok: true};
5684 });
5685}
5686
5687var createIndexAsCallback = callbackify(createIndex$1);
5688var findAsCallback = callbackify(find$1);
5689var explainAsCallback = callbackify(explain$1);
5690var getIndexesAsCallback = callbackify(getIndexes$1);
5691var deleteIndexAsCallback = callbackify(deleteIndex$1);
5692
5693var plugin = {};
5694plugin.createIndex = toPromise(function (requestDef, callback) {
5695
5696 if (typeof requestDef !== 'object') {
5697 return callback(new Error('you must provide an index to create'));
5698 }
5699
5700 var createIndex$$1 = isRemote(this) ?
5701 createIndex : createIndexAsCallback;
5702 createIndex$$1(this, requestDef, callback);
5703});
5704
5705plugin.find = toPromise(function (requestDef, callback) {
5706
5707 if (typeof callback === 'undefined') {
5708 callback = requestDef;
5709 requestDef = undefined;
5710 }
5711
5712 if (typeof requestDef !== 'object') {
5713 return callback(new Error('you must provide search parameters to find()'));
5714 }
5715
5716 var find$$1 = isRemote(this) ? find : findAsCallback;
5717 find$$1(this, requestDef, callback);
5718});
5719
5720plugin.explain = toPromise(function (requestDef, callback) {
5721
5722 if (typeof callback === 'undefined') {
5723 callback = requestDef;
5724 requestDef = undefined;
5725 }
5726
5727 if (typeof requestDef !== 'object') {
5728 return callback(new Error('you must provide search parameters to explain()'));
5729 }
5730
5731 var find$$1 = isRemote(this) ? explain : explainAsCallback;
5732 find$$1(this, requestDef, callback);
5733});
5734
5735plugin.getIndexes = toPromise(function (callback) {
5736
5737 var getIndexes$$1 = isRemote(this) ? getIndexes : getIndexesAsCallback;
5738 getIndexes$$1(this, callback);
5739});
5740
5741plugin.deleteIndex = toPromise(function (indexDef, callback) {
5742
5743 if (typeof indexDef !== 'object') {
5744 return callback(new Error('you must provide an index to delete'));
5745 }
5746
5747 var deleteIndex$$1 = isRemote(this) ?
5748 deleteIndex : deleteIndexAsCallback;
5749 deleteIndex$$1(this, indexDef, callback);
5750});
5751
5752/* global PouchDB */
5753
5754if (typeof PouchDB === 'undefined') {
5755 guardedConsole('error', 'pouchdb-find plugin error: ' +
5756 'Cannot find global "PouchDB" object! ' +
5757 'Did you remember to include pouchdb.js?');
5758} else {
5759 PouchDB.plugin(plugin);
5760}
5761
5762}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
5763},{"1":1,"2":2,"3":3,"4":4,"5":5,"6":6}]},{},[11]);