Pluggable DB adapter: async API, sql.js becomes opt-in - #44
Merged
Conversation
Implements the plan in documents/pluggable-db-adapter.md. The core library no longer imports sql.js. `GtfsSqlJs` now talks to a narrow async `GtfsDatabase` interface; consumers pick an adapter. A sql.js adapter ships as a subpath module (`gtfs-sqljs/adapters/sql-js`), and a reference better-sqlite3 adapter lives under `examples/adapters/`. Key changes: - New `src/adapters/types.ts` (GtfsDatabase, GtfsStatement, GtfsDatabaseAdapter, SqlValue, Row, ExportNotSupportedError) - New `src/adapters/sql-js/index.ts` with `createSqlJsAdapter` - All query / loader / schema code now `async` and uses GtfsDatabase - `GtfsSqlJs.attach(db, options)` entry point for caller-managed handles (file-backed drivers: better-sqlite3, op-sqlite, expo-sqlite) - `options.adapter` is required on fromZip / fromZipData / fromDatabase - Cache layer catches ExportNotSupportedError and warns + no-ops - sql.js moves to optional peerDependency; better-sqlite3 is a devDependency powering a new end-to-end CI test (`tests/e2e-better-sqlite3.test.ts`) - Breaking: every gtfs.* method returns `Promise<T>`; call sites must `await`. CHANGELOG documents the migration diff. All 143 tests pass (sql.js + better-sqlite3 paths). Build, typecheck, and lint are clean. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Node 18 does not expose `crypto` as a global, so `crypto.subtle.digest` threw `ReferenceError: crypto is not defined` whenever the cache path ran (first surfaced by the new better-sqlite3 e2e test). Guard the lookup and lazily import `node:crypto`'s webcrypto when `globalThis.crypto` is absent. Browsers and RN always go through the global path. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Moves the reference adapter from `examples/adapters/BetterSqlite3Adapter.ts` into `src/adapters/better-sqlite3/index.ts` and ships it as an opt-in subpath export, identical in shape to the sql.js adapter: - New subpath: `gtfs-sqljs/adapters/better-sqlite3`, exporting `wrapBetterSqlite3` and `createBetterSqlite3Adapter`. - `tsup.config.ts` gains the third entry; built artifact lives at `dist/adapters/better-sqlite3/index.js`. - `package.json`: new `exports` entry and `better-sqlite3` added as an optional `peerDependency` (kept in `devDependencies` for the CI test). - `tests/e2e-better-sqlite3.test.ts` now imports from the real adapter path; the ad-hoc `tests/helpers/better-sqlite3-adapter.ts` copy is deleted. No behavior change — same wrapping code, just promoted. All 143 tests still pass; build, typecheck, and lint are clean. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
README:
- Expand tagline: adapters for sql.js (browser / Node WASM) and
better-sqlite3 (Node native), RN support noted.
- Installation now names the adapter peer dependencies.
- Quick Start shows both sql.js (fromZip) and better-sqlite3 (attach).
- New "Adapters" section with the two built-in subpaths and the
factory vs. attach() entry points.
- API reference: all instance methods return Promise<T>; `adapter` is
required on fromZip/fromZipData/fromDatabase; document `attach()`.
- TypeScript type-imports section includes the adapter surface.
Usage Guide (documents/guide.md):
- New "Adapters overview" section up front.
- Rewritten "Loading the sql.js WASM File" around createSqlJsAdapter.
- Rewritten "Creating an Instance" with six scenarios covering sql.js
(ZIP URL / ZIP bytes / .db bytes) and better-sqlite3 (attach file /
factory in-memory / factory file-backed), plus a decision table and
a sketch of a custom adapter.
- Every query example now `await`s.
- Fixed the `getCalendars({ serviceId })` reference (the real method
is `getCalendarByServiceId(serviceId)`); added `getCalendarDatesForDate`.
- Cache examples plumb the adapter through; added a note on
ExportNotSupportedError behavior with file-backed adapters.
- Direct Database Access rewritten around the async GtfsDatabase surface.
- Complete Example at the bottom rewritten to await everything and
close the DB properly (previous version had `await` inside a
non-async `.map`).
No source changes — docs only.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The previous version listed the breaking changes as bullets but did not actually walk a user through the upgrade. It was missing: - the `npm install sql.js` step (sql.js is now a peer dep) - before/after diffs for the common sql.js call sites - the `getDatabase()` return-type shift (now returns a GtfsDatabase with async methods — silent failure for anyone doing direct prepare/step/getAsObject calls) - the better-sqlite3 `attach()` path as a concrete alternative - a table mapping removed options (`SQL`, `locateFile`, re-exported sql.js types) to their new homes - pointers into README and documents/guide.md Restructured as: unchanged → install → diff your queries → diff getDatabase() → attach() option → removed/renamed options table. Docs only; no source changes. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements
documents/pluggable-db-adapter.md.GtfsSqlJstalks to a narrow asyncGtfsDatabaseinterface.gtfs-sqljs/adapters/sql-js(createSqlJsAdapter). Other drivers (better-sqlite3, op-sqlite, expo-sqlite) plug in via the same interface.BetterSqlite3Adapterinexamples/adapters/, exercised by a new CI end-to-end test (tests/e2e-better-sqlite3.test.ts).GtfsSqlJs.attach(db, options?)entry point for caller-managed handles (file-backed drivers).sql.jsmoves fromdependenciesto optionalpeerDependency;better-sqlite3added todevDependencies.Breaking changes
Every
gtfs.*query method is nowasync/ returnsPromise<T>— call sites mustawait.options.adapteris required onfromZip/fromZipData/fromDatabase. The sql.js migration is:SQL/locateFileremoved fromGtfsSqlJsOptions(moved ontocreateSqlJsAdapter).sql.js type re-exports dropped from the public surface; consumers migrate to
GtfsDatabaseor import fromsql.jsdirectly.Cache layer catches
ExportNotSupportedErrorfrom adapters that cannot serialize in-memory and logs a warning instead of failing — file-backed drivers persist their own DB on disk.Test plan
npm run lint— cleannpm run typecheck— cleannpm test— 143 tests passing across sql.js + better-sqlite3 adaptersnpm run build— clean (dist/index.js+dist/adapters/sql-js/index.js)🤖 Generated with Claude Code