Skip to content

Commit 0dcb839

Browse files
committed
Merge pull request googleapis#898 from dhermes/issue-701-addendum
Making put/delete_multi in datastore.
2 parents 4dd4415 + 7d1bbb9 commit 0dcb839

File tree

13 files changed

+254
-36
lines changed

13 files changed

+254
-36
lines changed

docs/_components/datastore-getting-started.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ Open a Python console and...
4343
>>> entity = datastore.Entity(key=datastore.Key('Person'))
4444
>>> entity['name'] = 'Your name'
4545
>>> entity['age'] = 25
46-
>>> datastore.put([entity])
46+
>>> datastore.put(entity)
4747
>>> list(Query(kind='Person').fetch())
4848
[<Entity{...} {'name': 'Your name', 'age': 25}>]
4949

docs/_components/datastore-quickstart.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ you can create entities and save them::
5858
>>> entity = datastore.Entity(key=datastore.Key('Person'))
5959
>>> entity['name'] = 'Your name'
6060
>>> entity['age'] = 25
61-
>>> datastore.put([entity])
61+
>>> datastore.put(entity)
6262
>>> list(datastore.Query(kind='Person').fetch())
6363
[<Entity{...} {'name': 'Your name', 'age': 25}>]
6464

docs/index.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ Cloud Datastore
3939
entity = datastore.Entity(key=datastore.Key('Person'))
4040
entity['name'] = 'Your name'
4141
entity['age'] = 25
42-
datastore.put([entity])
42+
datastore.put(entity)
4343
4444
Cloud Storage
4545
~~~~~~~~~~~~~

gcloud/datastore/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,11 @@
5555
from gcloud.datastore._implicit_environ import set_default_dataset_id
5656
from gcloud.datastore.api import allocate_ids
5757
from gcloud.datastore.api import delete
58+
from gcloud.datastore.api import delete_multi
5859
from gcloud.datastore.api import get
5960
from gcloud.datastore.api import get_multi
6061
from gcloud.datastore.api import put
62+
from gcloud.datastore.api import put_multi
6163
from gcloud.datastore.batch import Batch
6264
from gcloud.datastore.connection import SCOPE
6365
from gcloud.datastore.connection import Connection

gcloud/datastore/api.py

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,7 @@ def get(key, missing=None, deferred=None, connection=None, dataset_id=None):
274274
return entities[0]
275275

276276

277-
def put(entities, connection=None, dataset_id=None):
277+
def put_multi(entities, connection=None, dataset_id=None):
278278
"""Save the entities in the Cloud Datastore.
279279
280280
:type entities: list of :class:`gcloud.datastore.entity.Entity`
@@ -312,7 +312,30 @@ def put(entities, connection=None, dataset_id=None):
312312
current.commit()
313313

314314

315-
def delete(keys, connection=None, dataset_id=None):
315+
def put(entity, connection=None, dataset_id=None):
316+
"""Save the entity in the Cloud Datastore.
317+
318+
.. note::
319+
320+
This is just a thin wrapper over :func:`gcloud.datastore.put_multi`.
321+
The backend API does not make a distinction between a single entity or
322+
multiple entities in a commit request.
323+
324+
:type entity: :class:`gcloud.datastore.entity.Entity`
325+
:param entity: The entity to be saved to the datastore.
326+
327+
:type connection: :class:`gcloud.datastore.connection.Connection`
328+
:param connection: Optional connection used to connect to datastore.
329+
If not passed, inferred from the environment.
330+
331+
:type dataset_id: :class:`gcloud.datastore.connection.Connection`
332+
:param dataset_id: Optional. The dataset ID used to connect to datastore.
333+
If not passed, inferred from the environment.
334+
"""
335+
put_multi([entity], connection=connection, dataset_id=dataset_id)
336+
337+
338+
def delete_multi(keys, connection=None, dataset_id=None):
316339
"""Delete the keys in the Cloud Datastore.
317340
318341
:type keys: list of :class:`gcloud.datastore.key.Key`
@@ -348,6 +371,29 @@ def delete(keys, connection=None, dataset_id=None):
348371
current.commit()
349372

350373

