Repository navigation
fix: shape .single() responses after insert, update, upsert and delete - #29
Merged
Merged
Conversation
The single-row content negotiation was only applied to GET requests, so `insert(...).select().single()` got a list back and the client failed with a type error while casting it to a map. Response shaping now happens in one place for every request that returns rows, and a result that does not contain exactly one row answers with the same 406 PGRST116 error PostgREST returns instead of a 200 carrying an `error` key.
grdsdev
approved these changes
Sep 9, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #25
What
.single()setsAccept: application/vnd.pgrst.object+json, and PostgREST answers that with a bare object instead of a list. The mock client only honored that header in theGEThandler, so every mutation that returned rows still answered with a list:The shaping now lives in a single
_createRowsResponsehelper that every handler returning rows goes through: insert, update, upsert, delete and select, including the count and empty-table paths.Error response for a non-single result
Previously a
.single()matching zero or several rows answered200with{'error': 'N rows were found for single query'}, which the client happily returned as if it were the row. It now answers406with the body PostgREST sends:{ "code": "PGRST116", "details": "Results contain 2 rows, application/vnd.pgrst.object+json requires 1 row", "hint": null, "message": "JSON object requested, multiple (or no) rows returned" }so
.single()throws aPostgrestExceptionand.maybeSingle()resolves tonullon zero rows, matching a real project.The separate
Accept: application/jsonbranch that used to shapemaybeSingleonGETis gone. PostgREST returns a list for that media type, and postgrest-dart already narrows it client-side.Tests
Added cases for
.single()and.maybeSingle()after insert, update, upsert and delete, for a single insert of several rows, for a select matching zero or several rows, and for.single()combined with.count(). The suite passes at 106 tests.