SQLite State Schema
LiveStore provides a schema definition language for defining your database tables and mutation definitions using explicit column configurations. LiveStore automatically migrates your database schema when you change your schema definitions.
Alternative Approach: You can also define tables using Effect Schema with annotations for type-safe schema definitions.
Example
Section titled “Example”import { import Events
Events, const makeSchema: <TInputSchema extends InputSchema>(inputSchema: TInputSchema) => FromInputSchema.DeriveSchema<TInputSchema>
makeSchema, import Schema
Schema, type SessionIdSymbol = typeof SessionIdSymbolconst SessionIdSymbol: typeof SessionIdSymbol
Can be used in queries to refer to the current session id.
Will be replaced with the actual session id at runtime
In client document table:
const uiState = State.SQLite.clientDocument({ name: 'ui_state', schema: Schema.Struct({ theme: Schema.Literal('dark', 'light', 'system'), user: Schema.String, showToolbar: Schema.Boolean, }), default: { value: defaultFrontendState, id: SessionIdSymbol },})
Or in a client document query:
const query$ = queryDb(tables.uiState.get(SessionIdSymbol))
SessionIdSymbol, import State
State } from '@livestore/livestore'
// You can model your state as SQLite tables (https://docs.livestore.dev/reference/state/sqlite-schema)export const const tables: { todos: State.SQLite.TableDef<State.SQLite.SqliteTableDefForInput<"todos", { readonly id: { columnType: "text"; schema: Schema.Schema<string, string, never>; default: None<never>; nullable: false; primaryKey: true; autoIncrement: false; }; readonly text: { columnType: "text"; schema: Schema.Schema<string, string, never>; default: Some<"">; nullable: false; primaryKey: false; autoIncrement: false; }; readonly completed: { columnType: "integer"; schema: Schema.Schema<boolean, number, never>; default: Some<false>; nullable: false; primaryKey: false; autoIncrement: false; }; readonly deletedAt: { ...; }; }>, State.SQLite.WithDefaults<...>, Schema.Schema<...>>; uiState: State.SQLite.ClientDocumentTableDef<...>;}
tables = { todos: State.SQLite.TableDef<State.SQLite.SqliteTableDefForInput<"todos", { readonly id: { columnType: "text"; schema: Schema.Schema<string, string, never>; default: None<never>; nullable: false; primaryKey: true; autoIncrement: false; }; readonly text: { columnType: "text"; schema: Schema.Schema<string, string, never>; default: Some<"">; nullable: false; primaryKey: false; autoIncrement: false; }; readonly completed: { columnType: "integer"; schema: Schema.Schema<boolean, number, never>; default: Some<false>; nullable: false; primaryKey: false; autoIncrement: false; }; readonly deletedAt: { ...; };}>, State.SQLite.WithDefaults<...>, Schema.Schema<...>>
todos: import State
State.import SQLite
SQLite.function table<"todos", { readonly id: { columnType: "text"; schema: Schema.Schema<string, string, never>; default: None<never>; nullable: false; primaryKey: true; autoIncrement: false; }; readonly text: { columnType: "text"; schema: Schema.Schema<string, string, never>; default: Some<"">; nullable: false; primaryKey: false; autoIncrement: false; }; readonly completed: { columnType: "integer"; schema: Schema.Schema<boolean, number, never>; default: Some<false>; nullable: false; primaryKey: false; autoIncrement: false; }; readonly deletedAt: { columnType: "integer"; ... 4 more ...; autoIncrement: false; };}, Partial<...>>(args: { ...;} & Partial<...>): State.SQLite.TableDef<...> (+2 overloads)
Creates a SQLite table definition from columns or an Effect Schema.
This function supports two main ways to define a table:
- Using explicit column definitions
- Using an Effect Schema (either the
name property needs to be provided or the schema needs to have a title/identifier)
// Using explicit columnsconst usersTable = State.SQLite.table({ name: 'users', columns: { id: State.SQLite.text({ primaryKey: true }), name: State.SQLite.text({ nullable: false }), email: State.SQLite.text({ nullable: false }), age: State.SQLite.integer({ nullable: true }), },})
// Using Effect Schema with annotationsimport { Schema } from '@livestore/utils/effect'
const UserSchema = Schema.Struct({ id: Schema.Int.pipe(State.SQLite.withPrimaryKey).pipe(State.SQLite.withAutoIncrement), email: Schema.String.pipe(State.SQLite.withUnique), name: Schema.String, active: Schema.Boolean.pipe(State.SQLite.withDefault(true)), createdAt: Schema.optional(Schema.Date),})
// Option 1: With explicit nameconst usersTable = State.SQLite.table({ name: 'users', schema: UserSchema,})
// Option 2: With name from schema annotation (title or identifier)const AnnotatedUserSchema = UserSchema.annotations({ title: 'users' })const usersTable2 = State.SQLite.table({ schema: AnnotatedUserSchema,})
// Adding indexesconst PostSchema = Schema.Struct({ id: Schema.String.pipe(State.SQLite.withPrimaryKey), title: Schema.String, authorId: Schema.String, createdAt: Schema.Date,}).annotations({ identifier: 'posts' })
const postsTable = State.SQLite.table({ schema: PostSchema, indexes: [ { name: 'idx_posts_author', columns: ['authorId'] }, { name: 'idx_posts_created', columns: ['createdAt'], isUnique: false }, ],})
table({ name: "todos"
name: 'todos', columns: { readonly id: { columnType: "text"; schema: Schema.Schema<string, string, never>; default: None<never>; nullable: false; primaryKey: true; autoIncrement: false; }; readonly text: { columnType: "text"; schema: Schema.Schema<string, string, never>; default: Some<"">; nullable: false; primaryKey: false; autoIncrement: false; }; readonly completed: { columnType: "integer"; schema: Schema.Schema<boolean, number, never>; default: Some<false>; nullable: false; primaryKey: false; autoIncrement: false; }; readonly deletedAt: { ...; };}
columns: { id: { columnType: "text"; schema: Schema.Schema<string, string, never>; default: None<never>; nullable: false; primaryKey: true; autoIncrement: false;}
id: import State
State.import SQLite
SQLite.const text: <string, string, false, typeof NoDefault, true, false>(args: { schema?: Schema.Schema<string, string, never>; default?: typeof NoDefault; nullable?: false; primaryKey?: true; autoIncrement?: false;}) => { columnType: "text"; schema: Schema.Schema<string, string, never>; default: None<never>; nullable: false; primaryKey: true; autoIncrement: false;} (+1 overload)
text({ primaryKey?: true
primaryKey: true }), text: { columnType: "text"; schema: Schema.Schema<string, string, never>; default: Some<"">; nullable: false; primaryKey: false; autoIncrement: false;}
text: import State
State.import SQLite
SQLite.const text: <string, string, false, "", false, false>(args: { schema?: Schema.Schema<string, string, never>; default?: ""; nullable?: false; primaryKey?: false; autoIncrement?: false;}) => { columnType: "text"; schema: Schema.Schema<string, string, never>; default: Some<"">; nullable: false; primaryKey: false; autoIncrement: false;} (+1 overload)
text({ default?: ""
default: '' }), completed: { columnType: "integer"; schema: Schema.Schema<boolean, number, never>; default: Some<false>; nullable: false; primaryKey: false; autoIncrement: false;}
completed: import State
State.import SQLite
SQLite.const boolean: <boolean, false, false, false, false>(args: { default?: false; nullable?: false; primaryKey?: false; autoIncrement?: false;}) => { columnType: "integer"; schema: Schema.Schema<boolean, number, never>; default: Some<false>; nullable: false; primaryKey: false; autoIncrement: false;} (+1 overload)
boolean({ default?: false
default: false }), deletedAt: { columnType: "integer"; schema: Schema.Schema<Date | null, number | null, never>; default: None<never>; nullable: true; primaryKey: false; autoIncrement: false;}
deletedAt: import State
State.import SQLite
SQLite.const integer: <number, Date, true, typeof NoDefault, false, false>(args: { schema?: Schema.Schema<Date, number, never>; default?: typeof NoDefault; nullable?: true; primaryKey?: false; autoIncrement?: false;}) => { columnType: "integer"; schema: Schema.Schema<Date | null, number | null, never>; default: None<never>; nullable: true; primaryKey: false; autoIncrement: false;} (+1 overload)
integer({ nullable?: true
nullable: true, schema?: Schema.Schema<Date, number, never>
schema: import Schema
Schema.class DateFromNumber
Defines a schema that converts a number into a Date object using the new Date constructor. This schema does not validate the numerical input,
allowing potentially invalid values such as NaN, Infinity, and
-Infinity to be converted into Date objects. During the encoding process,
any invalid Date object will be encoded to NaN.
DateFromNumber }), }, }), // Client documents can be used for local-only state (e.g. form inputs) uiState: State.SQLite.ClientDocumentTableDef<"uiState", { readonly filter: "completed" | "all" | "active"; readonly newTodoText: string;}, { readonly filter: "completed" | "all" | "active"; readonly newTodoText: string;}, { partialSet: true; default: { id: typeof SessionIdSymbol; value: { readonly newTodoText: ""; readonly filter: "all"; }; };}>
uiState: import State
State.import SQLite
SQLite.clientDocument<"uiState", { readonly filter: "completed" | "all" | "active"; readonly newTodoText: string;}, { readonly filter: "completed" | "all" | "active"; readonly newTodoText: string;}, { readonly name: "uiState"; readonly schema: Schema.Struct<{ newTodoText: typeof Schema.String; filter: Schema.Literal<["all", "active", "completed"]>; }>; readonly default: { readonly id: typeof SessionIdSymbol; readonly value: { readonly newTodoText: ""; readonly filter: "all"; }; };}>({ name, schema: valueSchema, ...inputOptions }: { name: "uiState"; schema: Schema.Schema<{ readonly filter: "completed" | "all" | "active"; readonly newTodoText: string; }, { ...; }, never>;} & { readonly name: "uiState"; readonly schema: Schema.Struct<{ newTodoText: typeof Schema.String; filter: Schema.Literal<["all", "active", "completed"]>; }>; readonly default: { readonly id: typeof SessionIdSymbol; readonly value: { readonly newTodoText: ""; readonly filter: "all"; }; };}): State.SQLite.ClientDocumentTableDef<...>export clientDocument
Special:
- Synced across client sessions (e.g. tabs) but not across different clients
- Derived setters
- Emits client-only events
- Has implicit setter-materializers
- Similar to
React.useState (except it's persisted)
Careful:
- When changing the table definitions in a non-backwards compatible way, the state might be lost without
explicit materializers to handle the old auto-generated events
Usage:
// Querying data// `'some-id'` can be ommited for SessionIdSymbolstore.queryDb(clientDocumentTable.get('some-id'))
// Setting data// Again, `'some-id'` can be ommited for SessionIdSymbolstore.commit(clientDocumentTable.set({ someField: 'some-value' }, 'some-id'))
clientDocument({ name: "uiState"
name: 'uiState', schema: Schema.Schema<{ readonly filter: "completed" | "all" | "active"; readonly newTodoText: string;}, { readonly filter: "completed" | "all" | "active"; readonly newTodoText: string;}, never> & Schema.Struct<{ newTodoText: typeof Schema.String; filter: Schema.Literal<["all", "active", "completed"]>;}>
schema: import Schema
Schema.function Struct<{ newTodoText: typeof Schema.String; filter: Schema.Literal<["all", "active", "completed"]>;}>(fields: { newTodoText: typeof Schema.String; filter: Schema.Literal<["all", "active", "completed"]>;}): Schema.Struct<{ newTodoText: typeof Schema.String; filter: Schema.Literal<["all", "active", "completed"]>;}> (+1 overload)
Struct({ newTodoText: typeof Schema.String
newTodoText: import Schema
Schema.class Stringexport String
String, filter: Schema.Literal<["all", "active", "completed"]>
filter: import Schema
Schema.function Literal<["all", "active", "completed"]>(literals_0: "all", literals_1: "active", literals_2: "completed"): Schema.Literal<["all", "active", "completed"]> (+2 overloads)
Literal('all', 'active', 'completed') }), default: { readonly id: typeof SessionIdSymbol; readonly value: { readonly newTodoText: ""; readonly filter: "all"; };}
default: { id: typeof SessionIdSymbol
id: const SessionIdSymbol: typeof SessionIdSymbol
Can be used in queries to refer to the current session id.
Will be replaced with the actual session id at runtime
In client document table:
const uiState = State.SQLite.clientDocument({ name: 'ui_state', schema: Schema.Struct({ theme: Schema.Literal('dark', 'light', 'system'), user: Schema.String, showToolbar: Schema.Boolean, }), default: { value: defaultFrontendState, id: SessionIdSymbol },})
Or in a client document query:
const query$ = queryDb(tables.uiState.get(SessionIdSymbol))
SessionIdSymbol, value: { readonly newTodoText: ""; readonly filter: "all";}
value: { newTodoText: ""
newTodoText: '', filter: "all"
filter: 'all' } }, }),}
// Events describe data changes (https://docs.livestore.dev/reference/events)export const const events: { todoCreated: State.SQLite.EventDef<"v1.TodoCreated", { readonly text: string; readonly id: string; }, { readonly text: string; readonly id: string; }, false>; todoCompleted: State.SQLite.EventDef<"v1.TodoCompleted", { readonly id: string; }, { readonly id: string; }, false>; todoUncompleted: State.SQLite.EventDef<"v1.TodoUncompleted", { readonly id: string; }, { readonly id: string; }, false>; todoDeleted: State.SQLite.EventDef<"v1.TodoDeleted", { readonly id: string; readonly deletedAt: Date; }, { readonly id: string; readonly deletedAt: string; }, false>; todoClearedCompleted: State.SQLite.EventDef<...>; uiStateSet: State.SQLite.ClientDocumentTableDef.SetEventDefLike<...>;}
events = { todoCreated: State.SQLite.EventDef<"v1.TodoCreated", { readonly text: string; readonly id: string;}, { readonly text: string; readonly id: string;}, false>
todoCreated: import Events
Events.synced<"v1.TodoCreated", { readonly text: string; readonly id: string;}, { readonly text: string; readonly id: string;}>(args: { name: "v1.TodoCreated"; schema: Schema.Schema<{ readonly text: string; readonly id: string; }, { readonly text: string; readonly id: string; }, never>;} & Omit<State.SQLite.DefineEventOptions<{ readonly text: string; readonly id: string;}, false>, "derived" | "clientOnly">): State.SQLite.EventDef<"v1.TodoCreated", { readonly text: string; readonly id: string;}, { readonly text: string; readonly id: string;}, false>export synced
synced({ name: "v1.TodoCreated"
name: 'v1.TodoCreated', schema: Schema.Schema<{ readonly text: string; readonly id: string;}, { readonly text: string; readonly id: string;}, never>
schema: import Schema
Schema.function Struct<{ id: typeof Schema.String; text: typeof Schema.String;}>(fields: { id: typeof Schema.String; text: typeof Schema.String;}): Schema.Struct<{ id: typeof Schema.String; text: typeof Schema.String;}> (+1 overload)
Struct({ id: typeof Schema.String
id: import Schema
Schema.class Stringexport String
String, text: typeof Schema.String
text: import Schema
Schema.class Stringexport String
String }), }), todoCompleted: State.SQLite.EventDef<"v1.TodoCompleted", { readonly id: string;}, { readonly id: string;}, false>
todoCompleted: import Events
Events.synced<"v1.TodoCompleted", { readonly id: string;}, { readonly id: string;}>(args: { name: "v1.TodoCompleted"; schema: Schema.Schema<{ readonly id: string; }, { readonly id: string; }, never>;} & Omit<State.SQLite.DefineEventOptions<{ readonly id: string;}, false>, "derived" | "clientOnly">): State.SQLite.EventDef<"v1.TodoCompleted", { readonly id: string;}, { readonly id: string;}, false>export synced
synced({ name: "v1.TodoCompleted"
name: 'v1.TodoCompleted', schema: Schema.Schema<{ readonly id: string;}, { readonly id: string;}, never>
schema: import Schema
Schema.function Struct<{ id: typeof Schema.String;}>(fields: { id: typeof Schema.String;}): Schema.Struct<{ id: typeof Schema.String;}> (+1 overload)
Struct({ id: typeof Schema.String
id: import Schema
Schema.class Stringexport String
String }), }), todoUncompleted: State.SQLite.EventDef<"v1.TodoUncompleted", { readonly id: string;}, { readonly id: string;}, false>
todoUncompleted: import Events
Events.synced<"v1.TodoUncompleted", { readonly id: string;}, { readonly id: string;}>(args: { name: "v1.TodoUncompleted"; schema: Schema.Schema<{ readonly id: string; }, { readonly id: string; }, never>;} & Omit<State.SQLite.DefineEventOptions<{ readonly id: string;}, false>, "derived" | "clientOnly">): State.SQLite.EventDef<"v1.TodoUncompleted", { readonly id: string;}, { readonly id: string;}, false>export synced
synced({ name: "v1.TodoUncompleted"
name: 'v1.TodoUncompleted', schema: Schema.Schema<{ readonly id: string;}, { readonly id: string;}, never>
schema: import Schema
Schema.function Struct<{ id: typeof Schema.String;}>(fields: { id: typeof Schema.String;}): Schema.Struct<{ id: typeof Schema.String;}> (+1 overload)
Struct({ id: typeof Schema.String
id: import Schema
Schema.class Stringexport String
String }), }), todoDeleted: State.SQLite.EventDef<"v1.TodoDeleted", { readonly id: string; readonly deletedAt: Date;}, { readonly id: string; readonly deletedAt: string;}, false>
todoDeleted: import Events
Events.synced<"v1.TodoDeleted", { readonly id: string; readonly deletedAt: Date;}, { readonly id: string; readonly deletedAt: string;}>(args: { name: "v1.TodoDeleted"; schema: Schema.Schema<{ readonly id: string; readonly deletedAt: Date; }, { readonly id: string; readonly deletedAt: string; }, never>;} & Omit<State.SQLite.DefineEventOptions<{ readonly id: string; readonly deletedAt: Date;}, false>, "derived" | "clientOnly">): State.SQLite.EventDef<"v1.TodoDeleted", { readonly id: string; readonly deletedAt: Date;}, { readonly id: string; readonly deletedAt: string;}, false>export synced
synced({ name: "v1.TodoDeleted"
name: 'v1.TodoDeleted', schema: Schema.Schema<{ readonly id: string; readonly deletedAt: Date;}, { readonly id: string; readonly deletedAt: string;}, never>
schema: import Schema
Schema.function Struct<{ id: typeof Schema.String; deletedAt: typeof Schema.Date;}>(fields: { id: typeof Schema.String; deletedAt: typeof Schema.Date;}): Schema.Struct<{ id: typeof Schema.String; deletedAt: typeof Schema.Date;}> (+1 overload)
Struct({ id: typeof Schema.String
id: import Schema
Schema.class Stringexport String
String, deletedAt: typeof Schema.Date
deletedAt: import Schema
Schema.class Dateexport Date
This schema converts a string into a Date object using the new Date
constructor. It ensures that only valid date strings are accepted,
rejecting any strings that would result in an invalid date, such as new Date("Invalid Date").
Date }), }), todoClearedCompleted: State.SQLite.EventDef<"v1.TodoClearedCompleted", { readonly deletedAt: Date;}, { readonly deletedAt: string;}, false>
todoClearedCompleted: import Events
Events.synced<"v1.TodoClearedCompleted", { readonly deletedAt: Date;}, { readonly deletedAt: string;}>(args: { name: "v1.TodoClearedCompleted"; schema: Schema.Schema<{ readonly deletedAt: Date; }, { readonly deletedAt: string; }, never>;} & Omit<State.SQLite.DefineEventOptions<{ readonly deletedAt: Date;}, false>, "derived" | "clientOnly">): State.SQLite.EventDef<"v1.TodoClearedCompleted", { readonly deletedAt: Date;}, { readonly deletedAt: string;}, false>export synced
synced({ name: "v1.TodoClearedCompleted"
name: 'v1.TodoClearedCompleted', schema: Schema.Schema<{ readonly deletedAt: Date;}, { readonly deletedAt: string;}, never>
schema: import Schema
Schema.function Struct<{ deletedAt: typeof Schema.Date;}>(fields: { deletedAt: typeof Schema.Date;}): Schema.Struct<{ deletedAt: typeof Schema.Date;}> (+1 overload)
Struct({ deletedAt: typeof Schema.Date
deletedAt: import Schema
Schema.class Dateexport Date
This schema converts a string into a Date object using the new Date
constructor. It ensures that only valid date strings are accepted,
rejecting any strings that would result in an invalid date, such as new Date("Invalid Date").
Date }), }), uiStateSet: State.SQLite.ClientDocumentTableDef.SetEventDefLike<"uiState", { readonly filter: "completed" | "all" | "active"; readonly newTodoText: string;}, { partialSet: true; default: { id: typeof SessionIdSymbol; value: { readonly newTodoText: ""; readonly filter: "all"; }; };}>
uiStateSet: const tables: { todos: State.SQLite.TableDef<State.SQLite.SqliteTableDefForInput<"todos", { readonly id: { columnType: "text"; schema: Schema.Schema<string, string, never>; default: None<never>; nullable: false; primaryKey: true; autoIncrement: false; }; readonly text: { columnType: "text"; schema: Schema.Schema<string, string, never>; default: Some<"">; nullable: false; primaryKey: false; autoIncrement: false; }; readonly completed: { columnType: "integer"; schema: Schema.Schema<boolean, number, never>; default: Some<false>; nullable: false; primaryKey: false; autoIncrement: false; }; readonly deletedAt: { ...; }; }>, State.SQLite.WithDefaults<...>, Schema.Schema<...>>; uiState: State.SQLite.ClientDocumentTableDef<...>;}
tables.uiState: State.SQLite.ClientDocumentTableDef<"uiState", { readonly filter: "completed" | "all" | "active"; readonly newTodoText: string;}, { readonly filter: "completed" | "all" | "active"; readonly newTodoText: string;}, { partialSet: true; default: { id: typeof SessionIdSymbol; value: { readonly newTodoText: ""; readonly filter: "all"; }; };}>
uiState.ClientDocumentTableDef<TName extends string, TType, TEncoded, TOptions extends ClientDocumentTableOptions<TType>>.Trait<"uiState", { readonly filter: "completed" | "all" | "active"; readonly newTodoText: string; }, { readonly filter: "completed" | "all" | "active"; readonly newTodoText: string; }, { ...; }>.set: State.SQLite.ClientDocumentTableDef.SetEventDefLike<"uiState", { readonly filter: "completed" | "all" | "active"; readonly newTodoText: string;}, { partialSet: true; default: { id: typeof SessionIdSymbol; value: { readonly newTodoText: ""; readonly filter: "all"; }; };}>
Derived event definition for setting the value of the client document table.
If the document doesn't exist yet, the first .set event will create it.
set,}
// Materializers are used to map events to state (https://docs.livestore.dev/reference/state/materializers)const const materializers: { "v1.TodoCreated": State.SQLite.Materializer<State.SQLite.EventDef<"v1.TodoCreated", { readonly text: string; readonly id: string; }, { readonly text: string; readonly id: string; }, false>>; "v1.TodoCompleted": State.SQLite.Materializer<State.SQLite.EventDef<"v1.TodoCompleted", { readonly id: string; }, { readonly id: string; }, false>>; "v1.TodoUncompleted": State.SQLite.Materializer<State.SQLite.EventDef<"v1.TodoUncompleted", { readonly id: string; }, { readonly id: string; }, false>>; "v1.TodoDeleted": State.SQLite.Materializer<...>; "v1.TodoClearedCompleted": State.SQLite.Materializer<...>;}
materializers = import State
State.import SQLite
SQLite.const materializers: <{ todoCreated: State.SQLite.EventDef<"v1.TodoCreated", { readonly text: string; readonly id: string; }, { readonly text: string; readonly id: string; }, false>; todoCompleted: State.SQLite.EventDef<"v1.TodoCompleted", { readonly id: string; }, { readonly id: string; }, false>; todoUncompleted: State.SQLite.EventDef<"v1.TodoUncompleted", { readonly id: string; }, { readonly id: string; }, false>; todoDeleted: State.SQLite.EventDef<"v1.TodoDeleted", { readonly id: string; readonly deletedAt: Date; }, { readonly id: string; readonly deletedAt: string; }, false>; todoClearedCompleted: State.SQLite.EventDef<...>; uiStateSet: State.SQLite.ClientDocumentTableDef.SetEventDefLike<...>;}>(_eventDefRecord: { todoCreated: State.SQLite.EventDef<"v1.TodoCreated", { readonly text: string; readonly id: string; }, { readonly text: string; readonly id: string; }, false>; todoCompleted: State.SQLite.EventDef<"v1.TodoCompleted", { readonly id: string; }, { readonly id: string; }, false>; todoUncompleted: State.SQLite.EventDef<"v1.TodoUncompleted", { readonly id: string; }, { readonly id: string; }, false>; todoDeleted: State.SQLite.EventDef<"v1.TodoDeleted", { readonly id: string; readonly deletedAt: Date; }, { readonly id: string; readonly deletedAt: string; }, false>; todoClearedCompleted: State.SQLite.EventDef<...>; uiStateSet: State.SQLite.ClientDocumentTableDef.SetEventDefLike<...>;}, handlers: { ...;}) => { ...;}
materializers(const events: { todoCreated: State.SQLite.EventDef<"v1.TodoCreated", { readonly text: string; readonly id: string; }, { readonly text: string; readonly id: string; }, false>; todoCompleted: State.SQLite.EventDef<"v1.TodoCompleted", { readonly id: string; }, { readonly id: string; }, false>; todoUncompleted: State.SQLite.EventDef<"v1.TodoUncompleted", { readonly id: string; }, { readonly id: string; }, false>; todoDeleted: State.SQLite.EventDef<"v1.TodoDeleted", { readonly id: string; readonly deletedAt: Date; }, { readonly id: string; readonly deletedAt: string; }, false>; todoClearedCompleted: State.SQLite.EventDef<...>; uiStateSet: State.SQLite.ClientDocumentTableDef.SetEventDefLike<...>;}
events, { 'v1.TodoCreated': ({ id: string
id, text: string
text }) => const tables: { todos: State.SQLite.TableDef<State.SQLite.SqliteTableDefForInput<"todos", { readonly id: { columnType: "text"; schema: Schema.Schema<string, string, never>; default: None<never>; nullable: false; primaryKey: true; autoIncrement: false; }; readonly text: { columnType: "text"; schema: Schema.Schema<string, string, never>; default: Some<"">; nullable: false; primaryKey: false; autoIncrement: false; }; readonly completed: { columnType: "integer"; schema: Schema.Schema<boolean, number, never>; default: Some<false>; nullable: false; primaryKey: false; autoIncrement: false; }; readonly deletedAt: { ...; }; }>, State.SQLite.WithDefaults<...>, Schema.Schema<...>>; uiState: State.SQLite.ClientDocumentTableDef<...>;}
tables.todos: State.SQLite.TableDef<State.SQLite.SqliteTableDefForInput<"todos", { readonly id: { columnType: "text"; schema: Schema.Schema<string, string, never>; default: None<never>; nullable: false; primaryKey: true; autoIncrement: false; }; readonly text: { columnType: "text"; schema: Schema.Schema<string, string, never>; default: Some<"">; nullable: false; primaryKey: false; autoIncrement: false; }; readonly completed: { columnType: "integer"; schema: Schema.Schema<boolean, number, never>; default: Some<false>; nullable: false; primaryKey: false; autoIncrement: false; }; readonly deletedAt: { ...; };}>, State.SQLite.WithDefaults<...>, Schema.Schema<...>>
todos.insert: (values: { readonly id: string; readonly text?: string; readonly completed?: boolean; readonly deletedAt?: Date | null;}) => QueryBuilder<readonly { readonly id: string; readonly text: string; readonly completed: boolean; readonly deletedAt: Date | null;}[], State.SQLite.TableDefBase<State.SQLite.SqliteTableDefForInput<"todos", { readonly id: { columnType: "text"; schema: Schema.Schema<string, string, never>; default: None<never>; nullable: false; primaryKey: true; autoIncrement: false; }; readonly text: { columnType: "text"; schema: Schema.Schema<string, string, never>; default: Some<"">; nullable: false; primaryKey: false; autoIncrement: false; }; readonly completed: { ...; }; readonly deletedAt: { ...; };}>, State.SQLite.WithDefaults<...>>, "select" | ... 6 more ... | "row">
Insert a new row into the table
Example:
db.todos.insert({ id: '123', text: 'Buy milk', status: 'active' })
insert({ id: string
id, text?: string
text, completed?: boolean
completed: false }), 'v1.TodoCompleted': ({ id: string
id }) => const tables: { todos: State.SQLite.TableDef<State.SQLite.SqliteTableDefForInput<"todos", { readonly id: { columnType: "text"; schema: Schema.Schema<string, string, never>; default: None<never>; nullable: false; primaryKey: true; autoIncrement: false; }; readonly text: { columnType: "text"; schema: Schema.Schema<string, string, never>; default: Some<"">; nullable: false; primaryKey: false; autoIncrement: false; }; readonly completed: { columnType: "integer"; schema: Schema.Schema<boolean, number, never>; default: Some<false>; nullable: false; primaryKey: false; autoIncrement: false; }; readonly deletedAt: { ...; }; }>, State.SQLite.WithDefaults<...>, Schema.Schema<...>>; uiState: State.SQLite.ClientDocumentTableDef<...>;}
tables.todos: State.SQLite.TableDef<State.SQLite.SqliteTableDefForInput<"todos", { readonly id: { columnType: "text"; schema: Schema.Schema<string, string, never>; default: None<never>; nullable: false; primaryKey: true; autoIncrement: false; }; readonly text: { columnType: "text"; schema: Schema.Schema<string, string, never>; default: Some<"">; nullable: false; primaryKey: false; autoIncrement: false; }; readonly completed: { columnType: "integer"; schema: Schema.Schema<boolean, number, never>; default: Some<false>; nullable: false; primaryKey: false; autoIncrement: false; }; readonly deletedAt: { ...; };}>, State.SQLite.WithDefaults<...>, Schema.Schema<...>>
todos.update: (values: Partial<{ readonly text: string; readonly id: string; readonly completed: boolean; readonly deletedAt: Date | null;}>) => QueryBuilder<readonly { readonly id: string; readonly text: string; readonly completed: boolean; readonly deletedAt: Date | null;}[], State.SQLite.TableDefBase<State.SQLite.SqliteTableDefForInput<"todos", { readonly id: { columnType: "text"; schema: Schema.Schema<string, string, never>; default: None<never>; nullable: false; primaryKey: true; autoIncrement: false; }; readonly text: { columnType: "text"; schema: Schema.Schema<string, string, never>; default: Some<"">; nullable: false; primaryKey: false; autoIncrement: false; }; readonly completed: { ...; }; readonly deletedAt: { ...; };}>, State.SQLite.WithDefaults<...>>, "select" | ... 6 more ... | "row">
Update rows in the table that match the where clause
Example:
db.todos.update({ status: 'completed' }).where({ id: '123' })
update({ completed?: boolean
completed: true }).where: (params: Partial<{ readonly id: string | { op: QueryBuilder<TResult, TTableDef extends State.SQLite.TableDefBase, TWithout extends QueryBuilder.ApiFeature = never>.WhereOps.SingleValue; value: string; } | { op: QueryBuilder.WhereOps.MultiValue; value: readonly string[]; } | undefined; readonly text: string | { op: QueryBuilder.WhereOps.SingleValue; value: string; } | { op: QueryBuilder.WhereOps.MultiValue; value: readonly string[]; } | undefined; readonly completed: boolean | ... 2 more ... | undefined; readonly deletedAt: Date | ... 3 more ... | undefined;}>) => QueryBuilder<...> (+2 overloads)
where({ id?: string | { op: QueryBuilder.WhereOps.SingleValue; value: string;} | { op: QueryBuilder.WhereOps.MultiValue; value: readonly string[];} | undefined
id }), 'v1.TodoUncompleted': ({ id: string
id }) => const tables: { todos: State.SQLite.TableDef<State.SQLite.SqliteTableDefForInput<"todos", { readonly id: { columnType: "text"; schema: Schema.Schema<string, string, never>; default: None<never>; nullable: false; primaryKey: true; autoIncrement: false; }; readonly text: { columnType: "text"; schema: Schema.Schema<string, string, never>; default: Some<"">; nullable: false; primaryKey: false; autoIncrement: false; }; readonly completed: { columnType: "integer"; schema: Schema.Schema<boolean, number, never>; default: Some<false>; nullable: false; primaryKey: false; autoIncrement: false; }; readonly deletedAt: { ...; }; }>, State.SQLite.WithDefaults<...>, Schema.Schema<...>>; uiState: State.SQLite.ClientDocumentTableDef<...>;}
tables.todos: State.SQLite.TableDef<State.SQLite.SqliteTableDefForInput<"todos", { readonly id: { columnType: "text"; schema: Schema.Schema<string, string, never>; default: None<never>; nullable: false; primaryKey: true; autoIncrement: false; }; readonly text: { columnType: "text"; schema: Schema.Schema<string, string, never>; default: Some<"">; nullable: false; primaryKey: false; autoIncrement: false; }; readonly completed: { columnType: "integer"; schema: Schema.Schema<boolean, number, never>; default: Some<false>; nullable: false; primaryKey: false; autoIncrement: false; }; readonly deletedAt: { ...; };}>, State.SQLite.WithDefaults<...>, Schema.Schema<...>>
todos.update: (values: Partial<{ readonly text: string; readonly id: string; readonly completed: boolean; readonly deletedAt: Date | null;}>) => QueryBuilder<readonly { readonly id: string; readonly text: string; readonly completed: boolean; readonly deletedAt: Date | null;}[], State.SQLite.TableDefBase<State.SQLite.SqliteTableDefForInput<"todos", { readonly id: { columnType: "text"; schema: Schema.Schema<string, string, never>; default: None<never>; nullable: false; primaryKey: true; autoIncrement: false; }; readonly text: { columnType: "text"; schema: Schema.Schema<string, string, never>; default: Some<"">; nullable: false; primaryKey: false; autoIncrement: false; }; readonly completed: { ...; }; readonly deletedAt: { ...; };}>, State.SQLite.WithDefaults<...>>, "select" | ... 6 more ... | "row">
Update rows in the table that match the where clause
Example:
db.todos.update({ status: 'completed' }).where({ id: '123' })
update({ completed?: boolean
completed: false }).where: (params: Partial<{ readonly id: string | { op: QueryBuilder<TResult, TTableDef extends State.SQLite.TableDefBase, TWithout extends QueryBuilder.ApiFeature = never>.WhereOps.SingleValue; value: string; } | { op: QueryBuilder.WhereOps.MultiValue; value: readonly string[]; } | undefined; readonly text: string | { op: QueryBuilder.WhereOps.SingleValue; value: string; } | { op: QueryBuilder.WhereOps.MultiValue; value: readonly string[]; } | undefined; readonly completed: boolean | ... 2 more ... | undefined; readonly deletedAt: Date | ... 3 more ... | undefined;}>) => QueryBuilder<...> (+2 overloads)
where({ id?: string | { op: QueryBuilder.WhereOps.SingleValue; value: string;} | { op: QueryBuilder.WhereOps.MultiValue; value: readonly string[];} | undefined
id }), 'v1.TodoDeleted': ({ id: string
id, deletedAt: Date
deletedAt }) => const tables: { todos: State.SQLite.TableDef<State.SQLite.SqliteTableDefForInput<"todos", { readonly id: { columnType: "text"; schema: Schema.Schema<string, string, never>; default: None<never>; nullable: false; primaryKey: true; autoIncrement: false; }; readonly text: { columnType: "text"; schema: Schema.Schema<string, string, never>; default: Some<"">; nullable: false; primaryKey: false; autoIncrement: false; }; readonly completed: { columnType: "integer"; schema: Schema.Schema<boolean, number, never>; default: Some<false>; nullable: false; primaryKey: false; autoIncrement: false; }; readonly deletedAt: { ...; }; }>, State.SQLite.WithDefaults<...>, Schema.Schema<...>>; uiState: State.SQLite.ClientDocumentTableDef<...>;}
tables.todos: State.SQLite.TableDef<State.SQLite.SqliteTableDefForInput<"todos", { readonly id: { columnType: "text"; schema: Schema.Schema<string, string, never>; default: None<never>; nullable: false; primaryKey: true; autoIncrement: false; }; readonly text: { columnType: "text"; schema: Schema.Schema<string, string, never>; default: Some<"">; nullable: false; primaryKey: false; autoIncrement: false; }; readonly completed: { columnType: "integer"; schema: Schema.Schema<boolean, number, never>; default: Some<false>; nullable: false; primaryKey: false; autoIncrement: false; }; readonly deletedAt: { ...; };}>, State.SQLite.WithDefaults<...>, Schema.Schema<...>>
todos.update: (values: Partial<{ readonly text: string; readonly id: string; readonly completed: boolean; readonly deletedAt: Date | null;}>) => QueryBuilder<readonly { readonly id: string; readonly text: string; readonly completed: boolean; readonly deletedAt: Date | null;}[], State.SQLite.TableDefBase<State.SQLite.SqliteTableDefForInput<"todos", { readonly id: { columnType: "text"; schema: Schema.Schema<string, string, never>; default: None<never>; nullable: false; primaryKey: true; autoIncrement: false; }; readonly text: { columnType: "text"; schema: Schema.Schema<string, string, never>; default: Some<"">; nullable: false; primaryKey: false; autoIncrement: false; }; readonly completed: { ...; }; readonly deletedAt: { ...; };}>, State.SQLite.WithDefaults<...>>, "select" | ... 6 more ... | "row">
Update rows in the table that match the where clause
Example:
db.todos.update({ status: 'completed' }).where({ id: '123' })
update({ deletedAt?: Date | null
deletedAt }).where: (params: Partial<{ readonly id: string | { op: QueryBuilder<TResult, TTableDef extends State.SQLite.TableDefBase, TWithout extends QueryBuilder.ApiFeature = never>.WhereOps.SingleValue; value: string; } | { op: QueryBuilder.WhereOps.MultiValue; value: readonly string[]; } | undefined; readonly text: string | { op: QueryBuilder.WhereOps.SingleValue; value: string; } | { op: QueryBuilder.WhereOps.MultiValue; value: readonly string[]; } | undefined; readonly completed: boolean | ... 2 more ... | undefined; readonly deletedAt: Date | ... 3 more ... | undefined;}>) => QueryBuilder<...> (+2 overloads)
where({ id?: string | { op: QueryBuilder.WhereOps.SingleValue; value: string;} | { op: QueryBuilder.WhereOps.MultiValue; value: readonly string[];} | undefined
id }), 'v1.TodoClearedCompleted': ({ deletedAt: Date
deletedAt }) => const tables: { todos: State.SQLite.TableDef<State.SQLite.SqliteTableDefForInput<"todos", { readonly id: { columnType: "text"; schema: Schema.Schema<string, string, never>; default: None<never>; nullable: false; primaryKey: true; autoIncrement: false; }; readonly text: { columnType: "text"; schema: Schema.Schema<string, string, never>; default: Some<"">; nullable: false; primaryKey: false; autoIncrement: false; }; readonly completed: { columnType: "integer"; schema: Schema.Schema<boolean, number, never>; default: Some<false>; nullable: false; primaryKey: false; autoIncrement: false; }; readonly deletedAt: { ...; }; }>, State.SQLite.WithDefaults<...>, Schema.Schema<...>>; uiState: State.SQLite.ClientDocumentTableDef<...>;}
tables.todos: State.SQLite.TableDef<State.SQLite.SqliteTableDefForInput<"todos", { readonly id: { columnType: "text"; schema: Schema.Schema<string, string, never>; default: None<never>; nullable: false; primaryKey: true; autoIncrement: false; }; readonly text: { columnType: "text"; schema: Schema.Schema<string, string, never>; default: Some<"">; nullable: false; primaryKey: false; autoIncrement: false; }; readonly completed: { columnType: "integer"; schema: Schema.Schema<boolean, number, never>; default: Some<false>; nullable: false; primaryKey: false; autoIncrement: false; }; readonly deletedAt: { ...; };}>, State.SQLite.WithDefaults<...>, Schema.Schema<...>>
todos.update: (values: Partial<{ readonly text: string; readonly id: string; readonly completed: boolean; readonly deletedAt: Date | null;}>) => QueryBuilder<readonly { readonly id: string; readonly text: string; readonly completed: boolean; readonly deletedAt: Date | null;}[], State.SQLite.TableDefBase<State.SQLite.SqliteTableDefForInput<"todos", { readonly id: { columnType: "text"; schema: Schema.Schema<string, string, never>; default: None<never>; nullable: false; primaryKey: true; autoIncrement: false; }; readonly text: { columnType: "text"; schema: Schema.Schema<string, string, never>; default: Some<"">; nullable: false; primaryKey: false; autoIncrement: false; }; readonly completed: { ...; }; readonly deletedAt: { ...; };}>, State.SQLite.WithDefaults<...>>, "select" | ... 6 more ... | "row">
Update rows in the table that match the where clause
Example:
db.todos.update({ status: 'completed' }).where({ id: '123' })
update({ deletedAt?: Date | null
deletedAt }).where: (params: Partial<{ readonly id: string | { op: QueryBuilder<TResult, TTableDef extends State.SQLite.TableDefBase, TWithout extends QueryBuilder.ApiFeature = never>.WhereOps.SingleValue; value: string; } | { op: QueryBuilder.WhereOps.MultiValue; value: readonly string[]; } | undefined; readonly text: string | { op: QueryBuilder.WhereOps.SingleValue; value: string; } | { op: QueryBuilder.WhereOps.MultiValue; value: readonly string[]; } | undefined; readonly completed: boolean | ... 2 more ... | undefined; readonly deletedAt: Date | ... 3 more ... | undefined;}>) => QueryBuilder<...> (+2 overloads)
where({ completed?: boolean | { op: QueryBuilder.WhereOps.SingleValue; value: boolean;} | { op: QueryBuilder.WhereOps.MultiValue; value: readonly boolean[];} | undefined
completed: true }),})
const const state: InternalState
state = import State
State.import SQLite
SQLite.const makeState: <{ tables: { todos: State.SQLite.TableDef<State.SQLite.SqliteTableDefForInput<"todos", { readonly id: { columnType: "text"; schema: Schema.Schema<string, string, never>; default: None<never>; nullable: false; primaryKey: true; autoIncrement: false; }; readonly text: { columnType: "text"; schema: Schema.Schema<string, string, never>; default: Some<"">; nullable: false; primaryKey: false; autoIncrement: false; }; readonly completed: { columnType: "integer"; schema: Schema.Schema<boolean, number, never>; default: Some<false>; nullable: false; primaryKey: false; autoIncrement: false; }; readonly deletedAt: { ...; }; }>, State.SQLite.WithDefaults<...>, Schema.Schema<...>>; uiState: State.SQLite.ClientDocumentTableDef<...>; }; materializers: { ...; };}>(inputSchema: { tables: { todos: State.SQLite.TableDef<State.SQLite.SqliteTableDefForInput<"todos", { readonly id: { columnType: "text"; schema: Schema.Schema<string, string, never>; default: None<never>; nullable: false; primaryKey: true; autoIncrement: false; }; readonly text: { columnType: "text"; schema: Schema.Schema<string, string, never>; default: Some<"">; nullable: false; primaryKey: false; autoIncrement: false; }; readonly completed: { columnType: "integer"; schema: Schema.Schema<boolean, number, never>; default: Some<false>; nullable: false; primaryKey: false; autoIncrement: false; }; readonly deletedAt: { ...; }; }>, State.SQLite.WithDefaults<...>, Schema.Schema<...>>; uiState: State.SQLite.ClientDocumentTableDef<...>; }; materializers: { ...; };}) => InternalState
makeState({ tables: { todos: State.SQLite.TableDef<State.SQLite.SqliteTableDefForInput<"todos", { readonly id: { columnType: "text"; schema: Schema.Schema<string, string, never>; default: None<never>; nullable: false; primaryKey: true; autoIncrement: false; }; readonly text: { columnType: "text"; schema: Schema.Schema<string, string, never>; default: Some<"">; nullable: false; primaryKey: false; autoIncrement: false; }; readonly completed: { columnType: "integer"; schema: Schema.Schema<boolean, number, never>; default: Some<false>; nullable: false; primaryKey: false; autoIncrement: false; }; readonly deletedAt: { ...; }; }>, State.SQLite.WithDefaults<...>, Schema.Schema<...>>; uiState: State.SQLite.ClientDocumentTableDef<...>;}
tables, materializers: { "v1.TodoCreated": State.SQLite.Materializer<State.SQLite.EventDef<"v1.TodoCreated", { readonly text: string; readonly id: string; }, { readonly text: string; readonly id: string; }, false>>; "v1.TodoCompleted": State.SQLite.Materializer<State.SQLite.EventDef<"v1.TodoCompleted", { readonly id: string; }, { readonly id: string; }, false>>; "v1.TodoUncompleted": State.SQLite.Materializer<State.SQLite.EventDef<"v1.TodoUncompleted", { readonly id: string; }, { readonly id: string; }, false>>; "v1.TodoDeleted": State.SQLite.Materializer<...>; "v1.TodoClearedCompleted": State.SQLite.Materializer<...>;}
materializers })
export const const schema: FromInputSchema.DeriveSchema<{ events: { todoCreated: State.SQLite.EventDef<"v1.TodoCreated", { readonly text: string; readonly id: string; }, { readonly text: string; readonly id: string; }, false>; todoCompleted: State.SQLite.EventDef<"v1.TodoCompleted", { readonly id: string; }, { readonly id: string; }, false>; todoUncompleted: State.SQLite.EventDef<"v1.TodoUncompleted", { readonly id: string; }, { readonly id: string; }, false>; todoDeleted: State.SQLite.EventDef<"v1.TodoDeleted", { readonly id: string; readonly deletedAt: Date; }, { readonly id: string; readonly deletedAt: string; }, false>; todoClearedCompleted: State.SQLite.EventDef<...>; uiStateSet: State.SQLite.ClientDocumentTableDef.SetEventDefLike<...>; }; state: InternalState;}>
schema = makeSchema<{ events: { todoCreated: State.SQLite.EventDef<"v1.TodoCreated", { readonly text: string; readonly id: string; }, { readonly text: string; readonly id: string; }, false>; todoCompleted: State.SQLite.EventDef<"v1.TodoCompleted", { readonly id: string; }, { readonly id: string; }, false>; todoUncompleted: State.SQLite.EventDef<"v1.TodoUncompleted", { readonly id: string; }, { readonly id: string; }, false>; todoDeleted: State.SQLite.EventDef<"v1.TodoDeleted", { readonly id: string; readonly deletedAt: Date; }, { readonly id: string; readonly deletedAt: string; }, false>; todoClearedCompleted: State.SQLite.EventDef<...>; uiStateSet: State.SQLite.ClientDocumentTableDef.SetEventDefLike<...>; }; state: InternalState;}>(inputSchema: { events: { todoCreated: State.SQLite.EventDef<"v1.TodoCreated", { readonly text: string; readonly id: string; }, { readonly text: string; readonly id: string; }, false>; todoCompleted: State.SQLite.EventDef<"v1.TodoCompleted", { readonly id: string; }, { readonly id: string; }, false>; todoUncompleted: State.SQLite.EventDef<"v1.TodoUncompleted", { readonly id: string; }, { readonly id: string; }, false>; todoDeleted: State.SQLite.EventDef<"v1.TodoDeleted", { readonly id: string; readonly deletedAt: Date; }, { readonly id: string; readonly deletedAt: string; }, false>; todoClearedCompleted: State.SQLite.EventDef<...>; uiStateSet: State.SQLite.ClientDocumentTableDef.SetEventDefLike<...>; }; state: InternalState;}): FromInputSchema.DeriveSchema<...>
makeSchema({ events: { todoCreated: State.SQLite.EventDef<"v1.TodoCreated", { readonly text: string; readonly id: string; }, { readonly text: string; readonly id: string; }, false>; todoCompleted: State.SQLite.EventDef<"v1.TodoCompleted", { readonly id: string; }, { readonly id: string; }, false>; todoUncompleted: State.SQLite.EventDef<"v1.TodoUncompleted", { readonly id: string; }, { readonly id: string; }, false>; todoDeleted: State.SQLite.EventDef<"v1.TodoDeleted", { readonly id: string; readonly deletedAt: Date; }, { readonly id: string; readonly deletedAt: string; }, false>; todoClearedCompleted: State.SQLite.EventDef<...>; uiStateSet: State.SQLite.ClientDocumentTableDef.SetEventDefLike<...>;}
events, state: InternalState
state })Defining Tables
Section titled “Defining Tables”Define SQLite tables using explicit column definitions:
import { import State
State } from '@livestore/livestore'
export const const userTable: State.SQLite.TableDef<State.SQLite.SqliteTableDefForInput<"users", { readonly id: { columnType: "text"; schema: Schema<string, string, never>; default: None<never>; nullable: false; primaryKey: true; autoIncrement: false; }; readonly email: { columnType: "text"; schema: Schema<string, string, never>; default: None<never>; nullable: false; primaryKey: false; autoIncrement: false; }; readonly name: { columnType: "text"; schema: Schema<string, string, never>; default: None<never>; nullable: false; primaryKey: false; autoIncrement: false; }; readonly age: { columnType: "integer"; ... 4 more ...; autoIncrement: false; }; readonly isActive: { ...; }; readonly metadata: { ...; };}>, State.SQLite.WithDefaults<...>, Schema<...>>
userTable = import State
State.import SQLite
SQLite.function table<"users", { readonly id: { columnType: "text"; schema: Schema<string, string, never>; default: None<never>; nullable: false; primaryKey: true; autoIncrement: false; }; readonly email: { columnType: "text"; schema: Schema<string, string, never>; default: None<never>; nullable: false; primaryKey: false; autoIncrement: false; }; readonly name: { columnType: "text"; schema: Schema<string, string, never>; default: None<never>; nullable: false; primaryKey: false; autoIncrement: false; }; readonly age: { columnType: "integer"; ... 4 more ...; autoIncrement: false; }; readonly isActive: { ...; }; readonly metadata: { ...; };}, { ...;}>(args: { ...;} & Partial<...>): State.SQLite.TableDef<...> (+2 overloads)
Creates a SQLite table definition from columns or an Effect Schema.
This function supports two main ways to define a table:
- Using explicit column definitions
- Using an Effect Schema (either the
name property needs to be provided or the schema needs to have a title/identifier)
// Using explicit columnsconst usersTable = State.SQLite.table({ name: 'users', columns: { id: State.SQLite.text({ primaryKey: true }), name: State.SQLite.text({ nullable: false }), email: State.SQLite.text({ nullable: false }), age: State.SQLite.integer({ nullable: true }), },})
// Using Effect Schema with annotationsimport { Schema } from '@livestore/utils/effect'
const UserSchema = Schema.Struct({ id: Schema.Int.pipe(State.SQLite.withPrimaryKey).pipe(State.SQLite.withAutoIncrement), email: Schema.String.pipe(State.SQLite.withUnique), name: Schema.String, active: Schema.Boolean.pipe(State.SQLite.withDefault(true)), createdAt: Schema.optional(Schema.Date),})
// Option 1: With explicit nameconst usersTable = State.SQLite.table({ name: 'users', schema: UserSchema,})
// Option 2: With name from schema annotation (title or identifier)const AnnotatedUserSchema = UserSchema.annotations({ title: 'users' })const usersTable2 = State.SQLite.table({ schema: AnnotatedUserSchema,})
// Adding indexesconst PostSchema = Schema.Struct({ id: Schema.String.pipe(State.SQLite.withPrimaryKey), title: Schema.String, authorId: Schema.String, createdAt: Schema.Date,}).annotations({ identifier: 'posts' })
const postsTable = State.SQLite.table({ schema: PostSchema, indexes: [ { name: 'idx_posts_author', columns: ['authorId'] }, { name: 'idx_posts_created', columns: ['createdAt'], isUnique: false }, ],})
table({ name: "users"
name: 'users', columns: { readonly id: { columnType: "text"; schema: Schema<string, string, never>; default: None<never>; nullable: false; primaryKey: true; autoIncrement: false; }; readonly email: { columnType: "text"; schema: Schema<string, string, never>; default: None<never>; nullable: false; primaryKey: false; autoIncrement: false; }; readonly name: { columnType: "text"; schema: Schema<string, string, never>; default: None<never>; nullable: false; primaryKey: false; autoIncrement: false; }; readonly age: { columnType: "integer"; ... 4 more ...; autoIncrement: false; }; readonly isActive: { ...; }; readonly metadata: { ...; };} & { ...;}
columns: { id: { columnType: "text"; schema: Schema<string, string, never>; default: None<never>; nullable: false; primaryKey: true; autoIncrement: false;}
id: import State
State.import SQLite
SQLite.const text: <string, string, false, typeof NoDefault, true, false>(args: { schema?: Schema<string, string, never>; default?: typeof NoDefault; nullable?: false; primaryKey?: true; autoIncrement?: false;}) => { columnType: "text"; schema: Schema<string, string, never>; default: None<never>; nullable: false; primaryKey: true; autoIncrement: false;} (+1 overload)
text({ primaryKey?: true
primaryKey: true }), email: { columnType: "text"; schema: Schema<string, string, never>; default: None<never>; nullable: false; primaryKey: false; autoIncrement: false;}
email: import State
State.import SQLite
SQLite.const text: () => { columnType: "text"; schema: Schema<string, string, never>; default: None<never>; nullable: false; primaryKey: false; autoIncrement: false;} (+1 overload)
text(), name: { columnType: "text"; schema: Schema<string, string, never>; default: None<never>; nullable: false; primaryKey: false; autoIncrement: false;}
name: import State
State.import SQLite
SQLite.const text: () => { columnType: "text"; schema: Schema<string, string, never>; default: None<never>; nullable: false; primaryKey: false; autoIncrement: false;} (+1 overload)
text(), age: { columnType: "integer"; schema: Schema<number, number, never>; default: Some<0>; nullable: false; primaryKey: false; autoIncrement: false;}
age: import State
State.import SQLite
SQLite.const integer: <number, number, false, 0, false, false>(args: { schema?: Schema<number, number, never>; default?: 0; nullable?: false; primaryKey?: false; autoIncrement?: false;}) => { columnType: "integer"; schema: Schema<number, number, never>; default: Some<0>; nullable: false; primaryKey: false; autoIncrement: false;} (+1 overload)
integer({ default?: 0
default: 0 }), isActive: { columnType: "integer"; schema: Schema<boolean, number, never>; default: Some<true>; nullable: false; primaryKey: false; autoIncrement: false;}
isActive: import State
State.import SQLite
SQLite.const boolean: <boolean, false, true, false, false>(args: { default?: true; nullable?: false; primaryKey?: false; autoIncrement?: false;}) => { columnType: "integer"; schema: Schema<boolean, number, never>; default: Some<true>; nullable: false; primaryKey: false; autoIncrement: false;} (+1 overload)
boolean({ default?: true
default: true }), metadata: { columnType: "text"; schema: Schema<unknown, string | null, never>; default: Some<any> | None<never>; nullable: true; primaryKey: false; autoIncrement: false;}
metadata: import State
State.import SQLite
SQLite.const json: <unknown, true, any, false, false>(args: { schema?: Schema<unknown, any, never>; default?: any; nullable?: true; primaryKey?: false; autoIncrement?: false;}) => { columnType: "text"; schema: Schema<unknown, string | null, never>; default: Some<any> | None<never>; nullable: true; primaryKey: false; autoIncrement: false;} (+1 overload)
json({ nullable?: true
nullable: true }), }, indexes?: [{ readonly name: "idx_users_email"; readonly columns: readonly ["email"]; readonly isUnique: true;}]
indexes: [{ name: "idx_users_email"
name: 'idx_users_email', columns: readonly ["email"]
columns: ['email'], isUnique: true
isUnique: true }],})Use the optional indexes array to declare secondary indexes or enforce uniqueness (set isUnique: true).
Column Types
Section titled “Column Types”You can use these column types when defining tables:
Core SQLite column types
Section titled “Core SQLite column types”State.SQLite.text: A text field, returnsstring.State.SQLite.integer: An integer field, returnsnumber.State.SQLite.real: A real field (floating point number), returnsnumber.State.SQLite.blob: A blob field (binary data), returnsUint8Array.
Higher level column types
Section titled “Higher level column types”State.SQLite.boolean: An integer field that stores0forfalseand1fortrueand returns aboolean.State.SQLite.json: A text field that stores a stringified JSON object and returns a decoded JSON value.State.SQLite.datetime: A text field that stores dates as ISO 8601 strings and returns aDate.State.SQLite.datetimeInteger: A integer field that stores dates as the number of milliseconds since the epoch and returns aDate.
Custom column schemas
Section titled “Custom column schemas”You can also provide a custom schema for a column which is used to automatically encode and decode the column value.
Example: JSON-encoded struct
Section titled “Example: JSON-encoded struct”import { import Schema
Schema, import State
State } from '@livestore/livestore'
export const const UserMetadata: Schema.Struct<{ petName: typeof Schema.String; favoriteColor: Schema.Literal<["red", "blue", "green"]>;}>
UserMetadata = import Schema
Schema.function Struct<{ petName: typeof Schema.String; favoriteColor: Schema.Literal<["red", "blue", "green"]>;}>(fields: { petName: typeof Schema.String; favoriteColor: Schema.Literal<["red", "blue", "green"]>;}): Schema.Struct<{ petName: typeof Schema.String; favoriteColor: Schema.Literal<["red", "blue", "green"]>;}> (+1 overload)
Struct({ petName: typeof Schema.String
petName: import Schema
Schema.class Stringexport String
String, favoriteColor: Schema.Literal<["red", "blue", "green"]>
favoriteColor: import Schema
Schema.function Literal<["red", "blue", "green"]>(literals_0: "red", literals_1: "blue", literals_2: "green"): Schema.Literal<["red", "blue", "green"]> (+2 overloads)
Literal('red', 'blue', 'green'),})
export const const userTable: State.SQLite.TableDef<State.SQLite.SqliteTableDefForInput<"user", { readonly id: { columnType: "text"; schema: Schema.Schema<string, string, never>; default: None<never>; nullable: false; primaryKey: true; autoIncrement: false; }; readonly name: { columnType: "text"; schema: Schema.Schema<string, string, never>; default: None<never>; nullable: false; primaryKey: false; autoIncrement: false; }; readonly metadata: { columnType: "text"; schema: Schema.Schema<{ readonly petName: string; readonly favoriteColor: "red" | "blue" | "green"; }, string, never>; default: Some<any> | None<...>; nullable: false; primaryKey: false; autoIncrement: false; };}>, State.SQLite.WithDefaults<...>, Schema.Schema<...>>
userTable = import State
State.import SQLite
SQLite.function table<"user", { readonly id: { columnType: "text"; schema: Schema.Schema<string, string, never>; default: None<never>; nullable: false; primaryKey: true; autoIncrement: false; }; readonly name: { columnType: "text"; schema: Schema.Schema<string, string, never>; default: None<never>; nullable: false; primaryKey: false; autoIncrement: false; }; readonly metadata: { columnType: "text"; schema: Schema.Schema<{ readonly petName: string; readonly favoriteColor: "red" | "blue" | "green"; }, string, never>; default: Some<any> | None<...>; nullable: false; primaryKey: false; autoIncrement: false; };}, Partial<...>>(args: { ...;} & Partial<...>): State.SQLite.TableDef<...> (+2 overloads)
Creates a SQLite table definition from columns or an Effect Schema.
This function supports two main ways to define a table:
- Using explicit column definitions
- Using an Effect Schema (either the
name property needs to be provided or the schema needs to have a title/identifier)
// Using explicit columnsconst usersTable = State.SQLite.table({ name: 'users', columns: { id: State.SQLite.text({ primaryKey: true }), name: State.SQLite.text({ nullable: false }), email: State.SQLite.text({ nullable: false }), age: State.SQLite.integer({ nullable: true }), },})
// Using Effect Schema with annotationsimport { Schema } from '@livestore/utils/effect'
const UserSchema = Schema.Struct({ id: Schema.Int.pipe(State.SQLite.withPrimaryKey).pipe(State.SQLite.withAutoIncrement), email: Schema.String.pipe(State.SQLite.withUnique), name: Schema.String, active: Schema.Boolean.pipe(State.SQLite.withDefault(true)), createdAt: Schema.optional(Schema.Date),})
// Option 1: With explicit nameconst usersTable = State.SQLite.table({ name: 'users', schema: UserSchema,})
// Option 2: With name from schema annotation (title or identifier)const AnnotatedUserSchema = UserSchema.annotations({ title: 'users' })const usersTable2 = State.SQLite.table({ schema: AnnotatedUserSchema,})
// Adding indexesconst PostSchema = Schema.Struct({ id: Schema.String.pipe(State.SQLite.withPrimaryKey), title: Schema.String, authorId: Schema.String, createdAt: Schema.Date,}).annotations({ identifier: 'posts' })
const postsTable = State.SQLite.table({ schema: PostSchema, indexes: [ { name: 'idx_posts_author', columns: ['authorId'] }, { name: 'idx_posts_created', columns: ['createdAt'], isUnique: false }, ],})
table({ name: "user"
name: 'user', columns: { readonly id: { columnType: "text"; schema: Schema.Schema<string, string, never>; default: None<never>; nullable: false; primaryKey: true; autoIncrement: false; }; readonly name: { columnType: "text"; schema: Schema.Schema<string, string, never>; default: None<never>; nullable: false; primaryKey: false; autoIncrement: false; }; readonly metadata: { columnType: "text"; schema: Schema.Schema<{ readonly petName: string; readonly favoriteColor: "red" | "blue" | "green"; }, string, never>; default: Some<any> | None<...>; nullable: false; primaryKey: false; autoIncrement: false; };}
columns: { id: { columnType: "text"; schema: Schema.Schema<string, string, never>; default: None<never>; nullable: false; primaryKey: true; autoIncrement: false;}
id: import State
State.import SQLite
SQLite.const text: <string, string, false, typeof NoDefault, true, false>(args: { schema?: Schema.Schema<string, string, never>; default?: typeof NoDefault; nullable?: false; primaryKey?: true; autoIncrement?: false;}) => { columnType: "text"; schema: Schema.Schema<string, string, never>; default: None<never>; nullable: false; primaryKey: true; autoIncrement: false;} (+1 overload)
text({ primaryKey?: true
primaryKey: true }), name: { columnType: "text"; schema: Schema.Schema<string, string, never>; default: None<never>; nullable: false; primaryKey: false; autoIncrement: false;}
name: import State
State.import SQLite
SQLite.const text: () => { columnType: "text"; schema: Schema.Schema<string, string, never>; default: None<never>; nullable: false; primaryKey: false; autoIncrement: false;} (+1 overload)
text(), metadata: { columnType: "text"; schema: Schema.Schema<{ readonly petName: string; readonly favoriteColor: "red" | "blue" | "green"; }, string, never>; default: Some<any> | None<never>; nullable: false; primaryKey: false; autoIncrement: false;}
metadata: import State
State.import SQLite
SQLite.const json: <{ readonly petName: string; readonly favoriteColor: "red" | "blue" | "green";}, false, any, false, false>(args: { schema?: Schema.Schema<{ readonly petName: string; readonly favoriteColor: "red" | "blue" | "green"; }, any, never>; default?: any; nullable?: false; primaryKey?: false; autoIncrement?: false;}) => { columnType: "text"; schema: Schema.Schema<{ readonly petName: string; readonly favoriteColor: "red" | "blue" | "green"; }, string, never>; default: Some<any> | None<never>; nullable: false; primaryKey: false; autoIncrement: false;} (+1 overload)
json({ schema?: Schema.Schema<{ readonly petName: string; readonly favoriteColor: "red" | "blue" | "green";}, any, never>
schema: const UserMetadata: Schema.Struct<{ petName: typeof Schema.String; favoriteColor: Schema.Literal<["red", "blue", "green"]>;}>
UserMetadata }), },})Schema migrations
Section titled “Schema migrations”Migration strategies:
auto: Automatically migrate the database to the newest schema and rematerializes the state from the eventlog.manual: Manually migrate the database to the newest schema.
Client documents
Section titled “Client documents”- Meant for convenience
- Client-only
- Goal: Similar ease of use as
React.useState - When schema changes in a non-backwards compatible way, previous events are dropped and the state is reset
- Don’t use client documents for sensitive data which must not be lost
- Implies
- Table with
idandvaluecolumns ${MyTable}Setevent + materializer (which are auto-registered)
- Table with
Basic usage
Section titled “Basic usage”import { import Schema
Schema, type SessionIdSymbol = typeof SessionIdSymbolconst SessionIdSymbol: typeof SessionIdSymbol
Can be used in queries to refer to the current session id.
Will be replaced with the actual session id at runtime
In client document table:
const uiState = State.SQLite.clientDocument({ name: 'ui_state', schema: Schema.Struct({ theme: Schema.Literal('dark', 'light', 'system'), user: Schema.String, showToolbar: Schema.Boolean, }), default: { value: defaultFrontendState, id: SessionIdSymbol },})
Or in a client document query:
const query$ = queryDb(tables.uiState.get(SessionIdSymbol))
SessionIdSymbol, import State
State, type class Store<TSchema extends LiveStoreSchema = LiveStoreSchema.Any, TContext = {}>
Store } from '@livestore/livestore'import { const useClientDocument: { <TTableDef extends State.SQLite.ClientDocumentTableDef.Trait<any, any, any, { partialSet: boolean; default: any; }>>(table: TTableDef, id?: State.SQLite.ClientDocumentTableDef.DefaultIdType<TTableDef> | SessionIdSymbol, options?: Partial<RowQuery.GetOrCreateOptions<TTableDef>>): UseClientDocumentResult<TTableDef>; <TTableDef extends State.SQLite.ClientDocumentTableDef.Trait<any, any, any, { partialSet: boolean; default: any; }>>(table: TTableDef, id: State.SQLite.ClientDocumentTableDef.DefaultIdType<TTableDef> | string | SessionIdSymbol, options?: Partial<RowQuery.GetOrCreateOptions<TTableDef>>): UseClientDocumentResult<TTableDef>;}
Similar to React.useState but returns a tuple of [state, setState, id, query$] for a given table where ...
state is the current value of the row (fully decoded according to the table schema)
setState is a function that can be used to update the document
id is the id of the document
query$ is a LiveQuery that e.g. can be used to subscribe to changes to the document
useClientDocument only works for client-document tables:
const MyState = State.SQLite.clientDocument({ name: 'MyState', schema: Schema.Struct({ showSidebar: Schema.Boolean, }), default: { id: SessionIdSymbol, value: { showSidebar: true } },})
const MyComponent = () => { const [{ showSidebar }, setState] = useClientDocument(MyState) return ( <div onClick={() => setState({ showSidebar: !showSidebar })}> {showSidebar ? 'Sidebar is open' : 'Sidebar is closed'} </div> )}
If the table has a default id, useClientDocument can be called without an id argument. Otherwise, the id argument is required.
useClientDocument } from '@livestore/react'import (alias) namespace Reactimport React
React from 'react'
export const const uiState: State.SQLite.ClientDocumentTableDef<"UiState", { readonly filter: "all" | "active" | "completed"; readonly newTodoText: string;}, { readonly filter: "all" | "active" | "completed"; readonly newTodoText: string;}, { partialSet: true; default: { id: typeof SessionIdSymbol; value: { readonly newTodoText: ""; readonly filter: "all"; }; };}>
uiState = import State
State.import SQLite
SQLite.clientDocument<"UiState", { readonly filter: "all" | "active" | "completed"; readonly newTodoText: string;}, { readonly filter: "all" | "active" | "completed"; readonly newTodoText: string;}, { readonly name: "UiState"; readonly schema: Schema.Struct<{ newTodoText: typeof Schema.String; filter: Schema.Literal<["all", "active", "completed"]>; }>; readonly default: { readonly id: typeof SessionIdSymbol; readonly value: { readonly newTodoText: ""; readonly filter: "all"; }; };}>({ name, schema: valueSchema, ...inputOptions }: { name: "UiState"; schema: Schema.Schema<{ readonly filter: "all" | "active" | "completed"; readonly newTodoText: string; }, { ...; }, never>;} & { readonly name: "UiState"; readonly schema: Schema.Struct<{ newTodoText: typeof Schema.String; filter: Schema.Literal<["all", "active", "completed"]>; }>; readonly default: { readonly id: typeof SessionIdSymbol; readonly value: { readonly newTodoText: ""; readonly filter: "all"; }; };}): State.SQLite.ClientDocumentTableDef<...>export clientDocument
Special:
- Synced across client sessions (e.g. tabs) but not across different clients
- Derived setters
- Emits client-only events
- Has implicit setter-materializers
- Similar to
React.useState (except it's persisted)
Careful:
- When changing the table definitions in a non-backwards compatible way, the state might be lost without
explicit materializers to handle the old auto-generated events
Usage:
// Querying data// `'some-id'` can be ommited for SessionIdSymbolstore.queryDb(clientDocumentTable.get('some-id'))
// Setting data// Again, `'some-id'` can be ommited for SessionIdSymbolstore.commit(clientDocumentTable.set({ someField: 'some-value' }, 'some-id'))
clientDocument({ name: "UiState"
name: 'UiState', schema: Schema.Schema<{ readonly filter: "all" | "active" | "completed"; readonly newTodoText: string;}, { readonly filter: "all" | "active" | "completed"; readonly newTodoText: string;}, never> & Schema.Struct<{ newTodoText: typeof Schema.String; filter: Schema.Literal<["all", "active", "completed"]>;}>
schema: import Schema
Schema.function Struct<{ newTodoText: typeof Schema.String; filter: Schema.Literal<["all", "active", "completed"]>;}>(fields: { newTodoText: typeof Schema.String; filter: Schema.Literal<["all", "active", "completed"]>;}): Schema.Struct<{ newTodoText: typeof Schema.String; filter: Schema.Literal<["all", "active", "completed"]>;}> (+1 overload)
Struct({ newTodoText: typeof Schema.String
newTodoText: import Schema
Schema.class Stringexport String
String, filter: Schema.Literal<["all", "active", "completed"]>
filter: import Schema
Schema.function Literal<["all", "active", "completed"]>(literals_0: "all", literals_1: "active", literals_2: "completed"): Schema.Literal<["all", "active", "completed"]> (+2 overloads)
Literal('all', 'active', 'completed'), }), default: { readonly id: typeof SessionIdSymbol; readonly value: { readonly newTodoText: ""; readonly filter: "all"; };}
default: { id: typeof SessionIdSymbol
id: const SessionIdSymbol: typeof SessionIdSymbol
Can be used in queries to refer to the current session id.
Will be replaced with the actual session id at runtime
In client document table:
const uiState = State.SQLite.clientDocument({ name: 'ui_state', schema: Schema.Struct({ theme: Schema.Literal('dark', 'light', 'system'), user: Schema.String, showToolbar: Schema.Boolean, }), default: { value: defaultFrontendState, id: SessionIdSymbol },})
Or in a client document query:
const query$ = queryDb(tables.uiState.get(SessionIdSymbol))
SessionIdSymbol, value: { readonly newTodoText: ""; readonly filter: "all";}
value: { newTodoText: ""
newTodoText: '', filter: "all"
filter: 'all' } },})
export const const readUiState: (store: Store) => { newTodoText: string; filter: "all" | "active" | "completed";}
readUiState = (store: Store<LiveStoreSchema.Any, {}>
store: class Store<TSchema extends LiveStoreSchema = LiveStoreSchema.Any, TContext = {}>
Store): { newTodoText: string
newTodoText: string; filter: "all" | "active" | "completed"
filter: 'all' | 'active' | 'completed' } => store: Store<LiveStoreSchema.Any, {}>
store.Store<LiveStoreSchema<TDbSchema extends DbSchema = DbSchema, TEventsDefRecord extends EventDefRecord = EventDefRecord>.Any, {}>.query: <{ readonly filter: "all" | "active" | "completed"; readonly newTodoText: string;}>(query: Queryable<{ readonly filter: "all" | "active" | "completed"; readonly newTodoText: string;}> | { query: string; bindValues: Bindable; schema?: Schema.Schema<{ readonly filter: "all" | "active" | "completed"; readonly newTodoText: string; }, { readonly filter: "all" | "active" | "completed"; readonly newTodoText: string; }, never>;}, options?: { otelContext?: Context; debugRefreshReason?: RefreshReason;}) => { readonly filter: "all" | "active" | "completed"; readonly newTodoText: string;}
Synchronously queries the database without creating a LiveQuery.
This is useful for queries that don't need to be reactive.
Example: Query builder
const completedTodos = store.query(tables.todo.where({ complete: true }))
Example: Raw SQL query
const completedTodos = store.query({ query: 'SELECT * FROM todo WHERE complete = 1', bindValues: {} })
query(const uiState: State.SQLite.ClientDocumentTableDef<"UiState", { readonly filter: "all" | "active" | "completed"; readonly newTodoText: string;}, { readonly filter: "all" | "active" | "completed"; readonly newTodoText: string;}, { partialSet: true; default: { id: typeof SessionIdSymbol; value: { readonly newTodoText: ""; readonly filter: "all"; }; };}>
uiState.ClientDocumentTableDef<TName extends string, TType, TEncoded, TOptions extends ClientDocumentTableOptions<TType>>.Trait<"UiState", { readonly filter: "all" | "active" | "completed"; readonly newTodoText: string; }, { readonly filter: "all" | "active" | "completed"; readonly newTodoText: string; }, { ...; }>.get: (id?: typeof SessionIdSymbol | undefined, options?: { default: Partial<{ readonly filter: "all" | "active" | "completed"; readonly newTodoText: string; }>;} | undefined) => QueryBuilder<{ readonly filter: "all" | "active" | "completed"; readonly newTodoText: string;}, State.SQLite.ClientDocumentTableDef.TableDefBase_<"UiState", { readonly filter: "all" | "active" | "completed"; readonly newTodoText: string;}>, QueryBuilder<TResult, TTableDef extends State.SQLite.TableDefBase, TWithout extends QueryBuilder.ApiFeature = never>.ApiFeature>
Get the current value of the client document table.
get())
export const const setNewTodoText: (store: Store, newTodoText: string) => void
setNewTodoText = (store: Store<LiveStoreSchema.Any, {}>
store: class Store<TSchema extends LiveStoreSchema = LiveStoreSchema.Any, TContext = {}>
Store, newTodoText: string
newTodoText: string): void => { store: Store<LiveStoreSchema.Any, {}>
store.Store<LiveStoreSchema<TDbSchema extends DbSchema = DbSchema, TEventsDefRecord extends EventDefRecord = EventDefRecord>.Any, {}>.commit: <readonly [{ name: "UiStateSet"; args: { id: string; value: { readonly filter: "all" | "active" | "completed"; readonly newTodoText: string; }; };}]>(list_0: { name: "UiStateSet"; args: { id: string; value: { readonly filter: "all" | "active" | "completed"; readonly newTodoText: string; }; };}) => void (+3 overloads)
commit(const uiState: State.SQLite.ClientDocumentTableDef<"UiState", { readonly filter: "all" | "active" | "completed"; readonly newTodoText: string;}, { readonly filter: "all" | "active" | "completed"; readonly newTodoText: string;}, { partialSet: true; default: { id: typeof SessionIdSymbol; value: { readonly newTodoText: ""; readonly filter: "all"; }; };}>
uiState.ClientDocumentTableDef<TName extends string, TType, TEncoded, TOptions extends ClientDocumentTableOptions<TType>>.Trait<"UiState", { readonly filter: "all" | "active" | "completed"; readonly newTodoText: string; }, { readonly filter: "all" | "active" | "completed"; readonly newTodoText: string; }, { ...; }>.set: (args: Partial<{ readonly filter: "all" | "active" | "completed"; readonly newTodoText: string;}>, id?: string | SessionIdSymbol) => { name: "UiStateSet"; args: { id: string; value: { readonly filter: "all" | "active" | "completed"; readonly newTodoText: string; }; };}
Derived event definition for setting the value of the client document table.
If the document doesn't exist yet, the first .set event will create it.
set({ newTodoText?: string
newTodoText }))}
export const const UiStateFilter: React.FC<{}>
UiStateFilter: (alias) namespace Reactimport React
React.type React.FC<P = {}> = React.FunctionComponent<P>
Represents the type of a function component. Can optionally
receive a type argument that represents the props the component
receives.
FC = () => { const [const state: { readonly filter: "all" | "active" | "completed"; readonly newTodoText: string;}
state, const setState: StateSetters<State.SQLite.ClientDocumentTableDef<"UiState", { readonly filter: "all" | "active" | "completed"; readonly newTodoText: string;}, { readonly filter: "all" | "active" | "completed"; readonly newTodoText: string;}, { partialSet: true; default: { id: typeof SessionIdSymbol; value: { readonly newTodoText: ""; readonly filter: "all"; }; };}>>
setState] = useClientDocument<State.SQLite.ClientDocumentTableDef<"UiState", { readonly filter: "all" | "active" | "completed"; readonly newTodoText: string;}, { readonly filter: "all" | "active" | "completed"; readonly newTodoText: string;}, { partialSet: true; default: { id: typeof SessionIdSymbol; value: { readonly newTodoText: ""; readonly filter: "all"; }; };}>>(table: State.SQLite.ClientDocumentTableDef<"UiState", { readonly filter: "all" | "active" | "completed"; readonly newTodoText: string;}, { readonly filter: "all" | "active" | "completed"; readonly newTodoText: string;}, { partialSet: true; default: { id: typeof SessionIdSymbol; value: { readonly newTodoText: ""; readonly filter: "all"; }; };}>, id?: typeof SessionIdSymbol | undefined, options?: Partial<...> | undefined): UseClientDocumentResult<...> (+1 overload)
Similar to React.useState but returns a tuple of [state, setState, id, query$] for a given table where ...
state is the current value of the row (fully decoded according to the table schema)
setState is a function that can be used to update the document
id is the id of the document
query$ is a LiveQuery that e.g. can be used to subscribe to changes to the document
useClientDocument only works for client-document tables:
const MyState = State.SQLite.clientDocument({ name: 'MyState', schema: Schema.Struct({ showSidebar: Schema.Boolean, }), default: { id: SessionIdSymbol, value: { showSidebar: true } },})
const MyComponent = () => { const [{ showSidebar }, setState] = useClientDocument(MyState) return ( <div onClick={() => setState({ showSidebar: !showSidebar })}> {showSidebar ? 'Sidebar is open' : 'Sidebar is closed'} </div> )}
If the table has a default id, useClientDocument can be called without an id argument. Otherwise, the id argument is required.
useClientDocument(const uiState: State.SQLite.ClientDocumentTableDef<"UiState", { readonly filter: "all" | "active" | "completed"; readonly newTodoText: string;}, { readonly filter: "all" | "active" | "completed"; readonly newTodoText: string;}, { partialSet: true; default: { id: typeof SessionIdSymbol; value: { readonly newTodoText: ""; readonly filter: "all"; }; };}>
uiState)
const const showActive: () => void
showActive = (alias) namespace Reactimport React
React.function React.useCallback<() => void>(callback: () => void, deps: React.DependencyList): () => void
useCallback will return a memoized version of the callback that only changes if one of the inputs
has changed.
useCallback(() => { const setState: (action: SetStateActionPartial<{ readonly filter: "all" | "active" | "completed"; readonly newTodoText: string;}>) => void
setState({ filter?: "all" | "active" | "completed"
filter: 'active' }) }, [const setState: StateSetters<State.SQLite.ClientDocumentTableDef<"UiState", { readonly filter: "all" | "active" | "completed"; readonly newTodoText: string;}, { readonly filter: "all" | "active" | "completed"; readonly newTodoText: string;}, { partialSet: true; default: { id: typeof SessionIdSymbol; value: { readonly newTodoText: ""; readonly filter: "all"; }; };}>>
setState])
const const showAll: () => void
showAll = (alias) namespace Reactimport React
React.function React.useCallback<() => void>(callback: () => void, deps: React.DependencyList): () => void
useCallback will return a memoized version of the callback that only changes if one of the inputs
has changed.
useCallback(() => { const setState: (action: SetStateActionPartial<{ readonly filter: "all" | "active" | "completed"; readonly newTodoText: string;}>) => void
setState({ filter?: "all" | "active" | "completed"
filter: 'all' }) }, [const setState: StateSetters<State.SQLite.ClientDocumentTableDef<"UiState", { readonly filter: "all" | "active" | "completed"; readonly newTodoText: string;}, { readonly filter: "all" | "active" | "completed"; readonly newTodoText: string;}, { partialSet: true; default: { id: typeof SessionIdSymbol; value: { readonly newTodoText: ""; readonly filter: "all"; }; };}>>
setState])
return ( <React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>
div> <React.JSX.IntrinsicElements.button: React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>
button React.ButtonHTMLAttributes<HTMLButtonElement>.type?: "button" | "submit" | "reset" | undefined
type="button" React.DOMAttributes<HTMLButtonElement>.onClick?: React.MouseEventHandler<HTMLButtonElement> | undefined
onClick={const showAll: () => void
showAll}> All </React.JSX.IntrinsicElements.button: React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>
button> <React.JSX.IntrinsicElements.button: React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>
button React.ButtonHTMLAttributes<HTMLButtonElement>.type?: "button" | "submit" | "reset" | undefined
type="button" React.DOMAttributes<HTMLButtonElement>.onClick?: React.MouseEventHandler<HTMLButtonElement> | undefined
onClick={const showActive: () => void
showActive}> Active ({const state: { readonly filter: "all" | "active" | "completed"; readonly newTodoText: string;}
state.filter: "all" | "active" | "completed"
filter === 'active' ? 'selected' : 'select'}) </React.JSX.IntrinsicElements.button: React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>
button> </React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>
div> )}KV-style client document
Section titled “KV-style client document”Sometimes you want a simple key-value store for arbitrary values without partial merging. You can model this by using Schema.Any as the value schema. With Schema.Any, updates fully replace the stored value (no partial merge semantics).
import { import Schema
Schema, import State
State, type class Store<TSchema extends LiveStoreSchema = LiveStoreSchema.Any, TContext = {}>
Store } from '@livestore/livestore'import { const useClientDocument: { <TTableDef extends State.SQLite.ClientDocumentTableDef.Trait<any, any, any, { partialSet: boolean; default: any; }>>(table: TTableDef, id?: State.SQLite.ClientDocumentTableDef.DefaultIdType<TTableDef> | SessionIdSymbol, options?: Partial<RowQuery.GetOrCreateOptions<TTableDef>>): UseClientDocumentResult<TTableDef>; <TTableDef extends State.SQLite.ClientDocumentTableDef.Trait<any, any, any, { partialSet: boolean; default: any; }>>(table: TTableDef, id: State.SQLite.ClientDocumentTableDef.DefaultIdType<TTableDef> | string | SessionIdSymbol, options?: Partial<RowQuery.GetOrCreateOptions<TTableDef>>): UseClientDocumentResult<TTableDef>;}
Similar to React.useState but returns a tuple of [state, setState, id, query$] for a given table where ...
state is the current value of the row (fully decoded according to the table schema)
setState is a function that can be used to update the document
id is the id of the document
query$ is a LiveQuery that e.g. can be used to subscribe to changes to the document
useClientDocument only works for client-document tables:
const MyState = State.SQLite.clientDocument({ name: 'MyState', schema: Schema.Struct({ showSidebar: Schema.Boolean, }), default: { id: SessionIdSymbol, value: { showSidebar: true } },})
const MyComponent = () => { const [{ showSidebar }, setState] = useClientDocument(MyState) return ( <div onClick={() => setState({ showSidebar: !showSidebar })}> {showSidebar ? 'Sidebar is open' : 'Sidebar is closed'} </div> )}
If the table has a default id, useClientDocument can be called without an id argument. Otherwise, the id argument is required.
useClientDocument } from '@livestore/react'import type (alias) namespace Reactimport React
React from 'react'
export const const kv: State.SQLite.ClientDocumentTableDef<"Kv", any, any, { partialSet: false; default: { id: undefined; value: null; };}>
kv = import State
State.import SQLite
SQLite.clientDocument<"Kv", any, any, { readonly name: "Kv"; readonly schema: typeof Schema.Any; readonly default: { readonly value: null; };}>({ name, schema: valueSchema, ...inputOptions }: { name: "Kv"; schema: Schema.Schema<any, any, never>;} & { readonly name: "Kv"; readonly schema: typeof Schema.Any; readonly default: { readonly value: null; };}): State.SQLite.ClientDocumentTableDef<"Kv", any, any, { partialSet: false; default: { id: undefined; value: null; };}>export clientDocument
Special:
- Synced across client sessions (e.g. tabs) but not across different clients
- Derived setters
- Emits client-only events
- Has implicit setter-materializers
- Similar to
React.useState (except it's persisted)
Careful:
- When changing the table definitions in a non-backwards compatible way, the state might be lost without
explicit materializers to handle the old auto-generated events
Usage:
// Querying data// `'some-id'` can be ommited for SessionIdSymbolstore.queryDb(clientDocumentTable.get('some-id'))
// Setting data// Again, `'some-id'` can be ommited for SessionIdSymbolstore.commit(clientDocumentTable.set({ someField: 'some-value' }, 'some-id'))
clientDocument({ name: "Kv"
name: 'Kv', schema: Schema.Schema<any, any, never> & typeof Schema.Any
schema: import Schema
Schema.class Any
Any, default: { readonly value: null;}
default: { value: null
value: null },})
export const const readKvValue: (store: Store, id: string) => unknown
readKvValue = (store: Store<LiveStoreSchema.Any, {}>
store: class Store<TSchema extends LiveStoreSchema = LiveStoreSchema.Any, TContext = {}>
Store, id: string
id: string): unknown => store: Store<LiveStoreSchema.Any, {}>
store.Store<LiveStoreSchema<TDbSchema extends DbSchema = DbSchema, TEventsDefRecord extends EventDefRecord = EventDefRecord>.Any, {}>.query: <any>(query: Queryable<any> | { query: string; bindValues: Bindable; schema?: Schema.Schema<any, any, never>;}, options?: { otelContext?: Context; debugRefreshReason?: RefreshReason;}) => any
Synchronously queries the database without creating a LiveQuery.
This is useful for queries that don't need to be reactive.
Example: Query builder
const completedTodos = store.query(tables.todo.where({ complete: true }))
Example: Raw SQL query
const completedTodos = store.query({ query: 'SELECT * FROM todo WHERE complete = 1', bindValues: {} })
query(const kv: State.SQLite.ClientDocumentTableDef<"Kv", any, any, { partialSet: false; default: { id: undefined; value: null; };}>
kv.ClientDocumentTableDef<TName extends string, TType, TEncoded, TOptions extends ClientDocumentTableOptions<TType>>.Trait<"Kv", any, any, { partialSet: false; default: { id: undefined; value: null; }; }>.get: (id: string | SessionIdSymbol, options?: { default: Partial<any>;} | undefined) => QueryBuilder<any, State.SQLite.ClientDocumentTableDef.TableDefBase_<"Kv", any>, QueryBuilder<TResult, TTableDef extends State.SQLite.TableDefBase, TWithout extends QueryBuilder.ApiFeature = never>.ApiFeature>
Get the current value of the client document table.
get(id: string
id))
export const const setKvValue: (store: Store, id: string, value: unknown) => void
setKvValue = (store: Store<LiveStoreSchema.Any, {}>
store: class Store<TSchema extends LiveStoreSchema = LiveStoreSchema.Any, TContext = {}>
Store, id: string
id: string, value: unknown
value: unknown): void => { store: Store<LiveStoreSchema.Any, {}>
store.Store<LiveStoreSchema<TDbSchema extends DbSchema = DbSchema, TEventsDefRecord extends EventDefRecord = EventDefRecord>.Any, {}>.commit: <readonly [{ name: "KvSet"; args: { id: string; value: any; };}]>(list_0: { name: "KvSet"; args: { id: string; value: any; };}) => void (+3 overloads)
commit(const kv: State.SQLite.ClientDocumentTableDef<"Kv", any, any, { partialSet: false; default: { id: undefined; value: null; };}>
kv.ClientDocumentTableDef<TName extends string, TType, TEncoded, TOptions extends ClientDocumentTableOptions<TType>>.Trait<"Kv", any, any, { partialSet: false; default: { id: undefined; value: null; }; }>.set: (args: any, id: string | SessionIdSymbol) => { name: "KvSet"; args: { id: string; value: any; };}
Derived event definition for setting the value of the client document table.
If the document doesn't exist yet, the first .set event will create it.
set(value: unknown
value, id: string
id))}
export const const KvViewer: React.FC<{ id: string;}>
KvViewer: (alias) namespace Reactimport React
React.type React.FC<P = {}> = React.FunctionComponent<P>
Represents the type of a function component. Can optionally
receive a type argument that represents the props the component
receives.
FC<{ id: string
id: string }> = ({ id: string
id }) => { const [const value: any
value, const setValue: StateSetters<State.SQLite.ClientDocumentTableDef<"Kv", any, any, { partialSet: false; default: { id: undefined; value: null; };}>>
setValue] = useClientDocument<State.SQLite.ClientDocumentTableDef<"Kv", any, any, { partialSet: false; default: { id: undefined; value: null; };}>>(table: State.SQLite.ClientDocumentTableDef<"Kv", any, any, { partialSet: false; default: { id: undefined; value: null; };}>, id: string | typeof SessionIdSymbol, options?: Partial<RowQuery.GetOrCreateOptions<State.SQLite.ClientDocumentTableDef<"Kv", any, any, { partialSet: false; default: { id: undefined; value: null; };}>>> | undefined): UseClientDocumentResult<State.SQLite.ClientDocumentTableDef<"Kv", any, any, { partialSet: false; default: { id: undefined; value: null; };}>> (+1 overload)
Similar to React.useState but returns a tuple of [state, setState, id, query$] for a given table where ...
state is the current value of the row (fully decoded according to the table schema)
setState is a function that can be used to update the document
id is the id of the document
query$ is a LiveQuery that e.g. can be used to subscribe to changes to the document
useClientDocument only works for client-document tables:
const MyState = State.SQLite.clientDocument({ name: 'MyState', schema: Schema.Struct({ showSidebar: Schema.Boolean, }), default: { id: SessionIdSymbol, value: { showSidebar: true } },})
const MyComponent = () => { const [{ showSidebar }, setState] = useClientDocument(MyState) return ( <div onClick={() => setState({ showSidebar: !showSidebar })}> {showSidebar ? 'Sidebar is open' : 'Sidebar is closed'} </div> )}
If the table has a default id, useClientDocument can be called without an id argument. Otherwise, the id argument is required.
useClientDocument(const kv: State.SQLite.ClientDocumentTableDef<"Kv", any, any, { partialSet: false; default: { id: undefined; value: null; };}>
kv, id: string
id)
return ( <React.JSX.IntrinsicElements.button: React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>
button React.ButtonHTMLAttributes<HTMLButtonElement>.type?: "button" | "submit" | "reset" | undefined
type="button" React.DOMAttributes<HTMLButtonElement>.onClick?: React.MouseEventHandler<HTMLButtonElement> | undefined
onClick={() => const setValue: (action: any) => void
setValue('hello')}> Current value: {var JSON: JSON
An intrinsic object that provides functions to convert JavaScript values to and from the JavaScript Object Notation (JSON) format.
JSON.JSON.stringify(value: any, replacer?: (this: any, key: string, value: any) => any, space?: string | number): string (+1 overload)
Converts a JavaScript value to a JavaScript Object Notation (JSON) string.
stringify(const value: any
value)} </React.JSX.IntrinsicElements.button: React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>
button> )}Column Types
Section titled “Column Types”You can use these column types:
Core SQLite column types
Section titled “Core SQLite column types”State.SQLite.text: A text field, returnsstring.State.SQLite.integer: An integer field, returnsnumber.State.SQLite.real: A real field (floating point number), returnsnumber.State.SQLite.blob: A blob field (binary data), returnsUint8Array.
Higher level column types
Section titled “Higher level column types”State.SQLite.boolean: An integer field that stores0forfalseand1fortrueand returns aboolean.State.SQLite.json: A text field that stores a stringified JSON object and returns a decoded JSON value.State.SQLite.datetime: A text field that stores dates as ISO 8601 strings and returns aDate.State.SQLite.datetimeInteger: A integer field that stores dates as the number of milliseconds since the epoch and returns aDate.
Custom column schemas
Section titled “Custom column schemas”You can also provide a custom schema for a column which is used to automatically encode and decode the column value.
Example: JSON-encoded struct
Section titled “Example: JSON-encoded struct”import { import Schema
Schema, import State
State } from '@livestore/livestore'
export const const UserMetadata: Schema.Struct<{ petName: typeof Schema.String; favoriteColor: Schema.Literal<["red", "blue", "green"]>;}>
UserMetadata = import Schema
Schema.function Struct<{ petName: typeof Schema.String; favoriteColor: Schema.Literal<["red", "blue", "green"]>;}>(fields: { petName: typeof Schema.String; favoriteColor: Schema.Literal<["red", "blue", "green"]>;}): Schema.Struct<{ petName: typeof Schema.String; favoriteColor: Schema.Literal<["red", "blue", "green"]>;}> (+1 overload)
Struct({ petName: typeof Schema.String
petName: import Schema
Schema.class Stringexport String
String, favoriteColor: Schema.Literal<["red", "blue", "green"]>
favoriteColor: import Schema
Schema.function Literal<["red", "blue", "green"]>(literals_0: "red", literals_1: "blue", literals_2: "green"): Schema.Literal<["red", "blue", "green"]> (+2 overloads)
Literal('red', 'blue', 'green'),})
export const const userTable: State.SQLite.TableDef<State.SQLite.SqliteTableDefForInput<"user", { readonly id: { columnType: "text"; schema: Schema.Schema<string, string, never>; default: None<never>; nullable: false; primaryKey: true; autoIncrement: false; }; readonly name: { columnType: "text"; schema: Schema.Schema<string, string, never>; default: None<never>; nullable: false; primaryKey: false; autoIncrement: false; }; readonly metadata: { columnType: "text"; schema: Schema.Schema<{ readonly petName: string; readonly favoriteColor: "red" | "blue" | "green"; }, string, never>; default: Some<any> | None<...>; nullable: false; primaryKey: false; autoIncrement: false; };}>, State.SQLite.WithDefaults<...>, Schema.Schema<...>>
userTable = import State
State.import SQLite
SQLite.function table<"user", { readonly id: { columnType: "text"; schema: Schema.Schema<string, string, never>; default: None<never>; nullable: false; primaryKey: true; autoIncrement: false; }; readonly name: { columnType: "text"; schema: Schema.Schema<string, string, never>; default: None<never>; nullable: false; primaryKey: false; autoIncrement: false; }; readonly metadata: { columnType: "text"; schema: Schema.Schema<{ readonly petName: string; readonly favoriteColor: "red" | "blue" | "green"; }, string, never>; default: Some<any> | None<...>; nullable: false; primaryKey: false; autoIncrement: false; };}, Partial<...>>(args: { ...;} & Partial<...>): State.SQLite.TableDef<...> (+2 overloads)
Creates a SQLite table definition from columns or an Effect Schema.
This function supports two main ways to define a table:
- Using explicit column definitions
- Using an Effect Schema (either the
name property needs to be provided or the schema needs to have a title/identifier)
// Using explicit columnsconst usersTable = State.SQLite.table({ name: 'users', columns: { id: State.SQLite.text({ primaryKey: true }), name: State.SQLite.text({ nullable: false }), email: State.SQLite.text({ nullable: false }), age: State.SQLite.integer({ nullable: true }), },})
// Using Effect Schema with annotationsimport { Schema } from '@livestore/utils/effect'
const UserSchema = Schema.Struct({ id: Schema.Int.pipe(State.SQLite.withPrimaryKey).pipe(State.SQLite.withAutoIncrement), email: Schema.String.pipe(State.SQLite.withUnique), name: Schema.String, active: Schema.Boolean.pipe(State.SQLite.withDefault(true)), createdAt: Schema.optional(Schema.Date),})
// Option 1: With explicit nameconst usersTable = State.SQLite.table({ name: 'users', schema: UserSchema,})
// Option 2: With name from schema annotation (title or identifier)const AnnotatedUserSchema = UserSchema.annotations({ title: 'users' })const usersTable2 = State.SQLite.table({ schema: AnnotatedUserSchema,})
// Adding indexesconst PostSchema = Schema.Struct({ id: Schema.String.pipe(State.SQLite.withPrimaryKey), title: Schema.String, authorId: Schema.String, createdAt: Schema.Date,}).annotations({ identifier: 'posts' })
const postsTable = State.SQLite.table({ schema: PostSchema, indexes: [ { name: 'idx_posts_author', columns: ['authorId'] }, { name: 'idx_posts_created', columns: ['createdAt'], isUnique: false }, ],})
table({ name: "user"
name: 'user', columns: { readonly id: { columnType: "text"; schema: Schema.Schema<string, string, never>; default: None<never>; nullable: false; primaryKey: true; autoIncrement: false; }; readonly name: { columnType: "text"; schema: Schema.Schema<string, string, never>; default: None<never>; nullable: false; primaryKey: false; autoIncrement: false; }; readonly metadata: { columnType: "text"; schema: Schema.Schema<{ readonly petName: string; readonly favoriteColor: "red" | "blue" | "green"; }, string, never>; default: Some<any> | None<...>; nullable: false; primaryKey: false; autoIncrement: false; };}
columns: { id: { columnType: "text"; schema: Schema.Schema<string, string, never>; default: None<never>; nullable: false; primaryKey: true; autoIncrement: false;}
id: import State
State.import SQLite
SQLite.const text: <string, string, false, typeof NoDefault, true, false>(args: { schema?: Schema.Schema<string, string, never>; default?: typeof NoDefault; nullable?: false; primaryKey?: true; autoIncrement?: false;}) => { columnType: "text"; schema: Schema.Schema<string, string, never>; default: None<never>; nullable: false; primaryKey: true; autoIncrement: false;} (+1 overload)
text({ primaryKey?: true
primaryKey: true }), name: { columnType: "text"; schema: Schema.Schema<string, string, never>; default: None<never>; nullable: false; primaryKey: false; autoIncrement: false;}
name: import State
State.import SQLite
SQLite.const text: () => { columnType: "text"; schema: Schema.Schema<string, string, never>; default: None<never>; nullable: false; primaryKey: false; autoIncrement: false;} (+1 overload)
text(), metadata: { columnType: "text"; schema: Schema.Schema<{ readonly petName: string; readonly favoriteColor: "red" | "blue" | "green"; }, string, never>; default: Some<any> | None<never>; nullable: false; primaryKey: false; autoIncrement: false;}
metadata: import State
State.import SQLite
SQLite.const json: <{ readonly petName: string; readonly favoriteColor: "red" | "blue" | "green";}, false, any, false, false>(args: { schema?: Schema.Schema<{ readonly petName: string; readonly favoriteColor: "red" | "blue" | "green"; }, any, never>; default?: any; nullable?: false; primaryKey?: false; autoIncrement?: false;}) => { columnType: "text"; schema: Schema.Schema<{ readonly petName: string; readonly favoriteColor: "red" | "blue" | "green"; }, string, never>; default: Some<any> | None<never>; nullable: false; primaryKey: false; autoIncrement: false;} (+1 overload)
json({ schema?: Schema.Schema<{ readonly petName: string; readonly favoriteColor: "red" | "blue" | "green";}, any, never>
schema: const UserMetadata: Schema.Struct<{ petName: typeof Schema.String; favoriteColor: Schema.Literal<["red", "blue", "green"]>;}>
UserMetadata }), },})Best Practices
Section titled “Best Practices”Column Configuration
Section titled “Column Configuration”- Use appropriate SQLite column types for your data (text, integer, real, blob)
- Set
primaryKey: truefor primary key columns - Use
nullable: truefor columns that can contain NULL values - Provide meaningful
defaultvalues where appropriate - Add unique constraints via table
indexesusingisUnique: true
Schema Design
Section titled “Schema Design”- Choose column types that match your data requirements
- Use custom schemas with
State.SQLite.json()for complex data structures - Group related table definitions in the same module
- Use descriptive table and column names
General Practices
Section titled “General Practices”- It’s usually recommend to not distinguish between app state vs app data but rather keep all state in LiveStore.
- This means you’ll rarely use
React.useStatewhen using LiveStore
- This means you’ll rarely use
- In some cases for “fast changing values” it can make sense to keep a version of a state value outside of LiveStore with a reactive setter for React and a debounced setter for LiveStore to avoid excessive LiveStore mutations. Cases where this can make sense can include:
- Text input / rich text editing
- Scroll position tracking, resize events, move/drag events
- …