SQL Queries
Query builder
Section titled “Query builder”LiveStore also provides a small query builder for the most common queries. The query builder automatically derives the appropriate result schema internally.
const table = State.SQLite.table({ name: 'my_table', columns: { id: State.SQLite.text({ primaryKey: true }), name: State.SQLite.text(), },})
// Read queriestable.select('name')table.where('name', '==', 'Alice')table.where({ name: 'Alice' })table.orderBy('name', 'desc').offset(10).limit(10)table.count().where('name', 'like', '%Ali%')
// Write queriestable.insert({ id: '123', name: 'Bob' })table.update({ name: 'Alice' }).where({ id: '123' })table.delete().where({ id: '123' })
Raw SQL queries
Section titled “Raw SQL queries”LiveStore supports arbitrary SQL queries on top of SQLite. In order for LiveStore to handle the query results correctly, you need to provide the result schema.
import { queryDb, State, Schema, sql } from '@livestore/livestore'
const table = State.SQLite.table({ name: 'my_table', columns: { id: State.SQLite.text({ primaryKey: true }), name: State.SQLite.text(), },})
const filtered$ = queryDb({ query: sql`select * from my_table where name = 'Alice'`, schema: Schema.Array(table.schema),})
const count$ = queryDb({ query: sql`select count(*) as count from my_table`, schema: Schema.Struct({ count: Schema.Number }).pipe(Schema.pluck('count'), Schema.Array, Schema.headOrElse()),})
Best Practices
Section titled “Best Practices”- Query results should be treated as immutable/read-only
- For queries which could return many rows, it’s recommended to paginate the results
- Usually both via paginated/virtualized rendering as well as paginated queries
- You’ll get best query performance by using a
WHERE
clause over an indexed column combined with aLIMIT
clause. AvoidOFFSET
as it can be slow on large tables
- You’ll get best query performance by using a
- Usually both via paginated/virtualized rendering as well as paginated queries
- For very large/complex queries, it can also make sense to implement incremental view maintenance (IVM) for your queries
- You can for example do this by have a separate table which is a materialized version of your query results which you update manually (and ideally incrementally) as the underlying data changes.