app/soc/logic/models/base.py
changeset 308 740090cd17c9
child 317 87215136c268
equal deleted inserted replaced
307:bf43430caffb 308:740090cd17c9
       
     1 #!/usr/bin/python2.5
       
     2 #
       
     3 # Copyright 2008 the Melange authors.
       
     4 #
       
     5 # Licensed under the Apache License, Version 2.0 (the "License");
       
     6 # you may not use this file except in compliance with the License.
       
     7 # You may obtain a copy of the License at
       
     8 #
       
     9 #   http://www.apache.org/licenses/LICENSE-2.0
       
    10 #
       
    11 # Unless required by applicable law or agreed to in writing, software
       
    12 # distributed under the License is distributed on an "AS IS" BASIS,
       
    13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
       
    14 # See the License for the specific language governing permissions and
       
    15 # limitations under the License.
       
    16 
       
    17 """Helpers functions for updating different kinds of models in datastore.
       
    18 """
       
    19 
       
    20 __authors__ = [
       
    21   '"Todd Larsen" <tlarsen@google.com>',
       
    22   '"Sverre Rabbelier" <sverer@rabbelier.nl>',
       
    23   '"Pawel Solyga" <pawel.solyga@gmail.com>',
       
    24   ]
       
    25 
       
    26 
       
    27 from google.appengine.ext import db
       
    28 
       
    29 from soc.logic import key_name
       
    30 from soc.logic import out_of_band
       
    31 
       
    32 
       
    33 class Logic():
       
    34   """Base logic for entity classes.
       
    35 
       
    36   The BaseLogic class functions specific to Entity classes by relying
       
    37   on the the child-classes to implement _model, _name and _key_name
       
    38   """
       
    39 
       
    40   def _updateField(self, model, name, value):
       
    41     """Hook called when a field is updated.
       
    42 
       
    43     Base classes should override if any special actions need to be
       
    44     taken when a field is updated. The field is not updated if the
       
    45     method does not return a True value.
       
    46     """
       
    47 
       
    48     return True
       
    49 
       
    50   def getFromKeyName(self, key_name):
       
    51     """"Returns User entity for key_name or None if not found.
       
    52 -
       
    53 -    Args:
       
    54 -      key_name: key name of entity
       
    55     """
       
    56 
       
    57     return self._model.get_by_key_name(key_name)
       
    58 
       
    59   def getFromFields(self, **kwargs):
       
    60     """Returns the entity for a given link name, or None if not found.
       
    61 
       
    62     Args:
       
    63       **kwargs: the fields of the entity that uniquely identifies it
       
    64     """
       
    65 
       
    66     key_name = self.getKeyNameForFields(**kwargs)
       
    67 
       
    68     if key_name:
       
    69       entity = self._model.get_by_key_name(key_name)
       
    70     else:
       
    71       entity = None
       
    72 
       
    73     return entity
       
    74 
       
    75   def getIfFields(self, **kwargs):
       
    76     """Returns entity for supplied link name if one exists.
       
    77 
       
    78     Args:
       
    79       **kwargs: the fields of the entity that uniquely identifies it
       
    80 
       
    81     Returns:
       
    82       * None if a field is false.
       
    83       * Eentity for supplied fields
       
    84 
       
    85     Raises:
       
    86       out_of_band.ErrorResponse if link name is not false, but no Sponsor entity
       
    87       with the supplied link name exists in the Datastore
       
    88     """
       
    89 
       
    90     if not all(kwargs.values()):
       
    91       # exit without error, to let view know that link_name was not supplied
       
    92       return None
       
    93 
       
    94     entity = self.getFromFields(**kwargs)
       
    95 
       
    96     if entity:
       
    97       # a Sponsor exist for this link_name, so return that Sponsor entity
       
    98       return entity
       
    99 
       
   100     fields = []
       
   101 
       
   102     for key, value in kwargs.iteritems():
       
   103       fields.extend('"%s" is "%s" ' % (key, value))
       
   104 
       
   105     # else: fields were supplied, but there is no Entity that has it
       
   106     raise out_of_band.ErrorResponse(
       
   107         'There is no %s with %s.' % (self._name, ''.join(fields)), status=404)
       
   108 
       
   109   def getKeyNameForFields(self, **kwargs):
       
   110     """Return a Datastore key_name for a Entity from the specified fields.
       
   111 
       
   112     Args:
       
   113       **kwargs: the fields of the entity that uniquely identifies it
       
   114     """
       
   115 
       
   116     if not all(kwargs.values()):
       
   117       return None
       
   118 
       
   119     return self._keyName(**kwargs)
       
   120 
       
   121   def getForLimitAndOffset(self, limit, offset=0):
       
   122     """Returns entities for given offset and limit or None if not found.
       
   123 
       
   124     Args:
       
   125       limit: max amount of entities to return
       
   126       offset: optional offset in entities list which defines first entity to
       
   127         return; default is zero (first entity)
       
   128     """
       
   129 
       
   130     query = self._model.all()
       
   131     return query.fetch(limit, offset)
       
   132 
       
   133   def updateModelProperties(self, model, **model_properties):
       
   134     """Update existing model entity using supplied model properties.
       
   135 
       
   136     Args:
       
   137       model: a model entity
       
   138       **model_properties: keyword arguments that correspond to model entity
       
   139         properties and their values
       
   140 
       
   141     Returns:
       
   142       the original model entity with any supplied properties changed
       
   143     """
       
   144 
       
   145     def update():
       
   146       return self._unsafeUpdateModelProperties(model, **model_properties)
       
   147 
       
   148     return db.run_in_transaction(update)
       
   149 
       
   150   def _unsafeUpdateModelProperties(self, model, **model_properties):
       
   151     """(see updateModelProperties)
       
   152 
       
   153     Like updateModelProperties(), but not run within a transaction.
       
   154     """
       
   155 
       
   156     properties = model.properties()
       
   157 
       
   158     for prop in properties.values():
       
   159       name = prop.name
       
   160 
       
   161       if not name in self._skip_properties and name in model_properties:
       
   162         value = model_properties[prop.name]
       
   163 
       
   164         if self._updateField(model, name, value):
       
   165           prop.__set__(model, value)
       
   166 
       
   167     model.put()
       
   168     return model
       
   169 
       
   170   def updateOrCreateFromKeyName(self, properties, key_name):
       
   171     """Update existing entity, or create new one with supplied properties.
       
   172 
       
   173     Args:
       
   174       properties: dictionairy with entity properties and their values
       
   175       key_name: the key_name of the entity that uniquely identifies it
       
   176 
       
   177     Returns:
       
   178       the entity corresponding to the key_name, with any supplied
       
   179       properties changed, or a new entity now associated with the
       
   180       supplied key_name and properties.
       
   181     """
       
   182 
       
   183     entity = self.getFromKeyName(key_name)
       
   184 
       
   185     if not entity:
       
   186       # entity did not exist, so create one in a transaction
       
   187       entity = self._model.get_or_insert(key_name, **properties)
       
   188 
       
   189     # there is no way to be sure if get_or_insert() returned a new entity or
       
   190     # got an existing one due to a race, so update with sponsor_properties anyway,
       
   191     # in a transaction
       
   192     return self.updateModelProperties(entity, **properties)
       
   193 
       
   194   def updateOrCreateFromFields(self, properties, **kwargs):
       
   195     """Like updateOrCreateFromKeyName, but resolves **kwargs to a key_name first
       
   196     """
       
   197 
       
   198     # attempt to retrieve the existing entity
       
   199     key_name  = self.getKeyNameForFields(**kwargs)
       
   200 
       
   201     return self.updateOrCreateFromKeyName(properties, key_name)
       
   202   
       
   203   def delete(self, entity):
       
   204     """Delete existing entity from datastore.
       
   205     
       
   206     Args:
       
   207       entity: an existing entity in datastore
       
   208     """
       
   209 
       
   210     entity.delete()