Skip to content

Commit 3a7e452

Browse files
odrobnikclaude
andcommitted
Initial commit: SQLiteKit extracted from SwiftPorts
Pure-Swift wrapper over the vendored SQLite amalgamation (stephencelis/CSQLite) with FTS5 and sqlite-vec behind opt-in traits. Extracted from Cocoanetics/SwiftPorts as a standalone, lib-only package so downstream consumers (SwiftAgents, the planned qmd port, the wiki app) depend on a minimal closure and can pin a tagged release instead of branch-tracking the monorepo. - SQLiteKit (SQLiteDatabase / SQLiteStatement / SQLiteValue / SQLiteRow / ResultSet / ResultFormatter) + CSQLiteShim + CSQLiteVec - FTS5 + SQLiteVec package traits, off by default - 46 tests, green with and without traits on macOS (build + both suites) - CI: macOS / iOS / Linux / Windows / Android (analog to SwiftPorts swift.yml) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
0 parents  commit 3a7e452

21 files changed

Lines changed: 12736 additions & 0 deletions

.github/workflows/swift.yml

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
---
2+
name: Swift
3+
on:
4+
push:
5+
branches:
6+
- main
7+
pull_request:
8+
branches:
9+
- main
10+
11+
# Analog to Cocoanetics/SwiftPorts' swift.yml, minus the external-C-dependency
12+
# install steps (brew / apt / vcpkg): SQLiteKit vendors the SQLite engine, so
13+
# there are no system libraries to provision on any platform.
14+
#
15+
# Each full-build platform runs the suite twice: a default run that pins the
16+
# trait-OFF contract (the `#else` branches — FTS5 / vec0 modules absent), then a
17+
# `--traits FTS5,SQLiteVec` run filtered to the on-state proofs. Android runs the
18+
# whole suite with both traits on the x86_64 emulator — the on-device target
19+
# sqlite-vec is built for.
20+
jobs:
21+
22+
build-macos:
23+
runs-on: macos-latest
24+
timeout-minutes: 15
25+
steps:
26+
- uses: actions/checkout@v6
27+
# macos-latest ships an older Xcode; SQLiteKit's tools-version is 6.2.
28+
- name: Select Xcode 26.0
29+
uses: maxim-lobanov/setup-xcode@v1
30+
with:
31+
xcode-version: "26.0"
32+
- name: Verify Swift version
33+
run: swift --version
34+
- name: Build (macOS)
35+
run: swift build --build-tests -v
36+
- name: Test (macOS)
37+
run: swift test -v --skip-build --no-parallel
38+
- name: Test engine traits FTS5 + SQLiteVec (macOS)
39+
run: swift test -v --traits FTS5,SQLiteVec --filter fullTextSearchFTS5 --filter semanticSearchSQLiteVec --filter vec0BlobBind
40+
41+
build-ios:
42+
# Build + run the suite on the iOS Simulator (default, trait-off). The
43+
# trait-on engine build for on-device is covered by build-android.
44+
runs-on: macos-latest
45+
timeout-minutes: 20
46+
steps:
47+
- uses: actions/checkout@v6
48+
- name: Select Xcode 26.0
49+
uses: maxim-lobanov/setup-xcode@v1
50+
with:
51+
xcode-version: "26.0"
52+
- name: Test (iOS Simulator)
53+
run: |
54+
xcodebuild \
55+
-scheme SQLiteKit \
56+
-destination 'platform=iOS Simulator,name=iPhone 16,OS=latest' \
57+
test
58+
59+
build-linux:
60+
# No `apt-get` step — the SQLite engine is vendored, so the container needs
61+
# nothing beyond the toolchain. Pinned to 6.2 (SQLiteKit's tools-version).
62+
runs-on: ubuntu-latest
63+
timeout-minutes: 15
64+
container:
65+
image: swift:6.2-jammy
66+
steps:
67+
- uses: actions/checkout@v6
68+
- name: Verify Swift version
69+
run: swift --version
70+
- name: Build (Linux)
71+
run: swift build --build-tests -v
72+
- name: Test (Linux)
73+
run: swift test -v --skip-build --no-parallel
74+
- name: Test engine traits FTS5 + SQLiteVec (Linux)
75+
run: swift test -v --traits FTS5,SQLiteVec --filter fullTextSearchFTS5 --filter semanticSearchSQLiteVec --filter vec0BlobBind
76+
77+
build-windows:
78+
# No vcpkg step — SQLite is vendored, so there are no external `.lib` files
79+
# to locate (unlike SwiftPorts' libgit2 / libarchive), hence no `-Xcc` /
80+
# `-Xlinker` search-path flags.
81+
runs-on: windows-latest
82+
timeout-minutes: 30
83+
steps:
84+
- uses: actions/checkout@v6
85+
- name: Setup Swift
86+
uses: SwiftyLab/setup-swift@latest
87+
with:
88+
swift-version: "6.3.1"
89+
- name: Verify Swift version
90+
run: swift --version
91+
- name: Build (Windows)
92+
run: swift build --build-tests -v
93+
- name: Test (Windows)
94+
run: swift test -v --skip-build --no-parallel
95+
- name: Test engine traits FTS5 + SQLiteVec (Windows)
96+
run: swift test -v --traits FTS5,SQLiteVec --filter fullTextSearchFTS5 --filter semanticSearchSQLiteVec --filter vec0BlobBind
97+
98+
build-android:
99+
# Cross-build the SDK and run the suite on an x86_64 emulator with both
100+
# engine traits on. No `container:` — the emulator needs nested KVM, only
101+
# available on the bare ubuntu runner image.
102+
runs-on: ubuntu-latest
103+
timeout-minutes: 60
104+
steps:
105+
- uses: actions/checkout@v6
106+
- name: Build & test SDK (Android emulator)
107+
uses: skiptools/swift-android-action@v2
108+
with:
109+
swift-version: "6.3.2"
110+
free-disk-space: true
111+
swift-build-flags: "--traits FTS5,SQLiteVec"
112+
swift-test-flags: "--traits FTS5,SQLiteVec"

