Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion gcloud/datastore/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -371,7 +371,8 @@ def allocate_ids(self, dataset_id, key_pbs):
datastore_pb.AllocateIdsResponse)
return list(response.key)

def save_entity(self, dataset_id, key_pb, properties):
def save_entity(self, dataset_id, key_pb, properties,
exclude_from_indexes=()):
"""Save an entity to the Cloud Datastore with the provided properties.

.. note::
Expand All @@ -387,6 +388,9 @@ def save_entity(self, dataset_id, key_pb, properties):

:type properties: dict
:param properties: The properties to store on the entity.

:type exclude_from_indexes: sequence of str

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

:param exclude_from_indexes: Names of properties *not* to be indexed.
"""
mutation = self.mutation()

Expand All @@ -410,6 +414,9 @@ def save_entity(self, dataset_id, key_pb, properties):
# Set the appropriate value.
helpers._set_protobuf_value(prop.value, value)

if name in exclude_from_indexes:
prop.value.indexed = False

# If this is in a transaction, we should just return True. The
# transaction will handle assigning any keys as necessary.
if self.transaction():
Expand Down
11 changes: 8 additions & 3 deletions gcloud/datastore/dataset.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,16 +78,21 @@ def query(self, *args, **kwargs):
kwargs['dataset'] = self
return Query(*args, **kwargs)

def entity(self, kind):
def entity(self, kind, exclude_from_indexes=()):
"""Create an entity bound to this dataset.

:type kind: string
:param kind: the "kind" of the new entity.
:param kind: the "kind" of the new entity (see
https://cloud.google.com/datastore/docs/concepts/entities#Datastore_Kinds_and_identifiers)

:param exclude_from_indexes: names of fields whose values are not to
be indexed.

:rtype: :class:`gcloud.datastore.entity.Entity`
:returns: a new Entity instance, bound to this dataset.
"""
return Entity(dataset=self, kind=kind)
return Entity(dataset=self, kind=kind,
exclude_from_indexes=exclude_from_indexes)

def transaction(self, *args, **kwargs):
"""Create a transaction bound to this dataset.
Expand Down
22 changes: 20 additions & 2 deletions gcloud/datastore/entity.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,15 +78,25 @@ class Entity(dict):
Python3), will be saved using the 'blob_value' field, without
any decoding / encoding step.

:type dataset: :class:`gcloud.datastore.dataset.Dataset`, or None
:param dataset: the Dataset instance associated with this entity.

:type kind: str
:param kind: the "kind" of the entity (see
https://cloud.google.com/datastore/docs/concepts/entities#Datastore_Kinds_and_identifiers)

:param exclude_from_indexes: names of fields whose values are not to be
indexed for this entity.
"""

def __init__(self, dataset=None, kind=None):
def __init__(self, dataset=None, kind=None, exclude_from_indexes=()):
super(Entity, self).__init__()
self._dataset = dataset
if kind:
self._key = Key().kind(kind)
else:
self._key = None
self._exclude_from_indexes = set(exclude_from_indexes)

def dataset(self):
"""Get the :class:`.dataset.Dataset` in which this entity belongs.
Expand Down Expand Up @@ -140,6 +150,13 @@ def kind(self):
if self._key:
return self._key.kind()

def exclude_from_indexes(self):
"""Names of fields which are *not* to be indexed for this entity.

:rtype: sequence of field names
"""
return frozenset(self._exclude_from_indexes)

@classmethod
def from_key(cls, key, dataset=None):
"""Create entity based on :class:`.datastore.key.Key`.
Expand Down Expand Up @@ -223,7 +240,8 @@ def save(self):
key_pb = connection.save_entity(
dataset_id=dataset.id(),
key_pb=key.to_protobuf(),
properties=dict(self))
properties=dict(self),
exclude_from_indexes=self.exclude_from_indexes())

