This document outlines the practical implementation plan for migrating sqlite-data from GRDB to SQLiteNIO, based on the comprehensive migration guide provided.
The migration involves:
- ~20 source files directly depending on GRDB
- Core abstractions: DatabaseReader, DatabaseWriter, Database, ValueObservation
- Query execution and cursor infrastructure
- Change observation and notification system
- CloudKit synchronization integration (complex)
Goal: Create SQLiteNIO abstractions that mimic GRDB's API surface
-
Sources/SQLiteData/SQLiteNIO/DatabaseProtocols.swiftDatabaseReaderprotocolDatabaseWriterprotocolConfigurationstructDatabasewrapper class
-
Sources/SQLiteData/SQLiteNIO/DatabaseQueue.swift- Wraps
SQLiteConnection - Implements
DatabaseWriter - Provides async read/write methods
- Thread-safety via actor or locks
- Wraps
-
Sources/SQLiteData/SQLiteNIO/DatabasePool.swift- Connection pooling for read/write separation
- Similar to
DatabaseQueuebut with pool management
Package.swift: Replace GRDB dependency with SQLiteNIO
Goal: Enable basic query execution with SQLiteNIO
-
Sources/SQLiteData/SQLiteNIO/SQLiteRowDecoder.swift- Decodes
SQLiteRowtoDecodabletypes - Maps column names to property names
- Handles type conversions
- Decodes
-
Sources/SQLiteData/SQLiteNIO/QueryCursor.swift- Async cursor over query results
- Compatible with existing
QueryCursor<T>API - Wraps SQLiteNIO's row iteration
Sources/SQLiteData/StructuredQueries+GRDB/Statement+GRDB.swift- Rename to
Statement+SQLiteNIO.swift - Replace GRDB
Databasewith SQLiteNIO wrapper - Convert sync methods to async
- Update
execute(),fetchAll(),fetchOne(),fetchCursor()
- Rename to
Goal: Implement database change observation using update hooks
-
Sources/SQLiteData/SQLiteNIO/SQLiteNIOObserver.swift- Actor for thread-safe observation
- Uses
sqlite3_update_hook(from PR #90 or raw SQLite3) - Buffers changes to avoid excessive queries
- Groups changes by table name
- Integrates with Swift Sharing library
-
Sources/SQLiteData/SQLiteNIO/UpdateHook.swift- Wrapper around
sqlite3_update_hook - Provides async callback mechanism
- Handles hook lifecycle
- Wrapper around
Sources/SQLiteData/Internal/FetchKey.swift- Update
subscribe()to useSQLiteNIOObserver - Replace
ValueObservationwith custom observation - Maintain existing
SharedSubscriptionAPI
- Update
Goal: Ensure @FetchAll, @FetchOne, @Fetch work with new implementation
Sources/SQLiteData/FetchAll.swift- May need scheduler updatesSources/SQLiteData/FetchOne.swift- May need scheduler updatesSources/SQLiteData/Fetch.swift- May need scheduler updatesSources/SQLiteData/FetchKeyRequest.swift- Should work as-is
Goal: Update default database dependency
Sources/SQLiteData/StructuredQueries+GRDB/DefaultDatabase.swift- Rename to
DefaultDatabase.swift(remove GRDB reference) - Update
defaultDatabase()to return SQLiteNIO connection - Handle in-memory databases for previews/tests
- Update connection string handling
- Rename to
Goal: Ensure tests pass and functionality works
-
Update test infrastructure
- Fix CloudKit test imports (conditional compilation)
- Update test helpers for async APIs
- Create SQLiteNIO test utilities
-
Run existing tests
- Fix failures incrementally
- Document breaking changes
-
Linux verification
- Build on Linux
- Run tests on Linux
- Verify no platform-specific issues
Goal: Migrate CloudKit sync layer (complex, may defer)
CloudKit integration is complex and may not be needed for initial Linux support.
A. Full Migration: Update all CloudKit code to use SQLiteNIO
- ~15 files in
Sources/SQLiteData/CloudKit/ - Requires understanding CloudKit sync semantics
- Significant testing required
B. Defer with Feature Flag: Keep CloudKit iOS/macOS only
- Use conditional compilation
- Document as known limitation
- Plan future migration
C. Hybrid Approach: CloudKit uses compatibility wrapper
- Create GRDB-compatible wrapper around SQLiteNIO
- Allows CloudKit code to remain mostly unchanged
- Best for gradual migration
Recommendation: Option B (defer) initially, then Option C
- GRDB uses synchronous APIs with dispatch queues
- SQLiteNIO uses async/await with NIO EventLoop
- Need to bridge these paradigms carefully
- GRDB has
ValueObservationScheduler - SQLiteNIO has EventLoop-based scheduling
- May need custom scheduler adapter
- Different error types between libraries
- Need consistent error reporting
- Preserve existing error semantics where possible
- GRDB is highly optimized
- SQLiteNIO may have different performance characteristics
- Need benchmarking after migration
- May need statement caching
- GRDB has sophisticated transaction handling
- SQLiteNIO may be simpler
- Ensure ACID properties preserved
- Some synchronous methods become async
DatabaseReader/DatabaseWriterprotocols change- Scheduler API may change
- CloudKit integration may be iOS/macOS only initially
- Use
@availableannotations - Provide migration guide
- Keep high-level APIs stable (@FetchAll, etc.)
- Package builds on macOS
- Package builds on Linux
- Basic queries work (@FetchAll, @FetchOne)
- Change observation works
- Tests pass (non-CloudKit)
- Property wrappers work in SwiftUI
- All tests pass
- CloudKit integration works
- Performance comparable to GRDB
- Documentation updated
- Example apps work
- CloudKit integration complexity
- Performance degradation
- Hidden GRDB dependencies
- Async/await transition bugs
- Threading issues
- Edge cases in observation
- Package dependency issues
- Build configuration
- Documentation gaps
- Week 1: Phases 1-2
- Week 2: Phases 3-5
- Week 3: Phase 6, skip Phase 7
- Weeks 1-2: Phases 1-2
- Weeks 3-4: Phases 3-5
- Weeks 5-6: Phases 6-7
- Weeks 1-3: Phases 1-2 (with testing)
- Weeks 4-6: Phases 3-5 (with testing)
- Weeks 7-9: Phase 6 (comprehensive testing)
- Week 10: Phase 7 (if needed)
- Review and approve this plan
- Set up development branch
- Start with Phase 1 implementation
- Regular check-ins after each phase
- Adjust plan based on learnings
- This migration touches core infrastructure
- High test coverage crucial
- Consider feature freeze during migration
- Budget time for unexpected issues
- Linux CI setup needed early