SQLAlchemy 2.0.36__cp313-cp313-win32.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- SQLAlchemy-2.0.36.dist-info/LICENSE +19 -0
- SQLAlchemy-2.0.36.dist-info/METADATA +243 -0
- SQLAlchemy-2.0.36.dist-info/RECORD +273 -0
- SQLAlchemy-2.0.36.dist-info/WHEEL +5 -0
- SQLAlchemy-2.0.36.dist-info/top_level.txt +1 -0
- sqlalchemy/__init__.py +294 -0
- sqlalchemy/connectors/__init__.py +18 -0
- sqlalchemy/connectors/aioodbc.py +174 -0
- sqlalchemy/connectors/asyncio.py +213 -0
- sqlalchemy/connectors/pyodbc.py +249 -0
- sqlalchemy/cyextension/__init__.py +6 -0
- sqlalchemy/cyextension/collections.cp313-win32.pyd +0 -0
- sqlalchemy/cyextension/collections.pyx +409 -0
- sqlalchemy/cyextension/immutabledict.cp313-win32.pyd +0 -0
- sqlalchemy/cyextension/immutabledict.pxd +8 -0
- sqlalchemy/cyextension/immutabledict.pyx +133 -0
- sqlalchemy/cyextension/processors.cp313-win32.pyd +0 -0
- sqlalchemy/cyextension/processors.pyx +68 -0
- sqlalchemy/cyextension/resultproxy.cp313-win32.pyd +0 -0
- sqlalchemy/cyextension/resultproxy.pyx +102 -0
- sqlalchemy/cyextension/util.cp313-win32.pyd +0 -0
- sqlalchemy/cyextension/util.pyx +91 -0
- sqlalchemy/dialects/__init__.py +61 -0
- sqlalchemy/dialects/_typing.py +25 -0
- sqlalchemy/dialects/mssql/__init__.py +88 -0
- sqlalchemy/dialects/mssql/aioodbc.py +64 -0
- sqlalchemy/dialects/mssql/base.py +4010 -0
- sqlalchemy/dialects/mssql/information_schema.py +254 -0
- sqlalchemy/dialects/mssql/json.py +133 -0
- sqlalchemy/dialects/mssql/provision.py +162 -0
- sqlalchemy/dialects/mssql/pymssql.py +126 -0
- sqlalchemy/dialects/mssql/pyodbc.py +745 -0
- sqlalchemy/dialects/mysql/__init__.py +101 -0
- sqlalchemy/dialects/mysql/aiomysql.py +333 -0
- sqlalchemy/dialects/mysql/asyncmy.py +337 -0
- sqlalchemy/dialects/mysql/base.py +3494 -0
- sqlalchemy/dialects/mysql/cymysql.py +84 -0
- sqlalchemy/dialects/mysql/dml.py +219 -0
- sqlalchemy/dialects/mysql/enumerated.py +244 -0
- sqlalchemy/dialects/mysql/expression.py +141 -0
- sqlalchemy/dialects/mysql/json.py +81 -0
- sqlalchemy/dialects/mysql/mariadb.py +32 -0
- sqlalchemy/dialects/mysql/mariadbconnector.py +277 -0
- sqlalchemy/dialects/mysql/mysqlconnector.py +180 -0
- sqlalchemy/dialects/mysql/mysqldb.py +303 -0
- sqlalchemy/dialects/mysql/provision.py +110 -0
- sqlalchemy/dialects/mysql/pymysql.py +137 -0
- sqlalchemy/dialects/mysql/pyodbc.py +138 -0
- sqlalchemy/dialects/mysql/reflection.py +677 -0
- sqlalchemy/dialects/mysql/reserved_words.py +571 -0
- sqlalchemy/dialects/mysql/types.py +774 -0
- sqlalchemy/dialects/oracle/__init__.py +67 -0
- sqlalchemy/dialects/oracle/base.py +3271 -0
- sqlalchemy/dialects/oracle/cx_oracle.py +1483 -0
- sqlalchemy/dialects/oracle/dictionary.py +507 -0
- sqlalchemy/dialects/oracle/oracledb.py +431 -0
- sqlalchemy/dialects/oracle/provision.py +220 -0
- sqlalchemy/dialects/oracle/types.py +287 -0
- sqlalchemy/dialects/postgresql/__init__.py +167 -0
- sqlalchemy/dialects/postgresql/_psycopg_common.py +187 -0
- sqlalchemy/dialects/postgresql/array.py +425 -0
- sqlalchemy/dialects/postgresql/asyncpg.py +1274 -0
- sqlalchemy/dialects/postgresql/base.py +5008 -0
- sqlalchemy/dialects/postgresql/dml.py +310 -0
- sqlalchemy/dialects/postgresql/ext.py +496 -0
- sqlalchemy/dialects/postgresql/hstore.py +397 -0
- sqlalchemy/dialects/postgresql/json.py +333 -0
- sqlalchemy/dialects/postgresql/named_types.py +509 -0
- sqlalchemy/dialects/postgresql/operators.py +129 -0
- sqlalchemy/dialects/postgresql/pg8000.py +662 -0
- sqlalchemy/dialects/postgresql/pg_catalog.py +300 -0
- sqlalchemy/dialects/postgresql/provision.py +175 -0
- sqlalchemy/dialects/postgresql/psycopg.py +772 -0
- sqlalchemy/dialects/postgresql/psycopg2.py +886 -0
- sqlalchemy/dialects/postgresql/psycopg2cffi.py +61 -0
- sqlalchemy/dialects/postgresql/ranges.py +1029 -0
- sqlalchemy/dialects/postgresql/types.py +303 -0
- sqlalchemy/dialects/sqlite/__init__.py +57 -0
- sqlalchemy/dialects/sqlite/aiosqlite.py +396 -0
- sqlalchemy/dialects/sqlite/base.py +2805 -0
- sqlalchemy/dialects/sqlite/dml.py +240 -0
- sqlalchemy/dialects/sqlite/json.py +92 -0
- sqlalchemy/dialects/sqlite/provision.py +198 -0
- sqlalchemy/dialects/sqlite/pysqlcipher.py +155 -0
- sqlalchemy/dialects/sqlite/pysqlite.py +756 -0
- sqlalchemy/dialects/type_migration_guidelines.txt +145 -0
- sqlalchemy/engine/__init__.py +62 -0
- sqlalchemy/engine/_py_processors.py +136 -0
- sqlalchemy/engine/_py_row.py +128 -0
- sqlalchemy/engine/_py_util.py +74 -0
- sqlalchemy/engine/base.py +3375 -0
- sqlalchemy/engine/characteristics.py +155 -0
- sqlalchemy/engine/create.py +875 -0
- sqlalchemy/engine/cursor.py +2181 -0
- sqlalchemy/engine/default.py +2365 -0
- sqlalchemy/engine/events.py +951 -0
- sqlalchemy/engine/interfaces.py +3403 -0
- sqlalchemy/engine/mock.py +131 -0
- sqlalchemy/engine/processors.py +61 -0
- sqlalchemy/engine/reflection.py +2098 -0
- sqlalchemy/engine/result.py +2382 -0
- sqlalchemy/engine/row.py +401 -0
- sqlalchemy/engine/strategies.py +19 -0
- sqlalchemy/engine/url.py +910 -0
- sqlalchemy/engine/util.py +167 -0
- sqlalchemy/event/__init__.py +25 -0
- sqlalchemy/event/api.py +225 -0
- sqlalchemy/event/attr.py +655 -0
- sqlalchemy/event/base.py +470 -0
- sqlalchemy/event/legacy.py +246 -0
- sqlalchemy/event/registry.py +386 -0
- sqlalchemy/events.py +17 -0
- sqlalchemy/exc.py +830 -0
- sqlalchemy/ext/__init__.py +11 -0
- sqlalchemy/ext/associationproxy.py +2013 -0
- sqlalchemy/ext/asyncio/__init__.py +25 -0
- sqlalchemy/ext/asyncio/base.py +279 -0
- sqlalchemy/ext/asyncio/engine.py +1466 -0
- sqlalchemy/ext/asyncio/exc.py +21 -0
- sqlalchemy/ext/asyncio/result.py +961 -0
- sqlalchemy/ext/asyncio/scoping.py +1614 -0
- sqlalchemy/ext/asyncio/session.py +1936 -0
- sqlalchemy/ext/automap.py +1691 -0
- sqlalchemy/ext/baked.py +574 -0
- sqlalchemy/ext/compiler.py +570 -0
- sqlalchemy/ext/declarative/__init__.py +65 -0
- sqlalchemy/ext/declarative/extensions.py +548 -0
- sqlalchemy/ext/horizontal_shard.py +481 -0
- sqlalchemy/ext/hybrid.py +1514 -0
- sqlalchemy/ext/indexable.py +341 -0
- sqlalchemy/ext/instrumentation.py +450 -0
- sqlalchemy/ext/mutable.py +1073 -0
- sqlalchemy/ext/mypy/__init__.py +6 -0
- sqlalchemy/ext/mypy/apply.py +320 -0
- sqlalchemy/ext/mypy/decl_class.py +515 -0
- sqlalchemy/ext/mypy/infer.py +590 -0
- sqlalchemy/ext/mypy/names.py +335 -0
- sqlalchemy/ext/mypy/plugin.py +303 -0
- sqlalchemy/ext/mypy/util.py +357 -0
- sqlalchemy/ext/orderinglist.py +416 -0
- sqlalchemy/ext/serializer.py +181 -0
- sqlalchemy/future/__init__.py +16 -0
- sqlalchemy/future/engine.py +15 -0
- sqlalchemy/inspection.py +174 -0
- sqlalchemy/log.py +288 -0
- sqlalchemy/orm/__init__.py +170 -0
- sqlalchemy/orm/_orm_constructors.py +2571 -0
- sqlalchemy/orm/_typing.py +179 -0
- sqlalchemy/orm/attributes.py +2835 -0
- sqlalchemy/orm/base.py +973 -0
- sqlalchemy/orm/bulk_persistence.py +2123 -0
- sqlalchemy/orm/clsregistry.py +571 -0
- sqlalchemy/orm/collections.py +1620 -0
- sqlalchemy/orm/context.py +3268 -0
- sqlalchemy/orm/decl_api.py +1883 -0
- sqlalchemy/orm/decl_base.py +2190 -0
- sqlalchemy/orm/dependency.py +1304 -0
- sqlalchemy/orm/descriptor_props.py +1076 -0
- sqlalchemy/orm/dynamic.py +300 -0
- sqlalchemy/orm/evaluator.py +379 -0
- sqlalchemy/orm/events.py +3261 -0
- sqlalchemy/orm/exc.py +228 -0
- sqlalchemy/orm/identity.py +302 -0
- sqlalchemy/orm/instrumentation.py +754 -0
- sqlalchemy/orm/interfaces.py +1474 -0
- sqlalchemy/orm/loading.py +1682 -0
- sqlalchemy/orm/mapped_collection.py +557 -0
- sqlalchemy/orm/mapper.py +4432 -0
- sqlalchemy/orm/path_registry.py +811 -0
- sqlalchemy/orm/persistence.py +1782 -0
- sqlalchemy/orm/properties.py +886 -0
- sqlalchemy/orm/query.py +3396 -0
- sqlalchemy/orm/relationships.py +3500 -0
- sqlalchemy/orm/scoping.py +2165 -0
- sqlalchemy/orm/session.py +5301 -0
- sqlalchemy/orm/state.py +1143 -0
- sqlalchemy/orm/state_changes.py +198 -0
- sqlalchemy/orm/strategies.py +3473 -0
- sqlalchemy/orm/strategy_options.py +2569 -0
- sqlalchemy/orm/sync.py +164 -0
- sqlalchemy/orm/unitofwork.py +796 -0
- sqlalchemy/orm/util.py +2424 -0
- sqlalchemy/orm/writeonly.py +678 -0
- sqlalchemy/pool/__init__.py +44 -0
- sqlalchemy/pool/base.py +1515 -0
- sqlalchemy/pool/events.py +370 -0
- sqlalchemy/pool/impl.py +581 -0
- sqlalchemy/py.typed +0 -0
- sqlalchemy/schema.py +70 -0
- sqlalchemy/sql/__init__.py +145 -0
- sqlalchemy/sql/_dml_constructors.py +140 -0
- sqlalchemy/sql/_elements_constructors.py +1850 -0
- sqlalchemy/sql/_orm_types.py +20 -0
- sqlalchemy/sql/_py_util.py +75 -0
- sqlalchemy/sql/_selectable_constructors.py +635 -0
- sqlalchemy/sql/_typing.py +460 -0
- sqlalchemy/sql/annotation.py +585 -0
- sqlalchemy/sql/base.py +2185 -0
- sqlalchemy/sql/cache_key.py +1057 -0
- sqlalchemy/sql/coercions.py +1405 -0
- sqlalchemy/sql/compiler.py +7818 -0
- sqlalchemy/sql/crud.py +1669 -0
- sqlalchemy/sql/ddl.py +1378 -0
- sqlalchemy/sql/default_comparator.py +552 -0
- sqlalchemy/sql/dml.py +1817 -0
- sqlalchemy/sql/elements.py +5499 -0
- sqlalchemy/sql/events.py +455 -0
- sqlalchemy/sql/expression.py +162 -0
- sqlalchemy/sql/functions.py +2055 -0
- sqlalchemy/sql/lambdas.py +1449 -0
- sqlalchemy/sql/naming.py +212 -0
- sqlalchemy/sql/operators.py +2579 -0
- sqlalchemy/sql/roles.py +323 -0
- sqlalchemy/sql/schema.py +6158 -0
- sqlalchemy/sql/selectable.py +7004 -0
- sqlalchemy/sql/sqltypes.py +3827 -0
- sqlalchemy/sql/traversals.py +1024 -0
- sqlalchemy/sql/type_api.py +2339 -0
- sqlalchemy/sql/util.py +1486 -0
- sqlalchemy/sql/visitors.py +1165 -0
- sqlalchemy/testing/__init__.py +96 -0
- sqlalchemy/testing/assertions.py +989 -0
- sqlalchemy/testing/assertsql.py +516 -0
- sqlalchemy/testing/asyncio.py +135 -0
- sqlalchemy/testing/config.py +427 -0
- sqlalchemy/testing/engines.py +472 -0
- sqlalchemy/testing/entities.py +117 -0
- sqlalchemy/testing/exclusions.py +435 -0
- sqlalchemy/testing/fixtures/__init__.py +28 -0
- sqlalchemy/testing/fixtures/base.py +366 -0
- sqlalchemy/testing/fixtures/mypy.py +312 -0
- sqlalchemy/testing/fixtures/orm.py +227 -0
- sqlalchemy/testing/fixtures/sql.py +503 -0
- sqlalchemy/testing/pickleable.py +155 -0
- sqlalchemy/testing/plugin/__init__.py +6 -0
- sqlalchemy/testing/plugin/bootstrap.py +51 -0
- sqlalchemy/testing/plugin/plugin_base.py +779 -0
- sqlalchemy/testing/plugin/pytestplugin.py +868 -0
- sqlalchemy/testing/profiling.py +324 -0
- sqlalchemy/testing/provision.py +496 -0
- sqlalchemy/testing/requirements.py +1818 -0
- sqlalchemy/testing/schema.py +224 -0
- sqlalchemy/testing/suite/__init__.py +19 -0
- sqlalchemy/testing/suite/test_cte.py +211 -0
- sqlalchemy/testing/suite/test_ddl.py +389 -0
- sqlalchemy/testing/suite/test_deprecations.py +153 -0
- sqlalchemy/testing/suite/test_dialect.py +740 -0
- sqlalchemy/testing/suite/test_insert.py +630 -0
- sqlalchemy/testing/suite/test_reflection.py +3225 -0
- sqlalchemy/testing/suite/test_results.py +502 -0
- sqlalchemy/testing/suite/test_rowcount.py +258 -0
- sqlalchemy/testing/suite/test_select.py +1999 -0
- sqlalchemy/testing/suite/test_sequence.py +317 -0
- sqlalchemy/testing/suite/test_types.py +2141 -0
- sqlalchemy/testing/suite/test_unicode_ddl.py +189 -0
- sqlalchemy/testing/suite/test_update_delete.py +139 -0
- sqlalchemy/testing/util.py +537 -0
- sqlalchemy/testing/warnings.py +52 -0
- sqlalchemy/types.py +76 -0
- sqlalchemy/util/__init__.py +160 -0
- sqlalchemy/util/_collections.py +715 -0
- sqlalchemy/util/_concurrency_py3k.py +288 -0
- sqlalchemy/util/_has_cy.py +40 -0
- sqlalchemy/util/_py_collections.py +541 -0
- sqlalchemy/util/compat.py +301 -0
- sqlalchemy/util/concurrency.py +108 -0
- sqlalchemy/util/deprecations.py +401 -0
- sqlalchemy/util/langhelpers.py +2218 -0
- sqlalchemy/util/preloaded.py +150 -0
- sqlalchemy/util/queue.py +322 -0
- sqlalchemy/util/tool_support.py +201 -0
- sqlalchemy/util/topological.py +120 -0
- sqlalchemy/util/typing.py +629 -0
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# dialects/mysql/cymysql.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
|
+
# mypy: ignore-errors
|
|
8
|
+
|
|
9
|
+
r"""
|
|
10
|
+
|
|
11
|
+
.. dialect:: mysql+cymysql
|
|
12
|
+
:name: CyMySQL
|
|
13
|
+
:dbapi: cymysql
|
|
14
|
+
:connectstring: mysql+cymysql://<username>:<password>@<host>/<dbname>[?<options>]
|
|
15
|
+
:url: https://github.com/nakagami/CyMySQL
|
|
16
|
+
|
|
17
|
+
.. note::
|
|
18
|
+
|
|
19
|
+
The CyMySQL dialect is **not tested as part of SQLAlchemy's continuous
|
|
20
|
+
integration** and may have unresolved issues. The recommended MySQL
|
|
21
|
+
dialects are mysqlclient and PyMySQL.
|
|
22
|
+
|
|
23
|
+
""" # noqa
|
|
24
|
+
|
|
25
|
+
from .base import BIT
|
|
26
|
+
from .base import MySQLDialect
|
|
27
|
+
from .mysqldb import MySQLDialect_mysqldb
|
|
28
|
+
from ... import util
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class _cymysqlBIT(BIT):
|
|
32
|
+
def result_processor(self, dialect, coltype):
|
|
33
|
+
"""Convert MySQL's 64 bit, variable length binary string to a long."""
|
|
34
|
+
|
|
35
|
+
def process(value):
|
|
36
|
+
if value is not None:
|
|
37
|
+
v = 0
|
|
38
|
+
for i in iter(value):
|
|
39
|
+
v = v << 8 | i
|
|
40
|
+
return v
|
|
41
|
+
return value
|
|
42
|
+
|
|
43
|
+
return process
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class MySQLDialect_cymysql(MySQLDialect_mysqldb):
|
|
47
|
+
driver = "cymysql"
|
|
48
|
+
supports_statement_cache = True
|
|
49
|
+
|
|
50
|
+
description_encoding = None
|
|
51
|
+
supports_sane_rowcount = True
|
|
52
|
+
supports_sane_multi_rowcount = False
|
|
53
|
+
supports_unicode_statements = True
|
|
54
|
+
|
|
55
|
+
colspecs = util.update_copy(MySQLDialect.colspecs, {BIT: _cymysqlBIT})
|
|
56
|
+
|
|
57
|
+
@classmethod
|
|
58
|
+
def import_dbapi(cls):
|
|
59
|
+
return __import__("cymysql")
|
|
60
|
+
|
|
61
|
+
def _detect_charset(self, connection):
|
|
62
|
+
return connection.connection.charset
|
|
63
|
+
|
|
64
|
+
def _extract_error_code(self, exception):
|
|
65
|
+
return exception.errno
|
|
66
|
+
|
|
67
|
+
def is_disconnect(self, e, connection, cursor):
|
|
68
|
+
if isinstance(e, self.dbapi.OperationalError):
|
|
69
|
+
return self._extract_error_code(e) in (
|
|
70
|
+
2006,
|
|
71
|
+
2013,
|
|
72
|
+
2014,
|
|
73
|
+
2045,
|
|
74
|
+
2055,
|
|
75
|
+
)
|
|
76
|
+
elif isinstance(e, self.dbapi.InterfaceError):
|
|
77
|
+
# if underlying connection is closed,
|
|
78
|
+
# this is the error you get
|
|
79
|
+
return True
|
|
80
|
+
else:
|
|
81
|
+
return False
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
dialect = MySQLDialect_cymysql
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
# dialects/mysql/dml.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 __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from typing import Any
|
|
10
|
+
from typing import List
|
|
11
|
+
from typing import Mapping
|
|
12
|
+
from typing import Optional
|
|
13
|
+
from typing import Tuple
|
|
14
|
+
from typing import Union
|
|
15
|
+
|
|
16
|
+
from ... import exc
|
|
17
|
+
from ... import util
|
|
18
|
+
from ...sql._typing import _DMLTableArgument
|
|
19
|
+
from ...sql.base import _exclusive_against
|
|
20
|
+
from ...sql.base import _generative
|
|
21
|
+
from ...sql.base import ColumnCollection
|
|
22
|
+
from ...sql.base import ReadOnlyColumnCollection
|
|
23
|
+
from ...sql.dml import Insert as StandardInsert
|
|
24
|
+
from ...sql.elements import ClauseElement
|
|
25
|
+
from ...sql.elements import KeyedColumnElement
|
|
26
|
+
from ...sql.expression import alias
|
|
27
|
+
from ...sql.selectable import NamedFromClause
|
|
28
|
+
from ...util.typing import Self
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
__all__ = ("Insert", "insert")
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def insert(table: _DMLTableArgument) -> Insert:
|
|
35
|
+
"""Construct a MySQL/MariaDB-specific variant :class:`_mysql.Insert`
|
|
36
|
+
construct.
|
|
37
|
+
|
|
38
|
+
.. container:: inherited_member
|
|
39
|
+
|
|
40
|
+
The :func:`sqlalchemy.dialects.mysql.insert` function creates
|
|
41
|
+
a :class:`sqlalchemy.dialects.mysql.Insert`. This class is based
|
|
42
|
+
on the dialect-agnostic :class:`_sql.Insert` construct which may
|
|
43
|
+
be constructed using the :func:`_sql.insert` function in
|
|
44
|
+
SQLAlchemy Core.
|
|
45
|
+
|
|
46
|
+
The :class:`_mysql.Insert` construct includes additional methods
|
|
47
|
+
:meth:`_mysql.Insert.on_duplicate_key_update`.
|
|
48
|
+
|
|
49
|
+
"""
|
|
50
|
+
return Insert(table)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class Insert(StandardInsert):
|
|
54
|
+
"""MySQL-specific implementation of INSERT.
|
|
55
|
+
|
|
56
|
+
Adds methods for MySQL-specific syntaxes such as ON DUPLICATE KEY UPDATE.
|
|
57
|
+
|
|
58
|
+
The :class:`~.mysql.Insert` object is created using the
|
|
59
|
+
:func:`sqlalchemy.dialects.mysql.insert` function.
|
|
60
|
+
|
|
61
|
+
.. versionadded:: 1.2
|
|
62
|
+
|
|
63
|
+
"""
|
|
64
|
+
|
|
65
|
+
stringify_dialect = "mysql"
|
|
66
|
+
inherit_cache = False
|
|
67
|
+
|
|
68
|
+
@property
|
|
69
|
+
def inserted(
|
|
70
|
+
self,
|
|
71
|
+
) -> ReadOnlyColumnCollection[str, KeyedColumnElement[Any]]:
|
|
72
|
+
"""Provide the "inserted" namespace for an ON DUPLICATE KEY UPDATE
|
|
73
|
+
statement
|
|
74
|
+
|
|
75
|
+
MySQL's ON DUPLICATE KEY UPDATE clause allows reference to the row
|
|
76
|
+
that would be inserted, via a special function called ``VALUES()``.
|
|
77
|
+
This attribute provides all columns in this row to be referenceable
|
|
78
|
+
such that they will render within a ``VALUES()`` function inside the
|
|
79
|
+
ON DUPLICATE KEY UPDATE clause. The attribute is named ``.inserted``
|
|
80
|
+
so as not to conflict with the existing
|
|
81
|
+
:meth:`_expression.Insert.values` method.
|
|
82
|
+
|
|
83
|
+
.. tip:: The :attr:`_mysql.Insert.inserted` attribute is an instance
|
|
84
|
+
of :class:`_expression.ColumnCollection`, which provides an
|
|
85
|
+
interface the same as that of the :attr:`_schema.Table.c`
|
|
86
|
+
collection described at :ref:`metadata_tables_and_columns`.
|
|
87
|
+
With this collection, ordinary names are accessible like attributes
|
|
88
|
+
(e.g. ``stmt.inserted.some_column``), but special names and
|
|
89
|
+
dictionary method names should be accessed using indexed access,
|
|
90
|
+
such as ``stmt.inserted["column name"]`` or
|
|
91
|
+
``stmt.inserted["values"]``. See the docstring for
|
|
92
|
+
:class:`_expression.ColumnCollection` for further examples.
|
|
93
|
+
|
|
94
|
+
.. seealso::
|
|
95
|
+
|
|
96
|
+
:ref:`mysql_insert_on_duplicate_key_update` - example of how
|
|
97
|
+
to use :attr:`_expression.Insert.inserted`
|
|
98
|
+
|
|
99
|
+
"""
|
|
100
|
+
return self.inserted_alias.columns
|
|
101
|
+
|
|
102
|
+
@util.memoized_property
|
|
103
|
+
def inserted_alias(self) -> NamedFromClause:
|
|
104
|
+
return alias(self.table, name="inserted")
|
|
105
|
+
|
|
106
|
+
@_generative
|
|
107
|
+
@_exclusive_against(
|
|
108
|
+
"_post_values_clause",
|
|
109
|
+
msgs={
|
|
110
|
+
"_post_values_clause": "This Insert construct already "
|
|
111
|
+
"has an ON DUPLICATE KEY clause present"
|
|
112
|
+
},
|
|
113
|
+
)
|
|
114
|
+
def on_duplicate_key_update(self, *args: _UpdateArg, **kw: Any) -> Self:
|
|
115
|
+
r"""
|
|
116
|
+
Specifies the ON DUPLICATE KEY UPDATE clause.
|
|
117
|
+
|
|
118
|
+
:param \**kw: Column keys linked to UPDATE values. The
|
|
119
|
+
values may be any SQL expression or supported literal Python
|
|
120
|
+
values.
|
|
121
|
+
|
|
122
|
+
.. warning:: This dictionary does **not** take into account
|
|
123
|
+
Python-specified default UPDATE values or generation functions,
|
|
124
|
+
e.g. those specified using :paramref:`_schema.Column.onupdate`.
|
|
125
|
+
These values will not be exercised for an ON DUPLICATE KEY UPDATE
|
|
126
|
+
style of UPDATE, unless values are manually specified here.
|
|
127
|
+
|
|
128
|
+
:param \*args: As an alternative to passing key/value parameters,
|
|
129
|
+
a dictionary or list of 2-tuples can be passed as a single positional
|
|
130
|
+
argument.
|
|
131
|
+
|
|
132
|
+
Passing a single dictionary is equivalent to the keyword argument
|
|
133
|
+
form::
|
|
134
|
+
|
|
135
|
+
insert().on_duplicate_key_update({"name": "some name"})
|
|
136
|
+
|
|
137
|
+
Passing a list of 2-tuples indicates that the parameter assignments
|
|
138
|
+
in the UPDATE clause should be ordered as sent, in a manner similar
|
|
139
|
+
to that described for the :class:`_expression.Update`
|
|
140
|
+
construct overall
|
|
141
|
+
in :ref:`tutorial_parameter_ordered_updates`::
|
|
142
|
+
|
|
143
|
+
insert().on_duplicate_key_update(
|
|
144
|
+
[("name", "some name"), ("value", "some value")])
|
|
145
|
+
|
|
146
|
+
.. versionchanged:: 1.3 parameters can be specified as a dictionary
|
|
147
|
+
or list of 2-tuples; the latter form provides for parameter
|
|
148
|
+
ordering.
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
.. versionadded:: 1.2
|
|
152
|
+
|
|
153
|
+
.. seealso::
|
|
154
|
+
|
|
155
|
+
:ref:`mysql_insert_on_duplicate_key_update`
|
|
156
|
+
|
|
157
|
+
"""
|
|
158
|
+
if args and kw:
|
|
159
|
+
raise exc.ArgumentError(
|
|
160
|
+
"Can't pass kwargs and positional arguments simultaneously"
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
if args:
|
|
164
|
+
if len(args) > 1:
|
|
165
|
+
raise exc.ArgumentError(
|
|
166
|
+
"Only a single dictionary or list of tuples "
|
|
167
|
+
"is accepted positionally."
|
|
168
|
+
)
|
|
169
|
+
values = args[0]
|
|
170
|
+
else:
|
|
171
|
+
values = kw
|
|
172
|
+
|
|
173
|
+
self._post_values_clause = OnDuplicateClause(
|
|
174
|
+
self.inserted_alias, values
|
|
175
|
+
)
|
|
176
|
+
return self
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
class OnDuplicateClause(ClauseElement):
|
|
180
|
+
__visit_name__ = "on_duplicate_key_update"
|
|
181
|
+
|
|
182
|
+
_parameter_ordering: Optional[List[str]] = None
|
|
183
|
+
|
|
184
|
+
stringify_dialect = "mysql"
|
|
185
|
+
|
|
186
|
+
def __init__(
|
|
187
|
+
self, inserted_alias: NamedFromClause, update: _UpdateArg
|
|
188
|
+
) -> None:
|
|
189
|
+
self.inserted_alias = inserted_alias
|
|
190
|
+
|
|
191
|
+
# auto-detect that parameters should be ordered. This is copied from
|
|
192
|
+
# Update._proces_colparams(), however we don't look for a special flag
|
|
193
|
+
# in this case since we are not disambiguating from other use cases as
|
|
194
|
+
# we are in Update.values().
|
|
195
|
+
if isinstance(update, list) and (
|
|
196
|
+
update and isinstance(update[0], tuple)
|
|
197
|
+
):
|
|
198
|
+
self._parameter_ordering = [key for key, value in update]
|
|
199
|
+
update = dict(update)
|
|
200
|
+
|
|
201
|
+
if isinstance(update, dict):
|
|
202
|
+
if not update:
|
|
203
|
+
raise ValueError(
|
|
204
|
+
"update parameter dictionary must not be empty"
|
|
205
|
+
)
|
|
206
|
+
elif isinstance(update, ColumnCollection):
|
|
207
|
+
update = dict(update)
|
|
208
|
+
else:
|
|
209
|
+
raise ValueError(
|
|
210
|
+
"update parameter must be a non-empty dictionary "
|
|
211
|
+
"or a ColumnCollection such as the `.c.` collection "
|
|
212
|
+
"of a Table object"
|
|
213
|
+
)
|
|
214
|
+
self.update = update
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
_UpdateArg = Union[
|
|
218
|
+
Mapping[Any, Any], List[Tuple[str, Any]], ColumnCollection[Any, Any]
|
|
219
|
+
]
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
# dialects/mysql/enumerated.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
|
+
# mypy: ignore-errors
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
import re
|
|
11
|
+
|
|
12
|
+
from .types import _StringType
|
|
13
|
+
from ... import exc
|
|
14
|
+
from ... import sql
|
|
15
|
+
from ... import util
|
|
16
|
+
from ...sql import sqltypes
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class ENUM(sqltypes.NativeForEmulated, sqltypes.Enum, _StringType):
|
|
20
|
+
"""MySQL ENUM type."""
|
|
21
|
+
|
|
22
|
+
__visit_name__ = "ENUM"
|
|
23
|
+
|
|
24
|
+
native_enum = True
|
|
25
|
+
|
|
26
|
+
def __init__(self, *enums, **kw):
|
|
27
|
+
"""Construct an ENUM.
|
|
28
|
+
|
|
29
|
+
E.g.::
|
|
30
|
+
|
|
31
|
+
Column('myenum', ENUM("foo", "bar", "baz"))
|
|
32
|
+
|
|
33
|
+
:param enums: The range of valid values for this ENUM. Values in
|
|
34
|
+
enums are not quoted, they will be escaped and surrounded by single
|
|
35
|
+
quotes when generating the schema. This object may also be a
|
|
36
|
+
PEP-435-compliant enumerated type.
|
|
37
|
+
|
|
38
|
+
.. versionadded: 1.1 added support for PEP-435-compliant enumerated
|
|
39
|
+
types.
|
|
40
|
+
|
|
41
|
+
:param strict: This flag has no effect.
|
|
42
|
+
|
|
43
|
+
.. versionchanged:: The MySQL ENUM type as well as the base Enum
|
|
44
|
+
type now validates all Python data values.
|
|
45
|
+
|
|
46
|
+
:param charset: Optional, a column-level character set for this string
|
|
47
|
+
value. Takes precedence to 'ascii' or 'unicode' short-hand.
|
|
48
|
+
|
|
49
|
+
:param collation: Optional, a column-level collation for this string
|
|
50
|
+
value. Takes precedence to 'binary' short-hand.
|
|
51
|
+
|
|
52
|
+
:param ascii: Defaults to False: short-hand for the ``latin1``
|
|
53
|
+
character set, generates ASCII in schema.
|
|
54
|
+
|
|
55
|
+
:param unicode: Defaults to False: short-hand for the ``ucs2``
|
|
56
|
+
character set, generates UNICODE in schema.
|
|
57
|
+
|
|
58
|
+
:param binary: Defaults to False: short-hand, pick the binary
|
|
59
|
+
collation type that matches the column's character set. Generates
|
|
60
|
+
BINARY in schema. This does not affect the type of data stored,
|
|
61
|
+
only the collation of character data.
|
|
62
|
+
|
|
63
|
+
"""
|
|
64
|
+
kw.pop("strict", None)
|
|
65
|
+
self._enum_init(enums, kw)
|
|
66
|
+
_StringType.__init__(self, length=self.length, **kw)
|
|
67
|
+
|
|
68
|
+
@classmethod
|
|
69
|
+
def adapt_emulated_to_native(cls, impl, **kw):
|
|
70
|
+
"""Produce a MySQL native :class:`.mysql.ENUM` from plain
|
|
71
|
+
:class:`.Enum`.
|
|
72
|
+
|
|
73
|
+
"""
|
|
74
|
+
kw.setdefault("validate_strings", impl.validate_strings)
|
|
75
|
+
kw.setdefault("values_callable", impl.values_callable)
|
|
76
|
+
kw.setdefault("omit_aliases", impl._omit_aliases)
|
|
77
|
+
return cls(**kw)
|
|
78
|
+
|
|
79
|
+
def _object_value_for_elem(self, elem):
|
|
80
|
+
# mysql sends back a blank string for any value that
|
|
81
|
+
# was persisted that was not in the enums; that is, it does no
|
|
82
|
+
# validation on the incoming data, it "truncates" it to be
|
|
83
|
+
# the blank string. Return it straight.
|
|
84
|
+
if elem == "":
|
|
85
|
+
return elem
|
|
86
|
+
else:
|
|
87
|
+
return super()._object_value_for_elem(elem)
|
|
88
|
+
|
|
89
|
+
def __repr__(self):
|
|
90
|
+
return util.generic_repr(
|
|
91
|
+
self, to_inspect=[ENUM, _StringType, sqltypes.Enum]
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
class SET(_StringType):
|
|
96
|
+
"""MySQL SET type."""
|
|
97
|
+
|
|
98
|
+
__visit_name__ = "SET"
|
|
99
|
+
|
|
100
|
+
def __init__(self, *values, **kw):
|
|
101
|
+
"""Construct a SET.
|
|
102
|
+
|
|
103
|
+
E.g.::
|
|
104
|
+
|
|
105
|
+
Column('myset', SET("foo", "bar", "baz"))
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
The list of potential values is required in the case that this
|
|
109
|
+
set will be used to generate DDL for a table, or if the
|
|
110
|
+
:paramref:`.SET.retrieve_as_bitwise` flag is set to True.
|
|
111
|
+
|
|
112
|
+
:param values: The range of valid values for this SET. The values
|
|
113
|
+
are not quoted, they will be escaped and surrounded by single
|
|
114
|
+
quotes when generating the schema.
|
|
115
|
+
|
|
116
|
+
:param convert_unicode: Same flag as that of
|
|
117
|
+
:paramref:`.String.convert_unicode`.
|
|
118
|
+
|
|
119
|
+
:param collation: same as that of :paramref:`.String.collation`
|
|
120
|
+
|
|
121
|
+
:param charset: same as that of :paramref:`.VARCHAR.charset`.
|
|
122
|
+
|
|
123
|
+
:param ascii: same as that of :paramref:`.VARCHAR.ascii`.
|
|
124
|
+
|
|
125
|
+
:param unicode: same as that of :paramref:`.VARCHAR.unicode`.
|
|
126
|
+
|
|
127
|
+
:param binary: same as that of :paramref:`.VARCHAR.binary`.
|
|
128
|
+
|
|
129
|
+
:param retrieve_as_bitwise: if True, the data for the set type will be
|
|
130
|
+
persisted and selected using an integer value, where a set is coerced
|
|
131
|
+
into a bitwise mask for persistence. MySQL allows this mode which
|
|
132
|
+
has the advantage of being able to store values unambiguously,
|
|
133
|
+
such as the blank string ``''``. The datatype will appear
|
|
134
|
+
as the expression ``col + 0`` in a SELECT statement, so that the
|
|
135
|
+
value is coerced into an integer value in result sets.
|
|
136
|
+
This flag is required if one wishes
|
|
137
|
+
to persist a set that can store the blank string ``''`` as a value.
|
|
138
|
+
|
|
139
|
+
.. warning::
|
|
140
|
+
|
|
141
|
+
When using :paramref:`.mysql.SET.retrieve_as_bitwise`, it is
|
|
142
|
+
essential that the list of set values is expressed in the
|
|
143
|
+
**exact same order** as exists on the MySQL database.
|
|
144
|
+
|
|
145
|
+
"""
|
|
146
|
+
self.retrieve_as_bitwise = kw.pop("retrieve_as_bitwise", False)
|
|
147
|
+
self.values = tuple(values)
|
|
148
|
+
if not self.retrieve_as_bitwise and "" in values:
|
|
149
|
+
raise exc.ArgumentError(
|
|
150
|
+
"Can't use the blank value '' in a SET without "
|
|
151
|
+
"setting retrieve_as_bitwise=True"
|
|
152
|
+
)
|
|
153
|
+
if self.retrieve_as_bitwise:
|
|
154
|
+
self._bitmap = {
|
|
155
|
+
value: 2**idx for idx, value in enumerate(self.values)
|
|
156
|
+
}
|
|
157
|
+
self._bitmap.update(
|
|
158
|
+
(2**idx, value) for idx, value in enumerate(self.values)
|
|
159
|
+
)
|
|
160
|
+
length = max([len(v) for v in values] + [0])
|
|
161
|
+
kw.setdefault("length", length)
|
|
162
|
+
super().__init__(**kw)
|
|
163
|
+
|
|
164
|
+
def column_expression(self, colexpr):
|
|
165
|
+
if self.retrieve_as_bitwise:
|
|
166
|
+
return sql.type_coerce(
|
|
167
|
+
sql.type_coerce(colexpr, sqltypes.Integer) + 0, self
|
|
168
|
+
)
|
|
169
|
+
else:
|
|
170
|
+
return colexpr
|
|
171
|
+
|
|
172
|
+
def result_processor(self, dialect, coltype):
|
|
173
|
+
if self.retrieve_as_bitwise:
|
|
174
|
+
|
|
175
|
+
def process(value):
|
|
176
|
+
if value is not None:
|
|
177
|
+
value = int(value)
|
|
178
|
+
|
|
179
|
+
return set(util.map_bits(self._bitmap.__getitem__, value))
|
|
180
|
+
else:
|
|
181
|
+
return None
|
|
182
|
+
|
|
183
|
+
else:
|
|
184
|
+
super_convert = super().result_processor(dialect, coltype)
|
|
185
|
+
|
|
186
|
+
def process(value):
|
|
187
|
+
if isinstance(value, str):
|
|
188
|
+
# MySQLdb returns a string, let's parse
|
|
189
|
+
if super_convert:
|
|
190
|
+
value = super_convert(value)
|
|
191
|
+
return set(re.findall(r"[^,]+", value))
|
|
192
|
+
else:
|
|
193
|
+
# mysql-connector-python does a naive
|
|
194
|
+
# split(",") which throws in an empty string
|
|
195
|
+
if value is not None:
|
|
196
|
+
value.discard("")
|
|
197
|
+
return value
|
|
198
|
+
|
|
199
|
+
return process
|
|
200
|
+
|
|
201
|
+
def bind_processor(self, dialect):
|
|
202
|
+
super_convert = super().bind_processor(dialect)
|
|
203
|
+
if self.retrieve_as_bitwise:
|
|
204
|
+
|
|
205
|
+
def process(value):
|
|
206
|
+
if value is None:
|
|
207
|
+
return None
|
|
208
|
+
elif isinstance(value, (int, str)):
|
|
209
|
+
if super_convert:
|
|
210
|
+
return super_convert(value)
|
|
211
|
+
else:
|
|
212
|
+
return value
|
|
213
|
+
else:
|
|
214
|
+
int_value = 0
|
|
215
|
+
for v in value:
|
|
216
|
+
int_value |= self._bitmap[v]
|
|
217
|
+
return int_value
|
|
218
|
+
|
|
219
|
+
else:
|
|
220
|
+
|
|
221
|
+
def process(value):
|
|
222
|
+
# accept strings and int (actually bitflag) values directly
|
|
223
|
+
if value is not None and not isinstance(value, (int, str)):
|
|
224
|
+
value = ",".join(value)
|
|
225
|
+
|
|
226
|
+
if super_convert:
|
|
227
|
+
return super_convert(value)
|
|
228
|
+
else:
|
|
229
|
+
return value
|
|
230
|
+
|
|
231
|
+
return process
|
|
232
|
+
|
|
233
|
+
def adapt(self, impltype, **kw):
|
|
234
|
+
kw["retrieve_as_bitwise"] = self.retrieve_as_bitwise
|
|
235
|
+
return util.constructor_copy(self, impltype, *self.values, **kw)
|
|
236
|
+
|
|
237
|
+
def __repr__(self):
|
|
238
|
+
return util.generic_repr(
|
|
239
|
+
self,
|
|
240
|
+
to_inspect=[SET, _StringType],
|
|
241
|
+
additional_kw=[
|
|
242
|
+
("retrieve_as_bitwise", False),
|
|
243
|
+
],
|
|
244
|
+
)
|
|
@@ -0,0 +1,141 @@
|
|
|
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
|
+
# mypy: ignore-errors
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
from ... import exc
|
|
11
|
+
from ... import util
|
|
12
|
+
from ...sql import coercions
|
|
13
|
+
from ...sql import elements
|
|
14
|
+
from ...sql import operators
|
|
15
|
+
from ...sql import roles
|
|
16
|
+
from ...sql.base import _generative
|
|
17
|
+
from ...sql.base import Generative
|
|
18
|
+
from ...util.typing import Self
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class match(Generative, elements.BinaryExpression):
|
|
22
|
+
"""Produce a ``MATCH (X, Y) AGAINST ('TEXT')`` clause.
|
|
23
|
+
|
|
24
|
+
E.g.::
|
|
25
|
+
|
|
26
|
+
from sqlalchemy import desc
|
|
27
|
+
from sqlalchemy.dialects.mysql import match
|
|
28
|
+
|
|
29
|
+
match_expr = match(
|
|
30
|
+
users_table.c.firstname,
|
|
31
|
+
users_table.c.lastname,
|
|
32
|
+
against="Firstname Lastname",
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
stmt = (
|
|
36
|
+
select(users_table)
|
|
37
|
+
.where(match_expr.in_boolean_mode())
|
|
38
|
+
.order_by(desc(match_expr))
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
Would produce SQL resembling::
|
|
42
|
+
|
|
43
|
+
SELECT id, firstname, lastname
|
|
44
|
+
FROM user
|
|
45
|
+
WHERE MATCH(firstname, lastname) AGAINST (:param_1 IN BOOLEAN MODE)
|
|
46
|
+
ORDER BY MATCH(firstname, lastname) AGAINST (:param_2) DESC
|
|
47
|
+
|
|
48
|
+
The :func:`_mysql.match` function is a standalone version of the
|
|
49
|
+
:meth:`_sql.ColumnElement.match` method available on all
|
|
50
|
+
SQL expressions, as when :meth:`_expression.ColumnElement.match` is
|
|
51
|
+
used, but allows to pass multiple columns
|
|
52
|
+
|
|
53
|
+
:param cols: column expressions to match against
|
|
54
|
+
|
|
55
|
+
:param against: expression to be compared towards
|
|
56
|
+
|
|
57
|
+
:param in_boolean_mode: boolean, set "boolean mode" to true
|
|
58
|
+
|
|
59
|
+
:param in_natural_language_mode: boolean , set "natural language" to true
|
|
60
|
+
|
|
61
|
+
:param with_query_expansion: boolean, set "query expansion" to true
|
|
62
|
+
|
|
63
|
+
.. versionadded:: 1.4.19
|
|
64
|
+
|
|
65
|
+
.. seealso::
|
|
66
|
+
|
|
67
|
+
:meth:`_expression.ColumnElement.match`
|
|
68
|
+
|
|
69
|
+
"""
|
|
70
|
+
|
|
71
|
+
__visit_name__ = "mysql_match"
|
|
72
|
+
|
|
73
|
+
inherit_cache = True
|
|
74
|
+
|
|
75
|
+
def __init__(self, *cols, **kw):
|
|
76
|
+
if not cols:
|
|
77
|
+
raise exc.ArgumentError("columns are required")
|
|
78
|
+
|
|
79
|
+
against = kw.pop("against", None)
|
|
80
|
+
|
|
81
|
+
if against is None:
|
|
82
|
+
raise exc.ArgumentError("against is required")
|
|
83
|
+
against = coercions.expect(
|
|
84
|
+
roles.ExpressionElementRole,
|
|
85
|
+
against,
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
left = elements.BooleanClauseList._construct_raw(
|
|
89
|
+
operators.comma_op,
|
|
90
|
+
clauses=cols,
|
|
91
|
+
)
|
|
92
|
+
left.group = False
|
|
93
|
+
|
|
94
|
+
flags = util.immutabledict(
|
|
95
|
+
{
|
|
96
|
+
"mysql_boolean_mode": kw.pop("in_boolean_mode", False),
|
|
97
|
+
"mysql_natural_language": kw.pop(
|
|
98
|
+
"in_natural_language_mode", False
|
|
99
|
+
),
|
|
100
|
+
"mysql_query_expansion": kw.pop("with_query_expansion", False),
|
|
101
|
+
}
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
if kw:
|
|
105
|
+
raise exc.ArgumentError("unknown arguments: %s" % (", ".join(kw)))
|
|
106
|
+
|
|
107
|
+
super().__init__(left, against, operators.match_op, modifiers=flags)
|
|
108
|
+
|
|
109
|
+
@_generative
|
|
110
|
+
def in_boolean_mode(self) -> Self:
|
|
111
|
+
"""Apply the "IN BOOLEAN MODE" modifier to the MATCH expression.
|
|
112
|
+
|
|
113
|
+
:return: a new :class:`_mysql.match` instance with modifications
|
|
114
|
+
applied.
|
|
115
|
+
"""
|
|
116
|
+
|
|
117
|
+
self.modifiers = self.modifiers.union({"mysql_boolean_mode": True})
|
|
118
|
+
return self
|
|
119
|
+
|
|
120
|
+
@_generative
|
|
121
|
+
def in_natural_language_mode(self) -> Self:
|
|
122
|
+
"""Apply the "IN NATURAL LANGUAGE MODE" modifier to the MATCH
|
|
123
|
+
expression.
|
|
124
|
+
|
|
125
|
+
:return: a new :class:`_mysql.match` instance with modifications
|
|
126
|
+
applied.
|
|
127
|
+
"""
|
|
128
|
+
|
|
129
|
+
self.modifiers = self.modifiers.union({"mysql_natural_language": True})
|
|
130
|
+
return self
|
|
131
|
+
|
|
132
|
+
@_generative
|
|
133
|
+
def with_query_expansion(self) -> Self:
|
|
134
|
+
"""Apply the "WITH QUERY EXPANSION" modifier to the MATCH expression.
|
|
135
|
+
|
|
136
|
+
:return: a new :class:`_mysql.match` instance with modifications
|
|
137
|
+
applied.
|
|
138
|
+
"""
|
|
139
|
+
|
|
140
|
+
self.modifiers = self.modifiers.union({"mysql_query_expansion": True})
|
|
141
|
+
return self
|