(Quick Reference)

1 Cassandra ORM Plugin - Reference Documentation

Authors: Bob Florian

Version: 0.4.3

1 Cassandra ORM Plugin

The Cassandra ORM Plugin provides GORM-like dynamic methods for persisting Groovy objects into Cassandra. The plugin does not implement the GORM API but generally follows the same syntax. It also includes additional methods and options that are specifically suited to Cassandra. In addition to the dynamic persistence methods, the plugin extends java.util.UUID with methods to generate and use TimeUUIDs, which often server as primary keys in Cassandra.

1.1 Getting Started

The cassandra-orm plugin must be used in conjunction with a compatible Cassandra client plugin. At this time there is only one such plugin, cassandra-astyanx, which uses the Netflix Astyanax Cassandra client. Because of a conflict between the Astyanax client and Grails, its recommended that you do this in BuildConfig.groovy

compile ()">> {
    excludes "commons-logging"
    excludes 'slf4j-log4j12'
}
runtime 
">>

See the cassandra-astyanax plugin for information about configuring Grails to connect to the Cassandra cluster(s).

Create a directory named grails-app/cassandra and put the classes you wish to persist in Cassandra there. The plugin will automatically add dynamic persistence methods to any class that has a cassandraMapping static property. A simple pair of domain classes might be:

class Person
{
	String username
	String emailAddress
	String firstName
	String lastName
	String country

List posts static hasMany = [posts: Post]

static cassandraMapping = [ primaryKey: 'username', explicitIndexes: ["emailAddress", "country"], counters: [[groupBy: "country"]] ] }

class Post
{
	UUID uuid
	String title
	String text
    Date occurTime

Person user static belongsTo = [user: Person]

static cassandraMapping = [ primaryKey: 'uuid', counters: [ [groupBy: ['occurTime']], [findBy: ['user'], groupBy:['occurTime']] ] ] }

You will need to create column families for each of these classes (there is currently no automatic creation of column families but its on the road-map). The column family names are derived from the class names:

create column family Person with comparator=UTF8Type and default_validation_class=UTF8Type;
create column family Person_IDX with comparator=UTF8Type and default_validation_class=UTF8Type;
create column family Person_CTR with comparator=UTF8Type and default_validation_class=CounterColumnType;

create column family Post with comparator=UTF8Type and default_validation_class=UTF8Type; create column family Post_IDX with comparator=UTF8Type and default_validation_class=UTF8Type; create column family Post_CTR with comparator=UTF8Type and default_validation_class=CounterColumnType;

To create a new user:

new Person(username: "jdoe", emailAddress: "jdoe@anywhere.com", firstName: "John", lastName: "Doe", country: "USA").save()

There are a number of ways to read back your user record(s):

def user1 = Person.get("jdoe")
def user2 = Person.findByEmailAddress("jdoe@anywhere.com")
def users = Person.findAllByCountry("USA")

To add some posts to that user:

user.addToPosts(new Post(title: "Post 1", text: "My first post", occurTime: new Date()-45))
user.addToPosts(new Post(title: "Post 2", text: "My second post", occurTime: new Date()-32))
user.addToPosts(new Post(title: "Post 3", text: "My third post", occurTime: new Date()-15))
user.addToPosts(new Post(title: "Post 4", text: "My fourth post", occurTime: new Date()-10))
user.addToPosts(new Post(title: "Post 5", text: "My fifth post", occurTime: new Date()))

To access the posts for a user:

user.posts.each {println it.title}

To access the last 3 posts in reverse order (UUID keys default to time-based):

user.posts(reversed: true, max: 3).each {println it.title}

To only read the titles from Cassandra (rather than whole objects):

user.posts(column: "title").each {println it}

To get the number of posts a user has:

user.postsCount()

To display the number of users per country:

Person.getCountsGroupByCountry()

To display the number of posts per time period (hour, day, month):

Post.getCountsGroupByOccurTime()
Post.getCountsGroupByOccurTime(grain: Calendar.DAY_OF_MONTH)
Post.getCountsGroupByOccurTime(grain: Calendar.MONTH)

To display the user for each post:

Post.list().each {
     println "${it.title} -- ${it.user.firstName} ${it.user.lastName}"
}

1.2 TimeUUID Methods

The cassandra-orm plugin adds the following methods related to UUID.

java.lang.Integer

byte[] getBytes()

Returns the integer value as an array of 4 bytes.

10000.bytes  // returns [0, 0, 39, 16]

java.lang.Long

byte[] getBytes()

Returns the long value as an array of 4 bytes.

100000000000.bytes  // returns [0, 0, 0, 23, 72, 118, -24, 0]

java.util.UUID

static UUID timeUUID()

Generates a time-based UUID from the current clock time.

def uuid = UUID.timeUUID()

static UUID timeUUID(long msec)

Generates a time-based UUID from the specified time in milliseconds since 1 Jan 1970 UTC (i.e. System.currentTimeMillis()).

def uuid = UUID.timeUUID(System.currentTimeMillis() - 3600000)

static UUID fromBytes(byte[] bytes)

Constructs a UUID from the specified array of 16 bytes.

UUID.fromBytes([-121, -54, -108, 96, -7, -37, 17, -31, -73, -1, 0, 28, 66, 0, 0, 9])

byte[] getBytes()

Returns a 16 byte array representation of the UUID.

UUID.timeUUID().bytes

String toUrlSafeString()

Returns a Base64 encoded string representation of the UUID. These are useful for generating hashes.

UUID.timeUUID().toUrlSafeString()  // something like "h82hoPnbEeG3_wAcQgAACQ"

Long getTime()

Returns the time component of a time-based UUID in milliseconds since 1 Jan 1970 UTC.

UUID.timeUUID().time

1.3 Configuring Domain Classes