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
[Feature request] Add join table attributes on M2M resource embedding #2566
Comments
Thanks for opening that issue - I already suggested exactly this in some other places. Good to be able to track it in a separate issue, though. I'm not certain about the best syntax for this, yet. I remember I made some suggestions somewhere, might need have to dig those out. But I don't think they really "clicked", so far. |
Actually... having said that, the following idea popped up: We could just add the same hint syntax we're already using for embedding on the column-level, too:
From the request perspective this would allow a very natural way of handling the distinct cases, why still allowing the more special cases with name collisions. I didn't think too much about wildcards (e.g. @steve-chavez, WDYT? |
@wolfgangwalther Sounds good! We can bring the junction columns to the target table without special syntax. I've also experimented a bit with the SQL. Right now, with WITH
pgrst_source AS (
SELECT
"test"."users".*,
COALESCE ((
SELECT json_agg("users".*)
FROM (
SELECT
"test"."tasks".*
FROM "test"."tasks", "test"."users_tasks"
WHERE "test"."users"."id" = "test"."users_tasks"."user_id"
AND "test"."tasks"."id" = "test"."users_tasks"."task_id" ) "users")
, '[]') AS "tasks"
FROM "test"."users"
)
SELECT
coalesce(json_agg(_postgrest_t), '[]')::character varying AS body
FROM ( SELECT * FROM pgrst_source) _postgrest_t; To support this, we need to alias the tables on the implicit JOIN(was never fan of implicit, but I couldn't remove it sometime ago). Like this: WITH
pgrst_source AS (
SELECT
"test"."users".*,
COALESCE ((
SELECT json_agg("users".*)
FROM (
SELECT
x.*,
y.created_at
FROM "test"."tasks" x, "test"."users_tasks" y
WHERE "test"."users"."id" = y."user_id"
AND x."id" = y."task_id" ) "users")
, '[]') AS "tasks"
FROM "test"."users"
)
SELECT
coalesce(json_agg(_postgrest_t), '[]')::character varying AS body
FROM ( SELECT * FROM pgrst_source) _postgrest_t;
Reusing the syntax for disambiguation sounds good as well. It's a rare use case(duplicating data?) but it's great we're being correct from the start. |
Not sure about wildcards as well. I think most users would like The other option is to require the user to be explicit and do |
I'm not sure I understand why we need the aliases. In fact I think they make it harder, because we now need to know which of the two table a column that is listed in the request belongs to. Can't we just remove the schema/table qualification in this part of the query like so? WITH
pgrst_source AS (
SELECT
"test"."users".*,
COALESCE ((
SELECT json_agg("users".*)
FROM (
SELECT
"tasks".*,
"created_at"
FROM "test"."tasks", "test"."users_tasks"
WHERE "test"."users"."id" = "test"."users_tasks"."user_id"
AND "test"."tasks"."id" = "test"."users_tasks"."task_id" ) "users")
, '[]') AS "tasks"
FROM "test"."users"
)
SELECT
coalesce(json_agg(_postgrest_t), '[]')::character varying AS body
FROM ( SELECT * FROM pgrst_source) _postgrest_t; In this case PG itself would error with an ambiguous column reference error (or whatever it is called) if "created_at" were to exist in both tables. We would just need to catch that and map it to some 3xx response, similar to what we do with the embedding itself. We would not need any information about which table a given column belongs to, however. Mapping the |
I agree with both. Also, getting just the non-PK (non-FK in fact) columns requires more work/knowledge about the schema.
Ah, that seems overly complicated. I think the default case should allow to select columns just by name from both tables, without any hint. What about:
We could use an "empty hint shortcut" like this:
|
Note that something like this is being done for the postgrest/src/PostgREST/DbRequestBuilder.hs Lines 321 to 324 in ba86b47
So that isn't too bad, and it has been working good.
Looks good! My only concern about adding more syntax is that it adds complexity and consequently more documentation. The embedding disambiguation is already a bit complicated. But since the need for disambiguating junctions cols is rare, I think it's all good.
Hm, I was hoping to eventually document our query grammar and have a spec(discussed on #1398 (comment)). The |
Hi folks ! Any news about the progress of this topic :) ? |
My feeling is that we are currently still in the "design-phase" of that. I don't really have any open questions right now, but nothing is carved in stone either. My feeling is that we do already have quite a few other issues / features ideas open - with some of those a little bit more planned out already. Therefore, I wouldn't bet on this being implemented soon - we tend to have a lot more good ideas than we can actually work on, so if anyone wants to step up and contribute that would be very much welcomed. |
Thank you for the reply. I would like to contribute on that one if possible. Have you some information to give in order to dive into the project ? Thank you ! |
I suggest you start off with setting up your local dev environment as described in https://github.com/PostgREST/postgrest/blob/main/nix/README.md. Then you should add some test-cases, probably to https://github.com/PostgREST/postgrest/blob/main/test/Feature/QuerySpec.hs. I just noticed that we're missing some basic m2m embedding tests there - those seem to be added only for update and rpc right now. So it might be worth adding a few of those, too. In any case your test-cases to request those junction columns should fail at first. At this point, you might enable After you got the query down, you'll need to dive into the codebase itself and probably add some stuff to the query parsing and then do the statement building parts. |
Hi PostgREST team, I think I over estimated myself for that task, I struggle to complete it. So I'll stop working on this topic, but I'll continue to learn the codebase :). |
@maxime-bus You're right - the whole embedding is a bit more complex and not too easy to understand when you start with the codebase. We do have a few issues tagged "beginner" - if you want to pick up any of those to start learning the codebase! https://github.com/PostgREST/postgrest/labels/beginner |
Flattening could solve this one: GET /actors?select=*,films:roles(..films(*),character) HTTP/1.1 Looks more flexible than the above, though a bit more verbose. |
While this is technically true, that wouldn't really be M2M embedding anymore, but rather nested embedding of O2M + M2O. So I'd still consider this a separate feature. |
Should be possible with #2564 as described above.
I think the above proposal is not needed anymore because:
Edit: On second thought, I'll add a test that proves this works with spread embedding and then close the issue. @wolfgangwalther LMK if you agree. |
Hello PostgREST team,
It would be nice, when using resource embedding, to be able to retrieve the data that come from the join table. Here's an example based on the documentation : https://postgrest.org/en/v7.0.0/api.html#resource-embedding
In the example, there is a relationship between
actors
andfilms
, thanks to the join tableroles
. Thanks to that, we can fetch actors and the films they acted in.The JSON response would be something like :
But it would be also nice to get the data
character
coming from tableroles
, which could give the JSON response :Do you think it is possible and a good idea ?
The text was updated successfully, but these errors were encountered: