Skip to content

fix(postgrest): accept CLI-generated types in insert/upsert/update - #1613

Open
twelfthlabor wants to merge 3 commits into
supabase:mainfrom
twelfthlabor:fix/typeddict-insert-1443
Open

twelfthlabor wants to merge 3 commits into
supabase:mainfrom
twelfthlabor:fix/typeddict-insert-1443

Conversation

@twelfthlabor

@twelfthlabor twelfthlabor commented Sep 4, 2026

Copy link
Copy Markdown

Issue: insert/upsert/update type their body as JSON, so CLI-generated TypedDicts with datetime/date/time/UUID/Decimal fields fail type checking (#1443). Widening the alias alone was not sufficient: mypy and pyright reject a TypedDict where a Mapping with concrete value types is expected, and httpx serializes json= with stdlib json.dumps, which raises TypeError on those values at request time.

Fix:

  • Add a JSONSerializableInput alias for write operations that also accepts TypedDict rows via their __required_keys__/__optional_keys__ markers, while plain mappings keep the strict JSONSerializable value types. The strict JSON alias is unchanged, so response validation stays strict.
  • Normalize outbound bodies to JSON-safe primitives via pydantic in RequestConfig (datetime to ISO strings, UUID/Decimal to strings). Plain JSON passes through unchanged, including non-finite floats, which still fail at request time instead of silently becoming null. The httpx request path itself is unchanged.

Tests: insert/upsert/update with datetime, date, time, UUID, and Decimal values, a static check that the CLI-generated TypedDict now type-checks, a negative static check that plain mappings with unserializable values still fail, a non-finite floats case, plus TypedDict runtime validation and a plain-JSON unchanged case, in both sync and async suites. ruff and mypy clean.

Fixes #1443

insert/upsert/update typed their body as JSON, so CLI-generated TypedDicts with datetime/date/time/UUID/Decimal fields failed type checking. Widening the alias alone is not enough: httpx serializes json= with stdlib json.dumps, which raises TypeError on those values at runtime.

Add a JSONSerializable input alias (strict JSON type left unchanged for response validation) and normalize outbound bodies to JSON-safe primitives via pydantic in RequestConfig, keeping the httpx request path as-is.

Fixes supabase#1443
@twelfthlabor
twelfthlabor requested review from a team and o-santi as code owners September 4, 2026 02:00
mypy and pyright reject a TypedDict where Mapping[str, <concrete>] is
expected, so the JSONSerializable alias still failed the pattern from
the issue. Add a write-only JSONSerializableInput alias that also accepts
TypedDict classes via their __required_keys__/__optional_keys__ markers;
plain mappings keep the strict JSONSerializable value types. Also cast the
encoder result to JSON so the package's mypy target passes.

Static regression helpers in the request-builder tests fail on the
previous annotations and pass here.
dump_python(mode="json") turns nan/inf into null, so a request that used
to fail client-side (httpx uses allow_nan=False) would silently write
SQL NULL. Use pydantic_core.to_jsonable_python with inf_nan_mode
"constants" so datetime/UUID/Decimal normalization is unchanged while
non-finite floats keep the pre-existing behavior. Covered in both test
suites.
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.

insert does not expect TypedDict provided by generated types

1 participant