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

Create aggregate function #37

Open
xoelop opened this issue Mar 16, 2021 · 2 comments
Open

Create aggregate function #37

xoelop opened this issue Mar 16, 2021 · 2 comments
Labels
enhancement New feature or request

Comments

@xoelop
Copy link

xoelop commented Mar 16, 2021

I'm trying to create an aggregate function to concat arrays even if they're empty, as described here

Running this directly on Postgres works

CREATE AGGREGATE array_accum (anyarray)
(
    sfunc = array_cat,
    stype = anyarray,
    initcond = '{}'
);  

But I don't know how to (or if it's even possible) do that with alembic_utils.

I tried adding this to my functions.py file:

ARRAY_ACCUM_DEFINITION = """
(
    sfunc = array_cat,
    stype = anyarray,
    initcond = '{}'
);  
"""

array_distinct = PGFunction(
    schema='public',
    signature='array_accum(anyarray)',
    definition=ARRAY_ACCUM_DEFINITION
)

But if fails because the SQL code outputted tries to create a normal function, instead of an aggregate one, and I couldn't find any references on how to create aggregate functions

[SQL: CREATE FUNCTION "public"."array_accum"(anyarray) (
    sfunc = array_cat,
    stype = anyarray,
    initcond = '{}'
)]
(Background on this error at: http://sqlalche.me/e/13/f405)

So what would be the right way to do this?

Thanks in advance, and thanks for making this library, is great to have things much cleaner

@olirice
Copy link
Owner

olirice commented Mar 16, 2021

Aggregate functions aren't currently supported

The create statements are pretty similar, which makes it look like it'd be a small change to add, but aggregate functions' properties are stored in a different view, pg_aggregate vs pg_function, and the properties are significantly different.

Due to those differences, it needs its own class to correctly detect when a replace operation is needed.

I don't currently have a plan to implement them but would consider a PR that doesn't reduce coverage

That functions definition isn't likely to change much so you could consider creating it using raw sql in the migration. Since it won't be registered with the pg_function view, alembic_utils wont attempt to drop it in subsequent revisions that use --autogenerate.

Alternatively, you could avoid needing a custom aggregate by unpacking the arrays and using array_agg

select
	array_agg(unpacked.elem)
from 
	(
		VALUES
		('{5}'::int[]),
		(null),
		('{1,2,3}'),
		('{}')
	) abc(arr),
	-- Unnest the arrays
	lateral (
		select * from unnest(abc.arr)
	) unpacked(elem)

/* returns
 --------------
| array_agg    |
| int[]        |
 --------------
| {5, 1, 2, 3} |
*/

Hope that helps

Leaving this open to track changes wrt aggregate functions in the future

@xoelop
Copy link
Author

xoelop commented Mar 17, 2021

Thanks for the quick reply! I think I'll go with creating it directly on the DB.

That's the 1st aggregate function I ever created, so I'm missing too much of the big picture to be able to create a PR for this.

@olirice olirice added the enhancement New feature or request label Oct 18, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants