-
-
Notifications
You must be signed in to change notification settings - Fork 1k
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
Respond with HTTP 200 instead of 201 when no rows inserted #1070
Comments
The |
This could work for both tables and views, I think. Although it probably does not play nicely with batch upserts, because once a column is updated, the GUC will be "updated". It might be possible to adjust this, by using two GUCs as counters instead.
|
@steve-chavez The design for this fix/feature seems rather vague. I am thinking of implementing it the following way:
I am not very familiar with PostgreSQL IO yet, let me know other things that need to be changed for this fix. |
@taimoorzaeem Looks good. Go ahead 👍 |
@steve-chavez @wolfgangwalther How do I add and increment local GUCs in the middle of the query? For example, consider this: postgrest/src/PostgREST/Query/QueryBuilder.hs Lines 85 to 105 in 57fa271
To count the number of inserts and updates I would have to repeatedly read with something like It seems too complicated to be added in this query. Besides I don't think we can use |
@taimoorzaeem Yes, I see that it gets a bit complex for batch upserts. To answer your question, the
This is how it would look like (maybe nullif is not necessary, but does some wonky things when testing): where coalesce(set_config('pgrst.inserted', (coalesce(nullif(current_setting('pgrst.inserted', true), '')::int, 0) + 1)::text, true),'0') <> '0' The
And it would look like: where coalesce(set_config('pgrst.updated', (coalesce(nullif(current_setting('pgrst.updated', true), '')::int, 0) + 1)::text, true),'0') <> '0' After that you'd follow the logic mentioned by Wolfgang: #1070 (comment) As an example, using the insert into api.projects (id, name)
-- just an example of inserted values values (1-5 already exist)
select id,name from (select 2, 'Windows 11' union all
select 3, 'Android' union all
select 6, 'NixOS' union all
select 5, 'Old OS' union all
select 7, 'New OS') pgrst_values(id,name)
where coalesce(set_config('pgrst.inserted', (coalesce(nullif(current_setting('pgrst.inserted', true), '')::int, 0) + 1)::text, true),'0') <> '0'
on conflict (id)
do update set name = excluded.name
where coalesce(set_config('pgrst.updated', (coalesce(nullif(current_setting('pgrst.updated', true), '')::int, 0) + 1)::text, true),'0') <> '0'
returning 1; EDIT: Suggestion updated in my comment below #1070 (comment) As an alternative to all of the above, we could use a single config WITH pgrst_insert as (
insert into api.projects (id, name)
-- just an example of inserted values values (1-5 already exist)
select id,name from (select 2, 'Windows 11' union all
select 3, 'Android' union all
select 6, 'NixOS' union all
select 5, 'Old OS' union all
select 7, 'New OS') pgrst_values(id,name)
where 'inserted' = set_config('pgrst.mutation', 'inserted', true)
on conflict (id)
do update set name = excluded.name
where 'updated' = set_config('pgrst.mutation', 'updated', true)
returning current_setting('pgrst.mutation') as mutation
)
select count(nullif(mutation, 'updated')) as rows_inserted,
count(nullif(mutation, 'inserted')) as rows_updated,
count(1) as rows_total
from pgrst_insert; I'm not sure if we need the exact quantity of updates/inserts, if not, it could be more performant I think (won't need count and possibly the CTE). |
Btw, to check if the queries are performant, there's a helper for pgbench tests https://github.com/PostgREST/postgrest/tree/main/test/pgbench That isn't part of the test suite but it can be used to share results and see if a query is worth doing. |
OK, I think we do not need to know how many rows are inserted/updated, only if there was at least one insert. If that's so, the query gets simpler: we'll only need to return a flag when it's inserted and finally count if that flag is greater than 0 (it appears at least once). Finally, the query would look like: WITH pgrst_insert as (
insert into api.projects (id, name)
-- just an example of inserted values values (1-5 already exist)
select id,name from (select 2, 'Windows 11' union all
select 3, 'Android' union all
select 6, 'NixOS' union all
select 5, 'Old OS' union all
select 7, 'New OS') pgrst_values(id,name)
where '1' = set_config('pgrst.inserted', '1', true)
on conflict (id)
do update set name = excluded.name
where '0' = set_config('pgrst.inserted', '0', true)
returning current_setting('pgrst.inserted') as inserted
)
select count(nullif(inserted, '0')) > 0 as inserted
from pgrst_insert; |
@laurenceisla @steve-chavez returning current_setting('pgrst.inserted') as inserted Using |
@taimoorzaeem The |
Currently this is happening with POST when the payload is
[]
, see: https://github.com/begriffs/postgrest/blob/108f3cd651a448fad065faf81a2090cee8a8d9fb/test/Feature/InsertSpec.hs#L129-L135And when
Prefer: resolution=ignore-duplicates
is specified and all rows in the payload are duplicates: https://github.com/begriffs/postgrest/blob/108f3cd651a448fad065faf81a2090cee8a8d9fb/test/Feature/UpsertSpec.hs#L95-L101.Also according to RFC, PUT should respond with 200 when the row is updated and with 201 when the row is inserted, currently it's always responding with 200.
These cases can be corrected by using the xmax system column, as described here.
The text was updated successfully, but these errors were encountered: