oak-query

Iterable model for chaining query to simplify collection transformations and manipulations

npm install oak-query
2 downloads in the last week
8 downloads in the last month

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]
npm loves you