.gitignore

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
.DS_Store
2+
/.build
3+
/.swiftpm
4+
/Packages
5+
Package.resolved
6+
xcuserdata/
7+
DerivedData/
8+
*.xcodeproj
9+
.netrc

.spi.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
version: 1
2+
builder:
3+
configs:
4+
- documentation_targets: [SQLiteKit]

CHANGELOG.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Changelog
2+
3+
All notable changes to this package are documented here. The format is based on
4+
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project
5+
adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6+
7+
## [Unreleased]
8+
9+
### Added
10+
11+
- Initial public release, extracted from
12+
[SwiftPorts](https://github.com/Cocoanetics/SwiftPorts) where it backs the
13+
`sqlite3` CLI port.
14+
- `SQLiteDatabase` — open in-memory or file-backed databases; `evaluate` /
15+
`execute` SQL with multi-statement result sets, streaming row callbacks,
16+
schema introspection, a `-safe`-mode authorizer (`enableSafeMode` /
17+
`attachTargets`), and online `backup`.
18+
- `SQLiteStatement` — prepared statements with positional (`?`) and named
19+
(`:name`) parameter binding, strict arity checks, and reusable
20+
bind / step / reset.
21+
- `SQLiteValue` / `SQLiteRow` / `ResultSet` — typed storage-class values,
22+
subscriptable by index and column name.
23+
- `ResultFormatter` — sqlite3-compatible output modes (list, csv, json, column,
24+
table, box, markdown, html, insert, line, …).
25+
- `FTS5` trait — full-text search with bm25 ranking.
26+
- `SQLiteVec` trait — on-device vector / semantic search via sqlite-vec
27+
(`vec0` cosine / L2 KNN), with packed little-endian float32 blob binding.
28+
- Cross-platform support: macOS, iOS, tvOS, watchOS, visionOS, Linux, Android,
29+
and Windows.

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2026 Cocoanetics / Oliver Drobnik
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

Package.swift

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
// swift-tools-version:6.2
2+
import PackageDescription
3+
4+
let package = Package(
5+
name: "SQLiteKit",
6+
platforms: [
7+
.macOS(.v13),
8+
.iOS(.v16),
9+
.tvOS(.v16),
10+
.watchOS(.v9),
11+
.visionOS(.v1),
12+
],
13+
products: [
14+
// The SDK: a thin, pure-Swift wrapper over the vendored SQLite
15+
// amalgamation. FTS5 and sqlite-vec ride along behind opt-in traits.
16+
.library(name: "SQLiteKit", targets: ["SQLiteKit"]),
17+
],
18+
// Opt-in, build-time engine toggles. Both off by default.
19+
// • depending on this package: .package(url: …, traits: ["FTS5", "SQLiteVec"])
20+
// • building this package direct: swift build --traits FTS5,SQLiteVec
21+
// See `fullTextSearchFTS5` / `semanticSearchSQLiteVec` / `vec0BlobBind`
22+
// in SQLiteKitTests for the on/off contract each trait pins.
23+
traits: [
24+
.trait(name: "FTS5",
25+
description: "Compile SQLite with FTS5 full-text search."),
26+
.trait(name: "SQLiteVec",
27+
description: "Compile in sqlite-vec for on-device vector / semantic search."),
28+
],
29+
dependencies: [
30+
// Vendored SQLite amalgamation — a single public-domain `sqlite3.c`
31+
// packaged as a SwiftPM C target. Pinned exact so the engine version
32+
// is identical on every platform. Our `FTS5` trait forwards to
33+
// CSQLite's `FTS5` trait, which compiles the amalgamation with
34+
// `-DSQLITE_ENABLE_FTS5`.
35+
.package(url: "https://github.com/stephencelis/CSQLite",
36+
exact: "3.50.4",
37+
traits: [.trait(name: "FTS5", condition: .when(traits: ["FTS5"]))]),
38+
],
39+
targets: [
40+
// Typed C wrappers for SQLite's variadic printf (`sqlite3_mprintf`),
41+
// which Swift can't call directly — gives `SQLiteKit` byte-exact access
42+
// to the engine's float formatting for round-trip output.
43+
.target(
44+
name: "CSQLiteShim",
45+
dependencies: [
46+
.product(name: "SQLiteSwiftCSQLite", package: "CSQLite"),
47+
],
48+
publicHeadersPath: "include"
49+
),
50+
// sqlite-vec, compiled statically into the engine for on-device vector
51+
// search. Linked only when the `SQLiteVec` trait is on (see SQLiteKit's
52+
// dependency below); no product exposes it, so consumers don't build it
53+
// unless they opt in. The vendored amalgamation (sqlite-vec.c) is
54+
// compiled via sqlite-vec-shim.c — which adds the one missing system
55+
// include — so it stays byte-for-byte upstream and is excluded from
56+
// direct compilation. See Sources/CSQLiteVec/README.md.
57+
.target(
58+
name: "CSQLiteVec",
59+
dependencies: [
60+
.product(name: "SQLiteSwiftCSQLite", package: "CSQLite"),
61+
],
62+
exclude: ["sqlite-vec.c", "README.md", "LICENSE-MIT", "LICENSE-APACHE"],
63+
publicHeadersPath: "include",
64+
cSettings: [
65+
// Static link against the core engine (no sqlite3ext.h
66+
// api-routine indirection); empty the API export macro so the
67+
// symbol isn't dllexport'd on Windows for a static build; drop
68+
// the filesystem helpers to keep vectors in-database.
69+
.define("SQLITE_CORE"),
70+
.define("SQLITE_VEC_STATIC"),
71+
.define("SQLITE_VEC_OMIT_FS"),
72+
]
73+
),
74+
// The SDK — `SQLiteDatabase`, `SQLiteStatement`, `SQLiteValue`,
75+
// `SQLiteRow`, `ResultSet`, `ResultFormatter`. Pure Swift over the
76+
// amalgamation; no system libsqlite3.
77+
.target(
78+
name: "SQLiteKit",
79+
dependencies: [
80+
.product(name: "SQLiteSwiftCSQLite", package: "CSQLite"),
81+
"CSQLiteShim",
82+
// Linked (and the amalgamation compiled) only when the
83+
// SQLiteVec trait is enabled.
84+
.target(name: "CSQLiteVec", condition: .when(traits: ["SQLiteVec"])),
85+
],
86+
linkerSettings: [
87+
// Apple SDKs provide these via libSystem; gate to non-Apple.
88+
.linkedLibrary("m", .when(platforms: [.linux, .android])),
89+
.linkedLibrary("dl", .when(platforms: [.linux, .android])),
90+
// Linux only: Android's Bionic folds pthread into libc (there
91+
// is no separate libpthread.so), so `-lpthread` would fail
92+
// there. The pthread symbols come from libc on Android.
93+
.linkedLibrary("pthread", .when(platforms: [.linux])),
94+
]
95+
),
96+
.testTarget(
97+
name: "SQLiteKitTests",
98+
dependencies: ["SQLiteKit"]
99+
),
100+
]
101+
)

0 commit comments

Comments
 (0)