Data Binding With cqlr

A while ago I wrote about using cqlc to reduce the boilerplate of binding Go structs to data in Cassandra. In the meantime, I’ve been building out an alternative approach that eliminates the need to use cqlc for this purpose. This experiment is called cqlr and it provides runtime bindings for gocql using either field tags, reflection or a user supplied mapping or any combination of these.

The motivation behind cqlr stems from gocql users asking for richer and more convenient data binding in the core library. gocql takes a low level approach to data binding in the sense that it is completely up to the user to match up CQL parameter placeholders to the relavant variables in the application. This process can become tedious and error prone as the application grows and evolves.


Whilst being a valid requirement from a user perspective, including richer support for data binding would significantly increase the overhead of maintaining the core library. The current policy of the gocql team is to provide solid and stable primitives to interact with Cassandra. There are enough moving parts in the library - for example, gocql already provides wire level marshaling for all CQL data types.

So adding a struct binding facility in the core would require a lot of extra design, investigation, debugging and maintainance. For now, the gocql team would prefer to channel this effort into making the basic features more stable and complete. Besides, many people are already successfully using gocql without a data binding facility, so having something like this must therefore only be a nice to have feature.

That being said, gocql is designed with simplicity and extensibility in mind, and considering that the use case seems to be valid, it appeared to make sense to investigate whether a useable data binding facility can indeed be layered on top of the core API. This experiment is called cqlr, short for CQL at Runtime.


cqlr is positioned as a lightweight alternative to cqlc for application developers who prefer dynamic coding over the type checked cqlc philosophy.

The idea behind cqlr is to instrospect application structs at runtime and to correlate this meta data with the runtime type information provided by the CQL driver. This results in cqlr generating per-column data mapping strategies. The application can provide as few or as many mapping hints as it likes. A mapping hint could be:

In the absence of any mapping hint for any given column, cqlr will attempt to use reflection in order to generate a mapping strategy for that column.

Reflection Strategy

This is the default mechanism - if no other strategy is specified for a column, then cqlr will try to match CQL columns to struct fields.

Take the following table definition:

    timeline ascii,
    id timeuuid,
    text text,
    PRIMARY KEY (timeline,id)

If the application defines a struct in this way:

type Tweet struct {
    Timeline string
    Id       gocql.UUID
    Text     string

Then cqlr can automatically bind query results from the gocql driver:

var s *gocql.Session

q := s.Query(`SELECT text, id, timeline FROM tweet WHERE timeline = ?`, "me")
b := BindQuery(q)

var tw Tweet

for b.Scan(&tw) {
    // Do something with the bound data

In addition to binding query result data, the application can also use a struct to pass in query parameters:

var s *gocql.Session

cql := "SELECT text, id, timeline FROM tweet WHERE timeline = ?"
q := Bind(cql, Tweet{Timeline: "me"}).Query(s)
b := BindQuery(q)

var tw Tweet

for b.Scan(&tw) {
    // Do something with the bound data

Tag Based Strategy

This strategy allows the application to specify the CQL column that a given struct field should be bound to.

Taking the following schema as an example:

    id int,
    timestamp timestamp,
    temperature float,
    PRIMARY KEY (id)

The application can define a struct with cql tags that indicate the column names to map each field to:

type Reading struct {
    What    int       `cql:"id"`
    When    time.Time `cql:"timestamp"`
    HowMuch float32   `cql:"temperature"`

The following example shows how to use this strategy to bind a stuct with an INSERT statement:

var s *gocql.Session

r := Reading{
    What:    120,
    When:    time.Now(),
    HowMuch: float32(1) / 3,

cql := "INSERT INTO sensors (id, timestamp, temperature) VALUES (?, ?, ?)"

if err := Bind(cql, r).Exec(s); err != nil {

Supported CQL Operations

The cqlr API supports the following CQL operations:

All strategies support each of these operations.

Application Supplied Strategies

In addition to the reflection and tag based strategies, it is also possible for an application to supply a custom mapping strategy. There are two ways in which an application can provide custom data binding instructions:

There are examples of both variants in the cqlr test suite.


cqlr is currently still relatively experimental and the API is still subject to change. In addition, I have not yet had any reports of how cqlr has fared in a real production setting, so it is still unclear as to whether this approach will hold water.

comments powered by Disqus