Commit f40c747

derdilla <82763757+NobodyForNothing@users.noreply.github.com>
2024-03-18 06:17:07
implement BloodPressureRepository add and get
Signed-off-by: derdilla <82763757+NobodyForNothing@users.noreply.github.com>
1 parent c2b1707
health_data_store/lib/src/repositories/blood_pressure_repository.dart
@@ -0,0 +1,86 @@
+import 'package:health_data_store/health_data_store.dart';
+import 'package:health_data_store/src/database_helper.dart';
+import 'package:health_data_store/src/database_manager.dart';
+import 'package:health_data_store/src/repositories/repository.dart';
+import 'package:sqflite_common/sqflite.dart';
+
+/// Repository for [BloodPressureRecord]s.
+/// 
+/// Provides high level access on [BloodPressureRecord]s saved in a 
+/// [DatabaseManager] managed database. Allows to store and query records.
+class BloodPressureRepository extends Repository<BloodPressureRecord> {
+  /// Create [BloodPressureRecord] repository.
+  BloodPressureRepository(this._db);
+
+  /// The [DatabaseManager] managed database
+  final Database _db;
+  
+  @override
+  Future<void> add(BloodPressureRecord record) async{
+    assert(record.sys != null || record.dia != null || record.pul != null,
+     "Adding records that don't contain values(sys,dia,pul) can't be accessed"
+     'and should therefore not be added to the repository.');
+    final timeSec = record.time.millisecondsSinceEpoch ~/ 1000;
+    await _db.transaction((txn) async {
+      final entryID = await DBHelper.getEntryID(
+        txn,
+        timeSec,
+        ['Systolic', 'Diastolic', 'Pulse'],
+      );
+      print(record);
+      if (record.sys != null) {
+        await txn.insert('Systolic', {
+          'entryID': entryID,
+          'sys': record.sys,
+        });
+      }
+      if (record.dia != null) {
+        await txn.insert('Diastolic', {
+          'entryID': entryID,
+          'dia': record.dia,
+        });
+      }
+      if (record.pul != null) {
+        await txn.insert('Pulse', {
+          'entryID': entryID,
+          'pul': record.pul,
+        });
+      }
+    });
+  }
+
+  @override
+  Future<List<BloodPressureRecord>> get(DateRange range) async {
+    final results = await _db.rawQuery(
+      'SELECT timestampUnixS, sys, dia, pul '
+        'FROM Timestamps AS t '
+        'LEFT JOIN Systolic AS s ON t.entryID = s.entryID '
+        'LEFT JOIN Diastolic AS d ON t.entryID = d.entryID '
+        'LEFT JOIN Pulse AS p ON t.entryID = p.entryID '
+        'WHERE timestampUnixS BETWEEN ? AND ?;',
+      [range.startStamp, range.endStamp]
+    );
+    final records = <BloodPressureRecord>[];
+    for (final r in results) {
+      final timeS = r['timestampUnixS'] as int;
+      final newRec = BloodPressureRecord(
+        time: DateTime.fromMillisecondsSinceEpoch(timeS * 1000),
+        sys: r['sys'] as int?,
+        dia: r['dia'] as int?,
+        pul: r['pul'] as int?,
+      );
+      if (newRec.sys !=null || newRec.dia != null || newRec.pul != null) {
+        records.add(newRec);
+      }
+    }
+
+    return records;
+  }
+
+  @override
+  Future<void> remove(BloodPressureRecord value) async {
+    // TODO: implement remove
+    throw UnimplementedError();
+  }
+
+}
health_data_store/lib/src/repositories/repository.dart
@@ -1,5 +1,3 @@
-import 'dart:collection';
-
 import 'package:health_data_store/src/database_manager.dart';
 import 'package:health_data_store/src/types/date_range.dart';
 
