GoRethink Goes 1.0

When RethinkDB released version 2.0, the official production-ready release, we knew what we'd be waiting for next at Compose - the updated GoRethink driver. We last looked at GoRethink in our two part series on Go, RethinkDB and Changefeeds (part 1, part 2). Now that the updated version of GoRethink is here, complete with a 1.0 version number – significant because GoRethink is semantically versioned – it's time to look at what has changed.

First, a little background – RethinkDB don't do a Go driver. They have official Ruby, JavaScript and Python drivers but leave other languages to the community. It's not that they don't care, but more that the ReQL language has its roots deep in dynamic languages and function chaining to create queries. That has driven, in turn, RethinkDB's particular focus on driver languages and offers an interesting challenge to third-party driver writers on how closely they follow the Rethink API and how much they adapt to their selected language.

In 1.0

In the case of GoRethink, author Dan Cannon has stuck very close the the API's styling whilst also trying to keep within the Go idiom. JavaScript, Python and Ruby tend to be lower casey in function names while Go demands upper case function and variable names if they are being exported to other parts of the app. This leads us to one of the more visible changes in version 1.0 – function names like Db become DB, Rql becomes RQL, Json becomes JSON and Http becomes HTTP. Minor changes, but if you are updating existing code they are ones you will need to make in your code.

Talking about idiomatic code, one challenge for Dan was converting way the dynamic language APIs did options to Go. Many functions in the official APIs take a map of key/value pairs as a way of simply passing options. It means that you can easily add or ignore an option. Take an example from connecting to a RethinkDB database in JavaScript:

conn = r.connect({ db: 'marvel',
                host: 'localhost',
                port: 28015 },
                 function(err, conn) { ... })

That's a loose collection of options which let you pass any data type and it's sort of hard to map that to a static language like Go. You could go and use the languages literal syntax for creating a map, but it would be tedious and somewhat hard to read. Dan came up with a rather neat solution though. Here's the code for the equivalent function in Go:

conn, err := r.Connect(r.ConnectOpts{
            Database: "marvel",
            Address: "localhost:28015" })

Now, apart from the r.ConnectOpts that looks like some sort of map is being used as the parameter. It isn't though. r.ConnectOpts is a Go structure which includes all the options that are available (source). In Go, you can create a struct like that and initialise it with values by adding variable: value, ... after the type name. So Dan leverages that to create what reads like a dynamic language map, but is in fact a strictly typed Go structure. In any RethinkDB API call where there are options that are passed in a map, there's an relevant structure in GoRethink for those options and it's named after whatever function it's found in so GetNearest has GetNearestOpts and IndexCreate has an IndexCreateOpts and so on. Once you know this, translating between the RethinkDB API and the GoRethink version of it is much easier.

Before 1.0

The real evolution of GoRethink too place before it was given the 1.0 version number. In version 0.7.2, support for connecting to a RethinkDB using TLS (Transport Level Security, the replacement for the now obsolete SSL) was added.

Version 0.7.0 added support for RethinkDB 2.0 and the ability to connect to clusters. It also added the ability Listen to a cursor, a feature that comes in useful when working with changefeeds as you can start following changes and feed the results into a Go channel where they can easily be iterated through. A gist gives a fuller example of using Listen and a idiomatic Go way of reading and getting the changefeed parsed by combining Go structs.

Back at 1.0

One of the less visible changes with GoRethink 1.0 is that it's adopted version 0.4 of the RethinkDB wire protocol for clients. That version of the wire protocol came in with the support for RethinkDB 2.0 and added developer support for parallel execution queries and the ability to add state documents to Changes streams among other things.

What's most notable there, apart from the functionality, is how well RethinkDB make their work visible that developers like Dan can quickly incorporate and support the modifications. Now, with RethinkDB 2.0 and GoRethink 1.0, there's a stable production ready combination of driver and database which Go developers, as well as JavaScript, Ruby and Python developers, should look in to especially if they are interested in real-time updating handled by the server.

GoRethink 1.0 has a gopkg.in page at http://gopkg.in/dancannon/gorethink.v1 and it's GitHub repository is at https://github.com/dancannon/gorethink/.