Fixed #31691 -- Added ordering support to JSONBAgg.
This commit is contained in:
parent
e0cdd0fcf5
commit
a8473b4d34
|
@ -39,8 +39,9 @@ class BoolOr(Aggregate):
|
||||||
function = 'BOOL_OR'
|
function = 'BOOL_OR'
|
||||||
|
|
||||||
|
|
||||||
class JSONBAgg(Aggregate):
|
class JSONBAgg(OrderableAggMixin, Aggregate):
|
||||||
function = 'JSONB_AGG'
|
function = 'JSONB_AGG'
|
||||||
|
template = '%(function)s(%(expressions)s %(ordering)s)'
|
||||||
output_field = JSONField()
|
output_field = JSONField()
|
||||||
|
|
||||||
def convert_value(self, value, expression, connection):
|
def convert_value(self, value, expression, connection):
|
||||||
|
|
|
@ -86,10 +86,21 @@ General-purpose aggregation functions
|
||||||
``JSONBAgg``
|
``JSONBAgg``
|
||||||
------------
|
------------
|
||||||
|
|
||||||
.. class:: JSONBAgg(expressions, filter=None, **extra)
|
.. class:: JSONBAgg(expressions, filter=None, ordering=(), **extra)
|
||||||
|
|
||||||
Returns the input values as a ``JSON`` array.
|
Returns the input values as a ``JSON`` array.
|
||||||
|
|
||||||
|
.. attribute:: ordering
|
||||||
|
|
||||||
|
.. versionadded:: 3.2
|
||||||
|
|
||||||
|
An optional string of a field name (with an optional ``"-"`` prefix
|
||||||
|
which indicates descending order) or an expression (or a tuple or list
|
||||||
|
of strings and/or expressions) that specifies the ordering of the
|
||||||
|
elements in the result list.
|
||||||
|
|
||||||
|
Examples are the same as for :attr:`ArrayAgg.ordering`.
|
||||||
|
|
||||||
``StringAgg``
|
``StringAgg``
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
|
|
|
@ -73,6 +73,9 @@ Minor features
|
||||||
* The new :attr:`.ExclusionConstraint.include` attribute allows creating
|
* The new :attr:`.ExclusionConstraint.include` attribute allows creating
|
||||||
covering exclusion constraints on PostgreSQL 12+.
|
covering exclusion constraints on PostgreSQL 12+.
|
||||||
|
|
||||||
|
* The new :attr:`.JSONBAgg.ordering` attribute determines the ordering of the
|
||||||
|
aggregated elements.
|
||||||
|
|
||||||
:mod:`django.contrib.redirects`
|
:mod:`django.contrib.redirects`
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
|
|
@ -222,6 +222,42 @@ class TestGeneralAggregate(PostgreSQLTestCase):
|
||||||
values = AggregateTestModel.objects.none().aggregate(jsonagg=JSONBAgg('integer_field'))
|
values = AggregateTestModel.objects.none().aggregate(jsonagg=JSONBAgg('integer_field'))
|
||||||
self.assertEqual(values, json.loads('{"jsonagg": []}'))
|
self.assertEqual(values, json.loads('{"jsonagg": []}'))
|
||||||
|
|
||||||
|
def test_json_agg_charfield_ordering(self):
|
||||||
|
ordering_test_cases = (
|
||||||
|
(F('char_field').desc(), ['Foo4', 'Foo3', 'Foo2', 'Foo1']),
|
||||||
|
(F('char_field').asc(), ['Foo1', 'Foo2', 'Foo3', 'Foo4']),
|
||||||
|
(F('char_field'), ['Foo1', 'Foo2', 'Foo3', 'Foo4']),
|
||||||
|
('char_field', ['Foo1', 'Foo2', 'Foo3', 'Foo4']),
|
||||||
|
('-char_field', ['Foo4', 'Foo3', 'Foo2', 'Foo1']),
|
||||||
|
(Concat('char_field', Value('@')), ['Foo1', 'Foo2', 'Foo3', 'Foo4']),
|
||||||
|
(Concat('char_field', Value('@')).desc(), ['Foo4', 'Foo3', 'Foo2', 'Foo1']),
|
||||||
|
)
|
||||||
|
for ordering, expected_output in ordering_test_cases:
|
||||||
|
with self.subTest(ordering=ordering, expected_output=expected_output):
|
||||||
|
values = AggregateTestModel.objects.aggregate(
|
||||||
|
jsonagg=JSONBAgg('char_field', ordering=ordering),
|
||||||
|
)
|
||||||
|
self.assertEqual(values, {'jsonagg': expected_output})
|
||||||
|
|
||||||
|
def test_json_agg_integerfield_ordering(self):
|
||||||
|
values = AggregateTestModel.objects.aggregate(
|
||||||
|
jsonagg=JSONBAgg('integer_field', ordering=F('integer_field').desc()),
|
||||||
|
)
|
||||||
|
self.assertEqual(values, {'jsonagg': [2, 1, 0, 0]})
|
||||||
|
|
||||||
|
def test_json_agg_booleanfield_ordering(self):
|
||||||
|
ordering_test_cases = (
|
||||||
|
(F('boolean_field').asc(), [False, False, True, True]),
|
||||||
|
(F('boolean_field').desc(), [True, True, False, False]),
|
||||||
|
(F('boolean_field'), [False, False, True, True]),
|
||||||
|
)
|
||||||
|
for ordering, expected_output in ordering_test_cases:
|
||||||
|
with self.subTest(ordering=ordering, expected_output=expected_output):
|
||||||
|
values = AggregateTestModel.objects.aggregate(
|
||||||
|
jsonagg=JSONBAgg('boolean_field', ordering=ordering),
|
||||||
|
)
|
||||||
|
self.assertEqual(values, {'jsonagg': expected_output})
|
||||||
|
|
||||||
def test_string_agg_array_agg_ordering_in_subquery(self):
|
def test_string_agg_array_agg_ordering_in_subquery(self):
|
||||||
stats = []
|
stats = []
|
||||||
for i, agg in enumerate(AggregateTestModel.objects.order_by('char_field')):
|
for i, agg in enumerate(AggregateTestModel.objects.order_by('char_field')):
|
||||||
|
|
Loading…
Reference in New Issue