diff --git a/Cargo.lock b/Cargo.lock index 608b20c1617..9f2621d7e47 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2113,6 +2113,16 @@ dependencies = [ "serde", ] +[[package]] +name = "event-table-client" +version = "1.12.0" +dependencies = [ + "anyhow", + "env_logger 0.10.2", + "spacetimedb-sdk", + "test-counter", +] + [[package]] name = "fallible-iterator" version = "0.2.0" @@ -6831,6 +6841,13 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "sdk-test-event-table-module" +version = "0.1.0" +dependencies = [ + "spacetimedb 1.12.0", +] + [[package]] name = "sdk-test-module" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index 369cb19b669..6ffd35cc999 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -48,11 +48,13 @@ members = [ "modules/sdk-test", "modules/sdk-test-connect-disconnect", "modules/sdk-test-procedure", + "modules/sdk-test-event-table", "modules/sdk-test-view", "sdks/rust/tests/test-client", "sdks/rust/tests/test-counter", "sdks/rust/tests/connect_disconnect_client", "sdks/rust/tests/procedure-client", + "sdks/rust/tests/event-table-client", "sdks/rust/tests/view-client", "tools/ci", "tools/upgrade-version", diff --git a/crates/bindings-macro/src/lib.rs b/crates/bindings-macro/src/lib.rs index b06e98ab8f9..428573be84c 100644 --- a/crates/bindings-macro/src/lib.rs +++ b/crates/bindings-macro/src/lib.rs @@ -61,6 +61,7 @@ mod sym { symbol!(unique); symbol!(update); symbol!(default); + symbol!(event); symbol!(u8); symbol!(i8); diff --git a/crates/bindings-macro/src/table.rs b/crates/bindings-macro/src/table.rs index 7bc2940d548..11d60e1a686 100644 --- a/crates/bindings-macro/src/table.rs +++ b/crates/bindings-macro/src/table.rs @@ -19,6 +19,7 @@ pub(crate) struct TableArgs { scheduled: Option, name: Ident, indices: Vec, + event: Option, } enum TableAccess { @@ -71,6 +72,7 @@ impl TableArgs { let mut scheduled = None; let mut name = None; let mut indices = Vec::new(); + let mut event = None; syn::meta::parser(|meta| { match_meta!(match meta { sym::public => { @@ -91,6 +93,10 @@ impl TableArgs { check_duplicate(&scheduled, &meta)?; scheduled = Some(ScheduledArg::parse_meta(meta)?); } + sym::event => { + check_duplicate(&event, &meta)?; + event = Some(meta.path.span()); + } }); Ok(()) }) @@ -107,6 +113,7 @@ impl TableArgs { scheduled, name, indices, + event, }) } } @@ -841,6 +848,18 @@ pub(crate) fn table_impl(mut args: TableArgs, item: &syn::DeriveInput) -> syn::R ); let table_access = args.access.iter().map(|acc| acc.to_value()); + let is_event = args.event.iter().map(|_| { + quote!( + const IS_EVENT: bool = true; + ) + }); + let can_be_lookup_impl = if args.event.is_none() { + quote! { + impl spacetimedb::query_builder::CanBeLookupTable for #original_struct_ident {} + } + } else { + quote! {} + }; let unique_col_ids = unique_columns.iter().map(|col| col.index); let primary_col_id = primary_key_column.clone().into_iter().map(|col| col.index); let sequence_col_ids = sequenced_columns.iter().map(|col| col.index); @@ -966,6 +985,7 @@ pub(crate) fn table_impl(mut args: TableArgs, item: &syn::DeriveInput) -> syn::R const TABLE_NAME: &'static str = #table_name; // the default value if not specified is Private #(const TABLE_ACCESS: spacetimedb::table::TableAccess = #table_access;)* + #(#is_event)* const UNIQUE_COLUMNS: &'static [u16] = &[#(#unique_col_ids),*]; const INDEXES: &'static [spacetimedb::table::IndexDesc<'static>] = &[#(#index_descs),*]; #(const PRIMARY_KEY: Option = Some(#primary_col_id);)* @@ -1077,6 +1097,8 @@ pub(crate) fn table_impl(mut args: TableArgs, item: &syn::DeriveInput) -> syn::R } } + #can_be_lookup_impl + }; let table_query_handle_def = quote! { diff --git a/crates/bindings/src/rt.rs b/crates/bindings/src/rt.rs index cea7adfbbec..287b2efde74 100644 --- a/crates/bindings/src/rt.rs +++ b/crates/bindings/src/rt.rs @@ -716,7 +716,8 @@ pub fn register_table() { .inner .build_table(T::TABLE_NAME, product_type_ref) .with_type(TableType::User) - .with_access(T::TABLE_ACCESS); + .with_access(T::TABLE_ACCESS) + .with_event(T::IS_EVENT); for &col in T::UNIQUE_COLUMNS { table = table.with_unique_constraint(col); diff --git a/crates/bindings/src/table.rs b/crates/bindings/src/table.rs index d7cbdd9b39a..f64d815b862 100644 --- a/crates/bindings/src/table.rs +++ b/crates/bindings/src/table.rs @@ -128,6 +128,7 @@ pub trait TableInternal: Sized { const PRIMARY_KEY: Option = None; const SEQUENCES: &'static [u16]; const SCHEDULE: Option> = None; + const IS_EVENT: bool = false; /// Returns the ID of this table. fn table_id() -> TableId; diff --git a/crates/bindings/tests/ui/views.rs b/crates/bindings/tests/ui/views.rs index f05092569fb..76a24c18d19 100644 --- a/crates/bindings/tests/ui/views.rs +++ b/crates/bindings/tests/ui/views.rs @@ -203,4 +203,37 @@ fn view_nonexistent_table(ctx: &ViewContext) -> Query { ctx.from.xyz().build() } +#[table(name = events, public, event)] +struct Events { + #[unique] + identity: Identity, +} + +/// Event tables CAN be the left/outer table in a semijoin (this should compile) +#[view(name = view_event_table_as_left_ok, public)] +fn view_event_table_as_left_ok(ctx: &ViewContext) -> Query { + ctx.from + .events() + .left_semijoin(ctx.from.player(), |a, b| a.identity.eq(b.identity)) + .build() +} + +/// Event tables cannot be used as the lookup (right) table in a semijoin +#[view(name = view_event_table_left_semijoin, public)] +fn view_event_table_left_semijoin(ctx: &ViewContext) -> Query { + ctx.from + .player_info() + .left_semijoin(ctx.from.events(), |a, b| a.identity.eq(b.identity)) + .build() +} + +/// Event tables cannot be used as the lookup (right) table in a right semijoin +#[view(name = view_event_table_right_semijoin, public)] +fn view_event_table_right_semijoin(ctx: &ViewContext) -> Query { + ctx.from + .player_info() + .right_semijoin(ctx.from.events(), |a, b| a.identity.eq(b.identity)) + .build() +} + fn main() {} diff --git a/crates/bindings/tests/ui/views.stderr b/crates/bindings/tests/ui/views.stderr index 0eda0361ba9..df41aa95d59 100644 --- a/crates/bindings/tests/ui/views.stderr +++ b/crates/bindings/tests/ui/views.stderr @@ -502,3 +502,39 @@ error[E0599]: no method named `xyz` found for struct `QueryBuilder` in the curre | 203 | ctx.from.xyz().build() | ^^^ method not found in `QueryBuilder` + +error[E0277]: the trait bound `Events: CanBeLookupTable` is not satisfied + --> tests/ui/views.rs:226:24 + | +226 | .left_semijoin(ctx.from.events(), |a, b| a.identity.eq(b.identity)) + | ------------- ^^^^^^^^^^^^^^^^^ the trait `CanBeLookupTable` is not implemented for `Events` + | | + | required by a bound introduced by this call + | + = help: the following other types implement trait `CanBeLookupTable`: + Player + PlayerInfo + Test +note: required by a bound in `join::>::left_semijoin` + --> $WORKSPACE/crates/query-builder/src/join.rs + | + | pub fn left_semijoin( + | ^^^^^^^^^^^^^^^^ required by this bound in `join::>::left_semijoin` + +error[E0277]: the trait bound `Events: CanBeLookupTable` is not satisfied + --> tests/ui/views.rs:235:25 + | +235 | .right_semijoin(ctx.from.events(), |a, b| a.identity.eq(b.identity)) + | -------------- ^^^^^^^^^^^^^^^^^ the trait `CanBeLookupTable` is not implemented for `Events` + | | + | required by a bound introduced by this call + | + = help: the following other types implement trait `CanBeLookupTable`: + Player + PlayerInfo + Test +note: required by a bound in `join::>::right_semijoin` + --> $WORKSPACE/crates/query-builder/src/join.rs + | + | pub fn right_semijoin( + | ^^^^^^^^^^^^^^^^ required by this bound in `join::>::right_semijoin` diff --git a/crates/codegen/src/rust.rs b/crates/codegen/src/rust.rs index 47c8097aa37..957d04c9fea 100644 --- a/crates/codegen/src/rust.rs +++ b/crates/codegen/src/rust.rs @@ -168,7 +168,41 @@ impl {accessor_trait} for super::RemoteTables {{ }} pub struct {insert_callback_id}(__sdk::CallbackId); -pub struct {delete_callback_id}(__sdk::CallbackId); +" + ); + + if table.is_event { + // Event tables: implement `EventTable` (insert-only, no delete). + write!( + out, + " +impl<'ctx> __sdk::EventTable for {table_handle}<'ctx> {{ + type Row = {row_type}; + type EventContext = super::EventContext; + + fn count(&self) -> u64 {{ self.imp.count() }} + fn iter(&self) -> impl Iterator + '_ {{ self.imp.iter() }} + + type InsertCallbackId = {insert_callback_id}; + + fn on_insert( + &self, + callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, + ) -> {insert_callback_id} {{ + {insert_callback_id}(self.imp.on_insert(Box::new(callback))) + }} + + fn remove_on_insert(&self, callback: {insert_callback_id}) {{ + self.imp.remove_on_insert(callback.0) + }} +}} +" + ); + } else { + // Persistent tables: implement `Table` (insert + delete). + write!( + out, + "pub struct {delete_callback_id}(__sdk::CallbackId); impl<'ctx> __sdk::Table for {table_handle}<'ctx> {{ type Row = {row_type}; @@ -204,7 +238,8 @@ impl<'ctx> __sdk::Table for {table_handle}<'ctx> {{ }} }} " - ); + ); + } out.delimited_block( " @@ -213,19 +248,21 @@ pub(super) fn register_table(client_cache: &mut __sdk::ClientCache({table_name:?});"); - for (unique_field_ident, unique_field_type_use) in iter_unique_cols(module.typespace_for_generate(), &schema, product_def) { - let unique_field_name = unique_field_ident.deref().to_case(Case::Snake); - let unique_field_type = type_name(module, unique_field_type_use); - writeln!( - out, - "_table.add_unique_constraint::<{unique_field_type}>({unique_field_name:?}, |row| &row.{unique_field_name});", - ); + if !table.is_event { + for (unique_field_ident, unique_field_type_use) in iter_unique_cols(module.typespace_for_generate(), &schema, product_def) { + let unique_field_name = unique_field_ident.deref().to_case(Case::Snake); + let unique_field_type = type_name(module, unique_field_type_use); + writeln!( + out, + "_table.add_unique_constraint::<{unique_field_type}>({unique_field_name:?}, |row| &row.{unique_field_name});", + ); + } } }, "}", ); - if table.primary_key.is_some() { + if table.primary_key.is_some() && !table.is_event { let update_callback_id = table_name_pascalcase.clone() + "UpdateCallbackId"; write!( out, @@ -270,7 +307,7 @@ pub(super) fn parse_table_update( ); for (unique_field_ident, unique_field_type_use) in - iter_unique_cols(module.typespace_for_generate(), &schema, product_def) + iter_unique_cols(module.typespace_for_generate(), &schema, product_def).filter(|_| !table.is_event) { let unique_field_name = unique_field_ident.deref().to_case(Case::Snake); let unique_field_name_pascalcase = unique_field_name.to_case(Case::Pascal); @@ -765,7 +802,16 @@ impl __sdk::__query_builder::HasIxCols for {struct_name} {{ }} }} }}"# - ) + )?; + + if !table.is_event { + writeln!( + out, + "\nimpl __sdk::__query_builder::CanBeLookupTable for {struct_name} {{}}" + )?; + } + + Ok(()) } pub fn implement_query_table_accessor(table: &TableDef, out: &mut impl Write, struct_name: &String) -> fmt::Result { @@ -1379,21 +1425,29 @@ impl __sdk::InModule for DbUpdate {{ ", |out| { for table in iter_tables(module) { - let with_updates = table - .primary_key - .map(|col| { - let pk_field = table.get_column(col).unwrap().name.deref().to_case(Case::Snake); - format!(".with_updates_by_pk(|row| &row.{pk_field})") - }) - .unwrap_or_default(); - let field_name = table_method_name(&table.name); - writeln!( - out, - "diff.{field_name} = cache.apply_diff_to_table::<{}>({:?}, &self.{field_name}){with_updates};", - type_ref_name(module, table.product_type_ref), - table.name.deref(), - ); + if table.is_event { + // Event tables: fire on_insert callbacks without persisting to cache. + writeln!( + out, + "diff.{field_name} = self.{field_name}.into_event_diff();", + ); + } else { + let with_updates = table + .primary_key + .map(|col| { + let pk_field = table.get_column(col).unwrap().name.deref().to_case(Case::Snake); + format!(".with_updates_by_pk(|row| &row.{pk_field})") + }) + .unwrap_or_default(); + + writeln!( + out, + "diff.{field_name} = cache.apply_diff_to_table::<{}>({:?}, &self.{field_name}){with_updates};", + type_ref_name(module, table.product_type_ref), + table.name.deref(), + ); + } } for view in iter_views(module) { let field_name = table_method_name(&view.name); diff --git a/crates/core/src/host/wasm_common/module_host_actor.rs b/crates/core/src/host/wasm_common/module_host_actor.rs index 52fabf85fa2..c55d52adee6 100644 --- a/crates/core/src/host/wasm_common/module_host_actor.rs +++ b/crates/core/src/host/wasm_common/module_host_actor.rs @@ -1254,6 +1254,12 @@ impl InstanceCommon { if phys.reads_from_view(true) || phys.reads_from_view(false) { bail!("view definition cannot read from other views"); } + if source_schema.is_event { + bail!( + "view definition cannot select from event table `{}`", + source_schema.table_name + ); + } if source_schema.row_type != *expected_row_type { bail!( "query returns `{}` but view expects `{}`", diff --git a/crates/core/src/subscription/module_subscription_actor.rs b/crates/core/src/subscription/module_subscription_actor.rs index 95412708e6b..7f9db6bb5ee 100644 --- a/crates/core/src/subscription/module_subscription_actor.rs +++ b/crates/core/src/subscription/module_subscription_actor.rs @@ -552,6 +552,17 @@ impl ModuleSubscriptions { send_err_msg ); + // V1 clients must not subscribe to event tables. + // Old codegen doesn't understand event tables and would accumulate rows in the client cache. + if query.returns_event_table() { + let _ = send_err_msg( + "Subscribing to event tables requires WebSocket v2. \ + Please upgrade your client SDK and regenerate your module bindings." + .into(), + ); + return Ok((None, false)); + } + let mut_tx = ScopeGuard::::into_inner(mut_tx); let (tx, tx_offset, trapped) = @@ -1045,6 +1056,18 @@ impl ModuleSubscriptions { send_err_msg, (None, false) ); + + // V1 clients must not subscribe to event tables. + // Old codegen doesn't understand event tables and would accumulate rows in the client cache. + if queries.iter().any(|q| q.returns_event_table()) { + let _ = send_err_msg( + "Subscribing to event tables requires WebSocket v2. \ + Please upgrade your client SDK and regenerate your module bindings." + .into(), + ); + return Ok((None, false)); + } + let (mut_tx, _) = self.guard_mut_tx(mut_tx, <_>::default()); // We minimize locking so that other clients can add subscriptions concurrently. @@ -1184,6 +1207,15 @@ impl ModuleSubscriptions { subscription_metrics, )?; + // V1 clients must not subscribe to event tables. + // Old codegen doesn't understand event tables and would accumulate rows in the client cache. + if queries.iter().any(|q| q.returns_event_table()) { + return Err(DBError::Other(anyhow::anyhow!( + "Subscribing to event tables requires WebSocket v2. \ + Please upgrade your client SDK and regenerate your module bindings." + ))); + } + let (tx, tx_offset, trapped) = self.materialize_views_and_downgrade_tx(mut_tx, instance, &queries, auth.caller())?; diff --git a/crates/core/src/subscription/module_subscription_manager.rs b/crates/core/src/subscription/module_subscription_manager.rs index e6d6cc76b42..a7474d19ad7 100644 --- a/crates/core/src/subscription/module_subscription_manager.rs +++ b/crates/core/src/subscription/module_subscription_manager.rs @@ -126,6 +126,11 @@ impl Plan { args.into_iter() } + /// Does this subscription return rows from an event table? + pub fn returns_event_table(&self) -> bool { + self.plans.iter().any(|p| p.returns_event_table()) + } + /// Returns the plan fragments that comprise this subscription. /// Will only return one element unless there is a table with multiple RLS rules. pub fn plans_fragments(&self) -> impl Iterator + '_ { diff --git a/crates/core/src/subscription/subscription.rs b/crates/core/src/subscription/subscription.rs index 8d24db68a11..b27dd5e1ce1 100644 --- a/crates/core/src/subscription/subscription.rs +++ b/crates/core/src/subscription/subscription.rs @@ -624,7 +624,7 @@ where I: Iterator>, { Ok(get_all_tables(relational_db, tx)? - .filter(|t| t.table_type == StTableType::User && auth.has_read_access(t.table_access)) + .filter(|t| t.table_type == StTableType::User && auth.has_read_access(t.table_access) && !t.is_event) .map(|schema| { let sql = format!("SELECT * FROM {}", schema.table_name); let tx = SchemaViewer::new(tx, auth); @@ -662,7 +662,7 @@ pub(crate) fn legacy_get_all( .get_all_tables(tx)? .iter() .map(Deref::deref) - .filter(|t| t.table_type == StTableType::User && auth.has_read_access(t.table_access)) + .filter(|t| t.table_type == StTableType::User && auth.has_read_access(t.table_access) && !t.is_event) .map(|src| SupportedQuery { kind: query::Supported::Select, expr: QueryExpr::new(src), diff --git a/crates/core/src/vm.rs b/crates/core/src/vm.rs index d8bb27a1caa..e995cf72cb3 100644 --- a/crates/core/src/vm.rs +++ b/crates/core/src/vm.rs @@ -699,6 +699,7 @@ pub(crate) mod tests { access, None, None, + false, ), )?; let schema = db.schema_for_table_mut(tx, table_id)?; diff --git a/crates/datastore/src/locking_tx_datastore/committed_state.rs b/crates/datastore/src/locking_tx_datastore/committed_state.rs index b597f742336..826042f7887 100644 --- a/crates/datastore/src/locking_tx_datastore/committed_state.rs +++ b/crates/datastore/src/locking_tx_datastore/committed_state.rs @@ -29,8 +29,9 @@ use crate::{ use crate::{ locking_tx_datastore::ViewCallInfo, system_tables::{ - ST_CONNECTION_CREDENTIALS_ID, ST_CONNECTION_CREDENTIALS_IDX, ST_VIEW_COLUMN_ID, ST_VIEW_COLUMN_IDX, ST_VIEW_ID, - ST_VIEW_IDX, ST_VIEW_PARAM_ID, ST_VIEW_PARAM_IDX, ST_VIEW_SUB_ID, ST_VIEW_SUB_IDX, + ST_CONNECTION_CREDENTIALS_ID, ST_CONNECTION_CREDENTIALS_IDX, ST_EVENT_TABLE_ID, ST_EVENT_TABLE_IDX, + ST_VIEW_COLUMN_ID, ST_VIEW_COLUMN_IDX, ST_VIEW_ID, ST_VIEW_IDX, ST_VIEW_PARAM_ID, ST_VIEW_PARAM_IDX, + ST_VIEW_SUB_ID, ST_VIEW_SUB_IDX, }, }; use anyhow::anyhow; @@ -471,6 +472,8 @@ impl CommittedState { self.create_table(ST_VIEW_SUB_ID, schemas[ST_VIEW_SUB_IDX].clone()); self.create_table(ST_VIEW_ARG_ID, schemas[ST_VIEW_ARG_IDX].clone()); + self.create_table(ST_EVENT_TABLE_ID, schemas[ST_EVENT_TABLE_IDX].clone()); + // Insert the sequences into `st_sequences` let (st_sequences, blob_store, pool) = self.get_table_and_blob_store_or_create(ST_SEQUENCE_ID, &schemas[ST_SEQUENCE_IDX]); @@ -617,6 +620,12 @@ impl CommittedState { schema: &Arc, row: &ProductValue, ) -> Result<()> { + // Event table rows in the commitlog are preserved for future replay features + // but don't rebuild state — event tables have no committed state. + if schema.is_event { + return Ok(()); + } + let (table, blob_store, pool) = self.get_table_and_blob_store_or_create(table_id, schema); let (_, row_ref) = match table.insert(pool, blob_store, row) { @@ -1187,6 +1196,24 @@ impl CommittedState { // and the fullness of the page. for (table_id, tx_table) in insert_tables { + // Event tables: record in TxData for commitlog persistence and subscription dispatch, + // but do NOT merge into committed state. + // NOTE: There is no need to call `get_table_and_blob_store_or_create` here. + // The logic for collecting inserts is duplicated, but it's cleaner this way. + if tx_table.get_schema().is_event { + let mut inserts = Vec::with_capacity(tx_table.row_count as usize); + for row_ref in tx_table.scan_rows(&tx_blob_store) { + inserts.push(row_ref.to_product_value()); + } + if !inserts.is_empty() { + let table_name = &tx_table.get_schema().table_name; + tx_data.set_inserts_for_table(table_id, table_name, inserts.into()); + } + let (_schema, _indexes, pages) = tx_table.consume_for_merge(); + self.page_pool.put_many(pages); + continue; + } + let (commit_table, commit_blob_store, page_pool) = self.get_table_and_blob_store_or_create(table_id, tx_table.get_schema()); diff --git a/crates/datastore/src/locking_tx_datastore/datastore.rs b/crates/datastore/src/locking_tx_datastore/datastore.rs index 48361dbf933..5961fe111e7 100644 --- a/crates/datastore/src/locking_tx_datastore/datastore.rs +++ b/crates/datastore/src/locking_tx_datastore/datastore.rs @@ -1614,6 +1614,7 @@ mod tests { StAccess::Public, schedule, pk, + false, ) } diff --git a/crates/datastore/src/locking_tx_datastore/mut_tx.rs b/crates/datastore/src/locking_tx_datastore/mut_tx.rs index 71bf3bda615..101a5feb753 100644 --- a/crates/datastore/src/locking_tx_datastore/mut_tx.rs +++ b/crates/datastore/src/locking_tx_datastore/mut_tx.rs @@ -21,10 +21,10 @@ use crate::{ error::{IndexError, SequenceError, TableError}, system_tables::{ with_sys_table_buf, StClientFields, StClientRow, StColumnFields, StColumnRow, StConstraintFields, - StConstraintRow, StFields as _, StIndexFields, StIndexRow, StRowLevelSecurityFields, StRowLevelSecurityRow, - StScheduledFields, StScheduledRow, StSequenceFields, StSequenceRow, StTableFields, StTableRow, SystemTable, - ST_CLIENT_ID, ST_COLUMN_ID, ST_CONSTRAINT_ID, ST_INDEX_ID, ST_ROW_LEVEL_SECURITY_ID, ST_SCHEDULED_ID, - ST_SEQUENCE_ID, ST_TABLE_ID, + StConstraintRow, StEventTableRow, StFields as _, StIndexFields, StIndexRow, StRowLevelSecurityFields, + StRowLevelSecurityRow, StScheduledFields, StScheduledRow, StSequenceFields, StSequenceRow, StTableFields, + StTableRow, SystemTable, ST_CLIENT_ID, ST_COLUMN_ID, ST_CONSTRAINT_ID, ST_EVENT_TABLE_ID, ST_INDEX_ID, + ST_ROW_LEVEL_SECURITY_ID, ST_SCHEDULED_ID, ST_SEQUENCE_ID, ST_TABLE_ID, }, }; use crate::{execution_context::ExecutionContext, system_tables::StViewColumnRow}; @@ -656,6 +656,7 @@ impl MutTxId { self.insert_st_column(table_schema.columns())?; let schedule = table_schema.schedule.clone(); + let is_event = table_schema.is_event; let mut schema_internal = table_schema; // Extract all indexes, constraints, and sequences from the schema. // We will add them back later with correct ids. @@ -685,6 +686,12 @@ impl MutTxId { table.with_mut_schema(|s| s.schedule.as_mut().unwrap().schedule_id = id); } + // Insert into st_event_table if this is an event table. + if is_event { + let row = StEventTableRow { table_id }; + self.insert_via_serialize_bsatn(ST_EVENT_TABLE_ID, &row)?; + } + // Create the indexes for the table. for index in indices { let col_set = ColSet::from(index.index_algorithm.columns()); diff --git a/crates/datastore/src/locking_tx_datastore/state_view.rs b/crates/datastore/src/locking_tx_datastore/state_view.rs index 1c7401c9e70..59b3e27fe55 100644 --- a/crates/datastore/src/locking_tx_datastore/state_view.rs +++ b/crates/datastore/src/locking_tx_datastore/state_view.rs @@ -4,10 +4,10 @@ use crate::error::{DatastoreError, TableError}; use crate::locking_tx_datastore::mut_tx::{IndexScanPoint, IndexScanRanged}; use crate::system_tables::{ ConnectionIdViaU128, StColumnFields, StColumnRow, StConnectionCredentialsFields, StConnectionCredentialsRow, - StConstraintFields, StConstraintRow, StIndexFields, StIndexRow, StScheduledFields, StScheduledRow, - StSequenceFields, StSequenceRow, StTableFields, StTableRow, StViewFields, StViewParamFields, StViewRow, - SystemTable, ST_COLUMN_ID, ST_CONNECTION_CREDENTIALS_ID, ST_CONSTRAINT_ID, ST_INDEX_ID, ST_SCHEDULED_ID, - ST_SEQUENCE_ID, ST_TABLE_ID, ST_VIEW_ID, ST_VIEW_PARAM_ID, + StConstraintFields, StConstraintRow, StEventTableFields, StIndexFields, StIndexRow, StScheduledFields, + StScheduledRow, StSequenceFields, StSequenceRow, StTableFields, StTableRow, StViewFields, StViewParamFields, + StViewRow, SystemTable, ST_COLUMN_ID, ST_CONNECTION_CREDENTIALS_ID, ST_CONSTRAINT_ID, ST_EVENT_TABLE_ID, + ST_INDEX_ID, ST_SCHEDULED_ID, ST_SEQUENCE_ID, ST_TABLE_ID, ST_VIEW_ID, ST_VIEW_PARAM_ID, }; use anyhow::anyhow; use core::ops::RangeBounds; @@ -159,6 +159,12 @@ pub trait StateView { .unwrap_or(None) .transpose()?; + // Check if this table is an event table by looking up st_event_table. + let is_event = self + .iter_by_col_eq(ST_EVENT_TABLE_ID, StEventTableFields::TableId, value_eq) + .map(|mut iter| iter.next().is_some()) + .unwrap_or(false); + Ok(TableSchema::new( table_id, table_name, @@ -171,6 +177,7 @@ pub trait StateView { table_access, schedule, table_primary_key, + is_event, )) } diff --git a/crates/datastore/src/system_tables.rs b/crates/datastore/src/system_tables.rs index 947e8bcb0d0..b007d4142da 100644 --- a/crates/datastore/src/system_tables.rs +++ b/crates/datastore/src/system_tables.rs @@ -80,6 +80,8 @@ pub const ST_VIEW_COLUMN_ID: TableId = TableId(14); pub const ST_VIEW_SUB_ID: TableId = TableId(15); /// The static ID of the table that tracks view arguments pub const ST_VIEW_ARG_ID: TableId = TableId(16); +/// The static ID of the table that tracks which tables are event tables +pub const ST_EVENT_TABLE_ID: TableId = TableId(17); pub(crate) const ST_CONNECTION_CREDENTIALS_NAME: &str = "st_connection_credentials"; pub const ST_TABLE_NAME: &str = "st_table"; @@ -97,6 +99,7 @@ pub(crate) const ST_VIEW_PARAM_NAME: &str = "st_view_param"; pub(crate) const ST_VIEW_COLUMN_NAME: &str = "st_view_column"; pub(crate) const ST_VIEW_SUB_NAME: &str = "st_view_sub"; pub(crate) const ST_VIEW_ARG_NAME: &str = "st_view_arg"; +pub(crate) const ST_EVENT_TABLE_NAME: &str = "st_event_table"; /// Reserved range of sequence values used for system tables. /// /// Ids for user-created tables will start at `ST_RESERVED_SEQUENCE_RANGE`. @@ -166,6 +169,10 @@ pub fn is_built_in_meta_row(table_id: TableId, row: &ProductValue) -> Result false, // We don't define any system views, so none of the view-related tables can be system meta-descriptors. ST_VIEW_ID | ST_VIEW_PARAM_ID | ST_VIEW_COLUMN_ID | ST_VIEW_SUB_ID | ST_VIEW_ARG_ID => false, + ST_EVENT_TABLE_ID => { + let row: StEventTableRow = to_typed_row(row)?; + table_id_is_reserved(row.table_id) + } TableId(..ST_RESERVED_SEQUENCE_RANGE) => { log::warn!("Unknown system table {table_id:?}"); false @@ -187,7 +194,7 @@ pub enum SystemTable { st_row_level_security, } -pub fn system_tables() -> [TableSchema; 16] { +pub fn system_tables() -> [TableSchema; 17] { [ // The order should match the `id` of the system table, that start with [ST_TABLE_IDX]. st_table_schema(), @@ -206,6 +213,7 @@ pub fn system_tables() -> [TableSchema; 16] { st_view_column_schema(), st_view_sub_schema(), st_view_arg_schema(), + st_event_table_schema(), ] } @@ -250,6 +258,7 @@ pub(crate) const ST_VIEW_PARAM_IDX: usize = 12; pub(crate) const ST_VIEW_COLUMN_IDX: usize = 13; pub(crate) const ST_VIEW_SUB_IDX: usize = 14; pub(crate) const ST_VIEW_ARG_IDX: usize = 15; +pub(crate) const ST_EVENT_TABLE_IDX: usize = 16; macro_rules! st_fields_enum { ($(#[$attr:meta])* enum $ty_name:ident { $($name:expr, $var:ident = $discr:expr,)* }) => { @@ -404,6 +413,10 @@ st_fields_enum!(enum StScheduledFields { "at_column", AtColumn = 4, }); +st_fields_enum!(enum StEventTableFields { + "table_id", TableId = 0, +}); + /// Helper method to check that a system table has the correct fields. /// Does not check field types since those aren't included in `StFields` types. /// If anything in here is not true, the system is completely broken, so it's fine to assert. @@ -567,6 +580,17 @@ fn system_module_def() -> ModuleDef { .with_index_no_accessor_name(btree(StVarFields::Name)) .with_primary_key(StVarFields::Name); + let st_event_table_type = builder.add_type::(); + builder + .build_table( + ST_EVENT_TABLE_NAME, + *st_event_table_type.as_ref().expect("should be ref"), + ) + .with_type(TableType::System) + .with_primary_key(StEventTableFields::TableId) + .with_unique_constraint(StEventTableFields::TableId) + .with_index_no_accessor_name(btree(StEventTableFields::TableId)); + let result = builder .finish() .try_into() @@ -588,6 +612,7 @@ fn system_module_def() -> ModuleDef { validate_system_table::(&result, ST_VIEW_COLUMN_NAME); validate_system_table::(&result, ST_VIEW_SUB_NAME); validate_system_table::(&result, ST_VIEW_ARG_NAME); + validate_system_table::(&result, ST_EVENT_TABLE_NAME); result } @@ -629,6 +654,7 @@ lazy_static::lazy_static! { m.insert("st_view_column_view_id_col_pos_key", ConstraintId(16)); m.insert("st_view_arg_id_key", ConstraintId(17)); m.insert("st_view_arg_bytes_key", ConstraintId(18)); + m.insert("st_event_table_table_id_key", ConstraintId(19)); m }; } @@ -660,6 +686,7 @@ lazy_static::lazy_static! { m.insert("st_view_sub_view_id_arg_id_identity_idx_btree", IndexId(20)); m.insert("st_view_arg_id_idx_btree", IndexId(21)); m.insert("st_view_arg_bytes_idx_btree", IndexId(22)); + m.insert("st_event_table_table_id_idx_btree", IndexId(23)); m }; } @@ -796,6 +823,10 @@ pub fn st_view_arg_schema() -> TableSchema { st_schema(ST_VIEW_ARG_NAME, ST_VIEW_ARG_ID) } +fn st_event_table_schema() -> TableSchema { + st_schema(ST_EVENT_TABLE_NAME, ST_EVENT_TABLE_ID) +} + /// If `table_id` refers to a known system table, return its schema. /// /// Used when restoring from a snapshot; system tables are reinstantiated with this schema, @@ -820,6 +851,7 @@ pub(crate) fn system_table_schema(table_id: TableId) -> Option { ST_VIEW_COLUMN_ID => Some(st_view_column_schema()), ST_VIEW_SUB_ID => Some(st_view_sub_schema()), ST_VIEW_ARG_ID => Some(st_view_arg_schema()), + ST_EVENT_TABLE_ID => Some(st_event_table_schema()), _ => None, } } @@ -1636,6 +1668,33 @@ impl From for ScheduleSchema { } } +/// System Table [ST_EVENT_TABLE_NAME] +/// +/// Tracks which tables are event tables. +/// Event tables persist to commitlog but are not merged into committed state. +/// +/// | table_id | +/// |----------| +/// | 4097 | +#[derive(Debug, Clone, PartialEq, Eq, SpacetimeType)] +#[sats(crate = spacetimedb_lib)] +pub struct StEventTableRow { + pub(crate) table_id: TableId, +} + +impl TryFrom> for StEventTableRow { + type Error = DatastoreError; + fn try_from(row: RowRef<'_>) -> Result { + read_via_bsatn(row) + } +} + +impl From for ProductValue { + fn from(x: StEventTableRow) -> Self { + to_product_value(&x) + } +} + thread_local! { static READ_BUF: RefCell> = const { RefCell::new(Vec::new()) }; } diff --git a/crates/lib/src/db/raw_def/v10.rs b/crates/lib/src/db/raw_def/v10.rs index 7474b6bedfe..6c2daf72b97 100644 --- a/crates/lib/src/db/raw_def/v10.rs +++ b/crates/lib/src/db/raw_def/v10.rs @@ -139,6 +139,13 @@ pub struct RawTableDefV10 { /// Default values for columns in this table. pub default_values: Vec, + + /// Whether this is an event table. + /// + /// Event tables are write-only: their rows are persisted to the commitlog + /// but are NOT merged into committed state. They are only visible to V2 + /// subscribers in the transaction that inserted them. + pub is_event: bool, } /// Marks a particular table column as having a particular default value. @@ -687,6 +694,7 @@ impl RawModuleDefV10Builder { table_type: TableType::User, table_access: TableAccess::Public, default_values: vec![], + is_event: false, }, } } @@ -1044,6 +1052,12 @@ impl RawTableDefBuilderV10<'_> { self } + /// Sets whether this table is an event table. + pub fn with_event(mut self, is_event: bool) -> Self { + self.table.is_event = is_event; + self + } + /// Generates a `RawConstraintDefV10` using the supplied `columns`. pub fn with_unique_constraint(mut self, columns: impl Into) -> Self { let columns = columns.into(); diff --git a/crates/physical-plan/src/plan.rs b/crates/physical-plan/src/plan.rs index b1572040f72..db900c4ac5c 100644 --- a/crates/physical-plan/src/plan.rs +++ b/crates/physical-plan/src/plan.rs @@ -121,6 +121,13 @@ impl ProjectPlan { Self::None(plan) | Self::Name(plan, ..) => plan.reads_from_view(anonymous), } } + + /// Does this plan use an event table as the lookup (rhs) table in a semi-join? + pub fn reads_from_event_table(&self) -> bool { + match self { + Self::None(plan) | Self::Name(plan, ..) => plan.reads_from_event_table(), + } + } } /// Physical plans always terminate with a projection. @@ -228,6 +235,15 @@ impl ProjectListPlan { Self::List(plans, ..) | Self::Agg(plans, ..) => plans.iter().any(|plan| plan.reads_from_view(anonymous)), } } + + /// Does this plan use an event table as the lookup (rhs) table in a semi-join? + pub fn reads_from_event_table(&self) -> bool { + match self { + Self::Limit(plan, _) => plan.reads_from_event_table(), + Self::Name(plans) => plans.iter().any(|plan| plan.reads_from_event_table()), + Self::List(plans, ..) | Self::Agg(plans, ..) => plans.iter().any(|plan| plan.reads_from_event_table()), + } + } } /// Query operators return tuples of rows. @@ -1150,6 +1166,14 @@ impl PhysicalPlan { _ => false, }) } + + /// Does this plan use an event table as the lookup (rhs) table in a semi-join? + pub fn reads_from_event_table(&self) -> bool { + self.any(&|plan| match plan { + Self::IxJoin(join, _) => join.rhs.is_event, + _ => false, + }) + } } /// Scan a table row by row, returning row ids @@ -1510,6 +1534,7 @@ mod tests { StAccess::Public, None, primary_key.map(ColId::from), + false, ))) } diff --git a/crates/query-builder/src/join.rs b/crates/query-builder/src/join.rs index 3240d93c32a..82c58ab245f 100644 --- a/crates/query-builder/src/join.rs +++ b/crates/query-builder/src/join.rs @@ -2,7 +2,7 @@ use crate::TableNameStr; use super::{ expr::{format_expr, BoolExpr}, - table::{ColumnRef, HasCols, HasIxCols, Table}, + table::{CanBeLookupTable, ColumnRef, HasCols, HasIxCols, Table}, Query, }; use std::marker::PhantomData; @@ -66,7 +66,7 @@ pub struct RightSemiJoin { } impl Table { - pub fn left_semijoin( + pub fn left_semijoin( self, right: Table, on: impl Fn(&L::IxCols, &R::IxCols) -> IxJoinEq, @@ -80,7 +80,7 @@ impl Table { } } - pub fn right_semijoin( + pub fn right_semijoin( self, right: Table, on: impl Fn(&L::IxCols, &R::IxCols) -> IxJoinEq, @@ -97,7 +97,7 @@ impl Table { } impl super::FromWhere { - pub fn left_semijoin( + pub fn left_semijoin( self, right: Table, on: impl Fn(&L::IxCols, &R::IxCols) -> IxJoinEq, @@ -111,7 +111,7 @@ impl super::FromWhere { } } - pub fn right_semijoin( + pub fn right_semijoin( self, right: Table, on: impl Fn(&L::IxCols, &R::IxCols) -> IxJoinEq, diff --git a/crates/query-builder/src/table.rs b/crates/query-builder/src/table.rs index b08098a51b3..254510e96b3 100644 --- a/crates/query-builder/src/table.rs +++ b/crates/query-builder/src/table.rs @@ -16,6 +16,11 @@ pub trait HasIxCols { fn ix_cols(name: TableNameStr) -> Self::IxCols; } +/// Marker trait for tables that can appear as the right/inner/lookup +/// table in a semi-join. Event tables do NOT implement this trait, +/// preventing them from being used as the lookup side of a join. +pub trait CanBeLookupTable: HasIxCols {} + pub struct Table { pub(super) table_name: TableNameStr, _marker: PhantomData, diff --git a/crates/schema/src/def.rs b/crates/schema/src/def.rs index 5cc0aaa27d6..1751610993b 100644 --- a/crates/schema/src/def.rs +++ b/crates/schema/src/def.rs @@ -31,6 +31,11 @@ use itertools::Itertools; use spacetimedb_data_structures::error_stream::{CollectAllErrors, CombineErrors, ErrorStream}; use spacetimedb_data_structures::map::{Equivalent, HashMap}; use spacetimedb_lib::db::raw_def; +use spacetimedb_lib::db::raw_def::v10::{ + RawConstraintDefV10, RawIndexDefV10, RawLifeCycleReducerDefV10, RawModuleDefV10, RawModuleDefV10Section, + RawProcedureDefV10, RawReducerDefV10, RawRowLevelSecurityDefV10, RawScheduleDefV10, RawScopedTypeNameV10, + RawSequenceDefV10, RawTableDefV10, RawTypeDefV10, RawViewDefV10, +}; use spacetimedb_lib::db::raw_def::v9::{ Lifecycle, RawColumnDefaultValueV9, RawConstraintDataV9, RawConstraintDefV9, RawIndexAlgorithm, RawIndexDefV9, RawMiscModuleExportV9, RawModuleDefV9, RawProcedureDefV9, RawReducerDefV9, RawRowLevelSecurityDefV9, @@ -468,6 +473,97 @@ impl TryFrom for ModuleDef { } } +impl From for RawModuleDefV10 { + fn from(val: ModuleDef) -> Self { + let ModuleDef { + tables, + views, + reducers, + lifecycle_reducers, + types, + typespace, + stored_in_table_def: _, + typespace_for_generate: _, + refmap: _, + row_level_security_raw, + procedures, + raw_module_def_version: _, + } = val; + + let mut sections = Vec::new(); + + sections.push(RawModuleDefV10Section::Typespace(typespace)); + + // Extract lifecycle reducer names before consuming reducers. + let raw_lifecycle: Vec = lifecycle_reducers + .into_iter() + .filter_map(|(lifecycle, reducer_id)| { + let id = reducer_id?; + let (name, _) = reducers.get_index(id.idx())?; + Some(RawLifeCycleReducerDefV10 { + lifecycle_spec: lifecycle, + function_name: name.clone().into(), + }) + }) + .collect(); + + let raw_types: Vec = types.into_values().map(Into::into).collect(); + if !raw_types.is_empty() { + sections.push(RawModuleDefV10Section::Types(raw_types)); + } + + // Collect schedules from tables (V10 stores them in a separate section). + let mut schedules = Vec::new(); + let raw_tables: Vec = tables + .into_values() + .map(|td| { + if let Some(sched) = td.schedule.clone() { + schedules.push(RawScheduleDefV10 { + source_name: Some(sched.name.into()), + table_name: td.name.clone().into(), + schedule_at_col: sched.at_column, + function_name: sched.function_name.into(), + }); + } + td.into() + }) + .collect(); + if !raw_tables.is_empty() { + sections.push(RawModuleDefV10Section::Tables(raw_tables)); + } + + let raw_reducers: Vec = reducers.into_values().map(Into::into).collect(); + if !raw_reducers.is_empty() { + sections.push(RawModuleDefV10Section::Reducers(raw_reducers)); + } + + let raw_procedures: Vec = procedures.into_values().map(Into::into).collect(); + if !raw_procedures.is_empty() { + sections.push(RawModuleDefV10Section::Procedures(raw_procedures)); + } + + let raw_views: Vec = views.into_values().map(Into::into).collect(); + if !raw_views.is_empty() { + sections.push(RawModuleDefV10Section::Views(raw_views)); + } + + if !schedules.is_empty() { + sections.push(RawModuleDefV10Section::Schedules(schedules)); + } + + if !raw_lifecycle.is_empty() { + sections.push(RawModuleDefV10Section::LifeCycleReducers(raw_lifecycle)); + } + + let raw_rls: Vec = row_level_security_raw.into_values().collect(); + if !raw_rls.is_empty() { + sections.push(RawModuleDefV10Section::RowLevelSecurity(raw_rls)); + } + + RawModuleDefV10 { sections } + } +} + /// Implemented by definitions stored in a `ModuleDef`. /// Allows looking definitions up in a `ModuleDef`, and across /// `ModuleDef`s during migrations. @@ -540,6 +636,12 @@ pub struct TableDef { /// Whether this table is public or private. pub table_access: TableAccess, + + /// Whether this is an event table. + /// + /// Event tables persist to the commitlog but are not merged into committed state. + /// Their rows are only visible to V2 subscribers in the transaction that inserted them. + pub is_event: bool, } impl TableDef { @@ -566,6 +668,7 @@ impl From for RawTableDefV9 { schedule, table_type, table_access, + is_event: _, // V9 does not support event tables; ignore when converting back } = val; RawTableDefV9 { @@ -582,6 +685,37 @@ impl From for RawTableDefV9 { } } +impl From for RawTableDefV10 { + fn from(val: TableDef) -> Self { + let TableDef { + name, + product_type_ref, + primary_key, + columns: _, // will be reconstructed from the product type. + indexes, + constraints, + sequences, + schedule: _, // V10 stores schedules in a separate section; handled in From. + table_type, + table_access, + is_event, + } = val; + + RawTableDefV10 { + source_name: name.into(), + product_type_ref, + primary_key: ColList::from_iter(primary_key), + indexes: indexes.into_values().map(Into::into).collect(), + constraints: constraints.into_values().map(Into::into).collect(), + sequences: sequences.into_values().map(Into::into).collect(), + table_type, + table_access, + default_values: Vec::new(), + is_event, + } + } +} + impl From for TableDef { fn from(def: ViewDef) -> Self { use TableAccess::*; @@ -603,6 +737,7 @@ impl From for TableDef { schedule: None, table_type: TableType::User, table_access: if is_public { Public } else { Private }, + is_event: false, } } } @@ -649,6 +784,19 @@ impl From for RawSequenceDefV9 { } } +impl From for RawSequenceDefV10 { + fn from(val: SequenceDef) -> Self { + RawSequenceDefV10 { + source_name: Some(val.name), + column: val.column, + start: val.start, + min_value: val.min_value, + max_value: val.max_value, + increment: val.increment, + } + } +} + /// A struct representing the validated definition of a database index. /// /// Cannot be created directly. Construct a [`ModuleDef`] by validating a [`RawModuleDef`] instead, @@ -696,6 +844,16 @@ impl From for RawIndexDefV9 { } } +impl From for RawIndexDefV10 { + fn from(val: IndexDef) -> Self { + RawIndexDefV10 { + source_name: Some(val.name), + accessor_name: val.accessor_name.map(Into::into), + algorithm: val.algorithm.into(), + } + } +} + /// Data specifying a supported index algorithm. #[non_exhaustive] #[derive(Debug, Clone, Eq, PartialEq)] @@ -956,6 +1114,15 @@ impl From for RawConstraintDefV9 { } } +impl From for RawConstraintDefV10 { + fn from(val: ConstraintDef) -> Self { + RawConstraintDefV10 { + source_name: Some(val.name), + data: val.data.into(), + } + } +} + /// Data for a constraint attached to a table. #[derive(Debug, Clone, Eq, PartialEq)] #[non_exhaustive] @@ -1113,6 +1280,16 @@ impl From for RawTypeDefV9 { } } +impl From for RawTypeDefV10 { + fn from(val: TypeDef) -> Self { + RawTypeDefV10 { + source_name: val.name.into(), + ty: val.ty, + custom_ordering: val.custom_ordering, + } + } +} + /// A scoped type name, in the form `scope0::scope1::...::scopeN::name`. /// /// These are the names that will be used *in client code generation*, NOT the names used for types @@ -1209,6 +1386,15 @@ impl From for RawScopedTypeNameV9 { } } +impl From for RawScopedTypeNameV10 { + fn from(val: ScopedTypeName) -> Self { + RawScopedTypeNameV10 { + scope: val.scope.into_vec().into_iter().map(|id| id.into()).collect(), + source_name: val.name.into(), + } + } +} + /// A view exported by the module. #[derive(Debug, Clone, Eq, PartialEq)] #[non_exhaustive] @@ -1306,6 +1492,28 @@ impl From for RawViewDefV9 { } } +impl From for RawViewDefV10 { + fn from(val: ViewDef) -> Self { + let ViewDef { + name, + is_anonymous, + is_public, + params, + return_type, + fn_ptr, + .. + } = val; + RawViewDefV10 { + source_name: name.into(), + index: fn_ptr.into(), + is_public, + is_anonymous, + params, + return_type, + } + } +} + impl From for RawMiscModuleExportV9 { fn from(def: ViewDef) -> Self { Self::View(def.into()) @@ -1341,6 +1549,15 @@ impl From for FunctionVisibility { } } +impl From for RawFunctionVisibility { + fn from(val: FunctionVisibility) -> Self { + match val { + FunctionVisibility::Private => RawFunctionVisibility::Private, + FunctionVisibility::ClientCallable => RawFunctionVisibility::ClientCallable, + } + } +} + /// A reducer exported by the module. #[derive(Debug, Clone, Eq, PartialEq)] #[non_exhaustive] @@ -1381,6 +1598,18 @@ impl From for RawReducerDefV9 { } } +impl From for RawReducerDefV10 { + fn from(val: ReducerDef) -> Self { + RawReducerDefV10 { + source_name: val.name.into(), + params: val.params, + visibility: val.visibility.into(), + ok_return_type: val.ok_return_type, + err_return_type: val.err_return_type, + } + } +} + #[derive(Debug, Clone, Eq, PartialEq)] #[non_exhaustive] pub struct ProcedureDef { @@ -1425,6 +1654,17 @@ impl From for RawProcedureDefV9 { } } +impl From for RawProcedureDefV10 { + fn from(val: ProcedureDef) -> Self { + RawProcedureDefV10 { + source_name: val.name.into(), + params: val.params, + return_type: val.return_type, + visibility: val.visibility.into(), + } + } +} + impl From for RawMiscModuleExportV9 { fn from(def: ProcedureDef) -> Self { Self::Procedure(def.into()) diff --git a/crates/schema/src/def/validate/v10.rs b/crates/schema/src/def/validate/v10.rs index 1667bd63b1f..d3e487b28b4 100644 --- a/crates/schema/src/def/validate/v10.rs +++ b/crates/schema/src/def/validate/v10.rs @@ -221,6 +221,7 @@ impl<'a> ModuleValidatorV10<'a> { table_type, table_access, default_values, + is_event, } = table; let product_type: &ProductType = self @@ -360,6 +361,7 @@ impl<'a> ModuleValidatorV10<'a> { schedule: None, // V10 handles schedules separately table_type, table_access, + is_event, }) } diff --git a/crates/schema/src/def/validate/v9.rs b/crates/schema/src/def/validate/v9.rs index 459f0cc80d2..03c9e6f8338 100644 --- a/crates/schema/src/def/validate/v9.rs +++ b/crates/schema/src/def/validate/v9.rs @@ -317,6 +317,7 @@ impl ModuleValidatorV9<'_> { schedule, table_type, table_access, + is_event: false, // V9 does not support event tables }) } diff --git a/crates/schema/src/schema.rs b/crates/schema/src/schema.rs index 4fa2085844f..3e050bff6f1 100644 --- a/crates/schema/src/schema.rs +++ b/crates/schema/src/schema.rs @@ -188,6 +188,9 @@ pub struct TableSchema { /// The schedule for the table, if present. pub schedule: Option, + /// Whether this is an event table. + pub is_event: bool, + /// Cache for `row_type_for_table` in the data store. pub row_type: ProductType, } @@ -212,6 +215,7 @@ impl TableSchema { table_access: StAccess, schedule: Option, primary_key: Option, + is_event: bool, ) -> Self { Self { row_type: columns_to_row_type(&columns), @@ -226,6 +230,7 @@ impl TableSchema { table_access, schedule, primary_key, + is_event, } } @@ -261,6 +266,7 @@ impl TableSchema { StAccess::Public, None, None, + false, ) } @@ -753,6 +759,7 @@ impl TableSchema { table_access, None, None, + false, ) } @@ -875,6 +882,7 @@ impl TableSchema { table_access, None, None, + false, ) } } @@ -904,6 +912,7 @@ impl Schema for TableSchema { schedule, table_type, table_access, + is_event, } = def; let columns = column_schemas_from_defs(module_def, columns, table_id); @@ -941,6 +950,7 @@ impl Schema for TableSchema { (*table_access).into(), schedule, *primary_key, + *is_event, ) } diff --git a/crates/standalone/src/subcommands/extract_schema.rs b/crates/standalone/src/subcommands/extract_schema.rs index 9b85e57059a..c9b35369957 100644 --- a/crates/standalone/src/subcommands/extract_schema.rs +++ b/crates/standalone/src/subcommands/extract_schema.rs @@ -67,7 +67,7 @@ pub async fn exec(args: &ArgMatches) -> anyhow::Result<()> { let module_def = extract_schema(program_bytes.into(), host_type.into()).await?; - let raw_def = RawModuleDef::V9(module_def.into()); + let raw_def = RawModuleDef::V10(module_def.into()); serde_json::to_writer(std::io::stdout().lock(), &sats::serde::SerdeWrapper(raw_def))?; diff --git a/crates/subscription/src/lib.rs b/crates/subscription/src/lib.rs index 20708a694c2..88bde4b6790 100644 --- a/crates/subscription/src/lib.rs +++ b/crates/subscription/src/lib.rs @@ -340,6 +340,11 @@ impl SubscriptionPlan { self.plan_opt.returns_view_table() } + /// Does this plan return rows from an event table? + pub fn returns_event_table(&self) -> bool { + self.plan_opt.return_table().is_some_and(|schema| schema.is_event) + } + /// The number of columns returned. /// Only relevant if [`Self::is_view`] is true. pub fn num_cols(&self) -> usize { @@ -513,6 +518,9 @@ impl SubscriptionPlan { if has_non_index_join(&plan_opt) { bail!("Subscriptions require indexes on join columns") } + if plan_opt.reads_from_event_table() { + bail!("Event tables cannot be used as the lookup table in subscription joins") + } let (table_ids, table_aliases) = table_ids_for_plan(&plan); diff --git a/docs/event-tables-status.md b/docs/event-tables-status.md new file mode 100644 index 00000000000..e94c33dec28 --- /dev/null +++ b/docs/event-tables-status.md @@ -0,0 +1,124 @@ +# Event Tables Implementation Status + +Tracking progress against the [event tables proposal](../../SpacetimeDBPrivate/proposals/00XX-event-tables.md). + +## Implemented + +### Server: Module-side (`#[table(..., event)]`) + +- [x] `event` attribute on `#[table]` macro (`crates/bindings-macro/src/table.rs`) +- [x] `is_event` field on `TableSchema` propagated through schema validation (`crates/schema/`) +- [x] `RawModuleDefV10` includes `is_event` in table definitions (`crates/lib/src/db/raw_def/v10.rs`) +- [x] Event table rows are recorded as inserts in `tx_data` at commit time but NOT merged into committed state (`crates/datastore/src/locking_tx_datastore/committed_state.rs`) +- [x] Commitlog replay treats event table inserts as noops — `replay_insert()` returns early when `schema.is_event` (`committed_state.rs`) +- [x] Event tables function as normal tables during reducer execution (insert/delete/update within a transaction) + +### Server: Subscriptions & Query Engine + +- [x] `SELECT * FROM *` excludes event tables (`crates/core/src/subscription/subscription.rs`) +- [x] `CanBeLookupTable` trait: event tables do NOT implement it, preventing use as the right/lookup table in view semijoins (`crates/bindings-macro/src/table.rs`, `crates/query-builder/src/table.rs`) +- [x] `reads_from_event_table()` check in `SubscriptionPlan::compile()` rejects event tables as lookup tables in subscription joins (`crates/subscription/src/lib.rs`). **Note:** the proposal says this should eventually be allowed (noops make it well-defined), but it is restricted for now for ease of implementation. +- [x] View definitions cannot select from event tables at runtime (`crates/core/src/host/wasm_common/module_host_actor.rs`). The proposal says to disallow event table access in the query builder entirely for now. + +### Server: V1 Protocol Compatibility + +- [x] V1 WebSocket subscriptions to event tables are rejected with a clear error message directing developers to upgrade (`crates/core/src/subscription/module_subscription_actor.rs`) + - Enforced in all three V1 paths: `SubscribeSingle`, `SubscribeMulti`, and legacy `Subscribe` +- [x] `returns_event_table()` methods on `SubscriptionPlan` and `Plan` for detecting event table subscriptions + +### Client: Rust SDK (v1 only) + +- [x] `EventTable` trait and `TableHandle` implementation that skips client cache storage (`sdks/rust/src/table.rs`) +- [x] `is_event` flag on `TableMetadata` in client cache (`sdks/rust/src/client_cache.rs`) +- [x] Codegen generates `EventTable` impl (insert-only, no delete callbacks) for event tables (`crates/codegen/src/rust.rs`). **Note:** the proposal says to generate both `on_insert` and `on_delete`. The server only sends inserts, but the client could synthesize the delete callback from the insert since every event table row is a noop. `on_delete` generation is deferred for now and can be added later. +- [x] `on_insert` callbacks fire for event table rows; `count()` and `iter()` always return empty +- [x] `spacetime_module.rs` exposes `is_event` in generated `SpacetimeModule` trait + +### Compile-time Checks (trybuild) + +- [x] Event tables cannot be the lookup (right) table in `left_semijoin` (`crates/bindings/tests/ui/views.rs`) +- [x] Event tables cannot be the lookup (right) table in `right_semijoin` +- [x] Event tables CAN be the left/outer table in a semijoin (positive compile test — would still be blocked at runtime by the view validation check) + +### Integration Tests + +- [x] V1 rejection test: verifies v1 clients get a subscription error with upgrade message +- [x] Basic event table test: `on_insert` fires, row values match, cache stays empty (written but `#[ignore]` — needs v2 SDK) +- [x] Multiple events in one reducer test (written but `#[ignore]` — needs v2 SDK) +- [x] Events don't persist across transactions test (written but `#[ignore]` — needs v2 SDK) + +### Proposal Document + +- [x] WebSocket Protocol Compatibility section added to proposal (`SpacetimeDBPrivate/proposals/00XX-event-tables.md`) + +## Not Yet Implemented + +### Reducer Callback Deprecation (2.0 — primary goal of proposal) + +The proposal's primary motivation is deprecating reducer event callbacks and replacing them with event tables. This has NOT been started: + +- [ ] Stop publishing `ReducerEvent` messages to v2 clients +- [ ] Remove `ctx.reducers.on_()` callback generation for v2 codegen +- [ ] Document migration path from reducer callbacks to event tables + +### Server: Untested Behaviors + +- [ ] RLS (Row-Level Security) on event tables — proposal says RLS should apply with same semantics as non-event tables; no specific testing or handling found +- [ ] Primary key, unique constraints, indexes on event tables — proposal says these should work; not tested +- [ ] Sequences and `auto_inc` on event tables — proposal says these should work; not tested +- [ ] Event table as right/inner table in subscription joins — proposal says this should eventually be allowed (noops make it well-defined); currently blocked by `reads_from_event_table()` check + +### Client: Rust SDK v2 WebSocket Support + +- [ ] Add `WsVersion` field to `WsParams` and `DbConnectionBuilder` +- [ ] Add `with_ws_version()` builder method +- [ ] Update `request_insert_protocol_header()` to use `ws_v2::BIN_PROTOCOL` when v2 is selected +- [ ] Handle v2 server messages (subscription responses, transaction updates) +- [ ] Re-enable `#[ignore]`'d event table integration tests once v2 is working + +### Server: Module-side for Other Languages + +- [ ] TypeScript module bindings: `event` attribute on table declarations +- [ ] C# module bindings: `event` attribute on table declarations + +### Client: Other SDKs + +- [ ] TypeScript SDK: `EventTable` support and client codegen +- [ ] C# SDK: `EventTable` support and client codegen +- [ ] C++ SDK: `EventTable` support and client codegen + +### Server: V2 Subscription Path for Event Tables + +- [ ] Verify event tables work correctly through the v2 subscription evaluation path (`eval_updates_sequential_inner_v2`) +- [ ] End-to-end test with a v2 client subscribing to event tables + +### Proposal: Future Work Items (not blocking 2.0) + +- [ ] `#[table]` attribute on reducer functions (auto-generate event table from reducer args) +- [ ] `ctx.on.()` convenience syntax on client +- [ ] Event tables in views / infectious event-table-ness for joined views +- [ ] TTL tables as generalization of event tables (`ttl = Duration::ZERO`) +- [ ] Temporal filters +- [ ] Light mode deprecation (2.0) +- [ ] `CallReducerFlags` / `NoSuccessNotify` deprecation (2.0) + +## Key Files + +| Area | File | +|------|------| +| Table macro | `crates/bindings-macro/src/table.rs` | +| Schema | `crates/schema/src/schema.rs` (`is_event` field) | +| Committed state | `crates/datastore/src/locking_tx_datastore/committed_state.rs` | +| Subscription filtering | `crates/core/src/subscription/subscription.rs` | +| V1 rejection | `crates/core/src/subscription/module_subscription_actor.rs` | +| Plan helpers | `crates/core/src/subscription/module_subscription_manager.rs`, `crates/subscription/src/lib.rs` | +| Query builder | `crates/query-builder/src/table.rs` (`CanBeLookupTable`) | +| Physical plan | `crates/physical-plan/src/plan.rs` (`reads_from_event_table`) | +| View validation | `crates/core/src/host/wasm_common/module_host_actor.rs` | +| Rust codegen | `crates/codegen/src/rust.rs` | +| Rust SDK | `sdks/rust/src/table.rs`, `sdks/rust/src/client_cache.rs` | +| Test module | `modules/sdk-test-event-table/src/lib.rs` | +| Test client | `sdks/rust/tests/event-table-client/src/main.rs` | +| Test harness | `sdks/rust/tests/test.rs` (event_table_tests module) | +| Compile tests | `crates/bindings/tests/ui/views.rs` | +| Proposal | `SpacetimeDBPrivate/proposals/00XX-event-tables.md` | diff --git a/modules/module-test/src/lib.rs b/modules/module-test/src/lib.rs index 433796e5b60..d8ef5ff62a0 100644 --- a/modules/module-test/src/lib.rs +++ b/modules/module-test/src/lib.rs @@ -165,6 +165,12 @@ pub struct HasSpecialStuff { connection_id: ConnectionId, } +#[table(name = my_event, public, event)] +pub struct MyEvent { + name: String, + value: u64, +} + /// These two tables defined with the same row type /// verify that we can define multiple tables with the same type. /// @@ -373,6 +379,11 @@ pub fn delete_players_by_name(ctx: &ReducerContext, name: String) -> Result<(), } } +#[spacetimedb::reducer] +pub fn emit_event(ctx: &ReducerContext, name: String, value: u64) { + ctx.db.my_event().insert(MyEvent { name, value }); +} + #[spacetimedb::reducer(client_connected)] fn client_connected(_ctx: &ReducerContext) {} diff --git a/modules/sdk-test-event-table/.cargo/config.toml b/modules/sdk-test-event-table/.cargo/config.toml new file mode 100644 index 00000000000..f4e8c002fc2 --- /dev/null +++ b/modules/sdk-test-event-table/.cargo/config.toml @@ -0,0 +1,2 @@ +[build] +target = "wasm32-unknown-unknown" diff --git a/modules/sdk-test-event-table/Cargo.toml b/modules/sdk-test-event-table/Cargo.toml new file mode 100644 index 00000000000..3dd8b22dbe4 --- /dev/null +++ b/modules/sdk-test-event-table/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "sdk-test-event-table-module" +version = "0.1.0" +edition.workspace = true + +[lib] +crate-type = ["cdylib"] + +[dependencies] +spacetimedb.workspace = true diff --git a/modules/sdk-test-event-table/src/lib.rs b/modules/sdk-test-event-table/src/lib.rs new file mode 100644 index 00000000000..b1fd9556514 --- /dev/null +++ b/modules/sdk-test-event-table/src/lib.rs @@ -0,0 +1,23 @@ +use spacetimedb::{ReducerContext, Table}; + +#[spacetimedb::table(name = test_event, public, event)] +pub struct TestEvent { + pub name: String, + pub value: u64, +} + +#[spacetimedb::reducer] +pub fn emit_test_event(ctx: &ReducerContext, name: String, value: u64) { + ctx.db.test_event().insert(TestEvent { name, value }); +} + +#[spacetimedb::reducer] +pub fn emit_multiple_test_events(ctx: &ReducerContext) { + ctx.db.test_event().insert(TestEvent { name: "a".to_string(), value: 1 }); + ctx.db.test_event().insert(TestEvent { name: "b".to_string(), value: 2 }); + ctx.db.test_event().insert(TestEvent { name: "c".to_string(), value: 3 }); +} + +/// A no-op reducer that lets us observe a subsequent transaction. +#[spacetimedb::reducer] +pub fn noop(_ctx: &ReducerContext) {} diff --git a/sdks/rust/src/client_cache.rs b/sdks/rust/src/client_cache.rs index 4a5bbfc312c..22d9b4b69b2 100644 --- a/sdks/rust/src/client_cache.rs +++ b/sdks/rust/src/client_cache.rs @@ -105,6 +105,19 @@ impl Default for TableAppliedDiff<'_, Row> { } impl<'r, Row> TableAppliedDiff<'r, Row> { + /// For event tables: construct a `TableAppliedDiff` with just inserts, + /// without touching the client cache. + /// Each insert will fire `on_insert` callbacks. + pub(crate) fn from_event_inserts(inserts: &'r [WithBsatn]) -> Self { + let insert_map = inserts.iter().map(|wb| (wb.bsatn.as_ref(), &wb.row)).collect(); + Self { + inserts: insert_map, + deletes: Default::default(), + update_deletes: Vec::new(), + update_inserts: Vec::new(), + } + } + /// Returns the applied diff restructured /// with row updates where deletes and inserts are found according to `derive_pk`. pub fn with_updates_by_pk(mut self, derive_pk: impl Fn(&Row) -> &Pk) -> Self { diff --git a/sdks/rust/src/lib.rs b/sdks/rust/src/lib.rs index aae49b6ac67..3c05e767e69 100644 --- a/sdks/rust/src/lib.rs +++ b/sdks/rust/src/lib.rs @@ -29,7 +29,7 @@ pub use db_connection::DbConnectionBuilder; pub use db_context::DbContext; pub use error::{Error, Result}; pub use event::{Event, ReducerEvent, Status}; -pub use table::{Table, TableWithPrimaryKey}; +pub use table::{EventTable, Table, TableWithPrimaryKey}; pub use spacetime_module::SubscriptionHandle; pub use spacetimedb_client_api_messages::websocket::v1::Compression; @@ -60,7 +60,7 @@ pub mod __codegen { }; pub use crate::subscription::{OnEndedCallback, SubscriptionBuilder, SubscriptionHandleImpl}; pub use crate::{ - ConnectionId, DbConnectionBuilder, DbContext, Event, Identity, ReducerEvent, ScheduleAt, Table, + ConnectionId, DbConnectionBuilder, DbContext, Event, EventTable, Identity, ReducerEvent, ScheduleAt, Table, TableWithPrimaryKey, TimeDuration, Timestamp, Uuid, }; } diff --git a/sdks/rust/src/spacetime_module.rs b/sdks/rust/src/spacetime_module.rs index 60909ee6a44..78361a4ee9b 100644 --- a/sdks/rust/src/spacetime_module.rs +++ b/sdks/rust/src/spacetime_module.rs @@ -241,6 +241,12 @@ impl TableUpdate { pub(crate) fn is_empty(&self) -> bool { self.inserts.is_empty() && self.deletes.is_empty() } + + /// For event tables: convert inserts directly to a `TableAppliedDiff` + /// without touching the client cache. Each insert fires `on_insert` callbacks. + pub fn into_event_diff(&self) -> crate::client_cache::TableAppliedDiff<'_, Row> { + crate::client_cache::TableAppliedDiff::from_event_inserts(&self.inserts) + } } impl TableUpdate { diff --git a/sdks/rust/src/table.rs b/sdks/rust/src/table.rs index 2198201cb6e..fd23bd59983 100644 --- a/sdks/rust/src/table.rs +++ b/sdks/rust/src/table.rs @@ -1,4 +1,4 @@ -//! The [`Table`] and [`TableWithPrimaryKey`] traits, +//! The [`EventTable`], [`Table`] and [`TableWithPrimaryKey`] traits, //! which allow certain simple queries of the client cache, //! and expose row callbacks which run when subscribed rows are inserted, deleted or updated. //! @@ -7,7 +7,46 @@ //! which mediate access to tables in the client cache. //! Obtain a table handle by calling a method on `ctx.db`, where `ctx` is a `DbConnection` or `EventContext`. -/// Trait implemented by table handles, which mediate access to tables in the client cache. +/// Trait for event tables, whose rows are transient and never persisted in the client cache. +/// +/// Event table rows are delivered as inserts but are not stored; +/// only `on_insert` callbacks fire, and `count`/`iter` always reflect an empty table. +/// +/// `EventTable` and [`Table`] are intentionally independent traits rather than sharing a supertrait. +/// In Rust, supertrait methods require the supertrait to be in scope, +/// so a shared `BaseTable` supertrait would force users of plain [`Table`]s +/// to import an extra trait just to call `count`, `iter`, or `on_insert`. +/// +/// Obtain a table handle by calling a method on `ctx.db`, where `ctx` is a `DbConnection` or `EventContext`. +pub trait EventTable { + /// The type of rows in this table. + type Row: 'static; + + /// The `EventContext` type generated for the module which defines this table. + type EventContext; + + /// The number of subscribed rows in the client cache (always 0 for event tables). + fn count(&self) -> u64; + + /// An iterator over all the subscribed rows in the client cache (always empty for event tables). + fn iter(&self) -> impl Iterator + '_; + + type InsertCallbackId; + /// Register a callback to run whenever a row is inserted. + /// + /// The returned [`Self::InsertCallbackId`] can be passed to [`Self::remove_on_insert`] + /// to cancel the callback. + fn on_insert( + &self, + callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, + ) -> Self::InsertCallbackId; + /// Cancel a callback previously registered by [`Self::on_insert`], causing it not to run in the future. + fn remove_on_insert(&self, callback: Self::InsertCallbackId); +} + +/// Trait for persistent (non-event) tables in the client cache. +/// +/// Provides read access to the client cache, insert callbacks, and delete callbacks. /// /// Obtain a table handle by calling a method on `ctx.db`, where `ctx` is a `DbConnection` or `EventContext`. pub trait Table { diff --git a/sdks/rust/tests/connect_disconnect_client/src/module_bindings/connected_type.rs b/sdks/rust/tests/connect_disconnect_client/src/module_bindings/connected_type.rs index c762b7a6bcc..dc05c7d6bf5 100644 --- a/sdks/rust/tests/connect_disconnect_client/src/module_bindings/connected_type.rs +++ b/sdks/rust/tests/connect_disconnect_client/src/module_bindings/connected_type.rs @@ -41,3 +41,5 @@ impl __sdk::__query_builder::HasIxCols for Connected { ConnectedIxCols {} } } + +impl __sdk::__query_builder::CanBeLookupTable for Connected {} diff --git a/sdks/rust/tests/connect_disconnect_client/src/module_bindings/disconnected_type.rs b/sdks/rust/tests/connect_disconnect_client/src/module_bindings/disconnected_type.rs index 4349be485a7..b0d370c7fa4 100644 --- a/sdks/rust/tests/connect_disconnect_client/src/module_bindings/disconnected_type.rs +++ b/sdks/rust/tests/connect_disconnect_client/src/module_bindings/disconnected_type.rs @@ -41,3 +41,5 @@ impl __sdk::__query_builder::HasIxCols for Disconnected { DisconnectedIxCols {} } } + +impl __sdk::__query_builder::CanBeLookupTable for Disconnected {} diff --git a/sdks/rust/tests/connect_disconnect_client/src/module_bindings/identity_connected_reducer.rs b/sdks/rust/tests/connect_disconnect_client/src/module_bindings/identity_connected_reducer.rs deleted file mode 100644 index 5c2d5e0df4e..00000000000 --- a/sdks/rust/tests/connect_disconnect_client/src/module_bindings/identity_connected_reducer.rs +++ /dev/null @@ -1,100 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub(super) struct IdentityConnectedArgs {} - -impl From for super::Reducer { - fn from(args: IdentityConnectedArgs) -> Self { - Self::IdentityConnected - } -} - -impl __sdk::InModule for IdentityConnectedArgs { - type Module = super::RemoteModule; -} - -pub struct IdentityConnectedCallbackId(__sdk::CallbackId); - -#[allow(non_camel_case_types)] -/// Extension trait for access to the reducer `identity_connected`. -/// -/// Implemented for [`super::RemoteReducers`]. -pub trait identity_connected { - /// Request that the remote module invoke the reducer `identity_connected` to run as soon as possible. - /// - /// This method returns immediately, and errors only if we are unable to send the request. - /// The reducer will run asynchronously in the future, - /// and its status can be observed by listening for [`Self::on_identity_connected`] callbacks. - fn identity_connected(&self) -> __sdk::Result<()>; - /// Register a callback to run whenever we are notified of an invocation of the reducer `identity_connected`. - /// - /// Callbacks should inspect the [`__sdk::ReducerEvent`] contained in the [`super::ReducerEventContext`] - /// to determine the reducer's status. - /// - /// The returned [`IdentityConnectedCallbackId`] can be passed to [`Self::remove_on_identity_connected`] - /// to cancel the callback. - fn on_identity_connected( - &self, - callback: impl FnMut(&super::ReducerEventContext) + Send + 'static, - ) -> IdentityConnectedCallbackId; - /// Cancel a callback previously registered by [`Self::on_identity_connected`], - /// causing it not to run in the future. - fn remove_on_identity_connected(&self, callback: IdentityConnectedCallbackId); -} - -impl identity_connected for super::RemoteReducers { - fn identity_connected(&self) -> __sdk::Result<()> { - self.imp.call_reducer("identity_connected", IdentityConnectedArgs {}) - } - fn on_identity_connected( - &self, - mut callback: impl FnMut(&super::ReducerEventContext) + Send + 'static, - ) -> IdentityConnectedCallbackId { - IdentityConnectedCallbackId(self.imp.on_reducer( - "identity_connected", - Box::new(move |ctx: &super::ReducerEventContext| { - #[allow(irrefutable_let_patterns)] - let super::ReducerEventContext { - event: - __sdk::ReducerEvent { - reducer: super::Reducer::IdentityConnected {}, - .. - }, - .. - } = ctx - else { - unreachable!() - }; - callback(ctx) - }), - )) - } - fn remove_on_identity_connected(&self, callback: IdentityConnectedCallbackId) { - self.imp.remove_on_reducer("identity_connected", callback.0) - } -} - -#[allow(non_camel_case_types)] -#[doc(hidden)] -/// Extension trait for setting the call-flags for the reducer `identity_connected`. -/// -/// Implemented for [`super::SetReducerFlags`]. -/// -/// This type is currently unstable and may be removed without a major version bump. -pub trait set_flags_for_identity_connected { - /// Set the call-reducer flags for the reducer `identity_connected` to `flags`. - /// - /// This type is currently unstable and may be removed without a major version bump. - fn identity_connected(&self, flags: __ws::CallReducerFlags); -} - -impl set_flags_for_identity_connected for super::SetReducerFlags { - fn identity_connected(&self, flags: __ws::CallReducerFlags) { - self.imp.set_call_reducer_flags("identity_connected", flags); - } -} diff --git a/sdks/rust/tests/connect_disconnect_client/src/module_bindings/identity_disconnected_reducer.rs b/sdks/rust/tests/connect_disconnect_client/src/module_bindings/identity_disconnected_reducer.rs deleted file mode 100644 index ae4679d09aa..00000000000 --- a/sdks/rust/tests/connect_disconnect_client/src/module_bindings/identity_disconnected_reducer.rs +++ /dev/null @@ -1,101 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub(super) struct IdentityDisconnectedArgs {} - -impl From for super::Reducer { - fn from(args: IdentityDisconnectedArgs) -> Self { - Self::IdentityDisconnected - } -} - -impl __sdk::InModule for IdentityDisconnectedArgs { - type Module = super::RemoteModule; -} - -pub struct IdentityDisconnectedCallbackId(__sdk::CallbackId); - -#[allow(non_camel_case_types)] -/// Extension trait for access to the reducer `identity_disconnected`. -/// -/// Implemented for [`super::RemoteReducers`]. -pub trait identity_disconnected { - /// Request that the remote module invoke the reducer `identity_disconnected` to run as soon as possible. - /// - /// This method returns immediately, and errors only if we are unable to send the request. - /// The reducer will run asynchronously in the future, - /// and its status can be observed by listening for [`Self::on_identity_disconnected`] callbacks. - fn identity_disconnected(&self) -> __sdk::Result<()>; - /// Register a callback to run whenever we are notified of an invocation of the reducer `identity_disconnected`. - /// - /// Callbacks should inspect the [`__sdk::ReducerEvent`] contained in the [`super::ReducerEventContext`] - /// to determine the reducer's status. - /// - /// The returned [`IdentityDisconnectedCallbackId`] can be passed to [`Self::remove_on_identity_disconnected`] - /// to cancel the callback. - fn on_identity_disconnected( - &self, - callback: impl FnMut(&super::ReducerEventContext) + Send + 'static, - ) -> IdentityDisconnectedCallbackId; - /// Cancel a callback previously registered by [`Self::on_identity_disconnected`], - /// causing it not to run in the future. - fn remove_on_identity_disconnected(&self, callback: IdentityDisconnectedCallbackId); -} - -impl identity_disconnected for super::RemoteReducers { - fn identity_disconnected(&self) -> __sdk::Result<()> { - self.imp - .call_reducer("identity_disconnected", IdentityDisconnectedArgs {}) - } - fn on_identity_disconnected( - &self, - mut callback: impl FnMut(&super::ReducerEventContext) + Send + 'static, - ) -> IdentityDisconnectedCallbackId { - IdentityDisconnectedCallbackId(self.imp.on_reducer( - "identity_disconnected", - Box::new(move |ctx: &super::ReducerEventContext| { - #[allow(irrefutable_let_patterns)] - let super::ReducerEventContext { - event: - __sdk::ReducerEvent { - reducer: super::Reducer::IdentityDisconnected {}, - .. - }, - .. - } = ctx - else { - unreachable!() - }; - callback(ctx) - }), - )) - } - fn remove_on_identity_disconnected(&self, callback: IdentityDisconnectedCallbackId) { - self.imp.remove_on_reducer("identity_disconnected", callback.0) - } -} - -#[allow(non_camel_case_types)] -#[doc(hidden)] -/// Extension trait for setting the call-flags for the reducer `identity_disconnected`. -/// -/// Implemented for [`super::SetReducerFlags`]. -/// -/// This type is currently unstable and may be removed without a major version bump. -pub trait set_flags_for_identity_disconnected { - /// Set the call-reducer flags for the reducer `identity_disconnected` to `flags`. - /// - /// This type is currently unstable and may be removed without a major version bump. - fn identity_disconnected(&self, flags: __ws::CallReducerFlags); -} - -impl set_flags_for_identity_disconnected for super::SetReducerFlags { - fn identity_disconnected(&self, flags: __ws::CallReducerFlags) { - self.imp.set_call_reducer_flags("identity_disconnected", flags); - } -} diff --git a/sdks/rust/tests/connect_disconnect_client/src/module_bindings/mod.rs b/sdks/rust/tests/connect_disconnect_client/src/module_bindings/mod.rs index 5a54035abec..d04ac5500ef 100644 --- a/sdks/rust/tests/connect_disconnect_client/src/module_bindings/mod.rs +++ b/sdks/rust/tests/connect_disconnect_client/src/module_bindings/mod.rs @@ -1,7 +1,7 @@ // THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE // WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. -// This was generated using spacetimedb cli version 1.11.2 (commit 13a0172567170d9b8c87d2aa71de3246c21acb8c). +// This was generated using spacetimedb cli version 1.12.0 (commit fa83d6d4023972609140a959099eab19a4e5f995). #![allow(unused, clippy::all)] use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; @@ -10,19 +10,11 @@ pub mod connected_table; pub mod connected_type; pub mod disconnected_table; pub mod disconnected_type; -pub mod identity_connected_reducer; -pub mod identity_disconnected_reducer; pub use connected_table::*; pub use connected_type::Connected; pub use disconnected_table::*; pub use disconnected_type::Disconnected; -pub use identity_connected_reducer::{ - identity_connected, set_flags_for_identity_connected, IdentityConnectedCallbackId, -}; -pub use identity_disconnected_reducer::{ - identity_disconnected, set_flags_for_identity_disconnected, IdentityDisconnectedCallbackId, -}; #[derive(Clone, PartialEq, Debug)] @@ -31,10 +23,7 @@ pub use identity_disconnected_reducer::{ /// Contained within a [`__sdk::ReducerEvent`] in [`EventContext`]s for reducer events /// to indicate which reducer caused the event. -pub enum Reducer { - IdentityConnected, - IdentityDisconnected, -} +pub enum Reducer {} impl __sdk::InModule for Reducer { type Module = RemoteModule; @@ -43,8 +32,6 @@ impl __sdk::InModule for Reducer { impl __sdk::Reducer for Reducer { fn reducer_name(&self) -> &'static str { match self { - Reducer::IdentityConnected => "identity_connected", - Reducer::IdentityDisconnected => "identity_disconnected", _ => unreachable!(), } } @@ -53,17 +40,6 @@ impl TryFrom<__ws::ReducerCallInfo<__ws::BsatnFormat>> for Reducer { type Error = __sdk::Error; fn try_from(value: __ws::ReducerCallInfo<__ws::BsatnFormat>) -> __sdk::Result { match &value.reducer_name[..] { - "identity_connected" => Ok( - __sdk::parse_reducer_args::( - "identity_connected", - &value.args, - )? - .into(), - ), - "identity_disconnected" => Ok(__sdk::parse_reducer_args::< - identity_disconnected_reducer::IdentityDisconnectedArgs, - >("identity_disconnected", &value.args)? - .into()), unknown => Err(__sdk::InternalError::unknown_name("reducer", unknown, "ReducerCallInfo").into()), } } diff --git a/sdks/rust/tests/event-table-client/Cargo.toml b/sdks/rust/tests/event-table-client/Cargo.toml new file mode 100644 index 00000000000..f6502644119 --- /dev/null +++ b/sdks/rust/tests/event-table-client/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "event-table-client" +version.workspace = true +edition.workspace = true + +[dependencies] +spacetimedb-sdk = { path = "../.." } +test-counter = { path = "../test-counter" } +anyhow.workspace = true +env_logger.workspace = true + +[lints] +workspace = true diff --git a/sdks/rust/tests/event-table-client/src/main.rs b/sdks/rust/tests/event-table-client/src/main.rs new file mode 100644 index 00000000000..648d2a7c1e0 --- /dev/null +++ b/sdks/rust/tests/event-table-client/src/main.rs @@ -0,0 +1,248 @@ +#[allow(clippy::too_many_arguments)] +#[allow(clippy::large_enum_variant)] +mod module_bindings; + +use module_bindings::*; + +use spacetimedb_sdk::{Event, EventTable}; +use std::sync::atomic::{AtomicU32, Ordering}; +use test_counter::TestCounter; + +const LOCALHOST: &str = "http://localhost:3000"; + +fn db_name_or_panic() -> String { + std::env::var("SPACETIME_SDK_TEST_DB_NAME").expect("Failed to read db name from env") +} + +/// Register a panic hook which will exit the process whenever any thread panics. +/// +/// This allows us to fail tests by panicking in callbacks. +fn exit_on_panic() { + let default_hook = std::panic::take_hook(); + std::panic::set_hook(Box::new(move |panic_info| { + default_hook(panic_info); + std::process::exit(1); + })); +} + +macro_rules! assert_eq_or_bail { + ($expected:expr, $found:expr) => {{ + let expected = &$expected; + let found = &$found; + if expected != found { + anyhow::bail!( + "Expected {} => {:?} but found {} => {:?}", + stringify!($expected), + expected, + stringify!($found), + found + ); + } + }}; +} + +fn main() { + env_logger::init(); + exit_on_panic(); + + let test = std::env::args() + .nth(1) + .expect("Pass a test name as a command-line argument to the test client"); + + match &*test { + "event-table" => exec_event_table(), + "multiple-events" => exec_multiple_events(), + "events-dont-persist" => exec_events_dont_persist(), + "v1-rejects-event-table" => exec_v1_rejects_event_table(), + _ => panic!("Unknown test: {test}"), + } +} + +fn connect_then( + test_counter: &std::sync::Arc, + callback: impl FnOnce(&DbConnection) + Send + 'static, +) -> DbConnection { + let connected_result = test_counter.add_test("on_connect"); + let name = db_name_or_panic(); + let conn = DbConnection::builder() + .with_module_name(name) + .with_uri(LOCALHOST) + .on_connect(|ctx, _, _| { + callback(ctx); + connected_result(Ok(())); + }) + .on_connect_error(|_ctx, error| panic!("Connect errored: {error:?}")) + .build() + .unwrap(); + conn.run_threaded(); + conn +} + +fn subscribe_these_then( + ctx: &impl RemoteDbContext, + queries: &[&str], + callback: impl FnOnce(&SubscriptionEventContext) + Send + 'static, +) { + ctx.subscription_builder() + .on_applied(callback) + .on_error(|_ctx, error| panic!("Subscription errored: {error:?}")) + .subscribe(queries); +} + +fn exec_event_table() { + let test_counter = TestCounter::new(); + + connect_then(&test_counter, { + let test_counter = test_counter.clone(); + move |ctx| { + subscribe_these_then(ctx, &["SELECT * FROM test_event;"], move |ctx| { + // Event table should be empty on subscription applied + assert_eq!(0usize, ctx.db.test_event().iter().count()); + + let mut on_insert_result = Some(test_counter.add_test("event-table-on-insert")); + + ctx.db.test_event().on_insert(move |ctx, row| { + if let Some(set_result) = on_insert_result.take() { + let run_checks = || { + assert_eq_or_bail!("hello", row.name); + assert_eq_or_bail!(42u64, row.value); + + let Event::Reducer(reducer_event) = &ctx.event else { + anyhow::bail!("Expected a reducer event"); + }; + anyhow::ensure!( + matches!(reducer_event.reducer, Reducer::EmitTestEvent { .. }), + "Unexpected Reducer variant {:?}", + reducer_event.reducer, + ); + + // Event table rows are not cached + assert_eq_or_bail!(0u64, ctx.db.test_event().count()); + assert_eq_or_bail!(0usize, ctx.db.test_event().iter().count()); + + Ok(()) + }; + set_result(run_checks()); + } + }); + + ctx.reducers.emit_test_event("hello".to_string(), 42).unwrap(); + }); + } + }); + + test_counter.wait_for_all(); +} + +/// Test that multiple events emitted in a single reducer call all arrive as inserts. +fn exec_multiple_events() { + let test_counter = TestCounter::new(); + + connect_then(&test_counter, { + let test_counter = test_counter.clone(); + move |ctx| { + subscribe_these_then(ctx, &["SELECT * FROM test_event;"], move |ctx| { + assert_eq!(0usize, ctx.db.test_event().iter().count()); + + let received = std::sync::Arc::new(AtomicU32::new(0)); + let result = test_counter.add_test("multiple-events"); + let result = std::sync::Mutex::new(Some(result)); + + ctx.db.test_event().on_insert({ + let received = received.clone(); + move |_ctx, _row| { + let count = received.fetch_add(1, Ordering::SeqCst) + 1; + if count == 3 { + let set_result = result.lock().unwrap().take().unwrap(); + set_result(Ok(())); + } + } + }); + + ctx.reducers.emit_multiple_test_events().unwrap(); + }); + } + }); + + test_counter.wait_for_all(); +} + +/// Test that event table rows don't persist across transactions. +/// Emit events, then call a no-op reducer. After the no-op completes, +/// verify we didn't receive any additional event inserts. +fn exec_events_dont_persist() { + let test_counter = TestCounter::new(); + + connect_then(&test_counter, { + let test_counter = test_counter.clone(); + move |ctx| { + subscribe_these_then(ctx, &["SELECT * FROM test_event;"], move |ctx| { + assert_eq!(0usize, ctx.db.test_event().iter().count()); + + let insert_count = std::sync::Arc::new(AtomicU32::new(0)); + let noop_result = test_counter.add_test("events-dont-persist"); + let noop_result = std::sync::Mutex::new(Some(noop_result)); + + ctx.db.test_event().on_insert({ + let insert_count = insert_count.clone(); + move |_ctx, _row| { + insert_count.fetch_add(1, Ordering::SeqCst); + } + }); + + // After the noop reducer completes, the insert count should + // still be 1 from the emit_test_event call — no stale events. + ctx.reducers.on_noop({ + let insert_count = insert_count.clone(); + move |_ctx| { + let set_result = noop_result.lock().unwrap().take().unwrap(); + let count = insert_count.load(Ordering::SeqCst); + if count == 1 { + set_result(Ok(())); + } else { + set_result(Err(anyhow::anyhow!( + "Expected 1 event insert, but got {count}" + ))); + } + } + }); + + ctx.reducers.emit_test_event("hello".to_string(), 42).unwrap(); + ctx.reducers.noop().unwrap(); + }); + } + }); + + test_counter.wait_for_all(); +} + +/// Test that v1 WebSocket clients are rejected when subscribing to event tables. +/// The server should return a subscription error directing the developer to upgrade. +fn exec_v1_rejects_event_table() { + let test_counter = TestCounter::new(); + + connect_then(&test_counter, { + let test_counter = test_counter.clone(); + move |ctx| { + let error_result = test_counter.add_test("v1-rejects-event-table"); + + ctx.subscription_builder() + .on_applied(move |_ctx: &SubscriptionEventContext| { + panic!("Subscription to event table should not succeed over v1"); + }) + .on_error(move |_ctx, error| { + let msg = format!("{error:?}"); + if msg.contains("v2") || msg.contains("upgrade") || msg.contains("Upgrade") { + error_result(Ok(())); + } else { + error_result(Err(anyhow::anyhow!( + "Expected error about v2/upgrade, got: {msg}" + ))); + } + }) + .subscribe(["SELECT * FROM test_event;"]); + } + }); + + test_counter.wait_for_all(); +} diff --git a/sdks/rust/tests/event-table-client/src/module_bindings/emit_multiple_test_events_reducer.rs b/sdks/rust/tests/event-table-client/src/module_bindings/emit_multiple_test_events_reducer.rs new file mode 100644 index 00000000000..90fe82b9852 --- /dev/null +++ b/sdks/rust/tests/event-table-client/src/module_bindings/emit_multiple_test_events_reducer.rs @@ -0,0 +1,101 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +#![allow(unused, clippy::all)] +use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; + +#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] +#[sats(crate = __lib)] +pub(super) struct EmitMultipleTestEventsArgs {} + +impl From for super::Reducer { + fn from(args: EmitMultipleTestEventsArgs) -> Self { + Self::EmitMultipleTestEvents + } +} + +impl __sdk::InModule for EmitMultipleTestEventsArgs { + type Module = super::RemoteModule; +} + +pub struct EmitMultipleTestEventsCallbackId(__sdk::CallbackId); + +#[allow(non_camel_case_types)] +/// Extension trait for access to the reducer `emit_multiple_test_events`. +/// +/// Implemented for [`super::RemoteReducers`]. +pub trait emit_multiple_test_events { + /// Request that the remote module invoke the reducer `emit_multiple_test_events` to run as soon as possible. + /// + /// This method returns immediately, and errors only if we are unable to send the request. + /// The reducer will run asynchronously in the future, + /// and its status can be observed by listening for [`Self::on_emit_multiple_test_events`] callbacks. + fn emit_multiple_test_events(&self) -> __sdk::Result<()>; + /// Register a callback to run whenever we are notified of an invocation of the reducer `emit_multiple_test_events`. + /// + /// Callbacks should inspect the [`__sdk::ReducerEvent`] contained in the [`super::ReducerEventContext`] + /// to determine the reducer's status. + /// + /// The returned [`EmitMultipleTestEventsCallbackId`] can be passed to [`Self::remove_on_emit_multiple_test_events`] + /// to cancel the callback. + fn on_emit_multiple_test_events( + &self, + callback: impl FnMut(&super::ReducerEventContext) + Send + 'static, + ) -> EmitMultipleTestEventsCallbackId; + /// Cancel a callback previously registered by [`Self::on_emit_multiple_test_events`], + /// causing it not to run in the future. + fn remove_on_emit_multiple_test_events(&self, callback: EmitMultipleTestEventsCallbackId); +} + +impl emit_multiple_test_events for super::RemoteReducers { + fn emit_multiple_test_events(&self) -> __sdk::Result<()> { + self.imp + .call_reducer("emit_multiple_test_events", EmitMultipleTestEventsArgs {}) + } + fn on_emit_multiple_test_events( + &self, + mut callback: impl FnMut(&super::ReducerEventContext) + Send + 'static, + ) -> EmitMultipleTestEventsCallbackId { + EmitMultipleTestEventsCallbackId(self.imp.on_reducer( + "emit_multiple_test_events", + Box::new(move |ctx: &super::ReducerEventContext| { + #[allow(irrefutable_let_patterns)] + let super::ReducerEventContext { + event: + __sdk::ReducerEvent { + reducer: super::Reducer::EmitMultipleTestEvents {}, + .. + }, + .. + } = ctx + else { + unreachable!() + }; + callback(ctx) + }), + )) + } + fn remove_on_emit_multiple_test_events(&self, callback: EmitMultipleTestEventsCallbackId) { + self.imp.remove_on_reducer("emit_multiple_test_events", callback.0) + } +} + +#[allow(non_camel_case_types)] +#[doc(hidden)] +/// Extension trait for setting the call-flags for the reducer `emit_multiple_test_events`. +/// +/// Implemented for [`super::SetReducerFlags`]. +/// +/// This type is currently unstable and may be removed without a major version bump. +pub trait set_flags_for_emit_multiple_test_events { + /// Set the call-reducer flags for the reducer `emit_multiple_test_events` to `flags`. + /// + /// This type is currently unstable and may be removed without a major version bump. + fn emit_multiple_test_events(&self, flags: __ws::CallReducerFlags); +} + +impl set_flags_for_emit_multiple_test_events for super::SetReducerFlags { + fn emit_multiple_test_events(&self, flags: __ws::CallReducerFlags) { + self.imp.set_call_reducer_flags("emit_multiple_test_events", flags); + } +} diff --git a/sdks/rust/tests/event-table-client/src/module_bindings/emit_test_event_reducer.rs b/sdks/rust/tests/event-table-client/src/module_bindings/emit_test_event_reducer.rs new file mode 100644 index 00000000000..12770a022e0 --- /dev/null +++ b/sdks/rust/tests/event-table-client/src/module_bindings/emit_test_event_reducer.rs @@ -0,0 +1,107 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +#![allow(unused, clippy::all)] +use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; + +#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] +#[sats(crate = __lib)] +pub(super) struct EmitTestEventArgs { + pub name: String, + pub value: u64, +} + +impl From for super::Reducer { + fn from(args: EmitTestEventArgs) -> Self { + Self::EmitTestEvent { + name: args.name, + value: args.value, + } + } +} + +impl __sdk::InModule for EmitTestEventArgs { + type Module = super::RemoteModule; +} + +pub struct EmitTestEventCallbackId(__sdk::CallbackId); + +#[allow(non_camel_case_types)] +/// Extension trait for access to the reducer `emit_test_event`. +/// +/// Implemented for [`super::RemoteReducers`]. +pub trait emit_test_event { + /// Request that the remote module invoke the reducer `emit_test_event` to run as soon as possible. + /// + /// This method returns immediately, and errors only if we are unable to send the request. + /// The reducer will run asynchronously in the future, + /// and its status can be observed by listening for [`Self::on_emit_test_event`] callbacks. + fn emit_test_event(&self, name: String, value: u64) -> __sdk::Result<()>; + /// Register a callback to run whenever we are notified of an invocation of the reducer `emit_test_event`. + /// + /// Callbacks should inspect the [`__sdk::ReducerEvent`] contained in the [`super::ReducerEventContext`] + /// to determine the reducer's status. + /// + /// The returned [`EmitTestEventCallbackId`] can be passed to [`Self::remove_on_emit_test_event`] + /// to cancel the callback. + fn on_emit_test_event( + &self, + callback: impl FnMut(&super::ReducerEventContext, &String, &u64) + Send + 'static, + ) -> EmitTestEventCallbackId; + /// Cancel a callback previously registered by [`Self::on_emit_test_event`], + /// causing it not to run in the future. + fn remove_on_emit_test_event(&self, callback: EmitTestEventCallbackId); +} + +impl emit_test_event for super::RemoteReducers { + fn emit_test_event(&self, name: String, value: u64) -> __sdk::Result<()> { + self.imp + .call_reducer("emit_test_event", EmitTestEventArgs { name, value }) + } + fn on_emit_test_event( + &self, + mut callback: impl FnMut(&super::ReducerEventContext, &String, &u64) + Send + 'static, + ) -> EmitTestEventCallbackId { + EmitTestEventCallbackId(self.imp.on_reducer( + "emit_test_event", + Box::new(move |ctx: &super::ReducerEventContext| { + #[allow(irrefutable_let_patterns)] + let super::ReducerEventContext { + event: + __sdk::ReducerEvent { + reducer: super::Reducer::EmitTestEvent { name, value }, + .. + }, + .. + } = ctx + else { + unreachable!() + }; + callback(ctx, name, value) + }), + )) + } + fn remove_on_emit_test_event(&self, callback: EmitTestEventCallbackId) { + self.imp.remove_on_reducer("emit_test_event", callback.0) + } +} + +#[allow(non_camel_case_types)] +#[doc(hidden)] +/// Extension trait for setting the call-flags for the reducer `emit_test_event`. +/// +/// Implemented for [`super::SetReducerFlags`]. +/// +/// This type is currently unstable and may be removed without a major version bump. +pub trait set_flags_for_emit_test_event { + /// Set the call-reducer flags for the reducer `emit_test_event` to `flags`. + /// + /// This type is currently unstable and may be removed without a major version bump. + fn emit_test_event(&self, flags: __ws::CallReducerFlags); +} + +impl set_flags_for_emit_test_event for super::SetReducerFlags { + fn emit_test_event(&self, flags: __ws::CallReducerFlags) { + self.imp.set_call_reducer_flags("emit_test_event", flags); + } +} diff --git a/sdks/rust/tests/event-table-client/src/module_bindings/mod.rs b/sdks/rust/tests/event-table-client/src/module_bindings/mod.rs new file mode 100644 index 00000000000..cfb86570288 --- /dev/null +++ b/sdks/rust/tests/event-table-client/src/module_bindings/mod.rs @@ -0,0 +1,846 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +// This was generated using spacetimedb cli version 1.12.0 (commit 196867e42b8a649940f9172e0f838cedd6a540ae). + +#![allow(unused, clippy::all)] +use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; + +pub mod emit_multiple_test_events_reducer; +pub mod emit_test_event_reducer; +pub mod noop_reducer; +pub mod test_event_table; +pub mod test_event_type; + +pub use emit_multiple_test_events_reducer::{ + emit_multiple_test_events, set_flags_for_emit_multiple_test_events, EmitMultipleTestEventsCallbackId, +}; +pub use emit_test_event_reducer::{emit_test_event, set_flags_for_emit_test_event, EmitTestEventCallbackId}; +pub use noop_reducer::{noop, set_flags_for_noop, NoopCallbackId}; +pub use test_event_table::*; +pub use test_event_type::TestEvent; + +#[derive(Clone, PartialEq, Debug)] + +/// One of the reducers defined by this module. +/// +/// Contained within a [`__sdk::ReducerEvent`] in [`EventContext`]s for reducer events +/// to indicate which reducer caused the event. + +pub enum Reducer { + EmitMultipleTestEvents, + EmitTestEvent { name: String, value: u64 }, + Noop, +} + +impl __sdk::InModule for Reducer { + type Module = RemoteModule; +} + +impl __sdk::Reducer for Reducer { + fn reducer_name(&self) -> &'static str { + match self { + Reducer::EmitMultipleTestEvents => "emit_multiple_test_events", + Reducer::EmitTestEvent { .. } => "emit_test_event", + Reducer::Noop => "noop", + _ => unreachable!(), + } + } +} +impl TryFrom<__ws::ReducerCallInfo<__ws::BsatnFormat>> for Reducer { + type Error = __sdk::Error; + fn try_from(value: __ws::ReducerCallInfo<__ws::BsatnFormat>) -> __sdk::Result { + match &value.reducer_name[..] { + "emit_multiple_test_events" => Ok(__sdk::parse_reducer_args::< + emit_multiple_test_events_reducer::EmitMultipleTestEventsArgs, + >("emit_multiple_test_events", &value.args)? + .into()), + "emit_test_event" => Ok(__sdk::parse_reducer_args::( + "emit_test_event", + &value.args, + )? + .into()), + "noop" => Ok(__sdk::parse_reducer_args::("noop", &value.args)?.into()), + unknown => Err(__sdk::InternalError::unknown_name("reducer", unknown, "ReducerCallInfo").into()), + } + } +} + +#[derive(Default)] +#[allow(non_snake_case)] +#[doc(hidden)] +pub struct DbUpdate { + test_event: __sdk::TableUpdate, +} + +impl TryFrom<__ws::DatabaseUpdate<__ws::BsatnFormat>> for DbUpdate { + type Error = __sdk::Error; + fn try_from(raw: __ws::DatabaseUpdate<__ws::BsatnFormat>) -> Result { + let mut db_update = DbUpdate::default(); + for table_update in raw.tables { + match &table_update.table_name[..] { + "test_event" => db_update + .test_event + .append(test_event_table::parse_table_update(table_update)?), + + unknown => { + return Err(__sdk::InternalError::unknown_name("table", unknown, "DatabaseUpdate").into()); + } + } + } + Ok(db_update) + } +} + +impl __sdk::InModule for DbUpdate { + type Module = RemoteModule; +} + +impl __sdk::DbUpdate for DbUpdate { + fn apply_to_client_cache(&self, cache: &mut __sdk::ClientCache) -> AppliedDiff<'_> { + let mut diff = AppliedDiff::default(); + + diff.test_event = self.test_event.into_event_diff(); + + diff + } +} + +#[derive(Default)] +#[allow(non_snake_case)] +#[doc(hidden)] +pub struct AppliedDiff<'r> { + test_event: __sdk::TableAppliedDiff<'r, TestEvent>, + __unused: std::marker::PhantomData<&'r ()>, +} + +impl __sdk::InModule for AppliedDiff<'_> { + type Module = RemoteModule; +} + +impl<'r> __sdk::AppliedDiff<'r> for AppliedDiff<'r> { + fn invoke_row_callbacks(&self, event: &EventContext, callbacks: &mut __sdk::DbCallbacks) { + callbacks.invoke_table_row_callbacks::("test_event", &self.test_event, event); + } +} + +#[doc(hidden)] +pub struct RemoteModule; + +impl __sdk::InModule for RemoteModule { + type Module = Self; +} + +/// The `reducers` field of [`EventContext`] and [`DbConnection`], +/// with methods provided by extension traits for each reducer defined by the module. +pub struct RemoteReducers { + imp: __sdk::DbContextImpl, +} + +impl __sdk::InModule for RemoteReducers { + type Module = RemoteModule; +} + +/// The `procedures` field of [`DbConnection`] and other [`DbContext`] types, +/// with methods provided by extension traits for each procedure defined by the module. +pub struct RemoteProcedures { + imp: __sdk::DbContextImpl, +} + +impl __sdk::InModule for RemoteProcedures { + type Module = RemoteModule; +} + +#[doc(hidden)] +/// The `set_reducer_flags` field of [`DbConnection`], +/// with methods provided by extension traits for each reducer defined by the module. +/// Each method sets the flags for the reducer with the same name. +/// +/// This type is currently unstable and may be removed without a major version bump. +pub struct SetReducerFlags { + imp: __sdk::DbContextImpl, +} + +impl __sdk::InModule for SetReducerFlags { + type Module = RemoteModule; +} + +/// The `db` field of [`EventContext`] and [`DbConnection`], +/// with methods provided by extension traits for each table defined by the module. +pub struct RemoteTables { + imp: __sdk::DbContextImpl, +} + +impl __sdk::InModule for RemoteTables { + type Module = RemoteModule; +} + +/// A connection to a remote module, including a materialized view of a subset of the database. +/// +/// Connect to a remote module by calling [`DbConnection::builder`] +/// and using the [`__sdk::DbConnectionBuilder`] builder-pattern constructor. +/// +/// You must explicitly advance the connection by calling any one of: +/// +/// - [`DbConnection::frame_tick`]. +/// - [`DbConnection::run_threaded`]. +/// - [`DbConnection::run_async`]. +/// - [`DbConnection::advance_one_message`]. +/// - [`DbConnection::advance_one_message_blocking`]. +/// - [`DbConnection::advance_one_message_async`]. +/// +/// Which of these methods you should call depends on the specific needs of your application, +/// but you must call one of them, or else the connection will never progress. +pub struct DbConnection { + /// Access to tables defined by the module via extension traits implemented for [`RemoteTables`]. + pub db: RemoteTables, + /// Access to reducers defined by the module via extension traits implemented for [`RemoteReducers`]. + pub reducers: RemoteReducers, + #[doc(hidden)] + /// Access to setting the call-flags of each reducer defined for each reducer defined by the module + /// via extension traits implemented for [`SetReducerFlags`]. + /// + /// This type is currently unstable and may be removed without a major version bump. + pub set_reducer_flags: SetReducerFlags, + + /// Access to procedures defined by the module via extension traits implemented for [`RemoteProcedures`]. + pub procedures: RemoteProcedures, + + imp: __sdk::DbContextImpl, +} + +impl __sdk::InModule for DbConnection { + type Module = RemoteModule; +} + +impl __sdk::DbContext for DbConnection { + type DbView = RemoteTables; + type Reducers = RemoteReducers; + type Procedures = RemoteProcedures; + type SetReducerFlags = SetReducerFlags; + + fn db(&self) -> &Self::DbView { + &self.db + } + fn reducers(&self) -> &Self::Reducers { + &self.reducers + } + fn procedures(&self) -> &Self::Procedures { + &self.procedures + } + fn set_reducer_flags(&self) -> &Self::SetReducerFlags { + &self.set_reducer_flags + } + + fn is_active(&self) -> bool { + self.imp.is_active() + } + + fn disconnect(&self) -> __sdk::Result<()> { + self.imp.disconnect() + } + + type SubscriptionBuilder = __sdk::SubscriptionBuilder; + + fn subscription_builder(&self) -> Self::SubscriptionBuilder { + __sdk::SubscriptionBuilder::new(&self.imp) + } + + fn try_identity(&self) -> Option<__sdk::Identity> { + self.imp.try_identity() + } + fn connection_id(&self) -> __sdk::ConnectionId { + self.imp.connection_id() + } + fn try_connection_id(&self) -> Option<__sdk::ConnectionId> { + self.imp.try_connection_id() + } +} + +impl DbConnection { + /// Builder-pattern constructor for a connection to a remote module. + /// + /// See [`__sdk::DbConnectionBuilder`] for required and optional configuration for the new connection. + pub fn builder() -> __sdk::DbConnectionBuilder { + __sdk::DbConnectionBuilder::new() + } + + /// If any WebSocket messages are waiting, process one of them. + /// + /// Returns `true` if a message was processed, or `false` if the queue is empty. + /// Callers should invoke this message in a loop until it returns `false` + /// or for as much time is available to process messages. + /// + /// Returns an error if the connection is disconnected. + /// If the disconnection in question was normal, + /// i.e. the result of a call to [`__sdk::DbContext::disconnect`], + /// the returned error will be downcastable to [`__sdk::DisconnectedError`]. + /// + /// This is a low-level primitive exposed for power users who need significant control over scheduling. + /// Most applications should call [`Self::frame_tick`] each frame + /// to fully exhaust the queue whenever time is available. + pub fn advance_one_message(&self) -> __sdk::Result { + self.imp.advance_one_message() + } + + /// Process one WebSocket message, potentially blocking the current thread until one is received. + /// + /// Returns an error if the connection is disconnected. + /// If the disconnection in question was normal, + /// i.e. the result of a call to [`__sdk::DbContext::disconnect`], + /// the returned error will be downcastable to [`__sdk::DisconnectedError`]. + /// + /// This is a low-level primitive exposed for power users who need significant control over scheduling. + /// Most applications should call [`Self::run_threaded`] to spawn a thread + /// which advances the connection automatically. + pub fn advance_one_message_blocking(&self) -> __sdk::Result<()> { + self.imp.advance_one_message_blocking() + } + + /// Process one WebSocket message, `await`ing until one is received. + /// + /// Returns an error if the connection is disconnected. + /// If the disconnection in question was normal, + /// i.e. the result of a call to [`__sdk::DbContext::disconnect`], + /// the returned error will be downcastable to [`__sdk::DisconnectedError`]. + /// + /// This is a low-level primitive exposed for power users who need significant control over scheduling. + /// Most applications should call [`Self::run_async`] to run an `async` loop + /// which advances the connection when polled. + pub async fn advance_one_message_async(&self) -> __sdk::Result<()> { + self.imp.advance_one_message_async().await + } + + /// Process all WebSocket messages waiting in the queue, + /// then return without `await`ing or blocking the current thread. + pub fn frame_tick(&self) -> __sdk::Result<()> { + self.imp.frame_tick() + } + + /// Spawn a thread which processes WebSocket messages as they are received. + pub fn run_threaded(&self) -> std::thread::JoinHandle<()> { + self.imp.run_threaded() + } + + /// Run an `async` loop which processes WebSocket messages when polled. + pub async fn run_async(&self) -> __sdk::Result<()> { + self.imp.run_async().await + } +} + +impl __sdk::DbConnection for DbConnection { + fn new(imp: __sdk::DbContextImpl) -> Self { + Self { + db: RemoteTables { imp: imp.clone() }, + reducers: RemoteReducers { imp: imp.clone() }, + procedures: RemoteProcedures { imp: imp.clone() }, + set_reducer_flags: SetReducerFlags { imp: imp.clone() }, + imp, + } + } +} + +/// A handle on a subscribed query. +// TODO: Document this better after implementing the new subscription API. +#[derive(Clone)] +pub struct SubscriptionHandle { + imp: __sdk::SubscriptionHandleImpl, +} + +impl __sdk::InModule for SubscriptionHandle { + type Module = RemoteModule; +} + +impl __sdk::SubscriptionHandle for SubscriptionHandle { + fn new(imp: __sdk::SubscriptionHandleImpl) -> Self { + Self { imp } + } + + /// Returns true if this subscription has been terminated due to an unsubscribe call or an error. + fn is_ended(&self) -> bool { + self.imp.is_ended() + } + + /// Returns true if this subscription has been applied and has not yet been unsubscribed. + fn is_active(&self) -> bool { + self.imp.is_active() + } + + /// Unsubscribe from the query controlled by this `SubscriptionHandle`, + /// then run `on_end` when its rows are removed from the client cache. + fn unsubscribe_then(self, on_end: __sdk::OnEndedCallback) -> __sdk::Result<()> { + self.imp.unsubscribe_then(Some(on_end)) + } + + fn unsubscribe(self) -> __sdk::Result<()> { + self.imp.unsubscribe_then(None) + } +} + +/// Alias trait for a [`__sdk::DbContext`] connected to this module, +/// with that trait's associated types bounded to this module's concrete types. +/// +/// Users can use this trait as a boundary on definitions which should accept +/// either a [`DbConnection`] or an [`EventContext`] and operate on either. +pub trait RemoteDbContext: + __sdk::DbContext< + DbView = RemoteTables, + Reducers = RemoteReducers, + SetReducerFlags = SetReducerFlags, + SubscriptionBuilder = __sdk::SubscriptionBuilder, +> +{ +} +impl< + Ctx: __sdk::DbContext< + DbView = RemoteTables, + Reducers = RemoteReducers, + SetReducerFlags = SetReducerFlags, + SubscriptionBuilder = __sdk::SubscriptionBuilder, + >, + > RemoteDbContext for Ctx +{ +} + +/// An [`__sdk::DbContext`] augmented with a [`__sdk::Event`], +/// passed to [`__sdk::Table::on_insert`], [`__sdk::Table::on_delete`] and [`__sdk::TableWithPrimaryKey::on_update`] callbacks. +pub struct EventContext { + /// Access to tables defined by the module via extension traits implemented for [`RemoteTables`]. + pub db: RemoteTables, + /// Access to reducers defined by the module via extension traits implemented for [`RemoteReducers`]. + pub reducers: RemoteReducers, + /// Access to setting the call-flags of each reducer defined for each reducer defined by the module + /// via extension traits implemented for [`SetReducerFlags`]. + /// + /// This type is currently unstable and may be removed without a major version bump. + pub set_reducer_flags: SetReducerFlags, + /// Access to procedures defined by the module via extension traits implemented for [`RemoteProcedures`]. + pub procedures: RemoteProcedures, + /// The event which caused these callbacks to run. + pub event: __sdk::Event, + imp: __sdk::DbContextImpl, +} + +impl __sdk::AbstractEventContext for EventContext { + type Event = __sdk::Event; + fn event(&self) -> &Self::Event { + &self.event + } + fn new(imp: __sdk::DbContextImpl, event: Self::Event) -> Self { + Self { + db: RemoteTables { imp: imp.clone() }, + reducers: RemoteReducers { imp: imp.clone() }, + set_reducer_flags: SetReducerFlags { imp: imp.clone() }, + procedures: RemoteProcedures { imp: imp.clone() }, + event, + imp, + } + } +} + +impl __sdk::InModule for EventContext { + type Module = RemoteModule; +} + +impl __sdk::DbContext for EventContext { + type DbView = RemoteTables; + type Reducers = RemoteReducers; + type Procedures = RemoteProcedures; + type SetReducerFlags = SetReducerFlags; + + fn db(&self) -> &Self::DbView { + &self.db + } + fn reducers(&self) -> &Self::Reducers { + &self.reducers + } + fn procedures(&self) -> &Self::Procedures { + &self.procedures + } + fn set_reducer_flags(&self) -> &Self::SetReducerFlags { + &self.set_reducer_flags + } + + fn is_active(&self) -> bool { + self.imp.is_active() + } + + fn disconnect(&self) -> __sdk::Result<()> { + self.imp.disconnect() + } + + type SubscriptionBuilder = __sdk::SubscriptionBuilder; + + fn subscription_builder(&self) -> Self::SubscriptionBuilder { + __sdk::SubscriptionBuilder::new(&self.imp) + } + + fn try_identity(&self) -> Option<__sdk::Identity> { + self.imp.try_identity() + } + fn connection_id(&self) -> __sdk::ConnectionId { + self.imp.connection_id() + } + fn try_connection_id(&self) -> Option<__sdk::ConnectionId> { + self.imp.try_connection_id() + } +} + +impl __sdk::EventContext for EventContext {} + +/// An [`__sdk::DbContext`] augmented with a [`__sdk::ReducerEvent`], +/// passed to on-reducer callbacks. +pub struct ReducerEventContext { + /// Access to tables defined by the module via extension traits implemented for [`RemoteTables`]. + pub db: RemoteTables, + /// Access to reducers defined by the module via extension traits implemented for [`RemoteReducers`]. + pub reducers: RemoteReducers, + /// Access to setting the call-flags of each reducer defined for each reducer defined by the module + /// via extension traits implemented for [`SetReducerFlags`]. + /// + /// This type is currently unstable and may be removed without a major version bump. + pub set_reducer_flags: SetReducerFlags, + /// Access to procedures defined by the module via extension traits implemented for [`RemoteProcedures`]. + pub procedures: RemoteProcedures, + /// The event which caused these callbacks to run. + pub event: __sdk::ReducerEvent, + imp: __sdk::DbContextImpl, +} + +impl __sdk::AbstractEventContext for ReducerEventContext { + type Event = __sdk::ReducerEvent; + fn event(&self) -> &Self::Event { + &self.event + } + fn new(imp: __sdk::DbContextImpl, event: Self::Event) -> Self { + Self { + db: RemoteTables { imp: imp.clone() }, + reducers: RemoteReducers { imp: imp.clone() }, + set_reducer_flags: SetReducerFlags { imp: imp.clone() }, + procedures: RemoteProcedures { imp: imp.clone() }, + event, + imp, + } + } +} + +impl __sdk::InModule for ReducerEventContext { + type Module = RemoteModule; +} + +impl __sdk::DbContext for ReducerEventContext { + type DbView = RemoteTables; + type Reducers = RemoteReducers; + type Procedures = RemoteProcedures; + type SetReducerFlags = SetReducerFlags; + + fn db(&self) -> &Self::DbView { + &self.db + } + fn reducers(&self) -> &Self::Reducers { + &self.reducers + } + fn procedures(&self) -> &Self::Procedures { + &self.procedures + } + fn set_reducer_flags(&self) -> &Self::SetReducerFlags { + &self.set_reducer_flags + } + + fn is_active(&self) -> bool { + self.imp.is_active() + } + + fn disconnect(&self) -> __sdk::Result<()> { + self.imp.disconnect() + } + + type SubscriptionBuilder = __sdk::SubscriptionBuilder; + + fn subscription_builder(&self) -> Self::SubscriptionBuilder { + __sdk::SubscriptionBuilder::new(&self.imp) + } + + fn try_identity(&self) -> Option<__sdk::Identity> { + self.imp.try_identity() + } + fn connection_id(&self) -> __sdk::ConnectionId { + self.imp.connection_id() + } + fn try_connection_id(&self) -> Option<__sdk::ConnectionId> { + self.imp.try_connection_id() + } +} + +impl __sdk::ReducerEventContext for ReducerEventContext {} + +/// An [`__sdk::DbContext`] passed to procedure callbacks. +pub struct ProcedureEventContext { + /// Access to tables defined by the module via extension traits implemented for [`RemoteTables`]. + pub db: RemoteTables, + /// Access to reducers defined by the module via extension traits implemented for [`RemoteReducers`]. + pub reducers: RemoteReducers, + /// Access to setting the call-flags of each reducer defined for each reducer defined by the module + /// via extension traits implemented for [`SetReducerFlags`]. + /// + /// This type is currently unstable and may be removed without a major version bump. + pub set_reducer_flags: SetReducerFlags, + /// Access to procedures defined by the module via extension traits implemented for [`RemoteProcedures`]. + pub procedures: RemoteProcedures, + imp: __sdk::DbContextImpl, +} + +impl __sdk::AbstractEventContext for ProcedureEventContext { + type Event = (); + fn event(&self) -> &Self::Event { + &() + } + fn new(imp: __sdk::DbContextImpl, _event: Self::Event) -> Self { + Self { + db: RemoteTables { imp: imp.clone() }, + reducers: RemoteReducers { imp: imp.clone() }, + procedures: RemoteProcedures { imp: imp.clone() }, + set_reducer_flags: SetReducerFlags { imp: imp.clone() }, + imp, + } + } +} + +impl __sdk::InModule for ProcedureEventContext { + type Module = RemoteModule; +} + +impl __sdk::DbContext for ProcedureEventContext { + type DbView = RemoteTables; + type Reducers = RemoteReducers; + type Procedures = RemoteProcedures; + type SetReducerFlags = SetReducerFlags; + + fn db(&self) -> &Self::DbView { + &self.db + } + fn reducers(&self) -> &Self::Reducers { + &self.reducers + } + fn procedures(&self) -> &Self::Procedures { + &self.procedures + } + fn set_reducer_flags(&self) -> &Self::SetReducerFlags { + &self.set_reducer_flags + } + + fn is_active(&self) -> bool { + self.imp.is_active() + } + + fn disconnect(&self) -> __sdk::Result<()> { + self.imp.disconnect() + } + + type SubscriptionBuilder = __sdk::SubscriptionBuilder; + + fn subscription_builder(&self) -> Self::SubscriptionBuilder { + __sdk::SubscriptionBuilder::new(&self.imp) + } + + fn try_identity(&self) -> Option<__sdk::Identity> { + self.imp.try_identity() + } + fn connection_id(&self) -> __sdk::ConnectionId { + self.imp.connection_id() + } + fn try_connection_id(&self) -> Option<__sdk::ConnectionId> { + self.imp.try_connection_id() + } +} + +impl __sdk::ProcedureEventContext for ProcedureEventContext {} + +/// An [`__sdk::DbContext`] passed to [`__sdk::SubscriptionBuilder::on_applied`] and [`SubscriptionHandle::unsubscribe_then`] callbacks. +pub struct SubscriptionEventContext { + /// Access to tables defined by the module via extension traits implemented for [`RemoteTables`]. + pub db: RemoteTables, + /// Access to reducers defined by the module via extension traits implemented for [`RemoteReducers`]. + pub reducers: RemoteReducers, + /// Access to setting the call-flags of each reducer defined for each reducer defined by the module + /// via extension traits implemented for [`SetReducerFlags`]. + /// + /// This type is currently unstable and may be removed without a major version bump. + pub set_reducer_flags: SetReducerFlags, + /// Access to procedures defined by the module via extension traits implemented for [`RemoteProcedures`]. + pub procedures: RemoteProcedures, + imp: __sdk::DbContextImpl, +} + +impl __sdk::AbstractEventContext for SubscriptionEventContext { + type Event = (); + fn event(&self) -> &Self::Event { + &() + } + fn new(imp: __sdk::DbContextImpl, _event: Self::Event) -> Self { + Self { + db: RemoteTables { imp: imp.clone() }, + reducers: RemoteReducers { imp: imp.clone() }, + procedures: RemoteProcedures { imp: imp.clone() }, + set_reducer_flags: SetReducerFlags { imp: imp.clone() }, + imp, + } + } +} + +impl __sdk::InModule for SubscriptionEventContext { + type Module = RemoteModule; +} + +impl __sdk::DbContext for SubscriptionEventContext { + type DbView = RemoteTables; + type Reducers = RemoteReducers; + type Procedures = RemoteProcedures; + type SetReducerFlags = SetReducerFlags; + + fn db(&self) -> &Self::DbView { + &self.db + } + fn reducers(&self) -> &Self::Reducers { + &self.reducers + } + fn procedures(&self) -> &Self::Procedures { + &self.procedures + } + fn set_reducer_flags(&self) -> &Self::SetReducerFlags { + &self.set_reducer_flags + } + + fn is_active(&self) -> bool { + self.imp.is_active() + } + + fn disconnect(&self) -> __sdk::Result<()> { + self.imp.disconnect() + } + + type SubscriptionBuilder = __sdk::SubscriptionBuilder; + + fn subscription_builder(&self) -> Self::SubscriptionBuilder { + __sdk::SubscriptionBuilder::new(&self.imp) + } + + fn try_identity(&self) -> Option<__sdk::Identity> { + self.imp.try_identity() + } + fn connection_id(&self) -> __sdk::ConnectionId { + self.imp.connection_id() + } + fn try_connection_id(&self) -> Option<__sdk::ConnectionId> { + self.imp.try_connection_id() + } +} + +impl __sdk::SubscriptionEventContext for SubscriptionEventContext {} + +/// An [`__sdk::DbContext`] augmented with a [`__sdk::Error`], +/// passed to [`__sdk::DbConnectionBuilder::on_disconnect`], [`__sdk::DbConnectionBuilder::on_connect_error`] and [`__sdk::SubscriptionBuilder::on_error`] callbacks. +pub struct ErrorContext { + /// Access to tables defined by the module via extension traits implemented for [`RemoteTables`]. + pub db: RemoteTables, + /// Access to reducers defined by the module via extension traits implemented for [`RemoteReducers`]. + pub reducers: RemoteReducers, + /// Access to setting the call-flags of each reducer defined for each reducer defined by the module + /// via extension traits implemented for [`SetReducerFlags`]. + /// + /// This type is currently unstable and may be removed without a major version bump. + pub set_reducer_flags: SetReducerFlags, + /// Access to procedures defined by the module via extension traits implemented for [`RemoteProcedures`]. + pub procedures: RemoteProcedures, + /// The event which caused these callbacks to run. + pub event: Option<__sdk::Error>, + imp: __sdk::DbContextImpl, +} + +impl __sdk::AbstractEventContext for ErrorContext { + type Event = Option<__sdk::Error>; + fn event(&self) -> &Self::Event { + &self.event + } + fn new(imp: __sdk::DbContextImpl, event: Self::Event) -> Self { + Self { + db: RemoteTables { imp: imp.clone() }, + reducers: RemoteReducers { imp: imp.clone() }, + set_reducer_flags: SetReducerFlags { imp: imp.clone() }, + procedures: RemoteProcedures { imp: imp.clone() }, + event, + imp, + } + } +} + +impl __sdk::InModule for ErrorContext { + type Module = RemoteModule; +} + +impl __sdk::DbContext for ErrorContext { + type DbView = RemoteTables; + type Reducers = RemoteReducers; + type Procedures = RemoteProcedures; + type SetReducerFlags = SetReducerFlags; + + fn db(&self) -> &Self::DbView { + &self.db + } + fn reducers(&self) -> &Self::Reducers { + &self.reducers + } + fn procedures(&self) -> &Self::Procedures { + &self.procedures + } + fn set_reducer_flags(&self) -> &Self::SetReducerFlags { + &self.set_reducer_flags + } + + fn is_active(&self) -> bool { + self.imp.is_active() + } + + fn disconnect(&self) -> __sdk::Result<()> { + self.imp.disconnect() + } + + type SubscriptionBuilder = __sdk::SubscriptionBuilder; + + fn subscription_builder(&self) -> Self::SubscriptionBuilder { + __sdk::SubscriptionBuilder::new(&self.imp) + } + + fn try_identity(&self) -> Option<__sdk::Identity> { + self.imp.try_identity() + } + fn connection_id(&self) -> __sdk::ConnectionId { + self.imp.connection_id() + } + fn try_connection_id(&self) -> Option<__sdk::ConnectionId> { + self.imp.try_connection_id() + } +} + +impl __sdk::ErrorContext for ErrorContext {} + +impl __sdk::SpacetimeModule for RemoteModule { + type DbConnection = DbConnection; + type EventContext = EventContext; + type ReducerEventContext = ReducerEventContext; + type ProcedureEventContext = ProcedureEventContext; + type SubscriptionEventContext = SubscriptionEventContext; + type ErrorContext = ErrorContext; + type Reducer = Reducer; + type DbView = RemoteTables; + type Reducers = RemoteReducers; + type SetReducerFlags = SetReducerFlags; + type DbUpdate = DbUpdate; + type AppliedDiff<'r> = AppliedDiff<'r>; + type SubscriptionHandle = SubscriptionHandle; + type QueryBuilder = __sdk::QueryBuilder; + + fn register_tables(client_cache: &mut __sdk::ClientCache) { + test_event_table::register_table(client_cache); + } +} diff --git a/sdks/rust/tests/event-table-client/src/module_bindings/noop_reducer.rs b/sdks/rust/tests/event-table-client/src/module_bindings/noop_reducer.rs new file mode 100644 index 00000000000..57d204605fb --- /dev/null +++ b/sdks/rust/tests/event-table-client/src/module_bindings/noop_reducer.rs @@ -0,0 +1,94 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +#![allow(unused, clippy::all)] +use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; + +#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] +#[sats(crate = __lib)] +pub(super) struct NoopArgs {} + +impl From for super::Reducer { + fn from(args: NoopArgs) -> Self { + Self::Noop + } +} + +impl __sdk::InModule for NoopArgs { + type Module = super::RemoteModule; +} + +pub struct NoopCallbackId(__sdk::CallbackId); + +#[allow(non_camel_case_types)] +/// Extension trait for access to the reducer `noop`. +/// +/// Implemented for [`super::RemoteReducers`]. +pub trait noop { + /// Request that the remote module invoke the reducer `noop` to run as soon as possible. + /// + /// This method returns immediately, and errors only if we are unable to send the request. + /// The reducer will run asynchronously in the future, + /// and its status can be observed by listening for [`Self::on_noop`] callbacks. + fn noop(&self) -> __sdk::Result<()>; + /// Register a callback to run whenever we are notified of an invocation of the reducer `noop`. + /// + /// Callbacks should inspect the [`__sdk::ReducerEvent`] contained in the [`super::ReducerEventContext`] + /// to determine the reducer's status. + /// + /// The returned [`NoopCallbackId`] can be passed to [`Self::remove_on_noop`] + /// to cancel the callback. + fn on_noop(&self, callback: impl FnMut(&super::ReducerEventContext) + Send + 'static) -> NoopCallbackId; + /// Cancel a callback previously registered by [`Self::on_noop`], + /// causing it not to run in the future. + fn remove_on_noop(&self, callback: NoopCallbackId); +} + +impl noop for super::RemoteReducers { + fn noop(&self) -> __sdk::Result<()> { + self.imp.call_reducer("noop", NoopArgs {}) + } + fn on_noop(&self, mut callback: impl FnMut(&super::ReducerEventContext) + Send + 'static) -> NoopCallbackId { + NoopCallbackId(self.imp.on_reducer( + "noop", + Box::new(move |ctx: &super::ReducerEventContext| { + #[allow(irrefutable_let_patterns)] + let super::ReducerEventContext { + event: + __sdk::ReducerEvent { + reducer: super::Reducer::Noop {}, + .. + }, + .. + } = ctx + else { + unreachable!() + }; + callback(ctx) + }), + )) + } + fn remove_on_noop(&self, callback: NoopCallbackId) { + self.imp.remove_on_reducer("noop", callback.0) + } +} + +#[allow(non_camel_case_types)] +#[doc(hidden)] +/// Extension trait for setting the call-flags for the reducer `noop`. +/// +/// Implemented for [`super::SetReducerFlags`]. +/// +/// This type is currently unstable and may be removed without a major version bump. +pub trait set_flags_for_noop { + /// Set the call-reducer flags for the reducer `noop` to `flags`. + /// + /// This type is currently unstable and may be removed without a major version bump. + fn noop(&self, flags: __ws::CallReducerFlags); +} + +impl set_flags_for_noop for super::SetReducerFlags { + fn noop(&self, flags: __ws::CallReducerFlags) { + self.imp.set_call_reducer_flags("noop", flags); + } +} diff --git a/sdks/rust/tests/event-table-client/src/module_bindings/test_event_table.rs b/sdks/rust/tests/event-table-client/src/module_bindings/test_event_table.rs new file mode 100644 index 00000000000..c7d807a084f --- /dev/null +++ b/sdks/rust/tests/event-table-client/src/module_bindings/test_event_table.rs @@ -0,0 +1,97 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +#![allow(unused, clippy::all)] +use super::test_event_type::TestEvent; +use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; + +/// Table handle for the table `test_event`. +/// +/// Obtain a handle from the [`TestEventTableAccess::test_event`] method on [`super::RemoteTables`], +/// like `ctx.db.test_event()`. +/// +/// Users are encouraged not to explicitly reference this type, +/// but to directly chain method calls, +/// like `ctx.db.test_event().on_insert(...)`. +pub struct TestEventTableHandle<'ctx> { + imp: __sdk::TableHandle, + ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, +} + +#[allow(non_camel_case_types)] +/// Extension trait for access to the table `test_event`. +/// +/// Implemented for [`super::RemoteTables`]. +pub trait TestEventTableAccess { + #[allow(non_snake_case)] + /// Obtain a [`TestEventTableHandle`], which mediates access to the table `test_event`. + fn test_event(&self) -> TestEventTableHandle<'_>; +} + +impl TestEventTableAccess for super::RemoteTables { + fn test_event(&self) -> TestEventTableHandle<'_> { + TestEventTableHandle { + imp: self.imp.get_table::("test_event"), + ctx: std::marker::PhantomData, + } + } +} + +pub struct TestEventInsertCallbackId(__sdk::CallbackId); + +impl<'ctx> __sdk::EventTable for TestEventTableHandle<'ctx> { + type Row = TestEvent; + type EventContext = super::EventContext; + + fn count(&self) -> u64 { + self.imp.count() + } + fn iter(&self) -> impl Iterator + '_ { + self.imp.iter() + } + + type InsertCallbackId = TestEventInsertCallbackId; + + fn on_insert( + &self, + callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, + ) -> TestEventInsertCallbackId { + TestEventInsertCallbackId(self.imp.on_insert(Box::new(callback))) + } + + fn remove_on_insert(&self, callback: TestEventInsertCallbackId) { + self.imp.remove_on_insert(callback.0) + } +} + +#[doc(hidden)] +pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { + let _table = client_cache.get_or_make_table::("test_event"); +} + +#[doc(hidden)] +pub(super) fn parse_table_update( + raw_updates: __ws::TableUpdate<__ws::BsatnFormat>, +) -> __sdk::Result<__sdk::TableUpdate> { + __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { + __sdk::InternalError::failed_parse("TableUpdate", "TableUpdate") + .with_cause(e) + .into() + }) +} + +#[allow(non_camel_case_types)] +/// Extension trait for query builder access to the table `TestEvent`. +/// +/// Implemented for [`__sdk::QueryTableAccessor`]. +pub trait test_eventQueryTableAccess { + #[allow(non_snake_case)] + /// Get a query builder for the table `TestEvent`. + fn test_event(&self) -> __sdk::__query_builder::Table; +} + +impl test_eventQueryTableAccess for __sdk::QueryTableAccessor { + fn test_event(&self) -> __sdk::__query_builder::Table { + __sdk::__query_builder::Table::new("test_event") + } +} diff --git a/sdks/rust/tests/event-table-client/src/module_bindings/test_event_type.rs b/sdks/rust/tests/event-table-client/src/module_bindings/test_event_type.rs new file mode 100644 index 00000000000..03025351b0a --- /dev/null +++ b/sdks/rust/tests/event-table-client/src/module_bindings/test_event_type.rs @@ -0,0 +1,46 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +#![allow(unused, clippy::all)] +use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; + +#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] +#[sats(crate = __lib)] +pub struct TestEvent { + pub name: String, + pub value: u64, +} + +impl __sdk::InModule for TestEvent { + type Module = super::RemoteModule; +} + +/// Column accessor struct for the table `TestEvent`. +/// +/// Provides typed access to columns for query building. +pub struct TestEventCols { + pub name: __sdk::__query_builder::Col, + pub value: __sdk::__query_builder::Col, +} + +impl __sdk::__query_builder::HasCols for TestEvent { + type Cols = TestEventCols; + fn cols(table_name: &'static str) -> Self::Cols { + TestEventCols { + name: __sdk::__query_builder::Col::new(table_name, "name"), + value: __sdk::__query_builder::Col::new(table_name, "value"), + } + } +} + +/// Indexed column accessor struct for the table `TestEvent`. +/// +/// Provides typed access to indexed columns for query building. +pub struct TestEventIxCols {} + +impl __sdk::__query_builder::HasIxCols for TestEvent { + type IxCols = TestEventIxCols; + fn ix_cols(table_name: &'static str) -> Self::IxCols { + TestEventIxCols {} + } +} diff --git a/sdks/rust/tests/procedure-client/src/module_bindings/mod.rs b/sdks/rust/tests/procedure-client/src/module_bindings/mod.rs index 892f78d2899..95a3641f8d1 100644 --- a/sdks/rust/tests/procedure-client/src/module_bindings/mod.rs +++ b/sdks/rust/tests/procedure-client/src/module_bindings/mod.rs @@ -1,7 +1,7 @@ // THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE // WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. -// This was generated using spacetimedb cli version 1.11.2 (commit 13a0172567170d9b8c87d2aa71de3246c21acb8c). +// This was generated using spacetimedb cli version 1.12.0 (commit fa83d6d4023972609140a959099eab19a4e5f995). #![allow(unused, clippy::all)] use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; @@ -23,7 +23,6 @@ pub mod return_primitive_procedure; pub mod return_struct_procedure; pub mod return_struct_type; pub mod schedule_proc_reducer; -pub mod scheduled_proc_procedure; pub mod scheduled_proc_table_table; pub mod scheduled_proc_table_type; pub mod sorted_uuids_insert_procedure; @@ -46,7 +45,6 @@ pub use return_primitive_procedure::return_primitive; pub use return_struct_procedure::return_struct; pub use return_struct_type::ReturnStruct; pub use schedule_proc_reducer::{schedule_proc, set_flags_for_schedule_proc, ScheduleProcCallbackId}; -pub use scheduled_proc_procedure::scheduled_proc; pub use scheduled_proc_table_table::*; pub use scheduled_proc_table_type::ScheduledProcTable; pub use sorted_uuids_insert_procedure::sorted_uuids_insert; diff --git a/sdks/rust/tests/procedure-client/src/module_bindings/my_table_type.rs b/sdks/rust/tests/procedure-client/src/module_bindings/my_table_type.rs index 82cd36470f0..a360bcaab32 100644 --- a/sdks/rust/tests/procedure-client/src/module_bindings/my_table_type.rs +++ b/sdks/rust/tests/procedure-client/src/module_bindings/my_table_type.rs @@ -43,3 +43,5 @@ impl __sdk::__query_builder::HasIxCols for MyTable { MyTableIxCols {} } } + +impl __sdk::__query_builder::CanBeLookupTable for MyTable {} diff --git a/sdks/rust/tests/procedure-client/src/module_bindings/pk_uuid_type.rs b/sdks/rust/tests/procedure-client/src/module_bindings/pk_uuid_type.rs index 1012ac4e4d8..dcc8174a6b3 100644 --- a/sdks/rust/tests/procedure-client/src/module_bindings/pk_uuid_type.rs +++ b/sdks/rust/tests/procedure-client/src/module_bindings/pk_uuid_type.rs @@ -44,3 +44,5 @@ impl __sdk::__query_builder::HasIxCols for PkUuid { PkUuidIxCols {} } } + +impl __sdk::__query_builder::CanBeLookupTable for PkUuid {} diff --git a/sdks/rust/tests/procedure-client/src/module_bindings/proc_inserts_into_type.rs b/sdks/rust/tests/procedure-client/src/module_bindings/proc_inserts_into_type.rs index 05765b70b28..f06a33b31cb 100644 --- a/sdks/rust/tests/procedure-client/src/module_bindings/proc_inserts_into_type.rs +++ b/sdks/rust/tests/procedure-client/src/module_bindings/proc_inserts_into_type.rs @@ -50,3 +50,5 @@ impl __sdk::__query_builder::HasIxCols for ProcInsertsInto { ProcInsertsIntoIxCols {} } } + +impl __sdk::__query_builder::CanBeLookupTable for ProcInsertsInto {} diff --git a/sdks/rust/tests/procedure-client/src/module_bindings/scheduled_proc_procedure.rs b/sdks/rust/tests/procedure-client/src/module_bindings/scheduled_proc_procedure.rs deleted file mode 100644 index 124f51162f0..00000000000 --- a/sdks/rust/tests/procedure-client/src/module_bindings/scheduled_proc_procedure.rs +++ /dev/null @@ -1,46 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -use super::scheduled_proc_table_type::ScheduledProcTable; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -struct ScheduledProcArgs { - pub data: ScheduledProcTable, -} - -impl __sdk::InModule for ScheduledProcArgs { - type Module = super::RemoteModule; -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the procedure `scheduled_proc`. -/// -/// Implemented for [`super::RemoteProcedures`]. -pub trait scheduled_proc { - fn scheduled_proc(&self, data: ScheduledProcTable) { - self.scheduled_proc_then(data, |_, _| {}); - } - - fn scheduled_proc_then( - &self, - data: ScheduledProcTable, - - __callback: impl FnOnce(&super::ProcedureEventContext, Result<(), __sdk::InternalError>) + Send + 'static, - ); -} - -impl scheduled_proc for super::RemoteProcedures { - fn scheduled_proc_then( - &self, - data: ScheduledProcTable, - - __callback: impl FnOnce(&super::ProcedureEventContext, Result<(), __sdk::InternalError>) + Send + 'static, - ) { - self.imp - .invoke_procedure_with_callback::<_, ()>("scheduled_proc", ScheduledProcArgs { data }, __callback); - } -} diff --git a/sdks/rust/tests/procedure-client/src/module_bindings/scheduled_proc_table_type.rs b/sdks/rust/tests/procedure-client/src/module_bindings/scheduled_proc_table_type.rs index 18f17e192ab..63dc6bfa8c4 100644 --- a/sdks/rust/tests/procedure-client/src/module_bindings/scheduled_proc_table_type.rs +++ b/sdks/rust/tests/procedure-client/src/module_bindings/scheduled_proc_table_type.rs @@ -57,3 +57,5 @@ impl __sdk::__query_builder::HasIxCols for ScheduledProcTable { } } } + +impl __sdk::__query_builder::CanBeLookupTable for ScheduledProcTable {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/b_tree_u_32_type.rs b/sdks/rust/tests/test-client/src/module_bindings/b_tree_u_32_type.rs index 4697837f624..0453db7ae66 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/b_tree_u_32_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/b_tree_u_32_type.rs @@ -48,3 +48,5 @@ impl __sdk::__query_builder::HasIxCols for BTreeU32 { } } } + +impl __sdk::__query_builder::CanBeLookupTable for BTreeU32 {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/indexed_simple_enum_type.rs b/sdks/rust/tests/test-client/src/module_bindings/indexed_simple_enum_type.rs index 36d13c5496a..58282b102a9 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/indexed_simple_enum_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/indexed_simple_enum_type.rs @@ -47,3 +47,5 @@ impl __sdk::__query_builder::HasIxCols for IndexedSimpleEnum { } } } + +impl __sdk::__query_builder::CanBeLookupTable for IndexedSimpleEnum {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/indexed_table_2_type.rs b/sdks/rust/tests/test-client/src/module_bindings/indexed_table_2_type.rs index b9c9a0abb67..368e21c6641 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/indexed_table_2_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/indexed_table_2_type.rs @@ -44,3 +44,5 @@ impl __sdk::__query_builder::HasIxCols for IndexedTable2 { IndexedTable2IxCols {} } } + +impl __sdk::__query_builder::CanBeLookupTable for IndexedTable2 {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/indexed_table_type.rs b/sdks/rust/tests/test-client/src/module_bindings/indexed_table_type.rs index 3f889c780dd..ca74210d615 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/indexed_table_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/indexed_table_type.rs @@ -45,3 +45,5 @@ impl __sdk::__query_builder::HasIxCols for IndexedTable { } } } + +impl __sdk::__query_builder::CanBeLookupTable for IndexedTable {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/large_table_type.rs b/sdks/rust/tests/test-client/src/module_bindings/large_table_type.rs index 4fc4378d700..aa1581e17fa 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/large_table_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/large_table_type.rs @@ -111,3 +111,5 @@ impl __sdk::__query_builder::HasIxCols for LargeTable { LargeTableIxCols {} } } + +impl __sdk::__query_builder::CanBeLookupTable for LargeTable {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/mod.rs b/sdks/rust/tests/test-client/src/module_bindings/mod.rs index 88c57803d23..49666584c49 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/mod.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/mod.rs @@ -1,7 +1,7 @@ // THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE // WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. -// This was generated using spacetimedb cli version 1.11.2 (commit 13a0172567170d9b8c87d2aa71de3246c21acb8c). +// This was generated using spacetimedb cli version 1.12.0 (commit fa83d6d4023972609140a959099eab19a4e5f995). #![allow(unused, clippy::all)] use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; @@ -297,7 +297,6 @@ pub mod result_vec_i_32_string_table; pub mod result_vec_i_32_string_type; pub mod scheduled_table_table; pub mod scheduled_table_type; -pub mod send_scheduled_message_reducer; pub mod simple_enum_type; pub mod sorted_uuids_insert_reducer; pub mod table_holds_table_table; @@ -878,9 +877,6 @@ pub use result_vec_i_32_string_table::*; pub use result_vec_i_32_string_type::ResultVecI32String; pub use scheduled_table_table::*; pub use scheduled_table_type::ScheduledTable; -pub use send_scheduled_message_reducer::{ - send_scheduled_message, set_flags_for_send_scheduled_message, SendScheduledMessageCallbackId, -}; pub use simple_enum_type::SimpleEnum; pub use sorted_uuids_insert_reducer::{ set_flags_for_sorted_uuids_insert, sorted_uuids_insert, SortedUuidsInsertCallbackId, @@ -1593,9 +1589,6 @@ pub enum Reducer { u: Vec<__sdk::Uuid>, }, NoOpSucceeds, - SendScheduledMessage { - arg: ScheduledTable, - }, SortedUuidsInsert, UpdateIndexedSimpleEnum { a: SimpleEnum, @@ -1913,7 +1906,6 @@ impl __sdk::Reducer for Reducer { Reducer::InsertVecUnitStruct { .. } => "insert_vec_unit_struct", Reducer::InsertVecUuid { .. } => "insert_vec_uuid", Reducer::NoOpSucceeds => "no_op_succeeds", - Reducer::SendScheduledMessage { .. } => "send_scheduled_message", Reducer::SortedUuidsInsert => "sorted_uuids_insert", Reducer::UpdateIndexedSimpleEnum { .. } => "update_indexed_simple_enum", Reducer::UpdatePkBool { .. } => "update_pk_bool", @@ -2812,10 +2804,6 @@ impl TryFrom<__ws::ReducerCallInfo<__ws::BsatnFormat>> for Reducer { &value.args, )? .into()), - "send_scheduled_message" => Ok(__sdk::parse_reducer_args::< - send_scheduled_message_reducer::SendScheduledMessageArgs, - >("send_scheduled_message", &value.args)? - .into()), "sorted_uuids_insert" => Ok( __sdk::parse_reducer_args::( "sorted_uuids_insert", diff --git a/sdks/rust/tests/test-client/src/module_bindings/one_bool_type.rs b/sdks/rust/tests/test-client/src/module_bindings/one_bool_type.rs index 430f9301e6d..d91d401ebd9 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/one_bool_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/one_bool_type.rs @@ -41,3 +41,5 @@ impl __sdk::__query_builder::HasIxCols for OneBool { OneBoolIxCols {} } } + +impl __sdk::__query_builder::CanBeLookupTable for OneBool {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/one_byte_struct_type.rs b/sdks/rust/tests/test-client/src/module_bindings/one_byte_struct_type.rs index 351eee787d4..351c6443c7a 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/one_byte_struct_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/one_byte_struct_type.rs @@ -43,3 +43,5 @@ impl __sdk::__query_builder::HasIxCols for OneByteStruct { OneByteStructIxCols {} } } + +impl __sdk::__query_builder::CanBeLookupTable for OneByteStruct {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/one_connection_id_type.rs b/sdks/rust/tests/test-client/src/module_bindings/one_connection_id_type.rs index 2be3c7ee2ed..4b16ca7dfcd 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/one_connection_id_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/one_connection_id_type.rs @@ -41,3 +41,5 @@ impl __sdk::__query_builder::HasIxCols for OneConnectionId { OneConnectionIdIxCols {} } } + +impl __sdk::__query_builder::CanBeLookupTable for OneConnectionId {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/one_enum_with_payload_type.rs b/sdks/rust/tests/test-client/src/module_bindings/one_enum_with_payload_type.rs index 46096c40139..c544a9b52cc 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/one_enum_with_payload_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/one_enum_with_payload_type.rs @@ -43,3 +43,5 @@ impl __sdk::__query_builder::HasIxCols for OneEnumWithPayload { OneEnumWithPayloadIxCols {} } } + +impl __sdk::__query_builder::CanBeLookupTable for OneEnumWithPayload {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/one_every_primitive_struct_type.rs b/sdks/rust/tests/test-client/src/module_bindings/one_every_primitive_struct_type.rs index 1a96a23f4ae..688cc4efddd 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/one_every_primitive_struct_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/one_every_primitive_struct_type.rs @@ -43,3 +43,5 @@ impl __sdk::__query_builder::HasIxCols for OneEveryPrimitiveStruct { OneEveryPrimitiveStructIxCols {} } } + +impl __sdk::__query_builder::CanBeLookupTable for OneEveryPrimitiveStruct {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/one_every_vec_struct_type.rs b/sdks/rust/tests/test-client/src/module_bindings/one_every_vec_struct_type.rs index 03a7de83002..375e11e3c0e 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/one_every_vec_struct_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/one_every_vec_struct_type.rs @@ -43,3 +43,5 @@ impl __sdk::__query_builder::HasIxCols for OneEveryVecStruct { OneEveryVecStructIxCols {} } } + +impl __sdk::__query_builder::CanBeLookupTable for OneEveryVecStruct {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/one_f_32_type.rs b/sdks/rust/tests/test-client/src/module_bindings/one_f_32_type.rs index 34f2df8c2a5..ac2ee3e1110 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/one_f_32_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/one_f_32_type.rs @@ -41,3 +41,5 @@ impl __sdk::__query_builder::HasIxCols for OneF32 { OneF32IxCols {} } } + +impl __sdk::__query_builder::CanBeLookupTable for OneF32 {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/one_f_64_type.rs b/sdks/rust/tests/test-client/src/module_bindings/one_f_64_type.rs index 81569d91fd9..f023a2afbca 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/one_f_64_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/one_f_64_type.rs @@ -41,3 +41,5 @@ impl __sdk::__query_builder::HasIxCols for OneF64 { OneF64IxCols {} } } + +impl __sdk::__query_builder::CanBeLookupTable for OneF64 {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/one_i_128_type.rs b/sdks/rust/tests/test-client/src/module_bindings/one_i_128_type.rs index 79f23eaf8d9..36a08cd03b3 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/one_i_128_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/one_i_128_type.rs @@ -41,3 +41,5 @@ impl __sdk::__query_builder::HasIxCols for OneI128 { OneI128IxCols {} } } + +impl __sdk::__query_builder::CanBeLookupTable for OneI128 {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/one_i_16_type.rs b/sdks/rust/tests/test-client/src/module_bindings/one_i_16_type.rs index bcc3cf72cb5..051ceb7f677 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/one_i_16_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/one_i_16_type.rs @@ -41,3 +41,5 @@ impl __sdk::__query_builder::HasIxCols for OneI16 { OneI16IxCols {} } } + +impl __sdk::__query_builder::CanBeLookupTable for OneI16 {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/one_i_256_type.rs b/sdks/rust/tests/test-client/src/module_bindings/one_i_256_type.rs index 7226d1ba3e8..68d94968af9 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/one_i_256_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/one_i_256_type.rs @@ -41,3 +41,5 @@ impl __sdk::__query_builder::HasIxCols for OneI256 { OneI256IxCols {} } } + +impl __sdk::__query_builder::CanBeLookupTable for OneI256 {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/one_i_32_type.rs b/sdks/rust/tests/test-client/src/module_bindings/one_i_32_type.rs index 037740e9a37..91d98a75a3f 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/one_i_32_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/one_i_32_type.rs @@ -41,3 +41,5 @@ impl __sdk::__query_builder::HasIxCols for OneI32 { OneI32IxCols {} } } + +impl __sdk::__query_builder::CanBeLookupTable for OneI32 {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/one_i_64_type.rs b/sdks/rust/tests/test-client/src/module_bindings/one_i_64_type.rs index 4a5d7fc4937..20eea08bba2 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/one_i_64_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/one_i_64_type.rs @@ -41,3 +41,5 @@ impl __sdk::__query_builder::HasIxCols for OneI64 { OneI64IxCols {} } } + +impl __sdk::__query_builder::CanBeLookupTable for OneI64 {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/one_i_8_type.rs b/sdks/rust/tests/test-client/src/module_bindings/one_i_8_type.rs index 9e5a5e9875e..886e0152acd 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/one_i_8_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/one_i_8_type.rs @@ -41,3 +41,5 @@ impl __sdk::__query_builder::HasIxCols for OneI8 { OneI8IxCols {} } } + +impl __sdk::__query_builder::CanBeLookupTable for OneI8 {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/one_identity_type.rs b/sdks/rust/tests/test-client/src/module_bindings/one_identity_type.rs index cf084da63f6..c394cbe6b5c 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/one_identity_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/one_identity_type.rs @@ -41,3 +41,5 @@ impl __sdk::__query_builder::HasIxCols for OneIdentity { OneIdentityIxCols {} } } + +impl __sdk::__query_builder::CanBeLookupTable for OneIdentity {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/one_simple_enum_type.rs b/sdks/rust/tests/test-client/src/module_bindings/one_simple_enum_type.rs index 3a9fdec6366..709946fe51a 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/one_simple_enum_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/one_simple_enum_type.rs @@ -43,3 +43,5 @@ impl __sdk::__query_builder::HasIxCols for OneSimpleEnum { OneSimpleEnumIxCols {} } } + +impl __sdk::__query_builder::CanBeLookupTable for OneSimpleEnum {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/one_string_type.rs b/sdks/rust/tests/test-client/src/module_bindings/one_string_type.rs index b865038c2ad..483871a58ec 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/one_string_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/one_string_type.rs @@ -41,3 +41,5 @@ impl __sdk::__query_builder::HasIxCols for OneString { OneStringIxCols {} } } + +impl __sdk::__query_builder::CanBeLookupTable for OneString {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/one_timestamp_type.rs b/sdks/rust/tests/test-client/src/module_bindings/one_timestamp_type.rs index 627dc23f012..fb84d4f1f08 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/one_timestamp_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/one_timestamp_type.rs @@ -41,3 +41,5 @@ impl __sdk::__query_builder::HasIxCols for OneTimestamp { OneTimestampIxCols {} } } + +impl __sdk::__query_builder::CanBeLookupTable for OneTimestamp {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/one_u_128_type.rs b/sdks/rust/tests/test-client/src/module_bindings/one_u_128_type.rs index 37a5596dfb7..ebacc86601d 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/one_u_128_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/one_u_128_type.rs @@ -41,3 +41,5 @@ impl __sdk::__query_builder::HasIxCols for OneU128 { OneU128IxCols {} } } + +impl __sdk::__query_builder::CanBeLookupTable for OneU128 {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/one_u_16_type.rs b/sdks/rust/tests/test-client/src/module_bindings/one_u_16_type.rs index 14d5ae4ca66..2326dfa3cdd 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/one_u_16_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/one_u_16_type.rs @@ -41,3 +41,5 @@ impl __sdk::__query_builder::HasIxCols for OneU16 { OneU16IxCols {} } } + +impl __sdk::__query_builder::CanBeLookupTable for OneU16 {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/one_u_256_type.rs b/sdks/rust/tests/test-client/src/module_bindings/one_u_256_type.rs index f46374339c6..431897ed9f6 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/one_u_256_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/one_u_256_type.rs @@ -41,3 +41,5 @@ impl __sdk::__query_builder::HasIxCols for OneU256 { OneU256IxCols {} } } + +impl __sdk::__query_builder::CanBeLookupTable for OneU256 {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/one_u_32_type.rs b/sdks/rust/tests/test-client/src/module_bindings/one_u_32_type.rs index 631a64eba6e..c0277eae098 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/one_u_32_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/one_u_32_type.rs @@ -41,3 +41,5 @@ impl __sdk::__query_builder::HasIxCols for OneU32 { OneU32IxCols {} } } + +impl __sdk::__query_builder::CanBeLookupTable for OneU32 {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/one_u_64_type.rs b/sdks/rust/tests/test-client/src/module_bindings/one_u_64_type.rs index d28962f0807..113b4cde7c7 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/one_u_64_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/one_u_64_type.rs @@ -41,3 +41,5 @@ impl __sdk::__query_builder::HasIxCols for OneU64 { OneU64IxCols {} } } + +impl __sdk::__query_builder::CanBeLookupTable for OneU64 {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/one_u_8_type.rs b/sdks/rust/tests/test-client/src/module_bindings/one_u_8_type.rs index 2f2c371fc58..e145bafcf2b 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/one_u_8_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/one_u_8_type.rs @@ -41,3 +41,5 @@ impl __sdk::__query_builder::HasIxCols for OneU8 { OneU8IxCols {} } } + +impl __sdk::__query_builder::CanBeLookupTable for OneU8 {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/one_unit_struct_type.rs b/sdks/rust/tests/test-client/src/module_bindings/one_unit_struct_type.rs index ca2a9f6aea8..86e0c90fc02 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/one_unit_struct_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/one_unit_struct_type.rs @@ -43,3 +43,5 @@ impl __sdk::__query_builder::HasIxCols for OneUnitStruct { OneUnitStructIxCols {} } } + +impl __sdk::__query_builder::CanBeLookupTable for OneUnitStruct {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/one_uuid_type.rs b/sdks/rust/tests/test-client/src/module_bindings/one_uuid_type.rs index 63ca43baa28..ffec937559d 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/one_uuid_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/one_uuid_type.rs @@ -41,3 +41,5 @@ impl __sdk::__query_builder::HasIxCols for OneUuid { OneUuidIxCols {} } } + +impl __sdk::__query_builder::CanBeLookupTable for OneUuid {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/option_every_primitive_struct_type.rs b/sdks/rust/tests/test-client/src/module_bindings/option_every_primitive_struct_type.rs index 48bcea2ef6c..d14c9a2af4f 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/option_every_primitive_struct_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/option_every_primitive_struct_type.rs @@ -43,3 +43,5 @@ impl __sdk::__query_builder::HasIxCols for OptionEveryPrimitiveStruct { OptionEveryPrimitiveStructIxCols {} } } + +impl __sdk::__query_builder::CanBeLookupTable for OptionEveryPrimitiveStruct {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/option_i_32_type.rs b/sdks/rust/tests/test-client/src/module_bindings/option_i_32_type.rs index e037ef3fcae..11999e80687 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/option_i_32_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/option_i_32_type.rs @@ -41,3 +41,5 @@ impl __sdk::__query_builder::HasIxCols for OptionI32 { OptionI32IxCols {} } } + +impl __sdk::__query_builder::CanBeLookupTable for OptionI32 {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/option_identity_type.rs b/sdks/rust/tests/test-client/src/module_bindings/option_identity_type.rs index 7662160d308..cdef62b565a 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/option_identity_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/option_identity_type.rs @@ -41,3 +41,5 @@ impl __sdk::__query_builder::HasIxCols for OptionIdentity { OptionIdentityIxCols {} } } + +impl __sdk::__query_builder::CanBeLookupTable for OptionIdentity {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/option_simple_enum_type.rs b/sdks/rust/tests/test-client/src/module_bindings/option_simple_enum_type.rs index 22a0f637cfa..7a9677dc52f 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/option_simple_enum_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/option_simple_enum_type.rs @@ -43,3 +43,5 @@ impl __sdk::__query_builder::HasIxCols for OptionSimpleEnum { OptionSimpleEnumIxCols {} } } + +impl __sdk::__query_builder::CanBeLookupTable for OptionSimpleEnum {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/option_string_type.rs b/sdks/rust/tests/test-client/src/module_bindings/option_string_type.rs index a15c40a4169..2ee9db0e75e 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/option_string_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/option_string_type.rs @@ -41,3 +41,5 @@ impl __sdk::__query_builder::HasIxCols for OptionString { OptionStringIxCols {} } } + +impl __sdk::__query_builder::CanBeLookupTable for OptionString {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/option_uuid_type.rs b/sdks/rust/tests/test-client/src/module_bindings/option_uuid_type.rs index eae9603c07a..d861e5d1dbb 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/option_uuid_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/option_uuid_type.rs @@ -41,3 +41,5 @@ impl __sdk::__query_builder::HasIxCols for OptionUuid { OptionUuidIxCols {} } } + +impl __sdk::__query_builder::CanBeLookupTable for OptionUuid {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/option_vec_option_i_32_type.rs b/sdks/rust/tests/test-client/src/module_bindings/option_vec_option_i_32_type.rs index c7ee8b31def..af5e6d52756 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/option_vec_option_i_32_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/option_vec_option_i_32_type.rs @@ -41,3 +41,5 @@ impl __sdk::__query_builder::HasIxCols for OptionVecOptionI32 { OptionVecOptionI32IxCols {} } } + +impl __sdk::__query_builder::CanBeLookupTable for OptionVecOptionI32 {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/pk_bool_type.rs b/sdks/rust/tests/test-client/src/module_bindings/pk_bool_type.rs index daee77e680e..9f4603ebe45 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/pk_bool_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/pk_bool_type.rs @@ -48,3 +48,5 @@ impl __sdk::__query_builder::HasIxCols for PkBool { } } } + +impl __sdk::__query_builder::CanBeLookupTable for PkBool {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/pk_connection_id_type.rs b/sdks/rust/tests/test-client/src/module_bindings/pk_connection_id_type.rs index 485f6174a1c..b2bf86242c9 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/pk_connection_id_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/pk_connection_id_type.rs @@ -48,3 +48,5 @@ impl __sdk::__query_builder::HasIxCols for PkConnectionId { } } } + +impl __sdk::__query_builder::CanBeLookupTable for PkConnectionId {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/pk_i_128_type.rs b/sdks/rust/tests/test-client/src/module_bindings/pk_i_128_type.rs index e92583fc9ae..d44037ca6c3 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/pk_i_128_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/pk_i_128_type.rs @@ -48,3 +48,5 @@ impl __sdk::__query_builder::HasIxCols for PkI128 { } } } + +impl __sdk::__query_builder::CanBeLookupTable for PkI128 {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/pk_i_16_type.rs b/sdks/rust/tests/test-client/src/module_bindings/pk_i_16_type.rs index b4f1dd4aae7..2487520d2b9 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/pk_i_16_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/pk_i_16_type.rs @@ -48,3 +48,5 @@ impl __sdk::__query_builder::HasIxCols for PkI16 { } } } + +impl __sdk::__query_builder::CanBeLookupTable for PkI16 {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/pk_i_256_type.rs b/sdks/rust/tests/test-client/src/module_bindings/pk_i_256_type.rs index 2efccf4bd1b..60c4ac60288 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/pk_i_256_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/pk_i_256_type.rs @@ -48,3 +48,5 @@ impl __sdk::__query_builder::HasIxCols for PkI256 { } } } + +impl __sdk::__query_builder::CanBeLookupTable for PkI256 {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/pk_i_32_type.rs b/sdks/rust/tests/test-client/src/module_bindings/pk_i_32_type.rs index cad072e3967..97e53a60b70 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/pk_i_32_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/pk_i_32_type.rs @@ -48,3 +48,5 @@ impl __sdk::__query_builder::HasIxCols for PkI32 { } } } + +impl __sdk::__query_builder::CanBeLookupTable for PkI32 {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/pk_i_64_type.rs b/sdks/rust/tests/test-client/src/module_bindings/pk_i_64_type.rs index de77151dc75..58c9f73b0a8 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/pk_i_64_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/pk_i_64_type.rs @@ -48,3 +48,5 @@ impl __sdk::__query_builder::HasIxCols for PkI64 { } } } + +impl __sdk::__query_builder::CanBeLookupTable for PkI64 {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/pk_i_8_type.rs b/sdks/rust/tests/test-client/src/module_bindings/pk_i_8_type.rs index 266a42838ac..00683d16fa2 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/pk_i_8_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/pk_i_8_type.rs @@ -48,3 +48,5 @@ impl __sdk::__query_builder::HasIxCols for PkI8 { } } } + +impl __sdk::__query_builder::CanBeLookupTable for PkI8 {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/pk_identity_type.rs b/sdks/rust/tests/test-client/src/module_bindings/pk_identity_type.rs index b3dd11bd37f..3b0d4700d57 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/pk_identity_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/pk_identity_type.rs @@ -48,3 +48,5 @@ impl __sdk::__query_builder::HasIxCols for PkIdentity { } } } + +impl __sdk::__query_builder::CanBeLookupTable for PkIdentity {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/pk_simple_enum_type.rs b/sdks/rust/tests/test-client/src/module_bindings/pk_simple_enum_type.rs index bd8c3a224db..33fe9505daf 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/pk_simple_enum_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/pk_simple_enum_type.rs @@ -50,3 +50,5 @@ impl __sdk::__query_builder::HasIxCols for PkSimpleEnum { } } } + +impl __sdk::__query_builder::CanBeLookupTable for PkSimpleEnum {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/pk_string_type.rs b/sdks/rust/tests/test-client/src/module_bindings/pk_string_type.rs index c0b1fd6dbcb..fc5700525e3 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/pk_string_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/pk_string_type.rs @@ -48,3 +48,5 @@ impl __sdk::__query_builder::HasIxCols for PkString { } } } + +impl __sdk::__query_builder::CanBeLookupTable for PkString {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/pk_u_128_type.rs b/sdks/rust/tests/test-client/src/module_bindings/pk_u_128_type.rs index 1dd77a89d92..4af2d8bf2b9 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/pk_u_128_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/pk_u_128_type.rs @@ -48,3 +48,5 @@ impl __sdk::__query_builder::HasIxCols for PkU128 { } } } + +impl __sdk::__query_builder::CanBeLookupTable for PkU128 {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/pk_u_16_type.rs b/sdks/rust/tests/test-client/src/module_bindings/pk_u_16_type.rs index 62dfd8240a2..7313b109bee 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/pk_u_16_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/pk_u_16_type.rs @@ -48,3 +48,5 @@ impl __sdk::__query_builder::HasIxCols for PkU16 { } } } + +impl __sdk::__query_builder::CanBeLookupTable for PkU16 {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/pk_u_256_type.rs b/sdks/rust/tests/test-client/src/module_bindings/pk_u_256_type.rs index f5c16e98e8d..e46bba4b98c 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/pk_u_256_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/pk_u_256_type.rs @@ -48,3 +48,5 @@ impl __sdk::__query_builder::HasIxCols for PkU256 { } } } + +impl __sdk::__query_builder::CanBeLookupTable for PkU256 {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/pk_u_32_two_type.rs b/sdks/rust/tests/test-client/src/module_bindings/pk_u_32_two_type.rs index 05845bc1fe2..5651bd8f752 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/pk_u_32_two_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/pk_u_32_two_type.rs @@ -48,3 +48,5 @@ impl __sdk::__query_builder::HasIxCols for PkU32Two { } } } + +impl __sdk::__query_builder::CanBeLookupTable for PkU32Two {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/pk_u_32_type.rs b/sdks/rust/tests/test-client/src/module_bindings/pk_u_32_type.rs index ae7339a90db..0305bb17994 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/pk_u_32_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/pk_u_32_type.rs @@ -48,3 +48,5 @@ impl __sdk::__query_builder::HasIxCols for PkU32 { } } } + +impl __sdk::__query_builder::CanBeLookupTable for PkU32 {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/pk_u_64_type.rs b/sdks/rust/tests/test-client/src/module_bindings/pk_u_64_type.rs index bcfe7145e51..9f4c617cc12 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/pk_u_64_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/pk_u_64_type.rs @@ -48,3 +48,5 @@ impl __sdk::__query_builder::HasIxCols for PkU64 { } } } + +impl __sdk::__query_builder::CanBeLookupTable for PkU64 {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/pk_u_8_type.rs b/sdks/rust/tests/test-client/src/module_bindings/pk_u_8_type.rs index 17f08e60179..04e2fc30b48 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/pk_u_8_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/pk_u_8_type.rs @@ -48,3 +48,5 @@ impl __sdk::__query_builder::HasIxCols for PkU8 { } } } + +impl __sdk::__query_builder::CanBeLookupTable for PkU8 {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/pk_uuid_type.rs b/sdks/rust/tests/test-client/src/module_bindings/pk_uuid_type.rs index b1c622d5da9..62acd5125be 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/pk_uuid_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/pk_uuid_type.rs @@ -48,3 +48,5 @@ impl __sdk::__query_builder::HasIxCols for PkUuid { } } } + +impl __sdk::__query_builder::CanBeLookupTable for PkUuid {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/result_every_primitive_struct_string_type.rs b/sdks/rust/tests/test-client/src/module_bindings/result_every_primitive_struct_string_type.rs index 050a599e3df..92228597561 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/result_every_primitive_struct_string_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/result_every_primitive_struct_string_type.rs @@ -43,3 +43,5 @@ impl __sdk::__query_builder::HasIxCols for ResultEveryPrimitiveStructString { ResultEveryPrimitiveStructStringIxCols {} } } + +impl __sdk::__query_builder::CanBeLookupTable for ResultEveryPrimitiveStructString {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/result_i_32_string_type.rs b/sdks/rust/tests/test-client/src/module_bindings/result_i_32_string_type.rs index 17f2efd216b..dde3d94ca4a 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/result_i_32_string_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/result_i_32_string_type.rs @@ -41,3 +41,5 @@ impl __sdk::__query_builder::HasIxCols for ResultI32String { ResultI32StringIxCols {} } } + +impl __sdk::__query_builder::CanBeLookupTable for ResultI32String {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/result_identity_string_type.rs b/sdks/rust/tests/test-client/src/module_bindings/result_identity_string_type.rs index ab7e5cce456..1cdb485977e 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/result_identity_string_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/result_identity_string_type.rs @@ -41,3 +41,5 @@ impl __sdk::__query_builder::HasIxCols for ResultIdentityString { ResultIdentityStringIxCols {} } } + +impl __sdk::__query_builder::CanBeLookupTable for ResultIdentityString {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/result_simple_enum_i_32_type.rs b/sdks/rust/tests/test-client/src/module_bindings/result_simple_enum_i_32_type.rs index da5e7e14a14..e89806e4a7e 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/result_simple_enum_i_32_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/result_simple_enum_i_32_type.rs @@ -43,3 +43,5 @@ impl __sdk::__query_builder::HasIxCols for ResultSimpleEnumI32 { ResultSimpleEnumI32IxCols {} } } + +impl __sdk::__query_builder::CanBeLookupTable for ResultSimpleEnumI32 {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/result_string_i_32_type.rs b/sdks/rust/tests/test-client/src/module_bindings/result_string_i_32_type.rs index 1e1e92a35be..ab52954cf94 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/result_string_i_32_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/result_string_i_32_type.rs @@ -41,3 +41,5 @@ impl __sdk::__query_builder::HasIxCols for ResultStringI32 { ResultStringI32IxCols {} } } + +impl __sdk::__query_builder::CanBeLookupTable for ResultStringI32 {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/result_vec_i_32_string_type.rs b/sdks/rust/tests/test-client/src/module_bindings/result_vec_i_32_string_type.rs index a65bb19af11..66ce7a2d84d 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/result_vec_i_32_string_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/result_vec_i_32_string_type.rs @@ -41,3 +41,5 @@ impl __sdk::__query_builder::HasIxCols for ResultVecI32String { ResultVecI32StringIxCols {} } } + +impl __sdk::__query_builder::CanBeLookupTable for ResultVecI32String {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/scheduled_table_type.rs b/sdks/rust/tests/test-client/src/module_bindings/scheduled_table_type.rs index 45b88ef0a35..671d9dbb9a8 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/scheduled_table_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/scheduled_table_type.rs @@ -51,3 +51,5 @@ impl __sdk::__query_builder::HasIxCols for ScheduledTable { } } } + +impl __sdk::__query_builder::CanBeLookupTable for ScheduledTable {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/send_scheduled_message_reducer.rs b/sdks/rust/tests/test-client/src/module_bindings/send_scheduled_message_reducer.rs deleted file mode 100644 index 0eaed8a2a8b..00000000000 --- a/sdks/rust/tests/test-client/src/module_bindings/send_scheduled_message_reducer.rs +++ /dev/null @@ -1,105 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -use super::scheduled_table_type::ScheduledTable; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub(super) struct SendScheduledMessageArgs { - pub arg: ScheduledTable, -} - -impl From for super::Reducer { - fn from(args: SendScheduledMessageArgs) -> Self { - Self::SendScheduledMessage { arg: args.arg } - } -} - -impl __sdk::InModule for SendScheduledMessageArgs { - type Module = super::RemoteModule; -} - -pub struct SendScheduledMessageCallbackId(__sdk::CallbackId); - -#[allow(non_camel_case_types)] -/// Extension trait for access to the reducer `send_scheduled_message`. -/// -/// Implemented for [`super::RemoteReducers`]. -pub trait send_scheduled_message { - /// Request that the remote module invoke the reducer `send_scheduled_message` to run as soon as possible. - /// - /// This method returns immediately, and errors only if we are unable to send the request. - /// The reducer will run asynchronously in the future, - /// and its status can be observed by listening for [`Self::on_send_scheduled_message`] callbacks. - fn send_scheduled_message(&self, arg: ScheduledTable) -> __sdk::Result<()>; - /// Register a callback to run whenever we are notified of an invocation of the reducer `send_scheduled_message`. - /// - /// Callbacks should inspect the [`__sdk::ReducerEvent`] contained in the [`super::ReducerEventContext`] - /// to determine the reducer's status. - /// - /// The returned [`SendScheduledMessageCallbackId`] can be passed to [`Self::remove_on_send_scheduled_message`] - /// to cancel the callback. - fn on_send_scheduled_message( - &self, - callback: impl FnMut(&super::ReducerEventContext, &ScheduledTable) + Send + 'static, - ) -> SendScheduledMessageCallbackId; - /// Cancel a callback previously registered by [`Self::on_send_scheduled_message`], - /// causing it not to run in the future. - fn remove_on_send_scheduled_message(&self, callback: SendScheduledMessageCallbackId); -} - -impl send_scheduled_message for super::RemoteReducers { - fn send_scheduled_message(&self, arg: ScheduledTable) -> __sdk::Result<()> { - self.imp - .call_reducer("send_scheduled_message", SendScheduledMessageArgs { arg }) - } - fn on_send_scheduled_message( - &self, - mut callback: impl FnMut(&super::ReducerEventContext, &ScheduledTable) + Send + 'static, - ) -> SendScheduledMessageCallbackId { - SendScheduledMessageCallbackId(self.imp.on_reducer( - "send_scheduled_message", - Box::new(move |ctx: &super::ReducerEventContext| { - #[allow(irrefutable_let_patterns)] - let super::ReducerEventContext { - event: - __sdk::ReducerEvent { - reducer: super::Reducer::SendScheduledMessage { arg }, - .. - }, - .. - } = ctx - else { - unreachable!() - }; - callback(ctx, arg) - }), - )) - } - fn remove_on_send_scheduled_message(&self, callback: SendScheduledMessageCallbackId) { - self.imp.remove_on_reducer("send_scheduled_message", callback.0) - } -} - -#[allow(non_camel_case_types)] -#[doc(hidden)] -/// Extension trait for setting the call-flags for the reducer `send_scheduled_message`. -/// -/// Implemented for [`super::SetReducerFlags`]. -/// -/// This type is currently unstable and may be removed without a major version bump. -pub trait set_flags_for_send_scheduled_message { - /// Set the call-reducer flags for the reducer `send_scheduled_message` to `flags`. - /// - /// This type is currently unstable and may be removed without a major version bump. - fn send_scheduled_message(&self, flags: __ws::CallReducerFlags); -} - -impl set_flags_for_send_scheduled_message for super::SetReducerFlags { - fn send_scheduled_message(&self, flags: __ws::CallReducerFlags) { - self.imp.set_call_reducer_flags("send_scheduled_message", flags); - } -} diff --git a/sdks/rust/tests/test-client/src/module_bindings/table_holds_table_type.rs b/sdks/rust/tests/test-client/src/module_bindings/table_holds_table_type.rs index f2fcf482df9..6428bc12127 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/table_holds_table_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/table_holds_table_type.rs @@ -47,3 +47,5 @@ impl __sdk::__query_builder::HasIxCols for TableHoldsTable { TableHoldsTableIxCols {} } } + +impl __sdk::__query_builder::CanBeLookupTable for TableHoldsTable {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/unique_bool_type.rs b/sdks/rust/tests/test-client/src/module_bindings/unique_bool_type.rs index 92652790a32..8dd6e742b46 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/unique_bool_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/unique_bool_type.rs @@ -48,3 +48,5 @@ impl __sdk::__query_builder::HasIxCols for UniqueBool { } } } + +impl __sdk::__query_builder::CanBeLookupTable for UniqueBool {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/unique_connection_id_type.rs b/sdks/rust/tests/test-client/src/module_bindings/unique_connection_id_type.rs index 17cff44a1bb..372dc63cd3d 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/unique_connection_id_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/unique_connection_id_type.rs @@ -48,3 +48,5 @@ impl __sdk::__query_builder::HasIxCols for UniqueConnectionId { } } } + +impl __sdk::__query_builder::CanBeLookupTable for UniqueConnectionId {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/unique_i_128_type.rs b/sdks/rust/tests/test-client/src/module_bindings/unique_i_128_type.rs index 4d89b720575..7861798ccb6 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/unique_i_128_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/unique_i_128_type.rs @@ -48,3 +48,5 @@ impl __sdk::__query_builder::HasIxCols for UniqueI128 { } } } + +impl __sdk::__query_builder::CanBeLookupTable for UniqueI128 {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/unique_i_16_type.rs b/sdks/rust/tests/test-client/src/module_bindings/unique_i_16_type.rs index 2743c6b2b45..54752636e8d 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/unique_i_16_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/unique_i_16_type.rs @@ -48,3 +48,5 @@ impl __sdk::__query_builder::HasIxCols for UniqueI16 { } } } + +impl __sdk::__query_builder::CanBeLookupTable for UniqueI16 {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/unique_i_256_type.rs b/sdks/rust/tests/test-client/src/module_bindings/unique_i_256_type.rs index 6571e72c953..a7d37880089 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/unique_i_256_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/unique_i_256_type.rs @@ -48,3 +48,5 @@ impl __sdk::__query_builder::HasIxCols for UniqueI256 { } } } + +impl __sdk::__query_builder::CanBeLookupTable for UniqueI256 {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/unique_i_32_type.rs b/sdks/rust/tests/test-client/src/module_bindings/unique_i_32_type.rs index 2bc9b21003e..63af8b357a3 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/unique_i_32_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/unique_i_32_type.rs @@ -48,3 +48,5 @@ impl __sdk::__query_builder::HasIxCols for UniqueI32 { } } } + +impl __sdk::__query_builder::CanBeLookupTable for UniqueI32 {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/unique_i_64_type.rs b/sdks/rust/tests/test-client/src/module_bindings/unique_i_64_type.rs index 8d7bc39e42f..a61f2af8d5d 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/unique_i_64_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/unique_i_64_type.rs @@ -48,3 +48,5 @@ impl __sdk::__query_builder::HasIxCols for UniqueI64 { } } } + +impl __sdk::__query_builder::CanBeLookupTable for UniqueI64 {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/unique_i_8_type.rs b/sdks/rust/tests/test-client/src/module_bindings/unique_i_8_type.rs index fd47d0cd913..ee7d92f5a4e 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/unique_i_8_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/unique_i_8_type.rs @@ -48,3 +48,5 @@ impl __sdk::__query_builder::HasIxCols for UniqueI8 { } } } + +impl __sdk::__query_builder::CanBeLookupTable for UniqueI8 {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/unique_identity_type.rs b/sdks/rust/tests/test-client/src/module_bindings/unique_identity_type.rs index 0a6e5554f82..550b4f355fd 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/unique_identity_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/unique_identity_type.rs @@ -48,3 +48,5 @@ impl __sdk::__query_builder::HasIxCols for UniqueIdentity { } } } + +impl __sdk::__query_builder::CanBeLookupTable for UniqueIdentity {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/unique_string_type.rs b/sdks/rust/tests/test-client/src/module_bindings/unique_string_type.rs index 603f60e8b57..3cb1224248c 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/unique_string_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/unique_string_type.rs @@ -48,3 +48,5 @@ impl __sdk::__query_builder::HasIxCols for UniqueString { } } } + +impl __sdk::__query_builder::CanBeLookupTable for UniqueString {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/unique_u_128_type.rs b/sdks/rust/tests/test-client/src/module_bindings/unique_u_128_type.rs index e75ee09a2a3..ff8cb2d808b 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/unique_u_128_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/unique_u_128_type.rs @@ -48,3 +48,5 @@ impl __sdk::__query_builder::HasIxCols for UniqueU128 { } } } + +impl __sdk::__query_builder::CanBeLookupTable for UniqueU128 {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/unique_u_16_type.rs b/sdks/rust/tests/test-client/src/module_bindings/unique_u_16_type.rs index 571fb9ee4c0..d5346884c0d 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/unique_u_16_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/unique_u_16_type.rs @@ -48,3 +48,5 @@ impl __sdk::__query_builder::HasIxCols for UniqueU16 { } } } + +impl __sdk::__query_builder::CanBeLookupTable for UniqueU16 {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/unique_u_256_type.rs b/sdks/rust/tests/test-client/src/module_bindings/unique_u_256_type.rs index 2bd9da359cb..4f3011011d0 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/unique_u_256_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/unique_u_256_type.rs @@ -48,3 +48,5 @@ impl __sdk::__query_builder::HasIxCols for UniqueU256 { } } } + +impl __sdk::__query_builder::CanBeLookupTable for UniqueU256 {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/unique_u_32_type.rs b/sdks/rust/tests/test-client/src/module_bindings/unique_u_32_type.rs index 9f9d9bd501f..1b1b9a67db7 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/unique_u_32_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/unique_u_32_type.rs @@ -48,3 +48,5 @@ impl __sdk::__query_builder::HasIxCols for UniqueU32 { } } } + +impl __sdk::__query_builder::CanBeLookupTable for UniqueU32 {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/unique_u_64_type.rs b/sdks/rust/tests/test-client/src/module_bindings/unique_u_64_type.rs index e4b29d0f09f..67dfa279a93 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/unique_u_64_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/unique_u_64_type.rs @@ -48,3 +48,5 @@ impl __sdk::__query_builder::HasIxCols for UniqueU64 { } } } + +impl __sdk::__query_builder::CanBeLookupTable for UniqueU64 {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/unique_u_8_type.rs b/sdks/rust/tests/test-client/src/module_bindings/unique_u_8_type.rs index fec9b5736f2..244a5b4dfe3 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/unique_u_8_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/unique_u_8_type.rs @@ -48,3 +48,5 @@ impl __sdk::__query_builder::HasIxCols for UniqueU8 { } } } + +impl __sdk::__query_builder::CanBeLookupTable for UniqueU8 {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/unique_uuid_type.rs b/sdks/rust/tests/test-client/src/module_bindings/unique_uuid_type.rs index 25c34119951..356e66a5c4e 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/unique_uuid_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/unique_uuid_type.rs @@ -48,3 +48,5 @@ impl __sdk::__query_builder::HasIxCols for UniqueUuid { } } } + +impl __sdk::__query_builder::CanBeLookupTable for UniqueUuid {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/users_type.rs b/sdks/rust/tests/test-client/src/module_bindings/users_type.rs index e9c256c2e28..8d0c5ec8726 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/users_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/users_type.rs @@ -48,3 +48,5 @@ impl __sdk::__query_builder::HasIxCols for Users { } } } + +impl __sdk::__query_builder::CanBeLookupTable for Users {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/vec_bool_type.rs b/sdks/rust/tests/test-client/src/module_bindings/vec_bool_type.rs index 85f50be571e..5b42fa0c9c0 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/vec_bool_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/vec_bool_type.rs @@ -41,3 +41,5 @@ impl __sdk::__query_builder::HasIxCols for VecBool { VecBoolIxCols {} } } + +impl __sdk::__query_builder::CanBeLookupTable for VecBool {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/vec_byte_struct_type.rs b/sdks/rust/tests/test-client/src/module_bindings/vec_byte_struct_type.rs index df8233ef624..3877d7a6531 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/vec_byte_struct_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/vec_byte_struct_type.rs @@ -43,3 +43,5 @@ impl __sdk::__query_builder::HasIxCols for VecByteStruct { VecByteStructIxCols {} } } + +impl __sdk::__query_builder::CanBeLookupTable for VecByteStruct {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/vec_connection_id_type.rs b/sdks/rust/tests/test-client/src/module_bindings/vec_connection_id_type.rs index 5205f48403e..faa6c9999a8 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/vec_connection_id_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/vec_connection_id_type.rs @@ -41,3 +41,5 @@ impl __sdk::__query_builder::HasIxCols for VecConnectionId { VecConnectionIdIxCols {} } } + +impl __sdk::__query_builder::CanBeLookupTable for VecConnectionId {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/vec_enum_with_payload_type.rs b/sdks/rust/tests/test-client/src/module_bindings/vec_enum_with_payload_type.rs index 9f012d949d7..d083b3daad9 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/vec_enum_with_payload_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/vec_enum_with_payload_type.rs @@ -43,3 +43,5 @@ impl __sdk::__query_builder::HasIxCols for VecEnumWithPayload { VecEnumWithPayloadIxCols {} } } + +impl __sdk::__query_builder::CanBeLookupTable for VecEnumWithPayload {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/vec_every_primitive_struct_type.rs b/sdks/rust/tests/test-client/src/module_bindings/vec_every_primitive_struct_type.rs index 52f9e17448d..3833b05fc25 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/vec_every_primitive_struct_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/vec_every_primitive_struct_type.rs @@ -43,3 +43,5 @@ impl __sdk::__query_builder::HasIxCols for VecEveryPrimitiveStruct { VecEveryPrimitiveStructIxCols {} } } + +impl __sdk::__query_builder::CanBeLookupTable for VecEveryPrimitiveStruct {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/vec_every_vec_struct_type.rs b/sdks/rust/tests/test-client/src/module_bindings/vec_every_vec_struct_type.rs index d28ce4a4307..532e4c16a7d 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/vec_every_vec_struct_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/vec_every_vec_struct_type.rs @@ -43,3 +43,5 @@ impl __sdk::__query_builder::HasIxCols for VecEveryVecStruct { VecEveryVecStructIxCols {} } } + +impl __sdk::__query_builder::CanBeLookupTable for VecEveryVecStruct {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/vec_f_32_type.rs b/sdks/rust/tests/test-client/src/module_bindings/vec_f_32_type.rs index 6cb53fa07a3..7bb2aa4d9b6 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/vec_f_32_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/vec_f_32_type.rs @@ -41,3 +41,5 @@ impl __sdk::__query_builder::HasIxCols for VecF32 { VecF32IxCols {} } } + +impl __sdk::__query_builder::CanBeLookupTable for VecF32 {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/vec_f_64_type.rs b/sdks/rust/tests/test-client/src/module_bindings/vec_f_64_type.rs index ef8b266dddf..c03a1171ebd 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/vec_f_64_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/vec_f_64_type.rs @@ -41,3 +41,5 @@ impl __sdk::__query_builder::HasIxCols for VecF64 { VecF64IxCols {} } } + +impl __sdk::__query_builder::CanBeLookupTable for VecF64 {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/vec_i_128_type.rs b/sdks/rust/tests/test-client/src/module_bindings/vec_i_128_type.rs index f54dd3a07e6..283b8163148 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/vec_i_128_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/vec_i_128_type.rs @@ -41,3 +41,5 @@ impl __sdk::__query_builder::HasIxCols for VecI128 { VecI128IxCols {} } } + +impl __sdk::__query_builder::CanBeLookupTable for VecI128 {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/vec_i_16_type.rs b/sdks/rust/tests/test-client/src/module_bindings/vec_i_16_type.rs index fea9dccb5d3..5bbc36d740e 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/vec_i_16_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/vec_i_16_type.rs @@ -41,3 +41,5 @@ impl __sdk::__query_builder::HasIxCols for VecI16 { VecI16IxCols {} } } + +impl __sdk::__query_builder::CanBeLookupTable for VecI16 {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/vec_i_256_type.rs b/sdks/rust/tests/test-client/src/module_bindings/vec_i_256_type.rs index aa82923e382..8dc66bfd112 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/vec_i_256_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/vec_i_256_type.rs @@ -41,3 +41,5 @@ impl __sdk::__query_builder::HasIxCols for VecI256 { VecI256IxCols {} } } + +impl __sdk::__query_builder::CanBeLookupTable for VecI256 {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/vec_i_32_type.rs b/sdks/rust/tests/test-client/src/module_bindings/vec_i_32_type.rs index 0e9e457df20..db7d3649739 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/vec_i_32_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/vec_i_32_type.rs @@ -41,3 +41,5 @@ impl __sdk::__query_builder::HasIxCols for VecI32 { VecI32IxCols {} } } + +impl __sdk::__query_builder::CanBeLookupTable for VecI32 {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/vec_i_64_type.rs b/sdks/rust/tests/test-client/src/module_bindings/vec_i_64_type.rs index df38c71ab81..3840fac9fba 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/vec_i_64_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/vec_i_64_type.rs @@ -41,3 +41,5 @@ impl __sdk::__query_builder::HasIxCols for VecI64 { VecI64IxCols {} } } + +impl __sdk::__query_builder::CanBeLookupTable for VecI64 {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/vec_i_8_type.rs b/sdks/rust/tests/test-client/src/module_bindings/vec_i_8_type.rs index fd47b9ee861..70d9f1f86cc 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/vec_i_8_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/vec_i_8_type.rs @@ -41,3 +41,5 @@ impl __sdk::__query_builder::HasIxCols for VecI8 { VecI8IxCols {} } } + +impl __sdk::__query_builder::CanBeLookupTable for VecI8 {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/vec_identity_type.rs b/sdks/rust/tests/test-client/src/module_bindings/vec_identity_type.rs index c2bb75f9554..0e2d4b04078 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/vec_identity_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/vec_identity_type.rs @@ -41,3 +41,5 @@ impl __sdk::__query_builder::HasIxCols for VecIdentity { VecIdentityIxCols {} } } + +impl __sdk::__query_builder::CanBeLookupTable for VecIdentity {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/vec_simple_enum_type.rs b/sdks/rust/tests/test-client/src/module_bindings/vec_simple_enum_type.rs index ec1cb92bb5b..59d1abed5c9 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/vec_simple_enum_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/vec_simple_enum_type.rs @@ -43,3 +43,5 @@ impl __sdk::__query_builder::HasIxCols for VecSimpleEnum { VecSimpleEnumIxCols {} } } + +impl __sdk::__query_builder::CanBeLookupTable for VecSimpleEnum {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/vec_string_type.rs b/sdks/rust/tests/test-client/src/module_bindings/vec_string_type.rs index 87082641a53..411e4042065 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/vec_string_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/vec_string_type.rs @@ -41,3 +41,5 @@ impl __sdk::__query_builder::HasIxCols for VecString { VecStringIxCols {} } } + +impl __sdk::__query_builder::CanBeLookupTable for VecString {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/vec_timestamp_type.rs b/sdks/rust/tests/test-client/src/module_bindings/vec_timestamp_type.rs index 721562993eb..33792f217dd 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/vec_timestamp_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/vec_timestamp_type.rs @@ -41,3 +41,5 @@ impl __sdk::__query_builder::HasIxCols for VecTimestamp { VecTimestampIxCols {} } } + +impl __sdk::__query_builder::CanBeLookupTable for VecTimestamp {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/vec_u_128_type.rs b/sdks/rust/tests/test-client/src/module_bindings/vec_u_128_type.rs index fdda362abad..d304ba0bdee 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/vec_u_128_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/vec_u_128_type.rs @@ -41,3 +41,5 @@ impl __sdk::__query_builder::HasIxCols for VecU128 { VecU128IxCols {} } } + +impl __sdk::__query_builder::CanBeLookupTable for VecU128 {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/vec_u_16_type.rs b/sdks/rust/tests/test-client/src/module_bindings/vec_u_16_type.rs index 1ce29594cc3..0a4f63ce8ff 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/vec_u_16_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/vec_u_16_type.rs @@ -41,3 +41,5 @@ impl __sdk::__query_builder::HasIxCols for VecU16 { VecU16IxCols {} } } + +impl __sdk::__query_builder::CanBeLookupTable for VecU16 {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/vec_u_256_type.rs b/sdks/rust/tests/test-client/src/module_bindings/vec_u_256_type.rs index db1e22d5ded..888de66026e 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/vec_u_256_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/vec_u_256_type.rs @@ -41,3 +41,5 @@ impl __sdk::__query_builder::HasIxCols for VecU256 { VecU256IxCols {} } } + +impl __sdk::__query_builder::CanBeLookupTable for VecU256 {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/vec_u_32_type.rs b/sdks/rust/tests/test-client/src/module_bindings/vec_u_32_type.rs index 8a81945e8cf..807b976fa36 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/vec_u_32_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/vec_u_32_type.rs @@ -41,3 +41,5 @@ impl __sdk::__query_builder::HasIxCols for VecU32 { VecU32IxCols {} } } + +impl __sdk::__query_builder::CanBeLookupTable for VecU32 {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/vec_u_64_type.rs b/sdks/rust/tests/test-client/src/module_bindings/vec_u_64_type.rs index 23283c48b23..fc9c942f587 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/vec_u_64_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/vec_u_64_type.rs @@ -41,3 +41,5 @@ impl __sdk::__query_builder::HasIxCols for VecU64 { VecU64IxCols {} } } + +impl __sdk::__query_builder::CanBeLookupTable for VecU64 {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/vec_u_8_type.rs b/sdks/rust/tests/test-client/src/module_bindings/vec_u_8_type.rs index 0e324f60f30..634f4481802 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/vec_u_8_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/vec_u_8_type.rs @@ -41,3 +41,5 @@ impl __sdk::__query_builder::HasIxCols for VecU8 { VecU8IxCols {} } } + +impl __sdk::__query_builder::CanBeLookupTable for VecU8 {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/vec_unit_struct_type.rs b/sdks/rust/tests/test-client/src/module_bindings/vec_unit_struct_type.rs index 2ee7e98c3cc..fdfdd6aa14e 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/vec_unit_struct_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/vec_unit_struct_type.rs @@ -43,3 +43,5 @@ impl __sdk::__query_builder::HasIxCols for VecUnitStruct { VecUnitStructIxCols {} } } + +impl __sdk::__query_builder::CanBeLookupTable for VecUnitStruct {} diff --git a/sdks/rust/tests/test-client/src/module_bindings/vec_uuid_type.rs b/sdks/rust/tests/test-client/src/module_bindings/vec_uuid_type.rs index 163a7b9aaec..4f9dbc4aea2 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/vec_uuid_type.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/vec_uuid_type.rs @@ -41,3 +41,5 @@ impl __sdk::__query_builder::HasIxCols for VecUuid { VecUuidIxCols {} } } + +impl __sdk::__query_builder::CanBeLookupTable for VecUuid {} diff --git a/sdks/rust/tests/test.rs b/sdks/rust/tests/test.rs index 0a89f60d84c..fe0799b3881 100644 --- a/sdks/rust/tests/test.rs +++ b/sdks/rust/tests/test.rs @@ -295,6 +295,57 @@ declare_tests_with_suffix!(typescript, "-ts"); declare_tests_with_suffix!(csharp, "-cs"); declare_tests_with_suffix!(cpp, "-cpp"); +/// Tests of event table functionality, using <./event-table-client> and <../../../modules/sdk-test>. +/// +/// These are separate from the existing client because as of writing (2026-02-07), +/// we do not have event table support in all of the module languages we have tested. +mod event_table_tests { + use spacetimedb_testing::sdk::Test; + + const MODULE: &str = "sdk-test-event-table"; + const CLIENT: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/tests/event-table-client"); + + fn make_test(subcommand: &str) -> Test { + Test::builder() + .with_name(subcommand) + .with_module(MODULE) + .with_client(CLIENT) + .with_language("rust") + .with_bindings_dir("src/module_bindings") + .with_compile_command("cargo build") + .with_run_command(format!("cargo run -- {}", subcommand)) + .build() + } + + // These tests require v2 WebSocket support in the Rust SDK, which is not yet implemented. + // The server now rejects v1 subscriptions to event tables with an upgrade error. + // Re-enable these once the Rust SDK supports v2 protocol negotiation. + + #[test] + #[ignore = "requires v2 WebSocket support in the Rust SDK"] + fn event_table() { + make_test("event-table").run(); + } + + #[test] + #[ignore = "requires v2 WebSocket support in the Rust SDK"] + fn multiple_events() { + make_test("multiple-events").run(); + } + + #[test] + #[ignore = "requires v2 WebSocket support in the Rust SDK"] + fn events_dont_persist() { + make_test("events-dont-persist").run(); + } + + /// Verify that v1 clients receive a clear error when subscribing to event tables. + #[test] + fn v1_rejects_event_table_subscription() { + make_test("v1-rejects-event-table").run(); + } +} + macro_rules! procedure_tests { ($mod_name:ident, $suffix:literal) => { mod $mod_name { diff --git a/sdks/rust/tests/view-client/src/module_bindings/mod.rs b/sdks/rust/tests/view-client/src/module_bindings/mod.rs index 40ff3f092bf..e87e4a6e611 100644 --- a/sdks/rust/tests/view-client/src/module_bindings/mod.rs +++ b/sdks/rust/tests/view-client/src/module_bindings/mod.rs @@ -1,7 +1,7 @@ // THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE // WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. -// This was generated using spacetimedb cli version 1.11.2 (commit 13a0172567170d9b8c87d2aa71de3246c21acb8c). +// This was generated using spacetimedb cli version 1.12.0 (commit fa83d6d4023972609140a959099eab19a4e5f995). #![allow(unused, clippy::all)] use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; diff --git a/sdks/rust/tests/view-client/src/module_bindings/player_level_type.rs b/sdks/rust/tests/view-client/src/module_bindings/player_level_type.rs index 98b25e6a137..8a5ba6071e4 100644 --- a/sdks/rust/tests/view-client/src/module_bindings/player_level_type.rs +++ b/sdks/rust/tests/view-client/src/module_bindings/player_level_type.rs @@ -50,3 +50,5 @@ impl __sdk::__query_builder::HasIxCols for PlayerLevel { } } } + +impl __sdk::__query_builder::CanBeLookupTable for PlayerLevel {} diff --git a/sdks/rust/tests/view-client/src/module_bindings/player_location_type.rs b/sdks/rust/tests/view-client/src/module_bindings/player_location_type.rs index a2d29d18188..51e3d45390f 100644 --- a/sdks/rust/tests/view-client/src/module_bindings/player_location_type.rs +++ b/sdks/rust/tests/view-client/src/module_bindings/player_location_type.rs @@ -56,3 +56,5 @@ impl __sdk::__query_builder::HasIxCols for PlayerLocation { } } } + +impl __sdk::__query_builder::CanBeLookupTable for PlayerLocation {} diff --git a/sdks/rust/tests/view-client/src/module_bindings/player_type.rs b/sdks/rust/tests/view-client/src/module_bindings/player_type.rs index b99ac46acf3..57b07de9a0b 100644 --- a/sdks/rust/tests/view-client/src/module_bindings/player_type.rs +++ b/sdks/rust/tests/view-client/src/module_bindings/player_type.rs @@ -50,3 +50,5 @@ impl __sdk::__query_builder::HasIxCols for Player { } } } + +impl __sdk::__query_builder::CanBeLookupTable for Player {}