Skip to content
Tinker
Download

Architecture

A Swift Package Manager workspace with a strictly downward dependency graph.

The app depends on the packages. The packages depend on DBCore. DBCore depends on Foundation and swift-log, and nothing else. Scripts/ci.sh lints the import statements to keep it that way.

App/Tinker            SwiftUI shell, AppKit grid and editor, menus, commands
│
├── DBGrid            Grid model, edit tracking, paging, DML generation
├── DBSQL             Statement splitter, tokenizer, quoting, formatter, filter compiler
├── DBPostgres        SQLDriver over postgres-nio (PostgresClient, binary results)
├── DBMySQL           SQLDriver over mysql-nio (prepared-statement protocol, text fallback)
├── DBSQLite          SQLDriver over the system libsqlite3, one dedicated thread per file
├── DBTunnel          SSH port forwarding over Citadel, known-hosts, TLS helpers
├── DBStore           Connection store, Keychain, query history, settings
├── DBTestKit         Fixtures, env-var server resolution, skip-with-reason helpers
│
└── DBCore            Driver protocol, value model, errors, ConnectionSession

Load-bearing decisions

Each is recorded as an architecture decision record in DECISIONS.md.

  • All database I/O runs in actors. @MainActor is reserved for views and view models. No DispatchQueue anywhere.
  • One driver-neutral value model. Every native type maps to exactly one DBValue case. Unknown types surface as .raw with their type name rather than being guessed at. Decimals and timestamps keep the server’s text.
  • Two execution paths, chosen by whether the statement streams rows, so a SELECT over a million rows and a CREATE PROCEDURE are both first-class.
  • Binary results on PostgreSQL, with text rendered losslessly by the driver. Prepared statements on MySQL, with a text fallback for statements the protocol cannot prepare.
  • Pooled connections are reset before reuse, and history and error logs are redacted.
  • No `try!`, no force unwraps outside tests, no `print`. Swift 6 with -strict-concurrency=complete and zero warnings, enforced in CI.

Dependencies

PurposePackage
PostgreSQLvapor/postgres-nio
MySQL / MariaDBvapor/mysql-nio
SSHorlandos-nl/Citadel
Loggingapple/swift-log
Updatessparkle-project/Sparkle
SQLitethe libsqlite3 macOS ships, through the system SQLite3 module

Nothing else is added without an ADR.

Persistence

DBStore is a SQLite database at ~/Library/Application Support/Tinker/store.sqlite in WAL mode: connections (without secrets), groups, query history, grid preferences and settings. Migrations are numbered SQL files tracked in PRAGMA user_version. No ORM; a small typed layer over the SQLite3 C API.

Definition of done

A feature is done when the build is warning-free under strict concurrency, the tests are green, the driver feature has an integration test that actually ran against a local server, and the performance criteria are measured with signposts rather than by eye.