From 22609d784c96245dba4275f6ebc494b2614aa9a5 Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Thu, 4 Jun 2020 13:28:21 -0400 Subject: [PATCH] Document that type_coerce does not currently imply parenthesization We've had a few issues where the current solution is to use the self_group() method, so document that as the current approach for the parenthesization use case. Whether or not type_coerce() is changed later, this is how it works at the moment. Fixes: #5375 Change-Id: I97414762a87ec8f1fd1adc1b6be5a52e576814ca References: #5344 (cherry picked from commit a4de30c50eb660a08c8d025c158c54a0bd84f051) --- lib/sqlalchemy/sql/elements.py | 41 +++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 15 deletions(-) diff --git a/lib/sqlalchemy/sql/elements.py b/lib/sqlalchemy/sql/elements.py index f050ce9a21..9251894787 100644 --- a/lib/sqlalchemy/sql/elements.py +++ b/lib/sqlalchemy/sql/elements.py @@ -2635,27 +2635,28 @@ class TypeCoerce(ColumnElement): from sqlalchemy import type_coerce - stmt = select([ - type_coerce(log_table.date_string, StringDateTime()) - ]) + stmt = select([type_coerce(log_table.date_string, StringDateTime())]) The above construct will produce a :class:`.TypeCoerce` object, which - renders SQL that labels the expression, but otherwise does not - modify its value on the SQL side:: + does not modify the rendering in any way on the SQL side, with the + possible exception of a generated label if used in a columns clause + context:: SELECT date_string AS anon_1 FROM log When result rows are fetched, the ``StringDateTime`` type processor will be applied to result rows on behalf of the ``date_string`` column. - The rationale for the "anon_1" label is so that the type-coerced - column remains separate in the list of result columns vs. other - type-coerced or direct values of the target column. In order to - provide a named label for the expression, use + + .. note:: the :func:`.type_coerce` construct does not render any + SQL syntax of its own, including that it does not imply + parenthesization. Please use :meth:`.TypeCoerce.self_group` + if explicit parenthesization is required. + + In order to provide a named label for the expression, use :meth:`_expression.ColumnElement.label`:: stmt = select([ - type_coerce( - log_table.date_string, StringDateTime()).label('date') + type_coerce(log_table.date_string, StringDateTime()).label('date') ]) @@ -2672,9 +2673,19 @@ class TypeCoerce(ColumnElement): # literal value "some string" stmt = select([type_coerce("some string", MyStringType)]) - :func:`.type_coerce` is similar to the :func:`.cast` function, - except that it does not render the ``CAST`` expression in the resulting - statement. + When using :func:`.type_coerce` with composed expressions, note that + **parenthesis are not applied**. If :func:`.type_coerce` is being + used in an operator context where the parenthesis normally present from + CAST are necessary, use the :meth:`.TypeCoerce.self_group` method:: + + >>> some_integer = column("someint", Integer) + >>> some_string = column("somestr", String) + >>> expr = type_coerce(some_integer + 5, String) + some_string + >>> print(expr) + someint + :someint_1 || somestr + >>> expr = type_coerce(some_integer + 5, String).self_group() + some_string + >>> print(expr) + (someint + :someint_1) || somestr :param expression: A SQL expression, such as a :class:`_expression.ColumnElement` @@ -2690,7 +2701,7 @@ class TypeCoerce(ColumnElement): :func:`.cast` - """ + """ # noqa self.type = type_api.to_instance(type_) self.clause = _literal_as_binds(expression, type_=self.type) -- 2.39.5