@@ -18,5 +16,5 @@ abstract class Repository<T> {
   Future<void> remove(T value);
 
   /// Inclusively returns all values in the specified [range].
-  Future<UnmodifiableListView<T>> get(DateRange range);
+  Future<List<T>> get(DateRange range);
 }
health_data_store/lib/src/database_helper.dart
@@ -42,7 +42,7 @@ class DBHelper {
     Transaction txn,
     int startUnixS,
     int endUnixS,
-  ) async {
+  ) async { // TODO: consider removing, once unused
     final result = await txn.query('Timestamps',
       columns: ['entryID'],
       where: 'timestampUnixS BETWEEN ? AND ?',
health_data_store/lib/src/database_manager.dart
@@ -50,10 +50,14 @@ class DatabaseManager {
       'FOREIGN KEY("entryID") REFERENCES "Timestamps"("entryID"),'
       'FOREIGN KEY("medID") REFERENCES "Medicine"("medID")'
     ');');
-    for (final intTable in ['Systolic', 'Diastolic', 'Pulse']) {
-      await _db.execute('CREATE TABLE "$intTable" ('
+    for (final info in [
+      ('Systolic','sys'),
+      ('Diastolic', 'dia'),
+      ('Pulse','pul')
+    ]) {
+      await _db.execute('CREATE TABLE "${info.$1}" ('
         '"entryID"	INTEGER NOT NULL,'
-        '"value"    INTEGER,'
+        '"${info.$2}"    INTEGER,'
         'FOREIGN KEY("entryID") REFERENCES "Timestamps"("entryID"),'
         'PRIMARY KEY("entryID")'
       ');');
health_data_store/test/src/repositories/blood_pressure_repository_test.dart
@@ -0,0 +1,43 @@
+
+import 'package:health_data_store/health_data_store.dart';
+import 'package:health_data_store/src/repositories/blood_pressure_repository.dart';
+import 'package:test/test.dart';
+
+import '../database_manager_test.dart';
+import '../types/blood_pressure_record_test.dart';
+
+void main() {
+  sqfliteTestInit();
+  test('should initialize', () async {
+    final db = await mockDBManager();
+    addTearDown(db.close);
+    BloodPressureRepository(db.db);
+  });
+  test('should store records without errors', () async {
+    final db = await mockDBManager();
+    addTearDown(db.close);
+    final repo = BloodPressureRepository(db.db);
+    await repo.add(mockRecord(sys: 123, dia: 456, pul: 789));
+    await repo.add(mockRecord(sys: 123, pul: 789));
+    await repo.add(mockRecord(sys: 123));
+    expect(() async => repo.add(mockRecord()), throwsA(isA<AssertionError>()));
+  });
+  test('should return stored records', () async {
+    final db = await mockDBManager();
+    addTearDown(db.close);
+    final repo = BloodPressureRepository(db.db);
+    final r1 = mockRecord(time: 50000, sys: 123);
+    final r2 = mockRecord(time: 80000, sys: 456, dia: 457, pul: 458);
+    final r3 = mockRecord(time: 20000, sys: 788, pul: 789);
+    await repo.add(r1);
+    await repo.add(r2);
+    await repo.add(r3);
+
+    final values = await repo.get(DateRange(
+      start: DateTime.fromMillisecondsSinceEpoch(20000),
+      end: DateTime.fromMillisecondsSinceEpoch(80000),
+    ));
+    expect(values, hasLength(3));
+    expect(values, containsAll([r1,r2,r3]));
+  });
+}
health_data_store/test/src/types/blood_pressure_record_test.dart
@@ -39,3 +39,15 @@ void main() {
     ))));
   });
 }
