updating the model and query classes to handle models with counter columns correctly

This commit is contained in:
Blake Eggleston
2013-07-24 09:49:15 -07:00
parent 17b77ea9e4
commit 19d6984e72
3 changed files with 28 additions and 17 deletions

View File

@@ -249,22 +249,26 @@ class Integer(Column):
class Counter(Integer):
db_type = 'counter'
def __init__(self,
index=False,
db_field=None,
required=False):
super(Counter, self).__init__(
primary_key=False,
partition_key=False,
index=index,
db_field=db_field,
default=0,
required=required,
)
def get_update_statement(self, val, prev, ctx):
val = self.to_database(val)
prev = self.to_database(prev)
prev = self.to_database(prev or 0)
field_id = uuid4().hex
# use a set statement if there is no
# previous value to compute a delta from
if prev is None:
ctx[field_id] = val
return ['"{}" = :{}'.format(self.db_field_name, field_id)]
delta = val - prev
if delta == 0:
return []
sign = '+' if delta > 0 else '-'
sign = '-' if delta < 0 else '+'
delta = abs(delta)
ctx[field_id] = delta
return ['"{0}" = "{0}" {1} {2}'.format(self.db_field_name, sign, delta)]

View File

@@ -70,6 +70,7 @@ class ColumnQueryEvaluator(AbstractQueryableColumn):
def _get_column(self):
return self.column
class ColumnDescriptor(object):
"""
Handles the reading and writing of column values to and from
@@ -127,6 +128,7 @@ class BaseModel(object):
"""
class DoesNotExist(_DoesNotExist): pass
class MultipleObjectsReturned(_MultipleObjectsReturned): pass
objects = QuerySetDescriptor()
@@ -316,14 +318,17 @@ class ModelMetaClass(type):
column_definitions = inherited_columns.items() + column_definitions
#columns defined on model, excludes automatically
#defined columns
defined_columns = OrderedDict(column_definitions)
#prepend primary key if one hasn't been defined
if not is_abstract and not any([v.primary_key for k,v in column_definitions]):
raise ModelDefinitionException("At least 1 primary key is required.")
counter_columns = [c for c in defined_columns.values() if isinstance(c, columns.Counter)]
data_columns = [c for c in defined_columns.values() if not c.primary_key and not isinstance(c, columns.Counter)]
if counter_columns and data_columns:
raise ModelDefinitionException('counter models may not have data columns')
has_partition_keys = any(v.partition_key for (k, v) in column_definitions)
#TODO: check that the defined columns don't conflict with any of the Model API's existing attributes/methods
@@ -382,6 +387,7 @@ class ModelMetaClass(type):
attrs['_partition_keys'] = partition_keys
attrs['_clustering_keys'] = clustering_keys
attrs['_has_counter'] = len(counter_columns) > 0
#setup class exceptions
DoesNotExistBase = None

View File

@@ -801,7 +801,7 @@ class DMLQuery(object):
query_values = {field_ids[n]:field_values[n] for n in field_names}
qs = []
if self.instance._can_update():
if self.instance._has_counter or self.instance._can_update():
qs += ["UPDATE {}".format(self.column_family_name)]
qs += ["SET"]
@@ -818,7 +818,7 @@ class DMLQuery(object):
val_mgr = self.instance._values[name]
set_statements += col.get_update_statement(val, val_mgr.previous_value, query_values)
pass
else:
set_statements += ['"{}" = :{}'.format(col.db_field_name, field_ids[col.db_field_name])]
qs += [', '.join(set_statements)]
@@ -831,8 +831,9 @@ class DMLQuery(object):
qs += [' AND '.join(where_statements)]
# clear the qs if there are not set statements
if not set_statements: qs = []
# clear the qs if there are no set statements and this is not a counter model
if not set_statements and not self.instance._has_counter:
qs = []
else:
qs += ["INSERT INTO {}".format(self.column_family_name)]