]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
re-implemented extension option
authorMike Bayer <mike_mp@zzzcomputing.com>
Sat, 21 Oct 2006 23:04:36 +0000 (23:04 +0000)
committerMike Bayer <mike_mp@zzzcomputing.com>
Sat, 21 Oct 2006 23:04:36 +0000 (23:04 +0000)
lib/sqlalchemy/orm/__init__.py
lib/sqlalchemy/orm/interfaces.py
lib/sqlalchemy/orm/mapper.py
lib/sqlalchemy/orm/query.py
lib/sqlalchemy/orm/strategies.py
test/orm/mapper.py

index c18da2005b7e699da843e704a0db19bc983cafc5..b5c590b74128b566690a55541f0ad06306a6af3e 100644 (file)
@@ -17,7 +17,7 @@ from util import polymorphic_union
 import properties, strategies
 from session import Session as create_session
 
-__all__ = ['relation', 'backref', 'eagerload', 'lazyload', 'noload', 'deferred', 'defer', 'undefer',
+__all__ = ['relation', 'backref', 'eagerload', 'lazyload', 'noload', 'deferred', 'defer', 'undefer', 'extension', 
         'mapper', 'clear_mappers', 'clear_mapper', 'sql', 'class_mapper', 'object_mapper', 'MapperExtension', 'Query', 
         'cascade_mappers', 'polymorphic_union', 'create_session', 'synonym', 'contains_eager', 'EXT_PASS'
         ]
@@ -73,6 +73,13 @@ def clear_mapper(m):
     new primary mapper."""
     del mapper_registry[m.class_key]
 
+def extension(ext):
+    """return a MapperOption that will insert the given MapperExtension to the 
+    beginning of the list of extensions that will be called in the context of the Query.
+    
+    used with query.options()."""
+    return mapperlib.ExtensionOption(ext)
+    
 def eagerload(name):
     """return a MapperOption that will convert the property of the given name
     into an eager load.  
index 8e505bac599b16c6bc58b7a09a29dec1a4147cc1..d6c4204f95bc91bce19ce8903c07a37db479b729 100644 (file)
@@ -5,7 +5,7 @@
 # the MIT License: http://www.opensource.org/licenses/mit-license.php
 
 
-from sqlalchemy import util
+from sqlalchemy import util, logging
 
 class MapperProperty(object):
     """manages the relationship of a Mapper to a single class attribute, as well
@@ -102,7 +102,9 @@ class MapperOption(object):
         pass
     def process_selection_context(self, context):
         pass
-
+    def process_query(self, query):
+        pass
+        
 class PropertyOption(MapperOption):
     """a MapperOption that is applied to a property off the mapper
     or one of its child mappers, identified by a dot-separated key."""
@@ -126,13 +128,16 @@ class PropertyOption(MapperOption):
                 mapper = getattr(prop, 'mapper', None)
             self.__prop = prop
         return prop
+PropertyOption.logger = logging.class_logger(PropertyOption)
 
 class StrategizedOption(PropertyOption):
     """a MapperOption that affects which LoaderStrategy will be used for an operation
     by a StrategizedProperty."""
     def process_query_property(self, context, property):
+        self.logger.debug("applying option to QueryContext, property key '%s'" % self.key)
         context.attributes[(LoaderStrategy, property)] = self.get_strategy_class()
     def process_selection_property(self, context, property):
+        self.logger.debug("applying option to SelectionContext, property key '%s'" % self.key)
         context.attributes[(LoaderStrategy, property)] = self.get_strategy_class()
     def get_strategy_class(self):
         raise NotImplementedError()
index 575609d3cdc6ff99d34f0a7d9084e735bdb4811b..b3dbe7a9211bccb40162e5ddb50a9dafd9111bd3 100644 (file)
@@ -1305,6 +1305,12 @@ class MapperExtension(object):
 class _ExtensionCarrier(MapperExtension):
     def __init__(self):
         self.elements = []
+    def insert(self, extension):
+        """insert a MapperExtension at the beginning of this ExtensionCarrier's list."""
+        self.elements.insert(0, extension)
+    def append(self, extension):
+        """append a MapperExtension at the end of this ExtensionCarrier's list."""
+        self.elements.append(extension)
     # TODO: shrink down this approach using __getattribute__ or similar
     def get_session(self):
         return self._do('get_session')
@@ -1334,14 +1340,19 @@ class _ExtensionCarrier(MapperExtension):
     def _do(self, funcname, *args, **kwargs):
         for elem in self.elements:
             if elem is self:
-                raise "WTF"
+                raise exceptions.AssertionError("ExtensionCarrier set to itself")
             ret = getattr(elem, funcname)(*args, **kwargs)
             if ret is not EXT_PASS:
                 return ret
         else:
             return EXT_PASS
             
-            
+class ExtensionOption(MapperExtension):
+    def __init__(self, ext):
+        self.ext = ext
+    def process_query(self, query):
+        query._insert_extension(self.ext)
+                    
 class ClassKey(object):
     """keys a class and an entity name to a mapper, via the mapper_registry."""
     __metaclass__ = util.ArgSingleton
index ea70de90afd016a1ce524baaca185671375f5929..82ed4e1a02ecf3d9d071b2a323662923e002247a 100644 (file)
@@ -14,7 +14,7 @@ __all__ = ['Query', 'QueryContext', 'SelectionContext']
 
 class Query(object):
     """encapsulates the object-fetching operations provided by Mappers."""
-    def __init__(self, class_or_mapper, session=None, entity_name=None, lockmode=None, with_options=None, **kwargs):
+    def __init__(self, class_or_mapper, session=None, entity_name=None, lockmode=None, with_options=None, extension=None, **kwargs):
         if isinstance(class_or_mapper, type):
             self.mapper = mapper.class_mapper(class_or_mapper, entity_name=entity_name)
         else:
@@ -24,7 +24,10 @@ class Query(object):
         self.always_refresh = kwargs.pop('always_refresh', self.mapper.always_refresh)
         self.order_by = kwargs.pop('order_by', self.mapper.order_by)
         self.lockmode = lockmode
-        self.extension = kwargs.pop('extension', self.mapper.extension)
+        self.extension = mapper._ExtensionCarrier()
+        if extension is not None:
+            self.extension.append(extension)
+        self.extension.append(self.mapper.extension)
         self._session = session
         if not hasattr(self.mapper, '_get_clause'):
             _get_clause = sql.and_()
@@ -32,6 +35,12 @@ class Query(object):
                 _get_clause.clauses.append(primary_key == sql.bindparam(primary_key._label, type=primary_key.type))
             self.mapper._get_clause = _get_clause
         self._get_clause = self.mapper._get_clause
+        for opt in self.with_options:
+            opt.process_query(self)
+    
+    def _insert_extension(self, ext):
+        self.extension.insert(ext)
+              
     def _get_session(self):
         if self._session is None:
             return self.mapper.get_session()
index 84512c5a93a893211cfa4335ed5e3254ccde1592..916a60d252c8bc89f44e83af5b9ca14ac0ff7f4d 100644 (file)
@@ -524,6 +524,7 @@ class EagerLazyOption(StrategizedOption):
             return EagerLoader
         elif self.lazy is None:
             return NoLoader
+EagerLazyOption.logger = logging.class_logger(EagerLazyOption)
 
 class RowDecorateOption(PropertyOption):
     def __init__(self, key, decorator=None):
@@ -531,5 +532,6 @@ class RowDecorateOption(PropertyOption):
         self.decorator = decorator
     def process_selection_property(self, context, property):
         context.attributes[(EagerLoader, property)] = self.decorator
+RowDecorateOption.logger = logging.class_logger(RowDecorateOption)
         
 
index 4a401fde835e2b4fe3f32dc7c3cada83e49bc82e..6c54a5bfbeb86461ecbf7f9dcb052be88cb140f2 100644 (file)
@@ -360,6 +360,15 @@ class MapperTest(MapperSuperTest):
         
         u = sess.query(User).get_by(uname='jack')
         self.assert_result(u.adlist, Address, *(user_address_result[0]['addresses'][1]))
+    
+    def testextensionoptions(self):
+        sess  = create_session()
+        mapper(User, users)
+        class testext(MapperExtension):
+            def select_by(self, *args, **kwargs):
+                return "HI"
+        l = sess.query(User).options(extension(testext())).select_by(x=5)
+        assert l == "HI"
         
     def testeageroptions(self):
         """tests that a lazy relation can be upgraded to an eager relation via the options method"""