11//! Autogenerated Unreal‑C++ code‑gen backend for SpacetimeDB CLI
22use crate :: code_indenter:: CodeIndenter ;
33use crate :: util:: {
4- collect_case, fmt_fn, iter_tables, print_auto_generated_file_comment, print_auto_generated_version_comment,
4+ collect_case, fmt_fn, iter_table_names_and_types, print_auto_generated_file_comment,
5+ print_auto_generated_version_comment,
56} ;
67use crate :: util:: { iter_indexes, iter_reducers} ;
78use crate :: Lang ;
@@ -38,7 +39,8 @@ impl UnrealCpp<'_> {
3839impl Lang for UnrealCpp < ' _ > {
3940 fn generate_table_file_from_schema ( & self , module : & ModuleDef , table : & TableDef , schema : TableSchema ) -> OutputFile {
4041 let struct_name = type_ref_name ( module, table. product_type_ref ) ;
41- let self_header = struct_name. clone ( ) + "Table" ;
42+ let table_pascal = table. name . deref ( ) . to_case ( Case :: Pascal ) ;
43+ let self_header = table_pascal. clone ( ) + "Table" ;
4244
4345 let mut output = UnrealCppAutogen :: new (
4446 & [
@@ -54,9 +56,8 @@ impl Lang for UnrealCpp<'_> {
5456 ) ;
5557
5658 let row_struct = format ! ( "F{struct_name}Type" ) ; // e.g. "FUserType", "FMessageType"
57- let handle_cls = format ! ( "U{struct_name }Table" ) ; // "UMessageTable"
59+ let handle_cls = format ! ( "U{table_pascal }Table" ) ; // "UMessageTable"
5860 let table_name = table. name . deref ( ) . to_string ( ) ;
59- let table_pascal = struct_name. clone ( ) ;
6061
6162 // Generate unique index classes first
6263 let product_type = module. typespace_for_generate ( ) [ table. product_type_ref ] . as_product ( ) ;
@@ -374,7 +375,7 @@ impl Lang for UnrealCpp<'_> {
374375 filename : format ! (
375376 "Source/{}/Public/ModuleBindings/Tables/{}Table.g.h" ,
376377 self . module_name,
377- type_ref_name( module, table. product_type_ref)
378+ table . name . deref ( ) . to_case ( Case :: Pascal ) // type_ref_name(module, table.product_type_ref)
378379 ) ,
379380 code : output. into_inner ( ) ,
380381 }
@@ -683,9 +684,8 @@ impl Lang for UnrealCpp<'_> {
683684 writeln ! ( client_h) ;
684685
685686 writeln ! ( client_h, "/** Forward declaration for tables */" ) ;
686- for table in iter_tables ( module) {
687- let table_pascal = type_ref_name ( module, table. product_type_ref ) ;
688- writeln ! ( client_h, "class U{table_pascal}Table;" ) ;
687+ for ( table_name, _) in iter_table_names_and_types ( module) {
688+ writeln ! ( client_h, "class U{}Table;" , table_name. deref( ) . to_case( Case :: Pascal ) ) ;
689689 }
690690 writeln ! ( client_h, "/***/" ) ;
691691 writeln ! ( client_h) ;
@@ -774,12 +774,11 @@ impl Lang for UnrealCpp<'_> {
774774 } ) ;
775775
776776 // Build table includes
777- let table_includes: Vec < String > = module
778- . tables ( )
779- . map ( |table| {
777+ let table_includes: Vec < String > = iter_table_names_and_types ( module)
778+ . map ( |( table_name, _) | {
780779 format ! (
781780 "ModuleBindings/Tables/{}Table.g.h" ,
782- type_ref_name( module, table . product_type_ref)
781+ table_name . deref ( ) . to_case ( Case :: Pascal ) // type_ref_name(module, product_type_ref)
783782 )
784783 } )
785784 . collect ( ) ;
@@ -805,26 +804,46 @@ impl Lang for UnrealCpp<'_> {
805804
806805 // Generate .cpp implementation files for each table
807806 for table in module. tables ( ) {
808- let table_cpp_content = generate_table_cpp ( module, table, self . module_name ) ;
807+ let schema = TableSchema :: from_module_def ( module, table, ( ) , 0 . into ( ) )
808+ . validated ( )
809+ . expect ( "table schema should validate" ) ;
810+ let table_cpp_content = generate_table_cpp ( module, table, self . module_name , & schema) ;
809811 let table_cpp_filename = format ! (
810812 "Source/{}/Private/ModuleBindings/Tables/{}Table.g.cpp" ,
811813 self . module_name,
812- type_ref_name( module, table. product_type_ref)
814+ table . name . deref ( ) . to_case ( Case :: Pascal ) // type_ref_name(module, table.product_type_ref)
813815 ) ;
814816 files. push ( OutputFile {
815817 filename : table_cpp_filename,
816818 code : table_cpp_content,
817819 } ) ;
818820 }
821+ for view in module. views ( ) {
822+ let tbl = TableDef :: from ( view. clone ( ) ) ;
823+ let schema = TableSchema :: from_view_def_for_codegen ( module, view)
824+ . validated ( )
825+ . expect ( "Failed to generate table due to validation errors" ) ;
826+ let view_cpp_content = generate_table_cpp ( module, & tbl, self . module_name , & schema) ;
827+ let view_cpp_filename = format ! (
828+ "Source/{}/Private/ModuleBindings/Tables/{}Table.g.cpp" ,
829+ self . module_name,
830+ view. name. deref( ) . to_case( Case :: Pascal ) //type_ref_name(module, view.product_type_ref)
831+ ) ;
832+ files. push ( OutputFile {
833+ filename : view_cpp_filename,
834+ code : view_cpp_content,
835+ } ) ;
836+ }
819837
820838 files
821839 }
822840}
823841
824842// Helper function to generate table .cpp implementation files
825- fn generate_table_cpp ( module : & ModuleDef , table : & TableDef , module_name : & str ) -> String {
826- let table_pascal = type_ref_name ( module, table. product_type_ref ) ;
827- let row_struct = format ! ( "F{table_pascal}Type" ) ;
843+ fn generate_table_cpp ( module : & ModuleDef , table : & TableDef , module_name : & str , schema : & TableSchema ) -> String {
844+ let table_pascal = table. name . deref ( ) . to_case ( Case :: Pascal ) ;
845+ let struct_name = type_ref_name ( module, table. product_type_ref ) ;
846+ let row_struct = format ! ( "F{struct_name}Type" ) ;
828847
829848 // Include the table header and other necessary headers
830849 let table_header = format ! ( "ModuleBindings/Tables/{table_pascal}Table.g.h" ) ;
@@ -838,10 +857,6 @@ fn generate_table_cpp(module: &ModuleDef, table: &TableDef, module_name: &str) -
838857
839858 let mut output = UnrealCppAutogen :: new_cpp ( & includes) ;
840859
841- let schema = TableSchema :: from_module_def ( module, table, ( ) , 0 . into ( ) )
842- . validated ( )
843- . expect ( "table schema should validate" ) ;
844-
845860 // Get unique indexes and non-unique BTree indexes
846861 let product_type = module. typespace_for_generate ( ) [ table. product_type_ref ] . as_product ( ) ;
847862
@@ -1856,14 +1871,13 @@ fn generate_remote_tables_class(output: &mut UnrealCppAutogen, module: &ModuleDe
18561871 writeln ! ( output) ;
18571872
18581873 // Generate table handle properties
1859- for table in module. tables ( ) {
1860- let table_pascal = type_ref_name ( module, table. product_type_ref ) ;
1861-
1874+ for ( table_name, _) in iter_table_names_and_types ( module) {
18621875 writeln ! ( output, " UPROPERTY(BlueprintReadOnly, Category=\" SpacetimeDB\" )" ) ;
18631876 writeln ! (
18641877 output,
1865- " U{table_pascal}Table* {};" ,
1866- table. name. deref( ) . to_case( Case :: Pascal )
1878+ " U{}Table* {};" ,
1879+ table_name. deref( ) . to_case( Case :: Pascal ) ,
1880+ table_name. deref( ) . to_case( Case :: Pascal )
18671881 ) ;
18681882 writeln ! ( output) ;
18691883 }
@@ -2357,16 +2371,16 @@ fn generate_client_implementation(output: &mut UnrealCppAutogen, module: &Module
23572371 writeln ! ( output, "\t Reducers->SetCallReducerFlags = SetReducerFlags;" ) ;
23582372 writeln ! ( output, "\t Reducers->Conn = this;" ) ;
23592373 writeln ! ( output) ;
2360- for table in module . tables ( ) {
2361- let table_pascal = type_ref_name ( module, table . product_type_ref ) ;
2362- let table_name = table . name . deref ( ) ;
2374+ for ( table_name , product_type_ref ) in iter_table_names_and_types ( module ) {
2375+ let struct_name = type_ref_name ( module, product_type_ref) ;
2376+ let table_name = table_name . deref ( ) ;
23632377 writeln ! (
23642378 output,
23652379 "\t RegisterTable<F{}Type, U{}Table, FEventContext>(TEXT(\" {}\" ), Db->{});" ,
2366- table_pascal ,
2367- table_pascal ,
2380+ struct_name ,
2381+ table_name . to_case ( Case :: Pascal ) ,
23682382 table_name,
2369- table . name . deref ( ) . to_case( Case :: Pascal )
2383+ table_name . to_case( Case :: Pascal )
23702384 ) ;
23712385 }
23722386 writeln ! ( output, "}}" ) ;
@@ -2412,23 +2426,22 @@ fn generate_client_implementation(output: &mut UnrealCppAutogen, module: &Module
24122426 writeln ! ( output, "{{" ) ;
24132427 writeln ! ( output) ;
24142428 writeln ! ( output, "\t /** Creating tables */" ) ;
2415- for table in module. tables ( ) {
2416- let table_pascal = type_ref_name ( module, table. product_type_ref ) ;
2429+ for ( table_name, _) in iter_table_names_and_types ( module) {
24172430 writeln ! (
24182431 output,
24192432 "\t {} = NewObject<U{}Table>(this);" ,
2420- table . name . deref( ) . to_case( Case :: Pascal ) ,
2421- table_pascal
2433+ table_name . deref( ) . to_case( Case :: Pascal ) ,
2434+ table_name . deref ( ) . to_case ( Case :: Pascal )
24222435 ) ;
24232436 }
24242437 writeln ! ( output, "\t /**/" ) ;
24252438 writeln ! ( output) ;
24262439 writeln ! ( output, "\t /** Initialization */" ) ;
2427- for table in module . tables ( ) {
2440+ for ( table_name , _ ) in iter_table_names_and_types ( module ) {
24282441 writeln ! (
24292442 output,
24302443 "\t {}->PostInitialize();" ,
2431- table . name . deref( ) . to_case( Case :: Pascal )
2444+ table_name . deref( ) . to_case( Case :: Pascal )
24322445 ) ;
24332446 }
24342447 writeln ! ( output, "\t /**/" ) ;
@@ -3095,10 +3108,8 @@ fn collect_optional_types(module: &ModuleDef) -> HashSet<String> {
30953108 }
30963109
30973110 // Collect from all tables
3098- for table in module. tables ( ) {
3099- let product_type = module. typespace_for_generate ( ) [ table. product_type_ref ]
3100- . as_product ( )
3101- . unwrap ( ) ;
3111+ for ( _, product_type_ref) in iter_table_names_and_types ( module) {
3112+ let product_type = module. typespace_for_generate ( ) [ product_type_ref] . as_product ( ) . unwrap ( ) ;
31023113 for ( _, field_ty) in & product_type. elements {
31033114 collect_from_type ( module, field_ty, & mut optional_types) ;
31043115 }
0 commit comments