Skip to content

fix: honor ignoreDuplicates in upsert - #28

Merged
spydon merged 1 commit into
mainfrom
fix/upsert-ignore-duplicates
Sep 9, 2026
Merged

spydon merged 1 commit into
mainfrom
fix/upsert-ignore-duplicates

Conversation

@spydon

@spydon spydon commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Fixes #26

Problem

PostgrestQueryBuilder.upsert sends Prefer: resolution=ignore-duplicates when called with ignoreDuplicates: true, and resolution=merge-duplicates otherwise. The request dispatch only recognized merge-duplicates, so an upsert with ignoreDuplicates: true was classified as RequestType.insert and never reached _handleUpsert. The conflicting row was appended as a duplicate:

await mockSupabase.from('users').insert({'id': 1, 'name': 'John Doe'});
await mockSupabase.from('users').upsert(
      {'id': 1, 'name': 'James Bond'},
      ignoreDuplicates: true,
    );
await mockSupabase.from('users').select();
// before: [{id: 1, name: John Doe}, {id: 1, name: James Bond}]
// after:  [{id: 1, name: John Doe}]

Changes

  • The POST dispatch now treats resolution=ignore-duplicates as an upsert alongside resolution=merge-duplicates. As a side effect, postgrestExceptionTrigger now receives RequestType.upsert rather than RequestType.insert for these requests, which is what it should have been.
  • _handleUpsert reads the resolution from the Prefer header. When ignore-duplicates is requested, a row that matches the conflict target is left untouched and no new row is inserted. Rows that do not conflict are still inserted.
  • Skipped rows are left out of the response body, matching what PostgREST returns for INSERT ... ON CONFLICT DO NOTHING RETURNING.

Tests

Three tests were added covering both reproductions from the issue (default id conflict target and an explicit onConflict column) plus a mixed batch where one row conflicts and one does not, asserting both the response body and the resulting table contents. The full suite passes, and dart format and dart analyze --fatal-warnings --fatal-infos are clean.

An upsert with `ignoreDuplicates: true` sends
`Prefer: resolution=ignore-duplicates`, which the request dispatch did
not recognize, so it was classified as an insert and the conflicting row
was added as a duplicate.

Treat both resolutions as upserts and skip conflicting rows instead of
merging them when `ignore-duplicates` is requested. Skipped rows are
left out of the response, matching PostgREST.

Fixes #26
@spydon
spydon merged commit fe35f89 into main Sep 9, 2026
1 check passed
@spydon
spydon deleted the fix/upsert-ignore-duplicates branch September 9, 2026 13:16
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.

ignoreDuplicates is ignored in upsert, the conflicting row is inserted as a duplicate

2 participants