Show
Ignore:
Timestamp:
10/23/07 11:41:22 (5 years ago)
Author:
ged
Message:

- migrate to attribute-based syntax in all examples and documentation.
- completed doc

Files:
1 modified

Legend:

Unmodified
Added
Removed
  • elixir/trunk/elixir/properties.py

    r223 r236  
    11''' 
    2 Special properties statements for Elixir entities 
    3  
    4 ========== 
    5 Properties 
    6 ========== 
    7  
    8 This module contains DSL statements which allow you to declare special  
    9 properties your Elixir entities might have.  For simple fields or  
    10 relationships between your entities, please see the corresponding modules. 
     2This module provides support for defining properties on your entities. It both 
     3provides, the `Property` class which acts as a building block for common  
     4properties such as fields and relationships (for those, please consult the  
     5corresponding modules), but also provides some more specialized properties,  
     6such as `ColumnProperty`. It also provides the GenericProperty class which allows you to wrap any SQLAlchemy property, and its DSL-syntax equivalent:  
     7has_property_. 
    118 
    129`has_property` 
    1310-------------- 
    14 The `has_property` statement allows you to define properties which rely on  
    15 their entity's table and columns (an thus which need them to be defined before 
    16 the property can be declared). 
     11The ``has_property`` statement allows you to define properties which rely on  
     12their entity's table (and columns) being defined before they can be declared 
     13themselves. The `has_property` statement takes two arguments: first the name of 
     14the property to be defined and second a function (often given as an anonymous 
     15lambda) taking one argument and returning the desired SQLAlchemy property. That 
     16function will be called whenever the entity table is completely defined, and 
     17will be given the .c attribute of the entity as argument (as a way to access  
     18the entity columns). 
    1719 
    1820Here is a quick example of how to use ``has_property``. 
     
    3133from sqlalchemy.orm import column_property 
    3234 
     35__doc_all__ = ['EntityBuilder', 'Property', 'GenericProperty',  
     36               'ColumnProperty'] 
    3337 
    3438class EntityBuilder(object): 
     39    ''' 
     40    Abstract base class for all entity builders. An Entity builder is a class  
     41    of objects which can be added to an Entity (usually by using special  
     42    properties or statements) to "build" that entity. Building an entity, 
     43    meaning to add columns to its "main" table, create other tables, add 
     44    properties to its mapper, ... To do so an EntityBuilder must override the 
     45    corresponding method(s). This is to ensure the different operations happen 
     46    in the correct order (for example, that the table is fully created before 
     47    the mapper that use it is defined). 
     48    ''' 
     49     
    3550    #TODO: add stub methods (create_cols, etc...) 
    3651    #XXX: add helper methods: add_property, etc... here? 
     
    3954 
    4055 
    41 class PropertyMeta(type): 
     56class CounterMeta(type): 
     57    ''' 
     58    A simple meta class which adds a ``_counter`` attribute to the instances of 
     59    the classes it is used on. This counter is simply incremented for each new 
     60    instance. 
     61    ''' 
    4262    counter = 0 
    4363 
    4464    def __call__(self, *args, **kwargs): 
    4565        instance = type.__call__(self, *args, **kwargs) 
    46         instance._counter = PropertyMeta.counter 
    47         PropertyMeta.counter += 1 
     66        instance._counter = CounterMeta.counter 
     67        CounterMeta.counter += 1 
    4868        return instance 
    4969 
    5070 
    5171class Property(EntityBuilder): 
    52     __metaclass__ = PropertyMeta 
     72    ''' 
     73    Abstract base class for all properties of an Entity. 
     74    ''' 
     75    __metaclass__ = CounterMeta 
    5376     
    5477    def __init__(self, *args, **kwargs): 
     
    5982        """Attach this property to its entity, using 'name' as name. 
    6083 
    61         Note that properties will not necessarily be attached in the order  
    62         they were declared. 
     84        Properties will be attached in the order they were declared. 
    6385        """ 
    6486        self.entity = entity 
     
    7395 
    7496class GenericProperty(Property): 
     97    ''' 
     98    Generic catch-all class to wrap an SQLAlchemy property. 
     99    ''' 
     100     
    75101    def __init__(self, prop): 
    76102        super(GenericProperty, self).__init__() 
     
    89115 
    90116class ColumnProperty(GenericProperty): 
     117    ''' 
     118    A specialized form of the GenericProperty to generate SQLAlchemy  
     119    ``column_property``'s.  
     120     
     121    It takes a single argument, which is a function (often  
     122    given as an anonymous lambda) taking one argument and returning the  
     123    desired (scalar-returning) SQLAlchemy ClauseElement. That function will be 
     124    called whenever the entity table is completely defined, and will be given  
     125    the .c attribute of the entity as argument (as a way to access the entity  
     126    columns). The ColumnProperty will first wrap your ClauseElement in a label 
     127    with the same name as the property, then wrap that in a column_property. 
     128 
     129    .. sourcecode:: python 
     130 
     131        class OrderLine(Entity): 
     132            quantity = Field(Float) 
     133            unit_price = Field(Numeric) 
     134            price = ColumnProperty(lambda c: c.quantity * c.unit_price) 
     135 
     136    Please look at the `corresponding SQLAlchemy  
     137    documentation <http://www.sqlalchemy.org/docs/04/mappers.html 
     138    #advdatamapping_mapper_expressions>`_ for details. 
     139    ''' 
     140 
    91141    def evaluate_property(self, prop): 
    92142        return column_property(prop.label(self.name))