Is it possible to implement an `if` method? A look at the ReQL `branch` method

One of the things that makes RethinkDB different from other databases is that its query language is embedded into the programming language. Unlike SQL, you use ReQL by installing a client driver for your programming langauge and building queries with this driver. The driver builds a query and then sends that query to the server to be executed and returned. An example of a ReQL query looks like this:

r.table('people')
 .filter({ name: 'jorge' })
 .run(conn)
 .then(function (rows) {
   console.log(rows);
 });

This query gets all the rows in the people table with ‘jorge’ as the values in the name field.

{
  "id":  "db68bcdf-05c8-41fa-a80d-f301a872af24" ,
  "last_name":  "washington" ,
  "name":  "jorge"
}, {
  "id":  "e40409e0-0b46-4ce9-9e4c-2e2211d8df8b" ,
  "last_name":  "silva" ,
  "name":  "jorge"
}

One of the things I started doing pretty quickly when I started using ReQL is adding if statements to my code. Looking at the code above, what happens if we just filtered the rows through an if statement.

r.table('people')
  .filter(function (row) { 
    if (row('name').eq('jorge')) return true; 
    return false;
  });

Instead of doing what you’d expect it to, this function returns true for all rows, basically ignoring our if statement.

{
  "id":  "db68bcdf-05c8-41fa-a80d-f301a872af24" ,
  "last_name":  "washington" ,
  "name":  "jorge"
}, {
  "id":  "dd99e938-aaac-467c-a2fd-efbba0c4af1b" ,
  "last_name":  "adams" ,
  "name":  "john"
}, {
  "id":  "e40409e0-0b46-4ce9-9e4c-2e2211d8df8b" ,
  "last_name":  "silva" ,
  "name":  "jorge"
}

After making this mistake a couple of times, I found the branch method. This method works basically as an if statement. The first argument is the condition to be tested. The second argument is what the function will return if the condition is true. The third argument is what the function will return if the condition is false. With branch, the same query we wrote before would look like this:

r.table('people')
  .filter(function (row) { 
     return r.branch(
      row('name').eq('jorge'), // if 'name' === 'jorge'
        true, 
        false
     ); 
  });
  // Same as...
  // .filter({ name: 'jorge' })

And it would return this:

{
  "id":  "db68bcdf-05c8-41fa-a80d-f301a872af24" ,
  "last_name":  "washington" ,
  "name":  "jorge"
}, {
  "id":  "e40409e0-0b46-4ce9-9e4c-2e2211d8df8b" ,
  "last_name":  "silva" ,
  "name":  "jorge"
}

Exactly what we wanted!

If you think about this for a minute, it makes perfect sense. Because ReQL is a query language that lives inside your programming language, it needs its own way of having if statements, so that it can then transform these into a query to send to the server. The branch method does exactly that. Its a function to have an if statement inside RethinkDB’s query language. This method is not called r.if because in many languages if is a reserved keyword and you won’t able to create a method named if in all languages.

Implementing an if method

After realizing that you can’t create an if methods in all languages, I was curious about what languagues would permit creating an if method and which ones wouldn’t. I tried doing this in three languages: JavaScript, Ruby, and Python. Here’s how it went:

JavaScript

In JavaScript, this was fairly simple. JavaScript objects can use reserved keywords as property names.

var sample = {
  if: function (condition, ifTrue, ifFalse) {
    if (condition) return ifTrue;
    return ifFalse;
  }
};
sample.if(true, true, false); // true
sample.if(false, true, false); // false

That being said, you can’t create a function called if.

var if = function ()  {
  console.log('This is an `if` function');
};
if();

That would throw a syntax error:

SyntaxError: Unexpected token if

Ruby

Ruby also allows a class to have an if method:

class SampleClass
  def if(condition, true_statement, false_statement)
    if condition
      return true_statement
    false_statement
  end
end

a = SampleClass.new()
puts a.if(true, true, false) // true
puts a.if(false, true, false) // false

Python

Python is a less permissive about its reserved keywords. If we try to create a class with an if method, Python will throw an error.

class SampleClass():

    def if(self, condition, true_statement, false_statement):
        if (condition) return true_statement
        return false_statement

sample = SampleClass()
print sample.if(True, True, False)

Throws:

  File "if.py", line 6
    def if(self, condition, true_statement, false_statement):
         ^
SyntaxError: invalid syntax

There is a way in which to do this, but it’s not very elegant. You can have a function as an if attribute on a dictionary and then you’d be able to call it using brackets.

class SampleClass():

    def __init__(self):
        self.data = {}
        self['if'] = self.create_if_function()

    def create_if_function(self):
        def function(self, condition, if_true, if_false):
            if (condition) return if_true
            return if_false
        return function

    def __setitem__(self, key, item):
        self.data[key] = item

    def __getitem__(self, key):
        return self.data[key]

sample = SampleClass()
sample['if'](True, True, False) // True
sample['if'](False, True, False) // False

While this works, it’s not very clear what exactly this function does because of the brackets.

Final Thoughts

It’s interesting to see what goes into building a query language on top of programming language in the way that ReQL does. This process always carries trade-offs. The difficulty lies in handling these trade-offs elegantly, which is something ReQL does extremely well. The branch method is an excellent example of this. It’s a method that is consistent across all drivers and programming languages where ReQL is implemented. At the same time, its name provides a very clear idea of what it does and how it should work.