Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions crates/codegen/src/csharp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ use std::ops::Deref;
use super::code_indenter::CodeIndenter;
use super::Lang;
use crate::util::{
collect_case, is_reducer_invokable, iter_indexes, iter_reducers, iter_tables, print_auto_generated_file_comment,
print_auto_generated_version_comment, type_ref_name,
collect_case, is_reducer_invokable, iter_indexes, iter_reducers, iter_table_names_and_types,
print_auto_generated_file_comment, print_auto_generated_version_comment, type_ref_name,
};
use crate::{indent_scope, OutputFile};
use convert_case::{Case, Casing};
Expand Down Expand Up @@ -745,11 +745,11 @@ impl Lang for Csharp<'_> {
indented_block(&mut output, |output| {
writeln!(output, "public RemoteTables(DbConnection conn)");
indented_block(output, |output| {
for table in iter_tables(module) {
for (table_name, _) in iter_table_names_and_types(module) {
writeln!(
output,
"AddTable({} = new(conn));",
table.name.deref().to_case(Case::Pascal)
table_name.deref().to_case(Case::Pascal)
);
}
});
Expand Down
52 changes: 31 additions & 21 deletions crates/codegen/src/rust.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ use super::code_indenter::{CodeIndenter, Indenter};
use super::util::{collect_case, iter_reducers, print_lines, type_ref_name};
use super::Lang;
use crate::util::{
iter_procedures, iter_tables, iter_types, iter_unique_cols, print_auto_generated_file_comment,
print_auto_generated_version_comment,
iter_procedures, iter_table_names_and_types, iter_tables, iter_types, iter_unique_cols, iter_views,
print_auto_generated_file_comment, print_auto_generated_version_comment,
};
use crate::OutputFile;
use convert_case::{Case, Casing};
Expand Down Expand Up @@ -930,12 +930,13 @@ fn reducer_flags_trait_name(reducer: &ReducerDef) -> String {
format!("set_flags_for_{}", reducer_function_name(reducer))
}

/// Iterate over all of the Rust `mod`s for types, reducers and tables in the `module`.
/// Iterate over all of the Rust `mod`s for types, reducers, views, and tables in the `module`.
fn iter_module_names(module: &ModuleDef) -> impl Iterator<Item = String> + '_ {
itertools::chain!(
iter_types(module).map(|ty| type_module_name(&ty.name)),
iter_reducers(module).map(|r| reducer_module_name(&r.name)),
iter_tables(module).map(|tbl| table_module_name(&tbl.name)),
iter_views(module).map(|view| table_module_name(&view.name)),
iter_procedures(module).map(|proc| procedure_module_name(&proc.name)),
)
}
Expand All @@ -954,8 +955,8 @@ fn print_module_reexports(module: &ModuleDef, out: &mut Indenter) {
let type_name = collect_case(Case::Pascal, ty.name.name_segments());
writeln!(out, "pub use {mod_name}::{type_name};")
}
for table in iter_tables(module) {
let mod_name = table_module_name(&table.name);
for (table_name, _) in iter_table_names_and_types(module) {
let mod_name = table_module_name(table_name);
// TODO: More precise reexport: we want:
// - The trait name.
// - The insert, delete and possibly update callback ids.
Expand Down Expand Up @@ -1113,12 +1114,12 @@ fn print_db_update_defn(module: &ModuleDef, out: &mut Indenter) {
out.delimited_block(
"pub struct DbUpdate {",
|out| {
for table in iter_tables(module) {
for (table_name, product_type_ref) in iter_table_names_and_types(module) {
writeln!(
out,
"{}: __sdk::TableUpdate<{}>,",
table_method_name(&table.name),
type_ref_name(module, table.product_type_ref),
table_method_name(table_name),
type_ref_name(module, product_type_ref),
);
}
},
Expand All @@ -1137,13 +1138,13 @@ impl TryFrom<__ws::DatabaseUpdate<__ws::BsatnFormat>> for DbUpdate {
match &table_update.table_name[..] {
",
|out| {
for table in iter_tables(module) {
for (table_name, _) in iter_table_names_and_types(module) {
writeln!(
out,
"{:?} => db_update.{}.append({}::parse_table_update(table_update)?),",
table.name.deref(),
table_method_name(&table.name),
table_module_name(&table.name),
table_name.deref(),
table_method_name(table_name),
table_module_name(table_name),
);
}
},
Expand Down Expand Up @@ -1198,6 +1199,15 @@ impl __sdk::InModule for DbUpdate {{
table.name.deref(),
);
}
for view in iter_views(module) {
let field_name = table_method_name(&view.name);
writeln!(
out,
"diff.{field_name} = cache.apply_diff_to_table::<{}>({:?}, &self.{field_name});",
type_ref_name(module, view.product_type_ref),
view.name.deref(),
);
}
},
"
diff
Expand All @@ -1215,12 +1225,12 @@ fn print_applied_diff_defn(module: &ModuleDef, out: &mut Indenter) {
out.delimited_block(
"pub struct AppliedDiff<'r> {",
|out| {
for table in iter_tables(module) {
for (table_name, product_type_ref) in iter_table_names_and_types(module) {
writeln!(
out,
"{}: __sdk::TableAppliedDiff<'r, {}>,",
table_method_name(&table.name),
type_ref_name(module, table.product_type_ref),
table_method_name(table_name),
type_ref_name(module, product_type_ref),
);
}
// Also write a `PhantomData` field which uses the lifetime `r`,
Expand Down Expand Up @@ -1248,13 +1258,13 @@ impl __sdk::InModule for AppliedDiff<'_> {{
out.delimited_block(
"fn invoke_row_callbacks(&self, event: &EventContext, callbacks: &mut __sdk::DbCallbacks<RemoteModule>) {",
|out| {
for table in iter_tables(module) {
for (table_name, product_type_ref) in iter_table_names_and_types(module) {
writeln!(
out,
"callbacks.invoke_table_row_callbacks::<{}>({:?}, &self.{}, event);",
type_ref_name(module, table.product_type_ref),
table.name.deref(),
table_method_name(&table.name),
type_ref_name(module, product_type_ref),
table_name.deref(),
table_method_name(table_name),
);
}
},
Expand Down Expand Up @@ -1290,8 +1300,8 @@ type SubscriptionHandle = SubscriptionHandle;
out.delimited_block(
"fn register_tables(client_cache: &mut __sdk::ClientCache<Self>) {",
|out| {
for table in iter_tables(module) {
writeln!(out, "{}::register_table(client_cache);", table_module_name(&table.name));
for (table_name, _) in iter_table_names_and_types(module) {
writeln!(out, "{}::register_table(client_cache);", table_module_name(table_name));
}
},
"}\n",
Expand Down
4 changes: 2 additions & 2 deletions crates/codegen/src/typescript.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::util::{
is_reducer_invokable, iter_constraints, iter_indexes, iter_reducers, iter_table_and_view_names, iter_tables,
is_reducer_invokable, iter_constraints, iter_indexes, iter_reducers, iter_table_names_and_types, iter_tables,
iter_types, iter_views, print_auto_generated_version_comment,
};
use crate::OutputFile;
Expand Down Expand Up @@ -195,7 +195,7 @@ impl Lang for TypeScript {

writeln!(out);
writeln!(out, "// Import and reexport all table handle types");
for table_name in iter_table_and_view_names(module) {
for (table_name, _) in iter_table_names_and_types(module) {
let table_module_name = table_module_name(table_name);
let table_name_pascalcase = table_name.deref().to_case(Case::Pascal);
// TODO: This really shouldn't be necessary. We could also have `table()` accept
Expand Down
95 changes: 53 additions & 42 deletions crates/codegen/src/unrealcpp.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
//! Autogenerated Unreal‑C++ code‑gen backend for SpacetimeDB CLI
use crate::code_indenter::CodeIndenter;
use crate::util::{
collect_case, fmt_fn, iter_tables, print_auto_generated_file_comment, print_auto_generated_version_comment,
collect_case, fmt_fn, iter_table_names_and_types, print_auto_generated_file_comment,
print_auto_generated_version_comment,
};
use crate::util::{iter_indexes, iter_reducers};
use crate::Lang;
Expand Down Expand Up @@ -38,7 +39,8 @@ impl UnrealCpp<'_> {
impl Lang for UnrealCpp<'_> {
fn generate_table_file_from_schema(&self, module: &ModuleDef, table: &TableDef, schema: TableSchema) -> OutputFile {
let struct_name = type_ref_name(module, table.product_type_ref);
let self_header = struct_name.clone() + "Table";
let table_pascal = table.name.deref().to_case(Case::Pascal);
let self_header = table_pascal.clone() + "Table";

let mut output = UnrealCppAutogen::new(
&[
Expand All @@ -54,9 +56,8 @@ impl Lang for UnrealCpp<'_> {
);

let row_struct = format!("F{struct_name}Type"); // e.g. "FUserType", "FMessageType"
let handle_cls = format!("U{struct_name}Table"); // "UMessageTable"
let handle_cls = format!("U{table_pascal}Table"); // "UMessageTable"
let table_name = table.name.deref().to_string();
let table_pascal = struct_name.clone();

// Generate unique index classes first
let product_type = module.typespace_for_generate()[table.product_type_ref].as_product();
Expand Down Expand Up @@ -374,7 +375,7 @@ impl Lang for UnrealCpp<'_> {
filename: format!(
"Source/{}/Public/ModuleBindings/Tables/{}Table.g.h",
self.module_name,
type_ref_name(module, table.product_type_ref)
table.name.deref().to_case(Case::Pascal) //type_ref_name(module, table.product_type_ref)
),
code: output.into_inner(),
}
Expand Down Expand Up @@ -683,9 +684,8 @@ impl Lang for UnrealCpp<'_> {
writeln!(client_h);

writeln!(client_h, "/** Forward declaration for tables */");
for table in iter_tables(module) {
let table_pascal = type_ref_name(module, table.product_type_ref);
writeln!(client_h, "class U{table_pascal}Table;");
for (table_name, _) in iter_table_names_and_types(module) {
writeln!(client_h, "class U{}Table;", table_name.deref().to_case(Case::Pascal));
}
writeln!(client_h, "/***/");
writeln!(client_h);
Expand Down Expand Up @@ -774,12 +774,11 @@ impl Lang for UnrealCpp<'_> {
});

// Build table includes
let table_includes: Vec<String> = module
.tables()
.map(|table| {
let table_includes: Vec<String> = iter_table_names_and_types(module)
.map(|(table_name, _)| {
format!(
"ModuleBindings/Tables/{}Table.g.h",
type_ref_name(module, table.product_type_ref)
table_name.deref().to_case(Case::Pascal) //type_ref_name(module, product_type_ref)
)
})
.collect();
Expand All @@ -805,26 +804,46 @@ impl Lang for UnrealCpp<'_> {

// Generate .cpp implementation files for each table
for table in module.tables() {
let table_cpp_content = generate_table_cpp(module, table, self.module_name);
let schema = TableSchema::from_module_def(module, table, (), 0.into())
.validated()
.expect("table schema should validate");
let table_cpp_content = generate_table_cpp(module, table, self.module_name, &schema);
let table_cpp_filename = format!(
"Source/{}/Private/ModuleBindings/Tables/{}Table.g.cpp",
self.module_name,
type_ref_name(module, table.product_type_ref)
table.name.deref().to_case(Case::Pascal) //type_ref_name(module, table.product_type_ref)
);
files.push(OutputFile {
filename: table_cpp_filename,
code: table_cpp_content,
});
}
for view in module.views() {
let tbl = TableDef::from(view.clone());
let schema = TableSchema::from_view_def_for_codegen(module, view)
.validated()
.expect("Failed to generate table due to validation errors");
let view_cpp_content = generate_table_cpp(module, &tbl, self.module_name, &schema);
let view_cpp_filename = format!(
"Source/{}/Private/ModuleBindings/Tables/{}Table.g.cpp",
self.module_name,
view.name.deref().to_case(Case::Pascal) //type_ref_name(module, view.product_type_ref)
);
files.push(OutputFile {
filename: view_cpp_filename,
code: view_cpp_content,
});
}

files
}
}

// Helper function to generate table .cpp implementation files
fn generate_table_cpp(module: &ModuleDef, table: &TableDef, module_name: &str) -> String {
let table_pascal = type_ref_name(module, table.product_type_ref);
let row_struct = format!("F{table_pascal}Type");
fn generate_table_cpp(module: &ModuleDef, table: &TableDef, module_name: &str, schema: &TableSchema) -> String {
let table_pascal = table.name.deref().to_case(Case::Pascal);
let struct_name = type_ref_name(module, table.product_type_ref);
let row_struct = format!("F{struct_name}Type");

// Include the table header and other necessary headers
let table_header = format!("ModuleBindings/Tables/{table_pascal}Table.g.h");
Expand All @@ -838,10 +857,6 @@ fn generate_table_cpp(module: &ModuleDef, table: &TableDef, module_name: &str) -

let mut output = UnrealCppAutogen::new_cpp(&includes);

let schema = TableSchema::from_module_def(module, table, (), 0.into())
.validated()
.expect("table schema should validate");

// Get unique indexes and non-unique BTree indexes
let product_type = module.typespace_for_generate()[table.product_type_ref].as_product();

Expand Down Expand Up @@ -1856,14 +1871,13 @@ fn generate_remote_tables_class(output: &mut UnrealCppAutogen, module: &ModuleDe
writeln!(output);

// Generate table handle properties
for table in module.tables() {
let table_pascal = type_ref_name(module, table.product_type_ref);

for (table_name, _) in iter_table_names_and_types(module) {
writeln!(output, " UPROPERTY(BlueprintReadOnly, Category=\"SpacetimeDB\")");
writeln!(
output,
" U{table_pascal}Table* {};",
table.name.deref().to_case(Case::Pascal)
" U{}Table* {};",
table_name.deref().to_case(Case::Pascal),
table_name.deref().to_case(Case::Pascal)
);
writeln!(output);
}
Expand Down Expand Up @@ -2357,16 +2371,16 @@ fn generate_client_implementation(output: &mut UnrealCppAutogen, module: &Module
writeln!(output, "\tReducers->SetCallReducerFlags = SetReducerFlags;");
writeln!(output, "\tReducers->Conn = this;");
writeln!(output);
for table in module.tables() {
let table_pascal = type_ref_name(module, table.product_type_ref);
let table_name = table.name.deref();
for (table_name, product_type_ref) in iter_table_names_and_types(module) {
let struct_name = type_ref_name(module, product_type_ref);
let table_name = table_name.deref();
writeln!(
output,
"\tRegisterTable<F{}Type, U{}Table, FEventContext>(TEXT(\"{}\"), Db->{});",
table_pascal,
table_pascal,
struct_name,
table_name.to_case(Case::Pascal),
table_name,
table.name.deref().to_case(Case::Pascal)
table_name.to_case(Case::Pascal)
);
}
writeln!(output, "}}");
Expand Down Expand Up @@ -2412,23 +2426,22 @@ fn generate_client_implementation(output: &mut UnrealCppAutogen, module: &Module
writeln!(output, "{{");
writeln!(output);
writeln!(output, "\t/** Creating tables */");
for table in module.tables() {
let table_pascal = type_ref_name(module, table.product_type_ref);
for (table_name, _) in iter_table_names_and_types(module) {
writeln!(
output,
"\t{} = NewObject<U{}Table>(this);",
table.name.deref().to_case(Case::Pascal),
table_pascal
table_name.deref().to_case(Case::Pascal),
table_name.deref().to_case(Case::Pascal)
);
}
writeln!(output, "\t/**/");
writeln!(output);
writeln!(output, "\t/** Initialization */");
for table in module.tables() {
for (table_name, _) in iter_table_names_and_types(module) {
writeln!(
output,
"\t{}->PostInitialize();",
table.name.deref().to_case(Case::Pascal)
table_name.deref().to_case(Case::Pascal)
);
}
writeln!(output, "\t/**/");
Expand Down Expand Up @@ -3095,10 +3108,8 @@ fn collect_optional_types(module: &ModuleDef) -> HashSet<String> {
}

// Collect from all tables
for table in module.tables() {
let product_type = module.typespace_for_generate()[table.product_type_ref]
.as_product()
.unwrap();
for (_, product_type_ref) in iter_table_names_and_types(module) {
let product_type = module.typespace_for_generate()[product_type_ref].as_product().unwrap();
for (_, field_ty) in &product_type.elements {
collect_from_type(module, field_ty, &mut optional_types);
}
Expand Down
Loading
Loading