What's New in Cqlengine 0.7
Recently we released version 0.7 of cqlengine, the Python object mapper for CQL3. We’ve been steadily moving towards full support of all of CQL3 for both queries and for table configuration. This post will outline the new features and provide examples on how to use them.
Counters
With counter support finally included it’s now possible to create and use tables with counter columns. They are exposed to the Python application as simple integers, and changes to their values will be sent as deltas to Cassandra. Let’s take a look at an example. I’ll assume you already have Cassandra running locally.
from cqlengine import *
from cqlengine.management import sync_table
from cqlengine.connection import setup
setup(['localhost'])
class CounterExample(Model):
__keyspace__ = 'test'
k = Integer(primary_key=True)
v1 = Counter()
v2 = Counter()
tmp = CounterExample.create(k=1)
tmp.v1 += 5
tmp.v2 += 6
tmp.save()
It’s important to understand the value now contained in tmp is only viewed from the perspective of the current process. That is, the above Python code will translate to the following CQL:
update counter_example set v1 = v1 + 5, v2 = v2 + 6 WHERE k = 1
If you want to do a blind write to the database, you can also use this syntax:
blah = CounterExample(k=1)
blah.v1 += 10
blah.save()
This will give you blind writes without needing to read the row beforehand.
Compaction Strategy
Also new is the ability to set your compaction strategy. We’ve added all the compaction options present in Cassandra 1.2. Compaction may be specified with compaction. Here’s an example:
class Leveled(cqlengine.Model):
__compaction__ = cqlengine.LeveledCompactionStrategy
__compaction_tombstone_threshold__ = .5
pk = cqlengine.Integer(primary_key=True)
some_val = cqlengine.Integer()
sync_table(Leveled)
sync_table()
will create or alter your table to match the compaction specifications. You’ll want to nodetool upgradesstables
on any tables where you change the compaction strategy. All compaction options are supported, see the docs for details.
Laying the Groundwork for Table Polymorphism
We’ve started reworking the cqlengine internals a bit to solve the problem of model polymorphism within a single table. Since version 0.6 of cqlengine, we’ve sync’ed any new columns to cassandra via ALTER
statements. So, if you were to do this:
class Animal(Model):
__table_name__ = 'animal'
animal_id = UUID(primary_key=True)
name = Text()
sync_table(Animal)
class Dog(Animal):
fierceness = Integer()
sync_table(Dog)
class Cat(Animal):
cuteness = Integer()
sync_table(Cat)
You’ll actually end up with a single table, animal
, with all the columns you provided.
cqlsh:cqlengine> desc table animal;
CREATE TABLE animal (
animal_id uuid PRIMARY KEY,
cuteness int,
fierceness int,
name text
) WITH
bloom_filter_fp_chance=0.010000 AND
caching='KEYS_ONLY' AND
comment='' AND
dclocal_read_repair_chance=0.000000 AND
gc_grace_seconds=864000 AND
read_repair_chance=0.100000 AND
replicate_on_write='true' AND
populate_io_cache_on_flush='false' AND
compaction={'class': 'SizeTieredCompactionStrategy'} AND
compression={'sstable_compression': 'SnappyCompressor'};
We’re working to make it possible to query the Animal class and automatically get back the subclass that was originally used to create the object.
Hopefully this has been educational. Any questions, comments? Hit me up @rustyrazorblade