@di-framework/sqlite-component 0.0.1 → 6.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,250 @@
1
+ # di-framework:sqlite — SQLite WebAssembly component
2
+
3
+ A Rust WebAssembly component that bundles SQLite (amalgamation 3.53.2) and
4
+ exposes it to other components through the `di-framework:sqlite@0.1.0` WIT
5
+ package. Database files live on the WASI filesystem the host preopens for the
6
+ component (a mounted volume), using rollback journals with `synchronous=FULL`.
7
+
8
+ It exists so the QuickJS-based di-framework application component (built by
9
+ `componentize-qjs` in `@di-framework/cli-plugin-platform`) can persist actor
10
+ state, queue jobs and migration bookkeeping without a native SQLite in the JS
11
+ runtime: the JS component *imports* `di-framework:sqlite/database`, this
12
+ component *exports* it, and `wac plug` wires them into one component.
13
+
14
+ ```
15
+ ┌──────────────────────────────┐ di-framework:sqlite/database ┌────────────────────────────┐
16
+ │ app.wasm (componentize-qjs) │ ───────── import ──────────────▶ │ di-framework-sqlite.wasm │
17
+ │ imports wasi:http, ... │ │ exports database, types │
18
+ └──────────────────────────────┘ │ imports wasi:filesystem, │
19
+ └────────────── wac plug ────────────────────────┤ wasi:clocks, cli │
20
+ │ └────────────────────────────┘
21
+ ▼
22
+ composed.wasm (only wasi:* / wasmcloud:* imports remain)
23
+ ```
24
+
25
+ ## Layout
26
+
27
+ ```
28
+ packages/di-framework-sqlite-component/
29
+ ├── Cargo.toml, Cargo.lock pinned crates (rusqlite 0.40.2, libsqlite3-sys 0.38.2, wit-bindgen 0.61.1, cc 1.4.5)
30
+ ├── rust-toolchain.toml Rust 1.97.1 + wasm32-wasip2 (honoured by rustup)
31
+ ├── .cargo/config.toml default target + C toolchain env + SQLite compile flags
32
+ ├── build.rs compiles csrc/wasi-vfs.c with the same wasi-sdk clang
33
+ ├── csrc/wasi-vfs.c SQLite VFS over wasi-libc (see "Persistence model")
34
+ ├── wit/world.wit di-framework:sqlite@0.1.0
35
+ ├── src/lib.rs the component (exports database + types)
36
+ ├── scripts/
37
+ │ ├── tool-versions.env every pinned version + SHA-256
38
+ │ ├── install-tools.sh checksum-verified installer for wasm-tools, wac, wasi-sdk (+ optional rustup)
39
+ │ ├── env.sh puts .tools/ on PATH and exports build env (sourceable)
40
+ │ ├── build.sh cargo build + validate + stage dist/
41
+ │ ├── compose.sh wac plug <consumer> with the provider
42
+ │ └── smoke.sh end-to-end test under wasmtime
43
+ ├── tests/smoke-consumer/ wasip2 command component importing the interface (used by smoke.sh)
44
+ ├── Makefile thin wrapper around the scripts
45
+ └── dist/ (generated) di-framework-sqlite.wasm, .wit, BUILD-INFO.txt, SHA256SUMS
46
+ ```
47
+
48
+ ## Building
49
+
50
+ ```sh
51
+ cd packages/di-framework-sqlite-component
52
+
53
+ make tools # wasm-tools 1.258.0, wac 0.11.0, wasi-sdk 34.0 -> .tools/ (SHA-256 verified)
54
+ make tools-rust # only if you have no rustup: hermetic rustup + Rust 1.97.1 + wasm32-wasip2 -> .tools/
55
+ make build # -> dist/di-framework-sqlite.wasm (~1.2 MB)
56
+ make smoke # compose with tests/smoke-consumer and run under wasmtime (needs `wasmtime` on PATH)
57
+ ```
58
+
59
+ `make build` runs `scripts/build.sh`, which is:
60
+
61
+ ```sh
62
+ . scripts/env.sh # PATH, CC_wasm32_wasip2, LIBSQLITE3_FLAGS, RUSTFLAGS
63
+ cargo build --locked --release --target wasm32-wasip2 -p di-framework-sqlite-component
64
+ wasm-tools validate --features all dist/di-framework-sqlite.wasm
65
+ wasm-tools component wit dist/di-framework-sqlite.wasm > dist/di-framework-sqlite.wit
66
+ ```
67
+
68
+ Requirements: a C compiler that targets `wasm32-wasip2` with wasi-libc headers
69
+ (the pinned wasi-sdk; Apple clang has no wasm backend), Rust 1.97.1 with the
70
+ `wasm32-wasip2` std, `wasm-tools`. `rustc` on `wasm32-wasip2` emits a component
71
+ directly (via `wasm-component-ld`), so no `wasm-tools component new` step is
72
+ needed. Builds are deterministic: `--remap-path-prefix` strips absolute paths
73
+ and `dist/SHA256SUMS` is identical across clean rebuilds on the same toolchain.
74
+
75
+ ### Pinning and checksums
76
+
77
+ `scripts/tool-versions.env` is the single source of truth. `install-tools.sh`
78
+ downloads release assets from GitHub / static.rust-lang.org, compares the
79
+ SHA-256 against the pinned value **before** unpacking or executing anything,
80
+ and aborts on mismatch. Hashes are recorded for macOS (arm64, x86_64) and Linux
81
+ (x86_64, aarch64). To upgrade: bump the version, download the new assets,
82
+ `shasum -a 256`, update the file, rebuild, run `make smoke`.
83
+
84
+ Rust itself is pinned by `rust-toolchain.toml` (rustup verifies components
85
+ against the signed channel manifest). Crates are pinned with `=` in
86
+ `Cargo.toml` and locked in `Cargo.lock`; `--locked` refuses to drift.
87
+
88
+ ### Environment overrides
89
+
90
+ | Variable | Meaning |
91
+ | --- | --- |
92
+ | `DF_SQLITE_TOOLS_DIR` | where `install-tools.sh` installs (default `.tools/`) |
93
+ | `WASI_SDK_PATH` | use an existing wasi-sdk instead of downloading |
94
+ | `CC_wasm32_wasip2`, `AR_wasm32_wasip2`, `CFLAGS_wasm32_wasip2` | C toolchain for `sqlite3.c` + `wasi-vfs.c` |
95
+ | `LIBSQLITE3_FLAGS` | extra `-D` flags for the amalgamation (see `.cargo/config.toml`) |
96
+
97
+ ## WIT interface (`di-framework:sqlite@0.1.0`)
98
+
99
+ Full text in [`wit/world.wit`](wit/world.wit). Summary:
100
+
101
+ **`types`**
102
+ - `value`: `null | integer(s64) | real(f64) | text(string) | blob(list<u8>)`
103
+ - `row = list<tuple<string, value>>` — column name / value pairs, in column order
104
+ - `error`: `open-failed(string) | closed | invalid-sql(string) | invalid-params(string) | execution-failed(sqlite-error) | value-conversion-failed(string) | busy | invalid-transaction-state(string) | other(string)`
105
+ - `sqlite-error { code, extended-code, message }` — e.g. `19`/`1555` for a primary-key violation
106
+ - `open-options { create?, read-only?, synchronous?, journal-mode?, busy-timeout-ms?, foreign-keys? }`
107
+ - enums `sync-mode { off, normal, full }`, `journal-mode { delete, persist, memory }`, `transaction-behavior { deferred, immediate, exclusive }`
108
+
109
+ **`database`**
110
+ - `open(path, option<open-options>) -> result<connection, error>`
111
+ - `sqlite-version() -> string`
112
+ - `resource connection`
113
+ - `exec(sql)` — multi-statement batch, no params, no results (DDL / migrations / pragmas)
114
+ - `run(sql, params) -> u64` — one statement, returns `changes`
115
+ - `query(sql, params) -> list<row>`
116
+ - `first(sql, params) -> option<row>`
117
+ - `begin(option<transaction-behavior>)` (default `immediate`), `commit()`, `rollback()`
118
+ - `savepoint(name)`, `release-savepoint(name)`, `rollback-to-savepoint(name)` — nesting
119
+ - `in-transaction() -> bool`, `changes() -> u64`, `last-insert-rowid() -> s64`
120
+ - `close()`
121
+
122
+ **Worlds**: `sqlite-provider { export types; export database; }` (this component)
123
+ and `imports { import types; import database; }` (consumers).
124
+
125
+ Defaults applied by `open` when options are omitted: `journal_mode=DELETE`,
126
+ `synchronous=FULL`, `foreign_keys=ON`, `busy_timeout=5000`. `open` verifies the
127
+ journal mode SQLite reports matches the request and fails otherwise.
128
+
129
+ ## Persistence model
130
+
131
+ - **Rollback journal, not WAL.** WAL requires shared memory and file locks; the
132
+ WASI filesystem offers neither. `sqlite3.c` is compiled with
133
+ `-DSQLITE_OMIT_WAL`, so `PRAGMA journal_mode=WAL` is a silent no-op and the
134
+ connection stays on `delete`. Offered modes: `delete` (default), `persist`,
135
+ `memory` (tests only).
136
+ - **`synchronous=FULL` by default** (`-DSQLITE_DEFAULT_SYNCHRONOUS=2` and set
137
+ again at open). Every commit fsyncs the journal and the database through
138
+ `wasi:filesystem/types.descriptor.sync`. `normal` is available via
139
+ `open-options` for lower-durability workloads.
140
+ - **Single writer.** The VFS does no locking. One connection per file inside
141
+ the component, and one component instance per file on the host — the
142
+ wasmCloud plugin enforces `replicas: 1` for actor workloads
143
+ (`WASMCLOUD_ACTORS_REPLICA_CONSTRAINT`).
144
+ - **Paths are guest paths inside a preopen.** The Kubernetes manifest mounts a
145
+ PVC at `mountPath` (default `/data/actors`) and exposes the same path to the
146
+ guest; open `/data/actors/<db>.sqlite`. Paths outside any preopen fail with
147
+ `open-failed`.
148
+ - **No temp files.** `-DSQLITE_TEMP_STORE=3` and `-DSQLITE_STMTJRNL_SPILL=-1`
149
+ keep temp tables, sorters and statement journals in memory.
150
+
151
+ ### The VFS (`csrc/wasi-vfs.c`)
152
+
153
+ `libsqlite3-sys` ships a `wasm32-wasi-vfs` feature whose C file is a 2010-era
154
+ copy of SQLite's `demovfs.c`. It is **not** used here because:
155
+
156
+ 1. its `xFileControl` returns `SQLITE_OK` for every opcode; since SQLite 3.7.x
157
+ `PRAGMA` first asks the VFS via `SQLITE_FCNTL_PRAGMA`, and an `OK` answer
158
+ means "handled" — so *every PRAGMA becomes a no-op* (`journal_mode`,
159
+ `synchronous`, `user_version`, ...);
160
+ 2. `xTruncate` is a no-op (unsafe for any journal mode but DELETE; VACUUM never
161
+ shrinks the file);
162
+ 3. `xRandomness` returns no entropy; `xDelete` scans past the end of its buffer.
163
+
164
+ `csrc/wasi-vfs.c` is the same public-domain design with those fixed
165
+ (`SQLITE_NOTFOUND`, `ftruncate`, `getentropy`, `pread`/`pwrite`, ms-precision
166
+ `xCurrentTimeInt64`) and is compiled by `build.rs` against
167
+ `libsqlite3-sys`'s exported `sqlite3.h`. `sqlite3.c` is built with
168
+ `-DSQLITE_OS_OTHER=1` so it calls our `sqlite3_os_init`. `make smoke` asserts
169
+ that `PRAGMA journal_mode` really returns `delete` and that no `-wal` or stale
170
+ `-journal` file is left behind.
171
+
172
+ ## Consuming from the JS component
173
+
174
+ 1. **WIT**: copy `wit/world.wit` to
175
+ `cli-extensions/packages/di-framework-cli-plugin-platform/assets/wit/deps/di-framework-sqlite/package.wit`
176
+ and add `import di-framework:sqlite/database@0.1.0;` to the generated guest
177
+ world (`sqliteProjectRequirements()` in `src/wit.ts` does this).
178
+ 2. **JS**: `componentize-qjs`/jco expose the import as an ES module:
179
+
180
+ ```ts
181
+ import { open } from 'di-framework:sqlite/database@0.1.0';
182
+
183
+ const db = open('/data/actors/orders.sqlite', undefined); // options optional
184
+ db.exec('CREATE TABLE IF NOT EXISTS kv (k TEXT PRIMARY KEY, v TEXT NOT NULL)');
185
+ db.run('INSERT OR REPLACE INTO kv VALUES (?1, ?2)', [
186
+ { tag: 'text', val: 'a' },
187
+ { tag: 'text', val: JSON.stringify({ n: 1 }) },
188
+ ]);
189
+ const row = db.first('SELECT v FROM kv WHERE k = ?1', [{ tag: 'text', val: 'a' }]);
190
+ // row: [['v', { tag: 'text', val: '{"n":1}' }]] | undefined
191
+
192
+ db.begin(undefined); // BEGIN IMMEDIATE
193
+ try { /* ... */ db.commit(); } catch (e) { db.rollback(); throw e; }
194
+ ```
195
+
196
+ `result<_, error>` failures surface as thrown `ComponentError`s whose
197
+ `payload` is the `error` variant (`{ tag: 'execution-failed', val: { code, extendedCode, message } }`).
198
+ `integer` values are `bigint`s. A `MigrationDatabase.transaction(fn)` wrapper
199
+ maps to `begin`/`commit`/`rollback` (or `savepoint` when already inside one).
200
+ 3. **Compose** after componentize:
201
+
202
+ ```sh
203
+ scripts/compose.sh path/to/app.wasm path/to/app.composed.wasm # = wac plug --plug dist/di-framework-sqlite.wasm app.wasm -o ...
204
+ ```
205
+
206
+ `wac plug` connects every export of the provider to the matching import of
207
+ the app; the composed component keeps only `wasi:*`/`wasmcloud:*` imports
208
+ for the host. `compose.sh` fails if `di-framework:sqlite/database` is still
209
+ imported afterwards.
210
+ 4. **Ship the artifact**: the plugin package build runs `make publish-asset`,
211
+ which builds the provider from source and copies the WASM, recovered WIT,
212
+ build metadata, and checksums into
213
+ `cli-extensions/packages/di-framework-cli-plugin-platform/dist/assets/sqlite/`. These generated
214
+ files ship in the npm package and are ignored by Git. No prebuilt provider is
215
+ checked into the source tree.
216
+
217
+ ### WASI version note
218
+
219
+ This component targets `wasm32-wasip2` (imports `wasi:*@0.2.9`), the only
220
+ stable Rust component target. The plugin's JS component targets WASI 0.3.0.
221
+ `wac plug` composes them fine — the composed component then imports both
222
+ `wasi:filesystem@0.2.9` (for SQLite) and the 0.3.0 interfaces (for the app) —
223
+ but the *host* must provide both. wasmtime does (p2 and p3 linkers coexist);
224
+ verify this on the wasmCloud host version you deploy to. When a stable
225
+ `wasm32-wasip3` Rust target lands, changing `RUST_TARGET` in
226
+ `scripts/tool-versions.env` and `.cargo/config.toml` is the only change needed
227
+ here.
228
+
229
+ ## Verification
230
+
231
+ `make smoke` builds `tests/smoke-consumer` (a `wasip2` command component that
232
+ imports the interface), composes it with the provider using the pinned `wac`,
233
+ and runs it under `wasmtime run --dir <tmp>::/data`. It checks: pragma
234
+ defaults (`delete`/FULL/foreign keys), WAL is compiled out, DDL via `exec`,
235
+ all `value` kinds round-trip, `changes`/`last-insert-rowid`, error mapping
236
+ (constraint code 19/1555, syntax → `invalid-sql`, arity → `invalid-params`,
237
+ multi-statement → `invalid-sql`, `commit` without `begin` →
238
+ `invalid-transaction-state`), transactions, savepoints and rollback, `close`,
239
+ reopening read-only (`SQLITE_READONLY` = 8), `open-failed` for missing
240
+ directories and paths outside the preopen, `:memory:`, and finally that the
241
+ `.sqlite` file exists on the host with no `-journal`/`-wal` left over.
242
+
243
+ ## Known limitations / follow-ups
244
+
245
+ - Synchronous interface (no `async func`/streams); fine for the small result
246
+ sets the framework issues, and matches `bun:sqlite`-style drivers.
247
+ - `row` repeats column names per row; switch to a `{columns, rows}` record if
248
+ large result sets ever matter.
249
+ - No prepared-statement cache across calls (each `run`/`query` prepares once).
250
+ - `wasmtime` used by `make smoke` is not pinned by this package.
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@di-framework/sqlite-component",
3
- "version": "0.0.1",
4
- "description": "Placeholder for the di-framework platform SQLite component.",
5
- "type": "module",
3
+ "version": "6.0.1",
4
+ "private": false,
5
+ "description": "SQLite WebAssembly component (di-framework:sqlite@0.1.0) for platform guests.",
6
6
  "license": "(MIT OR Apache-2.0)",
