Skip to content

SQL queries

LiveStore also provides a small query builder for the most common queries. The query builder automatically derives the appropriate result schema internally.

import {
import Schema
Schema
} from 'effect'
import {
import State
State
} from '@livestore/livestore'
const
const table: State.SQLite.TableDef<State.SQLite.SqliteTableDefForInput<"my_table", {
readonly id: {
columnType: "text";
schema: Schema.Codec<string, string, never, never>;
default: None<never>;
nullable: false;
primaryKey: true;
autoIncrement: false;
};
readonly name: {
columnType: "text";
schema: Schema.Codec<string, string, never, never>;
default: None<never>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly tags: {
columnType: "text";
schema: Schema.Codec<readonly string[], string, never, never>;
default: Some<readonly []>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
}>, State.SQLite.WithDefaults<...>, Schema.Struct<...>>
table
=
import State
State
.
import SQLite
SQLite
.
function table<"my_table", {
readonly id: {
columnType: "text";
schema: Schema.Codec<string, string, never, never>;
default: None<never>;
nullable: false;
primaryKey: true;
autoIncrement: false;
};
readonly name: {
columnType: "text";
schema: Schema.Codec<string, string, never, never>;
default: None<never>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly tags: {
columnType: "text";
schema: Schema.Codec<readonly string[], string, never, never>;
default: Some<readonly []>;
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:

  1. Using explicit column definitions
  2. Using an Effect Schema (either the name property needs to be provided or the schema needs to have a title/identifier)
// Using explicit columns
const 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 annotations
import { 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 name
const usersTable = State.SQLite.table({
name: 'users',
schema: UserSchema,
})
// Option 2: With name from schema annotation (title or identifier)
const AnnotatedUserSchema = UserSchema.annotate({ title: 'users' })
const usersTable2 = State.SQLite.table({
schema: AnnotatedUserSchema,
})
// Adding indexes
const PostSchema = Schema.Struct({
id: Schema.String.pipe(State.SQLite.withPrimaryKey),
title: Schema.String,
authorId: Schema.String,
createdAt: Schema.Date,
}).annotate({ 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: "my_table"
name
: 'my_table',
columns: {
readonly id: {
columnType: "text";
schema: Schema.Codec<string, string, never, never>;
default: None<never>;
nullable: false;
primaryKey: true;
autoIncrement: false;
};
readonly name: {
columnType: "text";
schema: Schema.Codec<string, string, never, never>;
default: None<never>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly tags: {
columnType: "text";
schema: Schema.Codec<readonly string[], string, never, never>;
default: Some<readonly []>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
}
columns
: {
id: {
columnType: "text";
schema: Schema.Codec<string, string, never, 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.Codec<string, string, never, never>;
default?: typeof NoDefault;
nullable?: false;
primaryKey?: true;
autoIncrement?: false;
}) => {
columnType: "text";
schema: Schema.Codec<string, string, never, never>;
default: None<never>;
nullable: false;
primaryKey: true;
autoIncrement: false;
} (+1 overload)
text
({
primaryKey?: true
primaryKey
: true }),
name: {
columnType: "text";
schema: Schema.Codec<string, string, never, never>;
default: None<never>;
nullable: false;
primaryKey: false;
autoIncrement: false;
}
name
:
import State
State
.
import SQLite
SQLite
.
const text: () => {
columnType: "text";
schema: Schema.Codec<string, string, never, never>;
default: None<never>;
nullable: false;
primaryKey: false;
autoIncrement: false;
} (+1 overload)
text
(),
tags: {
columnType: "text";
schema: Schema.Codec<readonly string[], string, never, never>;
default: Some<readonly []>;
nullable: false;
primaryKey: false;
autoIncrement: false;
}
tags
:
import State
State
.
import SQLite
SQLite
.
const json: <readonly string[], false, readonly [], false, false>(args: {
schema?: Schema.Codec<readonly string[], any, never, never>;
default?: readonly [];
nullable?: false;
primaryKey?: false;
autoIncrement?: false;
}) => {
columnType: "text";
schema: Schema.Codec<readonly string[], string, never, never>;
default: Some<readonly []>;
nullable: false;
primaryKey: false;
autoIncrement: false;
} (+1 overload)
json
({
schema?: Schema.Codec<readonly string[], any, never, never>
schema
:
import Schema
Schema
.
Array<Schema.String>(self: Schema.String): Schema.$Array<Schema.String>
export Array

Defines a ReadonlyArray schema for a given element schema.

Example (Defining an array of strings)

import { Schema } from "effect"
const schema = Schema.Array(Schema.String)
const result = Schema.decodeUnknownSync(schema)(["a", "b", "c"])
console.log(result)
// [ 'a', 'b', 'c' ]

@since4.0.0

Array
(
import Schema
Schema
.
const String: Schema.String

Type-level representation of

String

.

Schema for string values. Validates that the input is typeof "string".

@since4.0.0

@since4.0.0

String
),
default?: readonly []
default
: [] }),
},
})
// Read queries
const table: State.SQLite.TableDef<State.SQLite.SqliteTableDefForInput<"my_table", {
readonly id: {
columnType: "text";
schema: Schema.Codec<string, string, never, never>;
default: None<never>;
nullable: false;
primaryKey: true;
autoIncrement: false;
};
readonly name: {
columnType: "text";
schema: Schema.Codec<string, string, never, never>;
default: None<never>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly tags: {
columnType: "text";
schema: Schema.Codec<readonly string[], string, never, never>;
default: Some<readonly []>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
}>, State.SQLite.WithDefaults<...>, Schema.Struct<...>>
table
.
select: <"name">(pluckColumn: "name") => QueryBuilder<readonly string[], State.SQLite.TableDefBase<State.SQLite.SqliteTableDefForInput<"my_table", {
readonly id: {
columnType: "text";
schema: Schema.Codec<string, string, never, never>;
default: None<never>;
nullable: false;
primaryKey: true;
autoIncrement: false;
};
readonly name: {
columnType: "text";
schema: Schema.Codec<string, string, never, never>;
default: None<never>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly tags: {
columnType: "text";
schema: Schema.Codec<readonly string[], string, never, never>;
default: Some<readonly []>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
}>, State.SQLite.WithDefaults<...>>, "select" | ... 2 more ... | "row"> (+1 overload)

Selects and plucks a single column

select
('name')
const table: State.SQLite.TableDef<State.SQLite.SqliteTableDefForInput<"my_table", {
readonly id: {
columnType: "text";
schema: Schema.Codec<string, string, never, never>;
default: None<never>;
nullable: false;
primaryKey: true;
autoIncrement: false;
};
readonly name: {
columnType: "text";
schema: Schema.Codec<string, string, never, never>;
default: None<never>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly tags: {
columnType: "text";
schema: Schema.Codec<readonly string[], string, never, never>;
default: Some<readonly []>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
}>, State.SQLite.WithDefaults<...>, Schema.Struct<...>>
table
.
where: <"name">(col: "name", op: QueryBuilder<TResult, TTableDef extends State.SQLite.TableDefBase<any, any>, TWithout extends QueryBuilder.ApiFeature = never>.WhereOps.SingleValue, value: string) => QueryBuilder<readonly Schema.Struct<Fields extends Schema.Struct.Fields>.ReadonlySide<{
readonly id: Schema.Codec<string, string, never, never>;
readonly name: Schema.Codec<string, string, never, never>;
readonly tags: Schema.Codec<readonly string[], string, never, never>;
}, "Type">[], State.SQLite.TableDefBase<...>, "select" | "row"> (+3 overloads)
where
('name', '=', 'Alice')
const table: State.SQLite.TableDef<State.SQLite.SqliteTableDefForInput<"my_table", {
readonly id: {
columnType: "text";
schema: Schema.Codec<string, string, never, never>;
default: None<never>;
nullable: false;
primaryKey: true;
autoIncrement: false;
};
readonly name: {
columnType: "text";
schema: Schema.Codec<string, string, never, never>;
default: None<never>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly tags: {
columnType: "text";
schema: Schema.Codec<readonly string[], string, never, never>;
default: Some<readonly []>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
}>, State.SQLite.WithDefaults<...>, Schema.Struct<...>>
table
.
where: (params: Partial<{
readonly id: string | {
op: Exclude<QueryBuilder<TResult, TTableDef extends State.SQLite.TableDefBase<any, any>, TWithout extends QueryBuilder.ApiFeature = never>.WhereOps.SingleValue, QueryBuilder.WhereOps.JsonArray>;
value: string;
} | {
op: QueryBuilder.WhereOps.MultiValue;
value: readonly string[];
} | undefined;
readonly name: string | {
op: Exclude<QueryBuilder.WhereOps.SingleValue, QueryBuilder.WhereOps.JsonArray>;
value: string;
} | {
...;
} | undefined;
readonly tags: readonly string[] | ... 3 more ... | undefined;
}>) => QueryBuilder<...> (+3 overloads)
where
({
name?: string | {
op: Exclude<QueryBuilder.WhereOps.SingleValue, QueryBuilder.WhereOps.JsonArray>;
value: string;
} | {
op: QueryBuilder.WhereOps.MultiValue;
value: readonly string[];
} | undefined
name
: 'Alice' })
const table: State.SQLite.TableDef<State.SQLite.SqliteTableDefForInput<"my_table", {
readonly id: {
columnType: "text";
schema: Schema.Codec<string, string, never, never>;
default: None<never>;
nullable: false;
primaryKey: true;
autoIncrement: false;
};
readonly name: {
columnType: "text";
schema: Schema.Codec<string, string, never, never>;
default: None<never>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly tags: {
columnType: "text";
schema: Schema.Codec<readonly string[], string, never, never>;
default: Some<readonly []>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
}>, State.SQLite.WithDefaults<...>, Schema.Struct<...>>
table
.
orderBy: <"name">(col: "name", direction: "asc" | "desc") => QueryBuilder<readonly Schema.Struct<Fields extends Schema.Struct.Fields>.ReadonlySide<{
readonly id: Schema.Codec<string, string, never, never>;
readonly name: Schema.Codec<string, string, never, never>;
readonly tags: Schema.Codec<readonly string[], string, never, never>;
}, "Type">[], State.SQLite.TableDefBase<State.SQLite.SqliteTableDefForInput<"my_table", {
readonly id: {
columnType: "text";
schema: Schema.Codec<string, string, never, never>;
default: None<never>;
nullable: false;
primaryKey: true;
autoIncrement: false;
};
readonly name: {
...;
};
readonly tags: {
...;
};
}>, State.SQLite.WithDefaults<...>>, "onConflict" | "returning"> (+1 overload)
orderBy
('name', 'desc').
offset: (offset: number) => QueryBuilder<readonly Schema.Struct<Fields extends Schema.Struct.Fields>.ReadonlySide<{
readonly id: Schema.Codec<string, string, never, never>;
readonly name: Schema.Codec<string, string, never, never>;
readonly tags: Schema.Codec<readonly string[], string, never, never>;
}, "Type">[], State.SQLite.TableDefBase<State.SQLite.SqliteTableDefForInput<"my_table", {
readonly id: {
columnType: "text";
schema: Schema.Codec<string, string, never, never>;
default: None<never>;
nullable: false;
primaryKey: true;
autoIncrement: false;
};
readonly name: {
columnType: "text";
schema: Schema.Codec<...>;
default: None<never>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly tags: {
...;
};
}>, State.SQLite.WithDefaults<...>>, "orderBy" | ... 3 more ... | "row">

Example:

db.todos.offset(10)

offset
(10).
limit: (limit: number) => QueryBuilder<readonly Schema.Struct<Fields extends Schema.Struct.Fields>.ReadonlySide<{
readonly id: Schema.Codec<string, string, never, never>;
readonly name: Schema.Codec<string, string, never, never>;
readonly tags: Schema.Codec<readonly string[], string, never, never>;
}, "Type">[], State.SQLite.TableDefBase<State.SQLite.SqliteTableDefForInput<"my_table", {
readonly id: {
columnType: "text";
schema: Schema.Codec<string, string, never, never>;
default: None<never>;
nullable: false;
primaryKey: true;
autoIncrement: false;
};
readonly name: {
columnType: "text";
schema: Schema.Codec<...>;
default: None<never>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly tags: {
...;
};
}>, State.SQLite.WithDefaults<...>>, "orderBy" | ... 5 more ... | "row">

Example:

db.todos.limit(10)

limit
(10)
const table: State.SQLite.TableDef<State.SQLite.SqliteTableDefForInput<"my_table", {
readonly id: {
columnType: "text";
schema: Schema.Codec<string, string, never, never>;
default: None<never>;
nullable: false;
primaryKey: true;
autoIncrement: false;
};
readonly name: {
columnType: "text";
schema: Schema.Codec<string, string, never, never>;
default: None<never>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly tags: {
columnType: "text";
schema: Schema.Codec<readonly string[], string, never, never>;
default: Some<readonly []>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
}>, State.SQLite.WithDefaults<...>, Schema.Struct<...>>
table
.
count: () => QueryBuilder<number, State.SQLite.TableDefBase<State.SQLite.SqliteTableDefForInput<"my_table", {
readonly id: {
columnType: "text";
schema: Schema.Codec<string, string, never, never>;
default: None<never>;
nullable: false;
primaryKey: true;
autoIncrement: false;
};
readonly name: {
columnType: "text";
schema: Schema.Codec<string, string, never, never>;
default: None<never>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly tags: {
columnType: "text";
schema: Schema.Codec<readonly string[], string, never, never>;
default: Some<readonly []>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
}>, State.SQLite.WithDefaults<...>>, "select" | ... 7 more ... | "row">

Example:

db.todos.count()
db.todos.count().where('completed', true)

count
().
where: <"name">(col: "name", op: QueryBuilder<TResult, TTableDef extends State.SQLite.TableDefBase<any, any>, TWithout extends QueryBuilder.ApiFeature = never>.WhereOps.SingleValue, value: string) => QueryBuilder<number, State.SQLite.TableDefBase<State.SQLite.SqliteTableDefForInput<"my_table", {
readonly id: {
columnType: "text";
schema: Schema.Codec<string, string, never, never>;
default: None<never>;
nullable: false;
primaryKey: true;
autoIncrement: false;
};
readonly name: {
columnType: "text";
schema: Schema.Codec<string, string, never, never>;
default: None<never>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly tags: {
...;
};
}>, State.SQLite.WithDefaults<...>>, "select" | ... 7 more ... | "row"> (+3 overloads)
where
('name', 'LIKE', '%Ali%')
// JSON array containment queries
// NOTE: These use SQLite's json_each() which cannot be indexed
const table: State.SQLite.TableDef<State.SQLite.SqliteTableDefForInput<"my_table", {
readonly id: {
columnType: "text";
schema: Schema.Codec<string, string, never, never>;
default: None<never>;
nullable: false;
primaryKey: true;
autoIncrement: false;
};
readonly name: {
columnType: "text";
schema: Schema.Codec<string, string, never, never>;
default: None<never>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly tags: {
columnType: "text";
schema: Schema.Codec<readonly string[], string, never, never>;
default: Some<readonly []>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
}>, State.SQLite.WithDefaults<...>, Schema.Struct<...>>
table
.
where: (params: Partial<{
readonly id: string | {
op: Exclude<QueryBuilder<TResult, TTableDef extends State.SQLite.TableDefBase<any, any>, TWithout extends QueryBuilder.ApiFeature = never>.WhereOps.SingleValue, QueryBuilder.WhereOps.JsonArray>;
value: string;
} | {
op: QueryBuilder.WhereOps.MultiValue;
value: readonly string[];
} | undefined;
readonly name: string | {
op: Exclude<QueryBuilder.WhereOps.SingleValue, QueryBuilder.WhereOps.JsonArray>;
value: string;
} | {
...;
} | undefined;
readonly tags: readonly string[] | ... 3 more ... | undefined;
}>) => QueryBuilder<...> (+3 overloads)
where
({
tags?: readonly string[] | {
op: Exclude<QueryBuilder.WhereOps.SingleValue, QueryBuilder.WhereOps.JsonArray>;
value: readonly string[];
} | {
op: QueryBuilder.WhereOps.MultiValue;
value: readonly (readonly string[])[];
} | {
op: QueryBuilder.WhereOps.JsonArray;
value: string;
} | undefined
tags
: {
op: QueryBuilder.WhereOps.JsonArray
op
: 'JSON_CONTAINS',
value: string
value
: 'important' } })
const table: State.SQLite.TableDef<State.SQLite.SqliteTableDefForInput<"my_table", {
readonly id: {
columnType: "text";
schema: Schema.Codec<string, string, never, never>;
default: None<never>;
nullable: false;
primaryKey: true;
autoIncrement: false;
};
readonly name: {
columnType: "text";
schema: Schema.Codec<string, string, never, never>;
default: None<never>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly tags: {
columnType: "text";
schema: Schema.Codec<readonly string[], string, never, never>;
default: Some<readonly []>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
}>, State.SQLite.WithDefaults<...>, Schema.Struct<...>>
table
.
where: (params: Partial<{
readonly id: string | {
op: Exclude<QueryBuilder<TResult, TTableDef extends State.SQLite.TableDefBase<any, any>, TWithout extends QueryBuilder.ApiFeature = never>.WhereOps.SingleValue, QueryBuilder.WhereOps.JsonArray>;
value: string;
} | {
op: QueryBuilder.WhereOps.MultiValue;
value: readonly string[];
} | undefined;
readonly name: string | {
op: Exclude<QueryBuilder.WhereOps.SingleValue, QueryBuilder.WhereOps.JsonArray>;
value: string;
} | {
...;
} | undefined;
readonly tags: readonly string[] | ... 3 more ... | undefined;
}>) => QueryBuilder<...> (+3 overloads)
where
({
tags?: readonly string[] | {
op: Exclude<QueryBuilder.WhereOps.SingleValue, QueryBuilder.WhereOps.JsonArray>;
value: readonly string[];
} | {
op: QueryBuilder.WhereOps.MultiValue;
value: readonly (readonly string[])[];
} | {
op: QueryBuilder.WhereOps.JsonArray;
value: string;
} | undefined
tags
: {
op: QueryBuilder.WhereOps.JsonArray
op
: 'JSON_NOT_CONTAINS',
value: string
value
: 'archived' } })
// Write queries
const table: State.SQLite.TableDef<State.SQLite.SqliteTableDefForInput<"my_table", {
readonly id: {
columnType: "text";
schema: Schema.Codec<string, string, never, never>;
default: None<never>;
nullable: false;
primaryKey: true;
autoIncrement: false;
};
readonly name: {
columnType: "text";
schema: Schema.Codec<string, string, never, never>;
default: None<never>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly tags: {
columnType: "text";
schema: Schema.Codec<readonly string[], string, never, never>;
default: Some<readonly []>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
}>, State.SQLite.WithDefaults<...>, Schema.Struct<...>>
table
.
insert: (values: {
readonly name: string;
readonly id: string;
readonly tags?: readonly string[];
}) => QueryBuilder<readonly Schema.Struct<Fields extends Schema.Struct.Fields>.ReadonlySide<{
readonly id: Schema.Codec<string, string, never, never>;
readonly name: Schema.Codec<string, string, never, never>;
readonly tags: Schema.Codec<readonly string[], string, never, never>;
}, "Type">[], State.SQLite.TableDefBase<State.SQLite.SqliteTableDefForInput<"my_table", {
readonly id: {
columnType: "text";
schema: Schema.Codec<string, string, never, never>;
default: None<never>;
nullable: false;
primaryKey: true;
autoIncrement: false;
};
readonly name: {
...;
};
readonly tags: {
...;
};
}>, 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' })

@paramvalues - The row values to insert.

insert
({
id: string
id
: '123',
name: string
name
: 'Bob' })
const table: State.SQLite.TableDef<State.SQLite.SqliteTableDefForInput<"my_table", {
readonly id: {
columnType: "text";
schema: Schema.Codec<string, string, never, never>;
default: None<never>;
nullable: false;
primaryKey: true;
autoIncrement: false;
};
readonly name: {
columnType: "text";
schema: Schema.Codec<string, string, never, never>;
default: None<never>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly tags: {
columnType: "text";
schema: Schema.Codec<readonly string[], string, never, never>;
default: Some<readonly []>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
}>, State.SQLite.WithDefaults<...>, Schema.Struct<...>>
table
.
update: (values: Partial<Schema.Struct<Fields extends Schema.Struct.Fields>.ReadonlySide<{
readonly id: Schema.Codec<string, string, never, never>;
readonly name: Schema.Codec<string, string, never, never>;
readonly tags: Schema.Codec<readonly string[], string, never, never>;
}, "Type">>) => QueryBuilder<readonly Schema.Struct.ReadonlySide<{
readonly id: Schema.Codec<string, string, never, never>;
readonly name: Schema.Codec<string, string, never, never>;
readonly tags: Schema.Codec<readonly string[], string, never, never>;
}, "Type">[], State.SQLite.TableDefBase<...>, "select" | ... 6 more ... | "row">

Update rows in the table that match the where clause

Example:

db.todos.update({ status: 'completed' }).where({ id: '123' })

update
({
name?: string
name
: 'Alice' }).
where: (params: Partial<{
readonly id: string | {
op: Exclude<QueryBuilder<TResult, TTableDef extends State.SQLite.TableDefBase<any, any>, TWithout extends QueryBuilder.ApiFeature = never>.WhereOps.SingleValue, QueryBuilder.WhereOps.JsonArray>;
value: string;
} | {
op: QueryBuilder.WhereOps.MultiValue;
value: readonly string[];
} | undefined;
readonly name: string | {
op: Exclude<QueryBuilder.WhereOps.SingleValue, QueryBuilder.WhereOps.JsonArray>;
value: string;
} | {
...;
} | undefined;
readonly tags: readonly string[] | ... 3 more ... | undefined;
}>) => QueryBuilder<...> (+3 overloads)
where
({
id?: string | {
op: Exclude<QueryBuilder.WhereOps.SingleValue, QueryBuilder.WhereOps.JsonArray>;
value: string;
} | {
op: QueryBuilder.WhereOps.MultiValue;
value: readonly string[];
} | undefined
id
: '123' })
const table: State.SQLite.TableDef<State.SQLite.SqliteTableDefForInput<"my_table", {
readonly id: {
columnType: "text";
schema: Schema.Codec<string, string, never, never>;
default: None<never>;
nullable: false;
primaryKey: true;
autoIncrement: false;
};
readonly name: {
columnType: "text";
schema: Schema.Codec<string, string, never, never>;
default: None<never>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly tags: {
columnType: "text";
schema: Schema.Codec<readonly string[], string, never, never>;
default: Some<readonly []>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
}>, State.SQLite.WithDefaults<...>, Schema.Struct<...>>
table
.
delete: () => QueryBuilder<readonly Schema.Struct<Fields extends Schema.Struct.Fields>.ReadonlySide<{
readonly id: Schema.Codec<string, string, never, never>;
readonly name: Schema.Codec<string, string, never, never>;
readonly tags: Schema.Codec<readonly string[], string, never, never>;
}, "Type">[], State.SQLite.TableDefBase<State.SQLite.SqliteTableDefForInput<"my_table", {
readonly id: {
columnType: "text";
schema: Schema.Codec<string, string, never, never>;
default: None<never>;
nullable: false;
primaryKey: true;
autoIncrement: false;
};
readonly name: {
columnType: "text";
schema: Schema.Codec<string, string, never, never>;
default: None<never>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly tags: {
columnType: "text";
schema: Schema.Codec<readonly string[], string, never, never>;
default: Some<readonly []>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
}>, State.SQLite.WithDefaults<...>>, "select" | ... 6 more ... | "row">

Delete rows from the table that match the where clause

Example:

db.todos.delete().where({ status: 'completed' })

Note that it's generally recommended to do soft-deletes for synced apps.

delete
().
where: (params: Partial<{
readonly id: string | {
op: Exclude<QueryBuilder<TResult, TTableDef extends State.SQLite.TableDefBase<any, any>, TWithout extends QueryBuilder.ApiFeature = never>.WhereOps.SingleValue, QueryBuilder.WhereOps.JsonArray>;
value: string;
} | {
op: QueryBuilder.WhereOps.MultiValue;
value: readonly string[];
} | undefined;
readonly name: string | {
op: Exclude<QueryBuilder.WhereOps.SingleValue, QueryBuilder.WhereOps.JsonArray>;
value: string;
} | {
...;
} | undefined;
readonly tags: readonly string[] | ... 3 more ... | undefined;
}>) => QueryBuilder<...> (+3 overloads)
where
({
id?: string | {
op: Exclude<QueryBuilder.WhereOps.SingleValue, QueryBuilder.WhereOps.JsonArray>;
value: string;
} | {
op: QueryBuilder.WhereOps.MultiValue;
value: readonly string[];
} | undefined
id
: '123' })
// Upserts (insert or update on conflict)
const table: State.SQLite.TableDef<State.SQLite.SqliteTableDefForInput<"my_table", {
readonly id: {
columnType: "text";
schema: Schema.Codec<string, string, never, never>;
default: None<never>;
nullable: false;
primaryKey: true;
autoIncrement: false;
};
readonly name: {
columnType: "text";
schema: Schema.Codec<string, string, never, never>;
default: None<never>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly tags: {
columnType: "text";
schema: Schema.Codec<readonly string[], string, never, never>;
default: Some<readonly []>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
}>, State.SQLite.WithDefaults<...>, Schema.Struct<...>>
table
.
insert: (values: {
readonly name: string;
readonly id: string;
readonly tags?: readonly string[];
}) => QueryBuilder<readonly Schema.Struct<Fields extends Schema.Struct.Fields>.ReadonlySide<{
readonly id: Schema.Codec<string, string, never, never>;
readonly name: Schema.Codec<string, string, never, never>;
readonly tags: Schema.Codec<readonly string[], string, never, never>;
}, "Type">[], State.SQLite.TableDefBase<State.SQLite.SqliteTableDefForInput<"my_table", {
readonly id: {
columnType: "text";
schema: Schema.Codec<string, string, never, never>;
default: None<never>;
nullable: false;
primaryKey: true;
autoIncrement: false;
};
readonly name: {
...;
};
readonly tags: {
...;
};
}>, 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' })

@paramvalues - The row values to insert.

insert
({
id: string
id
: '123',
name: string
name
: 'Charlie' }).
onConflict: <"id">(target: "id", action: "ignore" | "replace") => QueryBuilder<readonly Schema.Struct<Fields extends Schema.Struct.Fields>.ReadonlySide<{
readonly id: Schema.Codec<string, string, never, never>;
readonly name: Schema.Codec<string, string, never, never>;
readonly tags: Schema.Codec<readonly string[], string, never, never>;
}, "Type">[], State.SQLite.TableDefBase<State.SQLite.SqliteTableDefForInput<"my_table", {
readonly id: {
columnType: "text";
schema: Schema.Codec<string, string, never, never>;
default: None<never>;
nullable: false;
primaryKey: true;
autoIncrement: false;
};
readonly name: {
...;
};
readonly tags: {
...;
};
}>, State.SQLite.WithDefaults<...>>, "select" | ... 6 more ... | "row"> (+1 overload)
onConflict
('id', 'replace')
const table: State.SQLite.TableDef<State.SQLite.SqliteTableDefForInput<"my_table", {
readonly id: {
columnType: "text";
schema: Schema.Codec<string, string, never, never>;
default: None<never>;
nullable: false;
primaryKey: true;
autoIncrement: false;
};
readonly name: {
columnType: "text";
schema: Schema.Codec<string, string, never, never>;
default: None<never>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly tags: {
columnType: "text";
schema: Schema.Codec<readonly string[], string, never, never>;
default: Some<readonly []>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
}>, State.SQLite.WithDefaults<...>, Schema.Struct<...>>
table
.
insert: (values: {
readonly name: string;
readonly id: string;
readonly tags?: readonly string[];
}) => QueryBuilder<readonly Schema.Struct<Fields extends Schema.Struct.Fields>.ReadonlySide<{
readonly id: Schema.Codec<string, string, never, never>;
readonly name: Schema.Codec<string, string, never, never>;
readonly tags: Schema.Codec<readonly string[], string, never, never>;
}, "Type">[], State.SQLite.TableDefBase<State.SQLite.SqliteTableDefForInput<"my_table", {
readonly id: {
columnType: "text";
schema: Schema.Codec<string, string, never, never>;
default: None<never>;
nullable: false;
primaryKey: true;
autoIncrement: false;
};
readonly name: {
...;
};
readonly tags: {
...;
};
}>, 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' })

@paramvalues - The row values to insert.

insert
({
id: string
id
: '456',
name: string
name
: 'Diana' }).
onConflict: <"id">(target: "id", action: "update", updateValues: Partial<Schema.Struct<Fields extends Schema.Struct.Fields>.ReadonlySide<{
readonly id: Schema.Codec<string, string, never, never>;
readonly name: Schema.Codec<string, string, never, never>;
readonly tags: Schema.Codec<readonly string[], string, never, never>;
}, "Type">>) => QueryBuilder<readonly Schema.Struct.ReadonlySide<{
readonly id: Schema.Codec<string, string, never, never>;
readonly name: Schema.Codec<string, string, never, never>;
readonly tags: Schema.Codec<readonly string[], string, never, never>;
}, "Type">[], State.SQLite.TableDefBase<...>, "select" | ... 6 more ... | "row"> (+1 overload)
onConflict
('id', 'update', {
name?: string
name
: 'Diana Updated' })

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 {
const queryDb: {
<TResultSchema, TResult = TResultSchema>(queryInput: QueryInputRaw<TResultSchema, ReadonlyArray<any>> | QueryBuilder<TResultSchema, any, any>, options?: {
map?: (rows: TResultSchema) => TResult;
label?: string;
deps?: DepKey;
}): LiveQueryDef<TResult>;
<TResultSchema, TResult = TResultSchema>(queryInput: ((get: GetAtomResult) => QueryInputRaw<TResultSchema, ReadonlyArray<any>>) | ((get: GetAtomResult) => QueryBuilder<TResultSchema, any, any>), options?: {
map?: (rows: TResultSchema) => TResult;
label?: string;
deps?: DepKey;
}): LiveQueryDef<TResult>;
}

NOTE queryDb is only supposed to read data. Don't use it to insert/update/delete data but use events instead.

When using contextual data when constructing the query, please make sure to include it in the deps option.

@example

const todos$ = queryDb(tables.todos.where({ complete: true }))

@example

// Group-by raw SQL query
const colorCounts$ = queryDb({
query: sql`SELECT color, COUNT(*) as count FROM todos WHERE complete = ? GROUP BY color`,
schema: Schema.Array(Schema.Struct({
color: Schema.String,
count: Schema.Number,
})),
bindValues: [1],
})

@example

// Using contextual data when constructing the query
const makeFilteredQuery = (filter: string) =>
queryDb(tables.todos.where({ title: { op: 'like', value: filter } }), { deps: [filter] })
const filteredTodos$ = makeFilteredQuery('buy coffee')

queryDb
,
import Schema
Schema
,
import State
State
,
const sql: (template: TemplateStringsArray, ...args: unknown[]) => string

This is a tag function for tagged literals. it lets us get syntax highlighting on SQL queries in VSCode, but doesn't do anything at runtime. Code copied from: https://esdiscuss.org/topic/string-identity-template-tag

sql
} from '@livestore/livestore'
const
const table: State.SQLite.TableDef<State.SQLite.SqliteTableDefForInput<"my_table", {
readonly id: {
columnType: "text";
schema: Schema.Codec<string, string, never, never>;
default: None<never>;
nullable: false;
primaryKey: true;
autoIncrement: false;
};
readonly name: {
columnType: "text";
schema: Schema.Codec<string, string, never, never>;
default: None<never>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
}>, State.SQLite.WithDefaults<{
readonly id: {
columnType: "text";
schema: Schema.Codec<string, string, never, never>;
default: None<never>;
nullable: false;
primaryKey: true;
autoIncrement: false;
};
readonly name: {
columnType: "text";
schema: Schema.Codec<string, string, never, never>;
default: None<never>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
}>, Schema.Struct<...>>
table
=
import State
State
.
import SQLite
SQLite
.
function table<"my_table", {
readonly id: {
columnType: "text";
schema: Schema.Codec<string, string, never, never>;
default: None<never>;
nullable: false;
primaryKey: true;
autoIncrement: false;
};
readonly name: {
columnType: "text";
schema: Schema.Codec<string, string, never, never>;
default: None<never>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
}, Partial<{
indexes: Index[];
}>>(args: {
name: "my_table";
columns: {
readonly id: {
columnType: "text";
schema: Schema.Codec<string, string, never, never>;
default: None<never>;
nullable: false;
primaryKey: true;
autoIncrement: false;
};
readonly name: {
columnType: "text";
schema: Schema.Codec<string, string, never, never>;
default: None<never>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
};
} & 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:

  1. Using explicit column definitions
  2. Using an Effect Schema (either the name property needs to be provided or the schema needs to have a title/identifier)
// Using explicit columns
const 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 annotations
import { 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 name
const usersTable = State.SQLite.table({
name: 'users',
schema: UserSchema,
})
// Option 2: With name from schema annotation (title or identifier)
const AnnotatedUserSchema = UserSchema.annotate({ title: 'users' })
const usersTable2 = State.SQLite.table({
schema: AnnotatedUserSchema,
})
// Adding indexes
const PostSchema = Schema.Struct({
id: Schema.String.pipe(State.SQLite.withPrimaryKey),
title: Schema.String,
authorId: Schema.String,
createdAt: Schema.Date,
}).annotate({ 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: "my_table"
name
: 'my_table',
columns: {
readonly id: {
columnType: "text";
schema: Schema.Codec<string, string, never, never>;
default: None<never>;
nullable: false;
primaryKey: true;
autoIncrement: false;
};
readonly name: {
columnType: "text";
schema: Schema.Codec<string, string, never, never>;
default: None<never>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
}
columns
: {
id: {
columnType: "text";
schema: Schema.Codec<string, string, never, 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.Codec<string, string, never, never>;
default?: typeof NoDefault;
nullable?: false;
primaryKey?: true;
autoIncrement?: false;
}) => {
columnType: "text";
schema: Schema.Codec<string, string, never, never>;
default: None<never>;
nullable: false;
primaryKey: true;
autoIncrement: false;
} (+1 overload)
text
({
primaryKey?: true
primaryKey
: true }),
name: {
columnType: "text";
schema: Schema.Codec<string, string, never, never>;
default: None<never>;
nullable: false;
primaryKey: false;
autoIncrement: false;
}
name
:
import State
State
.
import SQLite
SQLite
.
const text: () => {
columnType: "text";
schema: Schema.Codec<string, string, never, never>;
default: None<never>;
nullable: false;
primaryKey: false;
autoIncrement: false;
} (+1 overload)
text
(),
},
})
const
const filtered$: LiveQueryDef<readonly Schema.Struct.ReadonlySide<{
readonly id: Schema.Codec<string, string, never, never>;
readonly name: Schema.Codec<string, string, never, never>;
}, "Type">[], "def">
filtered$
=
queryDb<readonly Schema.Struct<Fields extends Schema.Struct.Fields>.ReadonlySide<{
readonly id: Schema.Codec<string, string, never, never>;
readonly name: Schema.Codec<string, string, never, never>;
}, "Type">[], readonly Schema.Struct.ReadonlySide<{
readonly id: Schema.Codec<string, string, never, never>;
readonly name: Schema.Codec<string, string, never, never>;
}, "Type">[]>(queryInput: QueryInputRaw<readonly Schema.Struct.ReadonlySide<{
readonly id: Schema.Codec<string, string, never, never>;
readonly name: Schema.Codec<string, string, never, never>;
}, "Type">[], readonly any[]> | QueryBuilder<...>, options?: {
...;
} | undefined): LiveQueryDef<...> (+1 overload)

NOTE queryDb is only supposed to read data. Don't use it to insert/update/delete data but use events instead.

When using contextual data when constructing the query, please make sure to include it in the deps option.

@example

const todos$ = queryDb(tables.todos.where({ complete: true }))

@example

// Group-by raw SQL query
const colorCounts$ = queryDb({
query: sql`SELECT color, COUNT(*) as count FROM todos WHERE complete = ? GROUP BY color`,
schema: Schema.Array(Schema.Struct({
color: Schema.String,
count: Schema.Number,
})),
bindValues: [1],
})

@example

// Using contextual data when constructing the query
const makeFilteredQuery = (filter: string) =>
queryDb(tables.todos.where({ title: { op: 'like', value: filter } }), { deps: [filter] })
const filteredTodos$ = makeFilteredQuery('buy coffee')

queryDb
({
query: string
query
:
const sql: (template: TemplateStringsArray, ...args: unknown[]) => string

This is a tag function for tagged literals. it lets us get syntax highlighting on SQL queries in VSCode, but doesn't do anything at runtime. Code copied from: https://esdiscuss.org/topic/string-identity-template-tag

sql
`select * from my_table where name = 'Alice'`,
schema: Schema.Codec<readonly Schema.Struct.ReadonlySide<{
readonly id: Schema.Codec<string, string, never, never>;
readonly name: Schema.Codec<string, string, never, never>;
}, "Type">[], readonly any[], never, never>
schema
:
import Schema
Schema
.
Array<Schema.Struct<{
readonly id: Schema.Codec<string, string, never, never>;
readonly name: Schema.Codec<string, string, never, never>;
}>>(self: Schema.Struct<{
readonly id: Schema.Codec<string, string, never, never>;
readonly name: Schema.Codec<string, string, never, never>;
}>): Schema.$Array<Schema.Struct<{
readonly id: Schema.Codec<string, string, never, never>;
readonly name: Schema.Codec<string, string, never, never>;
}>>
export Array

Defines a ReadonlyArray schema for a given element schema.

Example (Defining an array of strings)

import { Schema } from "effect"
const schema = Schema.Array(Schema.String)
const result = Schema.decodeUnknownSync(schema)(["a", "b", "c"])
console.log(result)
// [ 'a', 'b', 'c' ]

@since4.0.0

Array
(
const table: State.SQLite.TableDef<State.SQLite.SqliteTableDefForInput<"my_table", {
readonly id: {
columnType: "text";
schema: Schema.Codec<string, string, never, never>;
default: None<never>;
nullable: false;
primaryKey: true;
autoIncrement: false;
};
readonly name: {
columnType: "text";
schema: Schema.Codec<string, string, never, never>;
default: None<never>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
}>, State.SQLite.WithDefaults<{
readonly id: {
columnType: "text";
schema: Schema.Codec<string, string, never, never>;
default: None<never>;
nullable: false;
primaryKey: true;
autoIncrement: false;
};
readonly name: {
columnType: "text";
schema: Schema.Codec<string, string, never, never>;
default: None<never>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
}>, Schema.Struct<...>>
table
.
rowSchema: Schema.Struct<{
readonly id: Schema.Codec<string, string, never, never>;
readonly name: Schema.Codec<string, string, never, never>;
}>
rowSchema
),
})
const
const count$: LiveQueryDef<number, "def">
count$
=
queryDb<number, number>(queryInput: QueryInputRaw<number, readonly any[]> | QueryBuilder<number, any, any>, options?: {
map?: (rows: number) => number;
label?: string;
deps?: DepKey;
} | undefined): LiveQueryDef<number, "def"> (+1 overload)

NOTE queryDb is only supposed to read data. Don't use it to insert/update/delete data but use events instead.

When using contextual data when constructing the query, please make sure to include it in the deps option.

@example

const todos$ = queryDb(tables.todos.where({ complete: true }))

@example

// Group-by raw SQL query
const colorCounts$ = queryDb({
query: sql`SELECT color, COUNT(*) as count FROM todos WHERE complete = ? GROUP BY color`,
schema: Schema.Array(Schema.Struct({
color: Schema.String,
count: Schema.Number,
})),
bindValues: [1],
})

@example

// Using contextual data when constructing the query
const makeFilteredQuery = (filter: string) =>
queryDb(tables.todos.where({ title: { op: 'like', value: filter } }), { deps: [filter] })
const filteredTodos$ = makeFilteredQuery('buy coffee')

queryDb
({
query: string
query
:
const sql: (template: TemplateStringsArray, ...args: unknown[]) => string

This is a tag function for tagged literals. it lets us get syntax highlighting on SQL queries in VSCode, but doesn't do anything at runtime. Code copied from: https://esdiscuss.org/topic/string-identity-template-tag

sql
`select count(*) as count from my_table`,
schema: Schema.Codec<number, readonly any[], never, never>
schema
:
import Schema
Schema
.
function Struct<{
readonly count: Schema.Finite;
}>(fields: {
readonly count: Schema.Finite;
}): Schema.Struct<{
readonly count: Schema.Finite;
}>

Defines a struct schema from a map of field schemas.

Details

Each field value is a schema. Use

optionalKey

or

optional

to mark fields as optional, and

mutableKey

to mark them as mutable.

The resulting schema's Type is a readonly object type with the fields' decoded types. The Encoded form mirrors the field schemas' encoded types.

Example (Defining a basic struct)

import { Schema } from "effect"
const Person = Schema.Struct({
name: Schema.String,
age: Schema.Number,
email: Schema.optionalKey(Schema.String)
})
// { readonly name: string; readonly age: number; readonly email?: string }
type Person = typeof Person.Type
const alice = Schema.decodeUnknownSync(Person)({ name: "Alice", age: 30 })
console.log(alice)
// { name: 'Alice', age: 30 }

@since3.10.0

Struct
({
count: Schema.Finite
count
:
import Schema
Schema
.
const Finite: Schema.Finite

Type-level representation of

Finite

.

Schema for finite numbers, rejecting NaN, Infinity, and -Infinity.

@since3.10.0

@since3.10.0

Finite
}).
Pipeable.pipe<Schema.Struct<{
readonly count: Schema.Finite;
}>, PluckSchema<{
readonly count: Schema.Finite;
}, "count">, Schema.$Array<PluckSchema<{
readonly count: Schema.Finite;
}, "count">>, HeadOrElse<PluckSchema<{
readonly count: Schema.Finite;
}, "count">>>(this: Schema.Struct<...>, ab: (_: Schema.Struct<{
readonly count: Schema.Finite;
}>) => PluckSchema<{
readonly count: Schema.Finite;
}, "count">, bc: (_: PluckSchema<{
readonly count: Schema.Finite;
}, "count">) => Schema.$Array<...>, cd: (_: Schema.$Array<...>) => HeadOrElse<...>): HeadOrElse<...> (+21 overloads)
pipe
(
import Schema
Schema
.
const pluck: <"count">(key: "count") => <Fields extends {
readonly count: Schema.Top;
}>(schema: Schema.Struct<Fields>) => PluckSchema<Fields, "count" & keyof Fields>
pluck
('count'),
import Schema
Schema
.
const Array: ArrayLambda
export Array

Defines a ReadonlyArray schema for a given element schema.

Example (Defining an array of strings)

import { Schema } from "effect"
const schema = Schema.Array(Schema.String)
const result = Schema.decodeUnknownSync(schema)(["a", "b", "c"])
console.log(result)
// [ 'a', 'b', 'c' ]

@since4.0.0

Array
,
import Schema
Schema
.
const headOrElse: () => <S extends Schema.Top>(array: Schema.$Array<S>) => HeadOrElse<S> (+2 overloads)
headOrElse
()),
})

For JSON array columns, you can use JSON_CONTAINS and JSON_NOT_CONTAINS operators to check if an array contains (or doesn’t contain) a specific value:

// Find items with a specific tag
table.where({ tags: { op: 'JSON_CONTAINS', value: 'important' } })
// Find items without a specific tag
table.where({ tags: { op: 'JSON_NOT_CONTAINS', value: 'archived' } })
  • 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 a LIMIT clause. Avoid OFFSET as it can be slow on large tables
  • 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.