Skip to content

feat(db): fastedge::db/sql builtin over gcore:db/sql-sync - #155

Closed
godronus wants to merge 9 commits into
mainfrom
feat/db-interface
Closed

godronus wants to merge 9 commits into
mainfrom
feat/db-interface

Conversation

@godronus

@godronus godronus commented Oct 27, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

fastedge::db/sql: JS API for customer-owned Postgres bound to the app by name (Neon first), over gcore:db/sql-sync.

  • runtime/fastedge/builtins/db-sql.{h,cpp}: SqlDatabase.open(name), query(sql, params?, { rowMode? }), batch(statements, { rowMode? }) returning Promises; SqlError is a real Error (kind, SQLSTATE code, detail, hint, constraint)
  • Type mapping: int8/numeric → string (no precision loss), json/jsonb parsed, bytea → Uint8Array, rowMode: 'array'; params accept bigint, Uint8Array, Date, objects (JSON)
  • types/fastedge-db-sql.d.ts; merge-wit-bindings.js hoists FastEdge-wit's own deps/ into wit/deps/
  • Example examples/db-sql: Drizzle ORM via drizzle-orm/pg-proxy (recipe, no wrapper package), drizzle-kit migrations; mirrors the Rust example
  • runtime/FastEdge-wit → G-Core/FastEdge-wit feat/db-interface

Stacked on #156 (StarlingMonkey v0.4.0, wit-bindgen 0.52): this PR shows those commits until #156 merges.

Decisions needed

# Decision Proposal / state
1 Sync vs async Here: sync host calls, so query returns an already-settled Promise and Promise.all runs in series. Async version (stacked draft PR) makes queries concurrent: Promise.all of 3 = 319 ms vs 617 ms, no single-query cost. Recommendation: ship JS on async
2 Release order Every app built with this SDK imports gcore:db (the world includes it), even without using a database; hosts without it fail with 530 context error (also breaks cross-platform-build.test.js component-import tests against the current fastedge-test). Release only after: engine on all edges → @gcoredev/fastedge-test updated
3 Drizzle Documented recipe + example, no @gcoredev/fastedge-drizzle package (drizzle-orm Apache-2.0, drizzle-kit MIT)
4 Migrations Out of band (drizzle-kit from the developer machine/CI), not at the edge

Testing

  • Example run on fastedge-run against Neon (list, by id, 404, SQLSTATE 42P01 → SqlError kind: 'query').

Related: G-Core/FastEdge#659, G-Core/FastEdge-wit#8, G-Core/FastEdge-sdk-rust#93 · Async (stacked): #157

Copilot AI balanced review requested due to automatic review settings October 27, 2026 13:31

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Silent parameter corruption, result-column loss, incomplete cleanup, and public API mismatches remain unresolved.

3 open issues
1 file not reviewed
  • pnpm-lock.yaml: Generated file
What changed in this PR

Adds a PostgreSQL database interface to the FastEdge SDK, connecting JavaScript applications to host-managed database bindings.

Changes:

  • Introduces SQL runtime builtins, public TypeScript declarations, and module resolution.
  • Adds the SQL host interface and generated bindings, with dependency handling for WIT generation.
  • Provides a Drizzle example with schema migrations, seed data, and setup instructions.
File Description
types/​index.d.ts Includes SQL API declarations.
types/​fastedge-db-sql.d.ts Defines database, query, result, and error types.
src/​componentize/​es-bundle.ts Resolves SQL imports to runtime globals.
runtime/​fastedge/​scripts/​merge-wit-bindings.js Hoists nested WIT dependencies.
runtime/​fastedge/​host-api/​wit/​deps/​fastedge/​world.wit Imports the SQL host interface.
runtime/​fastedge/​host-api/​wit/​deps/​db/​sql.wit Defines the PostgreSQL host contract.
runtime/​fastedge/​host-api/​bindings/​bindings.h Adds SQL binding declarations.
runtime/​fastedge/​host-api/​bindings/​bindings.c Adds SQL calls and cleanup helpers.
runtime/​fastedge/​CMakeLists.txt Registers the SQL builtin.
runtime/​fastedge/​builtins/​db-sql.h Declares builtin database methods.
runtime/​fastedge/​builtins/​db-sql.cpp Implements SQL operations and value conversion.
pnpm-lock.yaml Records database example dependencies.
examples/​README.md Lists the SQL example.
examples/​db-sql/​tsconfig.json Configures example TypeScript checking.
examples/​db-sql/​src/​schema.ts Defines the example users table.
examples/​db-sql/​src/​index.ts Serves user queries over HTTP.
examples/​db-sql/​src/​db.ts Adapts SQL queries to Drizzle.
examples/​db-sql/​README.md Documents setup, usage, and limitations.
examples/​db-sql/​package.json Declares dependencies and example commands.
examples/​db-sql/​drizzle/​meta/​0001_snapshot.json Records schema state after seeding.
examples/​db-sql/​drizzle/​meta/​0000_snapshot.json Records the initial schema state.
examples/​db-sql/​drizzle/​meta/​_journal.json Tracks migration order.
examples/​db-sql/​drizzle/​0001_seed.sql Inserts sample users.
examples/​db-sql/​drizzle/​0000_init.sql Creates the users table.
examples/​db-sql/​drizzle.config.ts Configures external database migrations.
examples/​db-sql/​.fastedge/​build-config.js Configures the example WASM build.
context/​CHANGELOG.md Records the SQL proof of concept.

Review effort: Balanced

Comment on lines +150 to +153
if (v.isBigInt()) {
out.tag = GCORE_DB_SQL_VALUE_INT64;
out.val.int64 = JS::ToBigInt64(v.toBigInt());
return true;
Comment on lines 1135 to 1137
void wasi_io_streams_result_list_u8_stream_error_free(wasi_io_streams_result_list_u8_stream_error_t *ptr) {
if (!ptr->is_err) {
bindings_list_u8_free(&ptr->val.ok);
} else {
for (size_t j = 0; j < row.len && j < names.length(); j++) {
if (!from_value(cx, row.ptr[j], &cell)) return nullptr;
if (array_mode ? !JS_SetElement(cx, out, j, cell)
: !JS_SetPropertyById(cx, out, names[j], cell)) {
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants