expression.py 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. # dialects/mysql/expression.py
  2. # Copyright (C) 2005-2024 the SQLAlchemy authors and contributors
  3. # <see AUTHORS file>
  4. #
  5. # This module is part of SQLAlchemy and is released under
  6. # the MIT License: https://www.opensource.org/licenses/mit-license.php
  7. from ... import exc
  8. from ... import util
  9. from ...sql import coercions
  10. from ...sql import elements
  11. from ...sql import operators
  12. from ...sql import roles
  13. from ...sql.base import _generative
  14. from ...sql.base import Generative
  15. class match(Generative, elements.BinaryExpression):
  16. """Produce a ``MATCH (X, Y) AGAINST ('TEXT')`` clause.
  17. E.g.::
  18. from sqlalchemy import desc
  19. from sqlalchemy.dialects.mysql import match
  20. match_expr = match(
  21. users_table.c.firstname,
  22. users_table.c.lastname,
  23. against="Firstname Lastname",
  24. )
  25. stmt = (
  26. select(users_table)
  27. .where(match_expr.in_boolean_mode())
  28. .order_by(desc(match_expr))
  29. )
  30. Would produce SQL resembling::
  31. SELECT id, firstname, lastname
  32. FROM user
  33. WHERE MATCH(firstname, lastname) AGAINST (:param_1 IN BOOLEAN MODE)
  34. ORDER BY MATCH(firstname, lastname) AGAINST (:param_2) DESC
  35. The :func:`_mysql.match` function is a standalone version of the
  36. :meth:`_sql.ColumnElement.match` method available on all
  37. SQL expressions, as when :meth:`_expression.ColumnElement.match` is
  38. used, but allows to pass multiple columns
  39. :param cols: column expressions to match against
  40. :param against: expression to be compared towards
  41. :param in_boolean_mode: boolean, set "boolean mode" to true
  42. :param in_natural_language_mode: boolean , set "natural language" to true
  43. :param with_query_expansion: boolean, set "query expansion" to true
  44. .. versionadded:: 1.4.19
  45. .. seealso::
  46. :meth:`_expression.ColumnElement.match`
  47. """
  48. __visit_name__ = "mysql_match"
  49. inherit_cache = True
  50. def __init__(self, *cols, **kw):
  51. if not cols:
  52. raise exc.ArgumentError("columns are required")
  53. against = kw.pop("against", None)
  54. if against is None:
  55. raise exc.ArgumentError("against is required")
  56. against = coercions.expect(
  57. roles.ExpressionElementRole,
  58. against,
  59. )
  60. left = elements.BooleanClauseList._construct_raw(
  61. operators.comma_op,
  62. clauses=cols,
  63. )
  64. left.group = False
  65. flags = util.immutabledict(
  66. {
  67. "mysql_boolean_mode": kw.pop("in_boolean_mode", False),
  68. "mysql_natural_language": kw.pop(
  69. "in_natural_language_mode", False
  70. ),
  71. "mysql_query_expansion": kw.pop("with_query_expansion", False),
  72. }
  73. )
  74. if kw:
  75. raise exc.ArgumentError("unknown arguments: %s" % (", ".join(kw)))
  76. super(match, self).__init__(
  77. left, against, operators.match_op, modifiers=flags
  78. )
  79. @_generative
  80. def in_boolean_mode(self):
  81. """Apply the "IN BOOLEAN MODE" modifier to the MATCH expression.
  82. :return: a new :class:`_mysql.match` instance with modifications
  83. applied.
  84. """
  85. self.modifiers = self.modifiers.union({"mysql_boolean_mode": True})
  86. @_generative
  87. def in_natural_language_mode(self):
  88. """Apply the "IN NATURAL LANGUAGE MODE" modifier to the MATCH
  89. expression.
  90. :return: a new :class:`_mysql.match` instance with modifications
  91. applied.
  92. """
  93. self.modifiers = self.modifiers.union({"mysql_natural_language": True})
  94. @_generative
  95. def with_query_expansion(self):
  96. """Apply the "WITH QUERY EXPANSION" modifier to the MATCH expression.
  97. :return: a new :class:`_mysql.match` instance with modifications
  98. applied.
  99. """
  100. self.modifiers = self.modifiers.union({"mysql_query_expansion": True})