Skip to content

Commit f9858af

Browse files
Generate client bindings for views
1 parent db21fce commit f9858af

File tree

15 files changed

+364
-43
lines changed

15 files changed

+364
-43
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ futures-util = "0.3"
183183
getrandom02 = { package = "getrandom", version = "0.2" }
184184
git2 = "0.19"
185185
glob = "0.3.1"
186-
hashbrown = { version = "0.15", default-features = false, features = ["equivalent", "inline-more"] }
186+
hashbrown = { version = "0.15", default-features = false, features = ["default-hasher", "equivalent", "inline-more"] }
187187
headers = "0.4"
188188
heck = "0.4"
189189
hex = "0.4.3"

crates/codegen/src/csharp.rs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use convert_case::{Case, Casing};
1515
use spacetimedb_lib::sats::layout::PrimitiveType;
1616
use spacetimedb_primitives::ColId;
1717
use spacetimedb_schema::def::{BTreeAlgorithm, IndexAlgorithm, ModuleDef, TableDef, TypeDef};
18-
use spacetimedb_schema::schema::{Schema, TableSchema};
18+
use spacetimedb_schema::schema::TableSchema;
1919
use spacetimedb_schema::type_for_generate::{
2020
AlgebraicTypeDef, AlgebraicTypeUse, PlainEnumTypeDef, ProductTypeDef, SumTypeDef, TypespaceForGenerate,
2121
};
@@ -433,7 +433,7 @@ pub struct Csharp<'opts> {
433433
}
434434

435435
impl Lang for Csharp<'_> {
436-
fn generate_table_file(&self, module: &ModuleDef, table: &TableDef) -> OutputFile {
436+
fn generate_table_file_from_schema(&self, module: &ModuleDef, table: &TableDef, schema: TableSchema) -> OutputFile {
437437
let mut output = CsharpAutogen::new(
438438
self.namespace,
439439
&[
@@ -447,9 +447,6 @@ impl Lang for Csharp<'_> {
447447

448448
writeln!(output, "public sealed partial class RemoteTables");
449449
indented_block(&mut output, |output| {
450-
let schema = TableSchema::from_module_def(module, table, (), 0.into())
451-
.validated()
452-
.expect("Failed to generate table due to validation errors");
453450
let csharp_table_name = table.name.deref().to_case(Case::Pascal);
454451
let csharp_table_class_name = csharp_table_name.clone() + "Handle";
455452
let table_type = type_ref_name(module, table.product_type_ref);

crates/codegen/src/lib.rs

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
use spacetimedb_schema::def::{ModuleDef, ReducerDef, TableDef, TypeDef};
1+
use spacetimedb_schema::def::{ModuleDef, ReducerDef, TableDef, TypeDef, ViewDef};
2+
use spacetimedb_schema::schema::{Schema, TableSchema};
23

34
mod code_indenter;
45
pub mod csharp;
@@ -16,6 +17,7 @@ pub use util::AUTO_GENERATED_PREFIX;
1617
pub fn generate(module: &ModuleDef, lang: &dyn Lang) -> Vec<OutputFile> {
1718
itertools::chain!(
1819
module.tables().map(|tbl| lang.generate_table_file(module, tbl)),
20+
module.views().map(|view| lang.generate_view_file(module, view)),
1921
module.types().flat_map(|typ| lang.generate_type_files(module, typ)),
2022
util::iter_reducers(module).map(|reducer| lang.generate_reducer_file(module, reducer)),
2123
lang.generate_global_files(module),
@@ -29,8 +31,23 @@ pub struct OutputFile {
2931
}
3032

3133
pub trait Lang {
32-
fn generate_table_file(&self, module: &ModuleDef, tbl: &TableDef) -> OutputFile;
34+
fn generate_table_file_from_schema(&self, module: &ModuleDef, tbl: &TableDef, schema: TableSchema) -> OutputFile;
3335
fn generate_type_files(&self, module: &ModuleDef, typ: &TypeDef) -> Vec<OutputFile>;
3436
fn generate_reducer_file(&self, module: &ModuleDef, reducer: &ReducerDef) -> OutputFile;
3537
fn generate_global_files(&self, module: &ModuleDef) -> Vec<OutputFile>;
38+
39+
fn generate_table_file(&self, module: &ModuleDef, tbl: &TableDef) -> OutputFile {
40+
let schema = TableSchema::from_module_def(module, tbl, (), 0.into())
41+
.validated()
42+
.expect("Failed to generate table due to validation errors");
43+
self.generate_table_file_from_schema(module, tbl, schema)
44+
}
45+
46+
fn generate_view_file(&self, module: &ModuleDef, view: &ViewDef) -> OutputFile {
47+
let tbl = TableDef::from(view.clone());
48+
let schema = TableSchema::from_view_def_for_codegen(module, view)
49+
.validated()
50+
.expect("Failed to generate table due to validation errors");
51+
self.generate_table_file_from_schema(module, &tbl, schema)
52+
}
3653
}

crates/codegen/src/rust.rs

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use spacetimedb_lib::sats::layout::PrimitiveType;
1010
use spacetimedb_lib::sats::AlgebraicTypeRef;
1111
use spacetimedb_schema::def::{ModuleDef, ReducerDef, ScopedTypeName, TableDef, TypeDef};
1212
use spacetimedb_schema::identifier::Identifier;
13-
use spacetimedb_schema::schema::{Schema, TableSchema};
13+
use spacetimedb_schema::schema::TableSchema;
1414
use spacetimedb_schema::type_for_generate::{AlgebraicTypeDef, AlgebraicTypeUse};
1515
use std::collections::BTreeSet;
1616
use std::fmt::{self, Write};
@@ -70,11 +70,7 @@ impl __sdk::InModule for {type_name} {{
7070
code: output.into_inner(),
7171
}]
7272
}
73-
fn generate_table_file(&self, module: &ModuleDef, table: &TableDef) -> OutputFile {
74-
let schema = TableSchema::from_module_def(module, table, (), 0.into())
75-
.validated()
76-
.expect("Failed to generate table due to validation errors");
77-
73+
fn generate_table_file_from_schema(&self, module: &ModuleDef, table: &TableDef, schema: TableSchema) -> OutputFile {
7874
let type_ref = table.product_type_ref;
7975

8076
let mut output = CodeIndenter::new(String::new(), INDENT);
@@ -200,7 +196,7 @@ pub(super) fn register_table(client_cache: &mut __sdk::ClientCache<super::Remote
200196
"}",
201197
);
202198

203-
if schema.pk().is_some() {
199+
if table.primary_key.is_some() {
204200
let update_callback_id = table_name_pascalcase.clone() + "UpdateCallbackId";
205201
write!(
206202
out,

crates/codegen/src/typescript.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -108,11 +108,7 @@ impl Lang for TypeScript {
108108
}
109109
}
110110

111-
fn generate_table_file(&self, module: &ModuleDef, table: &TableDef) -> OutputFile {
112-
let schema = TableSchema::from_module_def(module, table, (), 0.into())
113-
.validated()
114-
.expect("Failed to generate table due to validation errors");
115-
111+
fn generate_table_file_from_schema(&self, module: &ModuleDef, table: &TableDef, schema: TableSchema) -> OutputFile {
116112
let mut output = CodeIndenter::new(String::new(), INDENT);
117113
let out = &mut output;
118114

crates/codegen/src/unrealcpp.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ impl UnrealCpp<'_> {
3636
}
3737

3838
impl Lang for UnrealCpp<'_> {
39-
fn generate_table_file(&self, module: &ModuleDef, table: &TableDef) -> OutputFile {
39+
fn generate_table_file_from_schema(&self, module: &ModuleDef, table: &TableDef, schema: TableSchema) -> OutputFile {
4040
let struct_name = type_ref_name(module, table.product_type_ref);
4141
let self_header = struct_name.clone() + "Table";
4242

@@ -58,10 +58,6 @@ impl Lang for UnrealCpp<'_> {
5858
let table_name = table.name.deref().to_string();
5959
let table_pascal = struct_name.clone();
6060

61-
let schema = TableSchema::from_module_def(module, table, (), 0.into())
62-
.validated()
63-
.expect("table schema should validate");
64-
6561
// Generate unique index classes first
6662
let product_type = module.typespace_for_generate()[table.product_type_ref].as_product();
6763

crates/codegen/tests/snapshots/codegen__codegen_csharp.snap

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
---
22
source: crates/codegen/tests/codegen.rs
3-
assertion_line: 37
43
expression: outfiles
54
---
65
"Reducers/Add.g.cs" = '''
@@ -1602,6 +1601,35 @@ namespace SpacetimeDB
16021601
}
16031602
}
16041603
'''
1604+
"Tables/MyPlayer.g.cs" = '''
1605+
// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
1606+
// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.
1607+
1608+
#nullable enable
1609+
1610+
using System;
1611+
using SpacetimeDB.BSATN;
1612+
using SpacetimeDB.ClientApi;
1613+
using System.Collections.Generic;
1614+
using System.Runtime.Serialization;
1615+
1616+
namespace SpacetimeDB
1617+
{
1618+
public sealed partial class RemoteTables
1619+
{
1620+
public sealed class MyPlayerHandle : RemoteTableHandle<EventContext, Player>
1621+
{
1622+
protected override string RemoteTableName => "my_player";
1623+
1624+
internal MyPlayerHandle(DbConnection conn) : base(conn)
1625+
{
1626+
}
1627+
}
1628+
1629+
public readonly MyPlayerHandle MyPlayer;
1630+
}
1631+
}
1632+
'''
16051633
"Tables/Person.g.cs" = '''
16061634
// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
16071635
// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.

crates/codegen/tests/snapshots/codegen__codegen_rust.snap

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2273,6 +2273,106 @@ fn register_tables(client_cache: &mut __sdk::ClientCache<Self>) {
22732273
}
22742274
}
22752275
'''
2276+
"my_player_table.rs" = '''
2277+
// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
2278+
// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.
2279+
2280+
#![allow(unused, clippy::all)]
2281+
use spacetimedb_sdk::__codegen::{
2282+
self as __sdk,
2283+
__lib,
2284+
__sats,
2285+
__ws,
2286+
};
2287+
use super::player_type::Player;
2288+
2289+
/// Table handle for the table `my_player`.
2290+
///
2291+
/// Obtain a handle from the [`MyPlayerTableAccess::my_player`] method on [`super::RemoteTables`],
2292+
/// like `ctx.db.my_player()`.
2293+
///
2294+
/// Users are encouraged not to explicitly reference this type,
2295+
/// but to directly chain method calls,
2296+
/// like `ctx.db.my_player().on_insert(...)`.
2297+
pub struct MyPlayerTableHandle<'ctx> {
2298+
imp: __sdk::TableHandle<Player>,
2299+
ctx: std::marker::PhantomData<&'ctx super::RemoteTables>,
2300+
}
2301+
2302+
#[allow(non_camel_case_types)]
2303+
/// Extension trait for access to the table `my_player`.
2304+
///
2305+
/// Implemented for [`super::RemoteTables`].
2306+
pub trait MyPlayerTableAccess {
2307+
#[allow(non_snake_case)]
2308+
/// Obtain a [`MyPlayerTableHandle`], which mediates access to the table `my_player`.
2309+
fn my_player(&self) -> MyPlayerTableHandle<'_>;
2310+
}
2311+
2312+
impl MyPlayerTableAccess for super::RemoteTables {
2313+
fn my_player(&self) -> MyPlayerTableHandle<'_> {
2314+
MyPlayerTableHandle {
2315+
imp: self.imp.get_table::<Player>("my_player"),
2316+
ctx: std::marker::PhantomData,
2317+
}
2318+
}
2319+
}
2320+
2321+
pub struct MyPlayerInsertCallbackId(__sdk::CallbackId);
2322+
pub struct MyPlayerDeleteCallbackId(__sdk::CallbackId);
2323+
2324+
impl<'ctx> __sdk::Table for MyPlayerTableHandle<'ctx> {
2325+
type Row = Player;
2326+
type EventContext = super::EventContext;
2327+
2328+
fn count(&self) -> u64 { self.imp.count() }
2329+
fn iter(&self) -> impl Iterator<Item = Player> + '_ { self.imp.iter() }
2330+
2331+
type InsertCallbackId = MyPlayerInsertCallbackId;
2332+
2333+
fn on_insert(
2334+
&self,
2335+
callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static,
2336+
) -> MyPlayerInsertCallbackId {
2337+
MyPlayerInsertCallbackId(self.imp.on_insert(Box::new(callback)))
2338+
}
2339+
2340+
fn remove_on_insert(&self, callback: MyPlayerInsertCallbackId) {
2341+
self.imp.remove_on_insert(callback.0)
2342+
}
2343+
2344+
type DeleteCallbackId = MyPlayerDeleteCallbackId;
2345+
2346+
fn on_delete(
2347+
&self,
2348+
callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static,
2349+
) -> MyPlayerDeleteCallbackId {
2350+
MyPlayerDeleteCallbackId(self.imp.on_delete(Box::new(callback)))
2351+
}
2352+
2353+
fn remove_on_delete(&self, callback: MyPlayerDeleteCallbackId) {
2354+
self.imp.remove_on_delete(callback.0)
2355+
}
2356+
}
2357+
2358+
#[doc(hidden)]
2359+
pub(super) fn register_table(client_cache: &mut __sdk::ClientCache<super::RemoteModule>) {
2360+
2361+
let _table = client_cache.get_or_make_table::<Player>("my_player");
2362+
}
2363+
2364+
#[doc(hidden)]
2365+
pub(super) fn parse_table_update(
2366+
raw_updates: __ws::TableUpdate<__ws::BsatnFormat>,
2367+
) -> __sdk::Result<__sdk::TableUpdate<Player>> {
2368+
__sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| {
2369+
__sdk::InternalError::failed_parse(
2370+
"TableUpdate<Player>",
2371+
"TableUpdate",
2372+
).with_cause(e).into()
2373+
})
2374+
}
2375+
'''
22762376
"namespace_test_c_type.rs" = '''
22772377
// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
22782378
// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.

crates/codegen/tests/snapshots/codegen__codegen_typescript.snap

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1731,6 +1731,84 @@ export class LoggedOutPlayerTableHandle<TableName extends string> implements __T
17311731
return this.tableCache.removeOnUpdate(cb);
17321732
}}
17331733
'''
1734+
"my_player_table.ts" = '''
1735+
// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
1736+
// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.
1737+
1738+
/* eslint-disable */
1739+
/* tslint:disable */
1740+
import {
1741+
AlgebraicType as __AlgebraicTypeValue,
1742+
BinaryReader as __BinaryReader,
1743+
BinaryWriter as __BinaryWriter,
1744+
ClientCache as __ClientCache,
1745+
ConnectionId as __ConnectionId,
1746+
DbConnectionBuilder as __DbConnectionBuilder,
1747+
DbConnectionImpl as __DbConnectionImpl,
1748+
Identity as __Identity,
1749+
SubscriptionBuilderImpl as __SubscriptionBuilderImpl,
1750+
TableCache as __TableCache,
1751+
TimeDuration as __TimeDuration,
1752+
Timestamp as __Timestamp,
1753+
deepEqual as __deepEqual,
1754+
type AlgebraicType as __AlgebraicTypeType,
1755+
type AlgebraicTypeVariants as __AlgebraicTypeVariants,
1756+
type CallReducerFlags as __CallReducerFlags,
1757+
type ErrorContextInterface as __ErrorContextInterface,
1758+
type Event as __Event,
1759+
type EventContextInterface as __EventContextInterface,
1760+
type ReducerEventContextInterface as __ReducerEventContextInterface,
1761+
type SubscriptionEventContextInterface as __SubscriptionEventContextInterface,
1762+
type TableHandle as __TableHandle,
1763+
} from "spacetimedb";
1764+
import { Player } from "./player_type";
1765+
import { type EventContext, type Reducer, RemoteReducers, RemoteTables } from ".";
1766+
declare type __keep = [EventContext, Reducer, RemoteReducers, RemoteTables];
1767+
1768+
/**
1769+
* Table handle for the table `my_player`.
1770+
*
1771+
* Obtain a handle from the [`myPlayer`] property on [`RemoteTables`],
1772+
* like `ctx.db.myPlayer`.
1773+
*
1774+
* Users are encouraged not to explicitly reference this type,
1775+
* but to directly chain method calls,
1776+
* like `ctx.db.myPlayer.on_insert(...)`.
1777+
*/
1778+
export class MyPlayerTableHandle<TableName extends string> implements __TableHandle<TableName> {
1779+
// phantom type to track the table name
1780+
readonly tableName!: TableName;
1781+
tableCache: __TableCache<Player>;
1782+
1783+
constructor(tableCache: __TableCache<Player>) {
1784+
this.tableCache = tableCache;
1785+
}
1786+
1787+
count(): number {
1788+
return this.tableCache.count();
1789+
}
1790+
1791+
iter(): Iterable<Player> {
1792+
return this.tableCache.iter();
1793+
}
1794+
1795+
onInsert = (cb: (ctx: EventContext, row: Player) => void) => {
1796+
return this.tableCache.onInsert(cb);
1797+
}
1798+
1799+
removeOnInsert = (cb: (ctx: EventContext, row: Player) => void) => {
1800+
return this.tableCache.removeOnInsert(cb);
1801+
}
1802+
1803+
onDelete = (cb: (ctx: EventContext, row: Player) => void) => {
1804+
return this.tableCache.onDelete(cb);
1805+
}
1806+
1807+
removeOnDelete = (cb: (ctx: EventContext, row: Player) => void) => {
1808+
return this.tableCache.removeOnDelete(cb);
1809+
}
1810+
}
1811+
'''
17341812
"namespace_test_c_type.ts" = '''
17351813
// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
17361814
// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.

crates/datastore/src/locking_tx_datastore/mut_tx.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,7 @@ impl MutTxId {
303303
/// - The returned [`ViewId`] is unique and not [`ViewId::SENTINEL`].
304304
/// - All view metadata maintained by the datastore is created atomically
305305
pub fn create_view(&mut self, module_def: &ModuleDef, view_def: &ViewDef) -> Result<(ViewId, TableId)> {
306-
let table_schema = TableSchema::from_view_def(module_def, view_def);
306+
let table_schema = TableSchema::from_view_def_for_datastore(module_def, view_def);
307307
let table_id = self.create_table(table_schema)?;
308308

309309
let ViewDef {

0 commit comments

Comments
 (0)