Skip to content

fix(types): accept scalar values in jsonb cast/dump/load#118

Merged
Taure merged 2 commits into
mainfrom
fix/jsonb-accept-scalars
May 14, 2026
Merged

fix(types): accept scalar values in jsonb cast/dump/load#118
Taure merged 2 commits into
mainfrom
fix/jsonb-accept-scalars

Conversation

@Taure
Copy link
Copy Markdown
Owner

@Taure Taure commented May 14, 2026

Summary

`cast(jsonb, ...)` only matched maps, lists, and binaries; any other JSON-compatible scalar (integer, float, boolean) was rejected as `cannot cast to jsonb`. Postgres jsonb accepts any valid JSON at the root of a jsonb column, including scalars, so this was an unnecessary restriction.

  • `cast/2`: add `is_number(V); is_boolean(V)` clause
  • `dump/2`: same scalar clause; emits via `json_encode/1`
  • `load/2`: round-trip scalars and lists back to callers

`null` continues to land in the generic `cast(, null) -> {ok, undefined}` and `load(, null) -> {ok, undefined}` clauses, preserving the existing convention that SQL NULL surfaces as the `undefined` atom.

Why

Found via barrow's bank-on-extract loop on top of asobi_lua. Scripts want to do:

```lua
game.storage.player_set(pid, "barrow", "run_loot", 5)
```

but currently have to wrap the integer as `{ n = 5 }` because the asobi_storage changeset rejects the scalar. The asobi_lua-side coercion was already widened in widgrensit/asobi_lua#46; this PR closes the kura-side gap so the wrapper can be dropped entirely.

Test plan

  • Updated 2 existing edge tests that asserted scalars were rejected (`cast_jsonb_non_string_non_map_non_list_test`, `load_jsonb_error_test`) — renamed to `*_scalar_test` and now assert successful round-trips.
  • Added `dump_jsonb_scalar_test` for the dump path.
  • `rebar3 eunit --module kura_types_edge_tests` — 95/95 pass.
  • `rebar3 fmt --check` clean.
  • `rebar3 xref` clean.
  • Pre-existing `kura_stress_tests` failures (pool saturation, concurrent reads) are unchanged and unrelated.

Downstream

Taure added 2 commits May 14, 2026 15:30
`cast(jsonb, ...)` only matched maps, lists, and binaries — any other
JSON-compatible scalar (integer, float, boolean) was rejected as
`cannot cast to jsonb`. That was inherited from a time when jsonb was
treated as "structured", but postgres accepts any valid JSON at the
root of a jsonb column, including scalars.

Add the missing clauses to `cast/2`, `dump/2`, and `load/2` so numbers
and booleans round-trip. `null` continues to land in the generic
`cast(_, null) -> {ok, undefined}` and `load(_, null) -> {ok, undefined}`
clauses higher up, keeping the kura convention of materialising SQL
NULLs as the `undefined` atom.

Found via barrow's bank-on-extract loop: scripts wanted
`game.storage.player_set(pid, "barrow", "run_loot", 5)` but had to
wrap as `{ n = 5 }` because the changeset cast rejected the scalar.
Pairs with the asobi_lua-side coercion fix in widgrensit/asobi_lua#46.
elvis.config was an untracked file in the worktree from an unrelated
experiment that got swept into the jsonb commit via `git add -A`.
It's not part of this PR's scope.
@github-actions
Copy link
Copy Markdown

🟢 Code Coverage — 91.7%

2175 of 2373 lines covered.


✅ ELP Lint

No diagnostics.


ℹ️ 11 OTP CVEs auto-ignored (already fixed in running version)

These CVEs are patched in the installed OTP version but NVD data
has not been updated to reflect this. They are excluded from the
scan via an auto-generated .trivyignore.

CVE Details
CVE-2026-23943 Fixed in 28.4.1, running 28.4.1 — Pre-auth SSH DoS via unbounded zlib inflate
CVE-2026-23942 Fixed in 28.4.1, running 28.4.1 — SFTP root escape via component-agnostic prefix check in ssh_sftpd
CVE-2026-23941 Fixed in 28.4.1, running 28.4.1 — Request smuggling via first-wins Content-Length parsing in inets httpd
CVE-2026-21620 Fixed in 28.3.2, running 28.4.1 — TFTP Path Traversal
CVE-2016-1000107 Fixed in 28.0.4, running 28.4.1 — Httpd CGI Scripts Environment Variable Pollution AKA "httpoxy"
CVE-2025-58050 Fixed in 28.0.3, running 28.4.1 — Buffer Read Overflow on Regular Expressions with (*scs:) and (*ACCEPT)
CVE-2025-48038 Fixed in 28.0.3, running 28.4.1 — SSH Unverified File Handles can Cause Excessive Use of System Resources
CVE-2025-48039 Fixed in 28.0.3, running 28.4.1 — SSH Unverified Paths can Cause Excessive Use of System Resources
CVE-2025-48040 Fixed in 28.0.3, running 28.4.1 — SSH Malicious Key Exchange Messages may Lead to Excessive Resource Consumption
CVE-2025-48041 Fixed in 28.0.3, running 28.4.1 — SSH_FXP_OPENDIR may Lead to Exhaustion of File Handles
CVE-2025-4748 Fixed in 28.0.1, running 28.4.1 — Absolute Path in Zip Module

@Taure Taure merged commit 64c487a into main May 14, 2026
16 checks passed
@Taure Taure deleted the fix/jsonb-accept-scalars branch May 14, 2026 15:12
Taure added a commit to widgrensit/asobi that referenced this pull request May 14, 2026
Picks up Taure/kura#118 — `cast/dump/load(jsonb, ...)` now accept JSON
scalars (integer/float/boolean) so callers no longer have to wrap them
as `#{<<"n">> => N}` to land in a jsonb column.
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.

1 participant