7
7
  "author": "@di-framework Contributors",
8
8
  "repository": {
@@ -10,13 +10,19 @@
10
10
  "url": "https://github.com/di-framework/platform",
11
11
  "directory": "platform/sqlite-component"
12
12
  },
13
- "main": "./src/index.ts",
14
- "types": "./src/index.ts",
15
- "exports": {
16
- ".": "./src/index.ts"
13
+ "bugs": {
14
+ "url": "https://github.com/di-framework/platform/issues"
17
15
  },
18
- "files": ["src"],
19
- "publishConfig": {
20
- "access": "public"
16
+ "homepage": "https://github.com/di-framework/platform",
17
+ "files": [
18
+ "dist",
19
+ "README.md",
20
+ "wit"
21
+ ],
22
+ "scripts": {
23
+ "build": "make build",
24
+ "test": "bun test",
25
+ "smoke": "make smoke",
26
+ "publish-asset": "make publish-asset"
21
27
  }
22
28
  }
package/wit/world.wit ADDED
@@ -0,0 +1,211 @@
1
+ package di-framework:sqlite@0.1.0;
2
+
3
+ /// Types shared by the `database` interface.
4
+ ///
5
+ /// Kept in a separate interface (mirroring `wasmcloud:postgres/types`) so that
6
+ /// values and errors unify when a consumer and a provider are composed with
7
+ /// WAC, and so a future `prepared` or `async` interface can reuse them.
8
+ interface types {
9
+ /// A structured error reported by SQLite itself.
10
+ record sqlite-error {
11
+ /// Primary SQLite result code (e.g. `19` = SQLITE_CONSTRAINT).
12
+ code: s32,
13
+ /// Extended result code (e.g. `2067` = SQLITE_CONSTRAINT_UNIQUE).
14
+ /// Equal to `code` when SQLite provides no extended information.
15
+ extended-code: s32,
16
+ /// Human-readable message from `sqlite3_errmsg`.
17
+ message: string,
18
+ }
19
+
20
+ /// Errors raised by functions in this package. Intentionally non-exhaustive:
21
+ /// consumers must keep a catch-all arm.
22
+ variant error {
23
+ /// The database file could not be opened or created. The guest path must
24
+ /// live under a directory the host has preopened (a mounted volume).
25
+ open-failed(string),
26
+ /// The connection has been closed with `close` and cannot be used again.
27
+ closed,
28
+ /// The statement could not be prepared: syntax error, unknown table or
29
+ /// column, or more than one statement passed to `run`/`query`/`first`.
30
+ invalid-sql(string),
31
+ /// Wrong number of parameters or a value that could not be bound.
32
+ invalid-params(string),
33
+ /// SQLite failed while executing a prepared statement (constraint
34
+ /// violation, read-only database, I/O error, ...). Branch on
35
+ /// `sqlite-error.code` / `extended-code` for machine-readable handling.
36
+ execution-failed(sqlite-error),
37
+ /// A column value could not be converted into a `value` (e.g. TEXT that is
38
+ /// not valid UTF-8).
39
+ value-conversion-failed(string),
40
+ /// The database file is locked or busy after the configured busy timeout.
41
+ /// With the WASI VFS this can only arise from another connection *inside
42
+ /// the same component instance*; the VFS does not perform file locking.
43
+ busy,
44
+ /// `begin`, `commit`, `rollback` (or a savepoint call) was issued in a
45
+ /// state that does not permit it (e.g. `commit` with no open transaction).
46
+ invalid-transaction-state(string),
47
+ /// Any other implementation-specific failure.
48
+ other(string),
49
+ }
50
+
51
+ /// A dynamically-typed SQLite value, used for parameters and results.
52
+ variant value {
53
+ null,
54
+ integer(s64),
55
+ real(f64),
56
+ text(string),
57
+ blob(list<u8>),
58
+ }
59
+
60
+ /// A result row: `(column-name, value)` pairs in column order. Column names
61
+ /// are repeated per row on purpose: result sets in the framework (actor
62
+ /// state, queue jobs, migration bookkeeping) are small and JS consumers turn
63
+ /// each row straight into an object.
64
+ type row = list<tuple<string, value>>;
65
+
66
+ /// `PRAGMA synchronous` level. `full` is the default and is what the
67
+ /// framework expects for durable actor / queue state; `normal` trades a
68
+ /// small durability window (power loss mid-commit) for fewer fsyncs. `off`
69
+ /// exists for tests only.
70
+ enum sync-mode {
71
+ off,
72
+ normal,
73
+ full,
74
+ }
75
+
76
+ /// Rollback-journal mode. WAL is intentionally not offered: the WASI VFS
77
+ /// has neither file locking nor shared memory, both of which WAL needs, and
78
+ /// SQLite is compiled with `SQLITE_OMIT_WAL`. `delete` is the default and
79
+ /// the safest choice on WASI preopens (the journal is unlinked after every
80
+ /// commit); `persist` keeps the journal file and zeroes its header; `memory`
81
+ /// is for tests only. TRUNCATE is deliberately left out of the surface.
82
+ enum journal-mode {
83
+ delete,
84
+ persist,
85
+ memory,
86
+ }
87
+
88
+ /// How `begin` acquires its lock. Maps to `BEGIN DEFERRED|IMMEDIATE|EXCLUSIVE`.
89
+ enum transaction-behavior {
90
+ deferred,
91
+ immediate,
92
+ exclusive,
93
+ }
94
+
95
+ /// Options accepted by `open`. Every field is optional; `none` means the
96
+ /// documented default.
97
+ record open-options {
98
+ /// Create the database file if it does not exist. Default: true.
99
+ create: option<bool>,
100
+ /// Open read-only. Default: false.
101
+ read-only: option<bool>,
102
+ /// `PRAGMA synchronous`. Default: `full`.
103
+ synchronous: option<sync-mode>,
104
+ /// `PRAGMA journal_mode`. Default: `delete`.
105
+ journal-mode: option<journal-mode>,
106
+ /// `PRAGMA busy_timeout` in milliseconds. Default: 5000.
107
+ busy-timeout-ms: option<u32>,
108
+ /// `PRAGMA foreign_keys`. Default: true.
109
+ foreign-keys: option<bool>,
110
+ }
111
+ }
112
+
113
+ /// Synchronous, single-writer SQLite access backed by the WASI filesystem.
114
+ ///
115
+ /// The implementer of this interface is the `di-framework:sqlite` Rust
116
+ /// component. It bundles SQLite (amalgamation) with a minimal WASI VFS: no
117
+ /// file locking, no mmap, no WAL, in-memory temp store. Consequently exactly
118
+ /// one component instance may own a given database file at a time; the
119
+ /// framework enforces `replicas: 1` for actor workloads for this reason.
120
+ ///
121
+ /// Paths are guest paths. The host mounts a volume at `mountPath` and the same
122
+ /// string is the guest-visible directory (a WASI preopen), e.g.
123
+ /// `/data/actors/orders/order-42.sqlite`.
124
+ interface database {
125
+ use types.{error, value, row, open-options, transaction-behavior};
126
+
127
+ /// Open (and by default create) the database at `path`, applying the
128
+ /// pragmas described in `open-options` (rollback journal, `synchronous=FULL`,
129
+ /// `foreign_keys=ON`, 5 s busy timeout when `options` is `none`). Use
130
+ /// `:memory:` for an in-memory database.
131
+ open: func(path: string, options: option<open-options>) -> result<connection, error>;
132
+
133
+ /// The bundled SQLite library version, e.g. `3.53.2`.
134
+ sqlite-version: func() -> string;
135
+
136
+ /// An open SQLite connection. Dropping the resource closes it; an open
137
+ /// transaction is rolled back by SQLite in that case.
138
+ resource connection {
139
+ /// Execute one or more `;`-separated statements without parameters and
140
+ /// discard any results. Intended for DDL / migrations / pragmas. Untrusted
141
+ /// input must never be interpolated into `sql`.
142
+ exec: func(sql: string) -> result<_, error>;
143
+
144
+ /// Execute a single parameterized statement and return the number of rows
145
+ /// changed (`sqlite3_changes`). Parameters bind positionally to `?`/`?NNN`.
146
+ /// Statements that return rows (e.g. `INSERT ... RETURNING`) run to
147
+ /// completion; their rows are discarded.
148
+ run: func(sql: string, params: list<value>) -> result<u64, error>;
149
+
150
+ /// Execute a single parameterized statement and return all rows.
151
+ query: func(sql: string, params: list<value>) -> result<list<row>, error>;
152
+
153
+ /// Execute a single parameterized statement and return only the first row,
154
+ /// or `none` when the statement produced no rows.
155
+ first: func(sql: string, params: list<value>) -> result<option<row>, error>;
156
+
157
+ /// `BEGIN [DEFERRED|IMMEDIATE|EXCLUSIVE]`. Default: `immediate`, which is
158
+ /// the right choice for a single-writer file with no lock arbitration.
159
+ /// Fails with `invalid-transaction-state` if a transaction is already open;
160
+ /// nest with `savepoint` instead.
161
+ begin: func(behavior: option<transaction-behavior>) -> result<_, error>;
162
+
163
+ /// `COMMIT` the open transaction.
164
+ commit: func() -> result<_, error>;
165
+
166
+ /// `ROLLBACK` the open transaction.
167
+ rollback: func() -> result<_, error>;
168
+
169
+ /// `SAVEPOINT <name>`; usable for nested transactions. `name` must match
170
+ /// `[A-Za-z_][A-Za-z0-9_]*`.
171
+ savepoint: func(name: string) -> result<_, error>;
172
+
173
+ /// `RELEASE SAVEPOINT <name>`.
174
+ release-savepoint: func(name: string) -> result<_, error>;
175
+
176
+ /// `ROLLBACK TO SAVEPOINT <name>` followed by `RELEASE`, so the savepoint
177
+ /// is fully unwound.
178
+ rollback-to-savepoint: func(name: string) -> result<_, error>;
179
+
180
+ /// True while a transaction (or savepoint) is open on this connection.
181
+ in-transaction: func() -> bool;
182
+
183
+ /// Rows changed by the most recent `run`/`exec`.
184
+ changes: func() -> u64;
185
+
186
+ /// `sqlite3_last_insert_rowid`.
187
+ last-insert-rowid: func() -> s64;
188
+
189
+ /// Explicitly close the connection. Subsequent calls fail with `closed`.
190
+ close: func() -> result<_, error>;
191
+ }
192
+ }
193
+
194
+ /// The world implemented by the Rust component. WASI imports (filesystem,
195
+ /// clocks, cli, io) are pulled in by the Rust `wasm32-wasip2` target and
196
+ /// therefore do not need to be listed here. `types` is exported explicitly so
197
+ /// the component is self-contained: without it WIT elaboration would turn the
198
+ /// `use types.{...}` into an *import* of `types`, which `wac plug` could not
199
+ /// satisfy from this component.
200
+ world sqlite-provider {
201
+ export types;
202
+ export database;
203
+ }
204
+
205
+ /// The world a consumer (e.g. the componentize-qjs JS component) targets when
206
+ /// it wants a SQLite database. `wac plug` satisfies these imports with the
207
+ /// `sqlite-provider` component's exports.
208
+ world imports {
209
+ import types;
210
+ import database;
211
+ }
package/src/index.ts DELETED
@@ -1,2 +0,0 @@
1
- /** Placeholder. Implementation ships from di-framework/platform. */
2
- export const name = "@di-framework/sqlite-component" as const;