Open
Conversation
This commit just focuses on moving the current sqlite state apis behind an interface. At this point in time everything is still hard coded to sqlite intentionally. The goal of this initial process is to get to a point where we have two distinct sqlite state backends being used at the same time. This will help validate that this is a working interface and we're on the right path. It's a non-goal at this point to make everything generic across all possible state backends. Once everything is fleshed out with sqlite and we have an example app that has two sqlite projections running in tandom I'll begin working on making things generic.
time. Includes a lot backwards compatible code to avoid a giant "big bang" commit
adapter/naming wiring
Simplify by defining tables, events, and backends explicitly for each state Update tsconfig to add project references and fix type definitions
snapshot behavior in node adapter
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Context / Motivation
LiveStore’s current state model is effectively “single state backend” (SQLite). Designing a truly generic multi-state API (e.g. SQLite + CRDT + JS-object state) likely requires broad refactors across schema representation, querying, migrations, rollback, syncing, and devtools.
This PR takes a pragmatic step first: a proof-of-concept that runs multiple independent SQLite databases side-by-side in a single store, in order to:
What this PR is
A focused exploration / scaffolding PR that introduces a “multi-state” shape internally and threads it end-to-end through:
The POC example supported by these changes is:
What this PR is not
This is not the final multi-state architecture, and it intentionally does not attempt to:
In other words: this PR is about learning and de-risking design, not production-hardening.
High-level API
Defining multiple backends (SQLite-only, for now)
There is a new
web-multi-state-todoexample where you can seeing an implementation of this api.Mental model
schema.state.backendsis now the canonical “all backends” container (Map).A rough conceptual future (not implemented here):
flowchart TD store["Store"] --> schema["Schema"] schema --> state["State"] state --> events["Events"] state --> backends["Backends"] events --> a_events["A-events"] events --> b_events["B-events"] backends --> a_backend["A-backend"] backends --> b_backend["B-backend"] a_backend --> a_tables["tables"] a_backend --> a_materializers["materializers"] b_backend --> b_tables["tables"] b_backend --> b_materializers["materializers"]Routing rules introduced by this POC
eventName → backendIdviaschema.state.materializersByEventNametableDef → backendIdvia backend tagging on table defsbackendIdexplicitly (used byqueryDbraw input)Reactive invalidation / table keys
To avoid collisions when two backends have the same table name (e.g. both have
items), reactive table refs are keyed as:Implementation Walkthrough (what changed)
1) Schema/state representation is now “multi-backend”
Key additions include:
schema.state.backends: Map<StateBackendId, InternalStateBackend>schema.state.defaultBackendIdschema.state.materializersByEventName: Map<eventName, { backendId, materializer }>resolveBackendIdForEventName(schema, eventName)This is the backbone that lets the rest of the system route correctly.
Relevant files
packages/@livestore/common/src/schema/schema.tspackages/@livestore/common/src/schema/state/sqlite/mod.ts2) Backend-scoped system tables + backend tagging for QueryBuilder routing
To make QueryBuilder routing deterministic, tables are tagged with a backend id:
setTableBackendId(tableDef, backendId)getTableBackendId(tableDef)(fail-fast if unassigned)System tables are also now instantiated per backend (so metadata stays backend-local and tagging stays correct).
Relevant files
packages/@livestore/common/src/schema/state/sqlite/table-def.tspackages/@livestore/common/src/schema/state/sqlite/system-tables/state-tables.tspackages/@livestore/common/src/schema/state/sqlite/system-tables/mod.ts3) Leader thread sync/materialization supports multiple state DBs
The leader thread now:
dbStates: Map<backendId, db>Relevant files
packages/@livestore/common/src/leader-thread/make-leader-thread-layer.tspackages/@livestore/common/src/leader-thread/LeaderSyncProcessor.ts4) Store runtime becomes backend-aware
Changes include:
SqliteDbWrappermap (sqliteDbWrappers)backendId:tableNamekeysRelevant files
packages/@livestore/livestore/src/store/store.tspackages/@livestore/livestore/src/store/table-key.tspackages/@livestore/livestore/src/live-queries/db-query.ts5) Snapshot export/import is now per-backend
Adapters/workers now export:
snapshotsByBackend: Array<[backendId, snapshotBytes]>And boot paths validate snapshot completeness where needed.
Relevant files
packages/@livestore/adapter-node/src/worker-schema.tspackages/@livestore/adapter-node/src/make-leader-worker.tspackages/@livestore/adapter-node/src/leader-thread-shared.tspackages/@livestore/adapter-web/src/web-worker/leader-worker/make-leader-worker.tspackages/@livestore/adapter-web/src/web-worker/client-session/snapshot-completeness.tsKnown limitations / open questions (intentional)
tables,migrations,hash).Reviewer Guide (what feedback is most useful)
schema.state.backends+materializersByEventNamefeel like the right “central routing primitive”?makeBackend,makeMultiState, backendId tagging)?