Skip to content

Commit 1930270

Browse files
Docs Update for C++ [3/4] (#4163)
# Description of Changes In order to give reviewers a chance to finish in one session the docs are getting split up for the C++ update. This pass contains the following section update: - Functions # API and ABI breaking changes N/A # Expected complexity level and risk 1 - Just documentation additions # Testing - [x] Manually tested each block
1 parent 2c8aad8 commit 1930270

File tree

6 files changed

+833
-0
lines changed

6 files changed

+833
-0
lines changed

docs/docs/00200-core-concepts/00200-functions/00300-reducers/00300-reducers.md

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,31 @@ use spacetimedb::Table;
108108
If you see errors like "no method named `try_insert` found", add this import.
109109
:::
110110

111+
</TabItem>
112+
<TabItem value="cpp" label="C++">
113+
114+
Use the `SPACETIMEDB_REDUCER` macro on a function:
115+
116+
```cpp
117+
#include <spacetimedb.h>
118+
using namespace SpacetimeDB;
119+
120+
SPACETIMEDB_REDUCER(create_user, ReducerContext ctx, std::string name, std::string email) {
121+
// Validate input
122+
if (name.empty()) {
123+
return Err("Name cannot be empty");
124+
}
125+
126+
// Modify tables
127+
User user{0, name, email}; // 0 for id - auto-increment will assign
128+
ctx.db[user].insert(user);
129+
130+
return Ok();
131+
}
132+
```
133+
134+
Reducers must take `ReducerContext ctx` as their first parameter. Additional parameters can be any registered types. Reducers return `ReducerResult` (which is `Outcome<void>`): use `Ok()` on success or `Err(message)` on error for convenience.
135+
111136
</TabItem>
112137
</Tabs>
113138
@@ -161,6 +186,17 @@ ctx.db.user().insert(User {
161186
});
162187
```
163188

189+
</TabItem>
190+
<TabItem value="cpp" label="C++">
191+
192+
```cpp
193+
ctx.db[user].insert(User{
194+
0, // auto-increment will assign
195+
"Alice",
196+
197+
});
198+
```
199+
164200
</TabItem>
165201
</Tabs>
166202

@@ -204,6 +240,17 @@ if let Some(user) = ctx.db.user().id().find(123) {
204240
let by_email = ctx.db.user().email().find("[email protected]");
205241
```
206242

243+
</TabItem>
244+
<TabItem value="cpp" label="C++">
245+
246+
```cpp
247+
if (auto user = ctx.db[user_id].find(123)) {
248+
LOG_INFO("Found: " + user->name);
249+
}
250+
251+
auto by_email = ctx.db[user_email].find("[email protected]");
252+
```
253+
207254
</TabItem>
208255
</Tabs>
209256

@@ -239,6 +286,15 @@ for user in ctx.db.user().name().filter("Alice") {
239286
}
240287
```
241288

289+
</TabItem>
290+
<TabItem value="cpp" label="C++">
291+
292+
```cpp
293+
for (const auto& user : ctx.db[user_name].filter("Alice")) {
294+
LOG_INFO("User " + std::to_string(user.id) + ": " + user.email);
295+
}
296+
```
297+
242298
</TabItem>
243299
</Tabs>
244300

@@ -279,6 +335,16 @@ if let Some(mut user) = ctx.db.user().id().find(123) {
279335
}
280336
```
281337

338+
</TabItem>
339+
<TabItem value="cpp" label="C++">
340+
341+
```cpp
342+
if (auto user = ctx.db[user_id].find(123)) {
343+
user->name = "Bob";
344+
ctx.db[user_id].update(*user);
345+
}
346+
```
347+
282348
</TabItem>
283349
</Tabs>
284350

@@ -322,6 +388,22 @@ let deleted = ctx.db.user().name().delete("Alice");
322388
log::info!("Deleted {} row(s)", deleted);
323389
```
324390

391+
</TabItem>
392+
<TabItem value="cpp" label="C++">
393+
394+
```cpp
395+
// Delete by primary key
396+
ctx.db[user_id].delete_by_key(123);
397+
398+
// Delete all matching an indexed column
399+
uint32_t deleted = 0;
400+
for (const auto& user : ctx.db[user_name].filter("Alice")) {
401+
ctx.db[user_id].delete_by_key(user.id);
402+
deleted++;
403+
}
404+
LOG_INFO("Deleted " + std::to_string(deleted) + " row(s)");
405+
```
406+
325407
</TabItem>
326408
</Tabs>
327409
@@ -357,6 +439,15 @@ for user in ctx.db.user().iter() {
357439
}
358440
```
359441

442+
</TabItem>
443+
<TabItem value="cpp" label="C++">
444+
445+
```cpp
446+
for (const auto& user : ctx.db[user]) {
447+
LOG_INFO(std::to_string(user.id) + ": " + user.name);
448+
}
449+
```
450+
360451
</TabItem>
361452
</Tabs>
362453

@@ -388,6 +479,14 @@ let total = ctx.db.user().count();
388479
log::info!("Total users: {}", total);
389480
```
390481

482+
</TabItem>
483+
<TabItem value="cpp" label="C++">
484+
485+
```cpp
486+
auto total = ctx.db[user].count();
487+
LOG_INFO("Total users: " + std::to_string(total));
488+
```
489+
391490
</TabItem>
392491
</Tabs>
393492
@@ -553,6 +652,48 @@ fn queue_fetch(ctx: &ReducerContext, url: String) {
553652
}
554653
```
555654

655+
</TabItem>
656+
<TabItem value="cpp" label="C++">
657+
658+
```cpp
659+
#define SPACETIMEDB_UNSTABLE_FEATURES
660+
#include <spacetimedb.h>
661+
using namespace SpacetimeDB;
662+
663+
// Define a table to store scheduled tasks
664+
struct FetchSchedule {
665+
uint64_t scheduled_id;
666+
ScheduleAt scheduled_at;
667+
std::string url;
668+
};
669+
SPACETIMEDB_STRUCT(FetchSchedule, scheduled_id, scheduled_at, url);
670+
SPACETIMEDB_TABLE(FetchSchedule, fetch_schedule, Private);
671+
FIELD_PrimaryKeyAutoInc(fetch_schedule, scheduled_id);
672+
673+
// Register the table for scheduling (column 1 = scheduled_at field, 0-based index)
674+
SPACETIMEDB_SCHEDULE(fetch_schedule, 1, fetch_external_data);
675+
676+
// The procedure to be scheduled - called automatically when the time arrives
677+
SPACETIMEDB_PROCEDURE(uint32_t, fetch_external_data, ProcedureContext ctx, FetchSchedule schedule) {
678+
LOG_INFO("Fetching data from: " + schedule.url);
679+
// Process response...
680+
return 0; // Success
681+
}
682+
683+
// From a reducer, schedule the procedure by inserting into the schedule table
684+
SPACETIMEDB_REDUCER(queue_fetch, ReducerContext ctx, std::string url) {
685+
auto scheduled_at = ScheduleAt(TimeDuration::from_seconds(0)); // Run immediately
686+
FetchSchedule fetch_task{
687+
0, // scheduled_id - auto-increment will assign
688+
scheduled_at, // When to execute
689+
url
690+
};
691+
ctx.db[fetch_schedule].insert(fetch_task);
692+
LOG_INFO("Fetch scheduled for URL: " + url);
693+
return Ok();
694+
}
695+
```
696+
556697
</TabItem>
557698
</Tabs>
558699

docs/docs/00200-core-concepts/00200-functions/00300-reducers/00400-reducer-context.md

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,27 @@ fn create_user(ctx: &ReducerContext, name: String) {
8181
}
8282
```
8383

84+
</TabItem>
85+
<TabItem value="cpp" label="C++">
86+
87+
```cpp
88+
#include <spacetimedb.h>
89+
using namespace SpacetimeDB;
90+
91+
struct User {
92+
uint64_t id;
93+
std::string name;
94+
};
95+
SPACETIMEDB_STRUCT(User, id, name);
96+
SPACETIMEDB_TABLE(User, user, Public);
97+
FIELD_PrimaryKeyAutoInc(user, id);
98+
99+
SPACETIMEDB_REDUCER(create_user, ReducerContext ctx, std::string name) {
100+
ctx.db[user].insert(User{0, name});
101+
return Ok();
102+
}
103+
```
104+
84105
</TabItem>
85106
</Tabs>
86107
@@ -184,6 +205,35 @@ fn update_score(ctx: &ReducerContext, new_score: u32) {
184205
}
185206
```
186207

208+
</TabItem>
209+
<TabItem value="cpp" label="C++">
210+
211+
```cpp
212+
#include <spacetimedb.h>
213+
using namespace SpacetimeDB;
214+
215+
struct Player {
216+
Identity identity;
217+
std::string name;
218+
uint32_t score;
219+
};
220+
SPACETIMEDB_STRUCT(Player, identity, name, score);
221+
SPACETIMEDB_TABLE(Player, player, Public);
222+
FIELD_PrimaryKey(player, identity);
223+
224+
SPACETIMEDB_REDUCER(update_score, ReducerContext ctx, uint32_t new_score) {
225+
// Get the caller's identity
226+
auto caller = ctx.sender;
227+
228+
// Find and update their player record
229+
if (auto player = ctx.db[player_identity].find(caller)) {
230+
player->score = new_score;
231+
ctx.db[player_identity].update(*player);
232+
}
233+
return Ok();
234+
}
235+
```
236+
187237
</TabItem>
188238
</Tabs>
189239
@@ -298,6 +348,36 @@ fn send_reminder(ctx: &ReducerContext, task: ScheduledTask) {
298348
}
299349
```
300350

351+
</TabItem>
352+
<TabItem value="cpp" label="C++">
353+
354+
```cpp
355+
#include <spacetimedb.h>
356+
using namespace SpacetimeDB;
357+
358+
struct ScheduledTask {
359+
uint64_t task_id;
360+
ScheduleAt scheduled_at;
361+
std::string message;
362+
};
363+
SPACETIMEDB_STRUCT(ScheduledTask, task_id, scheduled_at, message);
364+
SPACETIMEDB_TABLE(ScheduledTask, scheduled_task, Private);
365+
FIELD_PrimaryKeyAutoInc(scheduled_task, task_id);
366+
367+
// Register the table for scheduling (column 1 = scheduled_at field, 0-based index)
368+
SPACETIMEDB_SCHEDULE(scheduled_task, 1, send_reminder);
369+
370+
SPACETIMEDB_REDUCER(send_reminder, ReducerContext ctx, ScheduledTask task) {
371+
// Only allow the scheduler (module identity) to call this
372+
if (ctx.sender != ctx.identity()) {
373+
return Err("This reducer can only be called by the scheduler");
374+
}
375+
376+
LOG_INFO("Reminder: " + task.message);
377+
return Ok();
378+
}
379+
```
380+
301381
</TabItem>
302382
</Tabs>
303383
@@ -346,4 +426,23 @@ TypeScript uses `Math.random()` for random number generation, which is automatic
346426
- `random<T>() -> T` - Generate a single random value
347427
- `sender_auth() -> &AuthCtx` - Get authorization context for the caller (includes JWT claims and internal call detection)
348428
</TabItem>
429+
<TabItem value="cpp" label="C++">
430+
431+
| Property | Type | Description |
432+
| --------------- | ------------------------------ | ----------------------------------------------- |
433+
| `db[table]` | `Table<T>` | Access to a specific table's operations |
434+
| `sender` | `Identity` | Identity of the caller |
435+
| `timestamp` | `Timestamp` | Time when the reducer was invoked |
436+
| `connection_id` | `std::optional<ConnectionId>` | Connection ID of the caller, if available |
437+
438+
**Methods:**
439+
440+
- `identity() -> Identity` - Get the module's identity
441+
- `rng() -> StdbRng&` - Get the random number generator (deterministic and reproducible)
442+
- `sender_auth() -> const AuthCtx&` - Get authorization context for the caller (includes JWT claims and internal call detection)
443+
444+
:::note
445+
C++ uses the `std::optional` type for the `connection_id` to represent values that may not be present. The `rng()` method returns a deterministic random number generator that is seeded consistently across all nodes.
446+
:::
447+
</TabItem>
349448
</Tabs>

0 commit comments

Comments
 (0)