-
-
Notifications
You must be signed in to change notification settings - Fork 886
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge "Implement MySQL-specific MATCH"
- Loading branch information
Showing
7 changed files
with
376 additions
and
19 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
.. change:: | ||
:tags: usecase, mysql | ||
:tickets: 6132 | ||
|
||
Added new construct :class:`_mysql.match`, which provides for the full | ||
range of MySQL's MATCH operator including multiple column support and | ||
modifiers. Pull request courtesy Anton Kovalevich. | ||
|
||
.. seealso:: | ||
|
||
:class:`_mysql.match` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
from ... import exc | ||
from ... import util | ||
from ...sql import coercions | ||
from ...sql import elements | ||
from ...sql import operators | ||
from ...sql import roles | ||
from ...sql.base import _generative | ||
from ...sql.base import Generative | ||
|
||
|
||
class match(Generative, elements.BinaryExpression): | ||
"""Produce a ``MATCH (X, Y) AGAINST ('TEXT')`` clause. | ||
E.g.:: | ||
from sqlalchemy import desc | ||
from sqlalchemy.dialects.mysql import match | ||
match_expr = match( | ||
users_table.c.firstname, | ||
users_table.c.lastname, | ||
against="Firstname Lastname", | ||
) | ||
stmt = ( | ||
select(users_table) | ||
.where(match_expr.in_boolean_mode()) | ||
.order_by(desc(match_expr)) | ||
) | ||
Would produce SQL resembling:: | ||
SELECT id, firstname, lastname | ||
FROM user | ||
WHERE MATCH(firstname, lastname) AGAINST (:param_1 IN BOOLEAN MODE) | ||
ORDER BY MATCH(firstname, lastname) AGAINST (:param_2) DESC | ||
The :func:`_mysql.match` function is a standalone version of the | ||
:meth:`_sql.ColumnElement.match` method available on all | ||
SQL expressions, as when :meth:`_expression.ColumnElement.match` is | ||
used, but allows to pass multiple columns | ||
:param cols: column expressions to match against | ||
:param against: expression to be compared towards | ||
:param in_boolean_mode: boolean, set "boolean mode" to true | ||
:param in_natural_language_mode: boolean , set "natural language" to true | ||
:param with_query_expansion: boolean, set "query expansion" to true | ||
.. versionadded:: 1.4.19 | ||
.. seealso:: | ||
:meth:`_expression.ColumnElement.match` | ||
""" | ||
|
||
__visit_name__ = "mysql_match" | ||
|
||
inherit_cache = True | ||
|
||
def __init__(self, *cols, **kw): | ||
if not cols: | ||
raise exc.ArgumentError("columns are required") | ||
|
||
against = kw.pop("against", None) | ||
|
||
if not against: | ||
raise exc.ArgumentError("against is required") | ||
against = coercions.expect( | ||
roles.ExpressionElementRole, | ||
against, | ||
) | ||
|
||
left = elements.BooleanClauseList._construct_raw( | ||
operators.comma_op, | ||
clauses=cols, | ||
) | ||
left.group = False | ||
|
||
flags = util.immutabledict( | ||
{ | ||
"mysql_boolean_mode": kw.pop("in_boolean_mode", False), | ||
"mysql_natural_language": kw.pop( | ||
"in_natural_language_mode", False | ||
), | ||
"mysql_query_expansion": kw.pop("with_query_expansion", False), | ||
} | ||
) | ||
|
||
if kw: | ||
raise exc.ArgumentError("unknown arguments: %s" % (", ".join(kw))) | ||
|
||
super(match, self).__init__( | ||
left, against, operators.match_op, modifiers=flags | ||
) | ||
|
||
@_generative | ||
def in_boolean_mode(self): | ||
"""Apply the "IN BOOLEAN MODE" modifier to the MATCH expression. | ||
:return: a new :class:`_mysql.match` instance with modifications | ||
applied. | ||
""" | ||
|
||
self.modifiers = self.modifiers.union({"mysql_boolean_mode": True}) | ||
|
||
@_generative | ||
def in_natural_language_mode(self): | ||
"""Apply the "IN NATURAL LANGUAGE MODE" modifier to the MATCH | ||
expression. | ||
:return: a new :class:`_mysql.match` instance with modifications | ||
applied. | ||
""" | ||
|
||
self.modifiers = self.modifiers.union({"mysql_natural_language": True}) | ||
|
||
@_generative | ||
def with_query_expansion(self): | ||
"""Apply the "WITH QUERY EXPANSION" modifier to the MATCH expression. | ||
:return: a new :class:`_mysql.match` instance with modifications | ||
applied. | ||
""" | ||
|
||
self.modifiers = self.modifiers.union({"mysql_query_expansion": True}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.