summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2012-10-15 20:07:13 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2012-10-15 20:07:13 -0400
commit2484ef34c27f3342e62bd6285bb3668e2c913090 (patch)
treee7e329fb3e06e903c793f6944a1facd72b0bd4ef /test
parentaf3c8a75c8e9eba593f6568187226548f1b8735d (diff)
downloadsqlalchemy-2484ef34c27f3342e62bd6285bb3668e2c913090.tar.gz
- [feature] The Query can now load entity/scalar-mixed
"tuple" rows that contain types which aren't hashable, by setting the flag "hashable=False" on the corresponding TypeEngine object in use. Custom types that return unhashable types (typically lists) can set this flag to False. [ticket:2592] - [bug] Applying a column expression to a select statement using a label with or without other modifying constructs will no longer "target" that expression to the underlying Column; this affects ORM operations that rely upon Column targeting in order to retrieve results. That is, a query like query(User.id, User.id.label('foo')) will now track the value of each "User.id" expression separately instead of munging them together. It is not expected that any users will be impacted by this; however, a usage that uses select() in conjunction with query.from_statement() and attempts to load fully composed ORM entities may not function as expected if the select() named Column objects with arbitrary .label() names, as these will no longer target to the Column objects mapped by that entity. [ticket:2591]
Diffstat (limited to 'test')
-rw-r--r--test/orm/test_query.py28
-rw-r--r--test/sql/test_compiler.py18
-rw-r--r--test/sql/test_query.py15
-rw-r--r--test/sql/test_type_expressions.py2
4 files changed, 57 insertions, 6 deletions
diff --git a/test/orm/test_query.py b/test/orm/test_query.py
index 11d86a5f0..137fdcd95 100644
--- a/test/orm/test_query.py
+++ b/test/orm/test_query.py
@@ -51,12 +51,12 @@ class RowTupleTest(QueryTest):
User, users = self.classes.User, self.tables.users
mapper(User, users, properties={
- 'uname':users.c.name
+ 'uname': users.c.name
})
row = create_session().\
query(User.id, User.uname).\
- filter(User.id==7).first()
+ filter(User.id == 7).first()
assert row.id == 7
assert row.uname == 'jack'
@@ -106,7 +106,7 @@ class RowTupleTest(QueryTest):
sess.query(name_label, fn),
[
{'name':'uname', 'type':users.c.name.type,
- 'aliased':False,'expr':name_label},
+ 'aliased':False, 'expr':name_label},
{'name':None, 'type':fn.type, 'aliased':False,
'expr':fn
},
@@ -118,6 +118,28 @@ class RowTupleTest(QueryTest):
asserted
)
+ def test_unhashable_type(self):
+ from sqlalchemy.types import TypeDecorator, Integer
+ from sqlalchemy.sql import type_coerce
+
+ class MyType(TypeDecorator):
+ impl = Integer
+ hashable = False
+ def process_result_value(self, value, dialect):
+ return [value]
+
+ User, users = self.classes.User, self.tables.users
+
+ mapper(User, users)
+
+ s = Session()
+ row = s.\
+ query(User, type_coerce(users.c.id, MyType).label('foo')).\
+ filter(User.id == 7).first()
+ eq_(
+ row, (User(id=7), [7])
+ )
+
class RawSelectTest(QueryTest, AssertsCompiledSQL):
__dialect__ = 'default'
diff --git a/test/sql/test_compiler.py b/test/sql/test_compiler.py
index 53e626010..5b7a5d1d7 100644
--- a/test/sql/test_compiler.py
+++ b/test/sql/test_compiler.py
@@ -3245,6 +3245,22 @@ class ResultMapTest(fixtures.TestBase):
{'a': ('a', (t.c.a, 'a', 'a'), t.c.a.type)},
)
+ def test_label_plus_element(self):
+ t = Table('t', MetaData(), Column('a', Integer))
+ l1 = t.c.a.label('bar')
+ tc = type_coerce(t.c.a, String)
+ stmt = select([t.c.a, l1, tc])
+ comp = stmt.compile()
+ tc_anon_label = comp.result_map['a_1'][1][0]
+ eq_(
+ comp.result_map,
+ {
+ 'a': ('a', (t.c.a, 'a', 'a'), t.c.a.type),
+ 'bar': ('bar', (l1, 'bar'), l1.type),
+ 'a_1': ('%%(%d a)s' % id(tc), (tc_anon_label, 'a_1'), tc.type),
+ },
+ )
+
def test_label_conflict_union(self):
t1 = Table('t1', MetaData(), Column('a', Integer), Column('b', Integer))
t2 = Table('t2', MetaData(), Column('t1_a', Integer))
@@ -3259,5 +3275,5 @@ class ResultMapTest(fixtures.TestBase):
set(['t1_1_b', 't1_1_a', 't1_a', 't1_b'])
)
is_(
- comp.result_map['t1_a'][1][1], t1.c.a
+ comp.result_map['t1_a'][1][2], t1.c.a
) \ No newline at end of file
diff --git a/test/sql/test_query.py b/test/sql/test_query.py
index e2f2544c8..f8f5953c5 100644
--- a/test/sql/test_query.py
+++ b/test/sql/test_query.py
@@ -993,6 +993,19 @@ class QueryTest(fixtures.TestBase):
lambda: row[u2.c.user_id]
)
+ def test_ambiguous_column_by_col_plus_label(self):
+ users.insert().execute(user_id=1, user_name='john')
+ result = select([users.c.user_id,
+ type_coerce(users.c.user_id, Integer).label('foo')]
+ ).execute()
+ row = result.first()
+ eq_(
+ row[users.c.user_id], 1
+ )
+ eq_(
+ row[1], 1
+ )
+
@testing.requires.subqueries
def test_column_label_targeting(self):
users.insert().execute(user_id=7, user_name='ed')
@@ -1641,7 +1654,7 @@ class KeyTargetingTest(fixtures.TablesTest):
def test_column_label_overlap_fallback(self):
content, bar = self.tables.content, self.tables.bar
row = testing.db.execute(select([content.c.type.label("content_type")])).first()
- assert content.c.type in row
+ assert content.c.type not in row
assert bar.c.content_type not in row
assert sql.column('content_type') in row
diff --git a/test/sql/test_type_expressions.py b/test/sql/test_type_expressions.py
index 4bb8a928d..b65e4f24f 100644
--- a/test/sql/test_type_expressions.py
+++ b/test/sql/test_type_expressions.py
@@ -56,7 +56,7 @@ class SelectTest(_ExprFixture, fixtures.TestBase, AssertsCompiledSQL):
# the lower() function goes into the result_map, we don't really
# need this but it's fine
self.assert_compile(
- compiled.result_map['test_table_y'][1][1],
+ compiled.result_map['test_table_y'][1][2],
"lower(test_table.y)"
)
# then the original column gets put in there as well.