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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 88 additions & 0 deletions docs/docs/00200-core-concepts/00300-tables.md
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,24 @@ pub struct Person {
The `pub` modifier on the struct follows normal Rust visibility rules and has no meaning to SpacetimeDB. It controls whether the struct is accessible from other Rust modules in your crate, not whether the table is public to clients. Use the `public` attribute in `#[spacetimedb::table]` to control client visibility.
:::

</TabItem>
<TabItem value="cpp" label="C++">

Register the struct with `SPACETIMEDB_STRUCT`, the table with `SPACETIMEDB_TABLE`, then add field constraints:

```cpp
struct Person {
uint32_t id;
std::string name;
std::string email;
};
SPACETIMEDB_STRUCT(Person, id, name, email)
SPACETIMEDB_TABLE(Person, person, Public)
FIELD_PrimaryKeyAutoInc(person, id)
FIELD_Index(person, name)
FIELD_Unique(person, email)
```

</TabItem>
</Tabs>

Expand Down Expand Up @@ -239,6 +257,29 @@ ctx.db.player().insert(Player { /* ... */ });
| `name = player` | `ctx.db.player()` |
| `name = game_session` | `ctx.db.game_session()` |

</TabItem>
<TabItem value="cpp" label="C++">

The accessor name matches the table identifier you pass to `SPACETIMEDB_TABLE`:

```cpp
struct PlayerScores {
uint64_t id;
};
SPACETIMEDB_STRUCT(PlayerScores, id)
SPACETIMEDB_TABLE(PlayerScores, player_scores, Public)
FIELD_PrimaryKeyAutoInc(player_scores, id)

// Accessor matches the table identifier
ctx.db[player_scores].insert(PlayerScores{ /* ... */ });
```

| Table Identifier | Accessor |
|------------------|----------|
| `user` | `ctx.db[user]` |
| `player_scores` | `ctx.db[player_scores]` |
| `game_session` | `ctx.db[game_session]` |

</TabItem>
</Tabs>

Expand All @@ -251,6 +292,7 @@ Use idiomatic naming conventions for each language:
| **TypeScript** | snake_case | `'player_score'` | `ctx.db.playerScore` |
| **C#** | PascalCase | `Name = "PlayerScore"` | `ctx.Db.PlayerScore` |
| **Rust** | lower_snake_case | `name = player_score` | `ctx.db.player_score()` |
| **C++** | lower_snake_case | `player_score` | `ctx.db[player_score]` |

These conventions align with each language's standard style guides and make your code feel natural within its ecosystem.

Expand Down Expand Up @@ -291,6 +333,25 @@ pub struct User { /* ... */ }
pub struct Secret { /* ... */ }
```

</TabItem>
<TabItem value="cpp" label="C++">

```cpp
struct User {
uint64_t id;
};
SPACETIMEDB_STRUCT(User, id)
SPACETIMEDB_TABLE(User, user, Public)
FIELD_PrimaryKeyAutoInc(user, id)

struct Secret {
uint64_t id;
};
SPACETIMEDB_STRUCT(Secret, id)
SPACETIMEDB_TABLE(Secret, secret, Private)
FIELD_PrimaryKeyAutoInc(secret, id)
```

</TabItem>
</Tabs>

Expand Down Expand Up @@ -388,6 +449,33 @@ if let Some(player) = ctx.db.logged_out_player().identity().find(&ctx.sender) {
}
```

</TabItem>
<TabItem value="cpp" label="C++">

Apply multiple `SPACETIMEDB_TABLE` macros to the same struct:

```cpp
struct Player {
Identity identity;
int32_t player_id;
std::string name;
};
SPACETIMEDB_STRUCT(Player, identity, player_id, name)
SPACETIMEDB_TABLE(Player, player, Public)
SPACETIMEDB_TABLE(Player, logged_out_player, Private)
FIELD_PrimaryKey(player, identity)
FIELD_PrimaryKey(logged_out_player, identity)
FIELD_UniqueAutoInc(player, player_id)
FIELD_UniqueAutoInc(logged_out_player, player_id)

// Move between tables
auto maybe_logged_out = ctx.db[logged_out_player_identity].find(ctx.sender);
if (maybe_logged_out) {
ctx.db[player].insert(*maybe_logged_out);
ctx.db[logged_out_player_identity].delete_by_key(ctx.sender);
}
```

</TabItem>
</Tabs>

Expand Down
75 changes: 75 additions & 0 deletions docs/docs/00200-core-concepts/00300-tables/00200-column-types.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,29 @@ These optimizations apply across all supported languages.
| Special | `TimeDuration` | Relative duration in microseconds |
| Special | `ScheduleAt` | When a scheduled reducer should execute |

</TabItem>
<TabItem value="cpp" label="C++">

| Category | Type | Description |
|----------|------|-------------|
| Primitive | `bool` | Boolean value |
| Primitive | `std::string` | UTF-8 string |
| Primitive | `float` | 32-bit floating point |
| Primitive | `double` | 64-bit floating point |
| Primitive | `int8_t`, `int16_t`, `int32_t`, `int64_t` | Signed integers (8-bit to 64-bit) |
| Primitive | `uint8_t`, `uint16_t`, `uint32_t`, `uint64_t` | Unsigned integers (8-bit to 64-bit) |
| Primitive | `SpacetimeDB::i128`, `SpacetimeDB::i256` | Signed 128-bit and 256-bit integers |
| Primitive | `SpacetimeDB::u128`, `SpacetimeDB::u256` | Unsigned 128-bit and 256-bit integers |
| Composite | `struct` with `SPACETIMEDB_STRUCT` | Product type for nested data |
| Composite | `SPACETIMEDB_ENUM` | Sum type (tagged union) |
| Composite | `std::vector<T>` | Vector of elements |
| Composite | `std::optional<T>` | Optional value |
| Special | `Identity` | Unique identity for authentication |
| Special | `ConnectionId` | Client connection identifier |
| Special | `Timestamp` | Absolute point in time (microseconds since Unix epoch) |
| Special | `TimeDuration` | Relative duration in microseconds |
| Special | `ScheduleAt` | When a scheduled reducer should execute |

</TabItem>
</Tabs>

Expand Down Expand Up @@ -289,5 +312,57 @@ pub struct Player {
}
```

</TabItem>
<TabItem value="cpp" label="C++">

```cpp
// Define a nested struct type for coordinates
struct Coordinates {
double x;
double y;
double z;
};
SPACETIMEDB_STRUCT(Coordinates, x, y, z)

// Define unit types for enum variants
SPACETIMEDB_UNIT_TYPE(Active)
SPACETIMEDB_UNIT_TYPE(Inactive)

// Define an enum for status
SPACETIMEDB_ENUM(PlayerStatus,
(Active, Active),
(Inactive, Inactive),
(Suspended, std::string)
)

struct Player {
// Primitive types
uint64_t id;
std::string name;
uint8_t level;
uint32_t experience;
float health;
int64_t score;
bool is_online;

// Composite types
Coordinates position;
PlayerStatus status;
std::vector<uint32_t> inventory;
std::optional<uint64_t> guild_id;

// Special types
Identity owner;
std::optional<ConnectionId> connection;
Timestamp created_at;
TimeDuration play_time;
};
SPACETIMEDB_STRUCT(Player, id, name, level, experience, health, score, is_online,
position, status, inventory, guild_id,
owner, connection, created_at, play_time)
SPACETIMEDB_TABLE(Player, player, Public)
FIELD_PrimaryKeyAutoInc(player, id)
```

</TabItem>
</Tabs>
87 changes: 86 additions & 1 deletion docs/docs/00200-core-concepts/00300-tables/00210-file-storage.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ SpacetimeDB can store binary data directly in table columns, making it suitable

## Storing Binary Data Inline

Store binary data using `Vec<u8>` (Rust), `List<byte>` (C#), or `t.array(t.u8())` (TypeScript). This approach keeps data within the database, ensuring it participates in transactions and real-time updates.
Store binary data using `Vec<u8>` (Rust), `List<byte>` (C#), `std::vector<uint8_t>` (C++), or `t.array(t.u8())` (TypeScript). This approach keeps data within the database, ensuring it participates in transactions and real-time updates.

<Tabs groupId="server-language" queryString>
<TabItem value="typescript" label="TypeScript">
Expand Down Expand Up @@ -120,6 +120,37 @@ pub fn upload_avatar(
}
```

</TabItem>
<TabItem value="cpp" label="C++">

```cpp
struct UserAvatar {
uint64_t user_id;
std::string mime_type;
std::vector<uint8_t> data; // Binary data stored inline
Timestamp uploaded_at;
};
SPACETIMEDB_STRUCT(UserAvatar, user_id, mime_type, data, uploaded_at)
SPACETIMEDB_TABLE(UserAvatar, user_avatar, Public)
FIELD_PrimaryKey(user_avatar, user_id)

SPACETIMEDB_REDUCER(upload_avatar, ReducerContext ctx,
uint64_t user_id, std::string mime_type, std::vector<uint8_t> data) {
// Delete existing avatar if present
ctx.db[user_avatar_user_id].delete_by_key(user_id);

// Insert new avatar
ctx.db[user_avatar].insert(UserAvatar{
.user_id = user_id,
.mime_type = mime_type,
.data = data,
.uploaded_at = ctx.timestamp,
});

return Ok();
}
```

</TabItem>
</Tabs>

Expand Down Expand Up @@ -273,6 +304,41 @@ pub fn register_document(
}
```

</TabItem>
<TabItem value="cpp" label="C++">

```cpp
struct Document {
uint64_t id;
Identity owner_id;
std::string filename;
std::string mime_type;
uint64_t size_bytes;
std::string storage_url; // Reference to external storage
Timestamp uploaded_at;
};
SPACETIMEDB_STRUCT(Document, id, owner_id, filename, mime_type, size_bytes, storage_url, uploaded_at)
SPACETIMEDB_TABLE(Document, document, Public)
FIELD_PrimaryKeyAutoInc(document, id)
FIELD_Index(document, owner_id)

// Called after uploading file to external storage
SPACETIMEDB_REDUCER(register_document, ReducerContext ctx,
std::string filename, std::string mime_type, uint64_t size_bytes, std::string storage_url) {
ctx.db[document].insert(Document{
.id = 0, // auto-increment
.owner_id = ctx.sender,
.filename = filename,
.mime_type = mime_type,
.size_bytes = size_bytes,
.storage_url = storage_url,
.uploaded_at = ctx.timestamp,
});

return Ok();
}
```

</TabItem>
</Tabs>

Expand Down Expand Up @@ -735,6 +801,25 @@ pub struct Image {
}
```

</TabItem>
<TabItem value="cpp" label="C++">

```cpp
struct Image {
uint64_t id;
Identity owner_id;
std::vector<uint8_t> thumbnail; // Small preview stored inline
std::string original_url; // Large original in external storage
uint32_t width;
uint32_t height;
Timestamp uploaded_at;
};
SPACETIMEDB_STRUCT(Image, id, owner_id, thumbnail, original_url, width, height, uploaded_at)
SPACETIMEDB_TABLE(Image, image, Public)
FIELD_PrimaryKeyAutoInc(image, id)
FIELD_Index(image, owner_id)
```

</TabItem>
</Tabs>

Expand Down
23 changes: 23 additions & 0 deletions docs/docs/00200-core-concepts/00300-tables/00230-auto-increment.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,29 @@ fn add_post(ctx: &ReducerContext, title: String) -> Result<(), String> {

Use the `#[auto_inc]` attribute.

</TabItem>
<TabItem value="cpp" label="C++">

```cpp
struct Post {
uint64_t id;
std::string title;
};
SPACETIMEDB_STRUCT(Post, id, title)
SPACETIMEDB_TABLE(Post, post, Public)
FIELD_PrimaryKeyAutoInc(post, id)

SPACETIMEDB_REDUCER(add_post, ReducerContext ctx, std::string title) {
// Pass 0 for the auto-increment field
auto inserted = ctx.db[post].insert(Post{0, title});
// inserted.id now contains the assigned value
LOG_INFO("Created post with id: " + std::to_string(inserted.id));
return Ok();
}
```

Use the `FIELD_PrimaryKeyAutoInc(table, field)` macro after table registration.

</TabItem>
</Tabs>

Expand Down
Loading
Loading