Skip to content

Commit 64aaed4

Browse files
committed
Merge pull request #548 from tseaver/514-add_datastore_put_api
#514: add `datastore.put` API, remove `Entity.save'
2 parents f980aad + d46ed28 commit 64aaed4

File tree

12 files changed

+246
-239
lines changed

12 files changed

+246
-239
lines changed

docs/_components/datastore-getting-started.rst

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

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-
>>> entity.save()
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
@@ -34,7 +34,7 @@ Cloud Datastore
3434
entity = datastore.Entity(key=datastore.Key('Person'))
3535
entity['name'] = 'Your name'
3636
entity['age'] = 25
37-
entity.save()
37+
datastore.put([entity])
3838
3939
Cloud Storage
4040
~~~~~~~~~~~~~

gcloud/datastore/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
from gcloud.datastore.api import allocate_ids
5454
from gcloud.datastore.api import delete
5555
from gcloud.datastore.api import get
56+
from gcloud.datastore.api import put
5657
from gcloud.datastore.batch import Batch
5758
from gcloud.datastore.connection import Connection
5859
from gcloud.datastore.entity import Entity

gcloud/datastore/api.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,9 @@ def _get_dataset_id_from_keys(keys):
7070
:returns: The dataset ID of the keys.
7171
:raises: :class:`ValueError` if the key dataset IDs don't agree.
7272
"""
73+
if any(key is None for key in keys):
74+
raise ValueError('None not allowed')
75+
7376
dataset_id = keys[0].dataset_id
7477
# Rather than creating a list or set of all dataset IDs, we iterate
7578
# and check. We could allow the backend to check this for us if IDs
@@ -133,6 +136,32 @@ def get(keys, missing=None, deferred=None, connection=None):
133136
return entities
134137

135138

139+
def put(entities, connection=None):
140+
"""Save the entities in the Cloud Datastore.
141+
142+
:type entities: list of :class:`gcloud.datastore.entity.Entity`
143+
:param entities: The entities to be saved to the datastore.
144+
145+
:type connection: :class:`gcloud.datastore.connection.Connection`
146+
:param connection: Optional connection used to connect to datastore.
147+
"""
148+
if not entities:
149+
return
150+
151+
connection = connection or _implicit_environ.CONNECTION
152+
153+
current = _BATCHES.top
154+
in_batch = current is not None
155+
if not in_batch:
156+
keys = [entity.key for entity in entities]
157+
dataset_id = _get_dataset_id_from_keys(keys)
158+
current = Batch(dataset_id=dataset_id, connection=connection)
159+
for entity in entities:
160+
current.put(entity)
161+
if not in_batch:
162+
current.commit()
163+
164+
136165
def delete(keys, connection=None):
137166
"""Delete the keys in the Cloud Datastore.
138167

gcloud/datastore/demo/demo.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
toy.update({'name': 'Toy'})
2929

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

3333
# If we look it up by its key, we should find it...
3434
print(datastore.get([toy.key]))
@@ -55,7 +55,7 @@
5555
entity = datastore.Entity(key)
5656
entity['name'] = name
5757
entity['age'] = age
58-
entity.save()
58+
datastore.put([entity])
5959
# We'll start by look at all Thing entities:
6060
query = datastore.Query(kind='Thing')
6161

@@ -76,41 +76,41 @@
7676

7777
# You can also work inside a transaction.
7878
# (Check the official docs for explanations of what's happening here.)
79-
with datastore.Transaction():
79+
with datastore.Transaction() as xact:
8080
print('Creating and saving an entity...')
8181
key = datastore.Key('Thing', 'foo')
8282
thing = datastore.Entity(key)
8383
thing['age'] = 10
84-
thing.save()
84+
xact.put(thing)
8585

8686
print('Creating and saving another entity...')
8787
key2 = datastore.Key('Thing', 'bar')
8888
thing2 = datastore.Entity(key2)
8989
thing2['age'] = 15
90-
thing2.save()
90+
xact.put(thing2)
9191

9292
print('Committing the transaction...')
9393