+
+BloodPressureRecord mockRecord({
+  int? time,
+  int? sys,
+  int? dia,
+  int? pul,
+}) => BloodPressureRecord(
+  time: time!=null ? DateTime.fromMillisecondsSinceEpoch(time) : DateTime.now(),
+  sys: sys,
+  dia: dia,
+  pul: pul,
+);
health_data_store/test/src/database_helper_test.dart
@@ -54,7 +54,7 @@ void main() {
       expect(entry1, 1);
       await txn.insert('Systolic', {
         'entryID': entry1,
-        'value': 1,
+        'sys': 1,
       });
       final anotherEntry = await DBHelper.getEntryID(txn, 123, ['Systolic']);
       expect(anotherEntry, 2);
health_data_store/test/src/database_manager_test.dart
@@ -14,24 +14,18 @@ void sqfliteTestInit() {
 void main() {
   sqfliteTestInit();
   test('should initialize without issues', () async {
-    final db = await DatabaseManager.load(await openDatabase(
-      inMemoryDatabasePath,
-    ));
+    final db = await mockDBManager();
     addTearDown(db.close);
     expect(db.db.isOpen, isTrue);
   });
   test('should close', () async {
-    final db = await DatabaseManager.load(await openDatabase(
-      inMemoryDatabasePath,
-    ));
+    final db = await mockDBManager();
     expect(db.db.isOpen, isTrue);
     await db.close();
     expect(db.db.isOpen, isFalse);
   });
   test('should setup medicine table', () async {
-    final db = await DatabaseManager.load(await openDatabase(
-      inMemoryDatabasePath,
-    ));
+    final db = await mockDBManager();
     addTearDown(db.close);
 
     final result = await db.db
@@ -93,9 +87,7 @@ void main() {
         throwsException);
   });
   test('should create timestamps table correctly', () async {
-    final db = await DatabaseManager.load(await openDatabase(
-      inMemoryDatabasePath,
-    ));
+    final db = await mockDBManager();
     addTearDown(db.close);
     await db.db.insert('Timestamps', {
       'entryID': 1,
@@ -115,9 +107,7 @@ void main() {
     }), throwsException);
   });
   test('should create intake table correctly', () async {
-    final db = await DatabaseManager.load(await openDatabase(
-      inMemoryDatabasePath,
-    ));
+    final db = await mockDBManager();
     addTearDown(db.close);
 
     await db.db.insert('Intake', {
@@ -130,28 +120,28 @@ void main() {
     expect(data.first.keys, hasLength(3));
   });
   test('should create timestamps sys,dia,pul tables correctly', () async {
-    final db = await DatabaseManager.load(await openDatabase(
-      inMemoryDatabasePath,
-    ));
+    final db = await mockDBManager();
     addTearDown(db.close);
-    for (final t in ['Systolic', 'Diastolic', 'Pulse']) {
-      await db.db.insert(t, {
+    for (final t in [
+      ('Systolic','sys'),
+      ('Diastolic', 'dia'),
+      ('Pulse','pul')
+    ]) {
+      await db.db.insert(t.$1, {
         'entryID': 1,
-        'value': 1,
+        t.$2: 1,
       });
-      await db.db.insert(t, {
+      await db.db.insert(t.$1, {
         'entryID': 2,
-        'value': null,
+        t.$2: null,
       });
-      final data = await db.db.query(t);
+      final data = await db.db.query(t.$1);
       expect(data, hasLength(2));
       expect(data.first.keys, hasLength(2));
     }
   });
   test('should create notes table correctly', () async {
-    final db = await DatabaseManager.load(await openDatabase(
-      inMemoryDatabasePath,
-    ));
+    final db = await mockDBManager();
     addTearDown(db.close);
 
     await db.db.insert('Notes', {
@@ -165,3 +155,6 @@ void main() {
     expect(data.first['color'], equals(0xFF990098));
   });
 }
+
+Future<DatabaseManager> mockDBManager() async => DatabaseManager.load(
+    await openDatabase(inMemoryDatabasePath));
health_data_store/test/src/health_data_store_test.dart
@@ -2,5 +2,6 @@
 
 
 void main() {
-
+ // TODO: implement
+ throw UnimplementedError('TODO');
 }