]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
added order_by to EagerLoader, LazyLoader
authorMike Bayer <mike_mp@zzzcomputing.com>
Sun, 4 Dec 2005 19:41:57 +0000 (19:41 +0000)
committerMike Bayer <mike_mp@zzzcomputing.com>
Sun, 4 Dec 2005 19:41:57 +0000 (19:41 +0000)
removed "scope" parameter from Mapper until we need to revisit that idea

lib/sqlalchemy/mapping/__init__.py
lib/sqlalchemy/mapping/mapper.py
lib/sqlalchemy/mapping/properties.py
lib/sqlalchemy/util.py
test/mapper.py

index 51e859c51050ace82c3aa6560a2b5af0c4b661fb..ebc35c06b7edc67685663488d77a818d81465ac6 100644 (file)
@@ -53,10 +53,10 @@ def _relation_loader(mapper, secondary=None, primaryjoin=None, secondaryjoin=Non
 
 def _relation_mapper(class_, table=None, secondary=None, 
                     primaryjoin=None, secondaryjoin=None, 
-                    foreignkey=None, uselist=None, private=False, live=False, association=None, lazy=True, selectalias=None, **kwargs):
+                    foreignkey=None, uselist=None, private=False, live=False, association=None, lazy=True, selectalias=None, order_by=None, **kwargs):
 
     return _relation_loader(mapper(class_, table, **kwargs), secondary, primaryjoin, secondaryjoin, 
-                    foreignkey=foreignkey, uselist=uselist, private=private, live=live, association=association, lazy=lazy, selectalias=selectalias)
+                    foreignkey=foreignkey, uselist=uselist, private=private, live=live, association=association, lazy=lazy, selectalias=selectalias, order_by=order_by)
 
 class assignmapper(object):
     """provides a property object that will instantiate a Mapper for a given class the first
index 52712eff9c7cca528f64de412fd81b45395c6f76..57e7887e99a651c5815a001bef02c2082c47c3ee 100644 (file)
@@ -34,7 +34,6 @@ class Mapper(object):
                 class_, 
                 table, 
                 primarytable = None, 
-                scope = "thread", 
                 properties = None, 
                 primary_key = None, 
                 is_primary = False, 
@@ -47,7 +46,6 @@ class Mapper(object):
             'class_':class_,
             'table':table,
             'primarytable':primarytable,
-            'scope':scope,
             'properties':properties or {},
             'primary_key':primary_key,
             'is_primary':False,
@@ -62,7 +60,6 @@ class Mapper(object):
             self.extension = extension                
         self.hashkey = hashkey
         self.class_ = class_
-        self.scope = scope
         self.is_primary = is_primary
         
         if not issubclass(class_, object):
@@ -450,7 +447,6 @@ class Mapper(object):
         statement.use_labels = True
         return statement
 
-
     def _identity_key(self, row):
         return objectstore.get_row_key(row, self.class_, self.primarytable, self.pks_by_table[self.table])
 
@@ -503,7 +499,6 @@ class Mapper(object):
             instance = imap[identitykey]
             isnew = False
 
-
         # plugin point
         
         # call further mapper properties on the row, to pull further 
@@ -517,7 +512,6 @@ class Mapper(object):
             
         return instance
 
-        
 class MapperProperty(object):
     """an element attached to a Mapper that describes and assists in the loading and saving 
     of an attribute on an object instance."""
@@ -590,21 +584,22 @@ class TableFinder(sql.ClauseVisitor):
 def hash_key(obj):
     if obj is None:
         return 'None'
+    elif isinstance(obj, list):
+        return repr([hash_key(o) for o in obj])
     elif hasattr(obj, 'hash_key'):
         return obj.hash_key()
     else:
         return repr(obj)
 
-def mapper_hash_key(class_, table, primarytable = None, properties = None, scope = "thread", **kwargs):
+def mapper_hash_key(class_, table, primarytable = None, properties = None, **kwargs):
     if properties is None:
         properties = {}
     return (
-        "Mapper(%s, %s, primarytable=%s, properties=%s, scope=%s)" % (
+        "Mapper(%s, %s, primarytable=%s, properties=%s)" % (
             repr(class_),
             hash_key(table),
             hash_key(primarytable),
-            repr(dict([(k, hash_key(p)) for k,p in properties.iteritems()])),
-            scope        
+            repr(dict([(k, hash_key(p)) for k,p in properties.iteritems()]))
         )
     )
 
index 00b34762d6f61f017d746b2e28f40887d508c26d..fdce0c0e88edab984a4026399cd55d49a2f9849e 100644 (file)
@@ -62,7 +62,7 @@ class PropertyLoader(MapperProperty):
 
     """describes an object property that holds a single item or list of items that correspond
     to a related database table."""
-    def __init__(self, argument, secondary, primaryjoin, secondaryjoin, foreignkey=None, uselist=None, private=False, live=False, isoption=False, association=None, selectalias=None, **kwargs):
+    def __init__(self, argument, secondary, primaryjoin, secondaryjoin, foreignkey=None, uselist=None, private=False, live=False, isoption=False, association=None, selectalias=None, order_by=None, **kwargs):
         self.uselist = uselist
         self.argument = argument
         self.secondary = secondary
@@ -74,7 +74,8 @@ class PropertyLoader(MapperProperty):
         self.isoption = isoption
         self.association = association
         self.selectalias = selectalias
-        self._hash_key = "%s(%s, %s, %s, %s, %s, %s, %s)" % (self.__class__.__name__, hash_key(self.argument), hash_key(secondary), hash_key(primaryjoin), hash_key(secondaryjoin), hash_key(foreignkey), repr(uselist), repr(private))
+        self.order_by=util.to_list(order_by)
+        self._hash_key = "%s(%s, %s, %s, %s, %s, %s, %s, %s)" % (self.__class__.__name__, hash_key(self.argument), hash_key(secondary), hash_key(primaryjoin), hash_key(secondaryjoin), hash_key(foreignkey), repr(uselist), repr(private), hash_key(self.order_by))
 
     def _copy(self):
         return self.__class__(self.mapper, self.secondary, self.primaryjoin, self.secondaryjoin, self.foreignkey, self.uselist, self.private)
@@ -466,7 +467,9 @@ class LazyLoader(PropertyLoader):
                     allparams = False
                     break
             if allparams:
-                if self.secondary is not None:
+                if self.order_by is not None:
+                    order_by = self.order_by
+                elif self.secondary is not None:
                     order_by = [self.secondary.rowid_column]
                 else:
                     order_by = []
@@ -577,11 +580,16 @@ class EagerLoader(PropertyLoader):
 
         if self.secondaryjoin is not None:
             statement._outerjoin = sql.outerjoin(towrap, self.secondary, self.primaryjoin).outerjoin(self.eagertarget, self.eagersecondary)
-            statement.order_by(self.secondary.rowid_column)
+            if self.order_by is None:
+                statement.order_by(self.secondary.rowid_column)
         else:
             statement._outerjoin = towrap.outerjoin(self.eagertarget, self.eagerprimary)
-            statement.order_by(self.eagertarget.rowid_column)
+            if self.order_by is None:
+                statement.order_by(self.eagertarget.rowid_column)
 
+        if self.order_by is not None:
+            statement.order_by(*[self.eagertarget.get_col_by_original(c) for c in self.order_by])
+            
         statement.append_from(statement._outerjoin)
         statement.append_column(self.eagertarget)
         recursion_stack[self] = True
index 842d9ab3206a2e4e5f8f72610c84c3cd7ef3b542..c5ac8b979ae352e97845985348dd254100aae0ce 100644 (file)
 __all__ = ['OrderedProperties', 'OrderedDict']
 import thread, weakref, UserList,string
 
+def to_list(x):
+    if x is None:
+        return None
+    if not isinstance(x, list) and not isinstance(x, tuple):
+        return [x]
+        
 class OrderedProperties(object):
     """an object that maintains the order in which attributes are set upon it.
     also provides an iterator and a very basic dictionary interface to those attributes.
