]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- add a postgresql-specific form of array_agg() that injects the
authorMike Bayer <mike_mp@zzzcomputing.com>
Thu, 27 Aug 2015 15:21:25 +0000 (11:21 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Thu, 27 Aug 2015 15:22:05 +0000 (11:22 -0400)
ARRAY type, references #3132

doc/build/changelog/changelog_11.rst
doc/build/changelog/migration_11.rst
doc/build/dialects/postgresql.rst
lib/sqlalchemy/dialects/postgresql/__init__.py
lib/sqlalchemy/dialects/postgresql/array.py
lib/sqlalchemy/dialects/postgresql/base.py
lib/sqlalchemy/dialects/postgresql/ext.py
lib/sqlalchemy/sql/functions.py
test/dialect/postgresql/test_types.py

index 09d9e0958a1855a94f8617e7043778dabf2ba206..7d076a35c8c3b5148ba67947a3a7d53692308aa7 100644 (file)
@@ -42,7 +42,9 @@
 
         Added support for the SQL-standard function :class:`.array_agg`,
         which automatically returns an :class:`.Array` of the correct type
-        and supports index / slice operations.   As arrays are only
+        and supports index / slice operations, as well as
+        :func:`.postgresql.array_agg`, which returns a :class:`.postgresql.ARRAY`
+        with additional comparison features.   As arrays are only
         supported on Postgresql at the moment, only actually works on
         Postgresql.  Also added a new construct
         :class:`.postgresql.aggregate_order_by` in support of PG's
index 6e37fb04fd886d328d6b2eb87d56d24c4568abab..3a0666dcc0b2c093eb387e4ab86f1f56e8447962 100644 (file)
@@ -275,7 +275,7 @@ which is now available using :class:`.array_agg`::
     from sqlalchemy import func
     stmt = select([func.array_agg(table.c.value)])
 
-A Postgresql element for an aggreagte ORDER BY is also added via
+A Postgresql element for an aggregate ORDER BY is also added via
 :class:`.postgresql.aggregate_order_by`::
 
     from sqlalchemy.dialects.postgresql import aggregate_order_by
@@ -286,6 +286,13 @@ Producing::
 
     SELECT array_agg(table1.a ORDER BY table1.b DESC) AS array_agg_1 FROM table1
 
+The PG dialect itself also provides an :func:`.postgresql.array_agg` wrapper to
+ensure the :class:`.postgresql.ARRAY` type::
+
+    from sqlalchemy.dialects.postgresql import array_agg
+    stmt = select([array_agg(table.c.value).contains('foo')])
+
+
 Additionally, functions like ``percentile_cont()``, ``percentile_disc()``,
 ``rank()``, ``dense_rank()`` and others that require an ordering via
 ``WITHIN GROUP (ORDER BY <expr>)`` are now available via the
index facb2646e4d17208f2f37d72a3a4c3bc0ad7e079..7e2a20ef77aa6985ad06a424445d1c772a4fea01 100644 (file)
@@ -31,6 +31,7 @@ construction arguments, are as follows:
 .. autoclass:: ARRAY
     :members: __init__, Comparator
 
+.. autofunction:: array_agg
 
 .. autofunction:: Any
 
index 2dac6cecc7339ec244e747ca8c4d44b5b9791597..d67f2a07e85d62945df5f857af1fba1c4cf27b61 100644 (file)
@@ -17,7 +17,7 @@ from .base import \
 from .hstore import HSTORE, hstore
 from .json import JSON, JSONB
 from .array import array, ARRAY, Any, All
-from .ext import aggregate_order_by, ExcludeConstraint
+from .ext import aggregate_order_by, ExcludeConstraint, array_agg
 
 from .ranges import INT4RANGE, INT8RANGE, NUMRANGE, DATERANGE, TSRANGE, \
     TSTZRANGE
@@ -29,5 +29,6 @@ __all__ = (
     'INTERVAL', 'ARRAY', 'ENUM', 'dialect', 'array', 'HSTORE',
     'hstore', 'INT4RANGE', 'INT8RANGE', 'NUMRANGE', 'DATERANGE',
     'TSRANGE', 'TSTZRANGE', 'json', 'JSON', 'JSONB', 'Any', 'All',
-    'DropEnumType', 'CreateEnumType', 'ExcludeConstraint', 'aggregate_order_by'
+    'DropEnumType', 'CreateEnumType', 'ExcludeConstraint',
+    'aggregate_order_by', 'array_agg'
 )
index 68c7b0bdb672f33b34432b258beb223fbc3ffb2b..ebdfe16953ce5ba4687bde26a01e545c8dc05570 100644 (file)
@@ -22,7 +22,7 @@ def Any(other, arrexpr, operator=operators.eq):
 
     .. seealso::
 
-        :func:`.expression.any`
+        :func:`.expression.any_`
 
     """
 
@@ -36,7 +36,7 @@ def All(other, arrexpr, operator=operators.eq):
 
     .. seealso::
 
-        :func:`.expression.all`
+        :func:`.expression.all_`
 
     """
 
index 4022db14be174fe08ae393aaff484c6df114ec20..ec12e11451441a9a6fb0e2aaa6b7643041f05afa 100644 (file)
@@ -518,6 +518,11 @@ as well as array literals:
 
 * :class:`.postgresql.array` - array literal
 
+* :func:`.postgresql.array_agg` - ARRAY_AGG SQL function
+
+* :class:`.postgresql.aggregate_order_by` - helper for PG's ORDER BY aggregate
+  function syntax.
+
 JSON Types
 ----------
 
index 8b08cc498680ea6d367fbb732b78750e90d6f0a8..9b2e3fd73390e05bf30b0f73202097248c05c14c 100644 (file)
@@ -7,7 +7,9 @@
 
 from ...sql import expression
 from ...sql import elements
+from ...sql import functions
 from ...sql.schema import ColumnCollectionConstraint
+from .array import ARRAY
 
 
 class aggregate_order_by(expression.ColumnElement):
@@ -152,3 +154,15 @@ static/sql-createtable.html#SQL-CREATETABLE-EXCLUDE
                            initially=self.initially)
         c.dispatch._update(self.dispatch)
         return c
