From: Mike Bayer Date: Fri, 23 Dec 2005 04:44:44 +0000 (+0000) Subject: added defer and undefer mapper options X-Git-Tag: rel_0_1_0~215 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e97211413e9282b62d9494e7bbdc1c3040dff2c4;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git added defer and undefer mapper options --- diff --git a/lib/sqlalchemy/mapping/__init__.py b/lib/sqlalchemy/mapping/__init__.py index 3217e283e1..f5d635213a 100644 --- a/lib/sqlalchemy/mapping/__init__.py +++ b/lib/sqlalchemy/mapping/__init__.py @@ -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 diff --git a/lib/sqlalchemy/mapping/properties.py b/lib/sqlalchemy/mapping/properties.py index 41236261e0..b7b59508ef 100644 --- a/lib/sqlalchemy/mapping/properties.py +++ b/lib/sqlalchemy/mapping/properties.py @@ -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): diff --git a/test/mapper.py b/test/mapper.py index a0a706c0c4..fca87518ce 100644 --- a/test/mapper.py +++ b/test/mapper.py @@ -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):