updating the model and query classes to handle models with counter columns correctly
This commit is contained in:
@@ -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)]
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)]
|
||||
|
||||
Reference in New Issue
Block a user