174 break |
178 break |
175 |
179 |
176 return None |
180 return None |
177 |
181 |
178 |
182 |
179 def updateModelProperties(model, **model_properties): |
183 class BaseLogic(): |
180 """Update existing model entity using supplied model properties. |
184 """Base logic for entity classes. |
181 |
185 |
182 Args: |
186 The BaseLogic class functions specific to Entity classes by relying |
183 model: a model entity |
187 on the the child-classes to implement _model, _name and _key_name |
184 **model_properties: keyword arguments that correspond to model entity |
188 """ |
185 properties and their values |
189 |
186 |
190 def _updateField(self, model, name, value): |
187 Returns: |
191 """Hook called when a field is updated. |
188 the original model entity with any supplied properties changed |
192 |
189 """ |
193 Base classes should override if any special actions need to be |
190 def update(): |
194 taken when a field is updated. The field is not updated if the |
191 return _unsafeUpdateModelProperties(model, **model_properties) |
195 method does not return a True value. |
192 |
196 """ |
193 return db.run_in_transaction(update) |
197 |
194 |
198 return True |
195 |
199 |
196 def _unsafeUpdateModelProperties(model, **model_properties): |
200 def getFromKeyName(self, key_name): |
197 """(see updateModelProperties) |
201 """"Returns User entity for key_name or None if not found. |
198 |
202 - |
199 Like updateModelProperties(), but not run within a transaction. |
203 - Args: |
200 """ |
204 - key_name: key name of entity |
201 properties = model.properties() |
205 """ |
202 |
206 return self._model.get_by_key_name(key_name) |
203 for prop in properties.values(): |
207 |
204 if prop.name in model_properties: |
208 def getFromFields(self, **kwargs): |
205 value = model_properties[prop.name] |
209 """Returns the entity for a given link name, or None if not found. |
206 prop.__set__(model, value) |
210 |
207 |
211 Args: |
208 model.put() |
212 link_name: a link name of the entity that uniquely identifies it |
209 return model |
213 """ |
|
214 # lookup by Sponsor key name |
|
215 key_name = self.getKeyNameForFields(**kwargs) |
|
216 |
|
217 if key_name: |
|
218 entity = self._model.get_by_key_name(key_name) |
|
219 else: |
|
220 entity = None |
|
221 |
|
222 return entity |
|
223 |
|
224 def getIfFields(self, **kwargs): |
|
225 """Returns Sponsor entity for supplied link name if one exists. |
|
226 |
|
227 Args: |
|
228 link_name: a link name of the Sponsor that uniquely identifies it |
|
229 |
|
230 Returns: |
|
231 * None if link name is false. |
|
232 * Sponsor entity for supplied link_name |
|
233 |
|
234 Raises: |
|
235 out_of_band.ErrorResponse if link name is not false, but no Sponsor entity |
|
236 with the supplied link name exists in the Datastore |
|
237 """ |
|
238 if not all(kwargs.values()): |
|
239 # exit without error, to let view know that link_name was not supplied |
|
240 return None |
|
241 |
|
242 entity = self.getFromFields(**kwargs) |
|
243 |
|
244 if entity: |
|
245 # a Sponsor exist for this link_name, so return that Sponsor entity |
|
246 return entity |
|
247 |
|
248 fields = [] |
|
249 |
|
250 for key, value in kwargs.iteritems(): |
|
251 fields.extend('"%s" is "%s"' % (key, value)) |
|
252 |
|
253 # else: fields were supplied, but there is no Entity that has it |
|
254 raise out_of_band.ErrorResponse( |
|
255 'There is no %s with %s.' % (self._name, ''.join(fields)), status=404) |
|
256 |
|
257 def getKeyNameForFields(self, **kwargs): |
|
258 """Return a Datastore key_name for a Sponsor from the link name. |
|
259 |
|
260 Args: |
|
261 link_name: a link name of the entity that uniquely identifies it |
|
262 """ |
|
263 if not all(kwargs.values()): |
|
264 return None |
|
265 |
|
266 return self._keyName(**kwargs) |
|
267 |
|
268 def getForLimitAndOffset(self, limit, offset=0): |
|
269 """Returns entities for given offset and limit or None if not found. |
|
270 |
|
271 Args: |
|
272 limit: max amount of entities to return |
|
273 offset: optional offset in entities list which defines first entity to |
|
274 return; default is zero (first entity) |
|
275 """ |
|
276 query = self._model.all() |
|
277 return query.fetch(limit, offset) |
|
278 |
|
279 def updateModelProperties(self, model, **model_properties): |
|
280 """Update existing model entity using supplied model properties. |
|
281 |
|
282 Args: |
|
283 model: a model entity |
|
284 **model_properties: keyword arguments that correspond to model entity |
|
285 properties and their values |
|
286 |
|
287 Returns: |
|
288 the original model entity with any supplied properties changed |
|
289 """ |
|
290 def update(): |
|
291 return self._unsafeUpdateModelProperties(model, **model_properties) |
|
292 |
|
293 return db.run_in_transaction(update) |
|
294 |
|
295 def _unsafeUpdateModelProperties(self, model, **model_properties): |
|
296 """(see updateModelProperties) |
|
297 |
|
298 Like updateModelProperties(), but not run within a transaction. |
|
299 """ |
|
300 properties = model.properties() |
|
301 |
|
302 for prop in properties.values(): |
|
303 name = prop.name |
|
304 |
|
305 if not name in self._skip_properties and name in model_properties: |
|
306 value = model_properties[prop.name] |
|
307 |
|
308 if self._updateField(model, name, value): |
|
309 prop.__set__(model, value) |
|
310 |
|
311 model.put() |
|
312 return model |
|
313 |
|
314 def updateOrCreateFromKeyName(self, properties, key_name): |
|
315 """Update existing entity, or create new one with supplied properties. |
|
316 |
|
317 Args: |
|
318 link_name: a link_name of the entity that uniquely identifies it |
|
319 **properties: keyword arguments that correspond to entity |
|
320 properties and their values |
|
321 |
|
322 Returns: |
|
323 the entity corresponding to the key_name, with any supplied |
|
324 properties changed, or a new entity now associated with the |
|
325 supplied key_name and properties. |
|
326 """ |
|
327 |
|
328 entity = self.getFromKeyName(key_name) |
|
329 |
|
330 if not entity: |
|
331 # entity did not exist, so create one in a transaction |
|
332 entity = self._model.get_or_insert(key_name, **properties) |
|
333 |
|
334 # there is no way to be sure if get_or_insert() returned a new entity or |
|
335 # got an existing one due to a race, so update with sponsor_properties anyway, |
|
336 # in a transaction |
|
337 return self.updateModelProperties(entity, **properties) |
|
338 |
|
339 def updateOrCreateFromFields(self, properties, **kwargs): |
|
340 """Like updateOrCreateFromKeyName, but resolves **kwargs to a key_name first |
|
341 """ |
|
342 |
|
343 # attempt to retrieve the existing entity |
|
344 key_name = self.getKeyNameForFields(**kwargs) |
|
345 |
|
346 return self.updateOrCreateFromKeyName(properties, key_name) |