sqlite-mumu 0.2.0-rc.4

sqlite-mumu is a plugin for the mumu ecosystem
Documentation
# sqlite-mumu

_A MuMu/Lava plugin to provide fast, native SQLite access with typed params, streaming result-sets, and friendly data-last ergonomics._

**Repository:** <https://gitlab.com/tofo/sqlite-mumu>  
**License:** MIT OR Apache-2.0  
**Engine compatibility:** `core-mumu = 0.9.0-rc.4` (host builds; not intended for wasm)

---

## What this plugin aims to do

- to expose a minimal, predictable set of `sqlite:*` functions to MuMu/Lava  
- to interoperate cleanly with MuMu values (typed arrays, keyed arrays/objects, iterators)  
- to stream `SELECT` results via the core `Iterator` type (no giant in-memory buffers)  
- to bind parameters safely and ergonomically from MuMu arrays (int/float/string/bool/mixed)  
- to preserve concrete MuMu types on reads (e.g., integers as `Long`, floats as `Float`)  
- to remain “host-only” while exporting a dynamic entrypoint for `extend("sqlite")`

On native builds the plugin registers itself through the exported entrypoint `Cargo_lock(...)` so `extend("sqlite")` can load it at runtime.

---

## Feature overview

### 1) Open / Close

- `sqlite:open([path, flags]) → handle:int`  
  - `path` — SQLite file path (e.g., `"/tmp/app.db"`; special SQLite URIs are allowed)  
  - `flags``"ro"` (read-only) · `"rw"` (read/write) · `"rwc"` (read/write create; **default**)  
  - returns an integer **handle** for subsequent calls

- `sqlite:close([handle]) → bool`  
  - accepts key `"handle"` (and synonyms `"db"`, `"conn"`)  
  - returns `true` on success; errors if the handle is unknown

Connections are stored internally as `Arc<Mutex<rusqlite::Connection>>`, ensuring safe, serialized access.

### 2) Execute queries

- `sqlite:query([handle, sql, params]) → Iterator | int`  
  - `sql` — SQL string (or a single-element `StrArray`)  
  - `params` — optional parameters as:
    - `IntArray`, `FloatArray`, `StrArray`, `BoolArray`, or `MixedArray`
    - `_` (`Placeholder`) maps to `NULL`
  - For `SELECT`/`PRAGMA`/`WITH`:
    - returns a MuMu **`Iterator`** of **rows as `KeyedArray`**  
      (column names preserved as keys; insertion order preserved)
  - For `INSERT`/`UPDATE`/`DELETE`/DDL:
    - returns an **`Int`** (rows changed) from SQLite’s `execute`

**Type mapping (SQLite → MuMu per column):**

- `NULL``Placeholder`  
- `INTEGER``Long`  
- `REAL``Float`  
- `TEXT``SingleString`  
- `BLOB``SingleString("[BLOB]")` (opaque marker)

**Type mapping (MuMu params → SQLite):**

- `Int`/`Long`/`IntArray` → integer binds  
- `Float`/`FloatArray` → real binds  
- `SingleString`/`StrArray` → text binds  
- `Bool`/`BoolArray``1`/`0` integer binds  
- `MixedArray` — element-wise mapping based on the above  
- `Placeholder``NULL`

**Streaming:** result rows are yielded on demand. Consume with any iterator-aware tool (e.g., `slog`, your own collectors, or array/flow helpers).

---

## API surface

All functions use keyed arrays for clarity; handle key synonyms are accepted (`handle`, `db`, or `conn`).

- `sqlite:open([path:"/tmp/app.db", flags:"rwc"]) → 1000`  
- `sqlite:query([handle:1000, sql:"SELECT 1 AS n", params:_]) → Iterator`  
- `sqlite:close([db:1000]) → true`

Error messages are explicit (e.g., `"sqlite:query: prepare error: ..."`, `"sqlite:open: 'path' field missing"`). When the MuMu interpreter runs with `--verbose` (or `LAVA_VERBOSE=1`), the plugin prints extra diagnostics to `stderr` (e.g., row streaming traces).

---

## Minimal examples

```mu
extend("sqlite")

h = sqlite:open([path:"/tmp/example.db", flags:"rwc"])

// DDL / DML return changed-row counts
sqlite:query([handle:h, sql:"CREATE TABLE IF NOT EXISTS t(id INTEGER PRIMARY KEY, name TEXT)"])
sqlite:query([handle:h, sql:"INSERT INTO t(name) VALUES (?)", params:["Ada"]])
sqlite:query([handle:h, sql:"INSERT INTO t(name) VALUES (?)", params:["Ben"]])

// SELECT returns an Iterator of KeyedArray rows
rows = sqlite:query([handle:h, sql:"SELECT id, name FROM t WHERE id > ?", params:[0]])

// Stream to console (one row per poll tick)
slog(rows)

// Clean up
sqlite:close([handle:h])
```

```mu
// Parameter typing: arrays map directly to SQLite binds
h = sqlite:open([path:"/tmp/example.db"])
sqlite:query([handle:h, sql:"UPDATE t SET name = ? WHERE id = ?", params:["Eve", 1]])
sqlite:close([handle:h])
```

---

## Return & error conventions

- `sqlite:open` — returns `Int` handle; errors on invalid flags/path/open failure  
- `sqlite:query`
  - `SELECT`/`PRAGMA`/`WITH` — returns `Iterator` of `KeyedArray` rows  
  - other statements — returns `Int` rows changed  
  - parameters must be representable as SQLite binds; otherwise a descriptive error is returned  
- `sqlite:close` — returns `Bool(true)` if the handle existed, errors otherwise

`Iterator` exhaustion signals `"NO_MORE_DATA"` internally; helper functions (e.g., `slog`) handle this.

---

## Design notes

- **Host-only:** Uses `rusqlite`; not intended for wasm.  
- **Streaming first:** `SELECT` results are not fully materialized.  
- **Typed columns:** preserves integer/real distinction (`Long` vs `Float`).  
- **Stable key order:** rows are `KeyedArray` (insertion-order map).  
- **Diagnostics:** verbose logging is gated by the interpreter’s verbosity.  
- **Platform:** on Windows the build enables a bundled SQLite (`libsqlite3-sys` with `features = ["bundled"]`); on Unix-likes it uses the system library by default.

---

## Contributing

Issues and merge requests welcome at:  
<https://gitlab.com/tofo/sqlite-mumu>

Please align changes with the MuMu core conventions:

- keyed-argument APIs  
- predictable type mapping (columns & params)  
- iterator streaming for result sets  
- clear, actionable error messages

---

## License

Licensed under either of:

- MIT license  
- Apache License, Version 2.0

at your option.