374+
def delete(key, connection=None, dataset_id=None):
375+
"""Delete the key in the Cloud Datastore.
376+
377+
.. note::
378+
379+
This is just a thin wrapper over :func:`gcloud.datastore.delete_multi`.
380+
The backend API does not make a distinction between a single key or
381+
multiple keys in a commit request.
382+
383+
:type key: :class:`gcloud.datastore.key.Key`
384+
:param key: The key to be deleted from the datastore.
385+
386+
:type connection: :class:`gcloud.datastore.connection.Connection`
387+
:param connection: Optional connection used to connect to datastore.
388+
If not passed, inferred from the environment.
389+
390+
:type dataset_id: :class:`gcloud.datastore.connection.Connection`
391+
:param dataset_id: Optional. The dataset ID used to connect to datastore.
392+
If not passed, inferred from the environment.
393+
"""
394+
delete_multi([key], connection=connection, dataset_id=dataset_id)
395+
396+
351397
def allocate_ids(incomplete_key, num_ids, connection=None):
352398
"""Allocates a list of IDs from a partial key.
353399

gcloud/datastore/dataset.py

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,11 @@
1414
"""Convenience wrapper for invoking APIs/factories w/ a dataset ID."""
1515

1616
from gcloud.datastore.api import delete
17+
from gcloud.datastore.api import delete_multi
1718
from gcloud.datastore.api import get
1819
from gcloud.datastore.api import get_multi
1920
from gcloud.datastore.api import put
21+
from gcloud.datastore.api import put_multi
2022
from gcloud.datastore.batch import Batch
2123
from gcloud.datastore.key import Key
2224
from gcloud.datastore.query import Query
@@ -56,22 +58,38 @@ def get_multi(self, keys, missing=None, deferred=None):
5658
connection=self.connection,
5759
dataset_id=self.dataset_id)
5860

59-
def put(self, entities):
61+
def put(self, entity):
6062
"""Proxy to :func:`gcloud.datastore.api.put`.
6163
6264
Passes our ``dataset_id``.
6365
"""
64-
return put(entities, connection=self.connection,
66+
return put(entity, connection=self.connection,
6567
dataset_id=self.dataset_id)
6668

67-
def delete(self, keys):
69+
def put_multi(self, entities):
70+
"""Proxy to :func:`gcloud.datastore.api.put_multi`.
71+
72+
Passes our ``dataset_id``.
73+
"""
74+
return put_multi(entities, connection=self.connection,
75+
dataset_id=self.dataset_id)
76+
77+
def delete(self, key):
6878
"""Proxy to :func:`gcloud.datastore.api.delete`.
6979
7080
Passes our ``dataset_id``.
7181
"""
72-
return delete(keys, connection=self.connection,
82+
return delete(key, connection=self.connection,
7383
dataset_id=self.dataset_id)
7484

85+
def delete_multi(self, keys):
86+
"""Proxy to :func:`gcloud.datastore.api.delete_multi`.
87+
88+
Passes our ``dataset_id``.
89+
"""
90+
return delete_multi(keys, connection=self.connection,
91+
dataset_id=self.dataset_id)
92+
7593
def key(self, *path_args, **kwargs):
7694
"""Proxy to :class:`gcloud.datastore.key.Key`.
7795

gcloud/datastore/demo/demo.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,13 @@
3030
toy.update({'name': 'Toy'})
3131

3232
# Now let's save it to our datastore:
33-
datastore.put([toy])
33+
datastore.put(toy)
3434

3535
# If we look it up by its key, we should find it...
3636
print(datastore.get(toy.key))
3737

3838
# And we should be able to delete it...
39-
datastore.delete([toy.key])
39+
datastore.delete(toy.key)
4040

4141
# Since we deleted it, if we do another lookup it shouldn't be there again:
4242
print(datastore.get(toy.key))
@@ -57,7 +57,7 @@
5757
entity = datastore.Entity(key)
5858
entity['name'] = name
5959
entity['age'] = age
60-
datastore.put([entity])
60+
datastore.put(entity)
6161
# We'll start by look at all Thing entities:
6262
query = datastore.Query(kind='Thing')
6363

@@ -74,7 +74,7 @@
7474
print(list(query.fetch()))
7575

7676
# Now delete them.
77-
datastore.delete(sample_keys)
77+
datastore.delete_multi(sample_keys)
7878

7979
# You can also work inside a transaction.
8080
# (Check the official docs for explanations of what's happening here.)
@@ -94,7 +94,7 @@
9494
print('Committing the transaction...')
9595

9696
# Now that the transaction is commited, let's delete the entities.
97-
datastore.delete([key, key2])
97+
datastore.delete_multi([key, key2])
9898

9999
# To rollback a transaction, just call .rollback()
100100
with datastore.Transaction() as xact:
@@ -118,4 +118,4 @@
118118
print(thing.key) # This will be complete
119119

120120
# Now let's delete the entity.
121-
datastore.delete([thing.key])
121+
datastore.delete(thing.key)

gcloud/datastore/entity.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,8 @@ class Entity(dict):
6565
6666
:type key: :class:`gcloud.datastore.key.Key`
6767
:param key: Optional key to be set on entity. Required for
68-
:func:`gcloud.datastore.put()`
68+
:func:`gcloud.datastore.put()` and
69+
:func:`gcloud.datastore.put_multi()`
6970
7071
:type exclude_from_indexes: tuple of string
7172
:param exclude_from_indexes: Names of fields whose values are not to be

gcloud/datastore/test_api.py

Lines changed: 82 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -617,7 +617,7 @@ def test_miss(self):
617617
self.assertTrue(result is None)
618618

619619

620-
class Test_put_function(unittest2.TestCase):
620+
class Test_put_multi_function(unittest2.TestCase):
621621

622622
def setUp(self):
623623
from gcloud.datastore._testing import _setup_defaults
@@ -628,8 +628,9 @@ def tearDown(self):
628628
_tear_down_defaults(self)
629629

630630
def _callFUT(self, entities, connection=None, dataset_id=None):
631-
from gcloud.datastore.api import put
632-
return put(entities, connection=connection, dataset_id=dataset_id)
631+
from gcloud.datastore.api import put_multi
632+
return put_multi(entities, connection=connection,
633+
dataset_id=dataset_id)
633634

634635
def test_no_connection(self):
635636
from gcloud.datastore import _implicit_environ
@@ -762,7 +763,50 @@ def test_implicit_connection(self):
762763
self.assertEqual(len(CURR_BATCH.mutation.delete), 0)
763764

764765

765-
class Test_delete_function(unittest2.TestCase):
766+
class Test_put_function(unittest2.TestCase):
767+
768+
def setUp(self):
769+
from gcloud.datastore._testing import _setup_defaults
770+
_setup_defaults(self)
771+
772+
def tearDown(self):
773+
from gcloud.datastore._testing import _tear_down_defaults
774+
_tear_down_defaults(self)
775+
776+
def _callFUT(self, entity, connection=None, dataset_id=None):
777+
from gcloud.datastore.api import put
778+
return put(entity, connection=connection, dataset_id=dataset_id)
779+
780+
def test_implicit_connection(self):
781+
from gcloud.datastore._testing import _monkey_defaults
782+
from gcloud.datastore.test_batch import _Connection
783+
from gcloud.datastore.test_batch import _Entity
784+
from gcloud.datastore.test_batch import _Key
785+
786+
# Build basic mocks needed to delete.
787+
_DATASET = 'DATASET'
788+
connection = _Connection()
789+
entity = _Entity(foo=u'bar')
790+
key = entity.key = _Key(_DATASET)
791+
792+
with _monkey_defaults(connection=connection):
793+
# Set up Batch on stack so we can check it is used.
794+
with _NoCommitBatch(_DATASET, connection) as CURR_BATCH:
795+
result = self._callFUT(entity)
796+
797+
self.assertEqual(result, None)
798+
self.assertEqual(len(CURR_BATCH.mutation.insert_auto_id), 0)
799+
self.assertEqual(len(CURR_BATCH.mutation.upsert), 1)
800+
upserts = list(CURR_BATCH.mutation.upsert)
801+
self.assertEqual(len(upserts), 1)
802+
self.assertEqual(upserts[0].key, key.to_protobuf())
803+
properties = list(upserts[0].property)
804+
self.assertEqual(properties[0].name, 'foo')
805+
self.assertEqual(properties[0].value.string_value, u'bar')
806+
self.assertEqual(len(CURR_BATCH.mutation.delete), 0)
807+
808+
809+
class Test_delete_multi_function(unittest2.TestCase):
766810

767811
def setUp(self):
768812
from gcloud.datastore._testing import _setup_defaults
@@ -773,8 +817,8 @@ def tearDown(self):
773817
_tear_down_defaults(self)
774818

775819
def _callFUT(self, keys, connection=None, dataset_id=None):
776-
from gcloud.datastore.api import delete
777-
return delete(keys, connection=connection, dataset_id=dataset_id)
820+
from gcloud.datastore.api import delete_multi
821+
return delete_multi(keys, connection=connection, dataset_id=dataset_id)
778822

779823
def test_no_connection(self):
780824
from gcloud.datastore import _implicit_environ
@@ -918,6 +962,38 @@ def test_implicit_connection_and_dataset_id(self):
918962
self.assertEqual(len(connection._committed), 0)
919963

920964

965+
class Test_delete_function(unittest2.TestCase):
966+
967+
def setUp(self):
968+
from gcloud.datastore._testing import _setup_defaults
969+
_setup_defaults(self)
970+
971+
def tearDown(self):
972+
from gcloud.datastore._testing import _tear_down_defaults
973+
_tear_down_defaults(self)
974+
975+
def _callFUT(self, key, connection=None, dataset_id=None):
976+
from gcloud.datastore.api import delete
977+
return delete(key, connection=connection, dataset_id=dataset_id)
978+
979+
def test_no_batch(self):
980+
from gcloud.datastore.test_batch import _Connection
981+
from gcloud.datastore.test_batch import _Key
982+
983+
# Build basic mocks needed to delete.
984+
_DATASET = 'DATASET'
985+
connection = _Connection()
986+
key = _Key(_DATASET)
987+
988+
result = self._callFUT(key, connection=connection,
989+
dataset_id=_DATASET)
990+
self.assertEqual(result, None)
991+
self.assertEqual(len(connection._committed), 1)
992+
dataset_id, mutation = connection._committed[0]
993+
self.assertEqual(dataset_id, _DATASET)
994+
self.assertEqual(list(mutation.delete), [key.to_protobuf()])
995+
996+
921997
class Test_allocate_ids_function(unittest2.TestCase):
922998

923999
def _callFUT(self, incomplete_key, num_ids, connection=None):

0 commit comments

Comments
 (0)