+
+
+def array_agg(*arg, **kw):
+    """Postgresql-specific form of :class:`.array_agg`, ensures
+    return type is :class:`.postgresql.ARRAY` and not
+    the plain :class:`.types.Array`.
+
+    .. versionadded:: 1.1
+
+    """
+    kw['type_'] = ARRAY(functions._type_from_args(arg))
+    return functions.func.array_agg(*arg, **kw)
index d5d0eb7f2637db3012b3d61a9c5e622dbd7d3682..6cfbd12b3bf105ea34bd522f8399cf48e4de33f1 100644 (file)
@@ -661,17 +661,24 @@ class array_agg(GenericFunction):
     The ``func.array_agg(expr)`` construct returns an expression of
     type :class:`.Array`.
 
-    e.g.
+    e.g.::
 
         stmt = select([func.array_agg(table.c.values)[2:5]])
 
     .. versionadded:: 1.1
 
+    .. seealso::
+
+        :func:`.postgresql.array_agg` - PostgreSQL-specific version that
+        returns :class:`.ARRAY`, which has PG-specific operators added.
+
     """
 
+    type = sqltypes.Array
+
     def __init__(self, *args, **kwargs):
         args = [_literal_as_binds(c) for c in args]
-        kwargs.setdefault('type_', sqltypes.Array(_type_from_args(args)))
+        kwargs.setdefault('type_', self.type(_type_from_args(args)))
         kwargs['_parsed_args'] = args
         super(array_agg, self).__init__(*args, **kwargs)
 
index a625e1cee7e6f29bc80d9c156314b7ee41db647f..8eab9d4b97c5e860c2339b6de2462916572c12c5 100644 (file)
@@ -859,6 +859,17 @@ class ArrayTest(AssertsCompiledSQL, fixtures.TestBase):
             "ARRAY[%(param_4)s, %(param_5)s, %(param_6)s]))[%(param_7)s]"
         )
 
+    def test_array_agg_generic(self):
+        expr = func.array_agg(column('q', Integer))
+        is_(expr.type.__class__, types.Array)
+        is_(expr.type.item_type.__class__, Integer)
+
+    def test_array_agg_specific(self):
+        from sqlalchemy.dialects.postgresql import array_agg
+        expr = array_agg(column('q', Integer))
+        is_(expr.type.__class__, postgresql.ARRAY)
+        is_(expr.type.item_type.__class__, Integer)
+
 
 class ArrayRoundTripTest(fixtures.TablesTest, AssertsExecutionResults):