From 7720cc0124867f609ee952e6d20400240e1b0fa0 Mon Sep 17 00:00:00 2001 From: Danny Hermes Date: Thu, 15 Jan 2015 10:11:27 -0800 Subject: [PATCH] Making sure list value PBs all have same `indexed` value. Also throwing exception explaining why this must be true. --- gcloud/datastore/helpers.py | 17 ++++++++++-- gcloud/datastore/test_helpers.py | 47 ++++++++++++++++++++++++++++++-- 2 files changed, 60 insertions(+), 4 deletions(-) diff --git a/gcloud/datastore/helpers.py b/gcloud/datastore/helpers.py index 0cad56b15b98..c0559ff9be5d 100644 --- a/gcloud/datastore/helpers.py +++ b/gcloud/datastore/helpers.py @@ -52,8 +52,21 @@ def entity_from_protobuf(pb): for property_pb in pb.property: value = _get_value_from_property_pb(property_pb) entity_props[property_pb.name] = value - if not property_pb.value.indexed: - exclude_from_indexes.append(property_pb.name) + + # Check if property_pb.value was indexed. Lists need to be + # special-cased and we require all `indexed` values in a list agree. + if isinstance(value, list): + indexed_values = set(value_pb.indexed + for value_pb in property_pb.value.list_value) + if len(indexed_values) != 1: + raise ValueError('For a list_value, subvalues must either all ' + 'be indexed or all excluded from indexes.') + + if not indexed_values.pop(): + exclude_from_indexes.append(property_pb.name) + else: + if not property_pb.value.indexed: + exclude_from_indexes.append(property_pb.name) entity = Entity(key=key, exclude_from_indexes=exclude_from_indexes) entity.update(entity_props) diff --git a/gcloud/datastore/test_helpers.py b/gcloud/datastore/test_helpers.py index 184120e6e73f..6602d5ed6a61 100644 --- a/gcloud/datastore/test_helpers.py +++ b/gcloud/datastore/test_helpers.py @@ -48,11 +48,29 @@ def test_it(self): unindexed_prop_pb.value.integer_value = 10 unindexed_prop_pb.value.indexed = False + list_prop_pb1 = entity_pb.property.add() + list_prop_pb1.name = 'baz' + list_pb1 = list_prop_pb1.value.list_value + + unindexed_value_pb = list_pb1.add() + unindexed_value_pb.integer_value = 11 + unindexed_value_pb.indexed = False + + list_prop_pb2 = entity_pb.property.add() + list_prop_pb2.name = 'qux' + list_pb2 = list_prop_pb2.value.list_value + + indexed_value_pb = list_pb2.add() + indexed_value_pb.integer_value = 12 + indexed_value_pb.indexed = True + entity = self._callFUT(entity_pb) self.assertEqual(entity.kind, _KIND) - self.assertEqual(entity.exclude_from_indexes, frozenset(['bar'])) + self.assertEqual(entity.exclude_from_indexes, + frozenset(['bar', 'baz'])) entity_props = dict(entity) - self.assertEqual(entity_props, {'foo': 'Foo', 'bar': 10}) + self.assertEqual(entity_props, + {'foo': 'Foo', 'bar': 10, 'baz': [11], 'qux': [12]}) # Also check the key. key = entity.key @@ -61,6 +79,31 @@ def test_it(self): self.assertEqual(key.kind, _KIND) self.assertEqual(key.id, _ID) + def test_mismatched_value_indexed(self): + from gcloud.datastore import _datastore_v1_pb2 as datastore_pb + + _DATASET_ID = 'DATASET' + _KIND = 'KIND' + _ID = 1234 + entity_pb = datastore_pb.Entity() + entity_pb.key.partition_id.dataset_id = _DATASET_ID + entity_pb.key.path_element.add(kind=_KIND, id=_ID) + + list_prop_pb = entity_pb.property.add() + list_prop_pb.name = 'baz' + list_pb = list_prop_pb.value.list_value + + unindexed_value_pb1 = list_pb.add() + unindexed_value_pb1.integer_value = 10 + unindexed_value_pb1.indexed = False + + unindexed_value_pb2 = list_pb.add() + unindexed_value_pb2.integer_value = 11 + unindexed_value_pb2.indexed = True + + with self.assertRaises(ValueError): + self._callFUT(entity_pb) + class Test_key_from_protobuf(unittest2.TestCase):