--- a/app/soc/logic/model.py Sun Oct 12 00:08:54 2008 +0000
+++ b/app/soc/logic/model.py Sun Oct 12 00:12:53 2008 +0000
@@ -18,13 +18,17 @@
"""
__authors__ = [
+ '"Todd Larsen" <tlarsen@google.com>',
+ '"Sverre Rabbelier" <sverer@rabbelier.nl>',
'"Pawel Solyga" <pawel.solyga@gmail.com>',
- '"Todd Larsen" <tlarsen@google.com>',
]
from google.appengine.ext import db
+from soc.logic import key_name
+from soc.logic import out_of_band
+
def getFullClassName(cls):
"""Returns fully-qualified module.class name string."""
@@ -176,34 +180,167 @@
return None
-def updateModelProperties(model, **model_properties):
- """Update existing model entity using supplied model properties.
+class BaseLogic():
+ """Base logic for entity classes.
+
+ The BaseLogic class functions specific to Entity classes by relying
+ on the the child-classes to implement _model, _name and _key_name
+ """
+
+ def _updateField(self, model, name, value):
+ """Hook called when a field is updated.
+
+ Base classes should override if any special actions need to be
+ taken when a field is updated. The field is not updated if the
+ method does not return a True value.
+ """
+
+ return True
- Args:
- model: a model entity
- **model_properties: keyword arguments that correspond to model entity
- properties and their values
+ def getFromKeyName(self, key_name):
+ """"Returns User entity for key_name or None if not found.
+-
+- Args:
+- key_name: key name of entity
+ """
+ return self._model.get_by_key_name(key_name)
+
+ def getFromFields(self, **kwargs):
+ """Returns the entity for a given link name, or None if not found.
+
+ Args:
+ link_name: a link name of the entity that uniquely identifies it
+ """
+ # lookup by Sponsor key name
+ key_name = self.getKeyNameForFields(**kwargs)
- Returns:
- the original model entity with any supplied properties changed
- """
- def update():
- return _unsafeUpdateModelProperties(model, **model_properties)
+ if key_name:
+ entity = self._model.get_by_key_name(key_name)
+ else:
+ entity = None
+
+ return entity
+
+ def getIfFields(self, **kwargs):
+ """Returns Sponsor entity for supplied link name if one exists.
+
+ Args:
+ link_name: a link name of the Sponsor that uniquely identifies it
+
+ Returns:
+ * None if link name is false.
+ * Sponsor entity for supplied link_name
- return db.run_in_transaction(update)
+ Raises:
+ out_of_band.ErrorResponse if link name is not false, but no Sponsor entity
+ with the supplied link name exists in the Datastore
+ """
+ if not all(kwargs.values()):
+ # exit without error, to let view know that link_name was not supplied
+ return None
+
+ entity = self.getFromFields(**kwargs)
+
+ if entity:
+ # a Sponsor exist for this link_name, so return that Sponsor entity
+ return entity
+
+ fields = []
+
+ for key, value in kwargs.iteritems():
+ fields.extend('"%s" is "%s"' % (key, value))
+
+ # else: fields were supplied, but there is no Entity that has it
+ raise out_of_band.ErrorResponse(
+ 'There is no %s with %s.' % (self._name, ''.join(fields)), status=404)
+
+ def getKeyNameForFields(self, **kwargs):
+ """Return a Datastore key_name for a Sponsor from the link name.
+ Args:
+ link_name: a link name of the entity that uniquely identifies it
+ """
+ if not all(kwargs.values()):
+ return None
-def _unsafeUpdateModelProperties(model, **model_properties):
- """(see updateModelProperties)
+ return self._keyName(**kwargs)
+
+ def getForLimitAndOffset(self, limit, offset=0):
+ """Returns entities for given offset and limit or None if not found.
+
+ Args:
+ limit: max amount of entities to return
+ offset: optional offset in entities list which defines first entity to
+ return; default is zero (first entity)
+ """
+ query = self._model.all()
+ return query.fetch(limit, offset)
- Like updateModelProperties(), but not run within a transaction.
- """
- properties = model.properties()
+ def updateModelProperties(self, model, **model_properties):
+ """Update existing model entity using supplied model properties.
+
+ Args:
+ model: a model entity
+ **model_properties: keyword arguments that correspond to model entity
+ properties and their values
+
+ Returns:
+ the original model entity with any supplied properties changed
+ """
+ def update():
+ return self._unsafeUpdateModelProperties(model, **model_properties)
+
+ return db.run_in_transaction(update)
+
+ def _unsafeUpdateModelProperties(self, model, **model_properties):
+ """(see updateModelProperties)
+
+ Like updateModelProperties(), but not run within a transaction.
+ """
+ properties = model.properties()
- for prop in properties.values():
- if prop.name in model_properties:
- value = model_properties[prop.name]
- prop.__set__(model, value)
+ for prop in properties.values():
+ name = prop.name
+
+ if not name in self._skip_properties and name in model_properties:
+ value = model_properties[prop.name]
+
+ if self._updateField(model, name, value):
+ prop.__set__(model, value)
+
+ model.put()
+ return model
+
+ def updateOrCreateFromKeyName(self, properties, key_name):
+ """Update existing entity, or create new one with supplied properties.
+
+ Args:
+ link_name: a link_name of the entity that uniquely identifies it
+ **properties: keyword arguments that correspond to entity
+ properties and their values
- model.put()
- return model
\ No newline at end of file
+ Returns:
+ the entity corresponding to the key_name, with any supplied
+ properties changed, or a new entity now associated with the
+ supplied key_name and properties.
+ """
+
+ entity = self.getFromKeyName(key_name)
+
+ if not entity:
+ # entity did not exist, so create one in a transaction
+ entity = self._model.get_or_insert(key_name, **properties)
+
+ # there is no way to be sure if get_or_insert() returned a new entity or
+ # got an existing one due to a race, so update with sponsor_properties anyway,
+ # in a transaction
+ return self.updateModelProperties(entity, **properties)
+
+ def updateOrCreateFromFields(self, properties, **kwargs):
+ """Like updateOrCreateFromKeyName, but resolves **kwargs to a key_name first
+ """
+
+ # attempt to retrieve the existing entity
+ key_name = self.getKeyNameForFields(**kwargs)
+
+ return self.updateOrCreateFromKeyName(properties, key_name)