SpacetimeDB: subscription-erfaringer, refresh med enrichFromPg, whitespace-fiks

- Dokumentert at subscriptions ikke støtter JOINs (feiler stille)
- refresh() kaller enrichFromPg() for å hente fersk metadata fra PG
- Whitespace-normalisering i autogenererte module_bindings

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
vegard 2026-03-16 09:18:45 +01:00
parent 531defe986
commit 88a22e131b
11 changed files with 128 additions and 104 deletions

View file

@ -107,5 +107,26 @@ Ny modell:
- SyncOutbox-events prosesseres hver 1. sekund - SyncOutbox-events prosesseres hver 1. sekund
- Støtter: `messages/insert`, `messages/delete`, `messages/update`, `message_reactions/insert`, `message_reactions/delete` - Støtter: `messages/insert`, `messages/delete`, `messages/update`, `message_reactions/insert`, `message_reactions/delete`
## 7. Subscription-begrensninger
**SpacetimeDB-subscriptions støtter IKKE JOINs.** En subscription-query som `SELECT mr.* FROM message_reaction mr JOIN chat_message cm ON cm.id = mr.message_id WHERE ...` feiler stille — `onApplied` kalles aldri, og ingen data vises.
Bruk kun enkle `SELECT * FROM tabell WHERE ...`-queries i `.subscribe([...])`. Filtrer heller klient-side etter at data er lastet.
Eksempel:
```typescript
// FEIL — feiler stille, ingen data
.subscribe([
`SELECT * FROM chat_message WHERE channel_id = '${id}'`,
`SELECT mr.* FROM message_reaction mr JOIN chat_message cm ON cm.id = mr.message_id WHERE cm.channel_id = '${id}'`
]);
// RIKTIG — last alle reaksjoner, filtrer i koden
.subscribe([
`SELECT * FROM chat_message WHERE channel_id = '${id}'`,
`SELECT * FROM message_reaction`
]);
```
### Fallback ### Fallback
PG-polling adapter (`pg.svelte.ts`) brukes kun når SpacetimeDB ikke er konfigurert. Markeres som `readonly: true`. PG-polling adapter (`pg.svelte.ts`) brukes kun når SpacetimeDB ikke er konfigurert. Markeres som `readonly: true`.

View file

@ -1,19 +1,19 @@
// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE // THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. // WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.
/* eslint-disable */ /* eslint-disable */
/* tslint:disable */ /* tslint:disable */
import { import {
TypeBuilder as __TypeBuilder, TypeBuilder as __TypeBuilder,
t as __t, t as __t,
type AlgebraicTypeType as __AlgebraicTypeType, type AlgebraicTypeType as __AlgebraicTypeType,
type Infer as __Infer, type Infer as __Infer,
} from "spacetimedb"; } from "spacetimedb";
export default { export default {
messageId: __t.string(), messageId: __t.string(),
workspaceId: __t.string(), workspaceId: __t.string(),
userId: __t.string(), userId: __t.string(),
userName: __t.string(), userName: __t.string(),
reaction: __t.string(), reaction: __t.string(),
}; };

View file

@ -1,15 +1,15 @@
// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE // THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. // WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.
/* eslint-disable */ /* eslint-disable */
/* tslint:disable */ /* tslint:disable */
import { import {
TypeBuilder as __TypeBuilder, TypeBuilder as __TypeBuilder,
t as __t, t as __t,
type AlgebraicTypeType as __AlgebraicTypeType, type AlgebraicTypeType as __AlgebraicTypeType,
type Infer as __Infer, type Infer as __Infer,
} from "spacetimedb"; } from "spacetimedb";
export default { export default {
channelId: __t.string(), channelId: __t.string(),
}; };

View file

@ -1,17 +1,17 @@
// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE // THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. // WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.
/* eslint-disable */ /* eslint-disable */
/* tslint:disable */ /* tslint:disable */
import { import {
TypeBuilder as __TypeBuilder, TypeBuilder as __TypeBuilder,
t as __t, t as __t,
type AlgebraicTypeType as __AlgebraicTypeType, type AlgebraicTypeType as __AlgebraicTypeType,
type Infer as __Infer, type Infer as __Infer,
} from "spacetimedb"; } from "spacetimedb";
export default { export default {
id: __t.string(), id: __t.string(),
workspaceId: __t.string(), workspaceId: __t.string(),
newBody: __t.string(), newBody: __t.string(),
}; };

View file

@ -156,3 +156,4 @@ export class DbConnection extends __DbConnectionImpl<typeof REMOTE_MODULE> {
return new SubscriptionBuilder(this); return new SubscriptionBuilder(this);
}; };
} }

View file

@ -1,15 +1,15 @@
// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE // THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. // WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.
/* eslint-disable */ /* eslint-disable */
/* tslint:disable */ /* tslint:disable */
import { import {
TypeBuilder as __TypeBuilder, TypeBuilder as __TypeBuilder,
t as __t, t as __t,
type AlgebraicTypeType as __AlgebraicTypeType, type AlgebraicTypeType as __AlgebraicTypeType,
type Infer as __Infer, type Infer as __Infer,
} from "spacetimedb"; } from "spacetimedb";
export default { export default {
reactionsJson: __t.string(), reactionsJson: __t.string(),
}; };

View file

@ -1,19 +1,19 @@
// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE // THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. // WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.
/* eslint-disable */ /* eslint-disable */
/* tslint:disable */ /* tslint:disable */
import { import {
TypeBuilder as __TypeBuilder, TypeBuilder as __TypeBuilder,
t as __t, t as __t,
type AlgebraicTypeType as __AlgebraicTypeType, type AlgebraicTypeType as __AlgebraicTypeType,
type Infer as __Infer, type Infer as __Infer,
} from "spacetimedb"; } from "spacetimedb";
export default __t.row({ export default __t.row({
id: __t.u64().primaryKey(), id: __t.u64().primaryKey(),
messageId: __t.string().name("message_id"), messageId: __t.string().name("message_id"),
userId: __t.string().name("user_id"), userId: __t.string().name("user_id"),
userName: __t.string().name("user_name"), userName: __t.string().name("user_name"),
reaction: __t.string(), reaction: __t.string(),
}); });

View file

@ -1,18 +1,18 @@
// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE // THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. // WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.
/* eslint-disable */ /* eslint-disable */
/* tslint:disable */ /* tslint:disable */
import { import {
TypeBuilder as __TypeBuilder, TypeBuilder as __TypeBuilder,
t as __t, t as __t,
type AlgebraicTypeType as __AlgebraicTypeType, type AlgebraicTypeType as __AlgebraicTypeType,
type Infer as __Infer, type Infer as __Infer,
} from "spacetimedb"; } from "spacetimedb";
export default { export default {
messageId: __t.string(), messageId: __t.string(),
workspaceId: __t.string(), workspaceId: __t.string(),
userId: __t.string(), userId: __t.string(),
reaction: __t.string(), reaction: __t.string(),
}; };

View file

@ -42,3 +42,4 @@ export const SyncOutbox = __t.object("SyncOutbox", {
synced: __t.bool(), synced: __t.bool(),
}); });
export type SyncOutbox = __Infer<typeof SyncOutbox>; export type SyncOutbox = __Infer<typeof SyncOutbox>;

View file

@ -25,3 +25,4 @@ export type LoadReactionsParams = __Infer<typeof LoadReactionsReducer>;
export type MarkSyncedParams = __Infer<typeof MarkSyncedReducer>; export type MarkSyncedParams = __Infer<typeof MarkSyncedReducer>;
export type RemoveReactionParams = __Infer<typeof RemoveReactionReducer>; export type RemoveReactionParams = __Infer<typeof RemoveReactionReducer>;
export type SendMessageParams = __Infer<typeof SendMessageReducer>; export type SendMessageParams = __Infer<typeof SendMessageReducer>;

View file

@ -325,7 +325,7 @@ export function createSpacetimeChat(
edit, edit,
delete: del, delete: del,
react, react,
refresh: async () => { rebuildMessages(); }, refresh: async () => { rebuildMessages(); await enrichFromPg(); },
destroy destroy
}; };
} }