Generates predicate functions from Mongo queries
Switch branches/tags
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.


Re-write of underscore-query using ES6 and Ramda in an (extreme) point-free style.

This module exports a single createPredicate function. This function takes a mongo-like query and returns a predicate function. This function can then be used with R.filter or R.find, etc.

The module parses a wide variety of mongo queries - please see the tests for examples.

Documentation will be added shortly, but in the meantime check the Documentation for the query operators for underscore-query

Why Point Free

This is an experiment in how much of a non-trivial program can be written in a point-free manner. I wrote it partly to explore the ramda api and partly as a challenge.

Currently there are only 4 function declarations.

  • 3 are needed to allow recursion. While I probably could re-write the functions to use a y-combinator, I've not yet got round to it. The place that the recursion is used would make those particular functions a lot harder to reason about
  • 1 is needed to throw errors

I think when used well by people who are familiar with functional apis (such as Ramda), the style is very expressive. At a simple level a procedural for loop could be used for map or filter or reduce. By using map rather than a for loop, the intent of my program is easier to understand.

Here is an example of the journey from procedural to point free

Simple Procedural

function fn(input) {
  var output = []
  for (i = 0; i < input.length; i++) {
  return output

Using Native Map

function fn(input) {
  return {
      return item.key

Using FP Style Map

function fn(input){
  return map(function(item) {
    return item.key
  }, input)

Making Point free - part 1 (i.e. no arguments)

This works

var fn = {
  return item.key

Making Point free - part 2 - Using R.prop

var fn ="key"))

Using R.pluck

var fn = R.pluck("key")

Where doesn't it work

Some functions become a lot more verbose and less clear. For example:

function $mod(value, attr){
  return attr % value[0] === value[1]


const $mod = R.converge(R.identical, [
  R.converge(R.modulo, [R.nthArg(1), R.compose(R.head, R.nthArg(0))]),
  R.compose(R.last, R.nthArg(0))