--- /dev/null
+.. change::
+ :tags: usecase, postgresql
+ :tickets: 12432
+
+ When building a PostgreSQL ``ARRAY`` literal using
+ :class:`_postgresql.array` with an empty ``clauses`` argument, use the
+ ``type_`` argument to cast the resulting ``ARRAY[]`` SQL expression.
+ Pull request courtesy Denis Laxalde.
from ... import util
from ...sql import expression
from ...sql import operators
+from ...sql.visitors import InternalTraversal
if TYPE_CHECKING:
from ...engine.interfaces import Dialect
array(["foo", "bar"], type_=CHAR)
+ In particular, when constructing an empty array, the ``type_`` argument
+ will be used as a type cast so that::
+
+ stmt = array([], type_=Integer)
+ print(stmt.compile(dialect=postgresql.dialect()))
+
+ Produces:
+
+ .. sourcecode:: sql
+
+ ARRAY[]::INTEGER[]
+
+ As required by PostgreSQL for empty arrays.
+
Multidimensional arrays are produced by nesting :class:`.array` constructs.
The dimensionality of the final :class:`_types.ARRAY`
type is calculated by
stringify_dialect = "postgresql"
inherit_cache = True
+ _traverse_internals = (
+ expression.ExpressionClauseList._traverse_internals
+ + [("type", InternalTraversal.dp_type)]
+ )
def __init__(
self,
}"""
def visit_array(self, element, **kw):
+ if not element.clauses and not element.type.item_type._isnull:
+ return "ARRAY[]::%s" % element.type.compile(self.dialect)
return "ARRAY[%s]" % self.visit_clauselist(element, **kw)
def visit_slice(self, element, **kw):
String,
)
+ @testing.combinations(
+ ("with type_", Date, "ARRAY[]::DATE[]"),
+ ("no type_", None, "ARRAY[]"),
+ id_="iaa",
+ )
+ def test_array_literal_empty(self, type_, expected):
+ self.assert_compile(postgresql.array([], type_=type_), expected)
+
def test_array_literal(self):
self.assert_compile(
func.array_dims(
),
compare_values=False,
)
+
+ def test_array(self):
+ self._run_cache_key_equal_fixture(
+ lambda: (
+ array([0]),
+ array([0], type_=Integer),
+ array([1], type_=Integer),
+ ),
+ compare_values=False,
+ )
+
+ def test_array_empty(self):
+ self._run_cache_key_fixture(
+ lambda: (
+ array([], type_=Integer),
+ array([], type_=Text),
+ array([0]),
+ ),
+ compare_values=True,
+ )
eq_(connection.execute(stmt).all(), [(4, 1), (3, 2), (2, 3), (1, 4)])
+ def test_array_empty_with_type(self, connection):
+ stmt = select(postgresql.array([], type_=Integer))
+ eq_(connection.execute(stmt).all(), [([],)])
+
def test_plain_old_unnest(self, connection):
fn = func.unnest(
postgresql.array(["one", "two", "three", "four"])
{"_with_options", "_raw_columns", "_setup_joins"},
{"args"},
),
+ "array": ({"operator", "type", "clauses"}, {"clauses", "type_"}),
"next_value": ({"sequence"}, {"seq"}),
}