node package manager

oak-query

Oak Query

Integration of iterable to make easier query over collections.

Advantages

  • Less memory usage: no itermediate results and evaluations just as needed.
  • Less error prompt: fluid and handle many case without overhead.
  • Chaining syntax.
  • Reusability: easy factorisation.

Quick sample

var Query = require("oak-query");
 
var q = Query([5, 4, 3, 2, 1]);
 
console.info( q.first() ); // 5 
console.info( q.last() ); // 1 
console.info( q.skip(1).take(2).sum() ); // 7 
console.info( q.sort().first() ); // 1 

Based on iterator design, all query are also resolve at the evaluation, that make easier factorisations:

function filterCustumers(all){
  return Query(all).where(function(item){ return item.type === 3 });
}
 
function getCustumersRange(all, start, count){
  return filterCustumers(q).take(start, count);
}
 
function getLastCreatedCustumers(all){
  return filterCustumers(q).orderby("created").last();
}

Make less errors and easier to understand:

var pageSize = 10;
var customers = getCustumersRange(allEntities, pageSize * 10, pageSize).exec();
if(customers.any()){
  renderDetails(customers.orderby("name").toArray());
}
else{
  renderEmpty();
}

As we see above, the "exec" method is call. These method force the query to be resolved. That mean any changes on the original collection is ignored and the result is not resolved every time. This method is very useful when you use the result more than once.

Important !

This api add one method to Array prototype (asQuery) and one to RegExp prototype (matches):

// RegExp matches sample
/([^;]+)/g.matches("1;2;3;4;5")
  .map(function(match){
    return match.asQuery().last(); // Array asQuery sample
  })
  .toArray(); // [1,2,3,4,5]
 

If those two methods go agains yours rules, don't panic and feel free to remove them (Array.js and Regex.js contains definitions).

It's also important ##Reference ###Filters ####where(filter)

Query([1,2,3]).where(function(i){ return i !== 2 }); // [1, 3] 

notNull(filter)

Query(["a", "b", "$"]).matches(/[\w]+/).notNull(); // ["a", "b"] 

skip(count)

function filter(name){
  return Query(arguments).skip(1).where(function(i){ return name !== i });
}
filter("a", "b", "a", "b", "a", "v"); // ["b", "b", "v"] 

take(count)

Query([1, 2, 3, 4, 5]).take(2).sum(); // 3 

slice(skipCount, takeCount)

Query("String are valid iterable, but not the most effective way to use.").slice(7, 3); // "are" 

Selectors

map(fn)

Query("12345").map(parseInt); // [1,2,3,4,5] 

pluck(name)

Query([ { id: 1 },  { id: 2 }]).pluck("id"); // [1,2] 

first()

Query([1,8,2,4,6]).where(function(i){ return i > 3 }).first(); // 8 

any()

Query([1,8,2,4,6]).where(function(i){ return i > 3 }).any(); // true 

last()

Query([1,8,2,4,6]).where(function(i){ return i > 3 }).last(); // 6 

toArray(start, count)

Query([1,8,2,4,6]).where(function(i){ return i > 3 }).toArray(); // [8, 4, 6] => a real array object 

concat(sep)

Query([1,8,2,4,6]).where(function(i){ return i > 3 }).concat(); // "846" 

count()

Query([1,8,2,4,6]).where(function(i){ return i > 3 }).count(); // 3 

sum()

Query([1,8,2,4,6]).where(function(i){ return i > 3 }).sum(); // 18 

avg()

Query([1,8,2,4,6]).where(function(i){ return i > 3 }).avg(); // 6 

matches()

Query(["-a", "$", "b$"])
  .matches(/([\w]+)/)
  .map(function (m) { return Query(m).last() }); // ["a", null, "b"] 

Actions

forEach(fn)

Query([1,2,3]).forEach(function(item){
  // do something with the item 
}); // return the same object 

tryEach(fn)

Same as forEach but ignore exceptions ####call(fname)

var fn = function(){this.val++;}
var item1 =  { val: 3, increment: fn };
var item2 = { val: 3, increment: fn };
 
Query([item1, item2]).call("increment"); // return the same object 

tryCall(fname)

Same as call but ignore exceptions ####async(fn, end)

function execMiddlewaresAsync(middlewares, callback) {
    middlewares.async(function (curr, next, end) {
      curr.exec() ? next() : end();
    }, callback);
}

Misc

union(iterable)

Query([1,2,3]).union([4,5]); // [1,2,3,4,5] 

sort(desc, compare)

Query([5,3,1]).sort(); // [1,3,5] 

orderby(name, desc, compare)

Query([{ key: "c" }, { key: "a" }, { key: "b" }])
  .orderby("name"); // [{ key: "a" }, { key: "b" }, { key: "c" }] 

reverse()

Query([1,2,3]).reverse(); // [3,2,1] 

distinct()

Query([4,2,4,6,5,4,5]).distinct(); // [4,2,6,5]