summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES5
-rw-r--r--lib/sqlalchemy/databases/postgres.py3
-rw-r--r--lib/sqlalchemy/sql/compiler.py2
-rw-r--r--lib/sqlalchemy/sql/expression.py4
-rw-r--r--test/sql/query.py39
-rw-r--r--test/sql/select.py7
6 files changed, 45 insertions, 15 deletions
diff --git a/CHANGES b/CHANGES
index 01fa8d271..e68d8f119 100644
--- a/CHANGES
+++ b/CHANGES
@@ -4,6 +4,11 @@ CHANGES
0.4.2p4
------
+- sql
+ - added "ilike()" operator to column operations.
+ compiles to ILIKE on postgres, lower(x) LIKE lower(y)
+ on all others [ticket:727]
+
- orm
- proper error message is raised when trying to access
expired instance attributes with no session present
diff --git a/lib/sqlalchemy/databases/postgres.py b/lib/sqlalchemy/databases/postgres.py
index 19db8b6b7..bab998d69 100644
--- a/lib/sqlalchemy/databases/postgres.py
+++ b/lib/sqlalchemy/databases/postgres.py
@@ -625,7 +625,8 @@ class PGCompiler(compiler.DefaultCompiler):
operators = compiler.DefaultCompiler.operators.copy()
operators.update(
{
- sql_operators.mod : '%%'
+ sql_operators.mod : '%%',
+ sql_operators.ilike_op: 'ILIKE'
}
)
diff --git a/lib/sqlalchemy/sql/compiler.py b/lib/sqlalchemy/sql/compiler.py
index 35a12efe3..545c0a1b4 100644
--- a/lib/sqlalchemy/sql/compiler.py
+++ b/lib/sqlalchemy/sql/compiler.py
@@ -79,7 +79,7 @@ OPERATORS = {
operators.concat_op : '||',
operators.like_op : 'LIKE',
operators.notlike_op : 'NOT LIKE',
- operators.ilike_op : 'ILIKE',
+ operators.ilike_op : lambda x, y: "lower(%s) LIKE lower(%s)" % (x, y),
operators.notilike_op : 'NOT ILIKE',
operators.between_op : 'BETWEEN',
operators.in_op : 'IN',
diff --git a/lib/sqlalchemy/sql/expression.py b/lib/sqlalchemy/sql/expression.py
index 0bf9bea10..187b38a2c 100644
--- a/lib/sqlalchemy/sql/expression.py
+++ b/lib/sqlalchemy/sql/expression.py
@@ -1113,6 +1113,9 @@ class ColumnOperators(Operators):
def like(self, other):
return self.operate(operators.like_op, other)
+ def ilike(self, other):
+ return self.operate(operators.ilike_op, other)
+
def in_(self, *other):
return self.operate(operators.in_op, other)
@@ -1205,6 +1208,7 @@ class _CompareMixin(ColumnOperators):
operators.ge : (__compare, operators.lt),
operators.eq : (__compare, operators.ne),
operators.like_op : (__compare, operators.notlike_op),
+ operators.ilike_op : (__compare, operators.notilike_op),
}
def operate(self, op, *other):
diff --git a/test/sql/query.py b/test/sql/query.py
index 2d5076b9a..d1583dc57 100644
--- a/test/sql/query.py
+++ b/test/sql/query.py
@@ -28,7 +28,7 @@ class QueryTest(PersistTest):
def tearDownAll(self):
metadata.drop_all()
- def testinsert(self):
+ def test_insert(self):
users.insert().execute(user_id = 7, user_name = 'jack')
assert users.count().scalar() == 1
@@ -40,7 +40,7 @@ class QueryTest(PersistTest):
)
assert users.select().execute().fetchall() == [(7, 'jack'), (8, 'ed'), (9, None)]
- def testupdate(self):
+ def test_update(self):
users.insert().execute(user_id = 7, user_name = 'jack')
assert users.count().scalar() == 1
@@ -128,7 +128,7 @@ class QueryTest(PersistTest):
finally:
table.drop()
- def testrowiteration(self):
+ def test_row_iteration(self):
users.insert().execute(user_id = 7, user_name = 'jack')
users.insert().execute(user_id = 8, user_name = 'ed')
users.insert().execute(user_id = 9, user_name = 'fred')
@@ -148,6 +148,23 @@ class QueryTest(PersistTest):
l.append(row)
self.assert_(len(l) == 2, "fetchmany(size=2) got %s rows" % len(l))
+ def test_ilike(self):
+ users.insert().execute(
+ {'user_id':1, 'user_name':'one'},
+ {'user_id':2, 'user_name':'TwO'},
+ {'user_id':3, 'user_name':'ONE'},
+ {'user_id':4, 'user_name':'OnE'},
+ )
+
+ self.assertEquals(select([users.c.user_id]).where(users.c.user_name.ilike('one')).execute().fetchall(), [(1, ), (3, ), (4, )])
+
+ self.assertEquals(select([users.c.user_id]).where(users.c.user_name.ilike('TWO')).execute().fetchall(), [(2, )])
+
+ if testing.against('postgres'):
+ self.assertEquals(select([users.c.user_id]).where(users.c.user_name.like('one')).execute().fetchall(), [(1, )])
+ self.assertEquals(select([users.c.user_id]).where(users.c.user_name.like('TWO')).execute().fetchall(), [])
+
+
def test_compiled_execute(self):
users.insert().execute(user_id = 7, user_name = 'jack')
s = select([users], users.c.user_id==bindparam('id')).compile()
@@ -229,7 +246,7 @@ class QueryTest(PersistTest):
a_eq(prep(r"(\:that$other)"), "(:that$other)")
a_eq(prep(r".\:that$ :other."), ".:that$ ?.")
- def testdelete(self):
+ def test_delete(self):
users.insert().execute(user_id = 7, user_name = 'jack')
users.insert().execute(user_id = 8, user_name = 'fred')
print repr(users.select().execute().fetchall())
@@ -238,7 +255,7 @@ class QueryTest(PersistTest):
print repr(users.select().execute().fetchall())
- def testselectlimit(self):
+ def test_select_limit(self):
users.insert().execute(user_id=1, user_name='john')
users.insert().execute(user_id=2, user_name='jack')
users.insert().execute(user_id=3, user_name='ed')
@@ -251,7 +268,7 @@ class QueryTest(PersistTest):
@testing.unsupported('mssql')
@testing.fails_on('maxdb')
- def testselectlimitoffset(self):
+ def test_select_limit_offset(self):
users.insert().execute(user_id=1, user_name='john')
users.insert().execute(user_id=2, user_name='jack')
users.insert().execute(user_id=3, user_name='ed')
@@ -769,7 +786,9 @@ class JoinTest(PersistTest):
def assertRows(self, statement, expected):
"""Execute a statement and assert that rows returned equal expected."""
- found = exec_sorted(statement)
+ found = sorted([tuple(row)
+ for row in statement.execute().fetchall()])
+
self.assertEquals(found, sorted(expected))
def test_join_x1(self):
@@ -1020,12 +1039,6 @@ class OperatorTest(PersistTest):
)
-def exec_sorted(statement, *args, **kw):
- """Executes a statement and returns a sorted list plain tuple rows."""
-
- return sorted([tuple(row)
- for row in statement.execute(*args, **kw).fetchall()])
-
if __name__ == "__main__":
testbase.main()
diff --git a/test/sql/select.py b/test/sql/select.py
index 70bf704ce..b922c5c22 100644
--- a/test/sql/select.py
+++ b/test/sql/select.py
@@ -451,6 +451,8 @@ sq.myothertable_othername AS sq_myothertable_othername FROM (" + sqstring + ") A
clause = (table1.c.myid == 12) & table1.c.myid.between(15, 20) & table1.c.myid.like('hoho')
assert str(clause) == str(util.pickle.loads(util.pickle.dumps(clause)))
+
+
def testextracomparisonoperators(self):
self.assert_compile(
table1.select(table1.c.name.contains('jo')),
@@ -523,6 +525,11 @@ sq.myothertable_othername AS sq_myothertable_othername FROM (" + sqstring + ") A
"SELECT myothertable.othername, count(myothertable.otherid) AS count_1 FROM myothertable GROUP BY myothertable.othername ORDER BY myothertable.othername"
)
+ def testilike(self):
+ stmt = table1.select(table1.c.name.ilike('%something%'))
+ self.assert_compile(stmt, "SELECT mytable.myid, mytable.name, mytable.description FROM mytable WHERE lower(mytable.name) LIKE :mytable_name_1")
+ self.assert_compile(stmt, "SELECT mytable.myid, mytable.name, mytable.description FROM mytable WHERE mytable.name ILIKE %(mytable_name_1)s", dialect=postgres.PGDialect())
+
def testforupdate(self):
self.assert_compile(table1.select(table1.c.myid==7, for_update=True), "SELECT mytable.myid, mytable.name, mytable.description FROM mytable WHERE mytable.myid = :mytable_myid_1 FOR UPDATE")