From: Gaƫtan de Menten Date: Fri, 19 Oct 2007 10:27:06 +0000 (+0000) Subject: - Added contains operator (which generate a "LIKE %%" clause). X-Git-Tag: rel_0_4_1~127 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=ae553db3cdb71c3cc14ca02bf53d6a81ff99fb8a;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git - Added contains operator (which generate a "LIKE %%" clause). - Added test coverage for endswith operator --- diff --git a/CHANGES b/CHANGES index eab3ec1374..c788f3b5ce 100644 --- a/CHANGES +++ b/CHANGES @@ -10,6 +10,9 @@ CHANGES - Fixed empty (zero column) sqlite inserts, allowing inserts on autoincrementing single column tables. + +- Added contains operator (which generate a "LIKE %%" clause). + 0.4.0 ----- diff --git a/lib/sqlalchemy/sql/expression.py b/lib/sqlalchemy/sql/expression.py index 73e23cc92e..fd96c52cd7 100644 --- a/lib/sqlalchemy/sql/expression.py +++ b/lib/sqlalchemy/sql/expression.py @@ -1088,6 +1088,9 @@ class ColumnOperators(Operators): def endswith(self, other): return self.operate(operators.endswith_op, other) + def contains(self, other): + return self.operate(operators.contains_op, other) + def desc(self): return self.operate(operators.desc_op) @@ -1195,6 +1198,9 @@ class _CompareMixin(ColumnOperators): if op == operators.add and isinstance(type_, (sqltypes.Concatenable)): op = operators.concat_op return _BinaryExpression(self.expression_element(), obj, op, type_=type_) + + # a mapping of operators with the method they use, along with their negated + # operator for comparison operators operators = { operators.add : (__operate,), operators.mul : (__operate,), @@ -1251,18 +1257,30 @@ class _CompareMixin(ColumnOperators): def startswith(self, other): """Produce the clause ``LIKE '%'``""" - perc = isinstance(other,(str,unicode)) and '%' or literal('%',type_= sqltypes.String) + perc = isinstance(other, basestring) and '%' or literal('%', type_=sqltypes.String) return self.__compare(operators.like_op, other + perc) def endswith(self, other): """Produce the clause ``LIKE '%'``""" - if isinstance(other,(str,unicode)): po = '%' + other + if isinstance(other, basestring): + po = '%' + other else: po = literal('%', type_=sqltypes.String) + other po.type = sqltypes.to_instance(sqltypes.String) #force! return self.__compare(operators.like_op, po) + def contains(self, other): + """Produce the clause ``LIKE '%%'``""" + + if isinstance(other, basestring): + po = '%' + other + '%' + else: + perc = literal('%', type_=sqltypes.String) + po = perc + other + perc + po.type = sqltypes.to_instance(sqltypes.String) #force! + return self.__compare(operators.like_op, po) + def label(self, name): """Produce a column label, i.e. `` AS ``""" return _Label(name, self, self.type) diff --git a/lib/sqlalchemy/sql/operators.py b/lib/sqlalchemy/sql/operators.py index cf8aeb71db..78159697be 100644 --- a/lib/sqlalchemy/sql/operators.py +++ b/lib/sqlalchemy/sql/operators.py @@ -51,6 +51,9 @@ def startswith_op(a, b): def endswith_op(a, b): return a.endswith(b) +def contains_op(a, b): + return a.contains(b) + def comma_op(a, b): raise NotImplementedError() diff --git a/test/sql/select.py b/test/sql/select.py index 5c8b570d79..56bf1d92ca 100644 --- a/test/sql/select.py +++ b/test/sql/select.py @@ -417,6 +417,18 @@ 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')), + "SELECT mytable.myid, mytable.name, mytable.description FROM mytable WHERE mytable.name LIKE :mytable_name", + checkparams = {'mytable_name': u'%jo%'}, + ) + self.assert_compile( + table1.select(table1.c.name.endswith('hn')), + "SELECT mytable.myid, mytable.name, mytable.description FROM mytable WHERE mytable.name LIKE :mytable_name", + checkparams = {'mytable_name': u'%hn'}, + ) + def testunicodestartswith(self): string = u"hi \xf6 \xf5" self.assert_compile(