New OrderedMap type in support of nested collections
PYTHON-186 Updated existing tests, still need to add tests for nested collections.
This commit is contained in:
@@ -47,7 +47,7 @@ from cassandra.marshal import (int8_pack, int8_unpack, uint16_pack, uint16_unpac
|
||||
int32_pack, int32_unpack, int64_pack, int64_unpack,
|
||||
float_pack, float_unpack, double_pack, double_unpack,
|
||||
varint_pack, varint_unpack)
|
||||
from cassandra.util import OrderedDict, sortedset
|
||||
from cassandra.util import OrderedMap, sortedset
|
||||
|
||||
apache_cassandra_type_prefix = 'org.apache.cassandra.db.marshal.'
|
||||
|
||||
@@ -741,7 +741,7 @@ class MapType(_ParameterizedType):
|
||||
length = 2
|
||||
numelements = unpack(byts[:length])
|
||||
p = length
|
||||
themap = OrderedDict()
|
||||
themap = OrderedMap()
|
||||
for _ in range(numelements):
|
||||
key_len = unpack(byts[p:p + length])
|
||||
p += length
|
||||
@@ -753,7 +753,7 @@ class MapType(_ParameterizedType):
|
||||
p += val_len
|
||||
key = subkeytype.from_binary(keybytes, protocol_version)
|
||||
val = subvaltype.from_binary(valbytes, protocol_version)
|
||||
themap[key] = val
|
||||
themap._insert(key, val)
|
||||
return themap
|
||||
|
||||
@classmethod
|
||||
|
@@ -28,7 +28,7 @@ import types
|
||||
from uuid import UUID
|
||||
import six
|
||||
|
||||
from cassandra.util import OrderedDict, sortedset
|
||||
from cassandra.util import OrderedDict, OrderedMap, sortedset
|
||||
|
||||
if six.PY3:
|
||||
long = int
|
||||
@@ -76,6 +76,7 @@ class Encoder(object):
|
||||
datetime.date: self.cql_encode_date,
|
||||
dict: self.cql_encode_map_collection,
|
||||
OrderedDict: self.cql_encode_map_collection,
|
||||
OrderedMap: self.cql_encode_map_collection,
|
||||
list: self.cql_encode_list_collection,
|
||||
tuple: self.cql_encode_list_collection,
|
||||
set: self.cql_encode_set_collection,
|
||||
|
@@ -555,3 +555,73 @@ except ImportError:
|
||||
if item in other:
|
||||
isect.add(item)
|
||||
return isect
|
||||
|
||||
from collections import Mapping
|
||||
import six
|
||||
from six.moves import cPickle
|
||||
|
||||
class OrderedMap(Mapping):
|
||||
'''
|
||||
An ordered map that accepts non-hashable types for keys.
|
||||
|
||||
Implemented in support of Cassandra nested collections.
|
||||
|
||||
'''
|
||||
def __init__(self, *args, **kwargs):
|
||||
if len(args) > 1:
|
||||
raise TypeError('expected at most 1 arguments, got %d' % len(args))
|
||||
|
||||
self._items = []
|
||||
self._index = {}
|
||||
if args:
|
||||
e = args[0]
|
||||
if callable(getattr(e, 'keys', None)):
|
||||
for k in e.keys():
|
||||
self._items.append((k, e[k]))
|
||||
else:
|
||||
for k, v in e:
|
||||
self._insert(k, v)
|
||||
|
||||
for k, v in six.iteritems(kwargs):
|
||||
self._insert(k, v)
|
||||
|
||||
def _insert(self, key, value):
|
||||
flat_key = self._serialize_key(key)
|
||||
i = self._index.get(flat_key, -1)
|
||||
if i >= 0:
|
||||
self._items[i] = (key, value)
|
||||
else:
|
||||
self._items.append((key, value))
|
||||
self._index[flat_key] = len(self._items) - 1
|
||||
|
||||
def __getitem__(self, key):
|
||||
index = self._index[self._serialize_key(key)]
|
||||
return self._items[index][1]
|
||||
|
||||
def __iter__(self):
|
||||
for i in self._items:
|
||||
yield i[0]
|
||||
|
||||
def __len__(self):
|
||||
return len(self._items)
|
||||
|
||||
def __eq__(self, other):
|
||||
if isinstance(other, OrderedMap):
|
||||
return self._items == other._items
|
||||
try:
|
||||
d = dict(other)
|
||||
return len(d) == len(self._items) and all(i[1] == d[i[0]] for i in self._items)
|
||||
except KeyError:
|
||||
return False
|
||||
except TypeError:
|
||||
pass
|
||||
return NotImplemented
|
||||
|
||||
def __repr__(self):
|
||||
return '%s[%s]' % (
|
||||
self.__class__.__name__,
|
||||
', '.join("(%r, %r)" % (k, v) for k, v in self._items))
|
||||
|
||||
@staticmethod
|
||||
def _serialize_key(key):
|
||||
return cPickle.dumps(key)
|
||||
|
@@ -24,7 +24,7 @@ from decimal import Decimal
|
||||
from uuid import UUID
|
||||
|
||||
from cassandra.cqltypes import lookup_casstype
|
||||
from cassandra.util import OrderedDict, sortedset
|
||||
from cassandra.util import OrderedMap, sortedset
|
||||
|
||||
marshalled_value_pairs = (
|
||||
# binary form, type, python native type
|
||||
@@ -75,21 +75,20 @@ marshalled_value_pairs = (
|
||||
(b'', 'MapType(AsciiType, BooleanType)', None),
|
||||
(b'', 'ListType(FloatType)', None),
|
||||
(b'', 'SetType(LongType)', None),
|
||||
(b'\x00\x00', 'MapType(DecimalType, BooleanType)', OrderedDict()),
|
||||
(b'\x00\x00', 'MapType(DecimalType, BooleanType)', OrderedMap()),
|
||||
(b'\x00\x00', 'ListType(FloatType)', []),
|
||||
(b'\x00\x00', 'SetType(IntegerType)', sortedset()),
|
||||
(b'\x00\x01\x00\x10\xafYC\xa3\xea<\x11\xe1\xabc\xc4,\x03"y\xf0', 'ListType(TimeUUIDType)', [UUID(bytes=b'\xafYC\xa3\xea<\x11\xe1\xabc\xc4,\x03"y\xf0')]),
|
||||
)
|
||||
|
||||
ordered_dict_value = OrderedDict()
|
||||
ordered_dict_value[u'\u307fbob'] = 199
|
||||
ordered_dict_value[u''] = -1
|
||||
ordered_dict_value[u'\\'] = 0
|
||||
ordered_map_value = OrderedMap([(u'\u307fbob', 199),
|
||||
(u'', -1),
|
||||
(u'\\', 0)])
|
||||
|
||||
# these following entries work for me right now, but they're dependent on
|
||||
# vagaries of internal python ordering for unordered types
|
||||
marshalled_value_pairs_unsafe = (
|
||||
(b'\x00\x03\x00\x06\xe3\x81\xbfbob\x00\x04\x00\x00\x00\xc7\x00\x00\x00\x04\xff\xff\xff\xff\x00\x01\\\x00\x04\x00\x00\x00\x00', 'MapType(UTF8Type, Int32Type)', ordered_dict_value),
|
||||
(b'\x00\x03\x00\x06\xe3\x81\xbfbob\x00\x04\x00\x00\x00\xc7\x00\x00\x00\x04\xff\xff\xff\xff\x00\x01\\\x00\x04\x00\x00\x00\x00', 'MapType(UTF8Type, Int32Type)', ordered_map_value),
|
||||
(b'\x00\x02\x00\x08@\x01\x99\x99\x99\x99\x99\x9a\x00\x08@\x14\x00\x00\x00\x00\x00\x00', 'SetType(DoubleType)', sortedset([2.2, 5.0])),
|
||||
(b'\x00', 'IntegerType', 0),
|
||||
)
|
||||
|
Reference in New Issue
Block a user