index 54284f0c0de9ae8d7e1b3727646711c9cddbe00d..a0b34d172069f913c2930add7834ca38ea14b752 100644 (file)
@@ -120,6 +120,23 @@ class LazyTest(MapperSuperTest):
             {'user_id' : 7, 'addresses' : (Address, [{'address_id' : 1}])},
             )
 
+    def testorderby(self):
+        m = mapper(Address, addresses)
+
+        m = mapper(User, users, properties = dict(
+            addresses = relation(m, lazy = True, order_by=addresses.c.email_address),
+        ))
+        l = m.select()
+        dict(address_id = 1, user_id = 7, email_address = "jack@bean.com"),
+        dict(address_id = 2, user_id = 8, email_address = "ed@wood.com"),
+        dict(address_id = 3, user_id = 8, email_address = "ed@lala.com")
+
+        self.assert_result(l, User,
+            {'user_id' : 7, 'addresses' : (Address, [{'email_address' : 'jack@bean.com'}])},
+            {'user_id' : 8, 'addresses' : (Address, [{'email_address':'ed@lala.com'}, {'email_address':'ed@wood.com'}])},
+            {'user_id' : 9, 'addresses' : (Address, [])}
+            )
+
     def testonetoone(self):
         m = mapper(User, users, properties = dict(
             address = relation(Address, addresses, lazy = True, uselist = False)
@@ -204,6 +221,23 @@ class EagerTest(MapperSuperTest):
             {'user_id' : 9, 'addresses' : (Address, [])}
             )
 
+    def testorderby(self):
+        m = mapper(Address, addresses)
+        
+        m = mapper(User, users, properties = dict(
+            addresses = relation(m, lazy = False, order_by=addresses.c.email_address),
+        ))
+        l = m.select()
+        dict(address_id = 1, user_id = 7, email_address = "jack@bean.com"),
+        dict(address_id = 2, user_id = 8, email_address = "ed@wood.com"),
+        dict(address_id = 3, user_id = 8, email_address = "ed@lala.com")
+        
+        self.assert_result(l, User,
+            {'user_id' : 7, 'addresses' : (Address, [{'email_address' : 'jack@bean.com'}])},
+            {'user_id' : 8, 'addresses' : (Address, [{'email_address':'ed@lala.com'}, {'email_address':'ed@wood.com'}])},
+            {'user_id' : 9, 'addresses' : (Address, [])}
+            )
+        
     def testonetoone(self):
         m = mapper(User, users, properties = dict(
             address = relation(Address, addresses, lazy = False, uselist = False)