]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
added defer and undefer mapper options
authorMike Bayer <mike_mp@zzzcomputing.com>
Fri, 23 Dec 2005 04:44:44 +0000 (04:44 +0000)
committerMike Bayer <mike_mp@zzzcomputing.com>
Fri, 23 Dec 2005 04:44:44 +0000 (04:44 +0000)
lib/sqlalchemy/mapping/__init__.py
lib/sqlalchemy/mapping/properties.py
test/mapper.py

index 3217e283e17726be0d4e77796b0fd286f03061d8..f5d635213a12fd578c96dd6cd02a33ab63a580e8 100644 (file)
@@ -29,6 +29,7 @@ from properties import *
 import mapper as mapperlib
 
 __all__ = ['relation', 'eagerload', 'lazyload', 'noload', 'deferred', 'assignmapper', 'column', 'deferred',
+        'defer', 'undefer',
         'mapper', 'clear_mappers', 'objectstore', 'sql', 'extension', 'class_mapper', 'object_mapper', 'MapperExtension',
         'ColumnProperty', 'assign_mapper'
         ]
@@ -137,6 +138,15 @@ def noload(name, **kwargs):
     """returns a MapperOption that will convert the property of the given name
     into a non-load.  Used with mapper.options()"""
     return EagerLazyOption(name, toeager=None, **kwargs)
+
+def defer(name, **kwargs):
+    """returns a MapperOption that will convert the column property of the given 
+    name into a deferred load.  Used with mapper.options()"""
+    return DeferredOption(name, defer=True)
+def undefer(name, **kwargs):
+    """returns a MapperOption that will convert the column property of the given
+    name into a non-deferred (regular column) load.  Used with mapper.options."""
+    return DeferredOption(name, defer=False)
     
 def object_mapper(object):
     """given an object, returns the primary Mapper associated with the object
index 41236261e0859378c803972638f05a34d8639b18..b7b59508ef0c2b034b473099ea00b17159a333a3 100644 (file)
@@ -87,7 +87,7 @@ class DeferredColumnProperty(ColumnProperty):
             
             if self.group is not None:
                 groupcols = [p for p in self.parent.props.values() if isinstance(p, DeferredColumnProperty) and p.group==self.group]
-                row = sql.select([g.columns[0] for g in groupcols], clause).execute().fetchone()
+                row = sql.select([g.columns[0] for g in groupcols], clause, use_labels=True).execute().fetchone()
                 for prop in groupcols:
                     if prop is self:
                         continue
@@ -95,7 +95,7 @@ class DeferredColumnProperty(ColumnProperty):
                     objectstore.global_attributes.create_history(instance, prop.key, uselist=False)
                 return row[self.columns[0]]    
             else:
-                return sql.select([self.columns[0]], clause).scalar()
+                return sql.select([self.columns[0]], clause, use_labels=True).scalar()
         return lazyload
 
     def _is_primary(self):
@@ -819,6 +819,21 @@ class EagerLazyOption(GenericOption):
         kwargs = util.constructor_args(mapper.props[key], **self.kwargs)
         mapper.set_property(key, class_(**kwargs ))
 
+class DeferredOption(GenericOption):
+    def __init__(self, key, defer=False, **kwargs):
+        self.key = key
+        self.defer = defer
+        self.kwargs = kwargs
+    def hash_key(self):
+        return "DeferredOption(%s,%s)" % (self.key, self.defer)
+    def create_prop(self, mapper, key):
+        oldprop = mapper.props[key]
+        if self.defer:
+            prop = DeferredColumnProperty(*oldprop.columns, **self.kwargs)
+        else:
+            prop = ColumnProperty(*oldprop.columns, **self.kwargs)
+        mapper.set_property(key, prop)
+        
 class Aliasizer(sql.ClauseVisitor):
     """converts a table instance within an expression to be an alias of that table."""
     def __init__(self, *tables, **kwargs):
index a0a706c0c4bf8b925763e5540b2e8721ecb12f12..fca87518ce107433a3143522f07ce51c35d07df0 100644 (file)
@@ -127,7 +127,6 @@ class MapperTest(MapperSuperTest):
         m = mapper(User, users, properties = dict(
             addresses = relation(Address, addresses, lazy = True)
         ))
-#        l = m.select()
         l = m.options(eagerload('addresses')).select()
 
         def go():
@@ -217,7 +216,7 @@ class DeferredTest(MapperSuperTest):
 
         self.assert_sql(db, go, [
             ("SELECT orders.order_id AS orders_order_id, orders.user_id AS orders_user_id, orders.isopen AS orders_isopen FROM orders ORDER BY orders.oid", {}),
-            ("SELECT orders.description FROM orders WHERE orders.order_id = :orders_order_id", {'orders_order_id':3})
+            ("SELECT orders.description AS orders_description FROM orders WHERE orders.order_id = :orders_order_id", {'orders_order_id':3})
         ])
         
     def testgroup(self):
@@ -235,9 +234,54 @@ class DeferredTest(MapperSuperTest):
             print o2.opened, o2.description, o2.userident
         self.assert_sql(db, go, [
             ("SELECT orders.order_id AS orders_order_id FROM orders ORDER BY orders.oid", {}),
-            ("SELECT orders.user_id, orders.description, orders.isopen FROM orders WHERE orders.order_id = :orders_order_id", {'orders_order_id':3})
+            ("SELECT orders.user_id AS orders_user_id, orders.description AS orders_description, orders.isopen AS orders_isopen FROM orders WHERE orders.order_id = :orders_order_id", {'orders_order_id':3})
         ])
         
+    def testoptions(self):
+        """tests using options on a mapper to create deferred and undeferred columns"""
+        m = mapper(Order, orders)
+        m2 = m.options(defer('user_id'))
+        def go():
+            l = m2.select()
+            print l[2].user_id
+        self.assert_sql(db, go, [
+            ("SELECT orders.order_id AS orders_order_id, orders.description AS orders_description, orders.isopen AS orders_isopen FROM orders ORDER BY orders.oid", {}),
+            ("SELECT orders.user_id AS orders_user_id FROM orders WHERE orders.order_id = :orders_order_id", {'orders_order_id':3})
+        ])
+        objectstore.clear()
+        m3 = m2.options(undefer('user_id'))
+        print m3.hashkey
+        def go():
+            l = m3.select()
+            print l[3].user_id
+        self.assert_sql(db, go, [
+            ("SELECT orders.order_id AS orders_order_id, orders.user_id AS orders_user_id, orders.description AS orders_description, orders.isopen AS orders_isopen FROM orders ORDER BY orders.oid", {}),
+        ])
+
+    def testdeepoptions(self):
+        m = mapper(User, users, properties={
+            'orders':relation(Order, orders, properties={
+                'items':relation(Item, orderitems, properties={
+                    'item_name':deferred(orderitems.c.item_name)
+                })
+            })
+        })
+        l = m.select()
+        item = l[0].orders[1].items[1]
+        def go():
+            print item.item_name
+        self.assert_sql_count(db, go, 1)
+        self.assert_(item.item_name == 'item 4')
+        objectstore.clear()
+        m2 = m.options(undefer('orders.items.item_name'))
+        l = m2.select()
+        item = l[0].orders[1].items[1]
+        def go():
+            print item.item_name
+        self.assert_sql_count(db, go, 0)
+        self.assert_(item.item_name == 'item 4')
+    
+    
 class LazyTest(MapperSuperTest):
 
     def testbasic(self):