cqle: validate collection subtypes

for PYTHON-478, in lieu of PYTHON-494
This commit is contained in:
Adam Holmberg
2016-02-19 11:34:51 -06:00
parent a09c7c41ec
commit 4dfe8944b3

View File

@@ -80,6 +80,8 @@ class Column(object):
instance_counter = 0
_python_type_hashable = True
primary_key = False
"""
bool flag, indicates this column is a primary key. The first primary key defined
@@ -611,7 +613,6 @@ class BaseContainerColumn(Column):
https://cassandra.apache.org/doc/cql3/CQL.html#collections
"""
def __init__(self, types, **kwargs):
"""
:param types: a sequence of sub types in this collection
@@ -629,7 +630,6 @@ class BaseContainerColumn(Column):
instances.append(inst)
self.types = instances
super(BaseContainerColumn, self).__init__(**kwargs)
def validate(self, value):
@@ -658,6 +658,9 @@ class Set(BaseContainerColumn):
http://www.datastax.com/documentation/cql/3.1/cql/cql_using/use_set_t.html
"""
_python_type_hashable = False
def __init__(self, value_type, strict=True, default=set, **kwargs):
"""
:param value_type: a column class indicating the types of the value
@@ -667,9 +670,10 @@ class Set(BaseContainerColumn):
self.strict = strict
super(Set, self).__init__((value_type,), default=default, **kwargs)
self.value_col = self.types[0]
if not self.value_col._python_type_hashable:
raise ValidationError("Cannot create a Set with unhashable value type (see PYTHON-494)")
self.db_type = 'set<{0}>'.format(self.value_col.db_type)
def validate(self, value):
val = super(Set, self).validate(value)
if val is None:
@@ -683,7 +687,8 @@ class Set(BaseContainerColumn):
if None in val:
raise ValidationError("{0} None not allowed in a set".format(self.column_name))
# TODO: stop doing this conversion because it doesn't support non-hashable collections as keys (cassandra does)
# will need to start using the cassandra.util types in the next major rev (PYTHON-494)
return set(self.value_col.validate(v) for v in val)
def to_python(self, value):
@@ -703,6 +708,9 @@ class List(BaseContainerColumn):
http://www.datastax.com/documentation/cql/3.1/cql/cql_using/use_list_t.html
"""
_python_type_hashable = False
def __init__(self, value_type, default=list, **kwargs):
"""
:param value_type: a column class indicating the types of the value
@@ -711,7 +719,6 @@ class List(BaseContainerColumn):
self.value_col = self.types[0]
self.db_type = 'list<{0}>'.format(self.value_col.db_type)
def validate(self, value):
val = super(List, self).validate(value)
if val is None:
@@ -739,6 +746,9 @@ class Map(BaseContainerColumn):
http://www.datastax.com/documentation/cql/3.1/cql/cql_using/use_map_t.html
"""
_python_type_hashable = False
def __init__(self, key_type, value_type, default=dict, **kwargs):
"""
:param key_type: a column class indicating the types of the key
@@ -747,6 +757,10 @@ class Map(BaseContainerColumn):
super(Map, self).__init__((key_type, value_type), default=default, **kwargs)
self.key_col = self.types[0]
self.value_col = self.types[1]
if not self.key_col._python_type_hashable:
raise ValidationError("Cannot create a Map with unhashable key type (see PYTHON-494)")
self.db_type = 'map<{0}, {1}>'.format(self.key_col.db_type, self.value_col.db_type)
def validate(self, value):
@@ -758,7 +772,7 @@ class Map(BaseContainerColumn):
if None in val:
raise ValidationError("{0} None is not allowed in a map".format(self.column_name))
# TODO: stop doing this conversion because it doesn't support non-hashable collections as keys (cassandra does)
# will need to start using the cassandra.util types in the next major rev
# will need to start using the cassandra.util types in the next major rev (PYTHON-494)
return dict((self.key_col.validate(k), self.value_col.validate(v)) for k, v in val.items())
def to_python(self, value):
@@ -773,17 +787,6 @@ class Map(BaseContainerColumn):
return dict((self.key_col.to_database(k), self.value_col.to_database(v)) for k, v in value.items())
class UDTValueManager(BaseValueManager):
@property
def changed(self):
return self.value != self.previous_value or (self.value is not None and self.value.has_changed_fields())
def reset_previous_value(self):
if self.value is not None:
self.value.reset_changed_fields()
self.previous_value = copy(self.value)
class Tuple(BaseContainerColumn):
"""
Stores a fixed-length set of positional values
@@ -819,6 +822,17 @@ class Tuple(BaseContainerColumn):
return tuple(t.to_database(v) for t, v in zip(self.types, value))
class UDTValueManager(BaseValueManager):
@property
def changed(self):
return self.value != self.previous_value or (self.value is not None and self.value.has_changed_fields())
def reset_previous_value(self):
if self.value is not None:
self.value.reset_changed_fields()
self.previous_value = copy(self.value)
class UserDefinedType(Column):
"""
User Defined Type column