Repository navigation
fix(mapper): type hstore inside json as an object - #70
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
ℹ️ No critical issues. Two small gaps outside the diff are worth a look.
Reviewed changes
I reviewed the full diff: an hstore inside a JSON document is now typed as an object of nullable text in the TypeScript renderer, the JSON Schema writer and the oracle's soundness check.
- Renderer:
src/render.tsmapshstorein itsjsontable toRecord<string, string | null>. Outside a document it staysstring, and the array path wraps it as(Record<string, string | null>)[]. - JSON Schema:
src/schema.tswrites{ type: "object", additionalProperties: { type: ["string", "null"] } }for anhstoreinside a document. - Oracle:
json_admitsinoracle/src/seed.rsnow accepts anhstoreonly as an object whose values are all strings or null. The seed pool also gets realhstoreliterals, since hstore rejects the fallback'1'/'a'. - Coverage: there is a new
oracle/cases/json_hstorecase (plain,json_build_object,json_agg) and a newtests/render.test.tstest. The test passes locally.
The rule is correct. Postgres's JSON writers (json_build_object, json_agg, to_json, row_to_json) use a type's cast to json/jsonb when one exists, and the hstore extension creates both casts, so each of these writes an object. Other oracle cases already use contrib extensions (btree_gist, file_fdw), so create extension hstore will work on CI.
ℹ️ engine/core/src/schema.rs still writes an hstore inside a document as a string
The header of src/schema.ts says its spellings are the engine's (engine/core/src/sch
10000
ema.rs). The record case was added to both files together. After this PR, Type::json_schema in Rust still falls through to {"type": "string", "description": "pg type hstore"} when in_json is set, so the two tables disagree. Nothing ships through the Rust function today, since only its own tests call it. But engine/postgres/src/jsonshape.rs:1902 points to it as the place the renderer's rule is stated, so the two tables are now out of sync. Fixing it is a core edit, which means rebuilding all three engine.wasm. That may be better as a follow-up than as part of this PR.
Technical details
# Keep the Rust JSON Schema table in step with src/schema.ts for hstore
## Affected sites
- engine/core/src/schema.rs:173 — next to `"record" if opts.in_json`, there is no `hstore` arm, so an hstore inside a document falls to the `pg type {name}` string default at line 180
## Required outcome
- `Type::Scalar { name: "hstore" }.json_schema(IN_JSON)` returns `{"type": "object", "additionalProperties": {"type": ["string", "null"]}}`, the same as `typeSchema(scalar("hstore"), "postgres", false, true)`, and the `WIRE` spelling is unchanged
- a test in the existing `tests` module covers it
- all three `packages/<database>/engine.wasm` are rebuilt in one `engine/build.sh` run, since this is a change under `engine/core/`ℹ️ The Postgres docs page doesn't show the new hstore rule
AGENTS.md asks that a change users would notice also update the docs in the same PR. Users will see this one as a different type on hover. The Values inside a document rule in site/content/docs/postgres.mdx lists how values change once they're inside JSON (bigint, numeric, timestamptz, bytea, a row). Its <Pairs> are written in the page itself rather than captured, so a single line covers it, e.g. - `json_build_object('h', 'a=>1, b=>NULL'::hstore)` → `{ h: { a: "1", b: null } }`, plus a few words in the paragraph above it.
claude-opus-5-5 | 𝕏
|
Both findings are fixed in this PR:
|
There was a problem hiding this comment.
✅ No new issues found. Both points from the last review are fixed.
Reviewed changes
This run covers the two commits added since the last review. One updates the Rust JSON Schema table to match src/schema.ts; the other documents the new rule on the Postgres page.
- Rust JSON Schema:
engine/core/src/schema.rsnow has a"hstore" if opts.in_jsonarm. Inside a document it writes the same object of nullable text assrc/schema.ts. A new test checks this and also checks that theWIREspelling stays a string. - Engine artifacts: all three
engine.wasmfiles were rebuilt for the core edit.tests/fingerprint.test.ts,tests/engines.test.tsandtests/render.test.tspass locally at31561a0. - Docs: the "Values inside a document" paragraph in
site/content/docs/postgres.mdxnow covershstore, and a new<Pairs>line showsjson_build_object('h', 'a=>1, b=>NULL'::hstore)→{ h: { a: "1", b: null } }.
claude-opus-5-5 | 𝕏
31561a0 to
557be21
Compare

Postgres writes an
hstoreinside a JSON document as an object of its keys, each value text or null:json_build_object('h', 'a=>1, b=>NULL'::hstore)is{"h" : {"a": "1", "b": null}}, through the extension's cast to JSON, andjson_aggof an hstore column is an array of such objects. The mapper typed itstringthere, and so did the JSON Schema writer and the oracle's soundness check.src/render.ts: an hstore inside a document isRecord<string, string | null>; outside one it stays its text.src/schema.ts: the same as JSON Schema,{ type: "object", additionalProperties: { type: ["string", "null"] } }.oracle/src/seed.rs: the soundness check admits that object, and an hstore column is seeded with real values (no key, one key, a NULL value, a quoted key) instead of the fallback literals, which hstore refuses.oracle/cases/json_hstore: an hstore read plain, insidejson_build_object, and throughjson_agg.Verified:
nub run typecheck,tests/render.test.ts(with a new test),cargo build --workspace --all-targetswith no warning,cargo test -p reylo-oracle,nub run buildinsite/, and the new oracle case on Postgres 18, which passes with the new check and fails with the old one (column j holds {"a":"1","b":null} at .prefs, typed as hstore).