9494
# Now that the transaction is commited, let's delete the entities.
9595
datastore.delete([key, key2])
9696

9797
# To rollback a transaction, just call .rollback()
98-
with datastore.Transaction() as t:
98+
with datastore.Transaction() as xact:
9999
key = datastore.Key('Thing', 'another')
100100
thing = datastore.Entity(key)
101-
thing.save()
102-
t.rollback()
101+
xact.put(thing)
102+
xact.rollback()
103103

104104
# Let's check if the entity was actually created:
105105
created = datastore.get([key])
106106
print('yes' if created else 'no')
107107

108108
# Remember, a key won't be complete until the transaction is commited.
109109
# That is, while inside the transaction block, thing.key will be incomplete.
110-
with datastore.Transaction():
110+
with datastore.Transaction() as xact:
111111
key = datastore.Key('Thing') # partial
112112
thing = datastore.Entity(key)
113-
thing.save()
113+
xact.put(thing)
114114
print(thing.key) # This will still be partial
115115

116116
print(thing.key) # This will be complete

gcloud/datastore/entity.py

Lines changed: 2 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,6 @@
1414

1515
"""Class for representing a single entity in the Cloud Datastore."""
1616

17-
from gcloud.datastore import _implicit_environ
18-
19-
20-
class NoKey(RuntimeError):
21-
"""Exception raised by Entity methods which require a key."""
22-
2317

2418
class Entity(dict):
2519
"""Entities are akin to rows in a relational database
@@ -70,8 +64,8 @@ class Entity(dict):
7064
any decoding / encoding step.
7165
7266
:type key: :class:`gcloud.datastore.key.Key`
73-
:param key: Optional key to be set on entity. Required for :meth:`save()`
74-
or :meth:`reload()`.
67+
:param key: Optional key to be set on entity. Required for
68+
:func:`gcloud.datastore.put()`
7569
7670
:type exclude_from_indexes: tuple of string
7771
:param exclude_from_indexes: Names of fields whose values are not to be
@@ -104,55 +98,6 @@ def exclude_from_indexes(self):
10498
"""
10599
return frozenset(self._exclude_from_indexes)
106100

107-
@property
108-
def _must_key(self):
109-
"""Return our key, or raise NoKey if not set.
110-
111-
:rtype: :class:`gcloud.datastore.key.Key`.
112-
:returns: The entity's key.
113-
:raises: :class:`NoKey` if no key is set.
114-
"""
115-
if self.key is None:
116-
raise NoKey()
117-
return self.key
118-
119-
def save(self, connection=None):
120-
"""Save the entity in the Cloud Datastore.
121-
122-
.. note::
123-
Any existing properties for the entity will be replaced by those
124-
currently set on this instance. Already-stored properties which do
125-
not correspond to keys set on this instance will be removed from
126-
the datastore.
127-
128-
.. note::
129-
Property values which are "text" (``unicode`` in Python2, ``str`` in
130-
Python3) map to 'string_value' in the datastore; values which are
131-
"bytes" (``str`` in Python2, ``bytes`` in Python3) map to
132-
'blob_value'.
133-
134-
:type connection: :class:`gcloud.datastore.connection.Connection`
135-
:param connection: Optional connection used to connect to datastore.
136-
"""
137-
connection = connection or _implicit_environ.CONNECTION
138-
139-
key = self._must_key
140-
assigned, new_id = connection.save_entity(
141-
dataset_id=key.dataset_id,
142-
key_pb=key.to_protobuf(),
143-
properties=dict(self),
144-
exclude_from_indexes=self.exclude_from_indexes)
145-
146-
# If we are in a transaction and the current entity needs an
147-
# automatically assigned ID, tell the transaction where to put that.
148-
transaction = connection.transaction()
149-
if transaction and key.is_partial:
150-
transaction.add_auto_id_entity(self)
151-
152-
if assigned:
153-
# Update the key (which may have been altered).
154-
self.key = self.key.completed_key(new_id)
155-
156101
def __repr__(self):
157102
if self.key:
158103
return '<Entity%s %s>' % (self.key.path,

0 commit comments

Comments
 (0)