Socket
Socket
Sign inDemoInstall

sift

Package Overview
Dependencies
Maintainers
1
Versions
155
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

sift - npm Package Compare versions

Comparing version 0.0.13 to 0.0.15

2

package.json
{
"name": "sift",
"description": "mongodb query style array filtering",
"version": "0.0.13",
"version": "0.0.15",
"repository": {},

@@ -6,0 +6,0 @@ "engines": {},

## MongoDB inspired array filtering [![Build Status](https://secure.travis-ci.org/crcn/sift.js.png)](https://secure.travis-ci.org/crcn/sift.js)
For extended documentation, checkout http://docs.mongodb.org/manual/reference/operator/query/
## Features:
- Supported operators: $in, $nin, $exists, $gte, $gt, $lte, $lt, $eq, $neq, $mod, $all, $and, $or, $nor, $not, $size, $type
- Supported operators: [$in](#in), [$nin](#nin), [$exists](#exists), [$gte](#gte), [$gt](#gt), [$lte](#lte), [$lt](#lt), [$eq](#eq), [$neq](#neq), [$mod](#mod), [$all](#all), [$and](#and), [$or](#or), [$nor](#nor), [$not](#not), [$size](#size), [$type](#type), [$regex](#regex)
- Regexp searches

@@ -15,2 +17,3 @@ - Function filtering

## Node.js Examples

@@ -301,2 +304,10 @@

### $regex
Matches values based on the given regular expression
```javascript
sift({ $regex: /^f/i, $nin: ["frank"] }, ["frank", "fred", "sam", "frost"]); // ["fred", "frost"]
```
### $not

@@ -303,0 +314,0 @@

@@ -14,556 +14,556 @@ /*

/**
*/
/**
*/
var _convertDotToSubObject = function(keyParts, value) {
var _convertDotToSubObject = function(keyParts, value) {
var subObject = {},
currentValue = subObject;
var subObject = {},
currentValue = subObject;
for(var i = 0, n = keyParts.length - 1; i < n; i++) {
currentValue = currentValue[keyParts[i]] = {};
}
for(var i = 0, n = keyParts.length - 1; i < n; i++) {
currentValue = currentValue[keyParts[i]] = {};
}
currentValue[keyParts[i]] = value;
return subObject;
}
currentValue[keyParts[i]] = value;
return subObject;
}
/**
*/
/**
*/
var _queryParser = new (function() {
var _queryParser = new (function() {
/**
* tests against data
*/
/**
* tests against data
*/
var priority = this.priority = function(statement, data) {
var priority = this.priority = function(statement, data) {
var exprs = statement.exprs,
priority = 0;
var exprs = statement.exprs,
priority = 0;
//generally, expressions are ordered from least efficient, to most efficient.
for(var i = 0, n = exprs.length; i < n; i++) {
//generally, expressions are ordered from least efficient, to most efficient.
for(var i = 0, n = exprs.length; i < n; i++) {
var expr = exprs[i],
p;
var expr = exprs[i],
p;
if(!~(p = expr.e(expr.v, _comparable(data), data))) return -1;
if(!~(p = expr.e(expr.v, _comparable(data), data))) return -1;
priority += p;
priority += p;
}
}
return priority;
}
return priority;
}
/**
* parses a statement into something evaluable
*/
/**
* parses a statement into something evaluable
*/
var parse = this.parse = function(statement, key) {
var parse = this.parse = function(statement, key) {
//fixes sift(null, []) issue
if(!statement) statement = { $eq: statement };
//fixes sift(null, []) issue
if(!statement) statement = { $eq: statement };
var testers = [];
//if the statement is an object, then we're looking at something like: { key: match }
if(statement.constructor == Object) {
var testers = [];
//if the statement is an object, then we're looking at something like: { key: match }
if(Object.prototype.toString.call(statement) === "[object Object]") {
for(var k in statement) {
for(var k in statement) {
//find the apropriate operator. If one doesn't exist, then it's a property, which means
//we create a new statement (traversing)
var operator = !!_testers[k] ? k : '$trav',
//find the apropriate operator. If one doesn't exist, then it's a property, which means
//we create a new statement (traversing)
var operator = !!_testers[k] ? k : '$trav',
//value of given statement (the match)
value = statement[k],
//value of given statement (the match)
value = statement[k],
//default = match
exprValue = value;
//default = match
exprValue = value;
//if we're working with a traversable operator, then set the expr value
if(TRAV_OP[operator]) {
//if we're working with a traversable operator, then set the expr value
if(TRAV_OP[operator]) {
//using dot notation? convert into a sub-object
if(~k.indexOf(".")) {
var keyParts = k.split(".");
k = keyParts.shift(); //we're using the first key, so remove it
//using dot notation? convert into a sub-object
if(~k.indexOf(".")) {
var keyParts = k.split(".");
k = keyParts.shift(); //we're using the first key, so remove it
exprValue = value = _convertDotToSubObject(keyParts, value);
}
//*if* the value is an array, then we're dealing with something like: $or, $and
if(value instanceof Array) {
exprValue = [];
exprValue = value = _convertDotToSubObject(keyParts, value);
}
//*if* the value is an array, then we're dealing with something like: $or, $and
if(value instanceof Array) {
exprValue = [];
for(var i = value.length; i--;) {
exprValue.push(parse(value[i]));
}
for(var i = value.length; i--;) {
exprValue.push(parse(value[i]));
}
//otherwise we're dealing with $trav
} else {
exprValue = parse(value, k);
}
}
//otherwise we're dealing with $trav
} else {
exprValue = parse(value, k);
}
}
testers.push(_getExpr(operator, k, exprValue));
testers.push(_getExpr(operator, k, exprValue));
}
}
//otherwise we're comparing a particular value, so set to eq
} else {
testers.push(_getExpr('$eq', k, statement));
}
//otherwise we're comparing a particular value, so set to eq
} else {
testers.push(_getExpr('$eq', k, statement));
}
var stmt = {
exprs: testers,
k: key,
test: function(value) {
return !!~stmt.priority(value);
},
priority: function(value) {
return priority(stmt, value);
}
};
return stmt;
}
var stmt = {
exprs: testers,
k: key,
test: function(value) {
return !!~stmt.priority(value);
},
priority: function(value) {
return priority(stmt, value);
}
};
return stmt;
}
//traversable statements
var TRAV_OP = this.traversable = {
$and: true,
$or: true,
$nor: true,
$trav: true,
$not: true
};
//traversable statements
var TRAV_OP = this.traversable = {
$and: true,
$or: true,
$nor: true,
$trav: true,
$not: true
};
function _comparable(value) {
if(value instanceof Date) {
return value.getTime();
} else {
return value;
}
}
function _comparable(value) {
if(value instanceof Date) {
return value.getTime();
} else {
return value;
}
}
function btop(value) {
return value ? 0 : -1;
}
function btop(value) {
return value ? 0 : -1;
}
var _testers = this.testers = {
var _testers = this.testers = {
/**
*/
/**
*/
$eq: function(a, b) {
return btop(a.test(b));
},
$eq: function(a, b) {
return btop(a.test(b));
},
/**
*/
/**
*/
$ne: function(a, b) {
return btop(!a.test(b));
},
$ne: function(a, b) {
return btop(!a.test(b));
},
/**
*/
/**
*/
$lt: function(a, b) {
return btop(a > b);
},
$lt: function(a, b) {
return btop(a > b);
},
/**
*/
/**
*/
$gt: function(a, b) {
return btop(a < b);
},
$gt: function(a, b) {
return btop(a < b);
},
/**
*/
/**
*/
$lte: function(a, b) {
return btop(a >= b);
},
$lte: function(a, b) {
return btop(a >= b);
},
/**
*/
/**
*/
$gte: function(a, b) {
return btop(a <= b);
},
$gte: function(a, b) {
return btop(a <= b);
},
/**
*/
/**
*/
$exists: function(a, b) {
return btop(a === (b != null))
},
$exists: function(a, b) {
return btop(a === (b != null))
},
/**
*/
/**
*/
$in: function(a, b) {
$in: function(a, b) {
//intersecting an array
if(b instanceof Array) {
//intersecting an array
if(b instanceof Array) {
for(var i = b.length; i--;) {
if(~a.indexOf(b[i])) return i;
}
for(var i = b.length; i--;) {
if(~a.indexOf(b[i])) return i;
}
} else {
return btop(~a.indexOf(b));
}
} else {
return btop(~a.indexOf(b));
}
return -1;
},
return -1;
},
/**
*/
/**
*/
$not: function(a, b) {
if(!a.test) throw new Error("$not test should include an expression, not a value. Use $ne instead.");
return btop(!a.test(b));
},
$not: function(a, b) {
if(!a.test) throw new Error("$not test should include an expression, not a value. Use $ne instead.");
return btop(!a.test(b));
},
/**
*/
/**
*/
$type: function(a, b, org) {
$type: function(a, b, org) {
//instanceof doesn't work for strings / boolean. instanceof works with inheritance
return org ? btop(org instanceof a || org.constructor == a) : -1;
},
//instanceof doesn't work for strings / boolean. instanceof works with inheritance
return org ? btop(org instanceof a || org.constructor == a) : -1;
},
/**
*/
/**
*/
$nin: function(a, b) {
return ~_testers.$in(a, b) ? -1 : 0;
},
$nin: function(a, b) {
return ~_testers.$in(a, b) ? -1 : 0;
},
/**
*/
/**
*/
$mod: function(a, b) {
return b % a[0] == a[1] ? 0 : -1;
},
$mod: function(a, b) {
return b % a[0] == a[1] ? 0 : -1;
},
/**
*/
/**
*/
$all: function(a, b) {
$all: function(a, b) {
for(var i = a.length; i--;) {
for(var i = a.length; i--;) {
var a1 = a[i];
var indexInB = ~b.indexOf(a1);
if(!indexInB) return -1;
}
if(!indexInB) return -1;
}
return 0;
},
return 0;
},
/**
*/
/**
*/
$size: function(a, b) {
return b ? btop(a == b.length) : -1;
},
$size: function(a, b) {
return b ? btop(a == b.length) : -1;
},
/**
*/
/**
*/
$or: function(a, b) {
$or: function(a, b) {
var i = a.length, p, n = i;
var i = a.length, p, n = i;
for(; i--;) {
if(~priority(a[i], b)) {
return i;
}
}
for(; i--;) {
if(~priority(a[i], b)) {
return i;
}
}
return btop(n == 0);
},
return btop(n == 0);
},
/**
*/
/**
*/
$nor: function(a, b) {
$nor: function(a, b) {
var i = a.length, n = i;
var i = a.length, n = i;
for(; i--;) {
if(~priority(a[i], b)) {
return -1;
}
}
for(; i--;) {
if(~priority(a[i], b)) {
return -1;
}
}
return 0;
},
return 0;
},
/**
*/
/**
*/
$and: function(a, b) {
$and: function(a, b) {
for(var i = a.length; i--;) {
if(!~priority(a[i], b)) {
return -1;
}
}
for(var i = a.length; i--;) {
if(!~priority(a[i], b)) {
return -1;
}
}
return 0;
},
return 0;
},
/**
*/
/**
*/
$trav: function(a, b) {
$trav: function(a, b) {
if(b instanceof Array) {
for(var i = b.length; i--;) {
var subb = b[i];
if(subb[a.k] && ~priority(a, subb[a.k])) return i;
}
if(b instanceof Array) {
for(var i = b.length; i--;) {
var subb = b[i];
if(subb[a.k] && ~priority(a, subb[a.k])) return i;
}
return -1;
}
return -1;
}
//continue to traverse even if there isn't a value - this is needed for
//something like name:{$exists:false}
return priority(a, b ? b[a.k] : undefined);
},
//continue to traverse even if there isn't a value - this is needed for
//something like name:{$exists:false}
return priority(a, b ? b[a.k] : undefined);
},
/**
*/
/**
*/
$regex: function(a, b) {
var aRE = new RegExp(a);
return aRE.test(b) ? 0 : -1;
}
$regex: function(a, b) {
var aRE = new RegExp(a);
return aRE.test(b) ? 0 : -1;
}
}
}
var _prepare = {
/**
*/
var _prepare = {
/**
*/
$eq: function(a) {
var fn;
$eq: function(a) {
var fn;
if(a instanceof RegExp) {
return a;
} else if (a instanceof Function) {
fn = a;
} else {
fn = function(b) {
if(b instanceof Array) {
return ~b.indexOf(a);
} else {
return a == b;
}
}
}
if(a instanceof RegExp) {
return a;
} else if (a instanceof Function) {
fn = a;
} else {
fn = function(b) {
if(b instanceof Array) {
return ~b.indexOf(a);
} else {
return a == b;
}
}
}
return {
test: fn
}
return {
test: fn
}
},
/**
*/
$ne: function(a) {
return _prepare.$eq(a);
}
};
},
/**
*/
$ne: function(a) {
return _prepare.$eq(a);
}
};
var _getExpr = function(type, key, value) {
var _getExpr = function(type, key, value) {
var v = _comparable(value);
var v = _comparable(value);
return {
return {
//k key
k: key,
//k key
k: key,
//v value
v: _prepare[type] ? _prepare[type](v) : v,
//v value
v: _prepare[type] ? _prepare[type](v) : v,
//e eval
e: _testers[type]
};
//e eval
e: _testers[type]
};
}
}
})();
})();
var getSelector = function(selector) {
var getSelector = function(selector) {
if(!selector) {
if(!selector) {
return function(value) {
return value;
};
return function(value) {
return value;
};
} else
if(typeof selector == 'function') {
return selector;
}
} else
if(typeof selector == 'function') {
return selector;
}
throw new Error("Unknown sift selector " + selector);
}
throw new Error("Unknown sift selector " + selector);
}
var sifter = function(query, selector) {
var sifter = function(query, selector) {
//build the filter for the sifter
var filter = _queryParser.parse( query );
//the function used to sift through the given array
var self = function(target) {
var sifted = [], results = [], testValue, value, priority;
//build the filter for the sifter
var filter = _queryParser.parse( query );
//the function used to sift through the given array
var self = function(target) {
var sifted = [], results = [], testValue, value, priority;
//I'll typically start from the end, but in this case we need to keep the order
//of the array the same.
for(var i = 0, n = target.length; i < n; i++) {
//I'll typically start from the end, but in this case we need to keep the order
//of the array the same.
for(var i = 0, n = target.length; i < n; i++) {
value = target[i];
testValue = selector(value);
value = target[i];
testValue = selector(value);
//priority = -1? it's not something we can use.
if(!~(priority = filter.priority( testValue ))) continue;
//priority = -1? it's not something we can use.
if(!~(priority = filter.priority( testValue ))) continue;
//push all the sifted values to be sorted later. This is important particularly for statements
//such as $or
sifted.push({
value: value,
priority: priority
});
}
//push all the sifted values to be sorted later. This is important particularly for statements
//such as $or
sifted.push({
value: value,
priority: priority
});
}
//sort the values
sifted.sort(function(a, b) {
return a.priority > b.priority ? -1 : 1;
});
//sort the values
sifted.sort(function(a, b) {
return a.priority > b.priority ? -1 : 1;
});
var values = Array(sifted.length);
var values = Array(sifted.length);
//finally, fetch the values & return them.
for(var i = sifted.length; i--;) {
values[i] = sifted[i].value;
}
//finally, fetch the values & return them.
for(var i = sifted.length; i--;) {
values[i] = sifted[i].value;
}
return values;
}
return values;
}
//set the test function incase the sifter isn't needed
self.test = filter.test;
self.score = filter.priority;
self.query = query;
//set the test function incase the sifter isn't needed
self.test = filter.test;
self.score = filter.priority;
self.query = query;
return self;
}
return self;
}
/**
* sifts the given function
* @param query the mongodb query
* @param target the target array
* @param rawSelector the selector for plucking data from the given target
*/
/**
* sifts the given function
* @param query the mongodb query
* @param target the target array
* @param rawSelector the selector for plucking data from the given target
*/
var sift = function(query, target, rawSelector) {
var sift = function(query, target, rawSelector) {
//must be an array
if(typeof target != "object") {
rawSelector = target;
target = undefined;
}
//must be an array
if(typeof target != "object") {
rawSelector = target;
target = undefined;
}
var sft = sifter(query, getSelector(rawSelector));
var sft = sifter(query, getSelector(rawSelector));
//target given? sift through it and return the filtered result
if(target) return sft(target);
//target given? sift through it and return the filtered result
if(target) return sft(target);
//otherwise return the sifter func
return sft;
//otherwise return the sifter func
return sft;
}
}
sift.use = function(options) {
if(options.operators) sift.useOperators(options.operators);
}
sift.use = function(options) {
if(options.operators) sift.useOperators(options.operators);
}
sift.useOperators = function(operators) {
for(var key in operators) {
sift.useOperator(key, operators[key]);
}
}
sift.useOperators = function(operators) {
for(var key in operators) {
sift.useOperator(key, operators[key]);
}
}
sift.useOperator = function(operator, optionsOrFn) {
sift.useOperator = function(operator, optionsOrFn) {
var options = {};
var options = {};
if(typeof optionsOrFn == "object") {
options = optionsOrFn;
} else {
options = { test: optionsOrFn };
}
if(typeof optionsOrFn == "object") {
options = optionsOrFn;
} else {
options = { test: optionsOrFn };
}
var key = "$" + operator;
_queryParser.testers[key] = options.test;
var key = "$" + operator;
_queryParser.testers[key] = options.test;
if(options.traversable || options.traverse) {
_queryParser.traversable[key] = true;
}
}
if(options.traversable || options.traverse) {
_queryParser.traversable[key] = true;
}
}
//node.js?
if((typeof module != 'undefined') && (typeof module.exports != 'undefined')) {
module.exports = sift;
//node.js?
if((typeof module != 'undefined') && (typeof module.exports != 'undefined')) {
module.exports = sift;
} else
} else
//browser?
if(typeof window != 'undefined') {
window.sift = sift;
//browser?
if(typeof window != 'undefined') {
window.sift = sift;
}
}
})();
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc