Today we've released query builders for Rust and TypeScript modules. The purpose of the query builder API is so that you can write views that will take advantage of the unique performance guarantees of SpacetimeDB's query engine, particularly for realtime subscription updates.
The query builder also now allows you to iterate or scan a table in a view, something that previously wasn't possible using only the index accessors exposed by ViewContext and AnonymousViewContext.
The query builder exposes the following query operators:
.where()
Used for filtering. Equivalent to aWHEREcondition in SQL..leftSemijoin()
Equivalent to an inner join in sql where a row is return from thelhsonly if it matches with a row on therhs..rightSemijoin()
Equivalent to an inner join in sql where a row is return from therhsonly if it matches with a row on thelhs.
Examples (Rust)
use spacetimedb::{Identity, Query, Table, ViewContext, AnonymousViewContext};
#[spacetimedb::table(name = player_state)]
pub struct PlayerState {
#[unique]
player_id: u64,
online: bool,
}
#[spacetimedb::table(name = player_internal)]
pub struct Player {
#[auto_inc]
#[primary_key]
id: u64,
#[unique]
identity: Identity,
name: String,
#[index(btree)]
age: u8,
}
#[spacetimedb::table(name = moderator_internal)]
pub struct Moderator {
#[unique]
player_id: u64,
}
/// Returns all players.
/// Equivalent to `SELECT * FROM player_internal`.
#[spacetimedb::view(name = player, public)]
fn player(ctx: &AnonymousViewContext) -> Query<Player> {
ctx.from.player_internal().build()
}
/// Returns the caller's player.
/// Equivalent to `SELECT * FROM player_internal WHERE "identity" = :sender`.
#[spacetimedb::view(name = my_player, public)]
fn my_player(ctx: &ViewContext) -> Query<Player> {
ctx.from.player_internal().r#where(|p| p.identity.eq(ctx.sender)).build()
}
/// Returns only online players.
/// Equivalent to:
/// ```sql
/// SELECT q.*
/// FROM player_state p JOIN player_internal q ON p.player_id = q.id
/// WHERE p.online
/// ```
#[spacetimedb::view(name = online_player, public)]
fn online_player(ctx: &AnonymousViewContext) -> Query<Player> {
ctx.from
.player_state()
.r#where(|p| p.online.eq(true))
.right_semijoin(ctx.from.player_internal(), |(p, q)| p.player_id.eq(q.id))
.build()
}
/// Returns only the caller's player if online.
/// Equivalent to:
/// ```sql
/// SELECT q.*
/// FROM player_state p JOIN player_internal q ON p.player_id = q.id
/// WHERE p.online AND q.identity = :sender
/// ```
#[spacetimedb::view(name = my_online_player, public)]
fn my_online_player(ctx: &ViewContext) -> Query<Player> {
ctx.from
.player_state()
.r#where(|p| p.online.eq(true))
.right_semijoin(ctx.from.player_internal(), |(p, q)| p.player_id.eq(q.id))
.r#where(|p| p.identity.eq(ctx.sender))
.build()
}
/// Returns the moderators.
/// Equivalent to:
/// ```sql
/// SELECT p.* FROM player_internal p JOIN moderator_internal m ON p.id = m.player_id
/// ```
#[spacetimedb::view(name = moderator, public)]
fn moderator(ctx: &AnonymousViewContext) -> Query<Player> {
ctx.from
.player_internal()
.left_semijoin(ctx.from.moderator_internal(), |(p, m)| p.id.eq(m.player_id))
.build()
}Examples (TypeScript)
import { schema, table, t, type RowObj } from 'spacetimedb/server';
const playerState = table('playerState', {
playerId: t.u64().unique(),
online: t.bool(),
});
const playerInternal = table('playerInternal', {
id: t.u64().primaryKey().autoInc(),
identity: t.identity().unique(),
name: t.string(),
age: t.u8().index('btree'),
});
const spacetimedb = schema(playerState, playerInternal);
spacetimedb.view(
{ name: 'my_online_player', public: true },
t.array(playerInternal.row()),
ctx => {
return ctx.from.playerState
.where(p => p.online.eq(true))
.rightSemijoin(ctx.from.playerInternal, (p, q) => p.playerId.eq(q.id))
.where(p => p.identity.eq(ctx.sender))
.build();
}
);Bug Fixes
- Fixes an issue with the
--delete-data=on-conflictflag ofspacetimedb publish - Fixes an issue where databases were returning 400/500 errors after publishing with
-c - Fixes an issue where
on_insertandon_deletewere not firing correctly for per-client (ViewContext) views
What's Changed
- Delete duplicated docs folders by @gefjon in #3780
- Fixes reported issues with the TypeScript SDK by @cloutiertyler in #3737
- Fix some typescript issues by @coolreader18 in #3775
- Split Unity and C# tests into separate jobs by @jdetter in #3779
- Update typescript package size limits by @jdetter in #3786
- Add docs for procedures by @gefjon in #3766
- Actually report reducer fuel used by @drogus in #3799
- Fix view rewrite for delta tables by @joshua-spacetime in #3801
- Remove race condition from sdk test by @joshua-spacetime in #3804
- Implement DbContext for AnonymousViewContext and ViewContext by @tamaro-skaljic in #3787
- Fixes docs links by @cloutiertyler in #3803
- C# Views - Use Name from ViewAttribute instead of Method Name by @chutch1122 in #3792
- Remove duplicate assertSql in smoke test by @mamcx in #3588
- Docs: Update docs nav height to 56px by @clockwork-tien in #3788
- [TS] Fix
developmentexports breaking NextJS by @kistz in #3796 - [TS] Call registerType for procedure params by @coolreader18 in #3806
- CI - Skip the Unity testsuite on external PRs by @bfops in #3805
- Bump versions to 1.11.0 by @bfops in #3808
- Added and tested procedure docs for Unreal C++ & Unreal Blueprint by @JasonAtClockwork in #3810
- Update view ABI to support returning queries by @jsdt in #3685
- [Rust] Module-side query builder types by @Shubham8287 in #3797
- [Rust] update module bindings to use new view abi by @joshua-spacetime in #3819
- Update wasmtime to v39 by @coolreader18 in #3818
- [Rust] Query builder Integration. by @Shubham8287 in #3823
- Store
SubscriptionMetricsforUpdate,Subscribe,UnsubscribeinModuleSubscriptionsby @Centril in #3821 - smoketests: Adjust test_enable_disable_replication test by @kim in #3822
- [TS] Implement TextEncoder/TextDecoder with native code by @coolreader18 in #3800
- Debug "stuck module" issue by @kim in #3813
- Fixes issues with
--delete-data=on-conflictby @cloutiertyler in #3730 - Add a typescript query builder for views by @jsdt in #3812
New Contributors
- @tamaro-skaljic made their first contribution in #3787
- @chutch1122 made their first contribution in #3792
- @kistz made their first contribution in #3796
Full Changelog: v1.10.0...v1.11.0