Skip to content

feat: Add Embedded Swift support for SQLiteNIO - #5

Draft
scottmarchant wants to merge 1 commit into
feat/wasi-nio-freefrom
feat/embedded-support
Draft

feat: Add Embedded Swift support for SQLiteNIO#5
scottmarchant wants to merge 1 commit into
feat/wasi-nio-freefrom
feat/embedded-support

Conversation

@scottmarchant

@scottmarchant scottmarchant commented Jul 27, 2026

Copy link
Copy Markdown
Collaborator

Stacked on #4 (feat/wasi-nio-free) and retargets to base/vapor-main once that merges, so the diff here shows only the Embedded work. Research grade and lower priority than #4, which does not depend on this; review that one first.

Makes SQLiteNIO compile for wasm32-unknown-wasip1-embedded.

Changes:

  • SQLiteData's Encodable conformance moves to a conditional extension and the deprecated SQLiteDataType.serialize(_:) is elided: Embedded Swift has no Encoder and no any Encodable existential.
  • The async withConnection(_:) protocol requirement 1.13.0 added is elided under Embedded Swift, because a generic method requirement cannot be placed in a witness table and keeping it would make any SQLiteDatabase unusable there. The concrete SQLiteConnection.withConnection(_:) remains available.
  • SQLiteError: LocalizedError, the Data bridges, and the Date bridge gate on canImport(FoundationEssentials) || canImport(Foundation), since Embedded Swift has neither flavor. The errorDescription witness stays in the type body, so only the conformance is conditional.
  • The hook API gates whole-file on that same Foundation condition, and observerBuckets plus close()'s clearAllHooks() call gate with it. This one is deliberately not narrowed: the hook API's public surface is Foundation-shaped, with Date on SQLiteCommitEvent/SQLiteRollbackEvent and UUID on SQLiteHookToken.id, so keeping it would mean either shipping stand-ins for both types or giving Embedded a different public API than every other target.
  • SQLiteRow.description and SQLiteCustomFunction's error reporting rely on reflection (Array.description, any Error interpolation), so reflection-free equivalents replace them under Embedded Swift.

Where the full toolchain is present, nothing changes: every gate here is false outside Embedded Swift. swift package diagnose-api-breaking-changes against #4's tip reports no breaking changes in SQLiteNIO, and the 59-test suite passes unchanged.

What Embedded loses: the Encodable conformance on SQLiteData, the deprecated SQLiteDataType.serialize(_:), the protocol-level async withConnection(_:) (the concrete one stays), SQLiteError: LocalizedError, the Data and Date bridges, and the observation hook API. Nothing here affects regular WASI, which has FoundationEssentials and Codable and needs none of it. That is why this is a separate PR.

Prerequisite outside this repo: an Embedded-clean swift-log. Upstream swift-log does not compile under Embedded Swift (Logger.Level: Codable, Dictionary.description, and Array.description are all @_unavailableInEmbedded), so the build dies inside Logging before reaching a line of sqlite-nio code. This is verified against a locally patched clone; that patch is not committed anywhere on this branch and the manifest still points at upstream apple/swift-log, so this cannot land until swift-log gains Embedded support. swift-collections needed nothing.

Verification: the Embedded build is green with swiftly run +main-snapshot-2026-06-12 swift build --swift-sdk DEVELOPMENT-SNAPSHOT-2026-06-12-a-wasm32-unknown-wasip1-embedded and the patched swift-log, exercised end to end by a downstream consumer whose Embedded test suite passes against this branch. Native and regular WASI are verified unchanged, not merely unchanged by construction: 59 tests green and no API breakage against #4.

Notes for review: every gate is a capability gate (hasFeature(Embedded) or canImport), never a platform check; there is no os(WASI) anywhere in this stack. No SwiftPM traits, no versioned manifest, no tools-version bump, no new dependencies.

@scottmarchant
scottmarchant force-pushed the feat/embedded-support branch from d2eda14 to 84ccd33 Compare July 28, 2026 21:00
@scottmarchant
scottmarchant force-pushed the feat/embedded-support branch 2 times, most recently from 7923233 to 1bf01f2 Compare July 29, 2026 22:20
@scottmarchant
scottmarchant force-pushed the feat/wasi-nio-free branch 2 times, most recently from a699466 to ba8e2cc Compare July 30, 2026 02:42
@scottmarchant
scottmarchant force-pushed the feat/embedded-support branch from 1bf01f2 to 967513a Compare July 30, 2026 02:43
@scottmarchant
scottmarchant force-pushed the feat/embedded-support branch from 967513a to c3f48c2 Compare July 30, 2026 03:14
@scottmarchant scottmarchant changed the title Embedded Swift support for SQLiteNIO feat: Add Embedded Swift support for SQLiteNIO Jul 30, 2026
@scottmarchant
scottmarchant force-pushed the feat/embedded-support branch from c3f48c2 to 8b1167c Compare July 30, 2026 03:48
Motivation:

Embedded Swift has no reflection, no `Encoder`, no existential metatypes, no
generic protocol requirements, and no Foundation in either flavor. A handful of
SQLiteNIO declarations depend on one of those and are the only thing standing
between the SwiftNIO-free configuration and a `wasm32-unknown-wasip1-embedded`
build.

Modifications:

Elide exactly those declarations. Every gate is `#if hasFeature(Embedded)` or a
Foundation-flavor `canImport`, so no other target is affected in any way.

- `SQLiteData`'s `Encodable` conformance and the deprecated
  `SQLiteDataType.serialize(_:)` move behind `#if !hasFeature(Embedded)`:
  Embedded Swift has no `Encoder` and no `any Encodable` existential.
- `SQLiteDatabase`'s `async` `withConnection(_:)` requirement moves behind the
  same gate: a generic method requirement cannot be placed in a witness table,
  and keeping it would make `any SQLiteDatabase` unusable under Embedded Swift.
  The concrete ``SQLiteConnection/withConnection(_:)`` remains available.
- `SQLiteError: LocalizedError`, the `Data` bridges, and the `Date` bridge gate
  on `canImport(FoundationEssentials) || canImport(Foundation)`. The
  `errorDescription` witness stays in the type body, so the conformance is the
  only conditional part.
- The hook API gates whole-file on the same condition: hook events carry `Date`
  timestamps and observer identity rides on `UUID`, so the API cannot exist
  without one of the flavors. The `observerBuckets` container and `close()`'s
  `clearAllHooks()` call gate with it.
- `Exports.swift`'s `ByteBuffer(data:)` shim, and its Foundation-flavor import,
  move behind the same gate; the rest of the `[UInt8]` stand-in needs only the
  stdlib.
- `SQLiteRow.description` and `SQLiteCustomFunction`'s error reporting use
  reflection (`Array.description`, `any Error` interpolation); reflection-free
  equivalents replace them under Embedded Swift.

Result:

SQLiteNIO compiles for `wasm32-unknown-wasip1-embedded`. Building for that target
additionally requires an Embedded-clean `apple/swift-log`; see the pull request
description.
@scottmarchant
scottmarchant force-pushed the feat/embedded-support branch from 8b1167c to f00a97d Compare July 30, 2026 04:49
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.

1 participant