Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Translate PostgreSQL custom aggregates #2383

Merged
merged 1 commit into from
Jul 9, 2022
Merged

Conversation

roji
Copy link
Member

@roji roji commented May 25, 2022

Here's some nice WIP based off of @smitpatel's great work in dotnet/efcore#28092.

This implements the PG-specific aggregate operators (FILTER and ORDER BY), and provides a first implementation of string_agg and array_agg. Really impressive we can do this!

/cc @dotnet/efteam

Closes #2384

.Select(g => new
{
City = g.Key,
FaxNumbers = EF.Functions.ArrayAgg(g.Select(c => c.Fax).OrderBy(id => id))
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This "aggregates" a column into a PG array. This notably can allow loading related entities in a single query without the cartesian explosion (all posts of a blog are simply downloaded as an array).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/cc @Emill

MethodInfo method,
EnumerableExpression source,
IReadOnlyList<SqlExpression> arguments,
IDiagnosticsLogger<DbLoggerCategory.Query> logger)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you need this here? 🤔

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You mean why do I need to "replace" NpgsqlQueryableAggregateMethodTranslator.cs? There are two translations which actually need to be customized for PG (see comments on Count and Sum below), but it's also to support the PG-specific predicate and ordering clauses (which are handled by _sqlExpressionFactory.AggregateFunction)...

Makes sense?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. I didn't notice the subtle difference that translation is calling into AggregateFunction method. Fine to override if you are generating a different translation. I thought it was same code as relational. In the absence of provider translating these methods, relational would provide it.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, the new relational implementation makes sense as the default thing.

{
// These methods accept two enumerable (column) arguments; this is represented in LINQ as a projection from the grouping
// to a tuple of the two columns. Since we generally translate tuples to PostgresRowValueExpression, we take it apart here.
if (source.Selector is not PostgresRowValueExpression rowValueExpression)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@smitpatel here's a translation of an aggregate function with multiple enumerable arguments. See test below for the C# side - as discussed the grouping needs to be projected to a tuple containing the two columns. It looks a bit weird/complex, but it prevents applying different predicate/orderings/distincts which would have been possible had the function accepted two enumerables instead.

What do you think, how does it look?

Funnily enough, since the PG provider translates ValueTuple to PostgresRowValueExpression, that's what we get here. That's also a bit weird, but seems OK.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do have some idea, let's discuss next time we are in office.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BTW @smitpatel at some point we can discuss this too

g => new
{
City = g.Key,
Companies = EF.Functions.JsonbObjectAgg<string, string, Dictionary<string, string>>(
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And probably my last aggregate work for now 😌

We now support the PG jsonb_object_agg function, using it to project out a Dictionary<string,string> out of two arbitrary columns in a table. Can also get a string JSON document (see test above).

(@ajcvickers this goes in the direction of projecting raw JSON data so we can send it directly over HTTP without entity dematerialization).

/cc @smitpatel @maumar @ajcvickers

@roji roji force-pushed the CustomAggregates branch from 97372c6 to 1b5472d Compare June 4, 2022 17:16
@roji roji changed the title WIP on amazing PG aggregate support Translate PostgreSQL custom aggregates Jun 4, 2022
@roji
Copy link
Member Author

roji commented Jun 4, 2022

Rebased on the merged aggregate infra support (#2393), cleaned up and split spatial aggregates out to #2398 (because it relies on upstream tests in dotnet/efcore#28104 (comment), which hasn't yet been merged).

@roji roji force-pushed the CustomAggregates branch from 1b5472d to 9def04f Compare June 4, 2022 17:39
@roji roji force-pushed the CustomAggregates branch 2 times, most recently from d4a9594 to a22027b Compare June 24, 2022 07:25
* string_agg (string.Join)
* array_agg
* json_agg/jsonb_agg
* json_object_agg/jsonb_object_agg
* range_agg, range_intersect_agg
* Aggregate statistics functions

Closes npgsql#2395
Closes npgsql#532
@roji roji force-pushed the CustomAggregates branch from 099498e to b851d08 Compare July 9, 2022 22:13
@roji roji enabled auto-merge (squash) July 9, 2022 22:14
@roji roji merged commit 82a758c into npgsql:main Jul 9, 2022
@roji roji deleted the CustomAggregates branch July 9, 2022 22:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Translate basic aggregate spatial functions
2 participants