Typed per-table API: db.<table> with on_insert / on_update / on_delete #27
Labels
No labels
area:defold
area:docs
area:infra
area:protocol
area:testing
kind:bug
kind:chore
phase:breadth
phase:core
phase:hardening
phase:slice
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
yuris/spacetimedb-defold#27
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Row changes arrive as one firehose:
on_event(evt)whereevt.counts.eventsis a flat list of{ type, table, row }. Every consumer writes the same dispatch loop — filter by table name, branch on event type, call their own handler.Both peer SDKs offer per-table registration instead. The Godot SDK generates a facade per table (
client.db.<table>.on_insert(cb)/on_update/on_deleteplusremove_*, backed byLocalDatabase.subscribe_to_inserts/updates/deletes); the official SDKs do the same throughctx.db.<table>.Reversing an earlier call
I previously argued against this:
on_eventalready carries every row change, filtering is five lines of user code, and a registration layer is API surface to freeze at 1.0 for no new capability.That was wrong on one point. Once the generator emits column types and unique constraints, a generated table facade is where that schema information becomes usable — typed rows,
findby unique column, and the pk that update synthesis needs all hang off the same object. The per-table API stops being sugar over the event stream and becomes the place the schema lives. Both peer SDKs converged there for that reason.Shape
Generated per table, from the schema module:
Design constraints worth settling before writing code:
on_eventstays. It is the only way to see connection lifecycle, subscription and reducer events, and removing it breaks consumers for no gain. The per-table API is purely additive.init()and is then deleted must be able to unregister infinal(), or the closure captures a deadselfand the next row crashes it. This is the most Defold-specific requirement here — Godot gets it half-free from node lifecycle, and Lua closures have none. Return a handle fromon_insert, or take a token.Acceptance
Unit tests covering: registration and dispatch per table, deregistration actually stopping delivery, a pk table producing one
on_updaterather than delete+insert, a pk-less table producing insert/delete only, and a callback registering another callback mid-dispatch without corrupting the run.dev/example/should use the per-table API for at least one table, so conformance exercises it against a live server.