oak-query

Iterable model for chaining query to simplify collection transformations and manipulations

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.
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(allstartcount){
  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.

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(middlewarescallback) {
    middlewares.async(function (currnextend) {
      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]