From: Anton Kovalevich Date: Fri, 2 Apr 2021 12:41:03 +0000 (+0300) Subject: Fix docs + add match function tests X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=112fa2d23aef88b11530cccbb706e20ac20395f0;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git Fix docs + add match function tests --- diff --git a/lib/sqlalchemy/dialects/mysql/__init__.py b/lib/sqlalchemy/dialects/mysql/__init__.py index 20dd68d8f0..4db05984c2 100644 --- a/lib/sqlalchemy/dialects/mysql/__init__.py +++ b/lib/sqlalchemy/dialects/mysql/__init__.py @@ -49,6 +49,7 @@ from .base import VARCHAR from .base import YEAR from .dml import Insert from .dml import insert +from .expression import match from ...util import compat if compat.py3k: @@ -99,4 +100,5 @@ __all__ = ( "dialect", "insert", "Insert", + "match", ) diff --git a/lib/sqlalchemy/dialects/mysql/expression.py b/lib/sqlalchemy/dialects/mysql/expression.py index 49cdc43fd2..6af57baaed 100644 --- a/lib/sqlalchemy/dialects/mysql/expression.py +++ b/lib/sqlalchemy/dialects/mysql/expression.py @@ -1,5 +1,6 @@ from functools import wraps +from sqlalchemy import exc from sqlalchemy.ext.compiler import compiles from sqlalchemy.sql.elements import ( ColumnElement, @@ -58,9 +59,38 @@ class match(ColumnElement): All positional arguments passed to :func:`.match`, typically should be a :class:`_expression.ColumnElement` instances - :param against: typically scalar expression to be coerced into a ``str`` + :param: against typically scalar expression to be coerced into a ``str`` - :param flags: optional ``dict`` + :param: flags optional ``dict``. Use properties ``in_boolean_mode``, + ``in_natural_language_mode`` and ``with_query_expansion`` to control it: + + match_expr = match( + users_table.c.firstname, + users_table.c.lastname, + against="John Connor", + ) + + print(match_expr) + + # MATCH(firstname, lastname) AGAINST (:param_1) + + print(match_expr.in_boolean_mode) + + # MATCH(firstname, lastname) AGAINST (:param_1 IN BOOLEAN MODE) + + print(match_expr.in_natural_language_mode.with_query_expansion) + + # MATCH(firstname, lastname) AGAINST + # (:param_1 IN NATURAL LANGUAGE MODE WITH QUERY EXPANSION) + + :property: ``in_boolean_mode`` returns new ``match`` object with + set to ``True`` the ``mysql_boolean_mode`` flag + + :property: ``in_natural_language_mode`` returns new ``match`` object with + set to ``True`` the ``mysql_natural_language`` flag + + :property: ``with_query_expansion`` returns new ``match`` object with + set to ``True`` the ``mysql_query_expansion`` flag .. versionadded:: 1.4.4 @@ -77,7 +107,10 @@ class match(ColumnElement): } def __init__(self, *clauselist, against, flags=None): - if len(clauselist) == 1: + clauselist_len = len(clauselist) + if clauselist_len == 0: + raise exc.CompileError("Can not match with no columns") + elif clauselist_len == 1: self.clause = clauselist[0] else: self.clause = ClauseElementBatch(*clauselist, group=False) diff --git a/test/dialect/mysql/test_compiler.py b/test/dialect/mysql/test_compiler.py index a21f191ed9..75f7e4c5de 100644 --- a/test/dialect/mysql/test_compiler.py +++ b/test/dialect/mysql/test_compiler.py @@ -433,12 +433,11 @@ class CompileTest(fixtures.TestBase, AssertsCompiledSQL): def test_match_compile_modifiers(self): matchtable = table("matchtable", column("title", String)) title = matchtable.c.title - dialect = mysql.dialect() self.assert_compile( title.match("somstr", mysql_boolean_mode=False), "MATCH (matchtable.title) AGAINST (%s)", - dialect=dialect, + dialect=self.__dialect__, ) self.assert_compile( @@ -448,7 +447,7 @@ class CompileTest(fixtures.TestBase, AssertsCompiledSQL): mysql_natural_language=True, ), "MATCH (matchtable.title) AGAINST (%s IN NATURAL LANGUAGE MODE)", - dialect=dialect, + dialect=self.__dialect__, ) self.assert_compile( @@ -458,7 +457,7 @@ class CompileTest(fixtures.TestBase, AssertsCompiledSQL): mysql_query_expansion=True, ), "MATCH (matchtable.title) AGAINST (%s WITH QUERY EXPANSION)", - dialect=dialect, + dialect=self.__dialect__, ) self.assert_compile( @@ -470,13 +469,12 @@ class CompileTest(fixtures.TestBase, AssertsCompiledSQL): ), "MATCH (matchtable.title) AGAINST " "(%s IN NATURAL LANGUAGE MODE WITH QUERY EXPANSION)", - dialect=dialect, + dialect=self.__dialect__, ) def test_match_compile_modifiers_fail(self): matchtable = table("matchtable", column("title", String)) title = matchtable.c.title - dialect = mysql.dialect() msg = "Flag combination does not make sence: " \ "mysql_boolean_mode=%s, " \ @@ -491,7 +489,7 @@ class CompileTest(fixtures.TestBase, AssertsCompiledSQL): mysql_natural_language=True, mysql_query_expansion=True, ).compile, - dialect=dialect, + dialect=self.__dialect__, ) assert_raises_message( @@ -501,7 +499,7 @@ class CompileTest(fixtures.TestBase, AssertsCompiledSQL): "somstr", mysql_query_expansion=True, ).compile, - dialect=dialect, + dialect=self.__dialect__, ) assert_raises_message( @@ -511,7 +509,7 @@ class CompileTest(fixtures.TestBase, AssertsCompiledSQL): "somstr", mysql_natural_language=True, ).compile, - dialect=dialect, + dialect=self.__dialect__, ) def test_concat_compile_kw(self): diff --git a/test/dialect/mysql/test_match_expression.py b/test/dialect/mysql/test_match_expression.py new file mode 100644 index 0000000000..97023f7528 --- /dev/null +++ b/test/dialect/mysql/test_match_expression.py @@ -0,0 +1,103 @@ +from sqlalchemy import exc +from sqlalchemy import String +from sqlalchemy.dialects.mysql import base as mysql +from sqlalchemy.dialects.mysql import match +from sqlalchemy.sql import column +from sqlalchemy.sql import table +# from sqlalchemy.sql.expression import literal_column +from sqlalchemy.testing import assert_raises_message +from sqlalchemy.testing import AssertsCompiledSQL +from sqlalchemy.testing import fixtures + + +class MatchExpressionTest(fixtures.TestBase, AssertsCompiledSQL): + + __dialect__ = mysql.dialect() + + matcheble = table( + "user", + column("firstname", String), + column("lastname", String), + ) + + def test_match_expression(self): + firstname = self.matcheble.c.firstname + lastname = self.matcheble.c.lastname + + expr = match(firstname, lastname, against="John Connor") + + self.assert_compile( + expr, + "MATCH (user.firstname, user.lastname) AGAINST (%s)", + dialect=self.__dialect__, + ) + + self.assert_compile( + expr.in_boolean_mode, + "MATCH (user.firstname, user.lastname) AGAINST " + "(%s IN BOOLEAN MODE)", + dialect=self.__dialect__, + ) + + self.assert_compile( + expr.in_natural_language_mode, + "MATCH (user.firstname, user.lastname) AGAINST " + "(%s IN NATURAL LANGUAGE MODE)", + dialect=self.__dialect__, + ) + + self.assert_compile( + expr.with_query_expansion, + "MATCH (user.firstname, user.lastname) AGAINST " + "(%s WITH QUERY EXPANSION)", + dialect=self.__dialect__, + ) + + self.assert_compile( + expr.in_natural_language_mode.with_query_expansion, + "MATCH (user.firstname, user.lastname) AGAINST " + "(%s IN NATURAL LANGUAGE MODE WITH QUERY EXPANSION)", + dialect=self.__dialect__, + ) + + def test_match_expression_fails(self): + firstname = self.matcheble.c.firstname + lastname = self.matcheble.c.lastname + + assert_raises_message( + exc.CompileError, + "Can not match with no columns", + match, + against="John Connor", + ) + + expr = match(firstname, lastname, against="John Connor") + + msg = "Flag combination does not make sence: " \ + "mysql_boolean_mode=%s, " \ + "mysql_natural_language=%s, " \ + "mysql_query_expansion=%s" + + assert_raises_message( + exc.CompileError, + msg % (True, False, True), + expr.in_boolean_mode.with_query_expansion + .compile, + dialect=self.__dialect__, + ) + + assert_raises_message( + exc.CompileError, + msg % (True, True, False), + expr.in_boolean_mode.in_natural_language_mode + .compile, + dialect=self.__dialect__, + ) + + assert_raises_message( + exc.CompileError, + msg % (True, True, True), + expr.in_boolean_mode.in_natural_language_mode.with_query_expansion + .compile, + dialect=self.__dialect__, + )