# If we are in a transaction and the current entity needs an
# automatically assigned ID, tell the transaction where to put that.
Expand Down
45 changes: 45 additions & 0 deletions gcloud/datastore/test_connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -665,6 +665,51 @@ def test_save_entity_wo_transaction_w_upsert(self):
self.assertEqual(len(props), 1)
self.assertEqual(props[0].name, 'foo')
self.assertEqual(props[0].value.string_value, u'Foo')
self.assertEqual(props[0].value.indexed, True)
self.assertEqual(len(mutation.delete), 0)
self.assertEqual(request.mode, rq_class.NON_TRANSACTIONAL)

def test_save_entity_w_exclude_from_indexes(self):
from gcloud.datastore.connection import datastore_pb
from gcloud.datastore.key import Key

DATASET_ID = 'DATASET'
key_pb = Key(path=[{'kind': 'Kind', 'id': 1234}]).to_protobuf()
rsp_pb = datastore_pb.CommitResponse()
conn = self._makeOne()
URI = '/'.join([
conn.API_BASE_URL,
'datastore',
conn.API_VERSION,
'datasets',
DATASET_ID,
'commit',
])
http = conn._http = Http({'status': '200'}, rsp_pb.SerializeToString())
result = conn.save_entity(DATASET_ID, key_pb, {'foo': u'Foo'},
exclude_from_indexes=['foo'])
self.assertEqual(result, True)
cw = http._called_with
self.assertEqual(cw['uri'], URI)
self.assertEqual(cw['method'], 'POST')
self.assertEqual(cw['headers']['Content-Type'],
'application/x-protobuf')
self.assertEqual(cw['headers']['User-Agent'], conn.USER_AGENT)
rq_class = datastore_pb.CommitRequest
request = rq_class()
request.ParseFromString(cw['body'])
self.assertEqual(request.transaction, '')
mutation = request.mutation
self.assertEqual(len(mutation.insert_auto_id), 0)
upserts = list(mutation.upsert)
self.assertEqual(len(upserts), 1)
upsert = upserts[0]
self.assertEqual(upsert.key, key_pb)
props = list(upsert.property)
self.assertEqual(len(props), 1)
self.assertEqual(props[0].name, 'foo')
self.assertEqual(props[0].value.string_value, u'Foo')
self.assertEqual(props[0].value.indexed, False)
self.assertEqual(len(mutation.delete), 0)
self.assertEqual(request.mode, rq_class.NON_TRANSACTIONAL)

Expand Down
13 changes: 12 additions & 1 deletion gcloud/datastore/test_dataset.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,25 @@ def test_query_factory(self):
self.assertIsInstance(query, Query)
self.assertTrue(query.dataset() is dataset)

def test_entity_factory(self):
def test_entity_factory_defaults(self):
from gcloud.datastore.entity import Entity
DATASET_ID = 'DATASET'
KIND = 'KIND'
dataset = self._makeOne(DATASET_ID)
entity = dataset.entity(KIND)
self.assertIsInstance(entity, Entity)
self.assertEqual(entity.kind(), KIND)
self.assertEqual(sorted(entity.exclude_from_indexes()), [])

def test_entity_factory_explicit(self):
from gcloud.datastore.entity import Entity
DATASET_ID = 'DATASET'
KIND = 'KIND'
dataset = self._makeOne(DATASET_ID)
entity = dataset.entity(KIND, ['foo', 'bar'])
self.assertIsInstance(entity, Entity)
self.assertEqual(entity.kind(), KIND)
self.assertEqual(sorted(entity.exclude_from_indexes()), ['bar', 'foo'])

def test_transaction_factory(self):
from gcloud.datastore.transaction import Transaction
Expand Down
28 changes: 17 additions & 11 deletions gcloud/datastore/test_entity.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,27 +13,31 @@ def _getTargetClass(self):

return Entity

def _makeOne(self, dataset=_MARKER, kind=_KIND):
def _makeOne(self, dataset=_MARKER, kind=_KIND, exclude_from_indexes=()):
from gcloud.datastore.dataset import Dataset

klass = self._getTargetClass()
if dataset is _MARKER:
dataset = Dataset(_DATASET_ID)
return klass(dataset, kind)
return klass(dataset, kind, exclude_from_indexes)

