mirror of
https://github.com/clockworklabs/SpacetimeDB.git
synced 2026-05-13 03:08:40 -04:00
8a0cd87c4f
# Description of Changes To resolve #3875, we added exact-match unique index point lookup support to the C# bindings by introducing and using `datastore_index_scan_point_bsatn`. Previously, generated unique index `Find()` was (in at least one codepath) implemented as: * A range scan (`datastore_index_scan_range_bsatn`) over a BTree bound, then * `SingleOrDefault()` to collapse the results into a single row. When the scan is empty, `SingleOrDefault()` returns `default(T)`. For value-type rows this can manifest as a default-initialized row instead of “missing”, which is what surfaced as “default-ish row” behavior in views. Using `datastore_index_scan_point_bsatn` makes the C# implementation match Rust semantics more closely by performing an exact point lookup and returning: * `null` when no rows are found * the row when exactly one row is found * (defensively) an error if >1 row is returned (unique index invariant violation) Similarly, `datastore_delete_by_index_scan_point_bsatn` was added and used so deletes-by-unique-key are also exact-match point operations rather than range deletes. Runtime updates were made to utilize point scan in `FindSingle(key)` and in both mutable/read-only unique-index paths. To keep this non-breaking for existing modules, codegen now detects whether the table row is a struct or a class and chooses the appropriate base type: * Struct rows: `Find()` returns `Row?` (`Nullable<Row>`). * Class rows: `Find()` returns `Row?` (nullable reference, `null` on miss). # API and ABI breaking changes This change is non-breaking with respect to row type kinds, because class/record table rows continue to work via RefUniqueIndex/ReadOnlyRefUniqueIndex while struct rows use UniqueIndex/ReadOnlyUniqueIndex. API surface changes: * Generated `Find()` return type is now nullable (`Row?`) to correctly represent “missing”. ABI/runtime: * Requires the point-scan hostcall import (`datastore_index_scan_point_bsatn`) to be available; the runtime uses point-scan for unique lookup (and point delete for unique delete). # Expected complexity level and risk Low 2 # Testing - [X] Local testing: repro module + client validate view and direct Find() behavior --------- Signed-off-by: rekhoff <r.ekhoff@clockworklabs.io>