(function(root,factory){if(typeof define==="function"&&define.amd){define([],factory)}else if(typeof exports==="object"){module.exports=factory()}else{root.loki=factory()}})(this,function(){return function(){"use strict";var Utils={copyProperties:function(src,dest){var prop;for(prop in src){dest[prop]=src[prop]}},resolveTransformObject:function(subObj,params,depth){var prop,pname;if(typeof depth!=="number"){depth=0}if(++depth>=10)return subObj;for(prop in subObj){if(typeof subObj[prop]==="string"&&subObj[prop].indexOf("[%lktxp]")===0){pname=subObj[prop].substring(8);if(params.hasOwnProperty(pname)){subObj[prop]=params[pname]}}else if(typeof subObj[prop]==="object"){subObj[prop]=Utils.resolveTransformObject(subObj[prop],params,depth)}}return subObj},resolveTransformParams:function(transform,params){var idx,prop,clonedStep,resolvedTransform=[];if(typeof params==="undefined")return transform;for(idx=0;idxprop2}function sortHelper(prop1,prop2,desc){if(prop1===prop2){return 0}if(desc){if(ltHelper(prop1,prop2)){return 1}else{return-1}}else{if(gtHelper(prop1,prop2)){return 1}else{return-1}}}function containsCheckFn(a,b){if(Array.isArray(a)){return function(curr){return a.indexOf(curr)!==-1}}else if(a&&typeof a==="string"){return function(curr){return a.indexOf(curr)!==-1}}else if(a&&typeof a==="object"){return function(curr){return a.hasOwnProperty(curr)}}}var LokiOps={$eq:function(a,b){return a===b},$gt:function(a,b){return gtHelper(a,b)},$gte:function(a,b){return gtHelper(a,b,true)},$lt:function(a,b){return ltHelper(a,b)},$lte:function(a,b){return ltHelper(a,b,true)},$ne:function(a,b){return a!==b},$regex:function(a,b){return b.test(a)},$in:function(a,b){return b.indexOf(a)>-1},$containsAny:function(a,b){var checkFn;if(!Array.isArray(b)){b=[b]}checkFn=containsCheckFn(a,b)||function(){return false};return b.reduce(function(prev,curr){if(prev){return prev}return checkFn(curr)},false)},$contains:function(a,b){var checkFn;if(!Array.isArray(b)){b=[b]}checkFn=containsCheckFn(a,b)||function(){return false};return b.reduce(function(prev,curr){if(!prev){return prev}return checkFn(curr)},true)}};var operators={$eq:LokiOps.$eq,$gt:LokiOps.$gt,$gte:LokiOps.$gte,$lt:LokiOps.$lt,$lte:LokiOps.$lte,$ne:LokiOps.$ne,$regex:LokiOps.$regex,$in:LokiOps.$in,$contains:LokiOps.$contains,$containsAny:LokiOps.$containsAny};var indexedOpsList=["$eq","$gt","$gte","$lt","$lte"];function clone(data,method){var cloneMethod=method||"parse-stringify",cloned;if(cloneMethod==="parse-stringify"){cloned=JSON.parse(JSON.stringify(data))}return cloned}function localStorageAvailable(){try{return"localStorage"in window&&window.localStorage!==null}catch(e){return false}}function LokiEventEmitter(){}LokiEventEmitter.prototype.events={};LokiEventEmitter.prototype.asyncListeners=false;LokiEventEmitter.prototype.on=function(eventName,listener){var event=this.events[eventName];if(!event){event=this.events[eventName]=[]}event.push(listener);return listener};LokiEventEmitter.prototype.emit=function(eventName,data){var self=this;if(eventName&&this.events[eventName]){this.events[eventName].forEach(function(listener){if(self.asyncListeners){setTimeout(function(){listener(data)},1)}else{listener(data)}})}else{throw new Error("No event "+eventName+" defined")}};LokiEventEmitter.prototype.removeListener=function(eventName,listener){if(this.events[eventName]){var listeners=this.events[eventName];listeners.splice(listeners.indexOf(listener),1)}};function Loki(filename,options){this.filename=filename||"loki.db";this.collections=[];this.databaseVersion=1.1;this.engineVersion=1.1;this.autosave=false;this.autosaveInterval=5e3;this.autosaveHandle=null;this.options={};this.persistenceMethod=null;this.persistenceAdapter=null;this.events={init:[],loaded:[],flushChanges:[],close:[],changes:[],warning:[]};var getENV=function(){if(typeof window==="undefined"){return"NODEJS"}if(typeof global!=="undefined"&&global.window){return"NODEJS"}if(typeof document!=="undefined"){if(document.URL.indexOf("http://")===-1&&document.URL.indexOf("https://")===-1){return"CORDOVA"}return"BROWSER"}return"CORDOVA"};if(options&&options.hasOwnProperty("env")){this.ENV=options.env}else{this.ENV=getENV()}if(this.ENV==="undefined"){this.ENV="NODEJS"}this.configureOptions(options,true);this.on("init",this.clearChanges)}Loki.prototype=new LokiEventEmitter;Loki.prototype.getIndexedAdapter=function(){var adapter;if(typeof require==="function"){adapter=require("./loki-indexed-adapter.js")}return adapter};Loki.prototype.configureOptions=function(options,initialConfig){var defaultPersistence={NODEJS:"fs",BROWSER:"localStorage",CORDOVA:"localStorage"},persistenceMethods={fs:LokiFsAdapter,localStorage:LokiLocalStorageAdapter};this.options={};this.persistenceMethod=null;this.persistenceAdapter=null;if(typeof options!=="undefined"){this.options=options;if(this.options.hasOwnProperty("persistenceMethod")){if(typeof persistenceMethods[options.persistenceMethod]=="function"){this.persistenceMethod=options.persistenceMethod;this.persistenceAdapter=new persistenceMethods[options.persistenceMethod]}}if(this.options.hasOwnProperty("adapter")){this.persistenceMethod="adapter";this.persistenceAdapter=options.adapter}if(options.hasOwnProperty("autoload")&&typeof initialConfig!=="undefined"&&initialConfig){var self=this;setTimeout(function(){self.loadDatabase(options,options.autoloadCallback)},1)}if(this.options.hasOwnProperty("autosaveInterval")){this.autosaveDisable();this.autosaveInterval=parseInt(this.options.autosaveInterval,10)}if(this.options.hasOwnProperty("autosave")&&this.options.autosave){this.autosaveDisable();this.autosave=true;if(this.options.hasOwnProperty("autosaveCallback")){this.autosaveEnable(options,options.autosaveCallback)}else{this.autosaveEnable()}}}if(this.persistenceAdapter===null){this.persistenceMethod=defaultPersistence[this.ENV];if(this.persistenceMethod){this.persistenceAdapter=new persistenceMethods[this.persistenceMethod]}}};Loki.prototype.anonym=function(docs,indexesArray){var collection=new Collection("anonym",indexesArray);collection.insert(docs);return collection};Loki.prototype.addCollection=function(name,options){var collection=new Collection(name,options);this.collections.push(collection);return collection};Loki.prototype.loadCollection=function(collection){if(!collection.name){throw new Error("Collection must have a name property to be loaded")}this.collections.push(collection)};Loki.prototype.getCollection=function(collectionName){var i,len=this.collections.length;for(i=0;i1){this.filteredrows=this.filteredrows.slice(0,1)}return this}else{result=this.collection.chain().findAnd(queryObject[p]).data();if(firstOnly){if(result.length===0)return[];return result[0]}return result}}if(p==="$or"){if(this.searchIsChained){this.findOr(queryObject[p]);if(firstOnly&&this.filteredrows.length>1){this.filteredrows=this.filteredrows.slice(0,1)}return this}else{result=this.collection.chain().findOr(queryObject[p]).data();if(firstOnly){if(result.length===0)return[];return result[0]}return result}}if(p.indexOf(".")!=-1){usingDotNotation=true}if(queryObject[p]===null||typeof queryObject[p]!=="object"){operator="$eq";value=queryObject[p]}else if(typeof queryObject[p]==="object"){for(key in queryObject[p]){if(queryObject[p].hasOwnProperty(key)){operator=key;value=queryObject[p][key]}}}else{throw"Do not know what you want to do."}break}}if(operator==="$regex")value=new RegExp(value);if(this.collection.data===null){throw new TypeError}if((!this.searchIsChained||this.searchIsChained&&!this.filterInitialized)&&indexedOpsList.indexOf(operator)!==-1&&this.collection.binaryIndices.hasOwnProperty(property)){this.collection.ensureIndex(property);searchByIndex=true;index=this.collection.binaryIndices[property]}fun=operators[operator];if(!this.searchIsChained){if(!searchByIndex){t=this.collection.data;i=t.length;if(firstOnly){if(usingDotNotation){while(i--){if(this.dotSubScan(t[i],property,fun,value)){return t[i]}}}else{while(i--){if(fun(t[i][property],value)){return t[i]}}}return[]}else{if(usingDotNotation){while(i--){if(this.dotSubScan(t[i],property,fun,value)){result.push(t[i])}}}else{while(i--){if(fun(t[i][property],value)){result.push(t[i])}}}}}else{t=this.collection.data;var seg=this.calculateRange(operator,property,value,this);if(firstOnly){if(seg[1]!==-1){return t[index.values[seg[0]]]}return[]}for(i=seg[0];i<=seg[1];i++){result.push(t[index.values[i]])}this.filteredrows=result}return result}else{if(this.filterInitialized){if(!searchByIndex){t=this.collection.data;i=this.filteredrows.length;if(usingDotNotation){while(i--){if(this.dotSubScan(t[this.filteredrows[i]],property,fun,value)){result.push(this.filteredrows[i])}}}else{while(i--){if(fun(t[this.filteredrows[i]][property],value)){result.push(this.filteredrows[i])}}}}else{t=index;i=this.filteredrows.length;while(i--){if(fun(t[this.filteredrows[i]],value)){result.push(this.filteredrows[i])}}}this.filteredrows=result;return this}else{if(!searchByIndex){t=this.collection.data;i=t.length;if(usingDotNotation){while(i--){if(this.dotSubScan(t[i],property,fun,value)){result.push(i)}}}else{while(i--){if(fun(t[i][property],value)){result.push(i)}}}}else{t=this.collection.data;var segm=this.calculateRange(operator,property,value,this);for(var idx=segm[0];idx<=segm[1];idx++){result.push(index.values[idx])}this.filteredrows=result}this.filteredrows=result;this.filterInitialized=true;return this}}};Resultset.prototype.where=function(fun){var viewFunction,result=[];if("function"===typeof fun){viewFunction=fun}else{throw"Argument is not a stored view or a function"}try{if(!this.searchIsChained){var i=this.collection.data.length;while(i--){if(viewFunction(this.collection.data[i])===true){result.push(this.collection.data[i])}}return result}else{if(this.filterInitialized){var j=this.filteredrows.length;while(j--){if(viewFunction(this.collection.data[this.filteredrows[j]])===true){result.push(this.filteredrows[j])}}this.filteredrows=result;return this}else{var k=this.collection.data.length;while(k--){if(viewFunction(this.collection.data[k])===true){result.push(k)}}this.filteredrows=result;this.filterInitialized=true;return this}}}catch(err){throw err}};Resultset.prototype.data=function(){var result=[];if(this.searchIsChained&&!this.filterInitialized){if(this.filteredrows.length===0){return this.collection.data}else{this.filterInitialized=true}}var data=this.collection.data,fr=this.filteredrows;var i,len=this.filteredrows.length;for(i=0;iobjIndex){ofr[idx]--}}};DynamicView.prototype.mapReduce=function(mapFunction,reduceFunction){try{return reduceFunction(this.data().map(mapFunction))}catch(err){throw err}};function Collection(name,options){this.name=name;this.data=[];this.idIndex=[];this.binaryIndices={};this.constraints={unique:{},exact:{}};this.uniqueNames=[];this.transforms={};this.objType=name;this.dirty=true;this.cachedIndex=null;this.cachedBinaryIndex=null;this.cachedData=null;var self=this;options=options||{};if(options.hasOwnProperty("unique")){if(!Array.isArray(options.unique)){options.unique=[options.unique]}options.unique.forEach(function(prop){self.uniqueNames.push(prop);self.constraints.unique[prop]=new UniqueIndex(prop)})}if(options.hasOwnProperty("exact")){options.exact.forEach(function(prop){self.constraints.exact[prop]=new ExactIndex(prop)})}this.transactional=options.hasOwnProperty("transactional")?options.transactional:false;this.cloneObjects=options.hasOwnProperty("clone")?options.clone:false;this.asyncListeners=options.hasOwnProperty("asyncListeners")?options.asyncListeners:false;this.disableChangesApi=options.hasOwnProperty("disableChangesApi")?options.disableChangesApi:true;this.maxId=0;this.DynamicViews=[];this.events={insert:[],update:[],"pre-insert":[],"pre-update":[],close:[],flushbuffer:[],error:[],"delete":[],warning:[]};this.changes=[];this.ensureId();var indices=[];if(options&&options.indices){if(Object.prototype.toString.call(options.indices)==="[object Array]"){indices=options.indices}else if(typeof options.indices==="string"){indices=[options.indices]}else{throw new TypeError("Indices needs to be a string or an array of strings")}}for(var idx=0;idx0){this.flagBinaryIndexesDirty()}if(Array.isArray(doc)){var k=0,len=doc.length;for(k;k0){this.flagBinaryIndexesDirty()}if(typeof obj.$loki!=="undefined"){throw"Document is already in collection, please use update()"}try{this.startTransaction();this.maxId++;if(isNaN(this.maxId)){this.maxId=this.data[this.data.length-1].$loki+1}obj.$loki=this.maxId;obj.meta.version=0;var self=this;Object.keys(this.constraints.unique).forEach(function(key){self.constraints.unique[key].set(obj)});this.data.push(obj);for(var i=0;i0){this.flagBinaryIndexesDirty()}try{this.startTransaction();var arr=this.get(doc.$loki,true),position=arr[1];var self=this;Object.keys(this.constraints.unique).forEach(function(key){if(doc[key]!==null&&typeof doc[key]!=="undefined"){self.constraints.unique[key].remove(doc[key])}});for(var idx=0;idxdeepProperty(this.data[i],field,deep)){min=deepProperty(this.data[i],field,deep);result.index=this.data[i].$loki}}else{min=deepProperty(this.data[i],field,deep);result.index=this.data[i].$loki}}result.value=min;return result};Collection.prototype.extractNumerical=function(field){return this.extract(field).map(parseBase10).filter(Number).filter(function(n){return!isNaN(n)})};Collection.prototype.avg=function(field){return average(this.extractNumerical(field))};Collection.prototype.stdDev=function(field){return standardDeviation(this.extractNumerical(field))};Collection.prototype.mode=function(field){var dict={},data=this.extract(field);data.forEach(function(obj){if(dict[obj]){dict[obj]+=1}else{dict[obj]=1}});var max,prop,mode;for(prop in dict){if(max){if(max0){root=root[pieces.shift()]}return root}function binarySearch(array,item,fun){var lo=0,hi=array.length,compared,mid;while(lob?1:0},setSort:function(fun){this.bs=new BSonSort(fun)},bs:function(){return new BSonSort(this.sort)},set:function(key,value){var pos=this.bs(this.keys,key);if(pos.found){this.values[pos.index]=value}else{this.keys.splice(pos.index,0,key);this.values.splice(pos.index,0,value)}},get:function(key){return this.values[binarySearch(this.keys,key,this.sort).index]}};function UniqueIndex(uniqueField){this.field=uniqueField;this.keyMap={};this.lokiMap={}}UniqueIndex.prototype.keyMap={};UniqueIndex.prototype.lokiMap={};UniqueIndex.prototype.set=function(obj){if(obj[this.field]!==null&&typeof obj[this.field]!=="undefined"){if(this.keyMap[obj[this.field]]){throw new Error("Duplicate key for property "+this.field+": "+obj[this.field])}else{this.keyMap[obj[this.field]]=obj;this.lokiMap[obj.$loki]=obj[this.field]}}};UniqueIndex.prototype.get=function(key){return this.keyMap[key]};UniqueIndex.prototype.byId=function(id){return this.keyMap[this.lokiMap[id]]};UniqueIndex.prototype.update=function(obj){if(this.lokiMap[obj.$loki]!==obj[this.field]){var old=this.lokiMap[obj.$loki];this.set(obj);this.keyMap[old]=undefined}else{this.keyMap[obj[this.field]]=obj}};UniqueIndex.prototype.remove=function(key){var obj=this.keyMap[key];if(obj!==null&&typeof obj!=="undefined"){this.keyMap[key]=undefined;this.lokiMap[obj.$loki]=undefined}else{throw new Error("Key is not in unique index: "+this.field)}};UniqueIndex.prototype.clear=function(){this.keyMap={};this.lokiMap={}};function ExactIndex(exactField){this.index={};this.field=exactField}ExactIndex.prototype={set:function add(key,val){if(this.index[key]){this.index[key].push(val)}else{this.index[key]=[val]}},remove:function remove(key,val){var idxSet=this.index[key];for(var i in idxSet){if(idxSet[i]==val){idxSet.splice(i,1)}}if(idxSet.length<1){this.index[key]=undefined}},get:function get(key){return this.index[key]},clear:function clear(key){this.index={}}};function SortedIndex(sortedField){this.field=sortedField}SortedIndex.prototype={keys:[],values:[],sort:function(a,b){return ab?1:0},bs:function(){return new BSonSort(this.sort)},setSort:function(fun){this.bs=new BSonSort(fun)},set:function(key,value){var pos=binarySearch(this.keys,key,this.sort);if(pos.found){this.values[pos.index].push(value)}else{this.keys.splice(pos.index,0,key);this.values.splice(pos.index,0,[value])}},get:function(key){var bsr=binarySearch(this.keys,key,this.sort);if(bsr.found){return this.values[bsr.index]}else{return[]}},getLt:function(key){var bsr=binarySearch(this.keys,key,this.sort);var pos=bsr.index;if(bsr.found)pos--;return this.getAll(key,0,pos)},getGt:function(key){var bsr=binarySearch(this.keys,key,this.sort);var pos=bsr.index;if(bsr.found)pos++;return this.getAll(key,pos,this.keys.length)},getAll:function(key,start,end){var results=[];for(var i=start;i