# SqlHost

The interface that runs the SDK's SQL statements in atomic SQLite transactions.

The SDK owns its tables (`states`, `owners`, `records`, `turns`, and `events`) and every statement, so a host needs no schema code. The host runs each operation's statements in one transaction and returns their rows. Durable Objects' `transactionSync`, `node:sqlite`, and sqlite-wasm satisfy the contract synchronously.

```ts title="sql.ts"
import { DatabaseSync, type SQLInputValue } from 'node:sqlite'
import type { SqlHost, SqlValue } from 'nanocode-wasm'

const db = new DatabaseSync('agent.sqlite')

// Runs every statement of one operation, all or nothing
export const sql: SqlHost = {
  transaction(_kind, _operation, statements) {
    db.exec('BEGIN IMMEDIATE')
    try {
      const rows = statements.map(([query, ...values]) => {
        const statement = db.prepare(query)
        statement.setReturnArrays(true)
        return statement.all(
          ...(values as SQLInputValue[]),
        ) as unknown as SqlValue[][]
      })
      db.exec('COMMIT')
      return rows
    } catch (error) {
      db.exec('ROLLBACK')
      throw error
    }
  },
}
```

## Signature

```ts
interface SqlHost {
  // The largest string, BLOB, or row that the host's SQLite stores
  readonly value_limit?: number
  // Rows for each statement, in statement order
  transaction(
    kind: SqlKind,
    operation: string,
    statements: Statement[],
  ): SqlValue[][][] | Promise<SqlValue[][][]>
}

type SqlKind = 'store' | 'log'
type Statement = [string, ...SqlValue[]]
type SqlValue = string | number | null | ArrayBuffer
```

## Parameters

### kind

* **Type:** `SqlKind` (`'store' | 'log'`)

The SDK component that runs the operation. `'store'` is the SDK's `SqlStore` (session records and checkpoints), and `'log'` is its `SessionLog` (turns and events). A host can route both to one database.

```ts
import type { SqlHost } from 'nanocode-wasm'

declare const store: SqlHost
declare const log: SqlHost

// Keeps checkpoints and the event log in separate databases
const sql: SqlHost = {
  transaction: (kind, operation, statements) =>
    (kind === 'store' ? store : log).transaction(
      kind,
      operation,
      statements,
    ),
}
```

### operation

* **Type:** `string`

The name of the SDK operation, such as `submit`, `page`, or `append`. `metrics.timing.checkpoints` records store transaction times by this name.

```ts
import type { SqlHost } from 'nanocode-wasm'

declare const inner: SqlHost

// Logs each operation name
const sql: SqlHost = {
  transaction: (kind, operation, statements) => (
    console.log(kind, operation),
    inner.transaction(kind, operation, statements)
  ),
}
```

### statements

* **Type:** `Statement[]` (`[string, ...SqlValue[]][]`)

The statements of the operation, each the SQL text followed by its positional parameters. The SDK binds only text parameters.

```ts
import type { Statement } from 'nanocode-wasm'

declare const statement: Statement

// Splits the SQL text from its parameters
const [query, ...parameters] = statement
```

### value_limit

* **Type:** `number`

The largest string, BLOB, or row in bytes that the host's SQLite stores. If it is set, `instantiate` passes it to the module, and every scope's `SessionLog` uses it:

* **Events:** An event above the limit is logged as an `omitted` marker.
* **Results:** A turn result above the limit fails its turn.
* **Prompts:** `submit` returns `too_large` for a prompt whose turn or `input.accepted` event would not fit.
* **Imports:** `import` batches its statements within the limit.

```ts
import type { SqlHost } from 'nanocode-wasm'

declare const transaction: SqlHost['transaction']

// Matches a 2 MiB storage limit
const sql: SqlHost = { transaction, value_limit: 2 * 1024 * 1024 }
```

## Returns

* **Type:** `SqlValue[][][] | Promise<SqlValue[][][]>`

One array of rows per statement, in statement order, with each row as an array of cells. Return an empty array for a statement without rows. Each cell must be a string or `null`. An asynchronous host returns a promise.

```ts
// Rows for two statements: one row, then none
const rows = [[['1', 'queued']], []]
```

## Errors

A thrown error or rejected promise fails the operation, and the transaction must roll back. A cell that is neither a string nor `null` fails it with `SQL host returned a value that is neither text nor null`.

```ts
import type { SqlHost } from 'nanocode-wasm'

// Refuses every write while the store is read-only
const sql: SqlHost = {
  transaction() {
    throw new Error('the store is read-only')
  },
}
```
