app/soc/logic/model.py
changeset 305 972d28056d9d
parent 303 4f1bb54ddae5
child 310 0386d634ad9f
equal deleted inserted replaced
304:812abb9a7e3b 305:972d28056d9d
    30 from soc.logic import out_of_band
    30 from soc.logic import out_of_band
    31 
    31 
    32 
    32 
    33 def getFullClassName(cls):
    33 def getFullClassName(cls):
    34   """Returns fully-qualified module.class name string.""" 
    34   """Returns fully-qualified module.class name string.""" 
       
    35 
    35   return '%s.%s' % (cls.__module__, cls.__name__) 
    36   return '%s.%s' % (cls.__module__, cls.__name__) 
    36 
    37 
    37 
    38 
    38 def buildTypedQueryString(base_class, derived_class=None):
    39 def buildTypedQueryString(base_class, derived_class=None):
    39   """Returns a GQL query string compatible with PolyModel.
    40   """Returns a GQL query string compatible with PolyModel.
    44     derived_class: optional more-specific Model class that
    45     derived_class: optional more-specific Model class that
    45       derives from base_class, such as soc.models.document.Document;
    46       derives from base_class, such as soc.models.document.Document;
    46       default is None, in which case the inheritance_line
    47       default is None, in which case the inheritance_line
    47       property is *not* tested by the returned query string
    48       property is *not* tested by the returned query string
    48   """
    49   """
       
    50 
    49   query_str_parts = ['SELECT * FROM ', base_class.__name__]
    51   query_str_parts = ['SELECT * FROM ', base_class.__name__]
    50 
    52 
    51   if derived_class:
    53   if derived_class:
    52     query_str_parts.extend(
    54     query_str_parts.extend(
    53       [" WHERE inheritance_line = '", getFullClassName(derived_class), "'"])
    55       [" WHERE inheritance_line = '", getFullClassName(derived_class), "'"])
    62     base_class, derived_class: see buildTypedQueryString()
    64     base_class, derived_class: see buildTypedQueryString()
    63     order_by: optional field name by which to order the query results;
    65     order_by: optional field name by which to order the query results;
    64       default is None, in which case no ORDER BY clause is placed in
    66       default is None, in which case no ORDER BY clause is placed in
    65       the query string
    67       the query string
    66   """
    68   """
       
    69 
    67   query_str_parts = [
    70   query_str_parts = [
    68     buildTypedQueryString(base_class, derived_class=derived_class)]
    71     buildTypedQueryString(base_class, derived_class=derived_class)]
    69 
    72 
    70   if order_by:
    73   if order_by:
    71     query_str_parts.extend([' ORDER BY ', order_by])
    74     query_str_parts.extend([' ORDER BY ', order_by])
    80   Args:
    83   Args:
    81     limit: max amount of entities to return
    84     limit: max amount of entities to return
    82     offset: optional offset in entities list which defines first entity to
    85     offset: optional offset in entities list which defines first entity to
    83       return; default is zero (first entity)
    86       return; default is zero (first entity)
    84   """
    87   """
       
    88 
    85   query_string = buildOrderedQueryString(
    89   query_string = buildOrderedQueryString(
    86       base_class, derived_class=derived_class, order_by=order_by)
    90       base_class, derived_class=derived_class, order_by=order_by)
    87 
    91 
    88   query = db.GqlQuery(query_string)
    92   query = db.GqlQuery(query_string)
    89 
    93 
   107       of the supplied (non-None) fields
   111       of the supplied (non-None) fields
   108         OR
   112         OR
   109       possibly None if query had no results for the supplied field
   113       possibly None if query had no results for the supplied field
   110       that was used.
   114       that was used.
   111   """
   115   """
       
   116 
   112   # SELECT * FROM base_class WHERE inheritance_line = 'derived_class'
   117   # SELECT * FROM base_class WHERE inheritance_line = 'derived_class'
   113   typed_query_str = buildTypedQueryString(
   118   typed_query_str = buildTypedQueryString(
   114     base_class, derived_class=derived_class)
   119     base_class, derived_class=derived_class)
   115   
   120   
   116   if derived_class:
   121   if derived_class:
   144     if that offset would be less than zero
   149     if that offset would be less than zero
   145       OR
   150       OR
   146     None if there are no nearest entities or the offset of the beginning of
   151     None if there are no nearest entities or the offset of the beginning of
   147     the range cannot be found for some reason 
   152     the range cannot be found for some reason 
   148   """
   153   """
       
   154 
   149   # find entity "nearest" to supplied fields
   155   # find entity "nearest" to supplied fields
   150   nearest_entities, field = getNearestEntities(
   156   nearest_entities, field = getNearestEntities(
   151       base_class, fields_to_try, derived_class=derived_class)
   157       base_class, fields_to_try, derived_class=derived_class)
   152   
   158   
   153   if not nearest_entities:
   159   if not nearest_entities:
   201     """"Returns User entity for key_name or None if not found.
   207     """"Returns User entity for key_name or None if not found.
   202 -
   208 -
   203 -    Args:
   209 -    Args:
   204 -      key_name: key name of entity
   210 -      key_name: key name of entity
   205     """
   211     """
       
   212 
   206     return self._model.get_by_key_name(key_name)
   213     return self._model.get_by_key_name(key_name)
   207 
   214 
   208   def getFromFields(self, **kwargs):
   215   def getFromFields(self, **kwargs):
   209     """Returns the entity for a given link name, or None if not found.
   216     """Returns the entity for a given link name, or None if not found.
   210 
   217 
   211     Args:
   218     Args:
   212       link_name: a link name of the entity that uniquely identifies it
   219       **kwargs: the fields of the entity that uniquely identifies it
   213     """
   220     """
   214     # lookup by Sponsor key name
   221 
   215     key_name = self.getKeyNameForFields(**kwargs)
   222     key_name = self.getKeyNameForFields(**kwargs)
   216 
   223 
   217     if key_name:
   224     if key_name:
   218       entity = self._model.get_by_key_name(key_name)
   225       entity = self._model.get_by_key_name(key_name)
   219     else:
   226     else:
   220       entity = None
   227       entity = None
   221 
   228 
   222     return entity
   229     return entity
   223 
   230 
   224   def getIfFields(self, **kwargs):
   231   def getIfFields(self, **kwargs):
   225     """Returns Sponsor entity for supplied link name if one exists.
   232     """Returns entity for supplied link name if one exists.
   226 
   233 
   227     Args:
   234     Args:
   228       link_name: a link name of the Sponsor that uniquely identifies it
   235       **kwargs: the fields of the entity that uniquely identifies it
   229 
   236 
   230     Returns:
   237     Returns:
   231       * None if link name is false.
   238       * None if a field is false.
   232       * Sponsor entity for supplied link_name
   239       * Eentity for supplied fields
   233 
   240 
   234     Raises:
   241     Raises:
   235       out_of_band.ErrorResponse if link name is not false, but no Sponsor entity
   242       out_of_band.ErrorResponse if link name is not false, but no Sponsor entity
   236       with the supplied link name exists in the Datastore
   243       with the supplied link name exists in the Datastore
   237     """
   244     """
       
   245 
   238     if not all(kwargs.values()):
   246     if not all(kwargs.values()):
   239       # exit without error, to let view know that link_name was not supplied
   247       # exit without error, to let view know that link_name was not supplied
   240       return None
   248       return None
   241 
   249 
   242     entity = self.getFromFields(**kwargs)
   250     entity = self.getFromFields(**kwargs)
   246       return entity
   254       return entity
   247 
   255 
   248     fields = []
   256     fields = []
   249 
   257 
   250     for key, value in kwargs.iteritems():
   258     for key, value in kwargs.iteritems():
   251       fields.extend('"%s" is "%s"' % (key, value))
   259       fields.extend('"%s" is "%s" ' % (key, value))
   252 
   260 
   253     # else: fields were supplied, but there is no Entity that has it
   261     # else: fields were supplied, but there is no Entity that has it
   254     raise out_of_band.ErrorResponse(
   262     raise out_of_band.ErrorResponse(
   255         'There is no %s with %s.' % (self._name, ''.join(fields)), status=404)
   263         'There is no %s with %s.' % (self._name, ''.join(fields)), status=404)
   256 
   264 
   257   def getKeyNameForFields(self, **kwargs):
   265   def getKeyNameForFields(self, **kwargs):
   258     """Return a Datastore key_name for a Sponsor from the link name.
   266     """Return a Datastore key_name for a Entity from the specified fields.
   259 
   267 
   260     Args:
   268     Args:
   261       link_name: a link name of the entity that uniquely identifies it
   269       **kwargs: the fields of the entity that uniquely identifies it
   262     """
   270     """
       
   271 
   263     if not all(kwargs.values()):
   272     if not all(kwargs.values()):
   264       return None
   273       return None
   265 
   274 
   266     return self._keyName(**kwargs)
   275     return self._keyName(**kwargs)
   267 
   276 
   271     Args:
   280     Args:
   272       limit: max amount of entities to return
   281       limit: max amount of entities to return
   273       offset: optional offset in entities list which defines first entity to
   282       offset: optional offset in entities list which defines first entity to
   274         return; default is zero (first entity)
   283         return; default is zero (first entity)
   275     """
   284     """
       
   285 
   276     query = self._model.all()
   286     query = self._model.all()
   277     return query.fetch(limit, offset)
   287     return query.fetch(limit, offset)
   278 
   288 
   279   def updateModelProperties(self, model, **model_properties):
   289   def updateModelProperties(self, model, **model_properties):
   280     """Update existing model entity using supplied model properties.
   290     """Update existing model entity using supplied model properties.
   285         properties and their values
   295         properties and their values
   286 
   296 
   287     Returns:
   297     Returns:
   288       the original model entity with any supplied properties changed
   298       the original model entity with any supplied properties changed
   289     """
   299     """
       
   300 
   290     def update():
   301     def update():
   291       return self._unsafeUpdateModelProperties(model, **model_properties)
   302       return self._unsafeUpdateModelProperties(model, **model_properties)
   292 
   303 
   293     return db.run_in_transaction(update)
   304     return db.run_in_transaction(update)
   294 
   305 
   295   def _unsafeUpdateModelProperties(self, model, **model_properties):
   306   def _unsafeUpdateModelProperties(self, model, **model_properties):
   296     """(see updateModelProperties)
   307     """(see updateModelProperties)
   297 
   308 
   298     Like updateModelProperties(), but not run within a transaction.
   309     Like updateModelProperties(), but not run within a transaction.
   299     """
   310     """
       
   311 
   300     properties = model.properties()
   312     properties = model.properties()
   301 
   313 
   302     for prop in properties.values():
   314     for prop in properties.values():
   303       name = prop.name
   315       name = prop.name
   304 
   316 
   313 
   325 
   314   def updateOrCreateFromKeyName(self, properties, key_name):
   326   def updateOrCreateFromKeyName(self, properties, key_name):
   315     """Update existing entity, or create new one with supplied properties.
   327     """Update existing entity, or create new one with supplied properties.
   316 
   328 
   317     Args:
   329     Args:
   318       link_name: a link_name of the entity that uniquely identifies it
   330       properties: dictionairy with entity properties and their values
   319       **properties: keyword arguments that correspond to entity
   331       key_name: the key_name of the entity that uniquely identifies it
   320         properties and their values
       
   321 
   332 
   322     Returns:
   333     Returns:
   323       the entity corresponding to the key_name, with any supplied
   334       the entity corresponding to the key_name, with any supplied
   324       properties changed, or a new entity now associated with the
   335       properties changed, or a new entity now associated with the
   325       supplied key_name and properties.
   336       supplied key_name and properties.
   349     """Delete existing entity from datastore.
   360     """Delete existing entity from datastore.
   350     
   361     
   351     Args:
   362     Args:
   352       entity: an existing entity in datastore
   363       entity: an existing entity in datastore
   353     """
   364     """
       
   365 
   354     entity.delete()
   366     entity.delete()
   355   
   367