Unique-index lookups maintained from the schema #28
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#28
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?
cache.get(state, table, key)looks up by primary key only. Any other unique column requires a full scan throughcache.iter.Once the generator emits unique constraints, the cache can maintain a lookup per unique column the same way it maintains the pk index — the Godot SDK generates one index object per constraint doing exactly this (
core/module_table_unique_index.gd).Why it matters in practice
The query shape this serves is the common one in a game: a
playertable keyed by an auto-incrementid, with a uniqueidentitycolumn. "Which row is me?" is a lookup by identity, not by pk, and it runs on every connect and after every reconnect. Today that is O(n) over every cached player, on the main thread.Shape
Maintained inside
cache.apply_database_updatealongside the existing pk store:The correctness detail that makes this worth writing carefully: a unique column's value can change. When an update alters the indexed column, the old key must be erased before the new one is written, or the index keeps a stale entry pointing at a row that no longer holds that value. The Godot implementation handles this explicitly, and it is the case a naive version gets wrong.
Interaction with #21: update synthesis and index maintenance are looking at the same delete/insert pair. Whichever lands second should reuse the pairing the first established rather than diffing twice.
Acceptance
Unit tests in
dev/test/test_cache.lua: lookup hit and miss, a value change moving the entry and leaving no stale key, a delete removing the entry, and the index survivingdrop_table/drop_all.Priority
Medium, and cheap once the schema carries constraints. Not a blocker —
cache.iteris a correct if slow answer — but it is the difference between the cache being a store and being a database.