37 |
37 |
38 |
38 |
39 class Error(Exception): |
39 class Error(Exception): |
40 """Base class for all exceptions raised by this module. |
40 """Base class for all exceptions raised by this module. |
41 """ |
41 """ |
|
42 |
|
43 pass |
|
44 |
|
45 class InvalidArgumentError(Error): |
|
46 """Raised when an invalid argument is passed to a method. |
|
47 |
|
48 For example, if an argument is None, but must always be non-False. |
|
49 """ |
|
50 |
|
51 pass |
|
52 |
|
53 class NoEntityError(InvalidArgumentError): |
|
54 """Raised when no entity is passed to a method that requires one. |
|
55 """ |
|
56 |
42 pass |
57 pass |
43 |
58 |
44 |
59 |
45 class Logic(object): |
60 class Logic(object): |
46 """Base logic for entity classes. |
61 """Base logic for entity classes. |
103 entity: the unaltered entity |
118 entity: the unaltered entity |
104 name: the name of the field to be changed |
119 name: the name of the field to be changed |
105 value: the new value |
120 value: the new value |
106 """ |
121 """ |
107 |
122 |
|
123 if not entity: |
|
124 raise NoEntityError |
|
125 |
|
126 if not entity_properties or (name not in entity_properties): |
|
127 raise InvalidArgumentError |
|
128 |
108 return True |
129 return True |
109 |
130 |
110 def _onCreate(self, entity): |
131 def _onCreate(self, entity): |
111 """Called when an entity has been created. |
132 """Called when an entity has been created. |
112 |
133 |
113 Classes that override this can use it to do any post-creation operations. |
134 Classes that override this can use it to do any post-creation operations. |
114 """ |
135 """ |
115 |
136 |
|
137 if not entity: |
|
138 raise NoEntityError |
|
139 |
116 sidebar.flush() |
140 sidebar.flush() |
117 |
141 |
118 def _onUpdate(self, entity): |
142 def _onUpdate(self, entity): |
119 """Called when an entity has been updated. |
143 """Called when an entity has been updated. |
120 |
144 |
121 Classes that override this can use it to do any post-update operations. |
145 Classes that override this can use it to do any post-update operations. |
122 """ |
146 """ |
123 |
147 |
124 pass |
148 if not entity: |
125 |
149 raise NoEntityError |
|
150 |
126 def _onDelete(self, entity): |
151 def _onDelete(self, entity): |
127 """Called when an entity has been deleted. |
152 """Called when an entity has been deleted. |
128 |
153 |
129 Classes that override this can use it to do any post-deletion operations. |
154 Classes that override this can use it to do any post-deletion operations. |
130 """ |
155 """ |
131 |
156 |
132 pass |
157 if not entity: |
|
158 raise NoEntityError |
133 |
159 |
134 def getKeyNameFromFields(self, fields): |
160 def getKeyNameFromFields(self, fields): |
135 """Returns the KeyName constructed from fields dict for this type of entity. |
161 """Returns the KeyName constructed from fields dict for this type of entity. |
136 |
162 |
137 The KeyName is in the following format: |
163 The KeyName is in the following format: |
138 <key_value1>/<key_value2>/.../<key_valueN> |
164 <key_value1>/<key_value2>/.../<key_valueN> |
139 """ |
165 """ |
140 |
166 |
|
167 if not fields: |
|
168 raise InvalidArgumentError |
|
169 |
141 key_field_names = self.getKeyFieldNames() |
170 key_field_names = self.getKeyFieldNames() |
142 |
171 |
143 # check if all key_field_names for this entity are present in fields |
172 # check if all key_field_names for this entity are present in fields |
144 if not all(field in fields.keys() for field in key_field_names): |
173 if not all(field in fields.keys() for field in key_field_names): |
145 raise Error("Not all the required key fields are present") |
174 raise InvalidArgumentError("Not all the required key fields are present") |
146 |
175 |
147 if not all(fields.get(field) for field in key_field_names): |
176 if not all(fields.get(field) for field in key_field_names): |
148 raise Error("Not all KeyValues are non-false") |
177 raise InvalidArgumentError("Not all KeyValues are non-false") |
149 |
178 |
150 # construct the KeyValues in the order given by getKeyFieldNames() |
179 # construct the KeyValues in the order given by getKeyFieldNames() |
151 keyvalues = [] |
180 keyvalues = [] |
152 for key_field_name in key_field_names: |
181 for key_field_name in key_field_names: |
153 keyvalues.append(fields[key_field_name]) |
182 keyvalues.append(fields[key_field_name]) |
155 # construct the KeyName in the appropriate format |
184 # construct the KeyName in the appropriate format |
156 return '/'.join(keyvalues) |
185 return '/'.join(keyvalues) |
157 |
186 |
158 def getFullModelClassName(self): |
187 def getFullModelClassName(self): |
159 """Returns fully-qualified model module.class name string. |
188 """Returns fully-qualified model module.class name string. |
160 """ |
189 """ |
|
190 |
161 return '%s.%s' % (self._model.__module__, self._model.__name__) |
191 return '%s.%s' % (self._model.__module__, self._model.__name__) |
162 |
192 |
163 def getKeyValuesFromEntity(self, entity): |
193 def getKeyValuesFromEntity(self, entity): |
164 """Extracts the key values from entity and returns them. |
194 """Extracts the key values from entity and returns them. |
165 |
195 |
178 |
211 |
179 Args: |
212 Args: |
180 fields: the dict from which to extract the key values |
213 fields: the dict from which to extract the key values |
181 """ |
214 """ |
182 |
215 |
|
216 if not all( (i in fields for i in ['scope_path', 'link_id']) ): |
|
217 raise InvalidArgumentError |
|
218 |
183 return [fields['scope_path'], fields['link_id']] |
219 return [fields['scope_path'], fields['link_id']] |
184 |
220 |
185 def getKeyFieldNames(self): |
221 def getKeyFieldNames(self): |
186 """Returns an array with the names of the Key Fields. |
222 """Returns an array with the names of the Key Fields. |
187 |
223 |
212 required translations/modifications performed. |
248 required translations/modifications performed. |
213 |
249 |
214 Args: |
250 Args: |
215 dictionary: The arguments to massage |
251 dictionary: The arguments to massage |
216 """ |
252 """ |
|
253 |
|
254 if not dictionary: |
|
255 raise InvalidArgumentError |
217 |
256 |
218 keys = self.getKeyFieldNames() |
257 keys = self.getKeyFieldNames() |
219 values = self.getKeyValuesFromFields(dictionary) |
258 values = self.getKeyValuesFromFields(dictionary) |
220 key_fields = dicts.zip(keys, values) |
259 key_fields = dicts.zip(keys, values) |
221 |
260 |
226 |
265 |
227 Args: |
266 Args: |
228 key_name: key name of entity |
267 key_name: key name of entity |
229 """ |
268 """ |
230 |
269 |
|
270 if not key_name: |
|
271 raise InvalidArgumentError |
|
272 |
231 return self._model.get_by_key_name(key_name) |
273 return self._model.get_by_key_name(key_name) |
232 |
274 |
233 def getFromKeyFields(self, fields): |
275 def getFromKeyFields(self, fields): |
234 """Returns the entity for the specified key names, or None if not found. |
276 """Returns the entity for the specified key names, or None if not found. |
235 |
277 |
236 Args: |
278 Args: |
237 fields: a dict containing the fields of the entity that |
279 fields: a dict containing the fields of the entity that |
238 uniquely identifies it |
280 uniquely identifies it |
239 """ |
281 """ |
|
282 |
|
283 if not fields: |
|
284 raise InvalidArgumentError |
240 |
285 |
241 key_fields = self.getKeyFieldsFromFields(fields) |
286 key_fields = self.getKeyFieldsFromFields(fields) |
242 |
287 |
243 if all(key_fields.values()): |
288 if all(key_fields.values()): |
244 key_name = self.getKeyNameFromFields(key_fields) |
289 key_name = self.getKeyNameFromFields(key_fields) |
378 properties changed, or a new entity now associated with the |
429 properties changed, or a new entity now associated with the |
379 supplied key_name and properties. |
430 supplied key_name and properties. |
380 """ |
431 """ |
381 |
432 |
382 entity = self.getFromKeyName(key_name) |
433 entity = self.getFromKeyName(key_name) |
383 |
434 |
384 create_entity = not entity |
435 create_entity = not entity |
385 |
436 |
386 if create_entity: |
437 if create_entity: |
387 # entity did not exist, so create one in a transaction |
438 # entity did not exist, so create one in a transaction |
388 entity = self._model.get_or_insert(key_name, **properties) |
439 entity = self._model.get_or_insert(key_name, **properties) |
389 |
440 |
390 |
441 |
391 # there is no way to be sure if get_or_insert() returned a new entity or |
442 # there is no way to be sure if get_or_insert() returned a new entity or |
392 # got an existing one due to a race, so update with properties anyway, |
443 # got an existing one due to a race, so update with properties anyway, |
393 # in a transaction |
444 # in a transaction |
394 entity = self.updateEntityProperties(entity, properties, silent=True) |
445 entity = self.updateEntityProperties(entity, properties, silent=True) |
395 |
446 |
397 # a new entity has been created call _onCreate |
448 # a new entity has been created call _onCreate |
398 self._onCreate(entity) |
449 self._onCreate(entity) |
399 else: |
450 else: |
400 # the entity has been updated call _onUpdate |
451 # the entity has been updated call _onUpdate |
401 self._onUpdate(entity) |
452 self._onUpdate(entity) |
402 |
453 |
403 return entity |
454 return entity |
404 |
455 |
405 def isDeletable(self, entity): |
456 def isDeletable(self, entity): |
406 """Returns whether the specified entity can be deleted. |
457 """Returns whether the specified entity can be deleted. |
407 |
458 |
408 Args: |
459 Args: |
409 entity: an existing entity in datastore |
460 entity: an existing entity in datastore |
410 """ |
461 """ |
411 |
462 |
412 return True |
463 return True |
413 |
464 |
414 def delete(self, entity): |
465 def delete(self, entity): |
415 """Delete existing entity from datastore. |
466 """Delete existing entity from datastore. |
416 |
467 |
417 Args: |
468 Args: |
418 entity: an existing entity in datastore |
469 entity: an existing entity in datastore |
419 """ |
470 """ |
420 |
471 |
421 entity.delete() |
472 entity.delete() |