Commit 9929539

derdilla <82763757+NobodyForNothing@users.noreply.github.com>
2024-08-01 02:51:51
fix write attempts on db import
Signed-off-by: derdilla <82763757+NobodyForNothing@users.noreply.github.com>
1 parent ec68477
Changed files (5)
app/lib/features/export_import/export_button_bar.dart
@@ -116,7 +116,7 @@ class ExportButtonBar extends StatelessWidget {
                     final List<MedicineIntake> intakes = [];
                     try {
                       final db = await openReadOnlyDatabase(file.path!);
-                      final importedDB = await HealthDataStore.load(db);
+                      final importedDB = await HealthDataStore.load(db, true);
                       records.addAll(await importedDB.bpRepo.get(DateRange.all()));
                       notes.addAll(await importedDB.noteRepo.get(DateRange.all()));
                       intakes.addAll(await importedDB.intakeRepo.get(DateRange.all()));
health_data_store/lib/src/database_manager.dart
@@ -27,22 +27,22 @@ class DatabaseManager {
   ///
   /// If [db] doesn't contain a scheme or contains an outdated scheme, one will
   /// be created.
-  static Future<DatabaseManager> load(Database db) async {
+  static Future<DatabaseManager> load(Database db, [bool isReadOnly = false]) async {
     final dbMngr = DatabaseManager._create(db);
 
     final tables = await dbMngr._db.query('"main".sqlite_master');
-    if (tables.length <= 3) {
+    if (tables.length <= 3 && !isReadOnly) {
       // DB has just been created, no version yet.
       await dbMngr._db.setVersion(2);
     }
 
-    if (await dbMngr._db.getVersion() < 3) {
+    if (!isReadOnly && await dbMngr._db.getVersion() < 3) {
       await dbMngr._setUpTables();
       await dbMngr._db.setVersion(3);
     }
     // When updating the schema the update steps are maintained for ensured 
     // compatability.
-    
+    // TODO: develop strategy for loading older db versions as read only.
     return dbMngr;
   }
 
health_data_store/lib/src/health_data_store.dart
@@ -9,6 +9,7 @@ import 'package:health_data_store/src/repositories/medicine_repository.dart';
 import 'package:health_data_store/src/repositories/medicine_repository_impl.dart';
 import 'package:health_data_store/src/repositories/note_repository.dart';
 import 'package:health_data_store/src/repositories/note_repository_impl.dart';
+import 'package:health_data_store/src/repositories/repository.dart';
 import 'package:sqflite_common/sqflite.dart';
 
 /// Factory class for objects that provide access to the health database.
@@ -30,11 +31,17 @@ class HealthDataStore {
   /// decrease database performance in the first milliseconds after being
   /// returned. This is done to improve performance while interacting with the
   /// database.
-  static Future<HealthDataStore> load(Database db) async {
+  ///
+  /// When loading a database as [isReadOnly] no automatic changes to the
+  /// database are made. It will however not protect you from manually
+  /// attempting to modify the stored contents (e.g. in [Repository] methods).
+  static Future<HealthDataStore> load(Database db, [bool isReadOnly = false]) async {
     // TODO: loading readOnly dbs
     assert(db.isOpen);
     final mngr = await DatabaseManager.load(db);
-    unawaited(mngr.performCleanup());
+    if (!isReadOnly) {
+      unawaited(mngr.performCleanup());
+    }
     return HealthDataStore._create(mngr);
   }
 
health_data_store/test/src/database_manager_test.dart
@@ -1,6 +1,5 @@
 import 'package:health_data_store/src/database_manager.dart';
 import 'package:health_data_store/src/extensions/datetime_seconds.dart';
-import 'package:sqflite_common/sqflite.dart';
 import 'package:sqflite_common_ffi/sqflite_ffi.dart';
 import 'package:test/test.dart';
 
@@ -222,4 +221,5 @@ void main() {
 }
 
 Future<DatabaseManager> mockDBManager() async => DatabaseManager.load(
-    await openDatabase(inMemoryDatabasePath));
+  await openDatabase(inMemoryDatabasePath),
+);
health_data_store/test/src/health_data_store_test.dart
@@ -36,4 +36,10 @@ void main() {
   expect(data.length, 1);
   expect(data, contains(r));
  });
+ test('should not modify read-only databases', () async {
+  final db = await openReadOnlyDatabase(inMemoryDatabasePath);
+  await HealthDataStore.load(db, true);
+  await db.close();
+  // Potential unawaited async exceptions would cause the method to fail.
+ });
 }