@@ -156,46 +156,84 @@ def get(self, etag=False):
156
156
else :
157
157
return self ._client .request ('get' , self ._add_suffix ())
158
158
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 ):
160
187
"""Sets the data at this location to the given value.
188
+
161
189
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.
163
190
164
191
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.
167
210
168
211
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.
171
214
172
215
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.
177
218
"""
178
219
# pylint: disable=missing-raises-doc
220
+ if not isinstance (expected_etag , six .string_types ):
221
+ raise ValueError ('Expected ETag must be a string.' )
179
222
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
199
237
200
238
def push (self , value = '' ):
201
239
"""Creates a new child node.
@@ -281,7 +319,7 @@ def transaction(self, transaction_update):
281
319
data , etag = self .get (etag = True )
282
320
while tries < _TRANSACTION_MAX_RETRIES :
283
321
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 )
285
323
if success :
286
324
return new_data
287
325
tries += 1
0 commit comments