diff --git a/crates/bindings-csharp/Codegen.Tests/fixtures/diag/Lib.cs b/crates/bindings-csharp/Codegen.Tests/fixtures/diag/Lib.cs index edbf55555fe..a6590914d65 100644 --- a/crates/bindings-csharp/Codegen.Tests/fixtures/diag/Lib.cs +++ b/crates/bindings-csharp/Codegen.Tests/fixtures/diag/Lib.cs @@ -483,6 +483,15 @@ public partial struct TestScheduleIssues public static void DummyScheduledReducer(ReducerContext ctx, TestScheduleIssues table) { } } +[SpacetimeDB.Table] +public partial struct Player +{ + [Unique] + public Identity Identity; +} + +public struct NotSpacetimeType { } + public partial class Module { #pragma warning disable STDB_UNSTABLE // Enable ClientVisibilityFilter @@ -506,4 +515,84 @@ public partial class Module public static readonly Filter MY_FOURTH_FILTER = new Filter.Sql( "SELECT * FROM TestAutoIncNotInteger" ); + + // Invalid: View definition missing Public=true + [SpacetimeDB.View(Name = "view_def_no_public")] + public static List ViewDefNoPublic(ViewContext ctx) + { + return new List(); + } + + // Invalid: View definition with missing context type + [SpacetimeDB.View(Name = "view_def_no_context", Public = true)] + public static List ViewDefNoContext() + { + return new List(); + } + + // Invalid: View definition with wrong context type + [SpacetimeDB.View(Name = "view_def_wrong_context", Public = true)] + public static List ViewDefWrongContext(ReducerContext ctx) + { + return new List(); + } + + // Invalid: View that performs Insert + [SpacetimeDB.View(Name = "view_no_insert", Public = true)] + public static Player? ViewNoInsert(ViewContext ctx) + { + ctx.Db.Player.Insert(new Player { Identity = new() }); + return new Player { Identity = new() }; + } + + // Invalid: View that performs Delete + [SpacetimeDB.View(Name = "view_no_delete", Public = true)] + public static Player? ViewNoDelete(ViewContext ctx) + { + ctx.Db.Player.Delete(new Player { Identity = new() }); + return null; + } + + // TODO: Investigate why void return breaks the FFI generation + // // Invalid: Void return type is not Vec or Option + // [SpacetimeDB.View(Name = "view_def_no_return", Public = true)] + // public static void ViewDefNoReturn(ViewContext ctx) + // { + // return; + // } + + // Invalid: Wrong return type is not Vec or Option + [SpacetimeDB.View(Name = "view_def_wrong_return", Public = true)] + public static Player ViewDefWrongReturn(ViewContext ctx) + { + return new Player { Identity = new() }; + } + + // Invalid: Returns type that is not a SpacetimeType + [SpacetimeDB.View(Name = "view_def_returns_not_a_spacetime_type", Public = true)] + public static NotSpacetimeType? ViewDefReturnsNotASpacetimeType(AnonymousViewContext ctx) + { + return new NotSpacetimeType(); + } + + [SpacetimeDB.View(Name = "view_def_no_anon_identity", Public = true)] + public static Player? ViewDefNoAnonIdentity(AnonymousViewContext ctx) + { + ctx.GetIdentity(); + return null; + } + + [SpacetimeDB.View(Name = "view_def_no_iter", Public = true)] + public static Player? ViewDefNoIter(AnonymousViewContext ctx) + { + ctx.Db.Player.Iter(); + return null; + } + + [SpacetimeDB.View(Name = "view_def_index_no_mutation", Public = true)] + public static Player? ViewDefIndexNoMutation(AnonymousViewContext ctx) + { + ctx.Db.Player.Identity.Delete(0); + return null; + } } diff --git a/crates/bindings-csharp/Codegen.Tests/fixtures/diag/snapshots/ExtraCompilationErrors.verified.txt b/crates/bindings-csharp/Codegen.Tests/fixtures/diag/snapshots/ExtraCompilationErrors.verified.txt index a2d83c2492e..b369e66f498 100644 --- a/crates/bindings-csharp/Codegen.Tests/fixtures/diag/snapshots/ExtraCompilationErrors.verified.txt +++ b/crates/bindings-csharp/Codegen.Tests/fixtures/diag/snapshots/ExtraCompilationErrors.verified.txt @@ -1,4 +1,27 @@ [ + {/* + { + ctx.GetIdentity(); + ^^^^^^^^^^^ + return null; +*/ + Message: 'AnonymousViewContext' does not contain a definition for 'GetIdentity' and no accessible extension method 'GetIdentity' accepting a first argument of type 'AnonymousViewContext' could be found (are you missing a using directive or an assembly reference?), + Severity: Error, + Descriptor: { + Id: CS1061, + Title: , + HelpLink: https://msdn.microsoft.com/query/roslyn.query?appId=roslyn&k=k(CS1061), + MessageFormat: '{0}' does not contain a definition for '{1}' and no accessible extension method '{1}' accepting a first argument of type '{0}' could be found (are you missing a using directive or an assembly reference?), + Category: Compiler, + DefaultSeverity: Error, + IsEnabledByDefault: true, + CustomTags: [ + Compiler, + Telemetry, + NotConfigurable + ] + } + }, {/* SpacetimeDB.Internal.Module.RegisterTable(); SpacetimeDB.Internal.Module.RegisterClientVisibilityFilter(global::Module.MY_FILTER); @@ -22,6 +45,98 @@ SpacetimeDB.Internal.Module.RegisterClientVisibilityFilter(global::Module.MY_FOU ] } }, + {/* + { + ctx.Db.Player.Identity.Delete(0); + ^^^^^^ + return null; +*/ + Message: 'PlayerReadOnly.IdentityIndex' does not contain a definition for 'Delete' and no accessible extension method 'Delete' accepting a first argument of type 'PlayerReadOnly.IdentityIndex' could be found (are you missing a using directive or an assembly reference?), + Severity: Error, + Descriptor: { + Id: CS1061, + Title: , + HelpLink: https://msdn.microsoft.com/query/roslyn.query?appId=roslyn&k=k(CS1061), + MessageFormat: '{0}' does not contain a definition for '{1}' and no accessible extension method '{1}' accepting a first argument of type '{0}' could be found (are you missing a using directive or an assembly reference?), + Category: Compiler, + DefaultSeverity: Error, + IsEnabledByDefault: true, + CustomTags: [ + Compiler, + Telemetry, + NotConfigurable + ] + } + }, + {/* + { + ctx.Db.Player.Delete(new Player { Identity = new() }); + ^^^^^^ + return null; +*/ + Message: 'PlayerReadOnly' does not contain a definition for 'Delete' and no accessible extension method 'Delete' accepting a first argument of type 'PlayerReadOnly' could be found (are you missing a using directive or an assembly reference?), + Severity: Error, + Descriptor: { + Id: CS1061, + Title: , + HelpLink: https://msdn.microsoft.com/query/roslyn.query?appId=roslyn&k=k(CS1061), + MessageFormat: '{0}' does not contain a definition for '{1}' and no accessible extension method '{1}' accepting a first argument of type '{0}' could be found (are you missing a using directive or an assembly reference?), + Category: Compiler, + DefaultSeverity: Error, + IsEnabledByDefault: true, + CustomTags: [ + Compiler, + Telemetry, + NotConfigurable + ] + } + }, + {/* + { + ctx.Db.Player.Insert(new Player { Identity = new() }); + ^^^^^^ + return new Player { Identity = new() }; +*/ + Message: 'PlayerReadOnly' does not contain a definition for 'Insert' and no accessible extension method 'Insert' accepting a first argument of type 'PlayerReadOnly' could be found (are you missing a using directive or an assembly reference?), + Severity: Error, + Descriptor: { + Id: CS1061, + Title: , + HelpLink: https://msdn.microsoft.com/query/roslyn.query?appId=roslyn&k=k(CS1061), + MessageFormat: '{0}' does not contain a definition for '{1}' and no accessible extension method '{1}' accepting a first argument of type '{0}' could be found (are you missing a using directive or an assembly reference?), + Category: Compiler, + DefaultSeverity: Error, + IsEnabledByDefault: true, + CustomTags: [ + Compiler, + Telemetry, + NotConfigurable + ] + } + }, + {/* + { + ctx.Db.Player.Iter(); + ^^^^ + return null; +*/ + Message: 'PlayerReadOnly' does not contain a definition for 'Iter' and no accessible extension method 'Iter' accepting a first argument of type 'PlayerReadOnly' could be found (are you missing a using directive or an assembly reference?), + Severity: Error, + Descriptor: { + Id: CS1061, + Title: , + HelpLink: https://msdn.microsoft.com/query/roslyn.query?appId=roslyn&k=k(CS1061), + MessageFormat: '{0}' does not contain a definition for '{1}' and no accessible extension method '{1}' accepting a first argument of type '{0}' could be found (are you missing a using directive or an assembly reference?), + Category: Compiler, + DefaultSeverity: Error, + IsEnabledByDefault: true, + CustomTags: [ + Compiler, + Telemetry, + NotConfigurable + ] + } + }, {/* // Valid Filter, but [ClientVisibilityFilter] is disabled [SpacetimeDB.ClientVisibilityFilter] @@ -114,6 +229,29 @@ public partial struct TestDefaultFieldValues ] } }, + {/* + + var returnValue = Module.ViewDefWrongContext((SpacetimeDB.ViewContext)ctx); + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + using var output = new System.IO.MemoryStream(); +*/ + Message: Argument 1: cannot convert from 'SpacetimeDB.ViewContext' to 'SpacetimeDB.ReducerContext', + Severity: Error, + Descriptor: { + Id: CS1503, + Title: , + HelpLink: https://msdn.microsoft.com/query/roslyn.query?appId=roslyn&k=k(CS1503), + MessageFormat: Argument {0}: cannot convert from '{1}' to '{2}', + Category: Compiler, + DefaultSeverity: Error, + IsEnabledByDefault: true, + CustomTags: [ + Compiler, + Telemetry, + NotConfigurable + ] + } + }, {/* SpacetimeDB.Internal.Module.RegisterClientVisibilityFilter(global::Module.MY_SECOND_FILTER); SpacetimeDB.Internal.Module.RegisterClientVisibilityFilter(global::Module.MY_THIRD_FILTER); @@ -137,6 +275,75 @@ SpacetimeDB.Internal.Module.RegisterClientVisibilityFilter(global::Module.MY_THI ] } }, + {/* + + var returnValue = Module.ViewDefNoContext((SpacetimeDB.ViewContext)ctx); + ^^^^^^^^^^^^^^^^ + using var output = new System.IO.MemoryStream(); +*/ + Message: No overload for method 'ViewDefNoContext' takes 1 arguments, + Severity: Error, + Descriptor: { + Id: CS1501, + Title: , + HelpLink: https://msdn.microsoft.com/query/roslyn.query?appId=roslyn&k=k(CS1501), + MessageFormat: No overload for method '{0}' takes {1} arguments, + Category: Compiler, + DefaultSeverity: Error, + IsEnabledByDefault: true, + CustomTags: [ + Compiler, + Telemetry, + NotConfigurable + ] + } + }, + {/* + + private static readonly SpacetimeDB.BSATN.ValueOption returnRW = new(); + ^^^^^ + +*/ + Message: The type name 'BSATN' does not exist in the type 'NotSpacetimeType', + Severity: Error, + Descriptor: { + Id: CS0426, + Title: , + HelpLink: https://msdn.microsoft.com/query/roslyn.query?appId=roslyn&k=k(CS0426), + MessageFormat: The type name '{0}' does not exist in the type '{1}', + Category: Compiler, + DefaultSeverity: Error, + IsEnabledByDefault: true, + CustomTags: [ + Compiler, + Telemetry, + NotConfigurable + ] + } + }, + {/* + Params: [], + ReturnType: new SpacetimeDB.BSATN.ValueOption().GetAlgebraicType(registrar) + ^^^^^ +); +*/ + Message: The type name 'BSATN' does not exist in the type 'NotSpacetimeType', + Severity: Error, + Descriptor: { + Id: CS0426, + Title: , + HelpLink: https://msdn.microsoft.com/query/roslyn.query?appId=roslyn&k=k(CS0426), + MessageFormat: The type name '{0}' does not exist in the type '{1}', + Category: Compiler, + DefaultSeverity: Error, + IsEnabledByDefault: true, + CustomTags: [ + Compiler, + Telemetry, + NotConfigurable + ] + } + }, {/* { internal static readonly TRW FieldRW = new(); diff --git a/crates/bindings-csharp/Codegen.Tests/fixtures/diag/snapshots/Module#FFI.verified.cs b/crates/bindings-csharp/Codegen.Tests/fixtures/diag/snapshots/Module#FFI.verified.cs index 3b24e82bc77..f682dc6c61b 100644 --- a/crates/bindings-csharp/Codegen.Tests/fixtures/diag/snapshots/Module#FFI.verified.cs +++ b/crates/bindings-csharp/Codegen.Tests/fixtures/diag/snapshots/Module#FFI.verified.cs @@ -1,6 +1,10 @@ //HintName: FFI.cs // #nullable enable +// The runtime already defines SpacetimeDB.Internal.LocalReadOnly in Runtime\Internal\Module.cs as an empty partial type. +// This is needed so every module build doesn't generate a full LocalReadOnly type, but just adds on to the existing. +// We extend it here with generated table accessors, and just need to suppress the duplicate-type warning. +#pragma warning disable CS0436 using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; @@ -34,12 +38,110 @@ Timestamp time } } + public sealed record ViewContext : DbContext, Internal.IViewContext + { + public Identity Sender { get; } + + internal ViewContext(Identity sender, Internal.LocalReadOnly db) + : base(db) + { + Sender = sender; + } + } + + public sealed record AnonymousViewContext + : DbContext, + Internal.IAnonymousViewContext + { + internal AnonymousViewContext(Internal.LocalReadOnly db) + : base(db) { } + } + namespace Internal.TableHandles { + public readonly struct Player + : global::SpacetimeDB.Internal.ITableView + { + static global::Player global::SpacetimeDB.Internal.ITableView< + Player, + global::Player + >.ReadGenFields(System.IO.BinaryReader reader, global::Player row) + { + return row; + } + + static SpacetimeDB.Internal.RawTableDefV9 global::SpacetimeDB.Internal.ITableView< + Player, + global::Player + >.MakeTableDesc(SpacetimeDB.BSATN.ITypeRegistrar registrar) => + new( + Name: nameof(Player), + ProductTypeRef: (uint) + new global::Player.BSATN().GetAlgebraicType(registrar).Ref_, + PrimaryKey: [], + Indexes: + [ + new( + Name: null, + AccessorName: "Identity", + Algorithm: new SpacetimeDB.Internal.RawIndexAlgorithm.BTree([0]) + ) + ], + Constraints: + [ + global::SpacetimeDB.Internal.ITableView< + Player, + global::Player + >.MakeUniqueConstraint(0) + ], + Sequences: [], + Schedule: null, + TableType: SpacetimeDB.Internal.TableType.User, + TableAccess: SpacetimeDB.Internal.TableAccess.Private + ); + + public ulong Count => + global::SpacetimeDB.Internal.ITableView.DoCount(); + + public IEnumerable Iter() => + global::SpacetimeDB.Internal.ITableView.DoIter(); + + public global::Player Insert(global::Player row) => + global::SpacetimeDB.Internal.ITableView.DoInsert(row); + + public bool Delete(global::Player row) => + global::SpacetimeDB.Internal.ITableView.DoDelete(row); + + public sealed class IdentityUniqueIndex + : UniqueIndex< + Player, + global::Player, + SpacetimeDB.Identity, + SpacetimeDB.Identity.BSATN + > + { + internal IdentityUniqueIndex() + : base("Player_Identity_idx_btree") { } + + // Important: don't move this to the base class. + // C# generics don't play well with nullable types and can't accept both struct-type-based and class-type-based + // `globalName` in one generic definition, leading to buggy `Row?` expansion for either one or another. + public global::Player? Find(SpacetimeDB.Identity key) => + DoFilter(key).Cast().SingleOrDefault(); + + public global::Player Update(global::Player row) => DoUpdate(row); + } + + public IdentityUniqueIndex Identity => new(); + } + public readonly struct TestAutoIncNotInteger - : SpacetimeDB.Internal.ITableView + : global::SpacetimeDB.Internal.ITableView< + TestAutoIncNotInteger, + global::TestAutoIncNotInteger + > { - static global::TestAutoIncNotInteger SpacetimeDB.Internal.ITableView< + static global::TestAutoIncNotInteger global::SpacetimeDB.Internal.ITableView< TestAutoIncNotInteger, global::TestAutoIncNotInteger >.ReadGenFields(System.IO.BinaryReader reader, global::TestAutoIncNotInteger row) @@ -59,7 +161,7 @@ public readonly struct TestAutoIncNotInteger return row; } - static SpacetimeDB.Internal.RawTableDefV9 SpacetimeDB.Internal.ITableView< + static SpacetimeDB.Internal.RawTableDefV9 global::SpacetimeDB.Internal.ITableView< TestAutoIncNotInteger, global::TestAutoIncNotInteger >.MakeTableDesc(SpacetimeDB.BSATN.ITypeRegistrar registrar) => @@ -78,18 +180,18 @@ static SpacetimeDB.Internal.RawTableDefV9 SpacetimeDB.Internal.ITableView< ], Constraints: [ - SpacetimeDB.Internal.ITableView< + global::SpacetimeDB.Internal.ITableView< TestAutoIncNotInteger, global::TestAutoIncNotInteger >.MakeUniqueConstraint(1) ], Sequences: [ - SpacetimeDB.Internal.ITableView< + global::SpacetimeDB.Internal.ITableView< TestAutoIncNotInteger, global::TestAutoIncNotInteger >.MakeSequence(0), - SpacetimeDB.Internal.ITableView< + global::SpacetimeDB.Internal.ITableView< TestAutoIncNotInteger, global::TestAutoIncNotInteger >.MakeSequence(1) @@ -100,25 +202,25 @@ static SpacetimeDB.Internal.RawTableDefV9 SpacetimeDB.Internal.ITableView< ); public ulong Count => - SpacetimeDB.Internal.ITableView< + global::SpacetimeDB.Internal.ITableView< TestAutoIncNotInteger, global::TestAutoIncNotInteger >.DoCount(); public IEnumerable Iter() => - SpacetimeDB.Internal.ITableView< + global::SpacetimeDB.Internal.ITableView< TestAutoIncNotInteger, global::TestAutoIncNotInteger >.DoIter(); public global::TestAutoIncNotInteger Insert(global::TestAutoIncNotInteger row) => - SpacetimeDB.Internal.ITableView< + global::SpacetimeDB.Internal.ITableView< TestAutoIncNotInteger, global::TestAutoIncNotInteger >.DoInsert(row); public bool Delete(global::TestAutoIncNotInteger row) => - SpacetimeDB.Internal.ITableView< + global::SpacetimeDB.Internal.ITableView< TestAutoIncNotInteger, global::TestAutoIncNotInteger >.DoDelete(row); @@ -148,12 +250,12 @@ internal IdentityFieldUniqueIndex() } public readonly struct TestDefaultFieldValues - : SpacetimeDB.Internal.ITableView< + : global::SpacetimeDB.Internal.ITableView< TestDefaultFieldValues, global::TestDefaultFieldValues > { - static global::TestDefaultFieldValues SpacetimeDB.Internal.ITableView< + static global::TestDefaultFieldValues global::SpacetimeDB.Internal.ITableView< TestDefaultFieldValues, global::TestDefaultFieldValues >.ReadGenFields(System.IO.BinaryReader reader, global::TestDefaultFieldValues row) @@ -161,7 +263,7 @@ public readonly struct TestDefaultFieldValues return row; } - static SpacetimeDB.Internal.RawTableDefV9 SpacetimeDB.Internal.ITableView< + static SpacetimeDB.Internal.RawTableDefV9 global::SpacetimeDB.Internal.ITableView< TestDefaultFieldValues, global::TestDefaultFieldValues >.MakeTableDesc(SpacetimeDB.BSATN.ITypeRegistrar registrar) => @@ -180,7 +282,7 @@ static SpacetimeDB.Internal.RawTableDefV9 SpacetimeDB.Internal.ITableView< ], Constraints: [ - SpacetimeDB.Internal.ITableView< + global::SpacetimeDB.Internal.ITableView< TestDefaultFieldValues, global::TestDefaultFieldValues >.MakeUniqueConstraint(0) @@ -192,37 +294,37 @@ static SpacetimeDB.Internal.RawTableDefV9 SpacetimeDB.Internal.ITableView< ); public ulong Count => - SpacetimeDB.Internal.ITableView< + global::SpacetimeDB.Internal.ITableView< TestDefaultFieldValues, global::TestDefaultFieldValues >.DoCount(); public IEnumerable Iter() => - SpacetimeDB.Internal.ITableView< + global::SpacetimeDB.Internal.ITableView< TestDefaultFieldValues, global::TestDefaultFieldValues >.DoIter(); public global::TestDefaultFieldValues Insert(global::TestDefaultFieldValues row) => - SpacetimeDB.Internal.ITableView< + global::SpacetimeDB.Internal.ITableView< TestDefaultFieldValues, global::TestDefaultFieldValues >.DoInsert(row); public bool Delete(global::TestDefaultFieldValues row) => - SpacetimeDB.Internal.ITableView< + global::SpacetimeDB.Internal.ITableView< TestDefaultFieldValues, global::TestDefaultFieldValues >.DoDelete(row); } public readonly struct TestDuplicateTableName - : SpacetimeDB.Internal.ITableView< + : global::SpacetimeDB.Internal.ITableView< TestDuplicateTableName, global::TestDuplicateTableName > { - static global::TestDuplicateTableName SpacetimeDB.Internal.ITableView< + static global::TestDuplicateTableName global::SpacetimeDB.Internal.ITableView< TestDuplicateTableName, global::TestDuplicateTableName >.ReadGenFields(System.IO.BinaryReader reader, global::TestDuplicateTableName row) @@ -230,7 +332,7 @@ public readonly struct TestDuplicateTableName return row; } - static SpacetimeDB.Internal.RawTableDefV9 SpacetimeDB.Internal.ITableView< + static SpacetimeDB.Internal.RawTableDefV9 global::SpacetimeDB.Internal.ITableView< TestDuplicateTableName, global::TestDuplicateTableName >.MakeTableDesc(SpacetimeDB.BSATN.ITypeRegistrar registrar) => @@ -248,34 +350,34 @@ static SpacetimeDB.Internal.RawTableDefV9 SpacetimeDB.Internal.ITableView< ); public ulong Count => - SpacetimeDB.Internal.ITableView< + global::SpacetimeDB.Internal.ITableView< TestDuplicateTableName, global::TestDuplicateTableName >.DoCount(); public IEnumerable Iter() => - SpacetimeDB.Internal.ITableView< + global::SpacetimeDB.Internal.ITableView< TestDuplicateTableName, global::TestDuplicateTableName >.DoIter(); public global::TestDuplicateTableName Insert(global::TestDuplicateTableName row) => - SpacetimeDB.Internal.ITableView< + global::SpacetimeDB.Internal.ITableView< TestDuplicateTableName, global::TestDuplicateTableName >.DoInsert(row); public bool Delete(global::TestDuplicateTableName row) => - SpacetimeDB.Internal.ITableView< + global::SpacetimeDB.Internal.ITableView< TestDuplicateTableName, global::TestDuplicateTableName >.DoDelete(row); } public readonly struct TestIndexIssues - : SpacetimeDB.Internal.ITableView + : global::SpacetimeDB.Internal.ITableView { - static global::TestIndexIssues SpacetimeDB.Internal.ITableView< + static global::TestIndexIssues global::SpacetimeDB.Internal.ITableView< TestIndexIssues, global::TestIndexIssues >.ReadGenFields(System.IO.BinaryReader reader, global::TestIndexIssues row) @@ -283,7 +385,7 @@ public readonly struct TestIndexIssues return row; } - static SpacetimeDB.Internal.RawTableDefV9 SpacetimeDB.Internal.ITableView< + static SpacetimeDB.Internal.RawTableDefV9 global::SpacetimeDB.Internal.ITableView< TestIndexIssues, global::TestIndexIssues >.MakeTableDesc(SpacetimeDB.BSATN.ITypeRegistrar registrar) => @@ -323,20 +425,28 @@ static SpacetimeDB.Internal.RawTableDefV9 SpacetimeDB.Internal.ITableView< ); public ulong Count => - SpacetimeDB.Internal.ITableView.DoCount(); + global::SpacetimeDB.Internal.ITableView< + TestIndexIssues, + global::TestIndexIssues + >.DoCount(); public IEnumerable Iter() => - SpacetimeDB.Internal.ITableView.DoIter(); + global::SpacetimeDB.Internal.ITableView< + TestIndexIssues, + global::TestIndexIssues + >.DoIter(); public global::TestIndexIssues Insert(global::TestIndexIssues row) => - SpacetimeDB.Internal.ITableView.DoInsert( - row - ); + global::SpacetimeDB.Internal.ITableView< + TestIndexIssues, + global::TestIndexIssues + >.DoInsert(row); public bool Delete(global::TestIndexIssues row) => - SpacetimeDB.Internal.ITableView.DoDelete( - row - ); + global::SpacetimeDB.Internal.ITableView< + TestIndexIssues, + global::TestIndexIssues + >.DoDelete(row); public sealed class TestIndexWithoutColumnsIndex() : SpacetimeDB.Internal.IndexBase( @@ -397,12 +507,12 @@ public ulong Delete(Bound SelfIndexingColumn) => } public readonly struct TestScheduleWithMissingScheduleAtField - : SpacetimeDB.Internal.ITableView< + : global::SpacetimeDB.Internal.ITableView< TestScheduleWithMissingScheduleAtField, global::TestScheduleIssues > { - static global::TestScheduleIssues SpacetimeDB.Internal.ITableView< + static global::TestScheduleIssues global::SpacetimeDB.Internal.ITableView< TestScheduleWithMissingScheduleAtField, global::TestScheduleIssues >.ReadGenFields(System.IO.BinaryReader reader, global::TestScheduleIssues row) @@ -410,7 +520,7 @@ public readonly struct TestScheduleWithMissingScheduleAtField return row; } - static SpacetimeDB.Internal.RawTableDefV9 SpacetimeDB.Internal.ITableView< + static SpacetimeDB.Internal.RawTableDefV9 global::SpacetimeDB.Internal.ITableView< TestScheduleWithMissingScheduleAtField, global::TestScheduleIssues >.MakeTableDesc(SpacetimeDB.BSATN.ITypeRegistrar registrar) => @@ -428,37 +538,37 @@ static SpacetimeDB.Internal.RawTableDefV9 SpacetimeDB.Internal.ITableView< ); public ulong Count => - SpacetimeDB.Internal.ITableView< + global::SpacetimeDB.Internal.ITableView< TestScheduleWithMissingScheduleAtField, global::TestScheduleIssues >.DoCount(); public IEnumerable Iter() => - SpacetimeDB.Internal.ITableView< + global::SpacetimeDB.Internal.ITableView< TestScheduleWithMissingScheduleAtField, global::TestScheduleIssues >.DoIter(); public global::TestScheduleIssues Insert(global::TestScheduleIssues row) => - SpacetimeDB.Internal.ITableView< + global::SpacetimeDB.Internal.ITableView< TestScheduleWithMissingScheduleAtField, global::TestScheduleIssues >.DoInsert(row); public bool Delete(global::TestScheduleIssues row) => - SpacetimeDB.Internal.ITableView< + global::SpacetimeDB.Internal.ITableView< TestScheduleWithMissingScheduleAtField, global::TestScheduleIssues >.DoDelete(row); } public readonly struct TestScheduleWithoutPrimaryKey - : SpacetimeDB.Internal.ITableView< + : global::SpacetimeDB.Internal.ITableView< TestScheduleWithoutPrimaryKey, global::TestScheduleIssues > { - static global::TestScheduleIssues SpacetimeDB.Internal.ITableView< + static global::TestScheduleIssues global::SpacetimeDB.Internal.ITableView< TestScheduleWithoutPrimaryKey, global::TestScheduleIssues >.ReadGenFields(System.IO.BinaryReader reader, global::TestScheduleIssues row) @@ -466,7 +576,7 @@ public readonly struct TestScheduleWithoutPrimaryKey return row; } - static SpacetimeDB.Internal.RawTableDefV9 SpacetimeDB.Internal.ITableView< + static SpacetimeDB.Internal.RawTableDefV9 global::SpacetimeDB.Internal.ITableView< TestScheduleWithoutPrimaryKey, global::TestScheduleIssues >.MakeTableDesc(SpacetimeDB.BSATN.ITypeRegistrar registrar) => @@ -478,7 +588,7 @@ static SpacetimeDB.Internal.RawTableDefV9 SpacetimeDB.Internal.ITableView< Indexes: [], Constraints: [], Sequences: [], - Schedule: SpacetimeDB.Internal.ITableView< + Schedule: global::SpacetimeDB.Internal.ITableView< TestScheduleWithoutPrimaryKey, global::TestScheduleIssues >.MakeSchedule("DummyScheduledReducer", 3), @@ -487,37 +597,37 @@ static SpacetimeDB.Internal.RawTableDefV9 SpacetimeDB.Internal.ITableView< ); public ulong Count => - SpacetimeDB.Internal.ITableView< + global::SpacetimeDB.Internal.ITableView< TestScheduleWithoutPrimaryKey, global::TestScheduleIssues >.DoCount(); public IEnumerable Iter() => - SpacetimeDB.Internal.ITableView< + global::SpacetimeDB.Internal.ITableView< TestScheduleWithoutPrimaryKey, global::TestScheduleIssues >.DoIter(); public global::TestScheduleIssues Insert(global::TestScheduleIssues row) => - SpacetimeDB.Internal.ITableView< + global::SpacetimeDB.Internal.ITableView< TestScheduleWithoutPrimaryKey, global::TestScheduleIssues >.DoInsert(row); public bool Delete(global::TestScheduleIssues row) => - SpacetimeDB.Internal.ITableView< + global::SpacetimeDB.Internal.ITableView< TestScheduleWithoutPrimaryKey, global::TestScheduleIssues >.DoDelete(row); } public readonly struct TestScheduleWithoutScheduleAt - : SpacetimeDB.Internal.ITableView< + : global::SpacetimeDB.Internal.ITableView< TestScheduleWithoutScheduleAt, global::TestScheduleIssues > { - static global::TestScheduleIssues SpacetimeDB.Internal.ITableView< + static global::TestScheduleIssues global::SpacetimeDB.Internal.ITableView< TestScheduleWithoutScheduleAt, global::TestScheduleIssues >.ReadGenFields(System.IO.BinaryReader reader, global::TestScheduleIssues row) @@ -525,7 +635,7 @@ public readonly struct TestScheduleWithoutScheduleAt return row; } - static SpacetimeDB.Internal.RawTableDefV9 SpacetimeDB.Internal.ITableView< + static SpacetimeDB.Internal.RawTableDefV9 global::SpacetimeDB.Internal.ITableView< TestScheduleWithoutScheduleAt, global::TestScheduleIssues >.MakeTableDesc(SpacetimeDB.BSATN.ITypeRegistrar registrar) => @@ -544,7 +654,7 @@ static SpacetimeDB.Internal.RawTableDefV9 SpacetimeDB.Internal.ITableView< ], Constraints: [ - SpacetimeDB.Internal.ITableView< + global::SpacetimeDB.Internal.ITableView< TestScheduleWithoutScheduleAt, global::TestScheduleIssues >.MakeUniqueConstraint(1) @@ -556,25 +666,25 @@ static SpacetimeDB.Internal.RawTableDefV9 SpacetimeDB.Internal.ITableView< ); public ulong Count => - SpacetimeDB.Internal.ITableView< + global::SpacetimeDB.Internal.ITableView< TestScheduleWithoutScheduleAt, global::TestScheduleIssues >.DoCount(); public IEnumerable Iter() => - SpacetimeDB.Internal.ITableView< + global::SpacetimeDB.Internal.ITableView< TestScheduleWithoutScheduleAt, global::TestScheduleIssues >.DoIter(); public global::TestScheduleIssues Insert(global::TestScheduleIssues row) => - SpacetimeDB.Internal.ITableView< + global::SpacetimeDB.Internal.ITableView< TestScheduleWithoutScheduleAt, global::TestScheduleIssues >.DoInsert(row); public bool Delete(global::TestScheduleIssues row) => - SpacetimeDB.Internal.ITableView< + global::SpacetimeDB.Internal.ITableView< TestScheduleWithoutScheduleAt, global::TestScheduleIssues >.DoDelete(row); @@ -604,12 +714,12 @@ internal IdCorrectTypeUniqueIndex() } public readonly struct TestScheduleWithWrongPrimaryKeyType - : SpacetimeDB.Internal.ITableView< + : global::SpacetimeDB.Internal.ITableView< TestScheduleWithWrongPrimaryKeyType, global::TestScheduleIssues > { - static global::TestScheduleIssues SpacetimeDB.Internal.ITableView< + static global::TestScheduleIssues global::SpacetimeDB.Internal.ITableView< TestScheduleWithWrongPrimaryKeyType, global::TestScheduleIssues >.ReadGenFields(System.IO.BinaryReader reader, global::TestScheduleIssues row) @@ -617,7 +727,7 @@ public readonly struct TestScheduleWithWrongPrimaryKeyType return row; } - static SpacetimeDB.Internal.RawTableDefV9 SpacetimeDB.Internal.ITableView< + static SpacetimeDB.Internal.RawTableDefV9 global::SpacetimeDB.Internal.ITableView< TestScheduleWithWrongPrimaryKeyType, global::TestScheduleIssues >.MakeTableDesc(SpacetimeDB.BSATN.ITypeRegistrar registrar) => @@ -636,13 +746,13 @@ static SpacetimeDB.Internal.RawTableDefV9 SpacetimeDB.Internal.ITableView< ], Constraints: [ - SpacetimeDB.Internal.ITableView< + global::SpacetimeDB.Internal.ITableView< TestScheduleWithWrongPrimaryKeyType, global::TestScheduleIssues >.MakeUniqueConstraint(0) ], Sequences: [], - Schedule: SpacetimeDB.Internal.ITableView< + Schedule: global::SpacetimeDB.Internal.ITableView< TestScheduleWithWrongPrimaryKeyType, global::TestScheduleIssues >.MakeSchedule("DummyScheduledReducer", 3), @@ -651,25 +761,25 @@ static SpacetimeDB.Internal.RawTableDefV9 SpacetimeDB.Internal.ITableView< ); public ulong Count => - SpacetimeDB.Internal.ITableView< + global::SpacetimeDB.Internal.ITableView< TestScheduleWithWrongPrimaryKeyType, global::TestScheduleIssues >.DoCount(); public IEnumerable Iter() => - SpacetimeDB.Internal.ITableView< + global::SpacetimeDB.Internal.ITableView< TestScheduleWithWrongPrimaryKeyType, global::TestScheduleIssues >.DoIter(); public global::TestScheduleIssues Insert(global::TestScheduleIssues row) => - SpacetimeDB.Internal.ITableView< + global::SpacetimeDB.Internal.ITableView< TestScheduleWithWrongPrimaryKeyType, global::TestScheduleIssues >.DoInsert(row); public bool Delete(global::TestScheduleIssues row) => - SpacetimeDB.Internal.ITableView< + global::SpacetimeDB.Internal.ITableView< TestScheduleWithWrongPrimaryKeyType, global::TestScheduleIssues >.DoDelete(row); @@ -699,12 +809,12 @@ internal IdWrongTypeUniqueIndex() } public readonly struct TestScheduleWithWrongScheduleAtType - : SpacetimeDB.Internal.ITableView< + : global::SpacetimeDB.Internal.ITableView< TestScheduleWithWrongScheduleAtType, global::TestScheduleIssues > { - static global::TestScheduleIssues SpacetimeDB.Internal.ITableView< + static global::TestScheduleIssues global::SpacetimeDB.Internal.ITableView< TestScheduleWithWrongScheduleAtType, global::TestScheduleIssues >.ReadGenFields(System.IO.BinaryReader reader, global::TestScheduleIssues row) @@ -712,7 +822,7 @@ public readonly struct TestScheduleWithWrongScheduleAtType return row; } - static SpacetimeDB.Internal.RawTableDefV9 SpacetimeDB.Internal.ITableView< + static SpacetimeDB.Internal.RawTableDefV9 global::SpacetimeDB.Internal.ITableView< TestScheduleWithWrongScheduleAtType, global::TestScheduleIssues >.MakeTableDesc(SpacetimeDB.BSATN.ITypeRegistrar registrar) => @@ -731,13 +841,13 @@ static SpacetimeDB.Internal.RawTableDefV9 SpacetimeDB.Internal.ITableView< ], Constraints: [ - SpacetimeDB.Internal.ITableView< + global::SpacetimeDB.Internal.ITableView< TestScheduleWithWrongScheduleAtType, global::TestScheduleIssues >.MakeUniqueConstraint(1) ], Sequences: [], - Schedule: SpacetimeDB.Internal.ITableView< + Schedule: global::SpacetimeDB.Internal.ITableView< TestScheduleWithWrongScheduleAtType, global::TestScheduleIssues >.MakeSchedule("DummyScheduledReducer", 2), @@ -746,25 +856,25 @@ static SpacetimeDB.Internal.RawTableDefV9 SpacetimeDB.Internal.ITableView< ); public ulong Count => - SpacetimeDB.Internal.ITableView< + global::SpacetimeDB.Internal.ITableView< TestScheduleWithWrongScheduleAtType, global::TestScheduleIssues >.DoCount(); public IEnumerable Iter() => - SpacetimeDB.Internal.ITableView< + global::SpacetimeDB.Internal.ITableView< TestScheduleWithWrongScheduleAtType, global::TestScheduleIssues >.DoIter(); public global::TestScheduleIssues Insert(global::TestScheduleIssues row) => - SpacetimeDB.Internal.ITableView< + global::SpacetimeDB.Internal.ITableView< TestScheduleWithWrongScheduleAtType, global::TestScheduleIssues >.DoInsert(row); public bool Delete(global::TestScheduleIssues row) => - SpacetimeDB.Internal.ITableView< + global::SpacetimeDB.Internal.ITableView< TestScheduleWithWrongScheduleAtType, global::TestScheduleIssues >.DoDelete(row); @@ -794,12 +904,12 @@ internal IdCorrectTypeUniqueIndex() } public readonly struct TestUniqueNotEquatable - : SpacetimeDB.Internal.ITableView< + : global::SpacetimeDB.Internal.ITableView< TestUniqueNotEquatable, global::TestUniqueNotEquatable > { - static global::TestUniqueNotEquatable SpacetimeDB.Internal.ITableView< + static global::TestUniqueNotEquatable global::SpacetimeDB.Internal.ITableView< TestUniqueNotEquatable, global::TestUniqueNotEquatable >.ReadGenFields(System.IO.BinaryReader reader, global::TestUniqueNotEquatable row) @@ -807,7 +917,7 @@ public readonly struct TestUniqueNotEquatable return row; } - static SpacetimeDB.Internal.RawTableDefV9 SpacetimeDB.Internal.ITableView< + static SpacetimeDB.Internal.RawTableDefV9 global::SpacetimeDB.Internal.ITableView< TestUniqueNotEquatable, global::TestUniqueNotEquatable >.MakeTableDesc(SpacetimeDB.BSATN.ITypeRegistrar registrar) => @@ -831,11 +941,11 @@ static SpacetimeDB.Internal.RawTableDefV9 SpacetimeDB.Internal.ITableView< ], Constraints: [ - SpacetimeDB.Internal.ITableView< + global::SpacetimeDB.Internal.ITableView< TestUniqueNotEquatable, global::TestUniqueNotEquatable >.MakeUniqueConstraint(0), - SpacetimeDB.Internal.ITableView< + global::SpacetimeDB.Internal.ITableView< TestUniqueNotEquatable, global::TestUniqueNotEquatable >.MakeUniqueConstraint(1) @@ -847,25 +957,25 @@ static SpacetimeDB.Internal.RawTableDefV9 SpacetimeDB.Internal.ITableView< ); public ulong Count => - SpacetimeDB.Internal.ITableView< + global::SpacetimeDB.Internal.ITableView< TestUniqueNotEquatable, global::TestUniqueNotEquatable >.DoCount(); public IEnumerable Iter() => - SpacetimeDB.Internal.ITableView< + global::SpacetimeDB.Internal.ITableView< TestUniqueNotEquatable, global::TestUniqueNotEquatable >.DoIter(); public global::TestUniqueNotEquatable Insert(global::TestUniqueNotEquatable row) => - SpacetimeDB.Internal.ITableView< + global::SpacetimeDB.Internal.ITableView< TestUniqueNotEquatable, global::TestUniqueNotEquatable >.DoInsert(row); public bool Delete(global::TestUniqueNotEquatable row) => - SpacetimeDB.Internal.ITableView< + global::SpacetimeDB.Internal.ITableView< TestUniqueNotEquatable, global::TestUniqueNotEquatable >.DoDelete(row); @@ -897,21 +1007,700 @@ internal PrimaryKeyFieldUniqueIndex() public sealed class Local { - public Internal.TableHandles.TestAutoIncNotInteger TestAutoIncNotInteger => new(); - public Internal.TableHandles.TestDefaultFieldValues TestDefaultFieldValues => new(); - public Internal.TableHandles.TestDuplicateTableName TestDuplicateTableName => new(); - public Internal.TableHandles.TestIndexIssues TestIndexIssues => new(); - public Internal.TableHandles.TestScheduleWithMissingScheduleAtField TestScheduleWithMissingScheduleAtField => + public global::SpacetimeDB.Internal.TableHandles.Player Player => new(); + public global::SpacetimeDB.Internal.TableHandles.TestAutoIncNotInteger TestAutoIncNotInteger => + new(); + public global::SpacetimeDB.Internal.TableHandles.TestDefaultFieldValues TestDefaultFieldValues => + new(); + public global::SpacetimeDB.Internal.TableHandles.TestDuplicateTableName TestDuplicateTableName => + new(); + public global::SpacetimeDB.Internal.TableHandles.TestIndexIssues TestIndexIssues => new(); + public global::SpacetimeDB.Internal.TableHandles.TestScheduleWithMissingScheduleAtField TestScheduleWithMissingScheduleAtField => + new(); + public global::SpacetimeDB.Internal.TableHandles.TestScheduleWithoutPrimaryKey TestScheduleWithoutPrimaryKey => new(); - public Internal.TableHandles.TestScheduleWithoutPrimaryKey TestScheduleWithoutPrimaryKey => + public global::SpacetimeDB.Internal.TableHandles.TestScheduleWithoutScheduleAt TestScheduleWithoutScheduleAt => new(); - public Internal.TableHandles.TestScheduleWithoutScheduleAt TestScheduleWithoutScheduleAt => + public global::SpacetimeDB.Internal.TableHandles.TestScheduleWithWrongPrimaryKeyType TestScheduleWithWrongPrimaryKeyType => new(); - public Internal.TableHandles.TestScheduleWithWrongPrimaryKeyType TestScheduleWithWrongPrimaryKeyType => + public global::SpacetimeDB.Internal.TableHandles.TestScheduleWithWrongScheduleAtType TestScheduleWithWrongScheduleAtType => new(); - public Internal.TableHandles.TestScheduleWithWrongScheduleAtType TestScheduleWithWrongScheduleAtType => + public global::SpacetimeDB.Internal.TableHandles.TestUniqueNotEquatable TestUniqueNotEquatable => + new(); + } +} + +sealed class ViewDefIndexNoMutationViewDispatcher : global::SpacetimeDB.Internal.IAnonymousView +{ + private static readonly SpacetimeDB.BSATN.ValueOption returnRW = new(); + + public SpacetimeDB.Internal.RawViewDefV9 MakeAnonymousViewDef( + SpacetimeDB.BSATN.ITypeRegistrar registrar + ) => + new global::SpacetimeDB.Internal.RawViewDefV9( + Name: "ViewDefIndexNoMutation", + Index: 1, + IsPublic: true, + IsAnonymous: true, + Params: [], + ReturnType: new SpacetimeDB.BSATN.ValueOption().GetAlgebraicType( + registrar + ) + ); + + public byte[] Invoke( + System.IO.BinaryReader reader, + global::SpacetimeDB.Internal.IAnonymousViewContext ctx + ) + { + try + { + var returnValue = Module.ViewDefIndexNoMutation((SpacetimeDB.AnonymousViewContext)ctx); + using var output = new System.IO.MemoryStream(); + using var writer = new System.IO.BinaryWriter(output); + returnRW.Write(writer, returnValue); + return output.ToArray(); + } + catch (System.Exception e) + { + global::SpacetimeDB.Log.Error("Error in view 'ViewDefIndexNoMutation': " + e); + throw; + } + } +} + +sealed class ViewDefNoAnonIdentityViewDispatcher : global::SpacetimeDB.Internal.IAnonymousView +{ + private static readonly SpacetimeDB.BSATN.ValueOption returnRW = new(); + + public SpacetimeDB.Internal.RawViewDefV9 MakeAnonymousViewDef( + SpacetimeDB.BSATN.ITypeRegistrar registrar + ) => + new global::SpacetimeDB.Internal.RawViewDefV9( + Name: "ViewDefNoAnonIdentity", + Index: 2, + IsPublic: true, + IsAnonymous: true, + Params: [], + ReturnType: new SpacetimeDB.BSATN.ValueOption().GetAlgebraicType( + registrar + ) + ); + + public byte[] Invoke( + System.IO.BinaryReader reader, + global::SpacetimeDB.Internal.IAnonymousViewContext ctx + ) + { + try + { + var returnValue = Module.ViewDefNoAnonIdentity((SpacetimeDB.AnonymousViewContext)ctx); + using var output = new System.IO.MemoryStream(); + using var writer = new System.IO.BinaryWriter(output); + returnRW.Write(writer, returnValue); + return output.ToArray(); + } + catch (System.Exception e) + { + global::SpacetimeDB.Log.Error("Error in view 'ViewDefNoAnonIdentity': " + e); + throw; + } + } +} + +sealed class ViewDefNoContextViewDispatcher : global::SpacetimeDB.Internal.IView +{ + private static readonly SpacetimeDB.BSATN.List returnRW = new(); + + public SpacetimeDB.Internal.RawViewDefV9 MakeViewDef( + SpacetimeDB.BSATN.ITypeRegistrar registrar + ) => + new global::SpacetimeDB.Internal.RawViewDefV9( + Name: "ViewDefNoContext", + Index: 1, + IsPublic: true, + IsAnonymous: false, + Params: [], + ReturnType: new SpacetimeDB.BSATN.List().GetAlgebraicType( + registrar + ) + ); + + public byte[] Invoke( + System.IO.BinaryReader reader, + global::SpacetimeDB.Internal.IViewContext ctx + ) + { + try + { + var returnValue = Module.ViewDefNoContext((SpacetimeDB.ViewContext)ctx); + using var output = new System.IO.MemoryStream(); + using var writer = new System.IO.BinaryWriter(output); + returnRW.Write(writer, returnValue); + return output.ToArray(); + } + catch (System.Exception e) + { + global::SpacetimeDB.Log.Error("Error in view 'ViewDefNoContext': " + e); + throw; + } + } +} + +sealed class ViewDefNoIterViewDispatcher : global::SpacetimeDB.Internal.IAnonymousView +{ + private static readonly SpacetimeDB.BSATN.ValueOption returnRW = new(); + + public SpacetimeDB.Internal.RawViewDefV9 MakeAnonymousViewDef( + SpacetimeDB.BSATN.ITypeRegistrar registrar + ) => + new global::SpacetimeDB.Internal.RawViewDefV9( + Name: "ViewDefNoIter", + Index: 3, + IsPublic: true, + IsAnonymous: true, + Params: [], + ReturnType: new SpacetimeDB.BSATN.ValueOption().GetAlgebraicType( + registrar + ) + ); + + public byte[] Invoke( + System.IO.BinaryReader reader, + global::SpacetimeDB.Internal.IAnonymousViewContext ctx + ) + { + try + { + var returnValue = Module.ViewDefNoIter((SpacetimeDB.AnonymousViewContext)ctx); + using var output = new System.IO.MemoryStream(); + using var writer = new System.IO.BinaryWriter(output); + returnRW.Write(writer, returnValue); + return output.ToArray(); + } + catch (System.Exception e) + { + global::SpacetimeDB.Log.Error("Error in view 'ViewDefNoIter': " + e); + throw; + } + } +} + +sealed class ViewDefNoPublicViewDispatcher : global::SpacetimeDB.Internal.IView +{ + private static readonly SpacetimeDB.BSATN.List returnRW = new(); + + public SpacetimeDB.Internal.RawViewDefV9 MakeViewDef( + SpacetimeDB.BSATN.ITypeRegistrar registrar + ) => + new global::SpacetimeDB.Internal.RawViewDefV9( + Name: "ViewDefNoPublic", + Index: 2, + IsPublic: false, + IsAnonymous: false, + Params: [], + ReturnType: new SpacetimeDB.BSATN.List().GetAlgebraicType( + registrar + ) + ); + + public byte[] Invoke( + System.IO.BinaryReader reader, + global::SpacetimeDB.Internal.IViewContext ctx + ) + { + try + { + var returnValue = Module.ViewDefNoPublic((SpacetimeDB.ViewContext)ctx); + using var output = new System.IO.MemoryStream(); + using var writer = new System.IO.BinaryWriter(output); + returnRW.Write(writer, returnValue); + return output.ToArray(); + } + catch (System.Exception e) + { + global::SpacetimeDB.Log.Error("Error in view 'ViewDefNoPublic': " + e); + throw; + } + } +} + +sealed class ViewDefReturnsNotASpacetimeTypeViewDispatcher + : global::SpacetimeDB.Internal.IAnonymousView +{ + private static readonly SpacetimeDB.BSATN.ValueOption< + NotSpacetimeType, + NotSpacetimeType.BSATN + > returnRW = new(); + + public SpacetimeDB.Internal.RawViewDefV9 MakeAnonymousViewDef( + SpacetimeDB.BSATN.ITypeRegistrar registrar + ) => + new global::SpacetimeDB.Internal.RawViewDefV9( + Name: "ViewDefReturnsNotASpacetimeType", + Index: 4, + IsPublic: true, + IsAnonymous: true, + Params: [], + ReturnType: new SpacetimeDB.BSATN.ValueOption< + NotSpacetimeType, + NotSpacetimeType.BSATN + >().GetAlgebraicType(registrar) + ); + + public byte[] Invoke( + System.IO.BinaryReader reader, + global::SpacetimeDB.Internal.IAnonymousViewContext ctx + ) + { + try + { + var returnValue = Module.ViewDefReturnsNotASpacetimeType( + (SpacetimeDB.AnonymousViewContext)ctx + ); + using var output = new System.IO.MemoryStream(); + using var writer = new System.IO.BinaryWriter(output); + returnRW.Write(writer, returnValue); + return output.ToArray(); + } + catch (System.Exception e) + { + global::SpacetimeDB.Log.Error("Error in view 'ViewDefReturnsNotASpacetimeType': " + e); + throw; + } + } +} + +sealed class ViewDefWrongContextViewDispatcher : global::SpacetimeDB.Internal.IView +{ + private static readonly SpacetimeDB.BSATN.List returnRW = new(); + + public SpacetimeDB.Internal.RawViewDefV9 MakeViewDef( + SpacetimeDB.BSATN.ITypeRegistrar registrar + ) => + new global::SpacetimeDB.Internal.RawViewDefV9( + Name: "ViewDefWrongContext", + Index: 3, + IsPublic: true, + IsAnonymous: false, + Params: [], + ReturnType: new SpacetimeDB.BSATN.List().GetAlgebraicType( + registrar + ) + ); + + public byte[] Invoke( + System.IO.BinaryReader reader, + global::SpacetimeDB.Internal.IViewContext ctx + ) + { + try + { + var returnValue = Module.ViewDefWrongContext((SpacetimeDB.ViewContext)ctx); + using var output = new System.IO.MemoryStream(); + using var writer = new System.IO.BinaryWriter(output); + returnRW.Write(writer, returnValue); + return output.ToArray(); + } + catch (System.Exception e) + { + global::SpacetimeDB.Log.Error("Error in view 'ViewDefWrongContext': " + e); + throw; + } + } +} + +sealed class ViewDefWrongReturnViewDispatcher : global::SpacetimeDB.Internal.IView +{ + private static readonly Player.BSATN returnRW = new(); + + public SpacetimeDB.Internal.RawViewDefV9 MakeViewDef( + SpacetimeDB.BSATN.ITypeRegistrar registrar + ) => + new global::SpacetimeDB.Internal.RawViewDefV9( + Name: "ViewDefWrongReturn", + Index: 4, + IsPublic: true, + IsAnonymous: false, + Params: [], + ReturnType: new Player.BSATN().GetAlgebraicType(registrar) + ); + + public byte[] Invoke( + System.IO.BinaryReader reader, + global::SpacetimeDB.Internal.IViewContext ctx + ) + { + try + { + var returnValue = Module.ViewDefWrongReturn((SpacetimeDB.ViewContext)ctx); + using var output = new System.IO.MemoryStream(); + using var writer = new System.IO.BinaryWriter(output); + returnRW.Write(writer, returnValue); + return output.ToArray(); + } + catch (System.Exception e) + { + global::SpacetimeDB.Log.Error("Error in view 'ViewDefWrongReturn': " + e); + throw; + } + } +} + +sealed class ViewNoDeleteViewDispatcher : global::SpacetimeDB.Internal.IView +{ + private static readonly SpacetimeDB.BSATN.ValueOption returnRW = new(); + + public SpacetimeDB.Internal.RawViewDefV9 MakeViewDef( + SpacetimeDB.BSATN.ITypeRegistrar registrar + ) => + new global::SpacetimeDB.Internal.RawViewDefV9( + Name: "ViewNoDelete", + Index: 5, + IsPublic: true, + IsAnonymous: false, + Params: [], + ReturnType: new SpacetimeDB.BSATN.ValueOption().GetAlgebraicType( + registrar + ) + ); + + public byte[] Invoke( + System.IO.BinaryReader reader, + global::SpacetimeDB.Internal.IViewContext ctx + ) + { + try + { + var returnValue = Module.ViewNoDelete((SpacetimeDB.ViewContext)ctx); + using var output = new System.IO.MemoryStream(); + using var writer = new System.IO.BinaryWriter(output); + returnRW.Write(writer, returnValue); + return output.ToArray(); + } + catch (System.Exception e) + { + global::SpacetimeDB.Log.Error("Error in view 'ViewNoDelete': " + e); + throw; + } + } +} + +sealed class ViewNoInsertViewDispatcher : global::SpacetimeDB.Internal.IView +{ + private static readonly SpacetimeDB.BSATN.ValueOption returnRW = new(); + + public SpacetimeDB.Internal.RawViewDefV9 MakeViewDef( + SpacetimeDB.BSATN.ITypeRegistrar registrar + ) => + new global::SpacetimeDB.Internal.RawViewDefV9( + Name: "ViewNoInsert", + Index: 6, + IsPublic: true, + IsAnonymous: false, + Params: [], + ReturnType: new SpacetimeDB.BSATN.ValueOption().GetAlgebraicType( + registrar + ) + ); + + public byte[] Invoke( + System.IO.BinaryReader reader, + global::SpacetimeDB.Internal.IViewContext ctx + ) + { + try + { + var returnValue = Module.ViewNoInsert((SpacetimeDB.ViewContext)ctx); + using var output = new System.IO.MemoryStream(); + using var writer = new System.IO.BinaryWriter(output); + returnRW.Write(writer, returnValue); + return output.ToArray(); + } + catch (System.Exception e) + { + global::SpacetimeDB.Log.Error("Error in view 'ViewNoInsert': " + e); + throw; + } + } +} + +namespace SpacetimeDB.Internal.ViewHandles +{ + public sealed class PlayerReadOnly + : global::SpacetimeDB.Internal.ReadOnlyTableView + { + internal PlayerReadOnly() + : base("Player") { } + + public ulong Count => DoCount(); + + public sealed class IdentityIndex + : global::SpacetimeDB.Internal.ReadOnlyUniqueIndex< + global::SpacetimeDB.Internal.ViewHandles.PlayerReadOnly, + global::Player, + SpacetimeDB.Identity, + SpacetimeDB.Identity.BSATN + > + { + internal IdentityIndex() + : base("Player_Identity_idx_btree") { } + + public global::Player? Find(SpacetimeDB.Identity key) => FindSingle(key); + } + + public IdentityIndex Identity => new(); + } + + public sealed class TestAutoIncNotIntegerReadOnly + : global::SpacetimeDB.Internal.ReadOnlyTableView + { + internal TestAutoIncNotIntegerReadOnly() + : base("TestAutoIncNotInteger") { } + + public ulong Count => DoCount(); + + public sealed class IdentityFieldIndex + : global::SpacetimeDB.Internal.ReadOnlyUniqueIndex< + global::SpacetimeDB.Internal.ViewHandles.TestAutoIncNotIntegerReadOnly, + global::TestAutoIncNotInteger, + string, + SpacetimeDB.BSATN.String + > + { + internal IdentityFieldIndex() + : base("TestAutoIncNotInteger_IdentityField_idx_btree") { } + + public global::TestAutoIncNotInteger? Find(string key) => FindSingle(key); + } + + public IdentityFieldIndex IdentityField => new(); + } + + public sealed class TestDefaultFieldValuesReadOnly + : global::SpacetimeDB.Internal.ReadOnlyTableView + { + internal TestDefaultFieldValuesReadOnly() + : base("TestDefaultFieldValues") { } + + public ulong Count => DoCount(); + } + + public sealed class TestDuplicateTableNameReadOnly + : global::SpacetimeDB.Internal.ReadOnlyTableView + { + internal TestDuplicateTableNameReadOnly() + : base("TestDuplicateTableName") { } + + public ulong Count => DoCount(); + } + + public sealed class TestIndexIssuesReadOnly + : global::SpacetimeDB.Internal.ReadOnlyTableView + { + internal TestIndexIssuesReadOnly() + : base("TestIndexIssues") { } + + public ulong Count => DoCount(); + + public sealed class TestIndexWithoutColumnsIndex + : global::SpacetimeDB.Internal.ReadOnlyIndexBase + { + internal TestIndexWithoutColumnsIndex() + : base("TestIndexIssues__idx_btree") { } + } + + public TestIndexWithoutColumnsIndex TestIndexWithoutColumns => new(); + + public sealed class TestIndexWithEmptyColumnsIndex + : global::SpacetimeDB.Internal.ReadOnlyIndexBase + { + internal TestIndexWithEmptyColumnsIndex() + : base("TestIndexIssues__idx_btree") { } + } + + public TestIndexWithEmptyColumnsIndex TestIndexWithEmptyColumns => new(); + + public sealed class TestUnknownColumnsIndex + : global::SpacetimeDB.Internal.ReadOnlyIndexBase + { + internal TestUnknownColumnsIndex() + : base("TestIndexIssues__idx_btree") { } + } + + public TestUnknownColumnsIndex TestUnknownColumns => new(); + + public sealed class TestUnexpectedColumnsIndex + : global::SpacetimeDB.Internal.ReadOnlyIndexBase + { + internal TestUnexpectedColumnsIndex() + : base("TestIndexIssues_SelfIndexingColumn_idx_btree") { } + + public IEnumerable Filter(int SelfIndexingColumn) => + DoFilter( + new global::SpacetimeDB.Internal.BTreeIndexBounds( + SelfIndexingColumn + ) + ); + + public IEnumerable Filter( + global::SpacetimeDB.Internal.Bound SelfIndexingColumn + ) => + DoFilter( + new global::SpacetimeDB.Internal.BTreeIndexBounds( + SelfIndexingColumn + ) + ); + } + + public TestUnexpectedColumnsIndex TestUnexpectedColumns => new(); + } + + public sealed class TestScheduleWithMissingScheduleAtFieldReadOnly + : global::SpacetimeDB.Internal.ReadOnlyTableView + { + internal TestScheduleWithMissingScheduleAtFieldReadOnly() + : base("TestScheduleWithMissingScheduleAtField") { } + + public ulong Count => DoCount(); + } + + public sealed class TestScheduleWithoutPrimaryKeyReadOnly + : global::SpacetimeDB.Internal.ReadOnlyTableView + { + internal TestScheduleWithoutPrimaryKeyReadOnly() + : base("TestScheduleWithoutPrimaryKey") { } + + public ulong Count => DoCount(); + } + + public sealed class TestScheduleWithoutScheduleAtReadOnly + : global::SpacetimeDB.Internal.ReadOnlyTableView + { + internal TestScheduleWithoutScheduleAtReadOnly() + : base("TestScheduleWithoutScheduleAt") { } + + public ulong Count => DoCount(); + + public sealed class IdCorrectTypeIndex + : global::SpacetimeDB.Internal.ReadOnlyUniqueIndex< + global::SpacetimeDB.Internal.ViewHandles.TestScheduleWithoutScheduleAtReadOnly, + global::TestScheduleIssues, + int, + SpacetimeDB.BSATN.I32 + > + { + internal IdCorrectTypeIndex() + : base("TestScheduleWithoutScheduleAt_IdCorrectType_idx_btree") { } + + public global::TestScheduleIssues? Find(int key) => FindSingle(key); + } + + public IdCorrectTypeIndex IdCorrectType => new(); + } + + public sealed class TestScheduleWithWrongPrimaryKeyTypeReadOnly + : global::SpacetimeDB.Internal.ReadOnlyTableView + { + internal TestScheduleWithWrongPrimaryKeyTypeReadOnly() + : base("TestScheduleWithWrongPrimaryKeyType") { } + + public ulong Count => DoCount(); + + public sealed class IdWrongTypeIndex + : global::SpacetimeDB.Internal.ReadOnlyUniqueIndex< + global::SpacetimeDB.Internal.ViewHandles.TestScheduleWithWrongPrimaryKeyTypeReadOnly, + global::TestScheduleIssues, + string, + SpacetimeDB.BSATN.String + > + { + internal IdWrongTypeIndex() + : base("TestScheduleWithWrongPrimaryKeyType_IdWrongType_idx_btree") { } + + public global::TestScheduleIssues? Find(string key) => FindSingle(key); + } + + public IdWrongTypeIndex IdWrongType => new(); + } + + public sealed class TestScheduleWithWrongScheduleAtTypeReadOnly + : global::SpacetimeDB.Internal.ReadOnlyTableView + { + internal TestScheduleWithWrongScheduleAtTypeReadOnly() + : base("TestScheduleWithWrongScheduleAtType") { } + + public ulong Count => DoCount(); + + public sealed class IdCorrectTypeIndex + : global::SpacetimeDB.Internal.ReadOnlyUniqueIndex< + global::SpacetimeDB.Internal.ViewHandles.TestScheduleWithWrongScheduleAtTypeReadOnly, + global::TestScheduleIssues, + int, + SpacetimeDB.BSATN.I32 + > + { + internal IdCorrectTypeIndex() + : base("TestScheduleWithWrongScheduleAtType_IdCorrectType_idx_btree") { } + + public global::TestScheduleIssues? Find(int key) => FindSingle(key); + } + + public IdCorrectTypeIndex IdCorrectType => new(); + } + + public sealed class TestUniqueNotEquatableReadOnly + : global::SpacetimeDB.Internal.ReadOnlyTableView + { + internal TestUniqueNotEquatableReadOnly() + : base("TestUniqueNotEquatable") { } + + public ulong Count => DoCount(); + + public sealed class PrimaryKeyFieldIndex + : global::SpacetimeDB.Internal.ReadOnlyUniqueIndex< + global::SpacetimeDB.Internal.ViewHandles.TestUniqueNotEquatableReadOnly, + global::TestUniqueNotEquatable, + TestEnumWithExplicitValues, + SpacetimeDB.BSATN.Enum + > + { + internal PrimaryKeyFieldIndex() + : base("TestUniqueNotEquatable_PrimaryKeyField_idx_btree") { } + + public global::TestUniqueNotEquatable? Find(TestEnumWithExplicitValues key) => + FindSingle(key); + } + + public PrimaryKeyFieldIndex PrimaryKeyField => new(); + } +} + +namespace SpacetimeDB.Internal +{ + public sealed partial class LocalReadOnly + { + public global::SpacetimeDB.Internal.ViewHandles.PlayerReadOnly Player => new(); + public global::SpacetimeDB.Internal.ViewHandles.TestAutoIncNotIntegerReadOnly TestAutoIncNotInteger => + new(); + public global::SpacetimeDB.Internal.ViewHandles.TestDefaultFieldValuesReadOnly TestDefaultFieldValues => + new(); + public global::SpacetimeDB.Internal.ViewHandles.TestDuplicateTableNameReadOnly TestDuplicateTableName => + new(); + public global::SpacetimeDB.Internal.ViewHandles.TestIndexIssuesReadOnly TestIndexIssues => + new(); + public global::SpacetimeDB.Internal.ViewHandles.TestScheduleWithMissingScheduleAtFieldReadOnly TestScheduleWithMissingScheduleAtField => + new(); + public global::SpacetimeDB.Internal.ViewHandles.TestScheduleWithoutPrimaryKeyReadOnly TestScheduleWithoutPrimaryKey => + new(); + public global::SpacetimeDB.Internal.ViewHandles.TestScheduleWithoutScheduleAtReadOnly TestScheduleWithoutScheduleAt => + new(); + public global::SpacetimeDB.Internal.ViewHandles.TestScheduleWithWrongPrimaryKeyTypeReadOnly TestScheduleWithWrongPrimaryKeyType => + new(); + public global::SpacetimeDB.Internal.ViewHandles.TestScheduleWithWrongScheduleAtTypeReadOnly TestScheduleWithWrongScheduleAtType => + new(); + public global::SpacetimeDB.Internal.ViewHandles.TestUniqueNotEquatableReadOnly TestUniqueNotEquatable => new(); - public Internal.TableHandles.TestUniqueNotEquatable TestUniqueNotEquatable => new(); } } @@ -1040,6 +1829,15 @@ public static void Main() (identity, connectionId, random, time) => new SpacetimeDB.ReducerContext(identity, connectionId, random, time) ); + SpacetimeDB.Internal.Module.SetViewContextConstructor( + identity => new SpacetimeDB.ViewContext( + identity, + new SpacetimeDB.Internal.LocalReadOnly() + ) + ); + SpacetimeDB.Internal.Module.SetAnonymousViewContextConstructor( + () => new SpacetimeDB.AnonymousViewContext(new SpacetimeDB.Internal.LocalReadOnly()) + ); var __memoryStream = new MemoryStream(); var __writer = new BinaryWriter(__memoryStream); @@ -1051,6 +1849,20 @@ public static void Main() SpacetimeDB.Internal.Module.RegisterReducer(); SpacetimeDB.Internal.Module.RegisterReducer(); SpacetimeDB.Internal.Module.RegisterReducer(); + SpacetimeDB.Internal.Module.RegisterAnonymousView(); + SpacetimeDB.Internal.Module.RegisterAnonymousView(); + SpacetimeDB.Internal.Module.RegisterView(); + SpacetimeDB.Internal.Module.RegisterAnonymousView(); + SpacetimeDB.Internal.Module.RegisterView(); + SpacetimeDB.Internal.Module.RegisterAnonymousView(); + SpacetimeDB.Internal.Module.RegisterView(); + SpacetimeDB.Internal.Module.RegisterView(); + SpacetimeDB.Internal.Module.RegisterView(); + SpacetimeDB.Internal.Module.RegisterView(); + SpacetimeDB.Internal.Module.RegisterTable< + global::Player, + SpacetimeDB.Internal.TableHandles.Player + >(); SpacetimeDB.Internal.Module.RegisterTable< global::TestAutoIncNotInteger, SpacetimeDB.Internal.TableHandles.TestAutoIncNotInteger @@ -1337,3 +2149,5 @@ SpacetimeDB.Internal.BytesSink error ); #endif } + +#pragma warning restore CS0436 diff --git a/crates/bindings-csharp/Codegen.Tests/fixtures/diag/snapshots/Module#Player.verified.cs b/crates/bindings-csharp/Codegen.Tests/fixtures/diag/snapshots/Module#Player.verified.cs new file mode 100644 index 00000000000..ff392b76903 --- /dev/null +++ b/crates/bindings-csharp/Codegen.Tests/fixtures/diag/snapshots/Module#Player.verified.cs @@ -0,0 +1,101 @@ +//HintName: Player.cs +// +#nullable enable + +partial struct Player : System.IEquatable, SpacetimeDB.BSATN.IStructuralReadWrite +{ + public void ReadFields(System.IO.BinaryReader reader) + { + Identity = BSATN.IdentityRW.Read(reader); + } + + public void WriteFields(System.IO.BinaryWriter writer) + { + BSATN.IdentityRW.Write(writer, Identity); + } + + object SpacetimeDB.BSATN.IStructuralReadWrite.GetSerializer() + { + return new BSATN(); + } + + public override string ToString() => + $"Player {{ Identity = {SpacetimeDB.BSATN.StringUtil.GenericToString(Identity)} }}"; + + public readonly partial struct BSATN : SpacetimeDB.BSATN.IReadWrite + { + internal static readonly SpacetimeDB.Identity.BSATN IdentityRW = new(); + + public Player Read(System.IO.BinaryReader reader) + { + var ___result = new Player(); + ___result.ReadFields(reader); + return ___result; + } + + public void Write(System.IO.BinaryWriter writer, Player value) + { + value.WriteFields(writer); + } + + public SpacetimeDB.BSATN.AlgebraicType.Ref GetAlgebraicType( + SpacetimeDB.BSATN.ITypeRegistrar registrar + ) => + registrar.RegisterType(_ => new SpacetimeDB.BSATN.AlgebraicType.Product( + new SpacetimeDB.BSATN.AggregateElement[] + { + new("Identity", IdentityRW.GetAlgebraicType(registrar)) + } + )); + + SpacetimeDB.BSATN.AlgebraicType SpacetimeDB.BSATN.IReadWrite.GetAlgebraicType( + SpacetimeDB.BSATN.ITypeRegistrar registrar + ) => GetAlgebraicType(registrar); + } + + public override int GetHashCode() + { + var ___hashIdentity = Identity.GetHashCode(); + return ___hashIdentity; + } + +#nullable enable + public bool Equals(Player that) + { + var ___eqIdentity = this.Identity.Equals(that.Identity); + return ___eqIdentity; + } + + public override bool Equals(object? that) + { + if (that == null) + { + return false; + } + var that_ = that as Player?; + if (((object?)that_) == null) + { + return false; + } + return Equals(that_); + } + + public static bool operator ==(Player this_, Player that) + { + if (((object?)this_) == null || ((object?)that) == null) + { + return object.Equals(this_, that); + } + return this_.Equals(that); + } + + public static bool operator !=(Player this_, Player that) + { + if (((object?)this_) == null || ((object?)that) == null) + { + return !object.Equals(this_, that); + } + return !this_.Equals(that); + } +#nullable restore +} // Player diff --git a/crates/bindings-csharp/Codegen.Tests/fixtures/diag/snapshots/Module.verified.txt b/crates/bindings-csharp/Codegen.Tests/fixtures/diag/snapshots/Module.verified.txt index 422ef7c44c9..2f1f9e2b43a 100644 --- a/crates/bindings-csharp/Codegen.Tests/fixtures/diag/snapshots/Module.verified.txt +++ b/crates/bindings-csharp/Codegen.Tests/fixtures/diag/snapshots/Module.verified.txt @@ -271,6 +271,90 @@ public partial struct TestScheduleIssues } }, {/* + // Invalid: View definition missing Public=true + [SpacetimeDB.View(Name = "view_def_no_public")] + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + public static List ViewDefNoPublic(ViewContext ctx) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + { +^^^^^ + return new List(); +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + } +^^^^^ + +*/ + Message: View 'ViewDefNoPublic' must have Public = true. Views are always public in SpacetimeDB., + Severity: Error, + Descriptor: { + Id: STDB0023, + Title: Views must be public, + MessageFormat: View '{0}' must have Public = true. Views are always public in SpacetimeDB., + Category: SpacetimeDB, + DefaultSeverity: Error, + IsEnabledByDefault: true + } + }, + {/* + [SpacetimeDB.View(Name = "view_def_no_context", Public = true)] + public static List ViewDefNoContext() + ^^ + { +*/ + Message: View method ViewDefNoContext must have a first parameter of type ViewContext or AnonymousViewContext., + Severity: Error, + Descriptor: { + Id: STDB0020, + Title: Views must start with ViewContext or AnonymousViewContext, + MessageFormat: View method {0} must have a first parameter of type ViewContext or AnonymousViewContext., + Category: SpacetimeDB, + DefaultSeverity: Error, + IsEnabledByDefault: true + } + }, + {/* + [SpacetimeDB.View(Name = "view_def_wrong_context", Public = true)] + public static List ViewDefWrongContext(ReducerContext ctx) + ^^^^^^^^^^^^^^^^^^^^ + { +*/ + Message: View method ViewDefWrongContext must have a first parameter of type ViewContext or AnonymousViewContext., + Severity: Error, + Descriptor: { + Id: STDB0020, + Title: Views must start with ViewContext or AnonymousViewContext, + MessageFormat: View method {0} must have a first parameter of type ViewContext or AnonymousViewContext., + Category: SpacetimeDB, + DefaultSeverity: Error, + IsEnabledByDefault: true + } + }, + {/* + // Invalid: Wrong return type is not Vec or Option + [SpacetimeDB.View(Name = "view_def_wrong_return", Public = true)] + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + public static Player ViewDefWrongReturn(ViewContext ctx) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + { +^^^^^ + return new Player { Identity = new() }; +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + } +^^^^^ + +*/ + Message: View 'ViewDefWrongReturn' must return Vec or Option., + Severity: Error, + Descriptor: { + Id: STDB0022, + Title: Views must return Vec or Option, + MessageFormat: View '{0}' must return Vec or Option., + Category: SpacetimeDB, + DefaultSeverity: Error, + IsEnabledByDefault: true + } + }, + {/* [SpacetimeDB.Reducer] public static int TestReducerReturnType(ReducerContext ctx) => 0; ^^^ @@ -377,6 +461,19 @@ public partial struct TestScheduleIssues IsEnabledByDefault: true } }, + { + Location: , + Message: TableReadOnly with the same export name TestDuplicateTableNameReadOnly is registered in multiple places: global::TestDuplicateTableName, global::InAnotherNamespace.TestDuplicateTableName, + Severity: Error, + Descriptor: { + Id: STDB0007, + Title: Duplicate exports, + MessageFormat: {0} with the same export name {1} is registered in multiple places: {2}, + Category: SpacetimeDB, + DefaultSeverity: Error, + IsEnabledByDefault: true + } + }, {/* [SpacetimeDB.ClientVisibilityFilter] private Filter MY_FILTER = new Filter.Sql("SELECT * FROM TestAutoIncNotInteger"); diff --git a/crates/bindings-csharp/Codegen.Tests/fixtures/server/Lib.cs b/crates/bindings-csharp/Codegen.Tests/fixtures/server/Lib.cs index ebfaa60bb2d..11884f16af3 100644 --- a/crates/bindings-csharp/Codegen.Tests/fixtures/server/Lib.cs +++ b/crates/bindings-csharp/Codegen.Tests/fixtures/server/Lib.cs @@ -273,4 +273,16 @@ public class Module { [SpacetimeDB.ClientVisibilityFilter] public static readonly Filter ALL_PUBLIC_TABLES = new Filter.Sql("SELECT * FROM PublicTable"); + + [SpacetimeDB.View(Name = "public_table_view", Public = true)] + public static PublicTable? PublicTableByIdentity(ViewContext ctx) + { + return (PublicTable?)ctx.Db.PublicTable.Id.Find(0); + } + + [SpacetimeDB.View(Name = "find_public_table__by_identity", Public = true)] + public static PublicTable? FindPublicTableByIdentity(AnonymousViewContext ctx) + { + return (PublicTable?)ctx.Db.PublicTable.Id.Find(0); + } } diff --git a/crates/bindings-csharp/Codegen.Tests/fixtures/server/snapshots/Module#FFI.verified.cs b/crates/bindings-csharp/Codegen.Tests/fixtures/server/snapshots/Module#FFI.verified.cs index 5ed58322812..2ec9fd783d4 100644 --- a/crates/bindings-csharp/Codegen.Tests/fixtures/server/snapshots/Module#FFI.verified.cs +++ b/crates/bindings-csharp/Codegen.Tests/fixtures/server/snapshots/Module#FFI.verified.cs @@ -1,6 +1,10 @@ //HintName: FFI.cs // #nullable enable +// The runtime already defines SpacetimeDB.Internal.LocalReadOnly in Runtime\Internal\Module.cs as an empty partial type. +// This is needed so every module build doesn't generate a full LocalReadOnly type, but just adds on to the existing. +// We extend it here with generated table accessors, and just need to suppress the duplicate-type warning. +#pragma warning disable CS0436 using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; @@ -34,12 +38,31 @@ Timestamp time } } + public sealed record ViewContext : DbContext, Internal.IViewContext + { + public Identity Sender { get; } + + internal ViewContext(Identity sender, Internal.LocalReadOnly db) + : base(db) + { + Sender = sender; + } + } + + public sealed record AnonymousViewContext + : DbContext, + Internal.IAnonymousViewContext + { + internal AnonymousViewContext(Internal.LocalReadOnly db) + : base(db) { } + } + namespace Internal.TableHandles { internal readonly struct BTreeMultiColumn - : SpacetimeDB.Internal.ITableView + : global::SpacetimeDB.Internal.ITableView { - static global::BTreeMultiColumn SpacetimeDB.Internal.ITableView< + static global::BTreeMultiColumn global::SpacetimeDB.Internal.ITableView< BTreeMultiColumn, global::BTreeMultiColumn >.ReadGenFields(System.IO.BinaryReader reader, global::BTreeMultiColumn row) @@ -47,7 +70,7 @@ internal readonly struct BTreeMultiColumn return row; } - static SpacetimeDB.Internal.RawTableDefV9 SpacetimeDB.Internal.ITableView< + static SpacetimeDB.Internal.RawTableDefV9 global::SpacetimeDB.Internal.ITableView< BTreeMultiColumn, global::BTreeMultiColumn >.MakeTableDesc(SpacetimeDB.BSATN.ITypeRegistrar registrar) => @@ -72,25 +95,25 @@ static SpacetimeDB.Internal.RawTableDefV9 SpacetimeDB.Internal.ITableView< ); public ulong Count => - SpacetimeDB.Internal.ITableView< + global::SpacetimeDB.Internal.ITableView< BTreeMultiColumn, global::BTreeMultiColumn >.DoCount(); public IEnumerable Iter() => - SpacetimeDB.Internal.ITableView< + global::SpacetimeDB.Internal.ITableView< BTreeMultiColumn, global::BTreeMultiColumn >.DoIter(); public global::BTreeMultiColumn Insert(global::BTreeMultiColumn row) => - SpacetimeDB.Internal.ITableView< + global::SpacetimeDB.Internal.ITableView< BTreeMultiColumn, global::BTreeMultiColumn >.DoInsert(row); public bool Delete(global::BTreeMultiColumn row) => - SpacetimeDB.Internal.ITableView< + global::SpacetimeDB.Internal.ITableView< BTreeMultiColumn, global::BTreeMultiColumn >.DoDelete(row); @@ -215,9 +238,9 @@ public ulong Delete((uint X, uint Y, Bound Z) f) => } internal readonly struct BTreeViews - : SpacetimeDB.Internal.ITableView + : global::SpacetimeDB.Internal.ITableView { - static global::BTreeViews SpacetimeDB.Internal.ITableView< + static global::BTreeViews global::SpacetimeDB.Internal.ITableView< BTreeViews, global::BTreeViews >.ReadGenFields(System.IO.BinaryReader reader, global::BTreeViews row) @@ -225,7 +248,7 @@ internal readonly struct BTreeViews return row; } - static SpacetimeDB.Internal.RawTableDefV9 SpacetimeDB.Internal.ITableView< + static SpacetimeDB.Internal.RawTableDefV9 global::SpacetimeDB.Internal.ITableView< BTreeViews, global::BTreeViews >.MakeTableDesc(SpacetimeDB.BSATN.ITypeRegistrar registrar) => @@ -254,7 +277,7 @@ static SpacetimeDB.Internal.RawTableDefV9 SpacetimeDB.Internal.ITableView< ], Constraints: [ - SpacetimeDB.Internal.ITableView< + global::SpacetimeDB.Internal.ITableView< BTreeViews, global::BTreeViews >.MakeUniqueConstraint(0) @@ -266,16 +289,20 @@ static SpacetimeDB.Internal.RawTableDefV9 SpacetimeDB.Internal.ITableView< ); public ulong Count => - SpacetimeDB.Internal.ITableView.DoCount(); + global::SpacetimeDB.Internal.ITableView.DoCount(); public IEnumerable Iter() => - SpacetimeDB.Internal.ITableView.DoIter(); + global::SpacetimeDB.Internal.ITableView.DoIter(); public global::BTreeViews Insert(global::BTreeViews row) => - SpacetimeDB.Internal.ITableView.DoInsert(row); + global::SpacetimeDB.Internal.ITableView.DoInsert( + row + ); public bool Delete(global::BTreeViews row) => - SpacetimeDB.Internal.ITableView.DoDelete(row); + global::SpacetimeDB.Internal.ITableView.DoDelete( + row + ); internal sealed class IdUniqueIndex : UniqueIndex< @@ -401,9 +428,9 @@ public ulong Delete(Bound Faction) => } public readonly struct MultiTable1 - : SpacetimeDB.Internal.ITableView + : global::SpacetimeDB.Internal.ITableView { - static global::MultiTableRow SpacetimeDB.Internal.ITableView< + static global::MultiTableRow global::SpacetimeDB.Internal.ITableView< MultiTable1, global::MultiTableRow >.ReadGenFields(System.IO.BinaryReader reader, global::MultiTableRow row) @@ -415,7 +442,7 @@ public readonly struct MultiTable1 return row; } - static SpacetimeDB.Internal.RawTableDefV9 SpacetimeDB.Internal.ITableView< + static SpacetimeDB.Internal.RawTableDefV9 global::SpacetimeDB.Internal.ITableView< MultiTable1, global::MultiTableRow >.MakeTableDesc(SpacetimeDB.BSATN.ITypeRegistrar registrar) => @@ -439,14 +466,14 @@ static SpacetimeDB.Internal.RawTableDefV9 SpacetimeDB.Internal.ITableView< ], Constraints: [ - SpacetimeDB.Internal.ITableView< + global::SpacetimeDB.Internal.ITableView< MultiTable1, global::MultiTableRow >.MakeUniqueConstraint(1) ], Sequences: [ - SpacetimeDB.Internal.ITableView< + global::SpacetimeDB.Internal.ITableView< MultiTable1, global::MultiTableRow >.MakeSequence(1) @@ -457,16 +484,28 @@ static SpacetimeDB.Internal.RawTableDefV9 SpacetimeDB.Internal.ITableView< ); public ulong Count => - SpacetimeDB.Internal.ITableView.DoCount(); + global::SpacetimeDB.Internal.ITableView< + MultiTable1, + global::MultiTableRow + >.DoCount(); public IEnumerable Iter() => - SpacetimeDB.Internal.ITableView.DoIter(); + global::SpacetimeDB.Internal.ITableView< + MultiTable1, + global::MultiTableRow + >.DoIter(); public global::MultiTableRow Insert(global::MultiTableRow row) => - SpacetimeDB.Internal.ITableView.DoInsert(row); + global::SpacetimeDB.Internal.ITableView< + MultiTable1, + global::MultiTableRow + >.DoInsert(row); public bool Delete(global::MultiTableRow row) => - SpacetimeDB.Internal.ITableView.DoDelete(row); + global::SpacetimeDB.Internal.ITableView< + MultiTable1, + global::MultiTableRow + >.DoDelete(row); public sealed class FooUniqueIndex : UniqueIndex @@ -523,9 +562,9 @@ public ulong Delete(Bound Name) => } public readonly struct MultiTable2 - : SpacetimeDB.Internal.ITableView + : global::SpacetimeDB.Internal.ITableView { - static global::MultiTableRow SpacetimeDB.Internal.ITableView< + static global::MultiTableRow global::SpacetimeDB.Internal.ITableView< MultiTable2, global::MultiTableRow >.ReadGenFields(System.IO.BinaryReader reader, global::MultiTableRow row) @@ -537,7 +576,7 @@ public readonly struct MultiTable2 return row; } - static SpacetimeDB.Internal.RawTableDefV9 SpacetimeDB.Internal.ITableView< + static SpacetimeDB.Internal.RawTableDefV9 global::SpacetimeDB.Internal.ITableView< MultiTable2, global::MultiTableRow >.MakeTableDesc(SpacetimeDB.BSATN.ITypeRegistrar registrar) => @@ -556,14 +595,14 @@ static SpacetimeDB.Internal.RawTableDefV9 SpacetimeDB.Internal.ITableView< ], Constraints: [ - SpacetimeDB.Internal.ITableView< + global::SpacetimeDB.Internal.ITableView< MultiTable2, global::MultiTableRow >.MakeUniqueConstraint(2) ], Sequences: [ - SpacetimeDB.Internal.ITableView< + global::SpacetimeDB.Internal.ITableView< MultiTable2, global::MultiTableRow >.MakeSequence(1) @@ -574,16 +613,28 @@ static SpacetimeDB.Internal.RawTableDefV9 SpacetimeDB.Internal.ITableView< ); public ulong Count => - SpacetimeDB.Internal.ITableView.DoCount(); + global::SpacetimeDB.Internal.ITableView< + MultiTable2, + global::MultiTableRow + >.DoCount(); public IEnumerable Iter() => - SpacetimeDB.Internal.ITableView.DoIter(); + global::SpacetimeDB.Internal.ITableView< + MultiTable2, + global::MultiTableRow + >.DoIter(); public global::MultiTableRow Insert(global::MultiTableRow row) => - SpacetimeDB.Internal.ITableView.DoInsert(row); + global::SpacetimeDB.Internal.ITableView< + MultiTable2, + global::MultiTableRow + >.DoInsert(row); public bool Delete(global::MultiTableRow row) => - SpacetimeDB.Internal.ITableView.DoDelete(row); + global::SpacetimeDB.Internal.ITableView< + MultiTable2, + global::MultiTableRow + >.DoDelete(row); public sealed class BarUniqueIndex : UniqueIndex @@ -604,9 +655,9 @@ internal BarUniqueIndex() } public readonly struct PrivateTable - : SpacetimeDB.Internal.ITableView + : global::SpacetimeDB.Internal.ITableView { - static global::PrivateTable SpacetimeDB.Internal.ITableView< + static global::PrivateTable global::SpacetimeDB.Internal.ITableView< PrivateTable, global::PrivateTable >.ReadGenFields(System.IO.BinaryReader reader, global::PrivateTable row) @@ -614,7 +665,7 @@ public readonly struct PrivateTable return row; } - static SpacetimeDB.Internal.RawTableDefV9 SpacetimeDB.Internal.ITableView< + static SpacetimeDB.Internal.RawTableDefV9 global::SpacetimeDB.Internal.ITableView< PrivateTable, global::PrivateTable >.MakeTableDesc(SpacetimeDB.BSATN.ITypeRegistrar registrar) => @@ -632,22 +683,34 @@ static SpacetimeDB.Internal.RawTableDefV9 SpacetimeDB.Internal.ITableView< ); public ulong Count => - SpacetimeDB.Internal.ITableView.DoCount(); + global::SpacetimeDB.Internal.ITableView< + PrivateTable, + global::PrivateTable + >.DoCount(); public IEnumerable Iter() => - SpacetimeDB.Internal.ITableView.DoIter(); + global::SpacetimeDB.Internal.ITableView< + PrivateTable, + global::PrivateTable + >.DoIter(); public global::PrivateTable Insert(global::PrivateTable row) => - SpacetimeDB.Internal.ITableView.DoInsert(row); + global::SpacetimeDB.Internal.ITableView< + PrivateTable, + global::PrivateTable + >.DoInsert(row); public bool Delete(global::PrivateTable row) => - SpacetimeDB.Internal.ITableView.DoDelete(row); + global::SpacetimeDB.Internal.ITableView< + PrivateTable, + global::PrivateTable + >.DoDelete(row); } public readonly struct PublicTable - : SpacetimeDB.Internal.ITableView + : global::SpacetimeDB.Internal.ITableView { - static global::PublicTable SpacetimeDB.Internal.ITableView< + static global::PublicTable global::SpacetimeDB.Internal.ITableView< PublicTable, global::PublicTable >.ReadGenFields(System.IO.BinaryReader reader, global::PublicTable row) @@ -659,7 +722,7 @@ public readonly struct PublicTable return row; } - static SpacetimeDB.Internal.RawTableDefV9 SpacetimeDB.Internal.ITableView< + static SpacetimeDB.Internal.RawTableDefV9 global::SpacetimeDB.Internal.ITableView< PublicTable, global::PublicTable >.MakeTableDesc(SpacetimeDB.BSATN.ITypeRegistrar registrar) => @@ -678,14 +741,14 @@ static SpacetimeDB.Internal.RawTableDefV9 SpacetimeDB.Internal.ITableView< ], Constraints: [ - SpacetimeDB.Internal.ITableView< + global::SpacetimeDB.Internal.ITableView< PublicTable, global::PublicTable >.MakeUniqueConstraint(0) ], Sequences: [ - SpacetimeDB.Internal.ITableView< + global::SpacetimeDB.Internal.ITableView< PublicTable, global::PublicTable >.MakeSequence(0) @@ -696,16 +759,20 @@ static SpacetimeDB.Internal.RawTableDefV9 SpacetimeDB.Internal.ITableView< ); public ulong Count => - SpacetimeDB.Internal.ITableView.DoCount(); + global::SpacetimeDB.Internal.ITableView.DoCount(); public IEnumerable Iter() => - SpacetimeDB.Internal.ITableView.DoIter(); + global::SpacetimeDB.Internal.ITableView.DoIter(); public global::PublicTable Insert(global::PublicTable row) => - SpacetimeDB.Internal.ITableView.DoInsert(row); + global::SpacetimeDB.Internal.ITableView.DoInsert( + row + ); public bool Delete(global::PublicTable row) => - SpacetimeDB.Internal.ITableView.DoDelete(row); + global::SpacetimeDB.Internal.ITableView.DoDelete( + row + ); public sealed class IdUniqueIndex : UniqueIndex @@ -726,12 +793,12 @@ internal IdUniqueIndex() } internal readonly struct RegressionMultipleUniqueIndexesHadSameName - : SpacetimeDB.Internal.ITableView< + : global::SpacetimeDB.Internal.ITableView< RegressionMultipleUniqueIndexesHadSameName, global::RegressionMultipleUniqueIndexesHadSameName > { - static global::RegressionMultipleUniqueIndexesHadSameName SpacetimeDB.Internal.ITableView< + static global::RegressionMultipleUniqueIndexesHadSameName global::SpacetimeDB.Internal.ITableView< RegressionMultipleUniqueIndexesHadSameName, global::RegressionMultipleUniqueIndexesHadSameName >.ReadGenFields( @@ -742,7 +809,7 @@ internal readonly struct RegressionMultipleUniqueIndexesHadSameName return row; } - static SpacetimeDB.Internal.RawTableDefV9 SpacetimeDB.Internal.ITableView< + static SpacetimeDB.Internal.RawTableDefV9 global::SpacetimeDB.Internal.ITableView< RegressionMultipleUniqueIndexesHadSameName, global::RegressionMultipleUniqueIndexesHadSameName >.MakeTableDesc(SpacetimeDB.BSATN.ITypeRegistrar registrar) => @@ -768,11 +835,11 @@ static SpacetimeDB.Internal.RawTableDefV9 SpacetimeDB.Internal.ITableView< ], Constraints: [ - SpacetimeDB.Internal.ITableView< + global::SpacetimeDB.Internal.ITableView< RegressionMultipleUniqueIndexesHadSameName, global::RegressionMultipleUniqueIndexesHadSameName >.MakeUniqueConstraint(0), - SpacetimeDB.Internal.ITableView< + global::SpacetimeDB.Internal.ITableView< RegressionMultipleUniqueIndexesHadSameName, global::RegressionMultipleUniqueIndexesHadSameName >.MakeUniqueConstraint(1) @@ -784,13 +851,13 @@ static SpacetimeDB.Internal.RawTableDefV9 SpacetimeDB.Internal.ITableView< ); public ulong Count => - SpacetimeDB.Internal.ITableView< + global::SpacetimeDB.Internal.ITableView< RegressionMultipleUniqueIndexesHadSameName, global::RegressionMultipleUniqueIndexesHadSameName >.DoCount(); public IEnumerable Iter() => - SpacetimeDB.Internal.ITableView< + global::SpacetimeDB.Internal.ITableView< RegressionMultipleUniqueIndexesHadSameName, global::RegressionMultipleUniqueIndexesHadSameName >.DoIter(); @@ -798,13 +865,13 @@ static SpacetimeDB.Internal.RawTableDefV9 SpacetimeDB.Internal.ITableView< public global::RegressionMultipleUniqueIndexesHadSameName Insert( global::RegressionMultipleUniqueIndexesHadSameName row ) => - SpacetimeDB.Internal.ITableView< + global::SpacetimeDB.Internal.ITableView< RegressionMultipleUniqueIndexesHadSameName, global::RegressionMultipleUniqueIndexesHadSameName >.DoInsert(row); public bool Delete(global::RegressionMultipleUniqueIndexesHadSameName row) => - SpacetimeDB.Internal.ITableView< + global::SpacetimeDB.Internal.ITableView< RegressionMultipleUniqueIndexesHadSameName, global::RegressionMultipleUniqueIndexesHadSameName >.DoDelete(row); @@ -863,9 +930,12 @@ internal Unique2UniqueIndex() } public readonly struct SendMessageTimer - : SpacetimeDB.Internal.ITableView + : global::SpacetimeDB.Internal.ITableView< + SendMessageTimer, + global::Timers.SendMessageTimer + > { - static global::Timers.SendMessageTimer SpacetimeDB.Internal.ITableView< + static global::Timers.SendMessageTimer global::SpacetimeDB.Internal.ITableView< SendMessageTimer, global::Timers.SendMessageTimer >.ReadGenFields(System.IO.BinaryReader reader, global::Timers.SendMessageTimer row) @@ -879,7 +949,7 @@ public readonly struct SendMessageTimer return row; } - static SpacetimeDB.Internal.RawTableDefV9 SpacetimeDB.Internal.ITableView< + static SpacetimeDB.Internal.RawTableDefV9 global::SpacetimeDB.Internal.ITableView< SendMessageTimer, global::Timers.SendMessageTimer >.MakeTableDesc(SpacetimeDB.BSATN.ITypeRegistrar registrar) => @@ -900,19 +970,19 @@ static SpacetimeDB.Internal.RawTableDefV9 SpacetimeDB.Internal.ITableView< ], Constraints: [ - SpacetimeDB.Internal.ITableView< + global::SpacetimeDB.Internal.ITableView< SendMessageTimer, global::Timers.SendMessageTimer >.MakeUniqueConstraint(0) ], Sequences: [ - SpacetimeDB.Internal.ITableView< + global::SpacetimeDB.Internal.ITableView< SendMessageTimer, global::Timers.SendMessageTimer >.MakeSequence(0) ], - Schedule: SpacetimeDB.Internal.ITableView< + Schedule: global::SpacetimeDB.Internal.ITableView< SendMessageTimer, global::Timers.SendMessageTimer >.MakeSchedule("SendScheduledMessage", 1), @@ -921,25 +991,25 @@ static SpacetimeDB.Internal.RawTableDefV9 SpacetimeDB.Internal.ITableView< ); public ulong Count => - SpacetimeDB.Internal.ITableView< + global::SpacetimeDB.Internal.ITableView< SendMessageTimer, global::Timers.SendMessageTimer >.DoCount(); public IEnumerable Iter() => - SpacetimeDB.Internal.ITableView< + global::SpacetimeDB.Internal.ITableView< SendMessageTimer, global::Timers.SendMessageTimer >.DoIter(); public global::Timers.SendMessageTimer Insert(global::Timers.SendMessageTimer row) => - SpacetimeDB.Internal.ITableView< + global::SpacetimeDB.Internal.ITableView< SendMessageTimer, global::Timers.SendMessageTimer >.DoInsert(row); public bool Delete(global::Timers.SendMessageTimer row) => - SpacetimeDB.Internal.ITableView< + global::SpacetimeDB.Internal.ITableView< SendMessageTimer, global::Timers.SendMessageTimer >.DoDelete(row); @@ -972,15 +1042,481 @@ internal ScheduledIdUniqueIndex() public sealed class Local { - internal Internal.TableHandles.BTreeMultiColumn BTreeMultiColumn => new(); - internal Internal.TableHandles.BTreeViews BTreeViews => new(); - public Internal.TableHandles.MultiTable1 MultiTable1 => new(); - public Internal.TableHandles.MultiTable2 MultiTable2 => new(); - public Internal.TableHandles.PrivateTable PrivateTable => new(); - public Internal.TableHandles.PublicTable PublicTable => new(); - internal Internal.TableHandles.RegressionMultipleUniqueIndexesHadSameName RegressionMultipleUniqueIndexesHadSameName => + internal global::SpacetimeDB.Internal.TableHandles.BTreeMultiColumn BTreeMultiColumn => + new(); + internal global::SpacetimeDB.Internal.TableHandles.BTreeViews BTreeViews => new(); + public global::SpacetimeDB.Internal.TableHandles.MultiTable1 MultiTable1 => new(); + public global::SpacetimeDB.Internal.TableHandles.MultiTable2 MultiTable2 => new(); + public global::SpacetimeDB.Internal.TableHandles.PrivateTable PrivateTable => new(); + public global::SpacetimeDB.Internal.TableHandles.PublicTable PublicTable => new(); + internal global::SpacetimeDB.Internal.TableHandles.RegressionMultipleUniqueIndexesHadSameName RegressionMultipleUniqueIndexesHadSameName => + new(); + public global::SpacetimeDB.Internal.TableHandles.SendMessageTimer SendMessageTimer => new(); + } +} + +sealed class FindPublicTableByIdentityViewDispatcher : global::SpacetimeDB.Internal.IAnonymousView +{ + private static readonly SpacetimeDB.BSATN.ValueOption returnRW = + new(); + + public SpacetimeDB.Internal.RawViewDefV9 MakeAnonymousViewDef( + SpacetimeDB.BSATN.ITypeRegistrar registrar + ) => + new global::SpacetimeDB.Internal.RawViewDefV9( + Name: "FindPublicTableByIdentity", + Index: 0, + IsPublic: true, + IsAnonymous: true, + Params: [], + ReturnType: new SpacetimeDB.BSATN.ValueOption< + PublicTable, + PublicTable.BSATN + >().GetAlgebraicType(registrar) + ); + + public byte[] Invoke( + System.IO.BinaryReader reader, + global::SpacetimeDB.Internal.IAnonymousViewContext ctx + ) + { + try + { + var returnValue = Module.FindPublicTableByIdentity( + (SpacetimeDB.AnonymousViewContext)ctx + ); + using var output = new System.IO.MemoryStream(); + using var writer = new System.IO.BinaryWriter(output); + returnRW.Write(writer, returnValue); + return output.ToArray(); + } + catch (System.Exception e) + { + global::SpacetimeDB.Log.Error("Error in view 'FindPublicTableByIdentity': " + e); + throw; + } + } +} + +sealed class PublicTableByIdentityViewDispatcher : global::SpacetimeDB.Internal.IView +{ + private static readonly SpacetimeDB.BSATN.ValueOption returnRW = + new(); + + public SpacetimeDB.Internal.RawViewDefV9 MakeViewDef( + SpacetimeDB.BSATN.ITypeRegistrar registrar + ) => + new global::SpacetimeDB.Internal.RawViewDefV9( + Name: "PublicTableByIdentity", + Index: 0, + IsPublic: true, + IsAnonymous: false, + Params: [], + ReturnType: new SpacetimeDB.BSATN.ValueOption< + PublicTable, + PublicTable.BSATN + >().GetAlgebraicType(registrar) + ); + + public byte[] Invoke( + System.IO.BinaryReader reader, + global::SpacetimeDB.Internal.IViewContext ctx + ) + { + try + { + var returnValue = Module.PublicTableByIdentity((SpacetimeDB.ViewContext)ctx); + using var output = new System.IO.MemoryStream(); + using var writer = new System.IO.BinaryWriter(output); + returnRW.Write(writer, returnValue); + return output.ToArray(); + } + catch (System.Exception e) + { + global::SpacetimeDB.Log.Error("Error in view 'PublicTableByIdentity': " + e); + throw; + } + } +} + +namespace SpacetimeDB.Internal.ViewHandles +{ + internal sealed class BTreeMultiColumnReadOnly + : global::SpacetimeDB.Internal.ReadOnlyTableView + { + internal BTreeMultiColumnReadOnly() + : base("BTreeMultiColumn") { } + + public ulong Count => DoCount(); + + public sealed class LocationIndex + : global::SpacetimeDB.Internal.ReadOnlyIndexBase + { + internal LocationIndex() + : base("BTreeMultiColumn_X_Y_Z_idx_btree") { } + + public IEnumerable Filter(uint X) => + DoFilter( + new global::SpacetimeDB.Internal.BTreeIndexBounds( + X + ) + ); + + public IEnumerable Filter( + global::SpacetimeDB.Internal.Bound X + ) => + DoFilter( + new global::SpacetimeDB.Internal.BTreeIndexBounds( + X + ) + ); + + public IEnumerable Filter((uint X, uint Y) f) => + DoFilter( + new global::SpacetimeDB.Internal.BTreeIndexBounds< + uint, + SpacetimeDB.BSATN.U32, + uint, + SpacetimeDB.BSATN.U32 + >(f) + ); + + public IEnumerable Filter( + (uint X, global::SpacetimeDB.Internal.Bound Y) f + ) => + DoFilter( + new global::SpacetimeDB.Internal.BTreeIndexBounds< + uint, + SpacetimeDB.BSATN.U32, + uint, + SpacetimeDB.BSATN.U32 + >(f) + ); + + public IEnumerable Filter((uint X, uint Y, uint Z) f) => + DoFilter( + new global::SpacetimeDB.Internal.BTreeIndexBounds< + uint, + SpacetimeDB.BSATN.U32, + uint, + SpacetimeDB.BSATN.U32, + uint, + SpacetimeDB.BSATN.U32 + >(f) + ); + + public IEnumerable Filter( + (uint X, uint Y, global::SpacetimeDB.Internal.Bound Z) f + ) => + DoFilter( + new global::SpacetimeDB.Internal.BTreeIndexBounds< + uint, + SpacetimeDB.BSATN.U32, + uint, + SpacetimeDB.BSATN.U32, + uint, + SpacetimeDB.BSATN.U32 + >(f) + ); + } + + internal LocationIndex Location => new(); + } + + internal sealed class BTreeViewsReadOnly + : global::SpacetimeDB.Internal.ReadOnlyTableView + { + internal BTreeViewsReadOnly() + : base("BTreeViews") { } + + public ulong Count => DoCount(); + + public sealed class IdIndex + : global::SpacetimeDB.Internal.ReadOnlyUniqueIndex< + global::SpacetimeDB.Internal.ViewHandles.BTreeViewsReadOnly, + global::BTreeViews, + SpacetimeDB.Identity, + SpacetimeDB.Identity.BSATN + > + { + internal IdIndex() + : base("BTreeViews_Id_idx_btree") { } + + public global::BTreeViews? Find(SpacetimeDB.Identity key) => FindSingle(key); + } + + public IdIndex Id => new(); + + public sealed class LocationIndex + : global::SpacetimeDB.Internal.ReadOnlyIndexBase + { + internal LocationIndex() + : base("BTreeViews_X_Y_idx_btree") { } + + public IEnumerable Filter(uint X) => + DoFilter( + new global::SpacetimeDB.Internal.BTreeIndexBounds( + X + ) + ); + + public IEnumerable Filter( + global::SpacetimeDB.Internal.Bound X + ) => + DoFilter( + new global::SpacetimeDB.Internal.BTreeIndexBounds( + X + ) + ); + + public IEnumerable Filter((uint X, uint Y) f) => + DoFilter( + new global::SpacetimeDB.Internal.BTreeIndexBounds< + uint, + SpacetimeDB.BSATN.U32, + uint, + SpacetimeDB.BSATN.U32 + >(f) + ); + + public IEnumerable Filter( + (uint X, global::SpacetimeDB.Internal.Bound Y) f + ) => + DoFilter( + new global::SpacetimeDB.Internal.BTreeIndexBounds< + uint, + SpacetimeDB.BSATN.U32, + uint, + SpacetimeDB.BSATN.U32 + >(f) + ); + } + + internal LocationIndex Location => new(); + + public sealed class FactionIndex + : global::SpacetimeDB.Internal.ReadOnlyIndexBase + { + internal FactionIndex() + : base("BTreeViews_Faction_idx_btree") { } + + public IEnumerable Filter(string Faction) => + DoFilter( + new global::SpacetimeDB.Internal.BTreeIndexBounds< + string, + SpacetimeDB.BSATN.String + >(Faction) + ); + + public IEnumerable Filter( + global::SpacetimeDB.Internal.Bound Faction + ) => + DoFilter( + new global::SpacetimeDB.Internal.BTreeIndexBounds< + string, + SpacetimeDB.BSATN.String + >(Faction) + ); + } + + internal FactionIndex Faction => new(); + } + + public sealed class MultiTable1ReadOnly + : global::SpacetimeDB.Internal.ReadOnlyTableView + { + internal MultiTable1ReadOnly() + : base("MultiTable1") { } + + public ulong Count => DoCount(); + + public sealed class FooIndex + : global::SpacetimeDB.Internal.ReadOnlyUniqueIndex< + global::SpacetimeDB.Internal.ViewHandles.MultiTable1ReadOnly, + global::MultiTableRow, + uint, + SpacetimeDB.BSATN.U32 + > + { + internal FooIndex() + : base("MultiTable1_Foo_idx_btree") { } + + public global::MultiTableRow? Find(uint key) => FindSingle(key); + } + + public FooIndex Foo => new(); + + public sealed class NameIndex + : global::SpacetimeDB.Internal.ReadOnlyIndexBase + { + internal NameIndex() + : base("MultiTable1_Name_idx_btree") { } + + public IEnumerable Filter(string Name) => + DoFilter( + new global::SpacetimeDB.Internal.BTreeIndexBounds< + string, + SpacetimeDB.BSATN.String + >(Name) + ); + + public IEnumerable Filter( + global::SpacetimeDB.Internal.Bound Name + ) => + DoFilter( + new global::SpacetimeDB.Internal.BTreeIndexBounds< + string, + SpacetimeDB.BSATN.String + >(Name) + ); + } + + public NameIndex Name => new(); + } + + public sealed class MultiTable2ReadOnly + : global::SpacetimeDB.Internal.ReadOnlyTableView + { + internal MultiTable2ReadOnly() + : base("MultiTable2") { } + + public ulong Count => DoCount(); + + public sealed class BarIndex + : global::SpacetimeDB.Internal.ReadOnlyUniqueIndex< + global::SpacetimeDB.Internal.ViewHandles.MultiTable2ReadOnly, + global::MultiTableRow, + uint, + SpacetimeDB.BSATN.U32 + > + { + internal BarIndex() + : base("MultiTable2_Bar_idx_btree") { } + + public global::MultiTableRow? Find(uint key) => FindSingle(key); + } + + public BarIndex Bar => new(); + } + + public sealed class PrivateTableReadOnly + : global::SpacetimeDB.Internal.ReadOnlyTableView + { + internal PrivateTableReadOnly() + : base("PrivateTable") { } + + public ulong Count => DoCount(); + } + + public sealed class PublicTableReadOnly + : global::SpacetimeDB.Internal.ReadOnlyTableView + { + internal PublicTableReadOnly() + : base("PublicTable") { } + + public ulong Count => DoCount(); + + public sealed class IdIndex + : global::SpacetimeDB.Internal.ReadOnlyUniqueIndex< + global::SpacetimeDB.Internal.ViewHandles.PublicTableReadOnly, + global::PublicTable, + int, + SpacetimeDB.BSATN.I32 + > + { + internal IdIndex() + : base("PublicTable_Id_idx_btree") { } + + public global::PublicTable? Find(int key) => FindSingle(key); + } + + public IdIndex Id => new(); + } + + internal sealed class RegressionMultipleUniqueIndexesHadSameNameReadOnly + : global::SpacetimeDB.Internal.ReadOnlyTableView + { + internal RegressionMultipleUniqueIndexesHadSameNameReadOnly() + : base("RegressionMultipleUniqueIndexesHadSameName") { } + + public ulong Count => DoCount(); + + public sealed class Unique1Index + : global::SpacetimeDB.Internal.ReadOnlyUniqueIndex< + global::SpacetimeDB.Internal.ViewHandles.RegressionMultipleUniqueIndexesHadSameNameReadOnly, + global::RegressionMultipleUniqueIndexesHadSameName, + uint, + SpacetimeDB.BSATN.U32 + > + { + internal Unique1Index() + : base("RegressionMultipleUniqueIndexesHadSameName_Unique1_idx_btree") { } + + public global::RegressionMultipleUniqueIndexesHadSameName? Find(uint key) => + FindSingle(key); + } + + public Unique1Index Unique1 => new(); + + public sealed class Unique2Index + : global::SpacetimeDB.Internal.ReadOnlyUniqueIndex< + global::SpacetimeDB.Internal.ViewHandles.RegressionMultipleUniqueIndexesHadSameNameReadOnly, + global::RegressionMultipleUniqueIndexesHadSameName, + uint, + SpacetimeDB.BSATN.U32 + > + { + internal Unique2Index() + : base("RegressionMultipleUniqueIndexesHadSameName_Unique2_idx_btree") { } + + public global::RegressionMultipleUniqueIndexesHadSameName? Find(uint key) => + FindSingle(key); + } + + public Unique2Index Unique2 => new(); + } + + public sealed class SendMessageTimerReadOnly + : global::SpacetimeDB.Internal.ReadOnlyTableView + { + internal SendMessageTimerReadOnly() + : base("SendMessageTimer") { } + + public ulong Count => DoCount(); + + public sealed class ScheduledIdIndex + : global::SpacetimeDB.Internal.ReadOnlyUniqueIndex< + global::SpacetimeDB.Internal.ViewHandles.SendMessageTimerReadOnly, + global::Timers.SendMessageTimer, + ulong, + SpacetimeDB.BSATN.U64 + > + { + internal ScheduledIdIndex() + : base("SendMessageTimer_ScheduledId_idx_btree") { } + + public global::Timers.SendMessageTimer? Find(ulong key) => FindSingle(key); + } + + public ScheduledIdIndex ScheduledId => new(); + } +} + +namespace SpacetimeDB.Internal +{ + public sealed partial class LocalReadOnly + { + internal global::SpacetimeDB.Internal.ViewHandles.BTreeMultiColumnReadOnly BTreeMultiColumn => + new(); + internal global::SpacetimeDB.Internal.ViewHandles.BTreeViewsReadOnly BTreeViews => new(); + public global::SpacetimeDB.Internal.ViewHandles.MultiTable1ReadOnly MultiTable1 => new(); + public global::SpacetimeDB.Internal.ViewHandles.MultiTable2ReadOnly MultiTable2 => new(); + public global::SpacetimeDB.Internal.ViewHandles.PrivateTableReadOnly PrivateTable => new(); + public global::SpacetimeDB.Internal.ViewHandles.PublicTableReadOnly PublicTable => new(); + internal global::SpacetimeDB.Internal.ViewHandles.RegressionMultipleUniqueIndexesHadSameNameReadOnly RegressionMultipleUniqueIndexesHadSameName => + new(); + public global::SpacetimeDB.Internal.ViewHandles.SendMessageTimerReadOnly SendMessageTimer => new(); - public Internal.TableHandles.SendMessageTimer SendMessageTimer => new(); } } @@ -1094,6 +1630,15 @@ public static void Main() (identity, connectionId, random, time) => new SpacetimeDB.ReducerContext(identity, connectionId, random, time) ); + SpacetimeDB.Internal.Module.SetViewContextConstructor( + identity => new SpacetimeDB.ViewContext( + identity, + new SpacetimeDB.Internal.LocalReadOnly() + ) + ); + SpacetimeDB.Internal.Module.SetAnonymousViewContextConstructor( + () => new SpacetimeDB.AnonymousViewContext(new SpacetimeDB.Internal.LocalReadOnly()) + ); var __memoryStream = new MemoryStream(); var __writer = new BinaryWriter(__memoryStream); @@ -1103,6 +1648,8 @@ public static void Main() SpacetimeDB.Internal.Module.RegisterReducer(); SpacetimeDB.Internal.Module.RegisterReducer(); SpacetimeDB.Internal.Module.RegisterReducer(); + SpacetimeDB.Internal.Module.RegisterAnonymousView(); + SpacetimeDB.Internal.Module.RegisterView(); SpacetimeDB.Internal.Module.RegisterTable< global::BTreeMultiColumn, SpacetimeDB.Internal.TableHandles.BTreeMultiColumn @@ -1173,3 +1720,5 @@ SpacetimeDB.Internal.BytesSink error ); #endif } + +#pragma warning restore CS0436 diff --git a/crates/bindings-csharp/Codegen/Diag.cs b/crates/bindings-csharp/Codegen/Diag.cs index 83d3f8afa3f..5b2a6fee9a0 100644 --- a/crates/bindings-csharp/Codegen/Diag.cs +++ b/crates/bindings-csharp/Codegen/Diag.cs @@ -175,4 +175,47 @@ string typeName field => $"Default value for field {field.Name} has invalid format for provided type ", field => field ); + public static readonly ErrorDescriptor ViewContextParam = + new( + group, + "Views must start with ViewContext or AnonymousViewContext", + method => + $"View method {method.Identifier} must have a first parameter of type ViewContext or AnonymousViewContext.", + method => method.ParameterList + ); + + public static readonly ErrorDescriptor ViewMustHaveName = + new( + group, + "Views must have an explicit name.", + method => $"View '{method.Identifier}' must have an explicit name.", + method => method + ); + public static readonly ErrorDescriptor ViewInvalidReturn = + new( + group, + "Views must return Vec or Option", + method => $"View '{method.Identifier}' must return Vec or Option.", + method => method + ); + + // TODO: Remove once Views support Private: Views must be Public currently + public static readonly ErrorDescriptor ViewMustBePublic = + new( + group, + "Views must be public", + method => + $"View '{method.Identifier}' must have Public = true. Views are always public in SpacetimeDB.", + method => method + ); + + // TODO: Remove once Views support arguments: Views must have no arguments beyond the context. + public static readonly ErrorDescriptor ViewArgsUnsupported = + new( + group, + "Views must have no arguments beyond the context.", + method => + $"View '{method.Identifier}' must have no arguments beyond the context. This is a temporary limitation.", + method => method + ); } diff --git a/crates/bindings-csharp/Codegen/Module.cs b/crates/bindings-csharp/Codegen/Module.cs index 023e8cacd2e..d414d9ad106 100644 --- a/crates/bindings-csharp/Codegen/Module.cs +++ b/crates/bindings-csharp/Codegen/Module.cs @@ -70,7 +70,7 @@ record ColumnRef(int Index, string Name); record ColumnDeclaration : MemberDeclaration { public readonly EquatableArray Attrs; - public readonly EquatableArray Indexes; + public readonly EquatableArray Indexes; public readonly bool IsEquatable; public readonly string FullTableName; public readonly int ColumnIndex; @@ -102,8 +102,8 @@ public ColumnDeclaration(string tableName, int index, IFieldSymbol field, DiagRe Indexes = new( field .GetAttributes() - .Where(ViewIndex.CanParse) - .Select(a => new ViewIndex(new ColumnRef(index, field.Name), a, diag)) + .Where(TableIndex.CanParse) + .Select(a => new TableIndex(new ColumnRef(index, field.Name), a, diag)) .ToImmutableArray() ); @@ -199,8 +199,8 @@ or SpecialType.System_Int64 } } - public ColumnAttrs GetAttrs(TableView view) => - CombineColumnAttrs(Attrs.Where(x => x.Table == null || x.Table == view.Name)); + public ColumnAttrs GetAttrs(TableAccessor tableAccessor) => + CombineColumnAttrs(Attrs.Where(x => x.Table == null || x.Table == tableAccessor.Name)); // For the `TableDesc` constructor. public string GenerateColumnDef() => @@ -209,13 +209,13 @@ public string GenerateColumnDef() => record Scheduled(string ReducerName, int ScheduledAtColumn); -record TableView +record TableAccessor { public readonly string Name; public readonly bool IsPublic; public readonly Scheduled? Scheduled; - public TableView(TableDeclaration table, AttributeData data, DiagReporter diag) + public TableAccessor(TableDeclaration table, AttributeData data, DiagReporter diag) { var attr = data.ParseAs(); @@ -255,21 +255,21 @@ attr.Scheduled is { } reducer } } -enum ViewIndexType +enum TableIndexType { BTree, } /// -/// Represents an index on a database table view, used to optimize queries. +/// Represents an index on a database table accessor, used to optimize queries. /// Supports B-tree indexing (and potentially other types in the future). /// -record ViewIndex +record TableIndex { public readonly EquatableArray Columns; public readonly string? Table; public readonly string AccessorName; - public readonly ViewIndexType Type; + public readonly TableIndexType Type; // See: bindings_sys::index_id_from_name for documentation of this format. // Guaranteed not to contain quotes, so does not need to be escaped when embedded in a string. @@ -283,11 +283,11 @@ record ViewIndex /// The columns that make up this index. /// The name of the table this index belongs to, if any. /// The type of index (currently only B-tree is supported). - private ViewIndex( + private TableIndex( string? accessorName, ImmutableArray columns, string? tableName, - ViewIndexType type + TableIndexType type ) { Columns = new(columns); @@ -302,26 +302,26 @@ ViewIndexType type /// Creates a B-tree index on a single column with auto-generated name. /// /// The column to index. - public ViewIndex(ColumnRef col) + public TableIndex(ColumnRef col) : this( null, ImmutableArray.Create(col), null, - ViewIndexType.BTree // this might become hash in the future + TableIndexType.BTree // this might become hash in the future ) { } /// /// Creates an index with the given attribute and columns. /// Used internally by other constructors that parse attributes. /// - private ViewIndex(Index.BTreeAttribute attr, ImmutableArray columns) - : this(attr.Name, columns, attr.Table, ViewIndexType.BTree) { } + private TableIndex(Index.BTreeAttribute attr, ImmutableArray columns) + : this(attr.Name, columns, attr.Table, TableIndexType.BTree) { } /// /// Creates an index from a table declaration and attribute data. /// Validates the index configuration and reports any errors through the diag reporter. /// - private ViewIndex( + private TableIndex( TableDeclaration table, Index.BTreeAttribute attr, AttributeData data, @@ -346,14 +346,14 @@ DiagReporter diag /// /// Creates an index by parsing attribute data from a table declaration. /// - public ViewIndex(TableDeclaration table, AttributeData data, DiagReporter diag) + public TableIndex(TableDeclaration table, AttributeData data, DiagReporter diag) : this(table, data.ParseAs(), data, diag) { } /// /// Creates an index for a single column with attribute data. /// Validates that no additional columns were specified in the attribute. /// - private ViewIndex( + private TableIndex( ColumnRef column, Index.BTreeAttribute attr, AttributeData data, @@ -370,7 +370,7 @@ DiagReporter diag /// /// Creates an index for a single column by parsing attribute data. /// - public ViewIndex(ColumnRef col, AttributeData data, DiagReporter diag) + public TableIndex(ColumnRef col, AttributeData data, DiagReporter diag) : this(col, data.ParseAs(), data, diag) { } // `FullName` and Roslyn have different ways of representing nested types in full names - @@ -396,18 +396,19 @@ public string GenerateIndexDef() => ) """; - public string StandardIndexName(TableView view) => view.Name + StandardNameSuffix; + public string StandardIndexName(TableAccessor tableAccessor) => + tableAccessor.Name + StandardNameSuffix; } /// /// Represents a table declaration in a module. -/// Handles table metadata, views, indexes, and column declarations for code generation. +/// Handles table metadata, accessors, indexes, and column declarations for code generation. /// record TableDeclaration : BaseTypeDeclaration { public readonly Accessibility Visibility; - public readonly EquatableArray Views; - public readonly EquatableArray Indexes; + public readonly EquatableArray TableAccessors; + public readonly EquatableArray Indexes; public int? GetColumnIndex(AttributeData attrContext, string name, DiagReporter diag) { @@ -457,14 +458,14 @@ public TableDeclaration(GeneratorAttributeSyntaxContext context, DiagReporter di container = container.ContainingType; } - Views = new( - context.Attributes.Select(a => new TableView(this, a, diag)).ToImmutableArray() + TableAccessors = new( + context.Attributes.Select(a => new TableAccessor(this, a, diag)).ToImmutableArray() ); Indexes = new( context .TargetSymbol.GetAttributes() - .Where(ViewIndex.CanParse) - .Select(a => new ViewIndex(this, a, diag)) + .Where(TableIndex.CanParse) + .Select(a => new TableIndex(this, a, diag)) .ToImmutableArray() ); } @@ -475,12 +476,12 @@ protected override ColumnDeclaration ConvertMember( DiagReporter diag ) => new(FullName, index, field, diag); - public IEnumerable GenerateViewFilters(TableView view) + public IEnumerable GenerateTableAccessorFilters(TableAccessor tableAccessor) { var vis = SyntaxFacts.GetText(Visibility); var globalName = $"global::{FullName}"; - foreach (var ct in GetConstraints(view, ColumnAttrs.Unique)) + foreach (var ct in GetConstraints(tableAccessor, ColumnAttrs.Unique)) { var f = ct.Col; if (!f.IsEquatable) @@ -489,9 +490,9 @@ public IEnumerable GenerateViewFilters(TableView view) // only produce a lot of noisy typechecking errors. continue; } - var standardIndexName = ct.ToIndex().StandardIndexName(view); + var standardIndexName = ct.ToIndex().StandardIndexName(tableAccessor); yield return $$""" - {{vis}} sealed class {{f.Name}}UniqueIndex : UniqueIndex<{{view.Name}}, {{globalName}}, {{f.Type.Name}}, {{f.Type.BSATNName}}> { + {{vis}} sealed class {{f.Name}}UniqueIndex : UniqueIndex<{{tableAccessor.Name}}, {{globalName}}, {{f.Type.Name}}, {{f.Type.BSATNName}}> { internal {{f.Name}}UniqueIndex() : base("{{standardIndexName}}") {} // Important: don't move this to the base class. // C# generics don't play well with nullable types and can't accept both struct-type-based and class-type-based @@ -503,7 +504,7 @@ public IEnumerable GenerateViewFilters(TableView view) """; } - foreach (var index in GetIndexes(view)) + foreach (var index in GetIndexes(tableAccessor)) { var name = index.AccessorName; @@ -515,7 +516,7 @@ public IEnumerable GenerateViewFilters(TableView view) } var members = index.Columns.Select(c => Members[c.Index]).ToArray(); - var standardIndexName = index.StandardIndexName(view); + var standardIndexName = index.StandardIndexName(tableAccessor); yield return $$""" {{vis}} sealed class {{name}}Index() : SpacetimeDB.Internal.IndexBase<{{globalName}}>("{{standardIndexName}}") { @@ -564,42 +565,145 @@ public ulong Delete({{argsBounds}}) => } } + private IEnumerable GenerateReadOnlyAccessorFilters(TableAccessor tableAccessor) + { + var vis = SyntaxFacts.GetText(Visibility); + var globalName = $"global::{FullName}"; + + foreach (var ct in GetConstraints(tableAccessor, ColumnAttrs.Unique)) + { + var f = ct.Col; + if (!f.IsEquatable) + { + continue; + } + + var standardIndexName = ct.ToIndex().StandardIndexName(tableAccessor); + + yield return $$$""" + public sealed class {{{f.Name}}}Index + : global::SpacetimeDB.Internal.ReadOnlyUniqueIndex< + global::SpacetimeDB.Internal.ViewHandles.{{{tableAccessor.Name}}}ReadOnly, + {{{globalName}}}, + {{{f.Type.Name}}}, + {{{f.Type.BSATNName}}}> + { + internal {{{f.Name}}}Index() : base("{{{standardIndexName}}}") { } + + public {{{globalName}}}? Find({{{f.Type.Name}}} key) => FindSingle(key); + } + + public {{{f.Name}}}Index {{{f.Name}}} => new(); + """; + } + + foreach (var index in GetIndexes(tableAccessor)) + { + if (string.IsNullOrEmpty(index.AccessorName)) + { + continue; + } + + var members = index.Columns.Select(c => Members[c.Index]).ToArray(); + var standardIndexName = index.StandardIndexName(tableAccessor); + var name = index.AccessorName; + + var blocks = new List + { + $$$""" + public sealed class {{{name}}}Index + : global::SpacetimeDB.Internal.ReadOnlyIndexBase<{{{globalName}}}> + { + internal {{{name}}}Index() : base("{{{standardIndexName}}}") {} + """, + }; + + for (var n = 0; n < members.Length; n++) + { + var declaringMembers = members.Take(n + 1).ToArray(); + var types = string.Join( + ", ", + declaringMembers.Select(m => $"{m.Type.Name}, {m.Type.BSATNName}") + ); + var scalarArgs = string.Join( + ", ", + declaringMembers.Select(m => $"{m.Type.Name} {m.Name}") + ); + var boundsArgs = string.Join( + ", ", + declaringMembers + .Take(n) + .Select(m => $"{m.Type.Name} {m.Name}") + .Append( + $"global::SpacetimeDB.Internal.Bound<{declaringMembers[^1].Type.Name}> {declaringMembers[^1].Name}" + ) + ); + + var ctorArg = n == 0 ? declaringMembers[0].Name : "f"; + + if (n > 0) + { + scalarArgs = $"({scalarArgs}) f"; + boundsArgs = $"({boundsArgs}) f"; + } + + blocks.Add( + $$$""" + public IEnumerable<{{{globalName}}}> Filter({{{scalarArgs}}}) => + DoFilter(new global::SpacetimeDB.Internal.BTreeIndexBounds<{{{types}}}>({{{ctorArg}}})); + + public IEnumerable<{{{globalName}}}> Filter({{{boundsArgs}}}) => + DoFilter(new global::SpacetimeDB.Internal.BTreeIndexBounds<{{{types}}}>({{{ctorArg}}})); + """ + ); + } + + blocks.Add($"}}\n{vis} {name}Index {name} => new();"); + yield return string.Join("\n", blocks); + } + } + /// - /// Represents a generated view for a table, providing different access patterns + /// Represents a generated accessor for a table, providing different access patterns /// and visibility levels for the underlying table data. /// - /// Name of the generated view type + /// Name of the generated accessor type /// Fully qualified name of the table type - /// C# source code for the view implementation - /// C# property getter for accessing the view - public record struct View(string viewName, string tableName, string view, string getter); + /// C# source code for the accessor implementation + /// C# property getter for accessing the accessor + public record struct GeneratedTableAccessor( + string tableAccessorName, + string tableName, + string tableAccessor, + string getter + ); /// - /// Generates view implementations for all table views defined in this table declaration. - /// Each view represents a different way to access or filter the table's data. + /// Generates accessor implementations for all table accessors defined in this table declaration. + /// Each accessor represents a different way to access or filter the table's data. /// - /// Collection of View records containing generated code for each view - public IEnumerable GenerateViews() + /// Collection of Accessor records containing generated code for each accessor + public IEnumerable GenerateTableAccessors() { - // Don't try to generate views if this table is a sum type. - // We already emitted a diagnostic, and attempting to generate views will only result in more noisy errors. + // Don't try to generate accessors if this table is a sum type. + // We already emitted a diagnostic, and attempting to generate accessors will only result in more noisy errors. if (Kind is TypeKind.Sum) { yield break; } - foreach (var v in Views) + foreach (var v in TableAccessors) { var autoIncFields = Members.Where(m => m.GetAttrs(v).HasFlag(ColumnAttrs.AutoInc)); var globalName = $"global::{FullName}"; - var iTable = $"SpacetimeDB.Internal.ITableView<{v.Name}, {globalName}>"; + var iTable = $"global::SpacetimeDB.Internal.ITableView<{v.Name}, {globalName}>"; yield return new( v.Name, globalName, - $$""" - {{SyntaxFacts.GetText(Visibility)}} readonly struct {{v.Name}} : {{iTable}} { - static {{globalName}} {{iTable}}.ReadGenFields(System.IO.BinaryReader reader, {{globalName}} row) { - {{string.Join( + $$$""" + {{{SyntaxFacts.GetText(Visibility)}}} readonly struct {{{v.Name}}} : {{{iTable}}} { + static {{{globalName}}} {{{iTable}}}.ReadGenFields(System.IO.BinaryReader reader, {{{globalName}}} row) { + {{{string.Join( "\n", autoIncFields.Select(m => $$""" @@ -609,43 +713,82 @@ public IEnumerable GenerateViews() } """ ) - )}} + )}}} return row; } - static SpacetimeDB.Internal.RawTableDefV9 {{iTable}}.MakeTableDesc(SpacetimeDB.BSATN.ITypeRegistrar registrar) => new ( - Name: nameof({{v.Name}}), - ProductTypeRef: (uint) new {{globalName}}.BSATN().GetAlgebraicType(registrar).Ref_, - PrimaryKey: [{{GetPrimaryKey(v)?.ToString() ?? ""}}], + static SpacetimeDB.Internal.RawTableDefV9 {{{iTable}}}.MakeTableDesc(SpacetimeDB.BSATN.ITypeRegistrar registrar) => new ( + Name: nameof({{{v.Name}}}), + ProductTypeRef: (uint) new {{{globalName}}}.BSATN().GetAlgebraicType(registrar).Ref_, + PrimaryKey: [{{{GetPrimaryKey(v)?.ToString() ?? ""}}}], Indexes: [ - {{string.Join( + {{{string.Join( ",\n", GetConstraints(v, ColumnAttrs.Unique) .Select(c => c.ToIndex()) .Concat(GetIndexes(v)) .Select(b => b.GenerateIndexDef()) - )}} + )}}} ], - Constraints: {{GenConstraintList(v, ColumnAttrs.Unique, $"{iTable}.MakeUniqueConstraint")}}, - Sequences: {{GenConstraintList(v, ColumnAttrs.AutoInc, $"{iTable}.MakeSequence")}}, - Schedule: {{( + Constraints: {{{GenConstraintList(v, ColumnAttrs.Unique, $"{iTable}.MakeUniqueConstraint")}}}, + Sequences: {{{GenConstraintList(v, ColumnAttrs.AutoInc, $"{iTable}.MakeSequence")}}}, + Schedule: {{{( v.Scheduled is { } scheduled ? $"{iTable}.MakeSchedule(\"{scheduled.ReducerName}\", {scheduled.ScheduledAtColumn})" : "null" - )}}, + )}}}, TableType: SpacetimeDB.Internal.TableType.User, - TableAccess: SpacetimeDB.Internal.TableAccess.{{(v.IsPublic ? "Public" : "Private")}} + TableAccess: SpacetimeDB.Internal.TableAccess.{{{(v.IsPublic ? "Public" : "Private")}}} ); - public ulong Count => {{iTable}}.DoCount(); - public IEnumerable<{{globalName}}> Iter() => {{iTable}}.DoIter(); - public {{globalName}} Insert({{globalName}} row) => {{iTable}}.DoInsert(row); - public bool Delete({{globalName}} row) => {{iTable}}.DoDelete(row); + public ulong Count => {{{iTable}}}.DoCount(); + public IEnumerable<{{{globalName}}}> Iter() => {{{iTable}}}.DoIter(); + public {{{globalName}}} Insert({{{globalName}}} row) => {{{iTable}}}.DoInsert(row); + public bool Delete({{{globalName}}} row) => {{{iTable}}}.DoDelete(row); - {{string.Join("\n", GenerateViewFilters(v))}} + {{{string.Join("\n", GenerateTableAccessorFilters(v))}}} } """, - $"{SyntaxFacts.GetText(Visibility)} Internal.TableHandles.{v.Name} {v.Name} => new();" + $"{SyntaxFacts.GetText(Visibility)} global::SpacetimeDB.Internal.TableHandles.{v.Name} {v.Name} => new();" + ); + } + } + + public record struct GeneratedReadOnlyAccessor( + string tableAccessorName, + string tableName, + string readOnlyAccessor, + string readOnlyGetter + ); + + public IEnumerable GenerateReadOnlyAccessors() + { + if (Kind is TypeKind.Sum) + { + yield break; + } + + foreach (var accessor in TableAccessors) + { + var globalName = $"global::{FullName}"; + + var readOnlyIndexDecls = string.Join("\n", GenerateReadOnlyAccessorFilters(accessor)); + var visibility = SyntaxFacts.GetText(Visibility); + yield return new( + accessor.Name, + globalName, + $$$""" + {{{visibility}}} sealed class {{{accessor.Name}}}ReadOnly + : global::SpacetimeDB.Internal.ReadOnlyTableView<{{{globalName}}}> + { + internal {{{accessor.Name}}}ReadOnly() : base("{{{accessor.Name}}}") { } + + public ulong Count => DoCount(); + + {{{readOnlyIndexDecls}}} + } + """, + $"{visibility} global::SpacetimeDB.Internal.ViewHandles.{accessor.Name}ReadOnly {accessor.Name} => new();" ); } } @@ -676,16 +819,16 @@ public IEnumerable GenerateDefaultValues() yield break; } - foreach (var view in Views) + foreach (var tableAccessor in TableAccessors) { var members = string.Join(", ", Members.Select(m => m.Name)); var fieldsWithDefaultValues = Members.Where(m => - m.GetAttrs(view).HasFlag(ColumnAttrs.Default) + m.GetAttrs(tableAccessor).HasFlag(ColumnAttrs.Default) ); var defaultValueAttributes = string.Join( ", ", Members - .Where(m => m.GetAttrs(view).HasFlag(ColumnAttrs.Default)) + .Where(m => m.GetAttrs(tableAccessor).HasFlag(ColumnAttrs.Default)) .Select(m => m.Attrs.FirstOrDefault(a => a.Mask == ColumnAttrs.Default)) ); @@ -702,7 +845,7 @@ public IEnumerable GenerateDefaultValues() if (fieldsWithDefaultValue.Type.BSATNName.StartsWith("SpacetimeDB.BSATN.Enum")) { yield return new FieldDefaultValue( - view.Name, + tableAccessor.Name, fieldsWithDefaultValue.ColumnIndex.ToString(), $"({fieldsWithDefaultValue.Type.Name}){fieldsWithDefaultValue.ColumnDefaultValue}", fieldsWithDefaultValue.Type.BSATNName @@ -711,7 +854,7 @@ public IEnumerable GenerateDefaultValues() else { yield return new FieldDefaultValue( - view.Name, + tableAccessor.Name, fieldsWithDefaultValue.ColumnIndex.ToString(), fieldsWithDefaultValue.ColumnDefaultValue, fieldsWithDefaultValue.Type.BSATNName @@ -724,28 +867,28 @@ public IEnumerable GenerateDefaultValues() public record Constraint(ColumnDeclaration Col, int Pos, ColumnAttrs Attr) { - public ViewIndex ToIndex() => new(new ColumnRef(Pos, Col.Name)); + public TableIndex ToIndex() => new(new ColumnRef(Pos, Col.Name)); } public IEnumerable GetConstraints( - TableView view, + TableAccessor tableAccessor, ColumnAttrs filterByAttr = ~ColumnAttrs.UnSet ) => Members // Important: the position must be stored here, before filtering. - .Select((col, pos) => new Constraint(col, pos, col.GetAttrs(view))) + .Select((col, pos) => new Constraint(col, pos, col.GetAttrs(tableAccessor))) .Where(c => c.Attr.HasFlag(filterByAttr)); - public IEnumerable GetIndexes(TableView view) => + public IEnumerable GetIndexes(TableAccessor tableAccessor) => Indexes .Concat(Members.SelectMany(m => m.Indexes)) - .Where(i => i.Table == null || i.Table == view.Name); + .Where(i => i.Table == null || i.Table == tableAccessor.Name); // Reimplementation of V8 -> V9 constraint conversion in Rust. // See https://github.com/clockworklabs/SpacetimeDB/blob/13a800e9f88cbe885b98eab9e45b0fcfd3ab7014/crates/schema/src/def/validate/v8.rs#L74-L78 // and https://github.com/clockworklabs/SpacetimeDB/blob/13a800e9f88cbe885b98eab9e45b0fcfd3ab7014/crates/lib/src/db/raw_def/v8.rs#L460-L510 private string GenConstraintList( - TableView view, + TableAccessor tableAccessor, ColumnAttrs filterByAttr, string makeConstraintFn ) => @@ -753,14 +896,173 @@ string makeConstraintFn [ {{string.Join( ",\n", - GetConstraints(view, filterByAttr) + GetConstraints(tableAccessor, filterByAttr) .Select(pair => $"{makeConstraintFn}({pair.Pos})") )}} ] """; - internal int? GetPrimaryKey(TableView view) => - GetConstraints(view, ColumnAttrs.PrimaryKey).Select(c => (int?)c.Pos).SingleOrDefault(); + internal int? GetPrimaryKey(TableAccessor tableAccessor) => + GetConstraints(tableAccessor, ColumnAttrs.PrimaryKey) + .Select(c => (int?)c.Pos) + .SingleOrDefault(); +} + +/// +/// Represents a view method declaration in a module. +/// +record ViewDeclaration +{ + public readonly string Name; + public readonly string FullName; + public readonly bool IsAnonymous; + public readonly bool IsPublic; + public readonly TypeUse ReturnType; + public readonly EquatableArray Parameters; + public readonly Scope Scope; + + public static uint ViewIndexCounter = 0; + + public static uint GetNextViewIndex() => ViewIndexCounter++; + + public static uint AnonViewIndexCounter = 0; + + public static uint GetNextAnonViewIndex() => AnonViewIndexCounter++; + + public ViewDeclaration(GeneratorAttributeSyntaxContext context, DiagReporter diag) + { + var methodSyntax = (MethodDeclarationSyntax)context.TargetNode; + var method = (IMethodSymbol)context.TargetSymbol; + var attr = context.Attributes.Single().ParseAs(); + var hasContextParam = method.Parameters.Length > 0; + var firstParamType = hasContextParam ? method.Parameters[0].Type : null; + var isAnonymousContext = firstParamType?.Name == "AnonymousViewContext"; + var hasArguments = method.Parameters.Length > 1; + + if (string.IsNullOrEmpty(attr.Name)) + { + diag.Report(ErrorDescriptor.ViewMustHaveName, methodSyntax); + } + // TODO: Remove once Views support Private: Views must be Public currently + if (!attr.Public) + { + diag.Report(ErrorDescriptor.ViewMustBePublic, methodSyntax); + } + if (hasArguments) + { + diag.Report(ErrorDescriptor.ViewArgsUnsupported, methodSyntax); + } + + Name = method.Name; + FullName = SymbolToName(method); + IsPublic = attr.Public; + IsAnonymous = isAnonymousContext; + ReturnType = TypeUse.Parse(method, method.ReturnType, diag); + Scope = new Scope(methodSyntax.Parent as MemberDeclarationSyntax); + + if (method.Parameters.Length == 0) + { + diag.Report(ErrorDescriptor.ViewContextParam, methodSyntax); + } + else if ( + method.Parameters[0].Type + is not INamedTypeSymbol { Name: "ViewContext" or "AnonymousViewContext" } + ) + { + diag.Report(ErrorDescriptor.ViewContextParam, methodSyntax); + } + + // Validate return type: must be Option or Vec + if ( + !ReturnType.BSATNName.Contains("SpacetimeDB.BSATN.ValueOption") + && !ReturnType.BSATNName.Contains("SpacetimeDB.BSATN.List") + ) + { + diag.Report(ErrorDescriptor.ViewInvalidReturn, methodSyntax); + } + + Parameters = new( + method + .Parameters.Skip(1) + .Select(p => new MemberDeclaration(p, p.Type, diag)) + .ToImmutableArray() + ); + } + + public string GenerateViewDef(uint Index) => + $$$""" + new global::SpacetimeDB.Internal.RawViewDefV9( + Name: "{{{Name}}}", + Index: {{{Index}}}, + IsPublic: {{{IsPublic.ToString().ToLower()}}}, + IsAnonymous: {{{IsAnonymous.ToString().ToLower()}}}, + Params: [{{{MemberDeclaration.GenerateDefs(Parameters)}}}], + ReturnType: new {{{ReturnType.BSATNName.Replace( + "Module.", + "global::Module." + )}}}().GetAlgebraicType(registrar) + ); + """; + + public string GenerateDispatcherClass() + { + var paramReads = string.Join( + "\n ", + Parameters.Select(p => + $"var {p.Name} = {p.Name}{TypeUse.BsatnFieldSuffix}.Read(reader);" + ) + ); + + var makeViewDefMethod = IsAnonymous ? "MakeAnonymousViewDef" : "MakeViewDef"; + + var interfaceName = IsAnonymous + ? "global::SpacetimeDB.Internal.IAnonymousView" + : "global::SpacetimeDB.Internal.IView"; + var interfaceContext = IsAnonymous + ? "global::SpacetimeDB.Internal.IAnonymousViewContext" + : "global::SpacetimeDB.Internal.IViewContext"; + var concreteContext = IsAnonymous + ? "SpacetimeDB.AnonymousViewContext" + : "SpacetimeDB.ViewContext"; + + var invocationArgs = + Parameters.Length == 0 ? "" : ", " + string.Join(", ", Parameters.Select(p => p.Name)); + var index = IsAnonymous ? GetNextAnonViewIndex() : GetNextViewIndex(); + return $$$""" + sealed class {{{Name}}}ViewDispatcher : {{{interfaceName}}} { + {{{MemberDeclaration.GenerateBsatnFields(Accessibility.Private, Parameters)}}} + + private static readonly {{{ReturnType.BSATNName}}} returnRW = new(); + + public SpacetimeDB.Internal.RawViewDefV9 {{{makeViewDefMethod}}}(SpacetimeDB.BSATN.ITypeRegistrar registrar) + => {{{GenerateViewDef(index)}}} + + public byte[] Invoke( + System.IO.BinaryReader reader, + {{{interfaceContext}}} ctx + ) { + try { + {{{paramReads}}} + var returnValue = {{{FullName}}}(({{{concreteContext}}})ctx{{{invocationArgs}}}); + using var output = new System.IO.MemoryStream(); + using var writer = new System.IO.BinaryWriter(output); + returnRW.Write(writer, returnValue); + return output.ToArray(); + } catch (System.Exception e) { + global::SpacetimeDB.Log.Error("Error in view '{{{Name}}}': " + e); + throw; + } + } + } + """; + } + + public string GenerateClass() + { + var builder = new Scope.Extensions(Scope, FullName); + builder.Contents.Append(GenerateDispatcherClass()); + return builder.ToString(); + } } /// @@ -997,6 +1299,23 @@ public void Initialize(IncrementalGeneratorInitializationContext context) .WithTrackingName("SpacetimeDB.Table.GenerateExtensions") .RegisterSourceOutputs(context); + var viewDeclarations = context + .SyntaxProvider.ForAttributeWithMetadataName( + fullyQualifiedMetadataName: typeof(ViewAttribute).FullName!, + predicate: (node, _) => node is MethodDeclarationSyntax, + transform: (ctx, _) => ctx.ParseWithDiags(diag => new ViewDeclaration(ctx, diag)) + ) + .ReportDiagnostics(context) + .WithTrackingName("SpacetimeDB.View.Parse"); + + var views = CollectDistinct( + "View", + context, + viewDeclarations, + v => v.Name, + v => v.FullName + ); + var reducers = context .SyntaxProvider.ForAttributeWithMetadataName( fullyQualifiedMetadataName: typeof(ReducerAttribute).FullName, @@ -1040,13 +1359,23 @@ public void Initialize(IncrementalGeneratorInitializationContext context) r => r.FullName ); - var tableViews = CollectDistinct( + var tableAccessors = CollectDistinct( "Table", context, tables - .SelectMany((t, ct) => t.GenerateViews()) - .WithTrackingName("SpacetimeDB.Table.GenerateViews"), - v => v.viewName, + .SelectMany((t, ct) => t.GenerateTableAccessors()) + .WithTrackingName("SpacetimeDB.Table.GenerateTableAccessors"), + v => v.tableAccessorName, + v => v.tableName + ); + + var readOnlyAccessors = CollectDistinct( + "TableReadOnly", + context, + tables + .SelectMany((t, ct) => t.GenerateReadOnlyAccessors()) + .WithTrackingName("SpacetimeDB.Table.GenerateReadOnlyAccessors"), + v => v.tableAccessorName + "ReadOnly", v => v.tableName ); @@ -1086,12 +1415,20 @@ public void Initialize(IncrementalGeneratorInitializationContext context) // Register the generated source code with the compilation context as part of module publishing // Once the compilation is complete, the generated code will be used to create tables and reducers in the database context.RegisterSourceOutput( - tableViews.Combine(addReducers).Combine(rlsFiltersArray).Combine(columnDefaultValues), + tableAccessors + .Combine(addReducers) + .Combine(readOnlyAccessors) + .Combine(views) + .Combine(rlsFiltersArray) + .Combine(columnDefaultValues), (context, tuple) => { - var (((tableViews, addReducers), rlsFilters), columnDefaultValues) = tuple; + var ( + ((((tableAccessors, addReducers), readOnlyAccessors), views), rlsFilters), + columnDefaultValues + ) = tuple; // Don't generate the FFI boilerplate if there are no tables or reducers. - if (tableViews.Array.IsEmpty && addReducers.Array.IsEmpty) + if (tableAccessors.Array.IsEmpty && addReducers.Array.IsEmpty) { return; } @@ -1100,6 +1437,10 @@ public void Initialize(IncrementalGeneratorInitializationContext context) $$""" // #nullable enable + // The runtime already defines SpacetimeDB.Internal.LocalReadOnly in Runtime\Internal\Module.cs as an empty partial type. + // This is needed so every module build doesn't generate a full LocalReadOnly type, but just adds on to the existing. + // We extend it here with generated table accessors, and just need to suppress the duplicate-type warning. + #pragma warning disable CS0436 using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; @@ -1116,7 +1457,7 @@ public sealed record ReducerContext : DbContext, Internal.IReducerContext // We need this property to be non-static for parity with client SDK. public Identity Identity => Internal.IReducerContext.GetIdentity(); - internal ReducerContext(Identity identity, ConnectionId? connectionId, Random random, Timestamp time) { + internal ReducerContext(Identity identity, ConnectionId? connectionId, Random random, Timestamp time) { Sender = identity; ConnectionId = connectionId; Rng = random; @@ -1124,16 +1465,45 @@ internal ReducerContext(Identity identity, ConnectionId? connectionId, Random ra SenderAuth = AuthCtx.BuildFromSystemTables(connectionId, identity); } } + + public sealed record ViewContext : DbContext, Internal.IViewContext + { + public Identity Sender { get; } + + internal ViewContext(Identity sender, Internal.LocalReadOnly db) + : base(db) + { + Sender = sender; + } + } + public sealed record AnonymousViewContext : DbContext, Internal.IAnonymousViewContext + { + internal AnonymousViewContext(Internal.LocalReadOnly db) + : base(db) { } + } + namespace Internal.TableHandles { - {{string.Join("\n", tableViews.Select(v => v.view))}} + {{string.Join("\n", tableAccessors.Select(v => v.tableAccessor))}} } - + public sealed class Local { - {{string.Join("\n", tableViews.Select(v => v.getter))}} + {{string.Join("\n", tableAccessors.Select(v => v.getter))}} } } - + + {{string.Join("\n", views.Array.Select(v => v.GenerateDispatcherClass()))}} + + namespace SpacetimeDB.Internal.ViewHandles { + {{string.Join("\n", readOnlyAccessors.Array.Select(v => v.readOnlyAccessor))}} + } + + namespace SpacetimeDB.Internal { + public sealed partial class LocalReadOnly { + {{string.Join("\n", readOnlyAccessors.Select(v => v.readOnlyGetter))}} + } + } + static class ModuleRegistration { {{string.Join("\n", addReducers.Select(r => r.Class))}} @@ -1147,6 +1517,8 @@ static class ModuleRegistration { #endif public static void Main() { SpacetimeDB.Internal.Module.SetReducerContextConstructor((identity, connectionId, random, time) => new SpacetimeDB.ReducerContext(identity, connectionId, random, time)); + SpacetimeDB.Internal.Module.SetViewContextConstructor(identity => new SpacetimeDB.ViewContext(identity, new SpacetimeDB.Internal.LocalReadOnly())); + SpacetimeDB.Internal.Module.SetAnonymousViewContextConstructor(() => new SpacetimeDB.AnonymousViewContext(new SpacetimeDB.Internal.LocalReadOnly())); var __memoryStream = new MemoryStream(); var __writer = new BinaryWriter(__memoryStream); @@ -1158,7 +1530,15 @@ public static void Main() { )}} {{string.Join( "\n", - tableViews.Select(t => $"SpacetimeDB.Internal.Module.RegisterTable<{t.tableName}, SpacetimeDB.Internal.TableHandles.{t.viewName}>();") + views.Array.Select(v => + v.IsAnonymous + ? $"SpacetimeDB.Internal.Module.RegisterAnonymousView<{v.Name}ViewDispatcher>();" + : $"SpacetimeDB.Internal.Module.RegisterView<{v.Name}ViewDispatcher>();" + ) + )}} + {{string.Join( + "\n", + tableAccessors.Select(t => $"SpacetimeDB.Internal.Module.RegisterTable<{t.tableName}, SpacetimeDB.Internal.TableHandles.{t.tableAccessorName}>();") )}} {{string.Join( "\n", @@ -1209,6 +1589,8 @@ SpacetimeDB.Internal.BytesSink error ); #endif } + + #pragma warning restore CS0436 """ ); } diff --git a/crates/bindings-csharp/Runtime/Attrs.cs b/crates/bindings-csharp/Runtime/Attrs.cs index 596da6c0764..a60084150b8 100644 --- a/crates/bindings-csharp/Runtime/Attrs.cs +++ b/crates/bindings-csharp/Runtime/Attrs.cs @@ -80,6 +80,24 @@ public sealed class TableAttribute : Attribute public string ScheduledAt { get; init; } = "ScheduledAt"; } + /// + /// Registers a method as a SpacetimeDB view, enabling codegen for it. + /// Views are pure, read-only queries that run with a view context instead of a reducer context. + /// + [AttributeUsage(AttributeTargets.Method, Inherited = false)] + public sealed class ViewAttribute : Attribute + { + /// + /// Views must have an explicit name. + /// + public string? Name { get; init; } + + /// + /// Marks the view as callable by any client. Leave false to restrict to the module owner. + /// + public bool Public { get; init; } = false; + } + [AttributeUsage( AttributeTargets.Struct | AttributeTargets.Class | AttributeTargets.Field, AllowMultiple = true @@ -136,14 +154,14 @@ public string Value } if (value is bool) { - return value.ToString()?.ToLower(); + return value.ToString()?.ToLower()!; } var str = value.ToString(); if (value is string) { str = $"\"{str}\""; } - return str; + return str!; } } diff --git a/crates/bindings-csharp/Runtime/Internal/IIndex.cs b/crates/bindings-csharp/Runtime/Internal/IIndex.cs index 800a119133b..4e7d0cdaf9e 100644 --- a/crates/bindings-csharp/Runtime/Internal/IIndex.cs +++ b/crates/bindings-csharp/Runtime/Internal/IIndex.cs @@ -1,6 +1,9 @@ namespace SpacetimeDB.Internal; using System; +using System.Collections.Generic; +using System.IO; +using System.Text; using SpacetimeDB.BSATN; public abstract class IndexBase @@ -82,6 +85,13 @@ out handle } } +public abstract class ReadOnlyIndexBase(string name) : IndexBase(name) + where Row : IStructuralReadWrite, new() +{ + protected IEnumerable Filter(Bounds bounds) + where Bounds : IBTreeIndexBounds => DoFilter(bounds); +} + public abstract class UniqueIndex(string name) : IndexBase(name) where Handle : ITableView where Row : IStructuralReadWrite, new() @@ -103,3 +113,42 @@ protected Row DoUpdate(Row row) return ITableView.IntegrateGeneratedColumns(row, bytes, bytes_len); } } + +public abstract class ReadOnlyUniqueIndex(string name) + : ReadOnlyIndexBase(name) + where Handle : ReadOnlyTableView + where Row : IStructuralReadWrite, new() + where RW : struct, BSATN.IReadWrite +{ + private static BTreeIndexBounds ToBounds(T key) => new(key); + + protected IEnumerable Filter(T key) => Filter(ToBounds(key)); + + protected Row? FindSingle(T key) => Filter(key).Cast().SingleOrDefault(); +} + +public abstract class ReadOnlyTableView + where Row : IStructuralReadWrite, new() +{ + private readonly FFI.TableId tableId; + + private sealed class TableIter(FFI.TableId tableId) : RawTableIterBase + { + protected override void IterStart(out FFI.RowIter handle) => + FFI.datastore_table_scan_bsatn(tableId, out handle); + } + + protected ReadOnlyTableView(string tableName) + { + var nameBytes = Encoding.UTF8.GetBytes(tableName); + FFI.table_id_from_name(nameBytes, (uint)nameBytes.Length, out tableId); + } + + protected ulong DoCount() + { + FFI.datastore_table_row_count(tableId, out var count); + return count; + } + + protected IEnumerable DoIter() => new TableIter(tableId).Parse(); +} diff --git a/crates/bindings-csharp/Runtime/Internal/IView.cs b/crates/bindings-csharp/Runtime/Internal/IView.cs new file mode 100644 index 00000000000..615a53338d3 --- /dev/null +++ b/crates/bindings-csharp/Runtime/Internal/IView.cs @@ -0,0 +1,30 @@ +namespace SpacetimeDB.Internal; + +using SpacetimeDB.BSATN; + +public interface IView +{ + RawViewDefV9 MakeViewDef(ITypeRegistrar registrar); + + // This one is not static because we need to be able to store IView in a list. + byte[] Invoke(BinaryReader reader, IViewContext args); +} + +public interface IAnonymousView +{ + RawViewDefV9 MakeAnonymousViewDef(ITypeRegistrar registrar); + + // This one is not static because we need to be able to store IAnonymousView in a list. + byte[] Invoke(BinaryReader reader, IAnonymousViewContext args); +} + +public interface IViewContext +{ + public static Identity GetIdentity() + { + FFI.identity(out var identity); + return identity; + } +} + +public interface IAnonymousViewContext { } diff --git a/crates/bindings-csharp/Runtime/Internal/Module.cs b/crates/bindings-csharp/Runtime/Internal/Module.cs index f95f66ca292..f0afea9f0df 100644 --- a/crates/bindings-csharp/Runtime/Internal/Module.cs +++ b/crates/bindings-csharp/Runtime/Internal/Module.cs @@ -3,7 +3,6 @@ namespace SpacetimeDB.Internal; using System; using System.Collections.Generic; using System.Runtime.InteropServices; -using System.Text; using SpacetimeDB; using SpacetimeDB.BSATN; @@ -38,6 +37,11 @@ internal AlgebraicType.Ref RegisterType(Func Tables.Add(table); + internal void RegisterView(RawViewDefV9 view) + { + MiscExports.Add(new RawMiscModuleExportV9.View(view)); + } + internal void RegisterRowLevelSecurity(RawRowLevelSecurityDefV9 rls) => RowLevelSecurity.Add(rls); @@ -56,15 +60,31 @@ public static class Module { private static readonly RawModuleDefV9 moduleDef = new(); private static readonly List reducers = []; + private static readonly List> viewDefs = []; + private static readonly List viewDispatchers = []; + private static readonly List anonymousViewDispatchers = []; - private static Func? newContext = - null; + private static Func< + Identity, + ConnectionId?, + Random, + Timestamp, + IReducerContext + >? newReducerContext = null; + private static Func? newViewContext = null; + private static Func? newAnonymousViewContext = null; public static void SetReducerContextConstructor( Func ctor - ) => newContext = ctor; + ) => newReducerContext = ctor; + + public static void SetViewContextConstructor(Func ctor) => + newViewContext = ctor; - readonly struct TypeRegistrar() : ITypeRegistrar + public static void SetAnonymousViewContextConstructor(Func ctor) => + newAnonymousViewContext = ctor; + + public readonly struct TypeRegistrar() : ITypeRegistrar { private readonly Dictionary types = []; @@ -108,6 +128,24 @@ public static void RegisterTable() where View : ITableView, new() => moduleDef.RegisterTable(View.MakeTableDesc(typeRegistrar)); + public static void RegisterView() + where TDispatcher : IView, new() + { + var dispatcher = new TDispatcher(); + var def = dispatcher.MakeViewDef(typeRegistrar); + viewDispatchers.Add(dispatcher); + moduleDef.RegisterView(def); + } + + public static void RegisterAnonymousView() + where TDispatcher : IAnonymousView, new() + { + var dispatcher = new TDispatcher(); + var def = dispatcher.MakeAnonymousViewDef(typeRegistrar); + anonymousViewDispatchers.Add(dispatcher); + moduleDef.RegisterView(def); + } + public static void RegisterClientVisibilityFilter(Filter rlsFilter) { if (rlsFilter is Filter.Sql(var rlsSql)) @@ -204,6 +242,10 @@ public static void __describe_module__(BytesSink description) RawModuleDef versioned = new RawModuleDef.V9(moduleDef); var moduleBytes = IStructuralReadWrite.ToBytes(new RawModuleDef.BSATN(), versioned); description.Write(moduleBytes); + foreach (var writeView in viewDefs) + { + writeView(description); + } } catch (Exception e) { @@ -235,7 +277,7 @@ BytesSink error var random = new Random((int)timestamp.MicrosecondsSinceUnixEpoch); var time = timestamp.ToStd(); - var ctx = newContext!(senderIdentity, connectionId, random, time); + var ctx = newReducerContext!(senderIdentity, connectionId, random, time); using var stream = new MemoryStream(args.Consume()); using var reader = new BinaryReader(stream); @@ -254,4 +296,63 @@ BytesSink error return Errno.HOST_CALL_FAILURE; } } + + public static Errno __call_view__( + uint id, + ulong sender_0, + ulong sender_1, + ulong sender_2, + ulong sender_3, + BytesSource args, + BytesSink rows + ) + { + try + { + var sender = Identity.From( + MemoryMarshal.AsBytes([sender_0, sender_1, sender_2, sender_3]).ToArray() + ); + var ctx = newViewContext!(sender); + using var stream = new MemoryStream(args.Consume()); + using var reader = new BinaryReader(stream); + var bytes = viewDispatchers[(int)id].Invoke(reader, ctx); + rows.Write(bytes); + return Errno.OK; + } + catch (Exception e) + { + Log.Error($"Error while invoking view: {e}"); + return Errno.HOST_CALL_FAILURE; + } + } + + public static Errno __call_anonymous_view__(uint id, BytesSource args, BytesSink rows) + { + try + { + var ctx = newAnonymousViewContext!(); + using var stream = new MemoryStream(args.Consume()); + using var reader = new BinaryReader(stream); + var bytes = anonymousViewDispatchers[(int)id].Invoke(reader, ctx); + rows.Write(bytes); + return Errno.OK; + } + catch (Exception e) + { + Log.Error($"Error while invoking anonymous view: {e}"); + return Errno.HOST_CALL_FAILURE; + } + } +} + +/// +/// Read-only database access for view contexts. +/// The code generator will extend this partial class to add table accessors. +/// +public sealed partial class LocalReadOnly +{ + // This class is intentionally empty - the code generator will add + // read-only table accessors for each table in the module. + // Example generated code: + // public Internal.ViewHandles.UserReadOnly User => new(); } diff --git a/modules/module-test-cs/Lib.cs b/modules/module-test-cs/Lib.cs index aeb339cdd07..1889f75bf2e 100644 --- a/modules/module-test-cs/Lib.cs +++ b/modules/module-test-cs/Lib.cs @@ -1,5 +1,6 @@ namespace SpacetimeDB.Modules.ModuleTestCs; +using System.Reflection.Metadata.Ecma335; using SpacetimeDB; // A C# type alias for TestA. @@ -67,7 +68,7 @@ public partial struct TestE [Type] public partial record Baz { - public string field; + public string field = ""; } [Type] @@ -96,7 +97,7 @@ public partial record TestFBar { } [Type] public partial record TestFBaz { - public string value; + public string value = ""; } [Type] @@ -162,6 +163,12 @@ public partial struct HasSpecialStuff [Table(Name = "logged_out_player", Public = true)] public partial struct Player { + public Player() + { + this.identity = new Identity(); + this.player_id = 0; + this.name = ""; + } [PrimaryKey] public Identity identity; [AutoInc] @@ -178,6 +185,10 @@ public partial struct Player // We can derive `Deserialize` for lifetime generic types: public partial class Foo { + public Foo() + { + this.field = ""; + } public string field { get; set; } // TODO: Bsatn seems not to be available in C# yet @@ -195,6 +206,16 @@ public partial class Foo static partial class Module { + // ───────────────────────────────────────────────────────────────────────────── + // VIEWS + // ───────────────────────────────────────────────────────────────────────────── + + [View(Name = "my_player", Public = true)] + public static Player? my_player(ViewContext ctx) + { + return (Player?)ctx.Db.player.identity.Find(ctx.Sender); + } + // This reducer is run at module initialization. [Reducer(ReducerKind.Init)] public static void init(ReducerContext ctx) diff --git a/sdks/csharp/examples~/quickstart-chat/client/module_bindings/SpacetimeDBClient.g.cs b/sdks/csharp/examples~/quickstart-chat/client/module_bindings/SpacetimeDBClient.g.cs index 3ec6b5b9825..e205e194f5e 100644 --- a/sdks/csharp/examples~/quickstart-chat/client/module_bindings/SpacetimeDBClient.g.cs +++ b/sdks/csharp/examples~/quickstart-chat/client/module_bindings/SpacetimeDBClient.g.cs @@ -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.5.0 (commit e3866e3f3c47160f3246bd0d98a17c26ba21a47c). +// This was generated using spacetimedb cli version 1.7.0 (commit af3f85dcf4e95ec3a33b227dde9407a29871e152). #nullable enable diff --git a/sdks/csharp/examples~/regression-tests/client/module_bindings/SpacetimeDBClient.g.cs b/sdks/csharp/examples~/regression-tests/client/module_bindings/SpacetimeDBClient.g.cs index 7c0795d0624..7418a534cc3 100644 --- a/sdks/csharp/examples~/regression-tests/client/module_bindings/SpacetimeDBClient.g.cs +++ b/sdks/csharp/examples~/regression-tests/client/module_bindings/SpacetimeDBClient.g.cs @@ -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.5.0 (commit 722dd1cd0784bf0622133b4838baf50a3d100102). +// This was generated using spacetimedb cli version 1.7.0 (commit f01df570c478b16793a4d3ab64fa972e270ce858). #nullable enable diff --git a/sdks/csharp/examples~/regression-tests/client/module_bindings/Tables/GetAnonymousExampleDataById.g.cs b/sdks/csharp/examples~/regression-tests/client/module_bindings/Tables/GetAnonymousExampleDataById.g.cs new file mode 100644 index 00000000000..0d9910a0fa8 --- /dev/null +++ b/sdks/csharp/examples~/regression-tests/client/module_bindings/Tables/GetAnonymousExampleDataById.g.cs @@ -0,0 +1,27 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +#nullable enable + +using System; +using SpacetimeDB.BSATN; +using SpacetimeDB.ClientApi; +using System.Collections.Generic; +using System.Runtime.Serialization; + +namespace SpacetimeDB.Types +{ + public sealed partial class RemoteTables + { + public sealed class GetAnonymousExampleDataByIdHandle : RemoteTableHandle + { + protected override string RemoteTableName => "GetAnonymousExampleDataById"; + + internal GetAnonymousExampleDataByIdHandle(DbConnection conn) : base(conn) + { + } + } + + public readonly GetAnonymousExampleDataByIdHandle GetAnonymousExampleDataById; + } +} diff --git a/sdks/csharp/examples~/regression-tests/client/module_bindings/Tables/GetExampleDataById.g.cs b/sdks/csharp/examples~/regression-tests/client/module_bindings/Tables/GetExampleDataById.g.cs new file mode 100644 index 00000000000..7832fe7b6d7 --- /dev/null +++ b/sdks/csharp/examples~/regression-tests/client/module_bindings/Tables/GetExampleDataById.g.cs @@ -0,0 +1,27 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +#nullable enable + +using System; +using SpacetimeDB.BSATN; +using SpacetimeDB.ClientApi; +using System.Collections.Generic; +using System.Runtime.Serialization; + +namespace SpacetimeDB.Types +{ + public sealed partial class RemoteTables + { + public sealed class GetExampleDataByIdHandle : RemoteTableHandle + { + protected override string RemoteTableName => "GetExampleDataById"; + + internal GetExampleDataByIdHandle(DbConnection conn) : base(conn) + { + } + } + + public readonly GetExampleDataByIdHandle GetExampleDataById; + } +} diff --git a/sdks/csharp/examples~/regression-tests/republishing/client/module_bindings/SpacetimeDBClient.g.cs b/sdks/csharp/examples~/regression-tests/republishing/client/module_bindings/SpacetimeDBClient.g.cs index 2eae003de0e..a60dd23de85 100644 --- a/sdks/csharp/examples~/regression-tests/republishing/client/module_bindings/SpacetimeDBClient.g.cs +++ b/sdks/csharp/examples~/regression-tests/republishing/client/module_bindings/SpacetimeDBClient.g.cs @@ -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.5.0 (commit 93dbce08003b093790af2d5f590c5e597a24bfdb). +// This was generated using spacetimedb cli version 1.7.0 (commit f01df570c478b16793a4d3ab64fa972e270ce858). #nullable enable diff --git a/sdks/csharp/examples~/regression-tests/server/Lib.cs b/sdks/csharp/examples~/regression-tests/server/Lib.cs index 86a4ac55afc..0cf7f3cfef0 100644 --- a/sdks/csharp/examples~/regression-tests/server/Lib.cs +++ b/sdks/csharp/examples~/regression-tests/server/Lib.cs @@ -15,6 +15,18 @@ public partial struct ExampleData public uint Indexed; } + [SpacetimeDB.View(Name = "GetExampleDataById", Public = true)] + public static ExampleData? GetExampleDataById(ViewContext ctx)//, uint id) + { + return ctx.Db.ExampleData.Id.Find(0); + } + + [SpacetimeDB.View(Name = "GetAnonymousExampleDataById", Public = true)] + public static ExampleData? GetAnonymousExampleDataById(AnonymousViewContext ctx) //, uint id) + { + return ctx.Db.ExampleData.Id.Find(0); + } + [SpacetimeDB.Reducer] public static void Delete(ReducerContext ctx, uint id) { diff --git a/sdks/csharp/src/SpacetimeDB/ClientApi/CallProcedure.g.cs.meta b/sdks/csharp/src/SpacetimeDB/ClientApi/CallProcedure.g.cs.meta index b95ebddaba7..5b11ffaadea 100644 --- a/sdks/csharp/src/SpacetimeDB/ClientApi/CallProcedure.g.cs.meta +++ b/sdks/csharp/src/SpacetimeDB/ClientApi/CallProcedure.g.cs.meta @@ -8,4 +8,4 @@ MonoImporter: icon: {instanceID: 0} userData: assetBundleName: - assetBundleVariant: + assetBundleVariant: \ No newline at end of file diff --git a/sdks/csharp/src/SpacetimeDB/ClientApi/ProcedureResult.g.cs.meta b/sdks/csharp/src/SpacetimeDB/ClientApi/ProcedureResult.g.cs.meta index c3d45951cf7..cdb00377e29 100644 --- a/sdks/csharp/src/SpacetimeDB/ClientApi/ProcedureResult.g.cs.meta +++ b/sdks/csharp/src/SpacetimeDB/ClientApi/ProcedureResult.g.cs.meta @@ -8,4 +8,4 @@ MonoImporter: icon: {instanceID: 0} userData: assetBundleName: - assetBundleVariant: + assetBundleVariant: \ No newline at end of file diff --git a/sdks/csharp/src/SpacetimeDB/ClientApi/ProcedureStatus.g.cs.meta b/sdks/csharp/src/SpacetimeDB/ClientApi/ProcedureStatus.g.cs.meta index 20a97b43d00..ed8b3bbaa8e 100644 --- a/sdks/csharp/src/SpacetimeDB/ClientApi/ProcedureStatus.g.cs.meta +++ b/sdks/csharp/src/SpacetimeDB/ClientApi/ProcedureStatus.g.cs.meta @@ -8,4 +8,4 @@ MonoImporter: icon: {instanceID: 0} userData: assetBundleName: - assetBundleVariant: + assetBundleVariant: \ No newline at end of file