2 lines
53 KiB
JavaScript
2 lines
53 KiB
JavaScript
(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;idx<transform.length;idx++){clonedStep=JSON.parse(JSON.stringify(transform[idx]));resolvedTransform.push(Utils.resolveTransformObject(clonedStep,params))}return resolvedTransform}};function ltHelper(prop1,prop2,equal){if(prop1===prop2){if(equal){return true}else{return false}}if(prop1===undefined){return true}if(prop2===undefined){return false}if(prop1===null){return true}if(prop2===null){return false}return prop1<prop2}function gtHelper(prop1,prop2,equal){if(prop1===prop2){if(equal){return true}else{return false}}if(prop1===undefined){return false}if(prop2===undefined){return true}if(prop1===null){return false}if(prop2===null){return true}return prop1>prop2}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;i<len;i+=1){if(this.collections[i].name===collectionName){return this.collections[i]}}this.emit("warning","collection "+collectionName+" not found");return null};Loki.prototype.listCollections=function(){var i=this.collections.length,colls=[];while(i--){colls.push({name:this.collections[i].name,type:this.collections[i].objType,count:this.collections[i].data.length})}return colls};Loki.prototype.removeCollection=function(collectionName){var i,len=this.collections.length;for(i=0;i<len;i+=1){if(this.collections[i].name===collectionName){this.collections.splice(i,1);return}}};Loki.prototype.getName=function(){return this.name};Loki.prototype.serializeReplacer=function(key,value){switch(key){case"autosaveHandle":case"persistenceAdapter":case"constraints":return null;default:return value}};Loki.prototype.serialize=function(){return JSON.stringify(this,this.serializeReplacer)};Loki.prototype.toJson=Loki.prototype.serialize;Loki.prototype.loadJSON=function(serializedDb,options){if(serializedDb.length===0)serializedDb=JSON.stringify({});var obj=JSON.parse(serializedDb),i=0,len=obj.collections?obj.collections.length:0,coll,copyColl,clen,j;this.name=obj.name;this.databaseVersion=1;if(obj.hasOwnProperty("databaseVersion")){this.databaseVersion=obj.databaseVersion}this.collections=[];for(i;i<len;i+=1){coll=obj.collections[i];copyColl=this.addCollection(coll.name);clen=coll.data.length;j=0;if(options&&options.hasOwnProperty(coll.name)){var loader=options[coll.name].inflate?options[coll.name].inflate:Utils.copyProperties;for(j;j<clen;j++){var collObj=new options[coll.name].proto;loader(coll.data[j],collObj);copyColl.data[j]=collObj}}else{for(j;j<clen;j++){copyColl.data[j]=coll.data[j]}}copyColl.transactional=coll.transactional;copyColl.asyncListeners=coll.asyncListeners;copyColl.disableChangesApi=coll.disableChangesApi;copyColl.cloneObjects=coll.cloneObjects;copyColl.maxId=coll.data.length===0?0:coll.maxId;copyColl.idIndex=coll.idIndex;if(typeof coll.binaryIndices!=="undefined"){copyColl.binaryIndices=coll.binaryIndices}if(typeof coll.transforms!=="undefined"){copyColl.transforms=coll.transforms}copyColl.ensureId();copyColl.uniqueNames=[];if(coll.hasOwnProperty("uniqueNames")){copyColl.uniqueNames=coll.uniqueNames;for(j=0;j<copyColl.uniqueNames.length;j++){copyColl.ensureUniqueIndex(copyColl.uniqueNames[j])}}if(typeof coll.DynamicViews==="undefined")continue;for(var idx=0;idx<coll.DynamicViews.length;idx++){var colldv=coll.DynamicViews[idx];var dv=copyColl.addDynamicView(colldv.name,colldv.options);dv.resultdata=colldv.resultdata;dv.resultsdirty=colldv.resultsdirty;dv.filterPipeline=colldv.filterPipeline;dv.sortCriteria=colldv.sortCriteria;dv.sortFunction=null;dv.sortDirty=colldv.sortDirty;dv.resultset.filteredrows=colldv.resultset.filteredrows;dv.resultset.searchIsChained=colldv.resultset.searchIsChained;dv.resultset.filterInitialized=colldv.resultset.filterInitialized;dv.rematerialize({removeWhereFilters:true})}}};Loki.prototype.close=function(callback){if(this.autosave){this.autosaveDisable();if(this.autosaveDirty()){this.saveDatabase()}}if(callback){this.on("close",callback)}this.emit("close")};Loki.prototype.generateChangesNotification=function(arrayOfCollectionNames){function getCollName(coll){return coll.name}var changes=[],selectedCollections=arrayOfCollectionNames||this.collections.map(getCollName);this.collections.forEach(function(coll){if(selectedCollections.indexOf(getCollName(coll))!==-1){changes=changes.concat(coll.getChanges())}});return changes};Loki.prototype.serializeChanges=function(collectionNamesArray){return JSON.stringify(this.generateChangesNotification(collectionNamesArray))};Loki.prototype.clearChanges=function(){this.collections.forEach(function(coll){if(coll.flushChanges){coll.flushChanges()}})};function LokiFsAdapter(){this.fs=require("fs")}LokiFsAdapter.prototype.loadDatabase=function loadDatabase(dbname,callback){this.fs.readFile(dbname,{encoding:"utf8"},function readFileCallback(err,data){if(err){callback(new Error(err))}else{callback(data)}})};LokiFsAdapter.prototype.saveDatabase=function saveDatabase(dbname,dbstring,callback){this.fs.writeFile(dbname,dbstring,callback)};function LokiLocalStorageAdapter(){}LokiLocalStorageAdapter.prototype.loadDatabase=function loadDatabase(dbname,callback){if(localStorageAvailable()){callback(localStorage.getItem(dbname))}else{callback(new Error("localStorage is not available"))}};LokiLocalStorageAdapter.prototype.saveDatabase=function saveDatabase(dbname,dbstring,callback){if(localStorageAvailable()){localStorage.setItem(dbname,dbstring);callback(null)}else{callback(new Error("localStorage is not available"))}};Loki.prototype.loadDatabase=function(options,callback){var cFun=callback||function(err,data){if(err){throw err}return},self=this;if(this.persistenceAdapter!==null){this.persistenceAdapter.loadDatabase(this.filename,function loadDatabaseCallback(dbString){if(typeof dbString==="string"){self.loadJSON(dbString,options||{});cFun(null);self.emit("loaded","database "+self.filename+" loaded")}else{console.warn("lokijs loadDatabase : Database not found");if(typeof dbString==="object"){cFun(dbString)}else{cFun("Database not found")}}})}else{cFun(new Error("persistenceAdapter not configured"))}};Loki.prototype.saveDatabase=function(callback){var cFun=callback||function(err){if(err){throw err}return},self=this;if(this.persistenceAdapter!==null){this.persistenceAdapter.saveDatabase(this.filename,self.serialize(),function saveDatabasecallback(){self.autosaveClearFlags();cFun(null)})}else{cFun(new Error("persistenceAdapter not configured"))}};Loki.prototype.save=Loki.prototype.saveDatabase;Loki.prototype.autosaveDirty=function(){for(var idx=0;idx<this.collections.length;idx++){if(this.collections[idx].dirty){return true}}return false};Loki.prototype.autosaveClearFlags=function(){for(var idx=0;idx<this.collections.length;idx++){this.collections[idx].dirty=false}};Loki.prototype.autosaveEnable=function(options,callback){this.autosave=true;var delay=5e3,self=this;if(typeof this.autosaveInterval!=="undefined"&&this.autosaveInterval!==null){delay=this.autosaveInterval}this.autosaveHandle=setInterval(function autosaveHandleInterval(){if(self.autosaveDirty()){self.saveDatabase(callback)}},delay)};Loki.prototype.autosaveDisable=function(){if(typeof this.autosaveHandle!=="undefined"&&this.autosaveHandle!==null){clearInterval(this.autosaveHandle);this.autosaveHandle=null}};function Resultset(collection,queryObj,queryFunc,firstOnly){this.collection=collection;this.searchIsChained=!queryObj&&!queryFunc;this.filteredrows=[];this.filterInitialized=false;if(typeof queryObj!=="undefined"&&queryObj!==null){return this.find(queryObj,firstOnly)}if(typeof queryFunc!=="undefined"&&queryFunc!==null){return this.where(queryFunc)}return this}Resultset.prototype.toJSON=function(){var copy=this.copy();copy.collection=null;return copy};Resultset.prototype.limit=function(qty){if(this.searchIsChained&&!this.filterInitialized&&this.filteredrows.length===0){this.filteredrows=Object.keys(this.collection.data)}var rscopy=this.copy();rscopy.filteredrows=rscopy.filteredrows.slice(0,qty);return rscopy};Resultset.prototype.offset=function(pos){if(this.searchIsChained&&!this.filterInitialized&&this.filteredrows.length===0){this.filteredrows=Object.keys(this.collection.data)}var rscopy=this.copy();rscopy.filteredrows=rscopy.filteredrows.splice(pos,rscopy.filteredrows.length);return rscopy};Resultset.prototype.copy=function(){var result=new Resultset(this.collection,null,null);result.filteredrows=this.filteredrows.slice();result.filterInitialized=this.filterInitialized;return result};Resultset.prototype.branch=Resultset.prototype.copy;Resultset.prototype.transform=function(transform,parameters){var idx,step,rs=this;if(typeof parameters!=="undefined"){transform=Utils.resolveTransformParams(transform,parameters)}for(idx=0;idx<transform.length;idx++){step=transform[idx];switch(step.type){case"find":rs.find(step.value);break;case"where":rs.where(step.value);break;case"simplesort":rs.simplesort(step.property,step.desc);break;case"compoundsort":rs.compoundsort(step.value);break;case"sort":rs.sort(step.value);break;case"limit":rs=rs.limit(step.value);break;case"offset":rs=rs.offset(step.value);break;case"map":rs=rs.map(step.value);break;case"eqJoin":rs=rs.eqJoin(step.joinData,step.leftJoinKey,step.rightJoinKey,step.mapFun);break;case"mapReduce":rs=rs.mapReduce(step.mapFunction,step.reduceFunction);break;case"update":rs.update(step.value);break;case"remove":rs.remove();break;default:break}}return rs};Resultset.prototype.sort=function(comparefun){if(this.searchIsChained&&!this.filterInitialized&&this.filteredrows.length===0){this.filteredrows=Object.keys(this.collection.data)}var wrappedComparer=function(userComparer,rslt){return function(a,b){var obj1=rslt.collection.data[a];var obj2=rslt.collection.data[b];return userComparer(obj1,obj2)}}(comparefun,this);this.filteredrows.sort(wrappedComparer);return this};Resultset.prototype.simplesort=function(propname,isdesc){if(this.searchIsChained&&!this.filterInitialized&&this.filteredrows.length===0){this.filteredrows=Object.keys(this.collection.data)}if(typeof isdesc==="undefined"){isdesc=false}var wrappedComparer=function(prop,desc,rslt){return function(a,b){var obj1=rslt.collection.data[a];var obj2=rslt.collection.data[b];return sortHelper(obj1[prop],obj2[prop],desc)}}(propname,isdesc,this);this.filteredrows.sort(wrappedComparer);return this};Resultset.prototype.compoundeval=function(properties,obj1,obj2){var propertyCount=properties.length;if(propertyCount===0){throw new Error("Invalid call to compoundeval, need at least one property")}var isdesc=false;var firstProp=properties[0];if(typeof firstProp!=="string"){if(Array.isArray(firstProp)){isdesc=firstProp[1];firstProp=firstProp[0]}}if(obj1[firstProp]===obj2[firstProp]){if(propertyCount===1){return 0}else{return this.compoundeval(properties.slice(1),obj1,obj2,isdesc)}}return sortHelper(obj1[firstProp],obj2[firstProp],isdesc)};Resultset.prototype.compoundsort=function(properties){if(this.searchIsChained&&!this.filterInitialized&&this.filteredrows.length===0){this.filteredrows=Object.keys(this.collection.data)}var wrappedComparer=function(props,rslt){return function(a,b){var obj1=rslt.collection.data[a];var obj2=rslt.collection.data[b];return rslt.compoundeval(props,obj1,obj2)}}(properties,this);this.filteredrows.sort(wrappedComparer);return this};Resultset.prototype.calculateRange=function(op,prop,val){var rcd=this.collection.data;var index=this.collection.binaryIndices[prop].values;var min=0;var max=index.length-1;var mid=null;var lbound=0;var ubound=index.length-1;if(rcd.length===0){return[0,-1]}var minVal=rcd[index[min]][prop];var maxVal=rcd[index[max]][prop];switch(op){case"$eq":if(ltHelper(val,minVal)||gtHelper(val,maxVal)){return[0,-1]}break;case"$gt":if(gtHelper(val,maxVal,true)){return[0,-1]}break;case"$gte":if(gtHelper(val,maxVal)){return[0,-1]}break;case"$lt":if(ltHelper(val,minVal,true)){return[0,-1]}if(ltHelper(maxVal,val)){return[0,rcd.length-1]}break;case"$lte":if(ltHelper(val,minVal)){return[0,-1]}if(ltHelper(maxVal,val,true)){return[0,rcd.length-1]}break}while(min<max){mid=Math.floor((min+max)/2);if(ltHelper(rcd[index[mid]][prop],val)){min=mid+1}else{max=mid}}lbound=min;min=0;max=index.length-1;while(min<max){mid=Math.floor((min+max)/2);if(ltHelper(val,rcd[index[mid]][prop])){max=mid}else{min=mid+1}}ubound=max;var lval=rcd[index[lbound]][prop];var uval=rcd[index[ubound]][prop];switch(op){case"$eq":if(lval!==val){return[0,-1]}if(uval!==val){ubound--}return[lbound,ubound];case"$gt":if(ltHelper(uval,val,true)){return[0,-1]}return[ubound,rcd.length-1];case"$gte":if(ltHelper(lval,val)){return[0,-1]}return[lbound,rcd.length-1];case"$lt":if(lbound===0&<Helper(lval,val)){return[0,0]}return[0,lbound-1];case"$lte":if(uval!==val){ubound--}if(ubound===0&<Helper(uval,val)){return[0,0]}return[0,ubound];default:return[0,rcd.length-1]}};Resultset.prototype.findOr=function(expressionArray){var fri=0,ei=0,fr=null,docset=[],expResultset=null;if(this.filterInitialized){docset=[];for(ei=0;ei<expressionArray.length;ei++){expResultset=this.branch();expResultset.find(expressionArray[ei]);expResultset.data();fr=expResultset.filteredrows;for(fri=0;fri<fr.length;fri++){if(docset.indexOf(fr[fri])===-1){docset.push(fr[fri])}}}this.filteredrows=docset}else{for(ei=0;ei<expressionArray.length;ei++){expResultset=this.collection.chain();expResultset.find(expressionArray[ei]);expResultset.data();fr=expResultset.filteredrows;for(fri=0;fri<fr.length;fri++){if(this.filteredrows.indexOf(fr[fri])===-1){this.filteredrows.push(fr[fri])}}}}this.filterInitialized=true;return this};Resultset.prototype.findAnd=function(expressionArray){for(var i=0;i<expressionArray.length;i++){this.find(expressionArray[i])}return this};Resultset.prototype.dotSubScan=function(root,property,fun,value){var arrayRef=null;var pathIndex,subIndex;var paths=property.split(".");var path;for(pathIndex=0;pathIndex<paths.length;pathIndex++){path=paths[pathIndex];if(arrayRef){for(subIndex=0;subIndex<arrayRef.length;subIndex++){if(fun(arrayRef[subIndex][path],value)){return true}}}else{root=root[path];if(Array.isArray(root)){arrayRef=root}}}return fun(root,value)};Resultset.prototype.find=function(query,firstOnly){if(this.collection.data.length===0){if(this.searchIsChained){this.filteredrows=[];this.filterInitialized=true;return this}return[]}var queryObject=query||"getAll",property,value,operator,p,key,searchByIndex=false,result=[],index=null,fun,t,i,emptyQO=true;firstOnly=firstOnly||false;for(p in queryObject){emptyQO=false;break}if(emptyQO){queryObject="getAll"}if(queryObject==="getAll"){if(this.searchIsChained){this.filteredrows=Object.keys(this.collection.data);return this}else{return this.collection.data}}var usingDotNotation=false;for(p in queryObject){if(queryObject.hasOwnProperty(p)){property=p;if(p==="$and"){if(this.searchIsChained){this.findAnd(queryObject[p]);if(firstOnly&&this.filteredrows.length>1){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;i<len;i++){result.push(data[fr[i]])}return result};Resultset.prototype.update=function(updateFunction){if(typeof updateFunction!=="function"){throw"Argument is not a function"}if(this.searchIsChained&&!this.filterInitialized&&this.filteredrows.length===0){this.filteredrows=Object.keys(this.collection.data)}var len=this.filteredrows.length,rcd=this.collection.data;for(var idx=0;idx<len;idx++){updateFunction(rcd[this.filteredrows[idx]]);this.collection.update(rcd[this.filteredrows[idx]])}return this};Resultset.prototype.remove=function(){if(this.searchIsChained&&!this.filterInitialized&&this.filteredrows.length===0){this.filteredrows=Object.keys(this.collection.data)}var len=this.filteredrows.length;for(var idx=0;idx<len;idx++){this.collection.remove(this.filteredrows[idx])}this.filteredrows=[];return this};Resultset.prototype.mapReduce=function(mapFunction,reduceFunction){try{return reduceFunction(this.data().map(mapFunction))}catch(err){throw err}};Resultset.prototype.eqJoin=function(joinData,leftJoinKey,rightJoinKey,mapFun){var leftData=[],leftDataLength,rightData=[],rightDataLength,key,result=[],obj,leftKeyisFunction=typeof leftJoinKey==="function",rightKeyisFunction=typeof rightJoinKey==="function",joinMap={};leftData=this.data();leftDataLength=leftData.length;if(joinData instanceof Resultset){rightData=joinData.data()}else if(Array.isArray(joinData)){rightData=joinData}else{throw new TypeError("joinData needs to be an array or result set")}rightDataLength=rightData.length;for(var i=0;i<rightDataLength;i++){key=rightKeyisFunction?rightJoinKey(rightData[i]):rightData[i][rightJoinKey];joinMap[key]=rightData[i]}if(!mapFun){mapFun=function(left,right){return{left:left,right:right}}}for(var j=0;j<leftDataLength;j++){key=leftKeyisFunction?leftJoinKey(leftData[j]):leftData[j][leftJoinKey];result.push(mapFun(leftData[j],joinMap[key]||{}))}this.collection=new Collection("joinData");this.collection.insert(result);this.filteredrows=[];this.filterInitialized=false;return this};Resultset.prototype.map=function(mapFun){var data=this.data().map(mapFun);this.collection=new Collection("mappedData");this.collection.insert(data);this.filteredrows=[];this.filterInitialized=false;return this};function DynamicView(collection,name,options){this.collection=collection;this.name=name;this.rebuildPending=false;this.options=options||{};if(!this.options.hasOwnProperty("persistent")){this.options.persistent=false}if(!this.options.hasOwnProperty("sortPriority")){this.options.sortPriority="passive"}this.resultset=new Resultset(collection);this.resultdata=[];this.resultsdirty=false;this.cachedresultset=null;this.filterPipeline=[];this.sortFunction=null;this.sortCriteria=null;this.sortDirty=false;this.events={rebuild:[]}}DynamicView.prototype=new LokiEventEmitter;DynamicView.prototype.rematerialize=function(options){var fpl,fpi,idx;options=options||{};this.resultdata=[];this.resultsdirty=true;this.resultset=new Resultset(this.collection);if(this.sortFunction||this.sortCriteria){this.sortDirty=true}if(options.hasOwnProperty("removeWhereFilters")){fpl=this.filterPipeline.length;fpi=fpl;while(fpi--){if(this.filterPipeline[fpi].type==="where"){if(fpi!==this.filterPipeline.length-1){this.filterPipeline[fpi]=this.filterPipeline[this.filterPipeline.length-1]}this.filterPipeline.length--}}}var ofp=this.filterPipeline;this.filterPipeline=[];fpl=ofp.length;for(idx=0;idx<fpl;idx++){this.applyFind(ofp[idx].val)}this.data();this.emit("rebuild",this);return this};DynamicView.prototype.branchResultset=function(transform,parameters){var rs=this.resultset.copy();if(typeof transform==="undefined"){return rs}if(typeof transform==="string"){if(this.collection.transforms.hasOwnProperty(transform)){transform=this.collection.transforms[transform]}}if(typeof transform==="object"&&Array.isArray(transform)){return rs.transform(transform,parameters)}return rs};DynamicView.prototype.toJSON=function(){var copy=new DynamicView(this.collection,this.name,this.options);copy.resultset=this.resultset;copy.resultdata=[];copy.resultsdirty=true;copy.filterPipeline=this.filterPipeline;copy.sortFunction=this.sortFunction;copy.sortCriteria=this.sortCriteria;copy.sortDirty=this.sortDirty;copy.collection=null;return copy};DynamicView.prototype.applySort=function(comparefun){this.sortFunction=comparefun;this.sortCriteria=null;this.queueSortPhase();return this};DynamicView.prototype.applySimpleSort=function(propname,isdesc){if(typeof isdesc==="undefined"){isdesc=false}this.sortCriteria=[[propname,isdesc]];this.sortFunction=null;this.queueSortPhase();return this};DynamicView.prototype.applySortCriteria=function(criteria){this.sortCriterial=criteria;this.sortFunction=null;this.queueSortPhase();return this};DynamicView.prototype.startTransaction=function(){this.cachedresultset=this.resultset.copy();return this};DynamicView.prototype.commit=function(){this.cachedresultset=null;return this};DynamicView.prototype.rollback=function(){this.resultset=this.cachedresultset;if(this.options.persistent){this.resultdata=this.resultset.data();this.emit("rebuild",this)}return this};DynamicView.prototype.applyFind=function(query){this.filterPipeline.push({type:"find",val:query});this.resultset.find(query);if(this.sortFunction||this.sortCriteria){this.sortDirty=true;this.queueSortPhase()}if(this.options.persistent){this.resultsdirty=true;this.queueSortPhase()}return this};DynamicView.prototype.applyWhere=function(fun){this.filterPipeline.push({type:"where",val:fun});this.resultset.where(fun);if(this.sortFunction||this.sortCriteria){this.sortDirty=true;this.queueSortPhase()}if(this.options.persistent){this.resultsdirty=true;this.queueSortPhase()}return this};DynamicView.prototype.data=function(){if(this.sortDirty||this.resultsdirty||!this.resultset.filterInitialized){this.performSortPhase()}if(!this.options.persistent){return this.resultset.data()}return this.resultdata};DynamicView.prototype.queueRebuildEvent=function(){var self=this;if(this.rebuildPending){return}this.rebuildPending=true;setTimeout(function(){self.rebuildPending=false;self.emit("rebuild",this)},1)};DynamicView.prototype.queueSortPhase=function(){var self=this;if(this.sortDirty){return}this.sortDirty=true;if(this.options.sortPriority==="active"){setTimeout(function(){self.performSortPhase()},1)}else{this.queueRebuildEvent()}};DynamicView.prototype.performSortPhase=function(){if(!this.sortDirty&&!this.resultsdirty&&this.resultset.filterInitialized){return}if(this.sortFunction){this.resultset.sort(this.sortFunction)}if(this.sortCriteria){this.resultset.compoundsort(this.sortCriteria)}if(!this.options.persistent){this.sortDirty=false;return}this.resultdata=this.resultset.data();this.resultsdirty=false;this.sortDirty=false;this.emit("rebuild",this)};DynamicView.prototype.evaluateDocument=function(objIndex){var ofr=this.resultset.filteredrows;var oldPos=ofr.indexOf(objIndex);
|
|
var oldlen=ofr.length;var evalResultset=new Resultset(this.collection);evalResultset.filteredrows=[objIndex];evalResultset.filterInitialized=true;for(var idx=0;idx<this.filterPipeline.length;idx++){switch(this.filterPipeline[idx].type){case"find":evalResultset.find(this.filterPipeline[idx].val);break;case"where":evalResultset.where(this.filterPipeline[idx].val);break}}var newPos=evalResultset.filteredrows.length===0?-1:0;if(oldPos==-1&&newPos==-1)return;if(oldPos===-1&&newPos!==-1){ofr.push(objIndex);if(this.options.persistent){this.resultdata.push(this.collection.data[objIndex])}if(this.sortFunction||this.sortCriteria){this.queueSortPhase()}else{this.queueRebuildEvent()}return}if(oldPos!==-1&&newPos===-1){if(oldPos<oldlen-1){ofr[oldPos]=ofr[oldlen-1];ofr.length=oldlen-1;if(this.options.persistent){this.resultdata[oldPos]=this.resultdata[oldlen-1];this.resultdata.length=oldlen-1}}else{ofr.length=oldlen-1;if(this.options.persistent){this.resultdata.length=oldlen-1}}if(this.sortFunction||this.sortCriteria){this.queueSortPhase()}else{this.queueRebuildEvent()}return}if(oldPos!==-1&&newPos!==-1){if(this.options.persistent){this.resultdata[oldPos]=this.collection.data[objIndex]}if(this.sortFunction||this.sortCriteria){this.queueSortPhase()}else{this.queueRebuildEvent()}return}};DynamicView.prototype.removeDocument=function(objIndex){var ofr=this.resultset.filteredrows;var oldPos=ofr.indexOf(objIndex);var oldlen=ofr.length;var idx;if(oldPos!==-1){if(oldPos<oldlen-1){ofr[oldPos]=ofr[oldlen-1];ofr.length=oldlen-1;if(this.options.persistent){this.resultdata[oldPos]=this.resultdata[oldlen-1];this.resultdata.length=oldlen-1}}else{ofr.length=oldlen-1;if(this.options.persistent){this.resultdata.length=oldlen-1}}if(this.sortFunction||this.sortCriteria){this.queueSortPhase()}}oldlen=ofr.length;for(idx=0;idx<oldlen;idx++){if(ofr[idx]>objIndex){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;idx<indices.length;idx++){this.ensureIndex(indices[idx])}function createChange(name,op,obj){self.changes.push({name:name,operation:op,obj:JSON.parse(JSON.stringify(obj))})}function flushChanges(){self.changes=[]}this.getChanges=function(){return self.changes};this.flushChanges=flushChanges;function insertMeta(obj){if(!obj){return}if(!obj.meta){obj.meta={}}obj.meta.created=(new Date).getTime();obj.meta.revision=0}function updateMeta(obj){if(!obj){return}obj.meta.updated=(new Date).getTime();obj.meta.revision+=1}function createInsertChange(obj){createChange(self.name,"I",obj)}function createUpdateChange(obj){createChange(self.name,"U",obj)}function insertMetaWithChange(obj){insertMeta(obj);createInsertChange(obj)}function updateMetaWithChange(obj){updateMeta(obj);createUpdateChange(obj)}var insertHandler,updateHandler;function setHandlers(){insertHandler=self.disableChangesApi?insertMeta:insertMetaWithChange;updateHandler=self.disableChangesApi?updateMeta:updateMetaWithChange}setHandlers();this.setChangesApi=function(enabled){self.disableChangesApi=!enabled;setHandlers()};this.on("insert",function insertCallback(obj){insertHandler(obj)});this.on("update",function updateCallback(obj){updateHandler(obj)});this.on("delete",function deleteCallback(obj){if(!self.disableChangesApi){createChange(self.name,"R",obj)}});this.on("warning",console.warn);flushChanges()}Collection.prototype=new LokiEventEmitter;Collection.prototype.addTransform=function(name,transform){if(this.transforms.hasOwnProperty(name)){throw new Error("a transform by that name already exists")}this.transforms[name]=transform};Collection.prototype.setTransform=function(name,transform){this.transforms[name]=transform};Collection.prototype.removeTransform=function(name){delete transforms[name]};Collection.prototype.byExample=function(template){var k,obj,query;query=[];for(k in template){if(!template.hasOwnProperty(k))continue;query.push((obj={},obj[k]=template[k],obj))}return{$and:query}};Collection.prototype.findObject=function(template){return this.findOne(this.byExample(template))};Collection.prototype.findObjects=function(template){return this.find(this.byExample(template))};Collection.prototype.ensureIndex=function(property,force){if(typeof force==="undefined"){force=false}if(property===null||property===undefined){throw"Attempting to set index without an associated property"}if(this.binaryIndices.hasOwnProperty(property)&&!force){if(!this.binaryIndices[property].dirty)return}this.binaryIndices[property]={name:property,dirty:true,values:[]};var index,len=this.data.length,i=0;index=this.binaryIndices[property];for(i;i<len;i+=1){index.values.push(i)}var wrappedComparer=function(prop,coll){return function(a,b){var obj1=coll.data[a];var obj2=coll.data[b];if(obj1[prop]===obj2[prop])return 0;if(gtHelper(obj1[prop],obj2[prop]))return 1;if(ltHelper(obj1[prop],obj2[prop]))return-1}}(property,this);index.values.sort(wrappedComparer);index.dirty=false;this.dirty=true};Collection.prototype.ensureUniqueIndex=function(field){var index=this.constraints.unique[field];if(!index){if(this.uniqueNames.indexOf(field)==-1){this.uniqueNames.push(field)}this.constraints.unique[field]=index=new UniqueIndex(field)}var self=this;this.data.forEach(function(obj){index.set(obj)});return index};Collection.prototype.ensureAllIndexes=function(force){var objKeys=Object.keys(this.binaryIndices);var i=objKeys.length;while(i--){this.ensureIndex(objKeys[i],force)}};Collection.prototype.flagBinaryIndexesDirty=function(){var objKeys=Object.keys(this.binaryIndices);var i=objKeys.length;while(i--){this.binaryIndices[objKeys[i]].dirty=true}};Collection.prototype.count=function(){return this.data.length};Collection.prototype.ensureId=function(){var len=this.data.length,i=0;this.idIndex=[];for(i;i<len;i+=1){this.idIndex.push(this.data[i].$loki)}};Collection.prototype.ensureIdAsync=function(callback){this.async(function(){this.ensureId()},callback)};Collection.prototype.addDynamicView=function(name,options){var dv=new DynamicView(this,name,options);this.DynamicViews.push(dv);return dv};Collection.prototype.removeDynamicView=function(name){for(var idx=0;idx<this.DynamicViews.length;idx++){if(this.DynamicViews[idx].name===name){this.DynamicViews.splice(idx,1)}}};Collection.prototype.getDynamicView=function(name){for(var idx=0;idx<this.DynamicViews.length;idx++){if(this.DynamicViews[idx].name===name){return this.DynamicViews[idx]}}return null};Collection.prototype.findAndUpdate=function(filterFunction,updateFunction){var results=this.where(filterFunction),i=0,obj;try{for(i;i<results.length;i++){obj=updateFunction(results[i]);this.update(obj)}}catch(err){this.rollback();console.error(err.message)}};Collection.prototype.insert=function(doc){if(!doc){var error=new Error("Object cannot be null");this.emit("error",error);throw error}var self=this;var obj;var docs=Array.isArray(doc)?doc:[doc];var results=[];docs.forEach(function(d){if(typeof d!=="object"){throw new TypeError("Document needs to be an object")}obj=self.cloneObjects?JSON.parse(JSON.stringify(d)):d;if(typeof obj.meta==="undefined"){obj.meta={revision:0,created:0}}self.emit("pre-insert",obj);if(self.add(obj)){self.emit("insert",obj);results.push(obj)}else{return undefined}});return results.length===1?results[0]:results};Collection.prototype.clear=function(){this.data=[];this.idIndex=[];this.binaryIndices={};this.cachedIndex=null;this.cachedData=null;this.maxId=0;this.DynamicViews=[];this.dirty=true};Collection.prototype.update=function(doc){if(Object.keys(this.binaryIndices).length>0){this.flagBinaryIndexesDirty()}if(Array.isArray(doc)){var k=0,len=doc.length;for(k;k<len;k+=1){this.update(doc[k])}return}if(!doc.hasOwnProperty("$loki")){throw"Trying to update unsynced document. Please save the document first by using insert() or addMany()"}try{this.startTransaction();var arr=this.get(doc.$loki,true),obj,position,self=this;if(!arr){throw new Error("Trying to update a document not in collection.")}this.emit("pre-update",doc);obj=arr[0];Object.keys(this.constraints.unique).forEach(function(key){self.constraints.unique[key].update(obj)});position=arr[1];this.data[position]=doc;for(var idx=0;idx<this.DynamicViews.length;idx++){this.DynamicViews[idx].evaluateDocument(position)}this.idIndex[position]=obj.$loki;this.commit();this.dirty=true;this.emit("update",doc);return doc}catch(err){this.rollback();console.error(err.message);this.emit("error",err);throw err}};Collection.prototype.add=function(obj){var dvlen=this.DynamicViews.length;if("object"!==typeof obj){throw"Object being added needs to be an object"}if(Object.keys(this.binaryIndices).length>0){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;i<dvlen;i++){this.DynamicViews[i].evaluateDocument(this.data.length-1)}this.idIndex.push(obj.$loki);this.commit();this.dirty=true;return obj}catch(err){this.rollback();console.error(err.message)}};Collection.prototype.removeWhere=function(query){var list;if(typeof query==="function"){list=this.data.filter(query)}else{list=new Resultset(this,query)}var len=list.length;while(len--){this.remove(list[len])}var dv;for(dv in this.DynamicViews){this.DynamicViews[dv].rematerialize()}};Collection.prototype.removeDataOnly=function(){this.removeWhere(function(obj){return true})};Collection.prototype.remove=function(doc){if(typeof doc==="number"){doc=this.get(doc)}if("object"!==typeof doc){throw new Error("Parameter is not an object")}if(Array.isArray(doc)){var k=0,len=doc.length;for(k;k<len;k+=1){this.remove(doc[k])}return}if(!doc.hasOwnProperty("$loki")){throw new Error("Object is not a document stored in the collection")}if(Object.keys(this.binaryIndices).length>0){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;idx<this.DynamicViews.length;idx++){this.DynamicViews[idx].removeDocument(position)}this.data.splice(position,1);this.idIndex.splice(position,1);this.commit();this.dirty=true;this.emit("delete",arr[0]);delete doc.$loki;delete doc.meta;return doc}catch(err){this.rollback();console.error(err.message);this.emit("error",err);return null}};Collection.prototype.get=function(id,returnPosition){var retpos=returnPosition||false,data=this.idIndex,max=data.length-1,min=0,mid=Math.floor(min+(max-min)/2);id=typeof id==="number"?id:parseInt(id,10);if(isNaN(id)){throw"Passed id is not an integer"}while(data[min]<data[max]){mid=Math.floor((min+max)/2);if(data[mid]<id){min=mid+1}else{max=mid}}if(max===min&&data[min]===id){if(retpos){return[this.data[min],min]}return this.data[min]}return null};Collection.prototype.by=function(field,value){var self;if(!value){self=this;return function(value){return self.by(field,value)}}return this.constraints.unique[field].get(value)};Collection.prototype.findOne=function(query){var result=new Resultset(this,query,null,true);if(Array.isArray(result)&&result.length===0){return null}else{return result}};Collection.prototype.chain=function(transform,parameters){var rs=new Resultset(this,null,null);if(typeof transform==="undefined"){return rs}if(typeof transform==="string"){if(this.transforms.hasOwnProperty(transform)){transform=this.transforms[transform]}}if(typeof transform==="object"&&Array.isArray(transform)){return rs.transform(transform,parameters)}return null};Collection.prototype.find=function(query){if(typeof query==="undefined"){query="getAll"}return new Resultset(this,query,null)};Collection.prototype.findOneUnindexed=function(prop,value){var i=this.data.length,doc;while(i--){if(this.data[i][prop]===value){doc=this.data[i];return doc}}return null};Collection.prototype.startTransaction=function(){if(this.transactional){this.cachedData=clone(this.data,"parse-stringify");this.cachedIndex=this.idIndex;this.cachedBinaryIndex=this.binaryIndices;for(var idx=0;idx<this.DynamicViews.length;idx++){this.DynamicViews[idx].startTransaction()}}};Collection.prototype.commit=function(){if(this.transactional){this.cachedData=null;this.cachedIndex=null;this.cachedBinaryIndices=null;for(var idx=0;idx<this.DynamicViews.length;idx++){this.DynamicViews[idx].commit()}}};Collection.prototype.rollback=function(){if(this.transactional){if(this.cachedData!==null&&this.cachedIndex!==null){this.data=this.cachedData;this.idIndex=this.cachedIndex;this.binaryIndices=this.cachedBinaryIndex}for(var idx=0;idx<this.DynamicViews.length;idx++){this.DynamicViews[idx].rollback()}}};Collection.prototype.async=function(fun,callback){setTimeout(function(){if(typeof fun==="function"){fun();callback()}else{throw"Argument passed for async execution is not a function"}},0)};Collection.prototype.where=function(fun){return new Resultset(this,null,fun)};Collection.prototype.mapReduce=function(mapFunction,reduceFunction){try{return reduceFunction(this.data.map(mapFunction))}catch(err){throw err}};Collection.prototype.eqJoin=function(joinData,leftJoinProp,rightJoinProp,mapFun){return new Resultset(this).eqJoin(joinData,leftJoinProp,rightJoinProp,mapFun)};Collection.prototype.stages={};Collection.prototype.getStage=function(name){if(!this.stages[name]){this.stages[name]={}}return this.stages[name]};Collection.prototype.commitLog=[];Collection.prototype.stage=function(stageName,obj){var copy=JSON.parse(JSON.stringify(obj));this.getStage(stageName)[obj.$loki]=copy;return copy};Collection.prototype.commitStage=function(stageName,message){var stage=this.getStage(stageName),prop,timestamp=(new Date).getTime();for(prop in stage){this.update(stage[prop]);this.commitLog.push({timestamp:timestamp,message:message,data:JSON.parse(JSON.stringify(stage[prop]))})}this.stages[stageName]={}};Collection.prototype.no_op=function(){return};Collection.prototype.extract=function(field){var i=0,len=this.data.length,isDotNotation=isDeepProperty(field),result=[];for(i;i<len;i+=1){result.push(deepProperty(this.data[i],field,isDotNotation))}return result};Collection.prototype.max=function(field){return Math.max.apply(null,this.extract(field))};Collection.prototype.min=function(field){return Math.min.apply(null,this.extract(field))};Collection.prototype.maxRecord=function(field){var i=0,len=this.data.length,deep=isDeepProperty(field),result={index:0,value:undefined},max;for(i;i<len;i+=1){if(max!==undefined){if(max<deepProperty(this.data[i],field,deep)){max=deepProperty(this.data[i],field,deep);result.index=this.data[i].$loki}}else{max=deepProperty(this.data[i],field,deep);result.index=this.data[i].$loki}}result.value=max;return result};Collection.prototype.minRecord=function(field){var i=0,len=this.data.length,deep=isDeepProperty(field),result={index:0,value:undefined},min;for(i;i<len;i+=1){if(min!==undefined){if(min>deepProperty(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(max<dict[prop]){mode=prop}}else{mode=prop;max=dict[prop]}}return mode};Collection.prototype.median=function(field){var values=this.extractNumerical(field);values.sort(sub);var half=Math.floor(values.length/2);if(values.length%2){return values[half]}else{return(values[half-1]+values[half])/2}};function isDeepProperty(field){return field.indexOf(".")!==-1}function parseBase10(num){return parseFloat(num,10)}function isNotUndefined(obj){return obj!==undefined}function add(a,b){return a+b}function sub(a,b){return a-b}function median(values){values.sort(sub);var half=Math.floor(values.length/2);return values.length%2?values[half]:(values[half-1]+values[half])/2}function average(array){return array.reduce(add,0)/array.length}function standardDeviation(values){var avg=average(values);var squareDiffs=values.map(function(value){var diff=value-avg;var sqrDiff=diff*diff;return sqrDiff});var avgSquareDiff=average(squareDiffs);var stdDev=Math.sqrt(avgSquareDiff);return stdDev}function deepProperty(obj,property,isDeep){if(isDeep===false){return obj[property]}var pieces=property.split("."),root=obj;while(pieces.length>0){root=root[pieces.shift()]}return root}function binarySearch(array,item,fun){var lo=0,hi=array.length,compared,mid;while(lo<hi){mid=(lo+hi)/2|0;compared=fun.apply(null,[item,array[mid]]);if(compared===0){return{found:true,index:mid}}else if(compared<0){hi=mid}else{lo=mid+1}}return{found:false,index:hi}}function BSonSort(fun){return function(array,item){return binarySearch(array,item,fun)}}function KeyValueStore(){}KeyValueStore.prototype={keys:[],values:[],sort:function(a,b){return a<b?-1:a>b?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 a<b?-1:a>b?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<end;i++){results=results.concat(this.values[i])}return results},getPos:function(key){return binarySearch(this.keys,key,this.sort)},remove:function(key,value){var pos=binarySearch(this.keys,key,this.sort).index;var idxSet=this.values[pos];for(var i in idxSet){if(idxSet[i]==value)idxSet.splice(i,1)}if(idxSet.length<1){this.keys.splice(pos,1);this.values.splice(pos,1)}},clear:function(){this.keys=[];this.values=[]}};Loki.Collection=Collection;Loki.KeyValueStore=KeyValueStore;return Loki}()});
|