# Query SQLite with bound parameters

URL: /docs/cookbook/sqlite_query
Markdown: /docs/cookbook/sqlite_query.md

> Keep SQL text literal and interpolate values as parameters, then decode typed rows.

Generated by `cargo run -p agent_docs` from `compiler/examples/`. Edit the example files, then regenerate.

Keep SQL text literal and interpolate values as parameters, then decode typed rows.

`find_notes` returns `List<Note>`, which determines the row schema for `Sql.query`.
Each `sql"…"` interpolation becomes a bound parameter; neither string concatenation
nor a trust bypass is needed. `SqlError` propagates from the database operations.

Tests install `Sql.memory`, a real fresh in-memory SQLite database, so no filesystem
permission or persistent database is needed. One test proves SQL-looking input
matches only its literal value. Another runs a transaction that writes and then
fails on an absent table, checks `SqlError`, and proves the first write rolled back.
The harness uses test mode. For a persistent database, query `sakura doc std::sql::sqlite`
and supply an appropriately confined filesystem handler and manifest permissions.

[Source project](https://github.com/icantcodefyi/sakuralang/tree/master/compiler/examples/sqlite_query) · harness mode: `test`.

From the repository root, with this checkout's `sakura` on `PATH`:

```sh
cd compiler/examples/sqlite_query
sakura check --json
sakura test --json
```

### Manifest and permissions [#manifest-and-permissions]

```toml
[package]
name = "sqlite_query"
version = "0.1.0"
edition = "2026"

[permissions]
```

### Source and tests [#source-and-tests]

`src/main.sakura` includes all required imports and tests.

```sakura test id=cookbook-sqlite_query project=sqlite_query
// milestone: M3
// mode: test
// spec: design §17.145

import std/sql.{Sql, SqlError}

type Note = { id: Int, title: String }

fn create_notes() -> Unit ! {Sql, Fail<SqlError>} {
  Sql.migrate([sql"create table notes (id integer primary key, title text not null)"])
}

fn add_note(title: String) -> Unit ! {Sql, Fail<SqlError>} {
  let _ = Sql.execute(sql"insert into notes (title) values ({title})")
}

fn find_notes(title: String) -> List<Note> ! {Sql, Fail<SqlError>} {
  Sql.query(sql"select id, title from notes where title = {title} order by id")
}

test "SQLite binds interpolated values, including SQL-looking text" {
  with Sql.memory() {
    create_notes()
    add_note("tea")
    let literal = "x' OR 1=1 --"
    expect_eq(find_notes(literal), [])
    add_note(literal)
    expect_eq(find_notes(literal), [Note { id: 2, title: literal }])
    expect_eq(find_notes("tea"), [Note { id: 1, title: "tea" }])
  }
}

test "a failing transaction rolls back earlier writes" {
  with Sql.memory() {
    create_notes()
    expect_fails_with(
      fn() {
        Sql.transaction(fn() {
          add_note("rolled back")
          let _ = Sql.execute(sql"insert into absent_table (title) values ({"bad"})")
        })
      },
      fn(e) {
        match e {
          SqlError { .. } => true,
        }
      },
    )
    expect_eq(find_notes("rolled back"), [])
  }
}
```

### Compiler provenance and regeneration [#compiler-provenance-and-regeneration]

These eight projects teach supported Sakura APIs on the JavaScript backend. Each
project is exercised offline by `cargo test -p sakura_cli --test examples`;
HTTP and LLM exchanges are synthetic committed cassettes, with no network or API keys.
Use Node 26 for execution, including its built-in SQLite implementation.

The initial API baseline is compiler revision
[5cae349516c21714d90d36e87f1cfd6debe980c6](https://github.com/icantcodefyi/sakuralang/commit/5cae349516c21714d90d36e87f1cfd6debe980c6).
CI reruns these projects against the compiler in the same checkout. Build that
checkout's CLI and run `sakura --version` and `sakura prompt` before adapting a recipe;
pre-alpha APIs can change. An installed skill's frontmatter records its compiler
version and build revision. These teaching examples are separate from the agent
evaluation tasks.

The source of each page is its example's `recipe.md`, `sakura.toml`,
`src/main.sakura` and fixture files. Run `cargo run -p agent_docs` from `compiler/`
to regenerate the cookbook and skill reference. Edit those sources, not the rendered pages.
