]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- fixes to ShardedSession to work with deferred columns [ticket:771].
authorMike Bayer <mike_mp@zzzcomputing.com>
Sat, 8 Sep 2007 19:51:35 +0000 (19:51 +0000)
committerMike Bayer <mike_mp@zzzcomputing.com>
Sat, 8 Sep 2007 19:51:35 +0000 (19:51 +0000)
- user-defined shard_chooser() function must accept "clause=None"
  argument; this is the ClauseElement passed to session.execute(statement)
  and can be used to determine correct shard id (since execute() doesn't
  take an instance)

CHANGES
examples/sharding/attribute_shard.py
lib/sqlalchemy/orm/session.py
lib/sqlalchemy/orm/shard.py
lib/sqlalchemy/orm/strategies.py
test/orm/sharding/shard.py

diff --git a/CHANGES b/CHANGES
index 6282b9cdeeae3d162559dfcfbef2d8491515dab5..7e470d86127e5b8a041097b2a85f0f1691e24a2b 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -24,6 +24,13 @@ CHANGES
 - column defaults and onupdates, executing inline,  will add parenthesis 
   for subqueries and other parenthesis-requiring expressions
 
+- fixes to ShardedSession to work with deferred columns [ticket:771].
+
+- user-defined shard_chooser() function must accept "clause=None"
+  argument; this is the ClauseElement passed to session.execute(statement)
+  and can be used to determine correct shard id (since execute() doesn't
+  take an instance) 
+
 0.4.0beta5
 ----------
 
index 25da98872927c83db8e5bb2a6dd0a0765ed16575..0a9e992a32be70deea0a654aeaa8b8da3aba20c8 100644 (file)
@@ -22,6 +22,7 @@ from sqlalchemy import *
 from sqlalchemy.orm import *
 from sqlalchemy.orm.shard import ShardedSession
 from sqlalchemy.sql import operators
+from sqlalchemy import sql
 import datetime
 
 # step 2. databases
@@ -107,7 +108,7 @@ shard_lookup = {
 # note that we need to define conditions for 
 # the WeatherLocation class, as well as our secondary Report class which will
 # point back to its WeatherLocation via its 'location' attribute.
-def shard_chooser(mapper, instance):
+def shard_chooser(mapper, instance, clause=None):
     if isinstance(instance, WeatherLocation):
         return shard_lookup[instance.continent]
     else:
index b616570ab39ca2575751281a3b3e252b53e0a458..6f06474b72555468cd218bb0888308c6ee21ce2a 100644 (file)
@@ -488,20 +488,19 @@ class Session(object):
 
         If this ``Session`` is transactional, the connection will be in
         the context of this session's transaction.  Otherwise, the
-        connection is returned by the ``contextual_connect()`` method, which
-        some Engines override to return a thread-local connection, and
-        will have `close_with_result` set to `True`.
-
-        The given `**kwargs` will be sent to the engine's
-        ``contextual_connect()`` method, if no transaction is in
-        progress.
+        connection is returned by the ``contextual_connect()`` method
+        on the engine.
         
         the "mapper" argument is a class or mapper to which a bound engine
         will be located; use this when the Session itself is either bound
         to multiple engines or connections, or is not bound to any connectable.
+        
+        \**kwargs are additional arguments which will be passed to get_bind().
+        See the get_bind() method for details.  Note that the "ShardedSession"
+        subclass takes a different get_bind() argument signature.
         """
 
-        return self.__connection(self.get_bind(mapper))
+        return self.__connection(self.get_bind(mapper, **kwargs))
 
     def __connection(self, engine, **kwargs):
         if self.transaction is not None:
@@ -592,8 +591,23 @@ class Session(object):
 
         self.__binds[table] = bind
 
-    def get_bind(self, mapper, clause=None):
-
+    def get_bind(self, mapper, clause=None, **kwargs):
+        """return an engine corresponding to the given arguments.
+        
+            mapper
+                mapper relative to the desired operation
+            
+            clause
+                a ClauseElement which is to be executed.  if
+                mapper is not present, this may be used to locate
+                Table objects, which are then associated with mappers
+                which have associated binds.
+                
+            \**kwargs
+                Subclasses (i.e. ShardedSession) may add additional arguments 
+                to get_bind() which are passed through here.
+        """
+        
         if mapper is None and clause is None:
             if self.bind is not None:
                 return self.bind
index 752806c0ce585c98977b43e3e077bd312e8c1395..48e0579666c1fb6757327216e33240823efeb332 100644 (file)
@@ -9,11 +9,11 @@ class ShardedSession(Session):
         """construct a ShardedSession.
         
             shard_chooser
-                a callable which, passed a Mapper and a mapped instance, returns a
-                shard ID.  this id may be based off of the attributes present within the
-                object, or on some round-robin scheme.  If the scheme is based on a
-                selection, it should set whatever state on the instance to mark it in
-                the future as participating in that shard.
+                a callable which, passed a Mapper, a mapped instance, and possibly a
+                SQL clause, returns a shard ID. this id may be based off of the
+                attributes present within the object, or on some round-robin scheme. If
+                the scheme is based on a selection, it should set whatever state on the
+                instance to mark it in the future as participating in that shard.
             
             id_chooser
                 a callable, passed a query and a tuple of identity values,
@@ -47,9 +47,9 @@ class ShardedSession(Session):
         else:
             return self.get_bind(mapper, shard_id=shard_id, instance=instance).contextual_connect(**kwargs)
     
-    def get_bind(self, mapper, shard_id=None, instance=None):
+    def get_bind(self, mapper, shard_id=None, instance=None, clause=None):
         if shard_id is None:
-            shard_id = self.shard_chooser(mapper, instance)
+            shard_id = self.shard_chooser(mapper, instance, clause=clause)
         return self.__binds[shard_id]
 
     def bind_shard(self, shard_id, bind):
index 86be77ae0ef5a1d6c41faf1d6173f6b2d73c6116..1ece80616bcd9a52f5000ce72473ee144c522109 100644 (file)
@@ -196,8 +196,9 @@ class DeferredColumnLoader(LoaderStrategy):
                 statement = sql.select([p.columns[0] for p in group], clause, from_obj=[localparent.mapped_table], use_labels=True)
             else:
                 statement, params = create_statement()
-                
-            result = session.execute(statement, params, mapper=localparent)
+            
+            conn = session.connection(mapper=localparent, instance=instance)
+            result = conn.execute(statement, params)
             try:
                 row = result.fetchone()
                 for prop in group:
index e82de73ead9bfb5ba7e40d979ccf0db89f320a7f..c63a29e808c309c865293b191ab35cb10a54ca99 100644 (file)
@@ -66,7 +66,7 @@ class ShardTest(PersistTest):
             'South America':'south_america'
         }
         
-        def shard_chooser(mapper, instance):
+        def shard_chooser(mapper, instance, clause=None):
             if isinstance(instance, WeatherLocation):
                 return shard_lookup[instance.continent]
             else:
@@ -116,7 +116,8 @@ class ShardTest(PersistTest):
                 self.temperature = temperature
 
         mapper(WeatherLocation, weather_locations, properties={
-            'reports':relation(Report, backref='location')
+            'reports':relation(Report, backref='location'),
+            'city': deferred(weather_locations.c.city),
         })
 
         mapper(Report, weather_reports)