UNPKG

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