From 69ecfab45a495fc683678cff7b06f5672163df0b Mon Sep 17 00:00:00 2001 From: Gordon Farquharson Date: Tue, 27 Oct 2026 15:59:09 +0000 Subject: [PATCH] db: async `sql` interface (pollable futures) + reactor-async world; vendor wasi:io@0.2.3 --- deps/db/sql.wit | 48 +++++++++++++++++++++++++++++++++++++++++++++ deps/io/package.wit | 48 +++++++++++++++++++++++++++++++++++++++++++++ world.wit | 8 +++++++- 3 files changed, 103 insertions(+), 1 deletion(-) create mode 100644 deps/db/sql.wit create mode 100644 deps/io/package.wit diff --git a/deps/db/sql.wit b/deps/db/sql.wit new file mode 100644 index 0000000..e8747e1 --- /dev/null +++ b/deps/db/sql.wit @@ -0,0 +1,48 @@ +package gcore:db@0.1.0; + +/// FastEdge SQL interface (asynchronous variant). +/// +/// Same contract as `sql-sync`, but `query` and `batch` return at once with a future, so a guest can +/// run several calls concurrently (`wasi:io/poll`) and keep doing other work while they run. +/// +/// Calls already started run independently: their order of execution is not guaranteed. Wait for a +/// result before relying on its effects, and use `batch` for ordered or atomic work. Dropping a +/// future before it resolves abandons the result; the statement may or may not have been applied. +interface sql { + use wasi:io/poll@0.2.3.{pollable}; + use sql-types.{value, query-result, statement, error}; + + /// FastEdge SQL database resource. + resource database { + /// Open the database bound to `name`. + /// + /// `error::no-such-database` will be raised if the `name` is not recognized. + open: static func(name: string) -> result; + + /// Start one statement with positional parameters (`$1`, `$2`, ...). Auto-commits. + /// + /// `sql` must contain exactly one statement. + query: func(sql: string, params: list) -> future-query-result; + + /// Start several statements in one transaction. Either all commit or none do. + batch: func(statements: list) -> future-batch-result; + } + + /// The pending result of `database.query`. + resource future-query-result { + /// Ready when the result is available. + subscribe: func() -> pollable; + /// The result, once ready; `none` before that. Returns the result only once: later calls + /// return `some(err(error::internal-error))`. + get: func() -> option>; + } + + /// The pending result of `database.batch`: one `query-result` per statement, in order. + resource future-batch-result { + /// Ready when the result is available. + subscribe: func() -> pollable; + /// The result, once ready; `none` before that. Returns the result only once: later calls + /// return `some(err(error::internal-error))`. + get: func() -> option, error>>; + } +} diff --git a/deps/io/package.wit b/deps/io/package.wit new file mode 100644 index 0000000..e4d5ef7 --- /dev/null +++ b/deps/io/package.wit @@ -0,0 +1,48 @@ +package wasi:io@0.2.3; + +interface error { + resource error { + to-debug-string: func() -> string; + } +} + +interface poll { + resource pollable { + ready: func() -> bool; + block: func(); + } + + poll: func(in: list>) -> list; +} + +interface streams { + use error.{error}; + use poll.{pollable}; + + variant stream-error { + last-operation-failed(error), + closed, + } + + resource input-stream { + read: func(len: u64) -> result, stream-error>; + blocking-read: func(len: u64) -> result, stream-error>; + skip: func(len: u64) -> result; + blocking-skip: func(len: u64) -> result; + subscribe: func() -> pollable; + } + + resource output-stream { + check-write: func() -> result; + write: func(contents: list) -> result<_, stream-error>; + blocking-write-and-flush: func(contents: list) -> result<_, stream-error>; + flush: func() -> result<_, stream-error>; + blocking-flush: func() -> result<_, stream-error>; + subscribe: func() -> pollable; + write-zeroes: func(len: u64) -> result<_, stream-error>; + blocking-write-zeroes-and-flush: func(len: u64) -> result<_, stream-error>; + splice: func(src: borrow, len: u64) -> result; + blocking-splice: func(src: borrow, len: u64) -> result; + } +} + diff --git a/world.wit b/world.wit index 2f00602..3067355 100644 --- a/world.wit +++ b/world.wit @@ -11,4 +11,10 @@ world reactor { import gcore:db/sql-sync@0.1.0; export http-handler; -} \ No newline at end of file +} + +/// `reactor` plus the asynchronous `gcore:db/sql` (needs `wasi:io`). +world reactor-async { + include reactor; + import gcore:db/sql@0.1.0; +}