Comparing version 0.1.2 to 0.1.3
@@ -1,1 +0,1 @@ | ||
(function(){"use strict";function normalize(expr){for(var i=0;i<primitives.length;i++)if(primitives[i](expr))return _.isRegExp(expr)?{$regex:expr}:{$eq:expr};if(_.isObject(expr)){var keys=_.keys(expr),notQuery=0===_.intersection(Ops.queryOperators,keys).length;if(notQuery)return{$eq:expr};if(_.contains(keys,"$regex")){var regex=expr.$regex,options=expr.$options||"",modifiers="";_.isString(regex)&&(modifiers+=regex.ignoreCase||options.indexOf("i")>=0?"i":"",modifiers+=regex.multiline||options.indexOf("m")>=0?"m":"",modifiers+=regex.global||options.indexOf("g")>=0?"g":"",regex=new RegExp(regex,modifiers)),expr.$regex=regex,delete expr.$options}}return expr}var previousMingo,_,root=this,Mingo={};null!=root&&(previousMingo=root.Mingo),Mingo.noConflict=function(){return root.Mingo=previousMingo,Mingo},"undefined"!=typeof exports?(exports="undefined"!=typeof module&&module.exports?module.exports=Mingo:Mingo,_=require("underscore")):(root.Mingo=Mingo,_=root._);var primitives=[_.isString,_.isBoolean,_.isNumber,_.isDate,_.isNull,_.isRegExp],settings={key:"_id"};Mingo.setup=function(options){_.extend(settings,options||{})},Mingo.Query=function(criteria){this._criteria=criteria||{},this._compiledSelectors=[],this._compile()},Mingo.Query.prototype={_compile:function(){if(!_.isEmpty(this._criteria)){if(_.isArray(this._criteria)||_.isFunction(this._criteria)||!_.isObject(this._criteria))throw new Error("Invalid type for criteria");for(var name in this._criteria)if(this._criteria.hasOwnProperty(name)){var expr=this._criteria[name];if(_.contains(Ops.compoundOperators,name)){if(_.contains(["$not"],name))throw Error("Invalid operator");this._processOperator(name,name,expr)}else{expr=normalize(expr);for(var op in expr)expr.hasOwnProperty(op)&&this._processOperator(name,op,expr[op])}}}},_processOperator:function(field,operator,value){var compiledSelector;if(_.contains(Ops.simpleOperators,operator))compiledSelector={test:function(obj){var actualValue=Mingo._resolve(obj,field);return simpleOperators[operator](actualValue,value)}};else{if(!_.contains(Ops.compoundOperators,operator))throw Error("Invalid query operator '"+operator+"' detected");compiledSelector=compoundOperators[operator](field,value)}this._compiledSelectors.push(compiledSelector)},test:function(model){for(var match=!0,i=0;i<this._compiledSelectors.length;i++){var compiled=this._compiledSelectors[i];if(match=compiled.test(model),match===!1)break}return match},find:function(collection,projection){return new Mingo.Cursor(collection,this,projection)},remove:function(collection){for(var arr=[],i=0;i<collection.length;i++)this.test(collection[i])===!1&&arr.push(collection[i]);return arr}},Mingo.Cursor=function(collection,query,projection){this._query=query,this._collection=collection,this._projection=projection,this._operators={},this._result=!1,this._position=0},Mingo.Cursor.prototype={_fetch:function(){var self=this;if(this._result===!1){if(_.isObject(this._projection)&&_.extend(this._operators,{$project:this._projection}),!_.isArray(this._collection))throw Error("Input collection is not of a valid type.");this._result=_.filter(this._collection,this._query.test,this._query);var pipeline=[];if(_.each(["$sort","$skip","$limit","$project"],function(op){_.has(self._operators,op)&&pipeline.push(_.pick(self._operators,op))}),pipeline.length>0){var aggregator=new Mingo.Aggregator(pipeline);this._result=aggregator.run(this._result,this._query)}}return this._result},all:function(){return this._fetch()},first:function(){return this.count()>0?this._fetch()[0]:null},last:function(){return this.count()>0?this._fetch()[this.count()-1]:null},count:function(){return this._fetch().length},skip:function(n){return _.extend(this._operators,{$skip:n}),this},limit:function(n){return _.extend(this._operators,{$limit:n}),this},sort:function(modifier){return _.extend(this._operators,{$sort:modifier}),this},next:function(){return this.hasNext()?this._fetch()[this._position++]:!1},hasNext:function(){return this.count()>this._position},max:function(expr){return groupOperators.$max(this._fetch(),expr)},min:function(expr){return groupOperators.$min(this._fetch(),expr)},map:function(callback){return _.map(this._fetch(),callback)},forEach:function(callback){_.each(this._fetch(),callback)}},Mingo.Aggregator=function(operators){this._operators=operators},Mingo.Aggregator.prototype={run:function(collection,query){if(!_.isEmpty(this._operators))for(var i=0;i<this._operators.length;i++){var operator=this._operators[i];for(var key in operator)operator.hasOwnProperty(key)&&(collection=query?pipelineOperators[key].call(query,collection,operator[key]):pipelineOperators[key](collection,operator[key]))}return collection}},Mingo._get=function(obj,field){return _.result(obj,field)},Mingo._resolve=function(obj,field){if(!field)return void 0;for(var isText,names=field.split("."),value=obj,i=0;i<names.length;i++){if(isText=null===names[i].match(/^\d+$/),isText&&_.isArray(value)){var res=[];_.each(value,function(item){_.isObject(item)&&res.push(Mingo._resolve(item,names[i]))}),value=res}else value=Mingo._get(value,names[i]);if(void 0===value)break}return value},Mingo.compile=function(criteria){return new Mingo.Query(criteria)},Mingo.find=function(collection,criteria,projection){return new Mingo.Query(criteria).find(collection,projection)},Mingo.remove=function(collection,criteria){return new Mingo.Query(criteria).remove(collection)},Mingo.aggregate=function(collection,pipeline){if(!_.isArray(pipeline))throw Error("Aggregation pipeline must be an array");return new Mingo.Aggregator(pipeline).run(collection)},Mingo.CollectionMixin={query:function(criteria,projection){return Mingo.find(this.toJSON(),criteria,projection)},aggregate:function(pipeline){var args=[this.toJSON(),pipeline];return Mingo.aggregate.apply(null,args)}};var pipelineOperators={$group:function(collection,expr){var idKey=expr[settings.key],indexes=[],groups=_.groupBy(collection,function(obj){var key=computeValue(obj,idKey,idKey);return indexes.push(key),key});indexes=_.uniq(indexes),expr=_.omit(expr,settings.key);var result=[];return _.each(indexes,function(index){var obj={};obj[settings.key]=index;for(var key in expr)expr.hasOwnProperty(key)&&(obj[key]=accumulate(groups[index],key,expr[key]));result.push(obj)}),result},$match:function(collection,expr){var query=new Mingo.Query(expr);return query.find(collection).all()},$project:function(collection,expr){var projected=[],objKeys=_.keys(expr),removeId=!1;if(_.contains(objKeys,settings.key)){var id=objKeys[settings.key];removeId=0===id||id===!1}for(var i=0;i<collection.length;i++){var obj=collection[i],cloneObj={};_.each(objKeys,function(key){if(!removeId||key!==settings.key){var subExpr=expr[key];if(_.isString(subExpr))cloneObj[key]=computeValue(obj,subExpr,key);else if(1===subExpr||subExpr===!0)cloneObj[key]=_.result(obj,key);else if(_.isObject(subExpr)){var operator=_.keys(subExpr);if(operator=operator.length>1?!1:operator[0],operator!==!1&&_.contains(Ops.projectionOperators,operator)){var temp=projectionOperators[operator](obj,subExpr[operator],key);_.isUndefined(temp)||(cloneObj[key]=temp)}else cloneObj[key]=computeValue(obj,subExpr,key)}}}),removeId||_.has(cloneObj,settings.key)||(cloneObj[settings.key]=obj[settings.key]),projected.push(cloneObj)}return projected},$limit:function(collection,value){return _.first(collection,value)},$skip:function(collection,value){return _.rest(collection,value)},$unwind:function(collection,expr){for(var result=[],field=expr.substr(1),i=0;i<collection.length;i++){var obj=collection[i],value=Mingo._get(obj,field);if(!_.isArray(value))throw new Error("Target field '"+field+"' is not of type Array.");_.each(value,function(item){var tmp=_.clone(obj);tmp[field]=item,result.push(tmp)})}return result},$sort:function(collection,sortKeys){if(!_.isEmpty(sortKeys)&&_.isObject(sortKeys)){var modifiers=_.keys(sortKeys);modifiers.reverse().forEach(function(key){var indexes=[],grouped=_.groupBy(collection,function(obj){var value=Mingo._resolve(obj,key);return indexes.push(value),value});indexes=_.sortBy(_.uniq(indexes),function(item){return item}),-1===sortKeys[key]&&indexes.reverse(),collection=[],_.each(indexes,function(item){Array.prototype.push.apply(collection,grouped[item])})})}return collection}},compoundOperators={$and:function(selector,value){if(!_.isArray(value))throw new Error("Invalid expression for $and criteria");var queries=[];return _.each(value,function(expr){queries.push(new Mingo.Query(expr))}),{test:function(obj){for(var i=0;i<queries.length;i++)if(queries[i].test(obj)===!1)return!1;return!0}}},$or:function(selector,value){if(!_.isArray(value))throw new Error("Invalid expression for $or criteria");var queries=[];return _.each(value,function(expr){queries.push(new Mingo.Query(expr))}),{test:function(obj){for(var i=0;i<queries.length;i++)if(queries[i].test(obj))return!0;return!1}}},$nor:function(selector,value){if(!_.isArray(value))throw new Error("Invalid expression for $nor criteria");var query=this.$or("$or",value);return{test:function(obj){return!query.test(obj)}}},$not:function(selector,value){var criteria={};criteria[selector]=normalize(value);var query=new Mingo.Query(criteria);return{test:function(obj){return!query.test(obj)}}},$where:function(selector,value){return _.isFunction(value)||(value=new Function("return "+value+";")),{test:function(obj){return value.call(obj)===!0}}}},simpleOperators={$eq:function(a,b){return a=_.isArray(a)?a:[a],a=_.find(a,function(val){return _.isEqual(val,b)}),void 0!==a},$ne:function(a,b){return!this.$eq(a,b)},$in:function(a,b){return a=_.isArray(a)?a:[a],_.intersection(a,b).length>0},$nin:function(a,b){return _.isUndefined(a)||!this.$in(a,b)},$lt:function(a,b){return a=_.isArray(a)?a:[a],a=_.find(a,function(val){return b>val}),void 0!==a},$lte:function(a,b){return a=_.isArray(a)?a:[a],a=_.find(a,function(val){return b>=val}),void 0!==a},$gt:function(a,b){return a=_.isArray(a)?a:[a],a=_.find(a,function(val){return val>b}),void 0!==a},$gte:function(a,b){return a=_.isArray(a)?a:[a],a=_.find(a,function(val){return val>=b}),void 0!==a},$mod:function(a,b){return a=_.isArray(a)?a:[a],a=_.find(a,function(val){return _.isNumber(val)&&_.isArray(b)&&2===b.length&&val%b[0]===b[1]}),void 0!==a},$regex:function(a,b){return a=_.isArray(a)?a:[a],a=_.find(a,function(val){return _.isString(val)&&_.isRegExp(b)&&!!val.match(b)}),void 0!==a},$exists:function(a,b){return b===!1&&_.isUndefined(a)||b===!0&&!_.isUndefined(a)},$all:function(a,b){var self=this,matched=!1;if(_.isArray(a)&&_.isArray(b))for(var i=0;i<b.length;i++){if(!_.isObject(b[i])||!_.contains(_.keys(b[i]),"$elemMatch"))return _.intersection(b,a).length===b.length;matched=matched||self.$elemMatch(a,b[i].$elemMatch)}return matched},$size:function(a,b){return _.isArray(a)&&_.isNumber(b)&&a.length===b},$elemMatch:function(a,b){if(_.isArray(a)&&!_.isEmpty(a))for(var query=new Mingo.Query(b),i=0;i<a.length;i++)if(query.test(a[i]))return!0;return!1},$type:function(a,b){switch(b){case 1:return _.isNumeric(a)&&-1!==(a+"").indexOf(".");case 2:case 5:return _.isString(a);case 3:return _.isObject(a);case 4:return _.isArray(a);case 8:return _.isBoolean(a);case 9:return _.isDate(a);case 10:return _.isNull(a);case 11:return _.isRegExp(a);case 16:return _.isNumeric(a)&&2147483647>=a&&-1===(a+"").indexOf(".");case 18:return _.isNumeric(a)&&a>2147483647&&0x8000000000000000>=a&&-1===(a+"").indexOf(".");default:return!1}}},projectionOperators={$:function(){throw new Error("$ not implemented")},$elemMatch:function(obj,expr,field){var array=Mingo._resolve(obj,field),query=new Mingo.Query(expr);if(_.isUndefined(array)||!_.isArray(array))return void 0;for(var i=0;i<array.length;i++)if(query.test(array[i]))return array[i];return void 0},$slice:function(obj,expr,field){var array=Mingo._resolve(obj,field);return _.isUndefined(array)?void 0:(_.isArray(expr)||(expr=[expr]),Array.prototype.slice.apply(array,expr))}},groupOperators={$addToSet:function(collection,expr){var result=_.map(collection,function(obj){return computeValue(obj,expr)});return _.uniq(result)},$sum:function(collection,expr){return _.isNumber(expr)?collection.length*expr:_.reduce(collection,function(acc,obj){return acc+computeValue(obj,expr)},0)},$max:function(collection,expr){var obj=_.max(collection,function(obj){return computeValue(obj,expr)});return computeValue(obj,expr)},$min:function(collection,expr){var obj=_.min(collection,function(obj){return computeValue(obj,expr)});return computeValue(obj,expr)},$avg:function(collection,expr){return this.$sum(collection,expr)/collection.length},$push:function(collection,expr){return _.map(collection,function(obj){return computeValue(obj,expr)})},$first:function(collection,expr){return collection.length>0?computeValue(collection[0],expr):void 0},$last:function(collection,expr){return collection.length>0?computeValue(collection[collection.length-1],expr):void 0}},aggregateOperators={$add:function(obj,expr){var args=computeValue(obj,expr);return _.reduce(args,function(memo,num){return memo+num},0)},$subtract:function(obj,expr){var args=computeValue(obj,expr);return args[0]-args[1]},$divide:function(obj,expr){var args=computeValue(obj,expr);return args[0]/args[1]},$multiply:function(obj,expr){var args=computeValue(obj,expr);return _.reduce(args,function(memo,num){return memo*num},1)},$mod:function(obj,expr){var args=computeValue(obj,expr);return args[0]%args[1]},$cmp:function(obj,expr){var args=computeValue(obj,expr);return args[0]>args[1]?1:args[0]<args[1]?-1:0},$concat:function(obj,expr){var args=computeValue(obj,expr);return args.join("")},$strcasecmp:function(obj,expr){var args=computeValue(obj,expr);return args[0]=args[0].toUpperCase(),args[1]=args[1].toUpperCase(),args[0]>args[1]?1:args[0]<args[1]?-1:0},$substr:function(obj,expr){var args=computeValue(obj,expr);return _.isString(args[0])?args[0].substr(args[1],args[2]):void 0},$toLower:function(obj,expr){var value=computeValue(obj,expr);return value.toLowerCase()},$toUpper:function(obj,expr){var value=computeValue(obj,expr);return value.toUpperCase()}},setOperators={$setEquals:function(obj,expr){var args=computeValue(obj,expr);return 0===_.difference(args[0],args[1]).length},$setIntersection:function(obj,expr){var args=computeValue(obj,expr);return _.intersection(args[0],args[1])},$setDifference:function(obj,expr){var args=computeValue(obj,expr);return _.difference(args[0],args[1])},$setUnion:function(obj,expr){var args=computeValue(obj,expr);return _.union(args[0],args[1])},$setIsSubset:function(obj,expr){var args=computeValue(obj,expr);return _.intersection(args[0],args[1]).length===args[0].length},$anyElementTrue:function(obj,expr){for(var args=computeValue(obj,expr),i=0;i<args.length;i++)if(args[i])return!0;return!1},$allElementsTrue:function(obj,expr){for(var args=computeValue(obj,expr),i=0;i<args.length;i++)if(!args[i])return!1;return!0}},conditionalOperators={$cond:function(obj,expr){var ifExpr,thenExpr,elseExpr;if(_.isArray(expr)){if(3!=expr.length)throw Error("Invalid arguments for $cond operator");ifExpr=expr[0],thenExpr=expr[1],elseExpr=expr[2]}else _.isObject(expr)&&(ifExpr=expr["if"],thenExpr=expr.then,elseExpr=expr["else"]);var condition=computeValue(obj,ifExpr);return condition?computeValue(obj,thenExpr):computeValue(obj,elseExpr)},$ifNull:function(obj,expr){if(!_.isArray(expr)||2!=expr.length)throw Error("Invalid arguments for $ifNull operator");var args=computeValue(obj,expr);return null===args[0]||void 0===args[0]?args[1]:args[0]}};_.each(["$eq","$ne","$gt","$gte","$lt","$lte"],function(op){aggregateOperators[op]=function(obj,expr){var args=computeValue(obj,expr);return simpleOperators[op](args[0],args[1])}}),_.extend(aggregateOperators,setOperators,conditionalOperators);var Ops={simpleOperators:_.keys(simpleOperators),compoundOperators:_.keys(compoundOperators),setOperators:_.keys(setOperators),aggregateOperators:_.keys(aggregateOperators),groupOperators:_.keys(groupOperators),pipelineOperators:_.keys(pipelineOperators),projectionOperators:_.keys(projectionOperators)};Ops.queryOperators=_.union(Ops.simpleOperators,Ops.compoundOperators);var accumulate=function(collection,field,expr){if(_.contains(Ops.groupOperators,field))return groupOperators[field](collection,expr);if(_.isObject(expr)){var result={};for(var key in expr)if(expr.hasOwnProperty(key)&&(result[key]=accumulate(collection,key,expr[key]),_.contains(Ops.groupOperators,key))){if(result=result[key],_.keys(expr).length>1)throw new Error("Invalid $group expression '"+JSON.stringify(expr)+"'");break}return result}return void 0},computeValue=function(obj,expr,field){if(_.contains(Ops.aggregateOperators,field))return aggregateOperators[field](obj,expr);if(_.isString(expr)&&expr.length>0&&"$"===expr[0])return Mingo._resolve(obj,expr.slice(1));var result;if(_.isArray(expr)){result=[];for(var i=0;i<expr.length;i++)result.push(computeValue(obj,expr[i],null))}else if(_.isObject(expr)){result={};for(var key in expr)if(expr.hasOwnProperty(key)&&(result[key]=computeValue(obj,expr[key],key),_.contains(Ops.aggregateOperators,key))){if(result=result[key],_.keys(expr).length>1)throw new Error("Invalid aggregation expression '"+JSON.stringify(expr)+"'");break}}else for(var i=0;i<primitives.length;i++)if(primitives[i](expr))return expr;return result}}).call(this); | ||
(function(){"use strict";function normalize(expr){for(var i=0;i<primitives.length;i++)if(primitives[i](expr))return _.isRegExp(expr)?{$regex:expr}:{$eq:expr};if(_.isObject(expr)){var keys=_.keys(expr),notQuery=0===_.intersection(Ops.queryOperators,keys).length;if(notQuery)return{$eq:expr};if(_.contains(keys,"$regex")){var regex=expr.$regex,options=expr.$options||"",modifiers="";_.isString(regex)&&(modifiers+=regex.ignoreCase||options.indexOf("i")>=0?"i":"",modifiers+=regex.multiline||options.indexOf("m")>=0?"m":"",modifiers+=regex.global||options.indexOf("g")>=0?"g":"",regex=new RegExp(regex,modifiers)),expr.$regex=regex,delete expr.$options}}return expr}var previousMingo,_,root=this,Mingo={};null!=root&&(previousMingo=root.Mingo),Mingo.noConflict=function(){return root.Mingo=previousMingo,Mingo},"undefined"!=typeof exports?(exports="undefined"!=typeof module&&module.exports?module.exports=Mingo:Mingo,_=require("underscore")):(root.Mingo=Mingo,_=root._);var primitives=[_.isString,_.isBoolean,_.isNumber,_.isDate,_.isNull,_.isRegExp],settings={key:"_id"};Mingo.setup=function(options){_.extend(settings,options||{})},Mingo.Query=function(criteria){this._criteria=criteria||{},this._compiled=[],this._compile()},Mingo.Query.prototype={_compile:function(){if(!_.isEmpty(this._criteria)){if(_.isArray(this._criteria)||_.isFunction(this._criteria)||!_.isObject(this._criteria))throw new Error("Invalid type for criteria");for(var field in this._criteria)if(this._criteria.hasOwnProperty(field)){var expr=this._criteria[field];if(_.contains(Ops.compoundOperators,field)){if(_.contains(["$not"],field))throw Error("Invalid operator");this._processOperator(field,field,expr)}else{expr=normalize(expr);for(var op in expr)expr.hasOwnProperty(op)&&this._processOperator(field,op,expr[op])}}}},_processOperator:function(field,operator,value){var compiledSelector;if(_.contains(Ops.simpleOperators,operator))compiledSelector={test:function(obj){var actualValue=Mingo._resolve(obj,field);return simpleOperators[operator](actualValue,value)}};else{if(!_.contains(Ops.compoundOperators,operator))throw Error("Invalid query operator '"+operator+"' detected");compiledSelector=compoundOperators[operator](field,value)}this._compiled.push(compiledSelector)},test:function(obj){for(var i=0;i<this._compiled.length;i++)if(!this._compiled[i].test(obj))return!1;return!0},find:function(collection,projection){return new Mingo.Cursor(collection,this,projection)},remove:function(collection){for(var arr=[],i=0;i<collection.length;i++)this.test(collection[i])||arr.push(collection[i]);return arr}},Mingo.Cursor=function(collection,query,projection){this._query=query,this._collection=collection,this._projection=projection,this._operators={},this._result=!1,this._position=0},Mingo.Cursor.prototype={_fetch:function(){var self=this;if(this._result!==!1)return this._result;if(_.isObject(this._projection)&&_.extend(this._operators,{$project:this._projection}),!_.isArray(this._collection))throw Error("Input collection is not of a valid type.");this._result=_.filter(this._collection,this._query.test,this._query);var pipeline=[];if(_.each(["$sort","$skip","$limit","$project"],function(op){_.has(self._operators,op)&&pipeline.push(_.pick(self._operators,op))}),pipeline.length>0){var aggregator=new Mingo.Aggregator(pipeline);this._result=aggregator.run(this._result,this._query)}return this._result},all:function(){return this._fetch()},first:function(){return this.count()>0?this._fetch()[0]:null},last:function(){return this.count()>0?this._fetch()[this.count()-1]:null},count:function(){return this._fetch().length},skip:function(n){return _.extend(this._operators,{$skip:n}),this},limit:function(n){return _.extend(this._operators,{$limit:n}),this},sort:function(modifier){return _.extend(this._operators,{$sort:modifier}),this},next:function(){return this.hasNext()?this._fetch()[this._position++]:null},hasNext:function(){return this.count()>this._position},max:function(expr){return groupOperators.$max(this._fetch(),expr)},min:function(expr){return groupOperators.$min(this._fetch(),expr)},map:function(callback){return _.map(this._fetch(),callback)},forEach:function(callback){_.each(this._fetch(),callback)}},Mingo.Aggregator=function(operators){this._operators=operators},Mingo.Aggregator.prototype={run:function(collection,query){if(!_.isEmpty(this._operators))for(var i=0;i<this._operators.length;i++){var operator=this._operators[i];for(var key in operator)operator.hasOwnProperty(key)&&(collection=query?pipelineOperators[key].call(query,collection,operator[key]):pipelineOperators[key](collection,operator[key]))}return collection}},Mingo._get=function(obj,field){return _.result(obj,field)},Mingo._resolve=function(obj,field){if(!field)return void 0;for(var isText,names=field.split("."),value=obj,i=0;i<names.length;i++){if(isText=null===names[i].match(/^\d+$/),isText&&_.isArray(value)){var res=[];_.each(value,function(item){_.isObject(item)&&res.push(Mingo._resolve(item,names[i]))}),value=res}else value=Mingo._get(value,names[i]);if(void 0===value)break}return value},Mingo.compile=function(criteria){return new Mingo.Query(criteria)},Mingo.find=function(collection,criteria,projection){return new Mingo.Query(criteria).find(collection,projection)},Mingo.remove=function(collection,criteria){return new Mingo.Query(criteria).remove(collection)},Mingo.aggregate=function(collection,pipeline){if(!_.isArray(pipeline))throw Error("Aggregation pipeline must be an array");return new Mingo.Aggregator(pipeline).run(collection)},Mingo.Stream=function(){},Mingo.CollectionMixin={query:function(criteria,projection){return Mingo.find(this.toJSON(),criteria,projection)},aggregate:function(pipeline){var args=[this.toJSON(),pipeline];return Mingo.aggregate.apply(null,args)}};var pipelineOperators={$group:function(collection,expr){var idKey=expr[settings.key],indexes=[],groups=_.groupBy(collection,function(obj){var key=computeValue(obj,idKey,idKey);return indexes.push(key),key});indexes=_.uniq(indexes),expr=_.omit(expr,settings.key);var result=[];return _.each(indexes,function(index){var obj={};obj[settings.key]=index;for(var key in expr)expr.hasOwnProperty(key)&&(obj[key]=accumulate(groups[index],key,expr[key]));result.push(obj)}),result},$match:function(collection,expr){var query=new Mingo.Query(expr);return query.find(collection).all()},$project:function(collection,expr){var projected=[],objKeys=_.keys(expr),removeId=!1;if(_.contains(objKeys,settings.key)){var id=objKeys[settings.key];removeId=0===id||id===!1}for(var i=0;i<collection.length;i++){var obj=collection[i],cloneObj={};_.each(objKeys,function(key){if(!removeId||key!==settings.key){var subExpr=expr[key];if(_.isString(subExpr))cloneObj[key]=computeValue(obj,subExpr,key);else if(1===subExpr||subExpr===!0)cloneObj[key]=_.result(obj,key);else if(_.isObject(subExpr)){var operator=_.keys(subExpr);if(operator=operator.length>1?!1:operator[0],operator!==!1&&_.contains(Ops.projectionOperators,operator)){var temp=projectionOperators[operator](obj,subExpr[operator],key);_.isUndefined(temp)||(cloneObj[key]=temp)}else cloneObj[key]=computeValue(obj,subExpr,key)}}}),removeId||_.has(cloneObj,settings.key)||(cloneObj[settings.key]=obj[settings.key]),projected.push(cloneObj)}return projected},$limit:function(collection,value){return _.first(collection,value)},$skip:function(collection,value){return _.rest(collection,value)},$unwind:function(collection,expr){for(var result=[],field=expr.substr(1),i=0;i<collection.length;i++){var obj=collection[i],value=Mingo._get(obj,field);if(!_.isArray(value))throw new Error("Target field '"+field+"' is not of type Array.");_.each(value,function(item){var tmp=_.clone(obj);tmp[field]=item,result.push(tmp)})}return result},$sort:function(collection,sortKeys){if(!_.isEmpty(sortKeys)&&_.isObject(sortKeys)){var modifiers=_.keys(sortKeys);modifiers.reverse().forEach(function(key){var indexes=[],grouped=_.groupBy(collection,function(obj){var value=Mingo._resolve(obj,key);return indexes.push(value),value});indexes=_.sortBy(_.uniq(indexes),function(item){return item}),-1===sortKeys[key]&&indexes.reverse(),collection=[],_.each(indexes,function(item){Array.prototype.push.apply(collection,grouped[item])})})}return collection}},compoundOperators={$and:function(selector,value){if(!_.isArray(value))throw new Error("Invalid expression for $and criteria");var queries=[];return _.each(value,function(expr){queries.push(new Mingo.Query(expr))}),{test:function(obj){for(var i=0;i<queries.length;i++)if(queries[i].test(obj)===!1)return!1;return!0}}},$or:function(selector,value){if(!_.isArray(value))throw new Error("Invalid expression for $or criteria");var queries=[];return _.each(value,function(expr){queries.push(new Mingo.Query(expr))}),{test:function(obj){for(var i=0;i<queries.length;i++)if(queries[i].test(obj))return!0;return!1}}},$nor:function(selector,value){if(!_.isArray(value))throw new Error("Invalid expression for $nor criteria");var query=this.$or("$or",value);return{test:function(obj){return!query.test(obj)}}},$not:function(selector,value){var criteria={};criteria[selector]=normalize(value);var query=new Mingo.Query(criteria);return{test:function(obj){return!query.test(obj)}}},$where:function(selector,value){return _.isFunction(value)||(value=new Function("return "+value+";")),{test:function(obj){return value.call(obj)===!0}}}},simpleOperators={$eq:function(a,b){return a=_.isArray(a)?a:[a],a=_.find(a,function(val){return _.isEqual(val,b)}),void 0!==a},$ne:function(a,b){return!this.$eq(a,b)},$in:function(a,b){return a=_.isArray(a)?a:[a],_.intersection(a,b).length>0},$nin:function(a,b){return _.isUndefined(a)||!this.$in(a,b)},$lt:function(a,b){return a=_.isArray(a)?a:[a],a=_.find(a,function(val){return b>val}),void 0!==a},$lte:function(a,b){return a=_.isArray(a)?a:[a],a=_.find(a,function(val){return b>=val}),void 0!==a},$gt:function(a,b){return a=_.isArray(a)?a:[a],a=_.find(a,function(val){return val>b}),void 0!==a},$gte:function(a,b){return a=_.isArray(a)?a:[a],a=_.find(a,function(val){return val>=b}),void 0!==a},$mod:function(a,b){return a=_.isArray(a)?a:[a],a=_.find(a,function(val){return _.isNumber(val)&&_.isArray(b)&&2===b.length&&val%b[0]===b[1]}),void 0!==a},$regex:function(a,b){return a=_.isArray(a)?a:[a],a=_.find(a,function(val){return _.isString(val)&&_.isRegExp(b)&&!!val.match(b)}),void 0!==a},$exists:function(a,b){return b===!1&&_.isUndefined(a)||b===!0&&!_.isUndefined(a)},$all:function(a,b){var self=this,matched=!1;if(_.isArray(a)&&_.isArray(b))for(var i=0;i<b.length;i++){if(!_.isObject(b[i])||!_.contains(_.keys(b[i]),"$elemMatch"))return _.intersection(b,a).length===b.length;matched=matched||self.$elemMatch(a,b[i].$elemMatch)}return matched},$size:function(a,b){return _.isArray(a)&&_.isNumber(b)&&a.length===b},$elemMatch:function(a,b){if(_.isArray(a)&&!_.isEmpty(a))for(var query=new Mingo.Query(b),i=0;i<a.length;i++)if(query.test(a[i]))return!0;return!1},$type:function(a,b){switch(b){case 1:return _.isNumeric(a)&&-1!==(a+"").indexOf(".");case 2:case 5:return _.isString(a);case 3:return _.isObject(a);case 4:return _.isArray(a);case 8:return _.isBoolean(a);case 9:return _.isDate(a);case 10:return _.isNull(a);case 11:return _.isRegExp(a);case 16:return _.isNumeric(a)&&2147483647>=a&&-1===(a+"").indexOf(".");case 18:return _.isNumeric(a)&&a>2147483647&&0x8000000000000000>=a&&-1===(a+"").indexOf(".");default:return!1}}},projectionOperators={$:function(){throw new Error("$ not implemented")},$elemMatch:function(obj,expr,field){var array=Mingo._resolve(obj,field),query=new Mingo.Query(expr);if(_.isUndefined(array)||!_.isArray(array))return void 0;for(var i=0;i<array.length;i++)if(query.test(array[i]))return array[i];return void 0},$slice:function(obj,expr,field){var array=Mingo._resolve(obj,field);return _.isUndefined(array)?void 0:(_.isArray(expr)||(expr=[expr]),Array.prototype.slice.apply(array,expr))}},groupOperators={$addToSet:function(collection,expr){var result=_.map(collection,function(obj){return computeValue(obj,expr)});return _.uniq(result)},$sum:function(collection,expr){return _.isNumber(expr)?collection.length*expr:_.reduce(collection,function(acc,obj){return acc+computeValue(obj,expr)},0)},$max:function(collection,expr){var obj=_.max(collection,function(obj){return computeValue(obj,expr)});return computeValue(obj,expr)},$min:function(collection,expr){var obj=_.min(collection,function(obj){return computeValue(obj,expr)});return computeValue(obj,expr)},$avg:function(collection,expr){return this.$sum(collection,expr)/collection.length},$push:function(collection,expr){return _.map(collection,function(obj){return computeValue(obj,expr)})},$first:function(collection,expr){return collection.length>0?computeValue(collection[0],expr):void 0},$last:function(collection,expr){return collection.length>0?computeValue(collection[collection.length-1],expr):void 0}},aggregateOperators={$add:function(obj,expr){var args=computeValue(obj,expr);return _.reduce(args,function(memo,num){return memo+num},0)},$subtract:function(obj,expr){var args=computeValue(obj,expr);return args[0]-args[1]},$divide:function(obj,expr){var args=computeValue(obj,expr);return args[0]/args[1]},$multiply:function(obj,expr){var args=computeValue(obj,expr);return _.reduce(args,function(memo,num){return memo*num},1)},$mod:function(obj,expr){var args=computeValue(obj,expr);return args[0]%args[1]},$cmp:function(obj,expr){var args=computeValue(obj,expr);return args[0]>args[1]?1:args[0]<args[1]?-1:0},$concat:function(obj,expr){var args=computeValue(obj,expr);return args.join("")},$strcasecmp:function(obj,expr){var args=computeValue(obj,expr);return args[0]=args[0].toUpperCase(),args[1]=args[1].toUpperCase(),args[0]>args[1]?1:args[0]<args[1]?-1:0},$substr:function(obj,expr){var args=computeValue(obj,expr);return _.isString(args[0])?args[0].substr(args[1],args[2]):void 0},$toLower:function(obj,expr){var value=computeValue(obj,expr);return value.toLowerCase()},$toUpper:function(obj,expr){var value=computeValue(obj,expr);return value.toUpperCase()}},setOperators={$setEquals:function(obj,expr){var args=computeValue(obj,expr);return 0===_.difference(args[0],args[1]).length},$setIntersection:function(obj,expr){var args=computeValue(obj,expr);return _.intersection(args[0],args[1])},$setDifference:function(obj,expr){var args=computeValue(obj,expr);return _.difference(args[0],args[1])},$setUnion:function(obj,expr){var args=computeValue(obj,expr);return _.union(args[0],args[1])},$setIsSubset:function(obj,expr){var args=computeValue(obj,expr);return _.intersection(args[0],args[1]).length===args[0].length},$anyElementTrue:function(obj,expr){for(var args=computeValue(obj,expr),i=0;i<args.length;i++)if(args[i])return!0;return!1},$allElementsTrue:function(obj,expr){for(var args=computeValue(obj,expr),i=0;i<args.length;i++)if(!args[i])return!1;return!0}},conditionalOperators={$cond:function(obj,expr){var ifExpr,thenExpr,elseExpr;if(_.isArray(expr)){if(3!=expr.length)throw Error("Invalid arguments for $cond operator");ifExpr=expr[0],thenExpr=expr[1],elseExpr=expr[2]}else _.isObject(expr)&&(ifExpr=expr["if"],thenExpr=expr.then,elseExpr=expr["else"]);var condition=computeValue(obj,ifExpr);return condition?computeValue(obj,thenExpr):computeValue(obj,elseExpr)},$ifNull:function(obj,expr){if(!_.isArray(expr)||2!=expr.length)throw Error("Invalid arguments for $ifNull operator");var args=computeValue(obj,expr);return null===args[0]||void 0===args[0]?args[1]:args[0]}};_.each(["$eq","$ne","$gt","$gte","$lt","$lte"],function(op){aggregateOperators[op]=function(obj,expr){var args=computeValue(obj,expr);return simpleOperators[op](args[0],args[1])}}),_.extend(aggregateOperators,setOperators,conditionalOperators);var Ops={simpleOperators:_.keys(simpleOperators),compoundOperators:_.keys(compoundOperators),setOperators:_.keys(setOperators),aggregateOperators:_.keys(aggregateOperators),groupOperators:_.keys(groupOperators),pipelineOperators:_.keys(pipelineOperators),projectionOperators:_.keys(projectionOperators)};Ops.queryOperators=_.union(Ops.simpleOperators,Ops.compoundOperators);var accumulate=function(collection,field,expr){if(_.contains(Ops.groupOperators,field))return groupOperators[field](collection,expr);if(_.isObject(expr)){var result={};for(var key in expr)if(expr.hasOwnProperty(key)&&(result[key]=accumulate(collection,key,expr[key]),_.contains(Ops.groupOperators,key))){if(result=result[key],_.keys(expr).length>1)throw new Error("Invalid $group expression '"+JSON.stringify(expr)+"'");break}return result}return void 0},computeValue=function(obj,expr,field){if(_.contains(Ops.aggregateOperators,field))return aggregateOperators[field](obj,expr);if(_.isString(expr)&&expr.length>0&&"$"===expr[0])return Mingo._resolve(obj,expr.slice(1));var result;if(_.isArray(expr)){result=[];for(var i=0;i<expr.length;i++)result.push(computeValue(obj,expr[i],null))}else if(_.isObject(expr)){result={};for(var key in expr)if(expr.hasOwnProperty(key)&&(result[key]=computeValue(obj,expr[key],key),_.contains(Ops.aggregateOperators,key))){if(result=result[key],_.keys(expr).length>1)throw new Error("Invalid aggregation expression '"+JSON.stringify(expr)+"'");break}}else for(var i=0;i<primitives.length;i++)if(primitives[i](expr))return expr;return result}}).call(this); |
123
mingo.js
@@ -20,2 +20,7 @@ (function () { | ||
var nodeEnabled = 'undefined' !== typeof exports && | ||
'undefined' !== typeof module && | ||
'undefined' !== typeof require && | ||
'undefined' !== typeof process; | ||
// Export the Mingo object for **Node.js** | ||
@@ -100,3 +105,3 @@ if (typeof exports !== 'undefined') { | ||
this._criteria = criteria || {}; | ||
this._compiledSelectors = []; | ||
this._compiled = []; | ||
this._compile(); | ||
@@ -116,10 +121,10 @@ }; | ||
for (var name in this._criteria) { | ||
if (this._criteria.hasOwnProperty(name)) { | ||
var expr = this._criteria[name]; | ||
if (_.contains(Ops.compoundOperators, name)) { | ||
if (_.contains(["$not"], name)) { | ||
for (var field in this._criteria) { | ||
if (this._criteria.hasOwnProperty(field)) { | ||
var expr = this._criteria[field]; | ||
if (_.contains(Ops.compoundOperators, field)) { | ||
if (_.contains(["$not"], field)) { | ||
throw Error("Invalid operator"); | ||
} | ||
this._processOperator(name, name, expr); | ||
this._processOperator(field, field, expr); | ||
} else { | ||
@@ -130,3 +135,3 @@ // normalize expression | ||
if (expr.hasOwnProperty(op)) { | ||
this._processOperator(name, op, expr[op]); | ||
this._processOperator(field, op, expr[op]); | ||
} | ||
@@ -154,19 +159,21 @@ } | ||
} | ||
this._compiledSelectors.push(compiledSelector); | ||
this._compiled.push(compiledSelector); | ||
}, | ||
test: function (model) { | ||
var match = true; | ||
for (var i = 0; i < this._compiledSelectors.length; i++) { | ||
var compiled = this._compiledSelectors[i]; | ||
match = compiled.test(model); | ||
if (match === false) { | ||
break; | ||
/** | ||
* Checks if the object passes the query criteria. Returns true if so, false otherwise. | ||
* @param obj | ||
* @returns {boolean} | ||
*/ | ||
test: function (obj) { | ||
for (var i = 0; i < this._compiled.length; i++) { | ||
if (!this._compiled[i].test(obj)) { | ||
return false; | ||
} | ||
} | ||
return match; | ||
return true; | ||
}, | ||
/** | ||
* | ||
* Returns a Mingo.Cursor object for iterating over the results of the query | ||
* @param collection | ||
@@ -181,3 +188,3 @@ * @param projection | ||
/** | ||
* Remove matched documents from the collection returning the new | ||
* Remove matched documents from the collection returning the remainder | ||
* @param collection | ||
@@ -189,3 +196,3 @@ * @returns {Array} | ||
for (var i = 0; i < collection.length; i++) { | ||
if (this.test(collection[i]) === false) { | ||
if (!this.test(collection[i])) { | ||
arr.push(collection[i]); | ||
@@ -197,2 +204,9 @@ } | ||
// stream: function () { | ||
// if (!nodeEnabled) { | ||
// throw Error("Require NodeJS context"); | ||
// } | ||
// var Stream = require('stream'); | ||
// } | ||
}; | ||
@@ -221,27 +235,28 @@ | ||
if (this._result === false) { | ||
if (this._result !== false) { | ||
return this._result; | ||
} | ||
// inject projection operator | ||
if (_.isObject(this._projection)) { | ||
_.extend(this._operators, {"$project": this._projection}); | ||
} | ||
// inject projection operator | ||
if (_.isObject(this._projection)) { | ||
_.extend(this._operators, {"$project": this._projection}); | ||
} | ||
if (!_.isArray(this._collection)) { | ||
throw Error("Input collection is not of a valid type."); | ||
} | ||
if (!_.isArray(this._collection)) { | ||
throw Error("Input collection is not of a valid type."); | ||
} | ||
// filter collection | ||
this._result = _.filter(this._collection, this._query.test, this._query); | ||
var pipeline = []; | ||
// filter collection | ||
this._result = _.filter(this._collection, this._query.test, this._query); | ||
var pipeline = []; | ||
_.each(['$sort', '$skip', '$limit', '$project'], function (op) { | ||
if (_.has(self._operators, op)) { | ||
pipeline.push(_.pick(self._operators, op)); | ||
} | ||
}); | ||
_.each(['$sort', '$skip', '$limit', '$project'], function (op) { | ||
if (_.has(self._operators, op)) { | ||
pipeline.push(_.pick(self._operators, op)); | ||
} | ||
}); | ||
if (pipeline.length > 0) { | ||
var aggregator = new Mingo.Aggregator(pipeline); | ||
this._result = aggregator.run(this._result, this._query); | ||
} | ||
if (pipeline.length > 0) { | ||
var aggregator = new Mingo.Aggregator(pipeline); | ||
this._result = aggregator.run(this._result, this._query); | ||
} | ||
@@ -284,4 +299,3 @@ return this._result; | ||
/** | ||
* Sets the number of results to skip before returning any results. | ||
* You must apply cursor.skip() to the cursor before retrieving any matching objects. | ||
* Returns a cursor that begins returning results only after passing or skipping a number of documents. | ||
* @param {Number} n the number of results to skip. | ||
@@ -296,4 +310,3 @@ * @return {Mingo.Cursor} Returns the cursor, so you can chain this call. | ||
/** | ||
* Sets the limit of the number of results to return. | ||
* You must apply limit() to the cursor before retrieving any documents. | ||
* Constrains the size of a cursor's result set. | ||
* @param {Number} n the number of results to limit to. | ||
@@ -308,3 +321,3 @@ * @return {Mingo.Cursor} Returns the cursor, so you can chain this call. | ||
/** | ||
* Sets the sort order of the matching objects | ||
* Returns results ordered according to a sort specification. | ||
* @param {Object} modifier an object of key and values specifying the sort order. 1 for ascending and -1 for descending | ||
@@ -319,3 +332,3 @@ * @return {Mingo.Cursor} Returns the cursor, so you can chain this call. | ||
/** | ||
* Fetches the next value in the iteration of the cursor | ||
* Returns the next document in a cursor. | ||
* @returns {Object | Boolean} | ||
@@ -327,7 +340,7 @@ */ | ||
} | ||
return false; | ||
return null; | ||
}, | ||
/** | ||
* Checks if the cursor can continue to iterate | ||
* Returns true if the cursor has documents and can be iterated. | ||
* @returns {boolean} | ||
@@ -358,3 +371,3 @@ */ | ||
/** | ||
* Applies function to each document visited by the cursor and collects the return values from successive application into an array. | ||
* Applies a function to each document in a cursor and collects the return values in an array. | ||
* @param callback | ||
@@ -368,3 +381,3 @@ * @returns {Array} | ||
/** | ||
* Iterates the cursor to apply a JavaScript function to each matched document | ||
* Applies a JavaScript function for every document in a cursor. | ||
* @param callback | ||
@@ -390,4 +403,5 @@ */ | ||
/** | ||
* Executes the aggregation pipeline | ||
* Apply the pipeline operations over the collection by order of the sequence added | ||
* @param collection an array of objects to process | ||
* @param query the `Mingo.Query` object to use as context | ||
* @returns {Array} | ||
@@ -477,3 +491,3 @@ */ | ||
* @param projection | ||
* @returns {*} | ||
* @returns {Mingo.Cursor} | ||
*/ | ||
@@ -508,2 +522,7 @@ Mingo.find = function (collection, criteria, projection) { | ||
Mingo.Stream = function (criteria) { | ||
}; | ||
/** | ||
@@ -510,0 +529,0 @@ * Mixin for Backbone.Collection objects |
{ | ||
"name": "mingo", | ||
"version": "0.1.2", | ||
"version": "0.1.3", | ||
"description": "JavaScript implementation of MongoDB query language", | ||
@@ -5,0 +5,0 @@ "main": "mingo.js", |
@@ -121,17 +121,43 @@ # Mingo | ||
# API | ||
### Mingo.Query(expression) | ||
Creates a new ```Mingo.Query``` object with the given query expression | ||
### Mingo.Query(criteria) | ||
Creates a new ```Mingo.Query``` object with the given query criteria | ||
- ```test(obj)``` Returns true if the object passes the query criteria, otherwise false. | ||
- ```find(collection, [projection])``` Returns a ```Mingo.Cursor``` for iterating over the results of the query | ||
- ```remove(collection)``` Remove matching documents from the collection and return the remainder | ||
### Mingo.Aggregator(expressions) | ||
Creates a new ```Mingo.Aggregator``` object with a collection of aggregation pipeline expressions | ||
- ```run()``` Apply the pipeline operations over the collection by order of the sequence added | ||
### Mingo.Cursor(collection, query, projection) | ||
Creates a new ```Mingo.Cursor``` object which holds the result of applying the query over the collection | ||
- ```all()``` Returns the documents in a cursor as a collection. | ||
- ```first()``` Returns the first documents in a cursor. | ||
- ```last()``` Returns the last document in a cursor | ||
- ```count()``` Returns a count of the documents in a cursor. | ||
- ```limit(n)``` Constrains the size of a cursor's result set. | ||
- ```skip(n)``` Returns a cursor that begins returning results only after passing or skipping a number of documents. | ||
- ```sort(modifier)``` Returns results ordered according to a sort specification. | ||
- ```next()``` Returns the next document in a cursor. | ||
- ```hasNext()``` Returns true if the cursor has documents and can be iterated. | ||
- ```max(expression)``` Specifies an exclusive upper index bound for a cursor | ||
- ```min(expression)``` Specifies an inclusive lower index bound for a cursor. | ||
- ```map(callback)``` Applies a function to each document in a cursor and collects the return values in an array. | ||
- ```forEach(callback)``` Applies a JavaScript function for every document in a cursor. | ||
### Mingo.CollectionMixin | ||
A mixin object for ```Backbone.Collection``` which adds ```query()``` and ```aggregate()``` methods | ||
- ```query(criteria)``` | ||
- ```aggregate(expressions)``` | ||
### Mingo.find(collection, expression) | ||
Returns the matched objects from executing the query expression against the collection | ||
### Mingo.compile(criteria) | ||
Returns a ```Mingo.Query``` given the criteria | ||
### Mingo.remove(collection, expression) | ||
Returns the non-matched objects from executing the query expression against the collection | ||
### Mingo.find(collection, criteria) | ||
Returns a ```Mingo.Cursor``` for a ```Mingo.Query``` with the given criteria | ||
### Mingo.remove(collection, criteria) | ||
Returns the non-matched objects as a collection from executing a ```Mingo.Query``` with the given criteria | ||
### Mingo.aggregate(collection, expressions) | ||
@@ -143,4 +169,5 @@ Returns the result of executing the aggregate expressions over the collection | ||
- Geometry Specifiers ($geometry, $maxDistance, $center, $centerSphere, $box, $polygon) | ||
- Implement ```Mingo.Stream``` API to filter objects | ||
# License | ||
MIT Copyright (c) 2013 Francis Asante | ||
MIT |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
67691
1476
171