summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES7
-rw-r--r--examples/sharding/attribute_shard.py3
-rw-r--r--lib/sqlalchemy/orm/session.py34
-rw-r--r--lib/sqlalchemy/orm/shard.py14
-rw-r--r--lib/sqlalchemy/orm/strategies.py5
-rw-r--r--test/orm/sharding/shard.py5
6 files changed, 46 insertions, 22 deletions
diff --git a/CHANGES b/CHANGES
index 6282b9cde..7e470d861 100644
--- 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
----------
diff --git a/examples/sharding/attribute_shard.py b/examples/sharding/attribute_shard.py
index 25da98872..0a9e992a3 100644
--- a/examples/sharding/attribute_shard.py
+++ b/examples/sharding/attribute_shard.py
@@ -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:
diff --git a/lib/sqlalchemy/orm/session.py b/lib/sqlalchemy/orm/session.py
index b616570ab..6f06474b7 100644
--- a/lib/sqlalchemy/orm/session.py
+++ b/lib/sqlalchemy/orm/session.py
@@ -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
diff --git a/lib/sqlalchemy/orm/shard.py b/lib/sqlalchemy/orm/shard.py
index 752806c0c..48e057966 100644
--- a/lib/sqlalchemy/orm/shard.py
+++ b/lib/sqlalchemy/orm/shard.py
@@ -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):
diff --git a/lib/sqlalchemy/orm/strategies.py b/lib/sqlalchemy/orm/strategies.py
index 86be77ae0..1ece80616 100644
--- a/lib/sqlalchemy/orm/strategies.py
+++ b/lib/sqlalchemy/orm/strategies.py
@@ -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:
diff --git a/test/orm/sharding/shard.py b/test/orm/sharding/shard.py
index e82de73ea..c63a29e80 100644
--- a/test/orm/sharding/shard.py
+++ b/test/orm/sharding/shard.py
@@ -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)