Commit 0ee3c8f

derdilla <82763757+NobodyForNothing@users.noreply.github.com>
2024-07-31 13:36:35
Fix duplicate entries on import (#365)
* drop duplicate entries support Signed-off-by: derdilla <82763757+NobodyForNothing@users.noreply.github.com> * fix convention change Signed-off-by: derdilla <82763757+NobodyForNothing@users.noreply.github.com> --------- Signed-off-by: derdilla <82763757+NobodyForNothing@users.noreply.github.com>
1 parent 0a9df0f
health_data_store/lib/src/repositories/blood_pressure_repository_impl.dart
@@ -33,21 +33,29 @@ class BloodPressureRepositoryImpl extends BloodPressureRepository {
       final entryID = await DBHelper.getEntryID(
         txn,
         timeSec,
-        ['Systolic', 'Diastolic', 'Pulse'],
       );
       if (record.sys != null) {
+        await txn.delete('Systolic', where: 'entryID = ?',
+          whereArgs: [entryID],
+        );
         await txn.insert('Systolic', {
           'entryID': entryID,
           'sys': record.sys!.kPa,
         });
       }
       if (record.dia != null) {
+        await txn.delete('Diastolic', where: 'entryID = ?',
+          whereArgs: [entryID],
+        );
         await txn.insert('Diastolic', {
           'entryID': entryID,
           'dia': record.dia!.kPa,
         });
       }
       if (record.pul != null) {
+        await txn.delete('Pulse', where: 'entryID = ?',
+          whereArgs: [entryID],
+        );
         await txn.insert('Pulse', {
           'entryID': entryID,
           'pul': record.pul,
health_data_store/lib/src/repositories/medicine_intake_repository_impl.dart
@@ -30,8 +30,8 @@ class MedicineIntakeRepositoryImpl extends MedicineIntakeRepository {
     final medIDRes = await txn.query('Medicine',
       columns: ['medID'],
       where: 'designation = ? '
-          'AND color ' +((intake.medicine.color != null) ? '= ?' : 'IS NULL')
-          + ' AND defaultDose ' +((intake.medicine.dosis != null) ? '= ?':'IS '
+          'AND color ' + ((intake.medicine.color != null) ? '= ?' : 'IS NULL')
+          + ' AND defaultDose ' + ((intake.medicine.dosis != null) ? '= ?':'IS '
           'NULL'),
       whereArgs: [
         intake.medicine.designation,
@@ -46,10 +46,8 @@ class MedicineIntakeRepositoryImpl extends MedicineIntakeRepository {
     final medID = medIDRes.first['medID'];
 
     // obtain free entry id
-    final id = await DBHelper.getEntryID(
-      txn, intake.time.secondsSinceEpoch,
-      ['Intake'],
-    );
+    final id = await DBHelper.getEntryID(txn, intake.time.secondsSinceEpoch);
+    await txn.delete('Intake', where: 'entryID = ?', whereArgs: [id]);
 
     // store to db
     await txn.insert('Intake', {
health_data_store/lib/src/repositories/note_repository_impl.dart
@@ -27,9 +27,9 @@ class NoteRepositoryImpl extends NoteRepository {
       return;
     }
     await _db.transaction((txn) async {
-      final id = await DBHelper.getEntryID(
-        txn, note.time.secondsSinceEpoch,
-        ['Notes'],
+      final id = await DBHelper.getEntryID(txn, note.time.secondsSinceEpoch);
+      await txn.delete('Notes', where: 'entryID = ?',
+        whereArgs: [id],
       );
       await txn.insert('Notes', {
         'entryID': id,
health_data_store/lib/src/repositories/repository.dart
@@ -12,6 +12,10 @@ import 'package:health_data_store/src/types/date_range.dart';
 /// to avoid exposing the constructor to the public api.
 abstract class Repository<T> {
   /// Adds a new value to the repository.
+  ///
+  /// If there is an existing value of that type at the same time it gets
+  /// overridden. This is to ensure no duplicate entries are inserted and only
+  /// the most up to date value is used.
   Future<void> add(T value);
 
   /// Attempts to remove a value from the repository.
health_data_store/lib/src/database_helper.dart
@@ -7,19 +7,16 @@ class DBHelper {
 
   /// Get a entryID from the `Timestamps` table of a database.
   ///
-  /// Ensures that the associated timestamp matches [timestampUnixS] and that
-  /// it is used in no table with a name in [blockedTables]. Creates a entry
-  /// when necessary
+  /// Ensures that the associated timestamp matches [timestampUnixS]. Creates a
+  /// new id when necessary.
   static Future<int> getEntryID(
     Transaction txn,
     int timestampUnixS,
-    List<String> blockedTables,
   ) async {
-    var query = 'SELECT entryID FROM Timestamps WHERE timestampUnixS = ?';
-    for (final t in blockedTables) {
-      query += 'AND entryID NOT IN (SELECT entryID FROM $t)';
-    }
-    final existing = await txn.rawQuery(query, [timestampUnixS]);
+    final existing = await txn.rawQuery(
+      'SELECT entryID FROM Timestamps WHERE timestampUnixS = ?',
+      [timestampUnixS],
+    );
     int entryID;
     if (existing.isEmpty) {
       final result = await txn.query('Timestamps',
health_data_store/lib/src/database_manager.dart
@@ -105,10 +105,12 @@ class DatabaseManager {
   /// - medicines that are marked as deleted and have no referencing intakes
   /// - timestamp entries that have no
   Future<void> performCleanup() => _db.transaction((txn) async {
+    // Remove medicines marked deleted with no remaining entries
     await txn.rawDelete('DELETE FROM Medicine '
       'WHERE removed = 1 '
       'AND medID NOT IN (SELECT medID FROM Intake);',
     );
+    // Remove unused entry ids
     await txn.rawDelete('DELETE FROM Timestamps '
       'WHERE entryID NOT IN (SELECT entryID FROM Intake)'
       'AND entryID NOT IN (SELECT entryID FROM Systolic) '
health_data_store/test/src/repositories/blood_pressure_repository_test.dart
@@ -103,7 +103,7 @@ void main() {
     ));
     expect(values3, isEmpty);
   });
-  test('should remove correct record when multiple are at same time', () async {
+  test('overrides when inserting multiple records are at same time', () async {
     final db = await mockDBManager();
     addTearDown(db.close);
     final repo = BloodPressureRepositoryImpl(db.db);
@@ -111,8 +111,6 @@ void main() {
     final r2 = mockRecord(time: 10000, sys: 678, dia: 457, pul: 458);
     await repo.add(r1);
     await repo.add(r2);
-
-    await repo.remove(r1);
     final values2 = await repo.get(DateRange(
       start: DateTime.fromMillisecondsSinceEpoch(0),
       end: DateTime.fromMillisecondsSinceEpoch(80000),
health_data_store/test/src/repositories/medicine_intake_repository_test.dart
@@ -82,19 +82,18 @@ void main() {
     ));
     expect(values2, isEmpty);
   });
-  test('should remove correct intake when multiple are at same time', () async {
+  test('overrides when inserting multiple intakes are at same time', () async {
     final db = await mockDBManager();
     addTearDown(db.close);
     final repo = MedicineIntakeRepositoryImpl(db.db);
     final medRepo = MedicineRepositoryImpl(db.db);
     final med = mockMedicine();
     await medRepo.add(med);
-    final i1 = mockIntake(med, time: 10000);
+    final i1 = mockIntake(med, time: 10000, dosis: 123);
     final i2 = mockIntake(med, time: 10000, dosis: 458);
     await repo.add(i1);
     await repo.add(i2);
 
-    await repo.remove(i1);
     final values2 = await repo.get(DateRange(
       start: DateTime.fromMillisecondsSinceEpoch(0),
       end: DateTime.fromMillisecondsSinceEpoch(80000),
health_data_store/test/src/repositories/note_repository_test.dart
@@ -78,7 +78,6 @@ void main() {
     ));
     expect(values, isEmpty);
   });
-
   test('should emit stream events on changes', () async {
     final db = await mockDBManager();
     addTearDown(db.close);
health_data_store/test/src/database_helper_test.dart
@@ -14,9 +14,9 @@ void main() {
     ));
     addTearDown(db.close);
     await db.db.transaction((txn) async {
-      final entry1 = await DBHelper.getEntryID(txn, 123, []);
+      final entry1 = await DBHelper.getEntryID(txn, 123);
       expect(entry1, 1);
-      final entry2 = await DBHelper.getEntryID(txn, 124, []);
+      final entry2 = await DBHelper.getEntryID(txn, 124);
       expect(entry2, 2);
     });
   });
@@ -26,38 +26,10 @@ void main() {
     ));
     addTearDown(db.close);
     await db.db.transaction((txn) async {
-      final entry1 = await DBHelper.getEntryID(txn, 123, []);
+      final entry1 = await DBHelper.getEntryID(txn, 123);
       expect(entry1, 1);
-      final entry1Again = await DBHelper.getEntryID(txn, 123, []);
+      final entry1Again = await DBHelper.getEntryID(txn, 123);
       expect(entry1Again, 1);
     });
   });
-  test('should find existing entryID with constraints', () async {
-    final db = await DatabaseManager.load(await openDatabase(
-      inMemoryDatabasePath,
-    ));
-    addTearDown(db.close);
-    await db.db.transaction((txn) async {
-      final entry1 = await DBHelper.getEntryID(txn, 123, []);
-      expect(entry1, 1);
-      final entry1Again = await DBHelper.getEntryID(txn, 123, ['Systolic']);
-      expect(entry1Again, 1);
-    });
-  });
-  test('should find respect constraints when finding entryID', () async {
-    final db = await DatabaseManager.load(await openDatabase(
-      inMemoryDatabasePath,
-    ));
-    addTearDown(db.close);
-    await db.db.transaction((txn) async {
-      final entry1 = await DBHelper.getEntryID(txn, 123, []);
-      expect(entry1, 1);
-      await txn.insert('Systolic', {
-        'entryID': entry1,
-        'sys': 1,
-      });
-      final anotherEntry = await DBHelper.getEntryID(txn, 123, ['Systolic']);
-      expect(anotherEntry, 2);
-    });
-  });
 }