UNPKG

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