8000 Preliminary changes to API. · firebase/firebase-admin-python@aae28c2 · GitHub
[go: up one dir, main page]

Skip to content

Commit aae28c2

Browse files
author
Alexander Whatley
committed
Preliminary changes to API.
1 parent f0d7eb0 commit aae28c2

File tree

3 files changed

+72
-34
lines changed

3 files changed

+72
-34
lines changed

firebase_admin/db.py

Lines changed: 68 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -156,46 +156,84 @@ def get(self, etag=False):
156156
else:
157157
return self._client.request('get', self._add_suffix())
158158

159-
def set(self, value, etag=None):
159+
def get_if_changed(self, etag):
160+
"""Get data in this location if the ETag no longer matches.
161+
162+
Args:
163+
etag: The ETag value we want to check against the ETag in the current location.
164+
165+
Returns:
166+
object: Tuple of boolean of whether the request was successful, current location's etag,
167+
and snapshot of location's data if passed in etag does not match.
168+
169+
Raises:
170+
ValueError: If the ETag is not a string.
171+
"""
172+
# pylint: disable=missing-raises-doc
173+
if not isinstance(etag, six.string_types):
174+
raise ValueError('ETag must be a string.')
175+
176+
try:
177+
value, headers = self._client.request('get', self._add_suffix(),
178+
headers={'if-none-match': etag},
179+
resp_headers=True)
180+
new_etag = headers.get('ETag')
181+
return True, new_etag, value
182+
except ApiCallError as error:
183+
# what to do here?
184+
raise error
185+
186+
def set(self, value):
160187
"""Sets the data at this location to the given value.
188+
161189
The value must be JSON-serializable and not None.
162-
If etag != None, checks to make sure that the ETag value matches that of the location.
163190
164191
Args:
165-
value: JSON-serialable value to be set at this location.
166-
etag: Value of ETag that we want to check.
192+
value: JSON-serializable value to be set at this location.
193+
194+
Raises:
195+
ValueError: If the value is None.
196+
TypeError: If the value is not JSON-serializable.
197+
ApiCallError: If an error occurs while communicating with the remote database server.
198+
"""
199+
if value is None:
200+
raise ValueError('Value must not be None.')
201+
self._client.request_oneway('put', self._add_suffix(), json=value, params='print=silent')
202+
203+
def set_if_unchanged(self, expected_etag, value):
204+
"""Sets the data at this location to the given value, if expected_etag is the same as the
205+
correct ETag value.
206+
207+
Args:
208+
expected_etag: Value of ETag we want to check.
209+
value: JSON-serializable value to be set at this location.
167210
168211
Returns:
169-
object: Tuple of False, current location's etag, and snapshot of location's data
170-
if passed in etag does not match.
212+
object: Tuple of boolean of whether the request was successful, current location's etag,
213+
and snapshot of location's data if passed in etag does not match.
171214
172215
Raises:
173-
ValueError: If the value is None, or if etag is not a string.
174-
TypeError: If the value is not JSON-serializable.
175-
ApiCallError: If an error occurs while communicating with the remote database server,
176-
or if the ETag does not match.
216+
ValueError: If the value is None, or if expected_etag is not a string.
217+
ApiCallError: If an error occurs while communicating with the remote database server.
177218
"""
178219
# pylint: disable=missing-raises-doc
220+
if not isinstance(expected_etag, six.string_types):
221+
raise ValueError('Expected ETag must be a string.')
179222
if value is None:
180-
raise ValueError('Value must not be None.')
181-
if etag is not None:
182-
if not isinstance(etag, six.string_types):
183-
raise ValueError('ETag must be a string.')
184-
try:
185-
self._client.request_oneway(
186-
'put', self._add_suffix(), json=value, headers={'if-match': etag})
187-
return True, etag, value
188-
except ApiCallError as error:
189-
detail = error.detail
190-
if detail.response is not None and 'ETag' in detail.response.headers:
191-
etag = detail.response.headers['ETag']
192-
snapshot = detail.response.json()
193-
return False, etag, snapshot
194-
else:
195-
raise error
196-
else:
197-
self._client.request_oneway('put', self._add_suffix(), json=value,
198-
params='print=silent')
223+
raise ValueError('Value must not be none.')
224+
225+
try:
226+
self._client.request_oneway('put', self._add_suffix(),
227+
json=value, headers={'if-match': expected_etag})
228+
return True, expected_etag, value
229+
except ApiCallError as error:
230+
detail = error.detail
231+
if detail.response is not None and 'ETag' in detail.response.headers:
232+
etag = detail.response.headers['ETag']
233+
snapshot = detail.response.json()
234+
return False, etag, snapshot
235+
else:
236+
raise error
199237

200238
def push(self, value=''):
201239
"""Creates a new child node.
@@ -281,7 +319,7 @@ def transaction(self, transaction_update):
281319
data, etag = self.get(etag=True)
282320
while tries < _TRANSACTION_MAX_RETRIES:
283321
new_data = transaction_update(data)
284-
success, etag, data = self.set(new_data, etag=etag)
322+
success, etag, data = self.set_if_unchanged(etag, new_data)
285323
if success:
286324
return new_data
287325
tries += 1

integration/test_db.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -164,10 +164,10 @@ def test_get_and_set_with_etag(self, testref):
164164
assert isinstance(etag, six.string_types)
165165

166166
update_data = {'name' : 'Jack Horner', 'since' : 1940}
167-
failed_update = edward.set(update_data, 'invalid-etag')
167+
failed_update = edward.set_if_unchanged('invalid-etag', update_data)
168168
assert failed_update == (False, etag, push_data)
169169

170-
successful_update = edward.set(update_data, etag)
170+
successful_update = edward.set_if_unchanged(etag, update_data)
171171
assert successful_update[0]
172172
assert successful_update[2] == update_data
173173

tests/test_db.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -241,15 +241,15 @@ def test_set_with_etag(self):
241241
ref = db.reference('/test')
242242
data = {'foo': 'bar'}
243243
recorder = self.instrument(ref, json.dumps(data))
244-
vals = ref.set(data, '0')
244+
vals = ref.set_if_unchanged('0', data)
245245
assert vals == (True, '0', data)
246246
assert len(recorder) == 1
247247
assert recorder[0].method == 'PUT'
248248
assert recorder[0].url == 'https://test.firebaseio.com/test.json'
249249
assert json.loads(recorder[0].body.decode()) == data
250250
assert recorder[0].headers['Authorization'] == 'Bearer mock-token'
251251

252-
vals = ref.set(data, '1')
252+
vals = ref.set_if_unchanged('1', data)
253253
assert vals == (False, '0', data)
254254
assert len(recorder) == 1
255255

0 commit comments

Comments
 (0)
0