default_config : Path -> Config
Conservative defaults for a conventional web application.
Sqlite :: # (opaque)
Execute bounded SQLite statements with statically dispatched parameter encoders and row parsers.
Query parameters are ordinary flat records. Their field names map to SQLite
parameters with a leading colon, so { status } binds :status. Query
results are selected by the expected Roc type. Structural records derive
their parser automatically when their fields use supported SQLite types.
Todo : { id : I64, task : Str }
todos : List(Todo)
db = Sqlite.open!(Sqlite.default_config(db_path))?
todos = Sqlite.query_many!({
db,
query: "SELECT id, task FROM todos WHERE status = :status",
params: { status: "open" },
limits: Sqlite.default_query_limits,
})?
SQLite INTEGER maps strictly to I64, REAL to F64, TEXT to
Str, and BLOB to Sqlite.Blob. No text/number coercions are performed.
TODO: Add derived nullable fields once the compiler can compose their parser
errors through a platform-defined encoding.
A Db owns a bounded host connection pool. Statements are immutable logical
query descriptors; each execution briefly leases a connection and a cached
native prepared statement. Executions are safe to use concurrently. Their
final ARC release resets the native statement and returns the connection on
every success and error path.
default_config : Path -> Config
Conservative defaults for a conventional web application.
default_query_limits : QueryLimits
Conservative defaults for ordinary request-scoped queries.
Open and validate a bounded database pool.
Prepare a reusable logical statement and cache its result-column metadata.
execute! : { db : Db, query : Str, params : params } => Try({ }, QueryError)
where [
params.encoder_for : ParamsEncoding -> params, ParamsState -> Try(ParamsState, QueryError),
]
Execute a one-shot statement that must not return rows.
query! : { db : Db, query : Str, params : params, limits : QueryLimits } => Try(row, QueryError)
where [
params.encoder_for : ParamsEncoding -> params, ParamsState -> Try(ParamsState, QueryError),
row.parser_for : RowEncoding -> RowState -> Try({ value : row, rest : RowState }, QueryError),
]
Execute a one-shot query returning exactly one inferred result value.
query_many! : { db : Db, query : Str, params : params, limits : QueryLimits } => Try(List(row), QueryError)
where [
params.encoder_for : ParamsEncoding -> params, ParamsState -> Try(ParamsState, QueryError),
row.parser_for : RowEncoding -> RowState -> Try({ value : row, rest : RowState }, QueryError),
]
Execute a one-shot query returning a list of inferred result values.
Begin a transaction on one connection leased from the pool.
errcode_to_str : [
Abort,
AuthDenied,
Busy,
CanNotOpen,
Constraint,
Corrupt,
Done,
Empty,
Error,
Format,
Full,
IOErr,
Internal,
Interrupt,
Locked,
Mismatch,
Misuse,
NoLFS,
NoMem,
NotADatabase,
NotFound,
Notice,
OutOfRange,
Perm,
Protocol,
ReadOnly,
Row,
Schema,
TooBig,
Warning,
Unknown(
I64,
),
] -> Str
Convert an ErrCode to a display string.
Config : {
path : Path,
max_connections : U64,
acquire_timeout_ms : U64,
busy_timeout_ms : U64,
max_cached_statements_per_connection : U64,
journal_mode : JournalMode,
synchronous : Synchronous,
}
Configuration for one bounded host-owned connection pool.
max_connections is 1-64, both timeouts are at most ten minutes, and
each connection caches at most 256 native statements.
JournalMode : [Delete, Wal]
SQLite rollback-journal policy applied and verified on every connection.
Synchronous : [Full, Normal]
Full is the durable default. Normal trades power-loss durability for
substantially faster commits while preserving database consistency.
Sqlite.Db :: # (opaque)
A host-owned SQLite connection pool, safe to retain in immutable context.
to_inspect : Db -> Str
A raw SQLite value. Most applications use derived record codecs instead.
A raw named binding used internally by the derived parameter encoder.
QueryLimits : {
max_bytes : U64,
max_rows : U64,
timeout_ms : U64,
}
Bounds on a materialized query. max_bytes covers the host-side SQLite
value storage handed to Roc; max_rows also bounds per-row record
overhead after decoding. timeout_ms interrupts SQLite virtual-machine
execution; pool acquisition has its own database-level timeout.
ValueType : [Blob, Integer, Null, Real, Text]
SQLite's five runtime storage classes, used in decode diagnostics.
QueryError : [
DuplicateColumn(Str),
ExpectedSingleColumn({ actual : U64 }),
InvalidValue({ column : Str }),
MalformedRow,
MissingRequiredField(Str),
MultipleValuesForParameter,
NestedParameterRecord,
NoRowsReturned,
ParameterValueMissing(Str),
ParameterValueOutsideRecord,
PoolSaturated,
QueryTimedOut,
ResourceSaturated,
ResultTooLarge({ max_bytes : U64 }),
RowsReturnedUseQueryInstead,
SqliteErr(ErrCode, Str),
TooManyRows({ max_rows : U64 }),
TooManyRowsReturned,
ConcurrentTransactionUse,
TransactionFinished,
UnconsumedColumns,
UnexpectedType({ actual : ValueType, column : Str, expected : ValueType }),
]
Every failure produced by SQLite operations and their derived codecs.
Sqlite.Blob :: # (opaque)
A SQLite BLOB. The nominal wrapper distinguishes blobs from ordinary Roc lists for generic parsing and encoding.
TODO: Use Blob inside mixed result records once the compiler composes a
custom nominal parser's errors with sibling derived fields.
from_bytes : List(U8) -> Blob
parser_for : RowEncoding -> RowState -> Try(
{
rest : RowState,
value : Blob,
},
[
MalformedRow,
UnconsumedColumns,
..[
ConcurrentTransactionUse,
DuplicateColumn(
Str,
),
ExpectedSingleColumn(
{
actual : U64,
},
),
InvalidValue(
{
column : Str,
},
),
MissingRequiredField(
Str,
),
MultipleValuesForParameter,
NestedParameterRecord,
NoRowsReturned,
ParameterValueMissing(
Str,
),
ParameterValueOutsideRecord,
PoolSaturated,
QueryTimedOut,
ResourceSaturated,
ResultTooLarge(
{
max_bytes : U64,
},
),
RowsReturnedUseQueryInstead,
SqliteErr(
ErrCode,
Str,
),
TooManyRows(
{
max_rows : U64,
},
),
TooManyRowsReturned,
TransactionFinished,
UnexpectedType(
{
actual : ValueType,
column : Str,
expected : ValueType,
},
),
],
],
)
encoder_for : encoding -> Blob, state -> Try(state, err)
where [
encoding.encode_bytes : List(U8), state -> Try(state, err),
]
ParamsState : {
bindings : List(Binding),
field : [Field(Str), NoField],
value : [Encoded(Value), NoValue],
}
State used by the derived parameter-record encoder.
Sqlite.ParamsEncoding :: # (opaque)
SQLite named-parameter encoding.
rename_field : ParamsEncoding, Str -> Str
encode_str : Str, ParamsState -> Try(ParamsState, QueryError)
encode_i64 : I64, ParamsState -> Try(ParamsState, QueryError)
encode_f64 : F64, ParamsState -> Try(ParamsState, QueryError)
encode_bytes : List(U8), ParamsState -> Try(ParamsState, QueryError)
encode_null : ParamsState -> Try(ParamsState, QueryError)
RowState : {
columns : List(Str),
current : [Current({ name : Str, value : Value }), NoCurrent],
next : U64,
values : List(Value),
}
Pure state used by a compiler-derived SQLite row parser.
Sqlite.RowEncoding :: # (opaque)
SQLite row encoding consumed by parser_for.
rename_field : RowEncoding, Str -> Str
parse_bytes : RowEncoding, RowState -> Try({ value : List(U8), rest : RowState }, QueryError)
invalid_value : RowEncoding, RowState -> QueryError
parse_record_field : RowEncoding, FieldNames(_shape), RowState -> Try(
[
Field({ field : FieldName(_shape), rest : RowState }),
TryField({ name : Str, rest : RowState }),
TryFieldCaseless({ name : Str, rest : RowState }),
Continue({ rest : RowState }),
Done({ rest : RowState }),
],
QueryError,
)
skip_record_field : RowEncoding, RowState -> Try(RowState, QueryError)
Sqlite.Stmt :: # (opaque)
Represents a prepared statement that can be executed many times.
to_inspect : Stmt -> Str
execute! : Stmt, params => Try({ }, QueryError)
where [
params.encoder_for : ParamsEncoding -> params, ParamsState -> Try(ParamsState, QueryError),
]
Execute a prepared statement that must not return rows.
query! : Stmt, params, QueryLimits => Try(row, QueryError)
where [
params.encoder_for : ParamsEncoding -> params, ParamsState -> Try(ParamsState, QueryError),
row.parser_for : RowEncoding -> RowState -> Try({ value : row, rest : RowState }, QueryError),
]
Decode exactly one row as the expected result type.
query_many! : Stmt, params, QueryLimits => Try(List(row), QueryError)
where [
params.encoder_for : ParamsEncoding -> params, ParamsState -> Try(ParamsState, QueryError),
row.parser_for : RowEncoding -> RowState -> Try({ value : row, rest : RowState }, QueryError),
]
Decode all rows as the expected list item type.
Sqlite.Transaction :: # (opaque)
A transaction pinned to one pooled connection. Dropping its final Roc
reference before commit! or rollback! rolls it back automatically.
Operations within one transaction are sequential; overlapping use returns
ConcurrentTransactionUse.
to_inspect : Transaction -> Str
query_many! : Transaction, { query : Str, params : params, limits : QueryLimits } => Try(List(row), QueryError)
where [
params.encoder_for : ParamsEncoding -> params, ParamsState -> Try(ParamsState, QueryError),
row.parser_for : RowEncoding -> RowState -> Try({ value : row, rest : RowState }, QueryError),
]
TransactionMode : [Deferred, Immediate, Exclusive]
ErrCode : [
Error,
Internal,
Perm,
Abort,
Busy,
Locked,
NoMem,
ReadOnly,
Interrupt,
IOErr,
Corrupt,
NotFound,
Full,
CanNotOpen,
Protocol,
Empty,
Schema,
TooBig,
Constraint,
Mismatch,
Misuse,
NoLFS,
AuthDenied,
Format,
OutOfRange,
NotADatabase,
Notice,
Warning,
Row,
Done,
Unknown(I64),
]
Represents SQLite result codes.