def test_ctor_defaults(self):
klass = self._getTargetClass()
entity = klass()
self.assertEqual(entity.key(), None)
self.assertEqual(entity.dataset(), None)
self.assertEqual(entity.kind(), None)
self.assertEqual(sorted(entity.exclude_from_indexes()), [])

def test_ctor_explicit(self):
from gcloud.datastore.dataset import Dataset

dataset = Dataset(_DATASET_ID)
entity = self._makeOne(dataset, _KIND)
_EXCLUDE_FROM_INDEXES = ['foo', 'bar']
entity = self._makeOne(dataset, _KIND, _EXCLUDE_FROM_INDEXES)
self.assertTrue(entity.dataset() is dataset)
self.assertEqual(sorted(entity.exclude_from_indexes()),
sorted(_EXCLUDE_FROM_INDEXES))

def test_key_getter(self):
from gcloud.datastore.key import Key
Expand Down Expand Up @@ -132,7 +136,7 @@ def test_save_wo_transaction_wo_auto_id_wo_returned_key(self):
self.assertTrue(entity.save() is entity)
self.assertEqual(entity['foo'], 'Foo')
self.assertEqual(connection._saved,
(_DATASET_ID, 'KEY', {'foo': 'Foo'}))
(_DATASET_ID, 'KEY', {'foo': 'Foo'}, ()))
self.assertEqual(key._path, None)

def test_save_w_transaction_wo_partial_key(self):
Expand All @@ -146,7 +150,7 @@ def test_save_w_transaction_wo_partial_key(self):
self.assertTrue(entity.save() is entity)
self.assertEqual(entity['foo'], 'Foo')
self.assertEqual(connection._saved,
(_DATASET_ID, 'KEY', {'foo': 'Foo'}))
(_DATASET_ID, 'KEY', {'foo': 'Foo'}, ()))
self.assertEqual(transaction._added, ())
self.assertEqual(key._path, None)

Expand All @@ -162,11 +166,11 @@ def test_save_w_transaction_w_partial_key(self):
self.assertTrue(entity.save() is entity)
self.assertEqual(entity['foo'], 'Foo')
self.assertEqual(connection._saved,
(_DATASET_ID, 'KEY', {'foo': 'Foo'}))
(_DATASET_ID, 'KEY', {'foo': 'Foo'}, ()))
self.assertEqual(transaction._added, (entity,))
self.assertEqual(key._path, None)

def test_save_w_returned_key(self):
def test_save_w_returned_key_exclude_from_indexes(self):
from gcloud.datastore import datastore_v1_pb2 as datastore_pb
key_pb = datastore_pb.Key()
key_pb.partition_id.dataset_id = _DATASET_ID
Expand All @@ -175,13 +179,13 @@ def test_save_w_returned_key(self):
connection._save_result = key_pb
dataset = _Dataset(connection)
key = _Key()
entity = self._makeOne(dataset)
entity = self._makeOne(dataset, exclude_from_indexes=['foo'])
entity.key(key)
entity['foo'] = 'Foo'
self.assertTrue(entity.save() is entity)
self.assertEqual(entity['foo'], 'Foo')
self.assertEqual(connection._saved,
(_DATASET_ID, 'KEY', {'foo': 'Foo'}))
(_DATASET_ID, 'KEY', {'foo': 'Foo'}, ('foo',)))
self.assertEqual(key._path, [{'kind': _KIND, 'id': _ID}])

def test_delete_no_key(self):
Expand Down Expand Up @@ -257,8 +261,10 @@ class _Connection(object):
def transaction(self):
return self._transaction

def save_entity(self, dataset_id, key_pb, properties):
self._saved = (dataset_id, key_pb, properties)
def save_entity(self, dataset_id, key_pb, properties,
exclude_from_indexes=()):
self._saved = (dataset_id, key_pb, properties,
tuple(exclude_from_indexes))
return self._save_result

def delete_entities(self, dataset_id, key_pbs):
Expand Down