From 158a98a03d1a47092bcd2b5b3984da88665f9a0d Mon Sep 17 00:00:00 2001 From: Dillon Shaffer <46535284+Molkars@users.noreply.github.com> Date: Thu, 14 Nov 2024 10:43:15 -0700 Subject: [PATCH 1/6] Update quickstart.md --- docs/modules/c-sharp/quickstart.md | 65 +++++++++++++++--------------- 1 file changed, 33 insertions(+), 32 deletions(-) diff --git a/docs/modules/c-sharp/quickstart.md b/docs/modules/c-sharp/quickstart.md index 5d8c873d..38061021 100644 --- a/docs/modules/c-sharp/quickstart.md +++ b/docs/modules/c-sharp/quickstart.md @@ -60,18 +60,15 @@ spacetime init --lang csharp server To the top of `server/Lib.cs`, add some imports we'll be using: ```csharp -using System.Runtime.CompilerServices; -using SpacetimeDB.Module; -using static SpacetimeDB.Runtime; +using SpacetimeDB; ``` -- `SpacetimeDB.Module` contains the special attributes we'll use to define tables and reducers in our module. -- `SpacetimeDB.Runtime` contains the raw API bindings SpacetimeDB uses to communicate with the database. +- `SpacetimeDB` contains the special attributes we'll use to define tables and reducers in our module and the raw API bindings SpacetimeDB uses to communicate with the database. We also need to create our static module class which all of the module code will live in. In `server/Lib.cs`, add: ```csharp -static partial class Module +public static partial class Module { } ``` @@ -88,7 +85,7 @@ In `server/Lib.cs`, add the definition of the table `User` to the `Module` class [SpacetimeDB.Table(Public = true)] public partial class User { - [SpacetimeDB.Column(ColumnAttrs.PrimaryKey)] + [SpacetimeDB.PrimaryKey] public Identity Identity; public string? Name; public bool Online; @@ -113,7 +110,7 @@ public partial class Message We want to allow users to set their names, because `Identity` is not a terribly user-friendly identifier. To that effect, we define a reducer `SetName` which clients can invoke to set their `User.Name`. It will validate the caller's chosen name, using a function `ValidateName` which we'll define next, then look up the `User` record for the caller and update it to store the validated name. If the name fails the validation, the reducer will fail. -Each reducer may accept as its first argument a `ReducerContext`, which includes the `Identity` and `Address` of the client that called the reducer, and the `Timestamp` when it was invoked. For now, we only need the `Identity`, `ctx.Sender`. +Each reducer may accept as its first argument a `ReducerContext`, which includes the `Identity` and `Address` of the client that called the reducer, and the `Timestamp` when it was invoked. For now, we only need the `Identity`, `ctx.CallerIdentity`. It's also possible to call `SetName` via the SpacetimeDB CLI's `spacetime call` command without a connection, in which case no `User` record will exist for the caller. We'll return an error in this case, but you could alter the reducer to insert a `User` row for the module owner. You'll have to decide whether the module owner is always online or always offline, though. @@ -125,11 +122,11 @@ public static void SetName(ReducerContext ctx, string name) { name = ValidateName(name); - var user = User.FindByIdentity(ctx.Sender); + var user = ctx.Db.User.Identity.Find(ctx.CallerIdentity); if (user is not null) { user.Name = name; - User.UpdateByIdentity(ctx.Sender, user); + ctx.Db.User.Identity.Update(user); } } ``` @@ -158,7 +155,7 @@ public static string ValidateName(string name) ## Send messages -We define a reducer `SendMessage`, which clients will call to send messages. It will validate the message's text, then insert a new `Message` record using `Message.Insert`, with the `Sender` identity and `Time` timestamp taken from the `ReducerContext`. +We define a reducer `SendMessage`, which clients will call to send messages. It will validate the message's text, then insert a new `Message` record using `Ctx.Db.Message.Insert`, with the `Sender` identity and `Time` timestamp taken from the `ReducerContext`. In `server/Lib.cs`, add to the `Module` class: @@ -167,13 +164,14 @@ In `server/Lib.cs`, add to the `Module` class: public static void SendMessage(ReducerContext ctx, string text) { text = ValidateMessage(text); - Log(text); - new Message + Log.info(text); + var msg = new Message { - Sender = ctx.Sender, + Sender = ctx.CallerIdentity, Text = text, Sent = ctx.Time.ToUnixTimeMilliseconds(), - }.Insert(); + }; + ctx.Db.Message.Insert(msg); } ``` @@ -200,60 +198,61 @@ You could extend the validation in `ValidateMessage` in similar ways to `Validat ## Set users' online status -In C# modules, you can register for `Connect` and `Disconnect` events by using a special `ReducerKind`. We'll use the `Connect` event to create a `User` record for the client if it doesn't yet exist, and to set its online status. +In C# modules, you can register for `ClientConnected` and `ClientDisconnected` events by using a special `ReducerKind`. We'll use the `ClientConnected` event to create a `User` record for the client if it doesn't yet exist, and to set its online status. -We'll use `User.FindByIdentity` to look up a `User` row for `ctx.Sender`, if one exists. If we find one, we'll use `User.UpdateByIdentity` to overwrite it with a row that has `Online: true`. If not, we'll use `User.Insert` to insert a new row for our new user. All three of these methods are generated by the `[SpacetimeDB.Table]` attribute, with rows and behavior based on the row attributes. `FindByIdentity` returns a nullable `User`, because the unique constraint from the `[SpacetimeDB.Column(ColumnAttrs.PrimaryKey)]` attribute means there will be either zero or one matching rows. `Insert` will throw an exception if the insert violates this constraint; if we want to overwrite a `User` row, we need to do so explicitly using `UpdateByIdentity`. +We'll use `ctx.Db.User.Identity.Find` to look up a `User` row for `ctx.CallerIdentity`, if one exists. If we find one, we'll use `ctx.Db.User.Identity.Update` to overwrite it with a row that has `Online: true`. If not, we'll use `ctx.Db.User.Insert` to insert a new row for our new user. All three of these methods are generated by the `[SpacetimeDB.Table]` attribute, with rows and behavior based on the row attributes. `Ctx.Db.User.Identity.Find` returns a nullable `User`, because the unique constraint from the `[SpacetimeDB.PrimaryKey]` attribute means there will be either zero or one matching rows. `Insert` will throw an exception if the insert violates this constraint; if we want to overwrite a `User` row, we need to do so explicitly using `ctx.Db.User.Identity.Update`. In `server/Lib.cs`, add the definition of the connect reducer to the `Module` class: ```csharp -[SpacetimeDB.Reducer(ReducerKind.Connect)] -public static void OnConnect(ReducerContext ReducerContext) +[SpacetimeDB.Reducer(ReducerKind.ClientConnected)] +public static void Connect(ReducerContext ctx) { - Log($"Connect {ReducerContext.Sender}"); - var user = User.FindByIdentity(ReducerContext.Sender); + Log.info($"Connect {ReducerContext.Sender}"); + var user = ctx.Db.User.Identity.Find(ctx.CallerIdentity); if (user is not null) { // If this is a returning user, i.e., we already have a `User` with this `Identity`, // set `Online: true`, but leave `Name` and `Identity` unchanged. user.Online = true; - User.UpdateByIdentity(ReducerContext.Sender, user); + ctx.Db.User.Identity.Update(user); } else { // If this is a new user, create a `User` object for the `Identity`, // which is online, but hasn't set a name. - new User + var user = new User { Name = null, Identity = ReducerContext.Sender, Online = true, - }.Insert(); + }; + ctx.Db.User.Insert(user); } } ``` -Similarly, whenever a client disconnects, the module will execute the `OnDisconnect` event if it's registered with `ReducerKind.Disconnect`. We'll use it to un-set the `Online` status of the `User` for the disconnected client. +Similarly, whenever a client disconnects, the module will execute the `Disconnect` event if it's registered with `ReducerKind.ClientDisconnected`. We'll use it to un-set the `Online` status of the `User` for the disconnected client. Add the following code after the `OnConnect` handler: ```csharp -[SpacetimeDB.Reducer(ReducerKind.Disconnect)] -public static void OnDisconnect(ReducerContext ReducerContext) +[SpacetimeDB.Reducer(ReducerKind.ClientDisconnected)] +public static void OnDisconnect(ReducerContext ctx) { - var user = User.FindByIdentity(ReducerContext.Sender); + var user = ctx.Db.User.Identity.Find(ctx.CallerIdentity); if (user is not null) { // This user should exist, so set `Online: false`. user.Online = false; - User.UpdateByIdentity(ReducerContext.Sender, user); + ctx.Db.User.Identity.Update(user); } else { // User does not exist, log warning - Log("Warning: No user found for disconnected client."); + Log.Warning("No user found for disconnected client."); } } ``` @@ -272,6 +271,8 @@ From the `quickstart-chat` directory, run: spacetime publish --project-path server ``` +Install wasm-opt for optimized builds either from NPM or from the [binaryen releases](https://github.com/WebAssembly/binaryen/releases). + ```bash npm i wasm-opt -g ``` @@ -312,6 +313,6 @@ spacetime sql "SELECT * FROM Message" ## What's next? -You've just set up your first database in SpacetimeDB! The next step would be to create a client module that interacts with this module. You can use any of SpacetimDB's supported client languages to do this. Take a look at the quick start guide for your client language of choice: [Rust](/docs/languages/rust/rust-sdk-quickstart-guide), [C#](/docs/languages/csharp/csharp-sdk-quickstart-guide), or [TypeScript](/docs/languages/typescript/typescript-sdk-quickstart-guide). +You've just set up your first database in SpacetimeDB! The next step would be to create a client module that interacts with this module. You can use any of SpacetimDB's supported client languages to do this. Take a look at the quick start guide for your client language of choice: [Rust](/docs/sdks/rust/quickstart), [C#](/docs/sdks/c-sharp/quickstart), or [TypeScript](/docs/sdks/typescript/quickstart). -If you are planning to use SpacetimeDB with the Unity game engine, you can skip right to the [Unity Comprehensive Tutorial](/docs/unity/part-1) or check out our example game, [BitcraftMini](/docs/unity/part-3). +If you are planning to use SpacetimeDB with the Unity game engine, you can skip right to the [Unity Comprehensive Tutorial](/docs/unity/part-1) or check out our example game, [BitcraftMini](/docs/unity/part-5). From 7cf7ab176a410b5403703c4eaee16cd31142b5ca Mon Sep 17 00:00:00 2001 From: Dillon Shaffer <46535284+Molkars@users.noreply.github.com> Date: Thu, 14 Nov 2024 10:47:11 -0700 Subject: [PATCH 2/6] Update quickstart.md --- docs/modules/c-sharp/quickstart.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/modules/c-sharp/quickstart.md b/docs/modules/c-sharp/quickstart.md index 38061021..1882f9b0 100644 --- a/docs/modules/c-sharp/quickstart.md +++ b/docs/modules/c-sharp/quickstart.md @@ -155,7 +155,7 @@ public static string ValidateName(string name) ## Send messages -We define a reducer `SendMessage`, which clients will call to send messages. It will validate the message's text, then insert a new `Message` record using `Ctx.Db.Message.Insert`, with the `Sender` identity and `Time` timestamp taken from the `ReducerContext`. +We define a reducer `SendMessage`, which clients will call to send messages. It will validate the message's text, then insert a new `Message` record using `Ctx.Db.Message.Insert`, with the `CallerIdentity` identity and `Time` timestamp taken from the `ReducerContext`. In `server/Lib.cs`, add to the `Module` class: @@ -208,7 +208,7 @@ In `server/Lib.cs`, add the definition of the connect reducer to the `Module` cl [SpacetimeDB.Reducer(ReducerKind.ClientConnected)] public static void Connect(ReducerContext ctx) { - Log.info($"Connect {ReducerContext.Sender}"); + Log.info($"Connect {ctx.CallerIdentity}"); var user = ctx.Db.User.Identity.Find(ctx.CallerIdentity); if (user is not null) @@ -225,7 +225,7 @@ public static void Connect(ReducerContext ctx) var user = new User { Name = null, - Identity = ReducerContext.Sender, + Identity = ctx.CallerIdentity, Online = true, }; ctx.Db.User.Insert(user); From 367198dbc32c7ff894fea58791a49efd7d693854 Mon Sep 17 00:00:00 2001 From: Dillon Shaffer <46535284+Molkars@users.noreply.github.com> Date: Thu, 14 Nov 2024 11:06:04 -0700 Subject: [PATCH 3/6] Update index.md --- docs/modules/c-sharp/index.md | 165 ++++++++++++++++------------------ 1 file changed, 79 insertions(+), 86 deletions(-) diff --git a/docs/modules/c-sharp/index.md b/docs/modules/c-sharp/index.md index f6763fc7..552ede24 100644 --- a/docs/modules/c-sharp/index.md +++ b/docs/modules/c-sharp/index.md @@ -10,14 +10,13 @@ Let's start with a heavily commented version of the default example from the lan ```csharp // These imports bring into the scope common APIs you'll need to expose items from your module and to interact with the database runtime. -using SpacetimeDB.Module; -using static SpacetimeDB.Runtime; +using SpacetimeDB; // Roslyn generators are statically generating extra code as-if they were part of the source tree, so, // in order to inject new methods, types they operate on as well as their parents have to be marked as `partial`. // // We start with the top-level `Module` class for the module itself. -static partial class Module +public static partial class Module { // `[SpacetimeDB.Table]` registers a struct or a class as a SpacetimeDB table. // @@ -25,9 +24,10 @@ static partial class Module [SpacetimeDB.Table(Public = true)] public partial struct Person { - // `[SpacetimeDB.Column]` allows to specify column attributes / constraints such as + // SpacetimeDB allows you to specify column attributes / constraints such as // "this field should be unique" or "this field should get automatically assigned auto-incremented value". - [SpacetimeDB.Column(ColumnAttrs.Unique | ColumnAttrs.AutoInc)] + [SpacetimeDB.Unique] + [SpacetimeDB.PrimaryKey] public int Id; public string Name; public int Age; @@ -38,29 +38,29 @@ static partial class Module // Reducers are functions that can be invoked from the database runtime. // They can't return values, but can throw errors that will be caught and reported back to the runtime. [SpacetimeDB.Reducer] - public static void Add(string name, int age) + public static void Add(ReducerContext ctx, string name, int age) { // We can skip (or explicitly set to zero) auto-incremented fields when creating new rows. var person = new Person { Name = name, Age = age }; // `Insert()` method is auto-generated and will insert the given row into the table. - person.Insert(); + ctx.Db.Person.Insert(person); // After insertion, the auto-incremented fields will be populated with their actual values. // - // `Log()` function is provided by the runtime and will print the message to the database log. + // `Log` class is provided by the runtime and will print messages to the database log. // It should be used instead of `Console.WriteLine()` or similar functions. - Log($"Inserted {person.Name} under #{person.Id}"); + Log.Info($"Inserted {person.Name} under #{person.Id}"); } [SpacetimeDB.Reducer] - public static void SayHello() + public static void SayHello(ReducerContext ctx) { // Each table type gets a static Iter() method that can be used to iterate over the entire table. - foreach (var person in Person.Iter()) + foreach (var person in ctx.Db.Person.Iter()) { - Log($"Hello, {person.Name}!"); + Log.Info($"Hello, {person.Name}!"); } - Log("Hello, World!"); + Log.Info("Hello, World!"); } } ``` @@ -73,28 +73,21 @@ Now we'll get into details on all the APIs SpacetimeDB provides for writing modu First of all, logging as we're likely going to use it a lot for debugging and reporting errors. -`SpacetimeDB.Runtime` provides a `Log` function that will print the given message to the database log, along with the source location and a log level it was provided. +`SpacetimeDB` provides a `Log` class that will print messages to the database log, along with the source location and a log level it was provided. -Supported log levels are provided by the `LogLevel` enum: +Supported log levels are provided by different methods on the `Log` class: ```csharp -public enum LogLevel -{ - Error, - Warn, - Info, - Debug, - Trace, - Panic + public static void Trace(string message); + public static void Debug(string message); + public static void Info(string message); + public static void Warn(string message); + public static void Error(string message); + public static void Exception(string message); } ``` -If omitted, the log level will default to `Info`, so these two forms are equivalent: - -```csharp -Log("Hello, World!"); -Log("Hello, World!", LogLevel.Info); -``` +You should use `Log.Info` by default. ### Supported types @@ -116,9 +109,9 @@ The following types are supported out of the box and can be stored in the databa And a couple of special custom types: -- `SpacetimeDB.SATS.Unit` - semantically equivalent to an empty struct, sometimes useful in generic contexts where C# doesn't permit `void`. -- `Identity` (`SpacetimeDB.Runtime.Identity`) - a unique identifier for each user; internally a byte blob but can be printed, hashed and compared for equality. -- `Address` (`SpacetimeDB.Runtime.Address`) - an identifier which disamgibuates connections by the same `Identity`; internally a byte blob but can be printed, hashed and compared for equality. +- `SpacetimeDB.Unit` - semantically equivalent to an empty struct, sometimes useful in generic contexts where C# doesn't permit `void`. +- `Identity` (`SpacetimeDB.Identity`) - a unique identifier for each user; internally a byte blob but can be printed, hashed and compared for equality. +- `Address` (`SpacetimeDB.Address`) - an identifier which disamgibuates connections by the same `Identity`; internally a byte blob but can be printed, hashed and compared for equality. #### Custom types @@ -193,7 +186,7 @@ bool IsSome(MyEnum e) => e is not MyEnum.None; // Construct an instance of `MyEnum` with the `String` variant active. var myEnum = new MyEnum.String("Hello, world!"); -Console.WriteLine($"IsSome: {IsSome(myEnum)}"); +Log.Info($"IsSome: {IsSome(myEnum)}"); PrintEnum(myEnum); ``` @@ -211,7 +204,8 @@ It implies `[SpacetimeDB.Type]`, so you must not specify both attributes on the [SpacetimeDB.Table(Public = true)] public partial struct Person { - [SpacetimeDB.Column(ColumnAttrs.Unique | ColumnAttrs.AutoInc)] + [SpacetimeDB.PrimaryKey] + [SpacetimeDB.AutoInc] public int Id; public string Name; public int Age; @@ -221,10 +215,10 @@ public partial struct Person The example above will generate the following extra methods: ```csharp -public partial struct Person +public partial class ReducerCtx.Db.Person { // Inserts current instance as a new row into the table. - public void Insert(); + public void Insert(Person row); // Returns an iterator over all rows in the table, e.g.: // `for (var person in Person.Iter()) { ... }` @@ -234,22 +228,31 @@ public partial struct Person // `for (var person in Person.Query(p => p.Age >= 18)) { ... }` public static IEnumerable Query(Expression> filter); - // Generated for each column: + // Generated for each column with the `Indexed` attribute: - // Returns an iterator over all rows in the table that have the given value in the `Name` column. - public static IEnumerable FilterByName(string name); + public static class Name { + // Returns an iterator over all rows in the table that have the given value in the `Name` column. + public static IEnumerable Filter(string name); + public static void Update(Person row); + public static Person Find(string name); + } + public static class Name { + // Returns an iterator over all rows in the table that have the given value in the `Name` column. + public static IEnumerable Filter(string name); + } public static IEnumerable FilterByAge(int age); // Generated for each unique column: + public static partial class Id { + // Find a `Person` based on `id == $key` + public static Person? Find(int key); - // Finds a row in the table with the given value in the `Id` column and returns it, or `null` if no such row exists. - public static Person? FindById(int id); - - // Deletes a row in the table with the given value in the `Id` column and returns `true` if the row was found and deleted, or `false` if no such row exists. - public static bool DeleteById(int id); + // Delete a row by `key` on the row + public static bool Delete(int key); - // Updates a row in the table with the given value in the `Id` column and returns `true` if the row was found and updated, or `false` if no such row exists. - public static bool UpdateById(int oldId, Person newValue); + // Update based on the `id` of the row + public static bool Update(Person row); + } } ``` @@ -259,38 +262,33 @@ Attribute `[SpacetimeDB.Column]` can be used on any field of a `SpacetimeDB.Tabl The supported column attributes are: -- `ColumnAttrs.AutoInc` - this column should be auto-incremented. -- `ColumnAttrs.Unique` - this column should be unique. -- `ColumnAttrs.PrimaryKey` - this column should be a primary key, it implies `ColumnAttrs.Unique` but also allows clients to subscribe to updates via `OnUpdate` which will use this field to match the old and the new version of the row with each other. - -These attributes are bitflags and can be combined together, but you can also use some predefined shortcut aliases: - -- `ColumnAttrs.Identity` - same as `ColumnAttrs.Unique | ColumnAttrs.AutoInc`. -- `ColumnAttrs.PrimaryKeyAuto` - same as `ColumnAttrs.PrimaryKey | ColumnAttrs.AutoInc`. - +- `SpacetimeDB.AutoInc` - this column should be auto-incremented. +- `SpacetimeDB.Unique` - this column should be unique. +- `SpacetimeDB.PrimaryKey` - this column should be a primary key, it implies `SpacetimeDB.Unique` but also allows clients to subscribe to updates via `OnUpdate` which will use this field to match the old and the new version of the row with each other. +- ### Reducers -Attribute `[SpacetimeDB.Reducer]` can be used on any `static void` method to register it as a SpacetimeDB reducer. The method must accept only supported types as arguments. If it throws an exception, those will be caught and reported back to the database runtime. +Attribute `[SpacetimeDB.Reducer]` can be used on any `public static void` method to register it as a SpacetimeDB reducer. The method must accept only supported types as arguments. If it throws an exception, those will be caught and reported back to the database runtime. ```csharp [SpacetimeDB.Reducer] -public static void Add(string name, int age) +public static void Add(ReducerContext ctx, string name, int age) { var person = new Person { Name = name, Age = age }; - person.Insert(); - Log($"Inserted {person.Name} under #{person.Id}"); + ctx.Db.Person.Insert(person); + Log.Info($"Inserted {person.Name} under #{person.Id}"); } ``` -If a reducer has an argument with a type `ReducerContext` (`SpacetimeDB.Runtime.ReducerContext`), it will be provided with event details such as the sender identity (`SpacetimeDB.Runtime.Identity`), sender address (`SpacetimeDB.Runtime.Address?`) and the time (`DateTimeOffset`) of the invocation: +If a reducer has an argument with a type `ReducerContext` (`SpacetimeDB.ReducerContext`), it will be provided with event details such as the sender identity (`SpacetimeDB.Identity`), sender address (`SpacetimeDB.Address?`) and the time (`DateTimeOffset`) of the invocation: ```csharp [SpacetimeDB.Reducer] -public static void PrintInfo(ReducerContext e) +public static void PrintInfo(ReducerContext ctx) { - Log($"Sender identity: {e.Sender}"); - Log($"Sender address: {e.Address}"); - Log($"Time: {e.Time}"); + Log.Info($"Sender identity: {ctx.CallerIdentity}"); + Log.Info($"Sender address: {ctx.CallerAddress}"); + Log.Info($"Time: {ctx.Timestamp}"); } ``` @@ -325,21 +323,23 @@ public static partial class Timers { // Schedule a one-time reducer call by inserting a row. - new SendMessageTimer + var timer = new SendMessageTimer { Text = "bot sending a message", ScheduledAt = ctx.Time.AddSeconds(10), ScheduledId = 1, - }.Insert(); + }; + ctx.Db.SendMessageTimer.Insert(timer); // Schedule a recurring reducer. - new SendMessageTimer + var timer = new SendMessageTimer { Text = "bot sending a message", ScheduledAt = new TimeStamp(10), ScheduledId = 2, - }.Insert(); + }; + ctx.Db.SendMessageTimer.Insert(timer); } } ``` @@ -354,7 +354,7 @@ public static partial class Timers { public string Text; // fields of original struct - [SpacetimeDB.Column(ColumnAttrs.PrimaryKeyAuto)] + [SpacetimeDB.PrimaryKey] public ulong ScheduledId; // unique identifier to be used internally public SpacetimeDB.ScheduleAt ScheduleAt; // Scheduling details (Time or Inteval) @@ -370,34 +370,27 @@ public abstract partial record ScheduleAt: SpacetimeDB.TaggedEnum<(DateTimeOffse These are four special kinds of reducers that can be used to respond to module lifecycle events. They're stored in the `SpacetimeDB.Module.ReducerKind` class and can be used as an argument to the `[SpacetimeDB.Reducer]` attribute: - `ReducerKind.Init` - this reducer will be invoked when the module is first published. -- `ReducerKind.Update` - this reducer will be invoked when the module is updated. -- `ReducerKind.Connect` - this reducer will be invoked when a client connects to the database. -- `ReducerKind.Disconnect` - this reducer will be invoked when a client disconnects from the database. +- `ReducerKind.ClientConnected` - this reducer will be invoked when a client connects to the database. +- `ReducerKind.ClientDisconnected` - this reducer will be invoked when a client disconnects from the database. Example: ````csharp [SpacetimeDB.Reducer(ReducerKind.Init)] -public static void Init() -{ - Log("...and we're live!"); -} - -[SpacetimeDB.Reducer(ReducerKind.Update)] -public static void Update() +public static void Init(ReducerContext ctx) { - Log("Update get!"); + Log.Info("...and we're live!"); } -[SpacetimeDB.Reducer(ReducerKind.Connect)] -public static void OnConnect(DbEventArgs ctx) +[SpacetimeDB.Reducer(ReducerKind.ClientConnected)] +public static void OnConnect(ReducerContext ctx) { - Log($"{ctx.Sender} has connected from {ctx.Address}!"); + Log.Info($"{ctx.CallerIdentity} has connected from {ctx.CallerAddress}!"); } -[SpacetimeDB.Reducer(ReducerKind.Disconnect)] -public static void OnDisconnect(DbEventArgs ctx) +[SpacetimeDB.Reducer(ReducerKind.ClientDisconnected)] +public static void OnDisconnect(ReducerContext ctx) { - Log($"{ctx.Sender} has disconnected."); + Log.Info($"{ctx.CallerIdentity} has disconnected."); }``` ```` From 2c74622c37e1f7646be6d11882dd8d0d4ce1bbd8 Mon Sep 17 00:00:00 2001 From: Dillon Shaffer <46535284+Molkars@users.noreply.github.com> Date: Thu, 14 Nov 2024 11:06:32 -0700 Subject: [PATCH 4/6] Update index.md --- docs/modules/c-sharp/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/c-sharp/index.md b/docs/modules/c-sharp/index.md index 552ede24..98014b0b 100644 --- a/docs/modules/c-sharp/index.md +++ b/docs/modules/c-sharp/index.md @@ -27,7 +27,7 @@ public static partial class Module // SpacetimeDB allows you to specify column attributes / constraints such as // "this field should be unique" or "this field should get automatically assigned auto-incremented value". [SpacetimeDB.Unique] - [SpacetimeDB.PrimaryKey] + [SpacetimeDB.AutoInc] public int Id; public string Name; public int Age; From e262eb4bd45bf53c07a1c4eaa23db11d6a94a1b2 Mon Sep 17 00:00:00 2001 From: Dillon Shaffer <46535284+Molkars@users.noreply.github.com> Date: Thu, 14 Nov 2024 11:10:21 -0700 Subject: [PATCH 5/6] Update index.md --- docs/modules/c-sharp/index.md | 45 +++++++++++++---------------------- 1 file changed, 16 insertions(+), 29 deletions(-) diff --git a/docs/modules/c-sharp/index.md b/docs/modules/c-sharp/index.md index 98014b0b..90b90eda 100644 --- a/docs/modules/c-sharp/index.md +++ b/docs/modules/c-sharp/index.md @@ -78,13 +78,12 @@ First of all, logging as we're likely going to use it a lot for debugging and re Supported log levels are provided by different methods on the `Log` class: ```csharp - public static void Trace(string message); - public static void Debug(string message); - public static void Info(string message); - public static void Warn(string message); - public static void Error(string message); - public static void Exception(string message); -} +public static void Trace(string message); +public static void Debug(string message); +public static void Info(string message); +public static void Warn(string message); +public static void Error(string message); +public static void Exception(string message); ``` You should use `Log.Info` by default. @@ -220,38 +219,26 @@ public partial class ReducerCtx.Db.Person // Inserts current instance as a new row into the table. public void Insert(Person row); - // Returns an iterator over all rows in the table, e.g.: - // `for (var person in Person.Iter()) { ... }` - public static IEnumerable Iter(); - - // Returns an iterator over all rows in the table that match the given filter, e.g.: - // `for (var person in Person.Query(p => p.Age >= 18)) { ... }` - public static IEnumerable Query(Expression> filter); + // Deletes current instance from the table + public void Delete(Person row); - // Generated for each column with the `Indexed` attribute: + // Gets the number of rows in the table + public ulong Count { get { ... } }; - public static class Name { - // Returns an iterator over all rows in the table that have the given value in the `Name` column. - public static IEnumerable Filter(string name); - public static void Update(Person row); - public static Person Find(string name); - } - public static class Name { - // Returns an iterator over all rows in the table that have the given value in the `Name` column. - public static IEnumerable Filter(string name); - } - public static IEnumerable FilterByAge(int age); + // Returns an iterator over all rows in the table, e.g.: + // `for (var person in Person.Iter()) { ... }` + public IEnumerable Iter(); // Generated for each unique column: public static partial class Id { // Find a `Person` based on `id == $key` - public static Person? Find(int key); + public Person? Find(int key); // Delete a row by `key` on the row - public static bool Delete(int key); + public bool Delete(int key); // Update based on the `id` of the row - public static bool Update(Person row); + public bool Update(Person row); } } ``` From 138636d5457999a72e8f83fad5b884cbc66deb21 Mon Sep 17 00:00:00 2001 From: Dillon Shaffer <46535284+Molkars@users.noreply.github.com> Date: Thu, 14 Nov 2024 11:10:58 -0700 Subject: [PATCH 6/6] Update index.md --- docs/modules/c-sharp/index.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/modules/c-sharp/index.md b/docs/modules/c-sharp/index.md index 90b90eda..768170ac 100644 --- a/docs/modules/c-sharp/index.md +++ b/docs/modules/c-sharp/index.md @@ -370,13 +370,13 @@ public static void Init(ReducerContext ctx) } [SpacetimeDB.Reducer(ReducerKind.ClientConnected)] -public static void OnConnect(ReducerContext ctx) +public static void Connect(ReducerContext ctx) { Log.Info($"{ctx.CallerIdentity} has connected from {ctx.CallerAddress}!"); } [SpacetimeDB.Reducer(ReducerKind.ClientDisconnected)] -public static void OnDisconnect(ReducerContext ctx) +public static void Disconnect(ReducerContext ctx) { Log.Info($"{ctx.CallerIdentity} has disconnected."); }```