Skip to content

Commit 3abaec9

Browse files
onx2bfopsclockwork-labs-bot
authored
More granular table traits (#4775)
# Description of Changes Refactored the Rust SDK table trait surface into composable capabilities and updated Rust codegen to match. [Discord thread](https://discord.com/channels/1037340874172014652/1492137984902959164) ### Motivation The granular traits are a useful type-system cleanup on their own, but the main motivation is to let downstream integration crates like [bevy_stdb](https://github.com/onx2/bevy_stdb) express callback capabilities more directly instead of routing them through broader semantic categories. For example, `bevy_stdb` may want to support bindings like “forward only inserts from this subscribed view as Bevy messages” for a relation that is not semantically an `EventTable`. Today this can still be made to work with broader abstractions, so this is not primarily about enabling new runtime behavior. The value is mostly at compile time: more precise trait bounds, clearer downstream APIs, and better guarantees that a binding only requires the capabilities it actually uses. Concretely, this makes it easier for integration crates to model things like insert-only or delete-only bindings for ordinary tables or views without conflating those behaviors with `EventTable` semantics. Example: ```rust // Current semantic shape: plugin.add_event_table::<LogRow>(|reg, db| reg.bind(db.logs())); // Potential capability-based shape: plugin.add_insert_source::<CharacterRow>(|reg, db| reg.bind(db.characters_near_me())); plugin.add_delete_source::<CharacterRow>(|reg, db| reg.bind(db.characters_near_me())); ``` ### Summary - Added a shared `TableLike` trait for common table handle functionality: - `Row` - `EventContext` - `count` - `iter` - Added capability traits: - `WithInsert` - `WithDelete` - `WithUpdate` # API and ABI breaking changes None. This is additive only. # Expected complexity level and risk 2/5 This is additive but potential risks/complexity are that the surface area of the API is larger and there isn't really overlap between original approach and the additive. So maybe in usage we'll need to consider satisfying those new traits too? # Testing - [x] Ran `cargo check --manifest-path /Users/onx2/Documents/projects/SpacetimeDB/sdks/rust/Cargo.toml` - [x] Ran `cargo test --manifest-path /Users/onx2/Documents/projects/SpacetimeDB/Cargo.toml -p spacetimedb-codegen test_codegen_rust` - [x] Regenerated Rust client bindings using the workspace CLI and verified generated impls match the new trait structure - [ ] Reviewer: regenerate a Rust client with the workspace CLI and confirm the generated bindings compile cleanly --------- Co-authored-by: Zeke Foppa <196249+bfops@users.noreply.github.com> Co-authored-by: clockwork-labs-bot <clockwork-labs-bot@users.noreply.github.com>
1 parent 03e1b13 commit 3abaec9

153 files changed

Lines changed: 6826 additions & 10 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

crates/bindings-typescript/case-conversion-test-client/src/module_bindings/index.ts

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/codegen/src/rust.rs

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,14 @@ pub struct {insert_callback_id}(__sdk::CallbackId);
183183
write!(
184184
out,
185185
"
186+
impl<'ctx> __sdk::TableLike for {table_handle}<'ctx> {{
187+
type Row = {row_type};
188+
type EventContext = super::EventContext;
189+
190+
fn count(&self) -> u64 {{ self.imp.count() }}
191+
fn iter(&self) -> impl Iterator<Item = {row_type}> + '_ {{ self.imp.iter() }}
192+
}}
193+
186194
impl<'ctx> __sdk::EventTable for {table_handle}<'ctx> {{
187195
type Row = {row_type};
188196
type EventContext = super::EventContext;
@@ -203,6 +211,21 @@ impl<'ctx> __sdk::EventTable for {table_handle}<'ctx> {{
203211
self.imp.remove_on_insert(callback.0)
204212
}}
205213
}}
214+
215+
impl<'ctx> __sdk::WithInsert for {table_handle}<'ctx> {{
216+
type InsertCallbackId = {insert_callback_id};
217+
218+
fn on_insert(
219+
&self,
220+
callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static,
221+
) -> {insert_callback_id} {{
222+
{insert_callback_id}(self.imp.on_insert(Box::new(callback)))
223+
}}
224+
225+
fn remove_on_insert(&self, callback: {insert_callback_id}) {{
226+
self.imp.remove_on_insert(callback.0)
227+
}}
228+
}}
206229
"
207230
);
208231
} else {
@@ -213,6 +236,14 @@ impl<'ctx> __sdk::EventTable for {table_handle}<'ctx> {{
213236
out,
214237
"pub struct {delete_callback_id}(__sdk::CallbackId);
215238
239+
impl<'ctx> __sdk::TableLike for {table_handle}<'ctx> {{
240+
type Row = {row_type};
241+
type EventContext = super::EventContext;
242+
243+
fn count(&self) -> u64 {{ self.imp.count() }}
244+
fn iter(&self) -> impl Iterator<Item = {row_type}> + '_ {{ self.imp.iter() }}
245+
}}
246+
216247
impl<'ctx> __sdk::Table for {table_handle}<'ctx> {{
217248
type Row = {row_type};
218249
type EventContext = super::EventContext;
@@ -246,6 +277,36 @@ impl<'ctx> __sdk::Table for {table_handle}<'ctx> {{
246277
self.imp.remove_on_delete(callback.0)
247278
}}
248279
}}
280+
281+
impl<'ctx> __sdk::WithInsert for {table_handle}<'ctx> {{
282+
type InsertCallbackId = {insert_callback_id};
283+
284+
fn on_insert(
285+
&self,
286+
callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static,
287+
) -> {insert_callback_id} {{
288+
{insert_callback_id}(self.imp.on_insert(Box::new(callback)))
289+
}}
290+
291+
fn remove_on_insert(&self, callback: {insert_callback_id}) {{
292+
self.imp.remove_on_insert(callback.0)
293+
}}
294+
}}
295+
296+
impl<'ctx> __sdk::WithDelete for {table_handle}<'ctx> {{
297+
type DeleteCallbackId = {delete_callback_id};
298+
299+
fn on_delete(
300+
&self,
301+
callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static,
302+
) -> {delete_callback_id} {{
303+
{delete_callback_id}(self.imp.on_delete(Box::new(callback)))
304+
}}
305+
306+
fn remove_on_delete(&self, callback: {delete_callback_id}) {{
307+
self.imp.remove_on_delete(callback.0)
308+
}}
309+
}}
249310
"
250311
);
251312

@@ -272,6 +333,21 @@ impl<'ctx> __sdk::TableWithPrimaryKey for {table_handle}<'ctx> {{
272333
self.imp.remove_on_update(callback.0)
273334
}}
274335
}}
336+
337+
impl<'ctx> __sdk::WithUpdate for {table_handle}<'ctx> {{
338+
type UpdateCallbackId = {update_callback_id};
339+
340+
fn on_update(
341+
&self,
342+
callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static,
343+
) -> {update_callback_id} {{
344+
{update_callback_id}(self.imp.on_update(Box::new(callback)))
345+
}}
346+
347+
fn remove_on_update(&self, callback: {update_callback_id}) {{
348+
self.imp.remove_on_update(callback.0)
349+
}}
350+
}}
275351
"
276352
);
277353
}

0 commit comments

Comments
 (0)