Repository navigation
Add sqflite_watchos: sqflite on the watch's own SQLite - #5
Conversation
watchOS ships libsqlite3; watchos/Package.swift links it, and Dart calls its C API over dart:ffi, resolved from the process. sqflite's method protocol (open, close, execute, insert, update, query with paged cursors, batch with noResult and continueOnError, transactions with transaction ids, database files and bytes) is answered in Dart with sqflite_common_ffi's behaviour, since method channels do not run on watchOS. registerWith makes the factory sqflite's default, as sqflite_darwin does with its method-channel one. Two FFI exports: the Documents directory, and sqlite3_libversion(), which also keeps libsqlite3 linked. buildDatabaseFactory and SqfliteDatabaseException come from sqflite_common's src/ libraries, as sqflite_common_ffi imports them. sqflite's own example app depends on the unpublished sqflite_example_common, so the example's lib/ is a small watch demo; the official integration test is upstream's, unchanged. It uses package:test's test, which drive does not collect, so it runs with flutter-watchos test. The root README lists the package and drops sqflite from "Feasible but not yet ported"; tool/upstream_versions.yaml gains sqflite 2.4.4+2. Checked: 34 host tests running real SQL against macOS's libsqlite3; the official integration test (14 tests) on the watchOS 27.0 Simulator; the example there saving and listing rows. Not yet checked on a physical watch. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
deleteDatabase removed the database file alone. sqflite_darwin also removes its -wal, -shm and -journal files, and a write-ahead log left behind would be replayed into a new database created at the same path. The databases path is now a copy native owns: fileSystemRepresentation's buffer is only autoreleased, whatever keeps the string alive. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Its content is upstream's; only the layout changes, so that CI's dart format step passes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MAUstaoglu
left a comment
There was a problem hiding this comment.
Thanks for this careful port. The protocol matches sqflite_darwin: open/close, transactions, batch, cursors, readOnly, paths, and the -wal/-shm/-journal cleanup. The Dart tests run real SQL, which is great. Four things before we can merge:
Must-fix
- CI:
test/sqflite_watchos_test.dart:32and:479open/usr/lib/libsqlite3.dylib, but the analyze + test job runs on ubuntu-latest, so every test fails insetUpAll. Please loadlibsqlite3.so.0when not on macOS, or fake the bindings (AUTHORING §1). - Licensing:
lib/src/handler.dartis adapted from sqflite_common_ffi'ssqflite_ffi_impl.dart(same structure, messages and closed-id logic), but its header (:1-13) credits only FlutterWatch. Please:- add the Tekartik BSD-2 notice;
- change BSD-3 to BSD-2 at
README.md:69, to match LICENSE; - name sqflite_common_ffi in
PORTING_REPORT.md:20.
lib/src/sqlite3.dart:432throws forbooland plainList<int>arguments. sqflite_darwin and sqflite_common_ffi bind them as 0/1 and as a blob.tool/upstream_versions.yaml:28: sqflite's latest release is 2.4.5 (21 Oct), not 2.4.4+2.
Nice-to-have
- Set a busy timeout. FMDB waits 2 s on iOS; here a second connection fails at once (
lib/src/sqlite3.dart:242). :memory:should never be single-instance, as in sqflite_darwin (lib/src/handler.dart:209).- Use
sqflite_common: ^2.5.14, which fixes a hang when a cursor is closed inside a transaction, capped at<2.6.0because of thesrc/imports. - Extend
SqflitePlatform, as AUTHORING §1 asks. - All SQL runs on the UI isolate. Consider a background isolate, and a run on a physical watch, before 0.1.0.
test/sqflite_watchos_test.dart:52-53compares a factory with itself, so it can't fail.- Small fixes:
example/pubspec.yaml:12should be^2.4.4;README.md:61says nothing is unsupported, but the deprecatedSqflite.*helpers still go through the method channel;PORTING_REPORT.md:11uses ○ for the wrong state.
We'll start the CI run after your update. Thank you!
Posted from the wrong account; superseded by the maintainer review.
From the review of PR flutterwatch#5: * The host tests open the host's system SQLite: /usr/lib/libsqlite3.dylib on macOS, libsqlite3.so.0 on CI's Linux runner, where every test failed in setUpAll. * lib/src/handler.dart is adapted from sqflite_common_ffi's sqflite_ffi_impl.dart and now says so, with Alexandre Roux Tekartik's BSD-2-Clause notice. The README names BSD-2-Clause, as LICENSE does, and PORTING_REPORT names sqflite_common_ffi as a source. * A bool argument binds as 1 or 0, and a plain List<int> as a blob, as sqflite_darwin and sqflite_common_ffi bind them; both threw. * tool/upstream_versions.yaml: sqflite 2.4.5, the latest release. * Each connection waits up to 2 seconds for another connection's lock, FMDB's default on iOS; a second connection failed at once. * An in-memory database is never a single instance, as in sqflite_darwin. * sqflite_common ">=2.5.14 <2.6.0": 2.5.14 fixes a hang when a cursor is closed inside a transaction, and the src/ imports stop below the next minor. * SqfliteWatchos extends SqflitePlatform, as AUTHORING asks; its factory is databaseFactoryWatchos, since SqflitePlatform has an instance databaseFactory. * The registerWith test compared a factory with itself; it uses a second factory now. The example names sqflite ^2.4.4. The README lists the deprecated Sqflite.* debug helpers, which call the method channel directly, and PORTING_REPORT no longer marks the unified demo with the "no upstream test" sign. Checked: 39 host tests on macOS (5 new; four fail on the old code), and upstream's integration test, 14 tests, on the watchOS 27.0 Simulator. The host tests have not run on Linux here. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The root README's "Feasible but not yet ported" paragraph: main drops wakelock_plus from it, this branch drops sqflite; both are dropped. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CI's first run on Linux passed 38 of 39 host tests. The one that failed waited for a locked database: Ubuntu's libsqlite3 failed the second connection's insert with SQLITE_BUSY after 39 ms instead of waiting out the timeout, though PRAGMA busy_timeout read 2000 there too. The timeout is still checked on both; the wait itself only on macOS, whose SQLite is the watch's. The README also says that sqflite_common warns once per type, in debug, about bool and List<int> arguments, as the CI log shows it does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Thanks for the careful review. Pushed bddc6d1, then 2e8fa39 after the first CI run: Must-fix
Nice-to-have
Checked: 39 host tests on macOS, four of which fail on the old code. Upstream's integration test (14 tests) passes on the watchOS 27.0 Simulator. 🤖 Generated with Claude Code |
MAUstaoglu
left a comment
There was a problem hiding this comment.
Thanks, @iamoguzhanarslantas! Everything is resolved: we verified each fix, and CI is green. Merging as the staged 0.0.1. The follow-ups before 0.1.0 (SQL off the UI isolate, a physical-watch run, the busy-wait README note and the busy test's comment) are tracked in #20.
Summary
Adds
sqflite_watchos0.0.1, the watchOS implementation ofsqflite, which the README listed under "Feasible but not yet ported".libsqlite3.watchos/Package.swiftlinks it, and Dart calls its C API over dart:ffi (lib/src/sqlite3.dart): no FMDB, no method channel.lib/src/handler.dart) with the behaviour ofsqflite_common_ffi, the protocol's reference implementation outside a method channel: transaction ids (a call from outside the open transaction waits for it),transactionClosedwhen SQLite rolls a transaction back, paged cursors, batches withcontinueOnError, and single-instance databases.registerWithsets sqflite_common's default factory frombuildDatabaseFactory, assqflite_darwinsets its method-channel factory.buildDatabaseFactoryandSqfliteDatabaseExceptioncome from sqflite_common'ssrc/libraries, whichsqflite_common_ffiimports the same way;sqflite_common: ^2.5.11pins them.strdup, sincefileSystemRepresentation's buffer is only autoreleased) andsqlite3_libversion(), which also keepslibsqlite3linked.deleteDatabasealso removes the-wal,-shmand-journalfiles, assqflite_darwindoes.tool/upstream_versions.yamlgetssqflite.Verified
On the watchOS 27.0 Simulator (Apple Watch Series 12, 46 mm):
example/integration_test/sqflite_test.dartpasses, all 14 tests, unchanged but for the formatting CI checks. It runs withflutter-watchos test: it usespackage:test'stest, whichflutter-watchos drivedoes not collect, sodrivereports nothing and waits.ffiSymbolsin the export table.Off the watch:
libsqlite3, through sqflite_common'sDatabaseAPI and the protocol below it.tool/check,dart formatas CI runs it, andpub publish --dry-runare clean.Not verified
Notes for review
Future, as the README says; on iOS sqflite runs it on a native thread. That is fine for watch-sized data, but a heavy query holds up the frame it runs in.example/lib/is a small watch demo, because sqflite's own example is built onsqflite_example_common, which is not published.🤖 Generated with Claude Code