summaryrefslogtreecommitdiff
path: root/venv/lib/python3.11/site-packages/sqlalchemy/dialects/mysql/expression.py
blob: b81b58afc282a70e74d4421f081c2d694f533b68 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# dialects/mysql/expression.py
# Copyright (C) 2005-2024 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
# the MIT License: https://www.opensource.org/licenses/mit-license.php
# mypy: ignore-errors


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
from ...util.typing import Self


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 against is None:
            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().__init__(left, against, operators.match_op, modifiers=flags)

    @_generative
    def in_boolean_mode(self) -> 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})
        return self

    @_generative
    def in_natural_language_mode(self) -> 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})
        return self

    @_generative
    def with_query_expansion(self) -> 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})
        return self