Show
Ignore:
Timestamp:
09/24/07 15:41:42 (6 years ago)
Author:
ged
Message:
  • moved away from assign_mapper, now all assign_mapper-provided methods are on
    the Entity class. Now, if people don't like them, they have the option to
    simply provide another base class.
  • migrated from ".query()" and ".q" to ".query" syntax
  • added support for "manual session management" (ie you can now define an
    entity with "using_options(session=None)" and it won't use any
    SessionContext extension, nor receive the "query" attribute.
  • fixed TG issue (which uses activemapper's objectstore with Elixir!)
  • default objectstore is now a ScopedSession if working on SA 0.4. Ie it's
    not wrapped in an Objectstore object at all. This means, that depending on
    the version of SA you are using, you'll get a slightly different behavior.
  • fixed versioning extension (but I'm not sure what I've done to fix it --
    probably the session code)
  • made the versioning extension slightly faster (limit 1 on query and do not
    recompute the whole colvalues several times for the same update)
  • probably made the versioning extension work with manual sessions too
    (though this is untested)
  • dropped support for the old threadlocal SA extension (which doesn't even exist
    anymore in SA 0.4)
  • updated TODO file
  • cleaned test_multi
Files:
1 modified

Legend:

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

    r209 r210  
    77from sqlalchemy                     import Table, Integer, String, desc,\ 
    88                                           ForeignKey, and_ 
    9 from sqlalchemy.orm                 import deferred, Query, MapperExtension 
    10 from sqlalchemy.ext.assignmapper    import assign_mapper 
     9from sqlalchemy.orm                 import deferred, Query, MapperExtension,\ 
     10                                           mapper, object_session 
    1111from sqlalchemy.ext.sessioncontext  import SessionContext 
    1212from sqlalchemy.util                import OrderedDict 
     
    1515from elixir.fields                  import Field 
    1616from elixir.options                 import options_defaults 
     17 
    1718 
    1819try: 
     
    3536DEFAULT_POLYMORPHIC_COL_SIZE = 40 
    3637DEFAULT_POLYMORPHIC_COL_TYPE = String(DEFAULT_POLYMORPHIC_COL_SIZE) 
     38 
     39try:  
     40    from sqlalchemy.orm import ScopedSession 
     41except ImportError:  
     42    # Not on sqlalchemy version 0.4 
     43    ScopedSession = type(None) 
     44     
     45def _do_mapping(session, cls, *args, **kwargs): 
     46    if session is None: 
     47        return mapper(cls, *args, **kwargs) 
     48    elif isinstance(session, ScopedSession): 
     49        return session.mapper(cls, *args, **kwargs) 
     50    elif isinstance(session, SessionContext): 
     51        extension = kwargs.pop('extension', None) 
     52        if extension is not None: 
     53            if not isinstance(extension, list): 
     54                extension = [extension] 
     55            extension.append(session.mapper_extension) 
     56        else: 
     57            extension = session.mapper_extension 
     58 
     59        class query(object): 
     60            def __getattr__(s, key): 
     61                return getattr(session.registry().query(cls), key) 
     62            def __call__(s): 
     63                return session.registry().query(cls) 
     64 
     65        if not 'query' in cls.__dict__:  
     66            cls.query = query() 
     67 
     68        return mapper(cls, extension=extension, *args, **kwargs) 
    3769 
    3870class EntityDescriptor(object): 
     
    72104        self.table_args = list() 
    73105        self.metadata = getattr(self.module, 'metadata', elixir.metadata) 
     106        self.session = getattr(self.module, 'session', elixir.session) 
    74107 
    75108        for option in ('inheritance', 'polymorphic', 
    76109                       'autoload', 'tablename', 'shortnames',  
    77                        'auto_primarykey', 
    78                        'version_id_col'): 
     110                       'auto_primarykey', 'version_id_col'): 
    79111            setattr(self, option, options_defaults[option]) 
    80112 
    81113        for option_dict in ('mapper_options', 'table_options'): 
    82114            setattr(self, option_dict, options_defaults[option_dict].copy()) 
    83     
     115  
    84116    def setup_options(self): 
    85117        ''' 
     
    88120        ''' 
    89121        elixir.metadatas.add(self.metadata) 
     122 
     123        objectstore = None 
     124        session = self.session 
     125        if session is None or isinstance(session, ScopedSession): 
     126            # no stinking objectstore 
     127            pass 
     128        elif isinstance(session, SessionContext): 
     129            objectstore = Objectstore(session) 
     130        elif not hasattr(session, 'registry'): 
     131            # Both SessionContext and ScopedSession have a registry attribute, 
     132            # but objectstores (whether Elixir's or Activemapper's) don't, so  
     133            # if we are here, it means an Objectstore is used for the session. 
     134            objectstore = session 
     135            session = objectstore.context 
     136 
     137        self.session = session 
     138        self.objectstore = objectstore 
    90139 
    91140        entity = self.entity 
     
    286335        if self.entity.mapper: 
    287336            return 
    288          
    289         # look for a 'session' attribute assigned to the entity 
    290         # (or entity's base class) 
    291         session = getattr(self, 'session', None) 
    292         if session is None: 
    293             session = getattr(self.module, 'session', elixir.objectstore) 
    294         if not isinstance(session, Objectstore): 
    295             session = Objectstore(session) 
    296              
    297         self.objectstore = session 
    298337         
    299338        kwargs = self.mapper_options 
     
    362401            args = [self.entity.table] 
    363402 
    364         self.objectstore.mapper(self.entity, properties=properties,  
    365                                 *args, **kwargs) 
     403        self.entity.mapper = _do_mapping(self.session, self.entity,  
     404                                         properties=properties, 
     405                                         *args, **kwargs) 
    366406 
    367407    def after_mapper(self): 
     
    605645        return type.__call__(cls, *args, **kwargs) 
    606646 
    607     def q(cls): 
    608         return Query(cls, session=cls._descriptor.objectstore.session) 
    609     q = property(q) 
    610647 
    611648 
     
    638675            setattr(self, key, value) 
    639676 
     677    # session methods 
     678    def flush(self, *args, **kwargs): 
     679        return object_session(self).flush([self], *args, **kwargs) 
     680 
     681    def delete(self, *args, **kwargs): 
     682        return object_session(self).delete(self, *args, **kwargs) 
     683 
     684    def expire(self, *args, **kwargs): 
     685        return object_session(self).expire(self, *args, **kwargs) 
     686 
     687    def refresh(self, *args, **kwargs): 
     688        return object_session(self).refresh(self, *args, **kwargs) 
     689 
     690    def expunge(self, *args, **kwargs): 
     691        return object_session(self).expunge(self, *args, **kwargs) 
     692 
     693    # This bunch of session methods, along with all the query methods below  
     694    # only make sense when using a global/scoped/contextual session. 
     695    def _global_session(self): 
     696        return self._descriptor.session.registry() 
     697    _global_session = property(_global_session) 
     698 
     699    def merge(self, *args, **kwargs): 
     700        return self._global_session.merge(self, *args, **kwargs) 
     701 
     702    def save(self, *args, **kwargs): 
     703        return self._global_session.save(self, *args, **kwargs) 
     704 
     705    def update(self, *args, **kwargs): 
     706        return self._global_session.update(self, *args, **kwargs) 
     707 
     708    def save_or_update(self, *args, **kwargs): 
     709        return self._global_session.save_or_update(self, *args, **kwargs) 
     710 
     711    # query methods 
    640712    def get_by(cls, *args, **kwargs): 
    641         return cls.query().filter_by(*args, **kwargs).first() 
     713        return cls.query.filter_by(*args, **kwargs).first() 
    642714    get_by = classmethod(get_by) 
    643715 
    644  
    645716    def get(cls, *args, **kwargs): 
    646         return cls.query().get(*args, **kwargs) 
     717        return cls.query.get(*args, **kwargs) 
    647718    get = classmethod(get) 
    648719 
    649  
    650     # DEPRECATED LAND 
     720    #-----------------# 
     721    # DEPRECATED LAND # 
     722    #-----------------# 
     723 
     724    def filter(cls, *args, **kwargs): 
     725        warnings.warn("The filter method on the class is deprecated." 
     726                      "You should use cls.query.filter(...)",  
     727                      DeprecationWarning, stacklevel=2) 
     728        return cls.query.filter(*args, **kwargs) 
     729    filter = classmethod(filter) 
     730 
     731    def filter_by(cls, *args, **kwargs): 
     732        warnings.warn("The filter_by method on the class is deprecated." 
     733                      "You should use cls.query.filter_by(...)",  
     734                      DeprecationWarning, stacklevel=2) 
     735        return cls.query.filter_by(*args, **kwargs) 
     736    filter_by = classmethod(filter_by) 
     737 
    651738    def select(cls, *args, **kwargs): 
    652739        warnings.warn("The select method on the class is deprecated." 
    653                       "You should use cls.query.filter(...).all()", DeprecationWarning, 
    654                       stacklevel=2) 
    655         return cls.query().filter(*args, **kwargs).all() 
     740                      "You should use cls.query.filter(...).all()",  
     741                      DeprecationWarning, stacklevel=2) 
     742        return cls.query.filter(*args, **kwargs).all() 
    656743    select = classmethod(select) 
     744 
     745    def select_by(cls, *args, **kwargs): 
     746        warnings.warn("The select_by method on the class is deprecated." 
     747                      "You should use cls.query.filter_by(...).all()",  
     748                      DeprecationWarning, stacklevel=2) 
     749        return cls.query.filter_by(*args, **kwargs).all() 
     750    select_by = classmethod(select_by) 
     751 
     752    def selectfirst(cls, *args, **kwargs): 
     753        warnings.warn("The selectfirst method on the class is deprecated." 
     754                      "You should use cls.query.filter(...).first()",  
     755                      DeprecationWarning, stacklevel=2) 
     756        return cls.query.filter(*args, **kwargs).first() 
     757    selectfirst = classmethod(selectfirst) 
     758 
     759    def selectfirst_by(cls, *args, **kwargs): 
     760        warnings.warn("The selectfirst_by method on the class is deprecated." 
     761                      "You should use cls.query.filter_by(...).first()",  
     762                      DeprecationWarning, stacklevel=2) 
     763        return cls.query.filter_by(*args, **kwargs).first() 
     764    selectfirst_by = classmethod(selectfirst_by) 
     765 
     766    def selectone(cls, *args, **kwargs): 
     767        warnings.warn("The selectone method on the class is deprecated." 
     768                      "You should use cls.query.filter(...).one()",  
     769                      DeprecationWarning, stacklevel=2) 
     770        return cls.query.filter(*args, **kwargs).one() 
     771    selectone = classmethod(selectone) 
     772 
     773    def selectone_by(cls, *args, **kwargs): 
     774        warnings.warn("The selectone_by method on the class is deprecated." 
     775                      "You should use cls.query.filter_by(...).one()",  
     776                      DeprecationWarning, stacklevel=2) 
     777        return cls.query.filter_by(*args, **kwargs).one() 
     778    selectone_by = classmethod(selectone_by) 
     779 
     780    def join_to(cls, *args, **kwargs): 
     781        warnings.warn("The join_to method on the class is deprecated." 
     782                      "You should use cls.query.join(...)",  
     783                      DeprecationWarning, stacklevel=2) 
     784        return cls.query.join_to(*args, **kwargs).all() 
     785    join_to = classmethod(join_to) 
     786 
     787    def join_via(cls, *args, **kwargs): 
     788        warnings.warn("The join_via method on the class is deprecated." 
     789                      "You should use cls.query.join(...)",  
     790                      DeprecationWarning, stacklevel=2) 
     791        return cls.query.join_via(*args, **kwargs).all() 
     792    join_via = classmethod(join_via) 
     793 
     794    def count(cls, *args, **kwargs): 
     795        warnings.warn("The count method on the class is deprecated." 
     796                      "You should use cls.query.filter(...).count()",  
     797                      DeprecationWarning, stacklevel=2) 
     798        return cls.query.filter(*args, **kwargs).count() 
     799    count = classmethod(count) 
     800 
     801    def count_by(cls, *args, **kwargs): 
     802        warnings.warn("The count_by method on the class is deprecated." 
     803                      "You should use cls.query.filter_by(...).count()",  
     804                      DeprecationWarning, stacklevel=2) 
     805        return cls.query.filter_by(*args, **kwargs).count() 
     806    count_by = classmethod(count_by) 
     807 
     808    def options(cls, *args, **kwargs): 
     809        warnings.warn("The options method on the class is deprecated." 
     810                      "You should use cls.query.options(...)",  
     811                      DeprecationWarning, stacklevel=2) 
     812        return cls.query.options(*args, **kwargs) 
     813    options = classmethod(options) 
     814 
     815    def instances(cls, *args, **kwargs): 
     816        warnings.warn("The instances method on the class is deprecated." 
     817                      "You should use cls.query.instances(...)",  
     818                      DeprecationWarning, stacklevel=2) 
     819        return cls.query.instances(*args, **kwargs) 
     820    instances = classmethod(instances) 
     821 
    657822 
    658823 
     
    668833    def __init__(self, ctx): 
    669834        self.context = ctx 
    670         self.is_ctx = isinstance(ctx, SessionContext) 
    671835 
    672836    def __getattr__(self, name): 
    673837        return getattr(self.context.registry(), name) 
    674838     
    675     def mapper(self, cls, *args, **kwargs): 
    676         if self.is_ctx: 
    677             assign_mapper(self.context, cls, *args, **kwargs) 
    678         else: 
    679             cls.mapper = self.context.mapper(cls, *args, **kwargs) 
    680          
    681839    session = property(lambda s:s.context.registry()) 
    682840