Commit 0d6a734

derdilla <derdilla06@gmail.com>
2023-06-01 18:07:52
create new class for analysis
1 parent 0b67187
lib/model/blood_pressure.dart
@@ -74,25 +74,6 @@ class BloodPressureModel extends ChangeNotifier {
     notifyListeners();
   }
 
-  /// Returns the last x BloodPressureRecords from new to old.
-  /// Caches new ones if necessary
-  Future<UnmodifiableListView<BloodPressureRecord>> getLastX(int count) async {
-    List<BloodPressureRecord> lastMeasurements = [];
-
-    var dbEntries = await _database.query('bloodPressureModel',
-        orderBy: 'timestamp DESC', limit: count); // de
-    for (var e in dbEntries) {
-      lastMeasurements.add(BloodPressureRecord(
-          DateTime.fromMillisecondsSinceEpoch(e['timestamp']as int),
-          e['systolic'] as int,
-          e['diastolic'] as int,
-          e['pulse'] as int,
-          e['notes'].toString()));
-
-    }
-    return UnmodifiableListView(lastMeasurements);
-  }
-
   /// Returns all recordings in saved in a range in ascending order
   Future<UnmodifiableListView<BloodPressureRecord>> getInTimeRange(DateTime from, DateTime to) async {
     var dbEntries = await _database.query('bloodPressureModel',
@@ -122,52 +103,25 @@ class BloodPressureModel extends ChangeNotifier {
   Future<int> get count async {
     return (await _database.rawQuery('SELECT COUNT(*) FROM bloodPressureModel'))[0]['COUNT(*)'] as int? ?? -1;
   }
-  Future<int> get measurementsPerDay async {
-    final c = await count;
-    if (c <= 1) {
-      return -1;
-    }
-    var firstDay = DateTime.fromMillisecondsSinceEpoch((await _database.rawQuery('SELECT timestamp FROM bloodPressureModel ORDER BY timestamp ASC LIMIT 1'))[0]['timestamp'] as int? ?? -1);
-    var lastDay = DateTime.fromMillisecondsSinceEpoch((await _database.rawQuery('SELECT timestamp FROM bloodPressureModel ORDER BY timestamp DESC LIMIT 1'))[0]['timestamp'] as int? ?? -1);
-
-    if (lastDay.difference(firstDay).inDays <= 0) {
-      return c;
-    }
-
-    return c ~/ lastDay.difference(firstDay).inDays;
 
+  Future<DateTime> get firstDay async {
+    return DateTime.fromMillisecondsSinceEpoch((await _database.rawQuery('SELECT timestamp FROM bloodPressureModel ORDER BY timestamp ASC LIMIT 1'))[0]['timestamp'] as int? ?? -1);
+  }
+  Future<DateTime> get lastDay async {
+    return DateTime.fromMillisecondsSinceEpoch((await _database.rawQuery('SELECT timestamp FROM bloodPressureModel ORDER BY timestamp DESC LIMIT 1'))[0]['timestamp'] as int? ?? -1);
   }
-
 
   Future<int> get avgDia async {
-    var res = (await _database.rawQuery('SELECT AVG(diastolic) as dia FROM bloodPressureModel'))[0]['dia'];
-    int? val;
-    try {
-      val = (res as int?);
-    } catch (e) {
-      val = (res as double?)?.toInt();
-    }
-    return val ?? -1;
+    var res = _toInt((await _database.rawQuery('SELECT AVG(diastolic) as dia FROM bloodPressureModel'))[0]['dia']);
+    return res ?? -1;
   }
   Future<int> get avgSys async {
-    var res = (await _database.rawQuery('SELECT AVG(systolic) as sys FROM bloodPressureModel'))[0]['sys'];
-    int? val;
-    try {
-      val = (res as int?);
-    } catch (e) {
-      val = (res as double?)?.toInt();
-    }
-    return val ?? -1;
+    var res = _toInt((await _database.rawQuery('SELECT AVG(systolic) as sys FROM bloodPressureModel'))[0]['sys']);
+    return res ?? -1;
   }
   Future<int> get avgPul async {
-    var res = (await _database.rawQuery('SELECT AVG(pulse) as pul FROM bloodPressureModel'))[0]['pul'];
-    int? val;
-    try {
-      val = (res as int?);
-    } catch (e) {
-      val = (res as double?)?.toInt();
-    }
-    return val ?? -1;
+    var res = _toInt((await _database.rawQuery('SELECT AVG(pulse) as pul FROM bloodPressureModel'))[0]['pul']);
+    return res ?? -1;
   }
 
   Future<int> get maxDia async {
@@ -196,44 +150,6 @@ class BloodPressureModel extends ChangeNotifier {
     return (res as int?) ?? -1;
   }
 
-  /// outer list is type (0 -> diastolic, 1 -> systolic, 2 -> pulse)
-  /// inner list index is hour of day ([0] -> 00:00-00:59; [1] -> ...)
-  Future<List<List<int>>> get allAvgsRelativeToDaytime async {
-    // setup vars
-    List<List<int>> allDiaValuesRelativeToTime = [[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]];
-    List<List<int>> allSysValuesRelativeToTime = [[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]];
-    List<List<int>> allPulValuesRelativeToTime = [[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]];
-
-    // sort all data
-    final dbRes = await _database.query('bloodPressureModel', columns: ['*']);
-    for (var entry in dbRes) {
-      DateTime ts = DateTime.fromMillisecondsSinceEpoch(entry['timestamp'] as int);
-      allDiaValuesRelativeToTime[ts.hour].add(entry['diastolic'] as int);
-      allSysValuesRelativeToTime[ts.hour].add(entry['systolic'] as int);
-      allPulValuesRelativeToTime[ts.hour].add(entry['pulse'] as int);
-    }
-    for(int i = 0; i < 24; i++) {
-      if (allDiaValuesRelativeToTime[i].isEmpty) {
-        allDiaValuesRelativeToTime[i].add(await avgDia);
-      }
-      if (allSysValuesRelativeToTime[i].isEmpty) {
-        allSysValuesRelativeToTime[i].add(await avgSys);
-      }
-      if (allPulValuesRelativeToTime[i].isEmpty) {
-        allPulValuesRelativeToTime[i].add(await avgPul);
-      }
-    }
-
-    // make avgs
-    List<List<int>> res = [[],[],[]];
-    for(int i = 0; i < 24; i++) {
-      res[0].add(allDiaValuesRelativeToTime[i].average.toInt());
-      res[1].add(allSysValuesRelativeToTime[i].average.toInt());
-      res[2].add(allPulValuesRelativeToTime[i].average.toInt());
-    }
-    return res;
-  }
-
   Future<void> save(void Function(bool success, String? msg) callback, {bool exportAsText = false}) async {
     // create csv
     String csvData = 'timestampUnixMs, systolic, diastolic, pulse, notes\n';
@@ -305,6 +221,14 @@ class BloodPressureModel extends ChangeNotifier {
   void close() {
     _database.close();
   }
+
+  int? _toInt(Object? v) {
+    try {
+      return (v as int?);
+    } catch (e) {
+      return (v as double?)?.toInt();
+    }
+  }
 }
 
 @immutable
lib/model/blood_pressure_analyzer.dart
@@ -0,0 +1,62 @@
+import 'package:blood_pressure_app/model/blood_pressure.dart';
+
+class BloodPressureAnalyser {
+  final BloodPressureModel _model;
+  
+  BloodPressureAnalyser(this._model);
+  
+  Future<int> get measurementsPerDay async {
+    final c = await _model.count;
+    final firstDay = await _model.firstDay;
+    final lastDay = await _model.lastDay;
+
+    if (c <= 1 || firstDay.millisecondsSinceEpoch == -1 ||
+        lastDay.millisecondsSinceEpoch == -1) {
+      return -1;
+    }
+    if (lastDay.difference(firstDay).inDays <= 0) {
+      return c;
+    }
+
+    return c ~/ lastDay.difference(firstDay).inDays;
+  }
+
+
+  /// outer list is type (0 -> diastolic, 1 -> systolic, 2 -> pulse)
+  /// inner list index is hour of day ([0] -> 00:00-00:59; [1] -> ...)
+  Future<List<List<int>>> get allAvgsRelativeToDaytime async {
+    // setup vars
+    List<List<int>> allDiaValuesRelativeToTime = [[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]];
+    List<List<int>> allSysValuesRelativeToTime = [[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]];
+    List<List<int>> allPulValuesRelativeToTime = [[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]];
+
+    // sort all data
+    final dbRes = await _database.query('bloodPressureModel', columns: ['*']);
+    for (var entry in dbRes) {
+      DateTime ts = DateTime.fromMillisecondsSinceEpoch(entry['timestamp'] as int);
+      allDiaValuesRelativeToTime[ts.hour].add(entry['diastolic'] as int);
+      allSysValuesRelativeToTime[ts.hour].add(entry['systolic'] as int);
+      allPulValuesRelativeToTime[ts.hour].add(entry['pulse'] as int);
+    }
+    for(int i = 0; i < 24; i++) {
+      if (allDiaValuesRelativeToTime[i].isEmpty) {
+        allDiaValuesRelativeToTime[i].add(await avgDia);
+      }
+      if (allSysValuesRelativeToTime[i].isEmpty) {
+        allSysValuesRelativeToTime[i].add(await avgSys);
+      }
+      if (allPulValuesRelativeToTime[i].isEmpty) {
+        allPulValuesRelativeToTime[i].add(await avgPul);
+      }
+    }
+
+    // make avgs
+    List<List<int>> res = [[],[],[]];
+    for(int i = 0; i < 24; i++) {
+      res[0].add(allDiaValuesRelativeToTime[i].average.toInt());
+      res[1].add(allSysValuesRelativeToTime[i].average.toInt());
+      res[2].add(allPulValuesRelativeToTime[i].average.toInt());
+    }
+    return res;
+  }
+}
\ No newline at end of file
test/model/bood_pressure_test.dart
@@ -31,7 +31,6 @@ void main() {
     test('should start empty', () async {
       var m = await BloodPressureModel.create(dbPath: '/tmp/bp_test/should_start_empty');
 
-      expect((await m.getLastX(100)).length, 0);
       expect((await m.getInTimeRange(DateTime.fromMillisecondsSinceEpoch(0), DateTime.now())).length, 0);
 
     });
@@ -56,7 +55,7 @@ void main() {
 
       var r = BloodPressureRecord(DateTime.fromMillisecondsSinceEpoch(31415926), -172, 10000, 0, "((V⍳V)=⍳⍴V)/V←,V    ⌷←⍳→⍴∆∇⊃‾⍎⍕⌈๏ แผ่นดินฮั่นเABCDEFGHIJKLMNOPQRSTUVWXYZ /0123456789abcdefghijklmnopqrstuvwxyz £©µÀÆÖÞßéöÿ–—‘“”„†•…‰™œŠŸž€ ΑΒΓΔΩαβγδω АБВГДабвг, \n \t д∀∂∈ℝ∧∪≡∞ ↑↗↨↻⇣ ┐┼╔╘░►☺♀ fi�⑀₂ἠḂӥẄɐː⍎אԱა");
       m.addListener(() async {
-        var res = (await m.getLastX(1)).first;
+        var res = (await m.getInTimeRange(DateTime.fromMillisecondsSinceEpoch(0), DateTime.now())).first;
         expect(res, isNotNull);
         expect(res.creationTime, r.creationTime);
         expect(res.systolic, r.systolic);
@@ -75,7 +74,7 @@ void main() {
       await m.add(r);
 
       var m2 = await BloodPressureModel.create(dbPath: '/tmp/bp_test/should_store_between_sessions');
-      var res = (await m2.getLastX(1)).first;
+      var res = (await m.getInTimeRange(DateTime.fromMillisecondsSinceEpoch(0), DateTime.now())).first;
 
       expect(res.creationTime, r.creationTime);
       expect(res.systolic, r.systolic);
@@ -98,12 +97,12 @@ void main() {
       var m = await BloodPressureModel.create(dbPath: '/tmp/bp_test/should_delete');
 
       await m.add(BloodPressureRecord(DateTime.fromMillisecondsSinceEpoch(758934), 123, 87, 65, ';)'));
-      expect((await m.getLastX(100)).length, 1);
+      expect((await m.getInTimeRange(DateTime.fromMillisecondsSinceEpoch(0), DateTime.now())).length, 1);
       expect((await m.getInTimeRange(DateTime.fromMillisecondsSinceEpoch(0), DateTime.now())).length, 1);
 
       await m.delete(DateTime.fromMillisecondsSinceEpoch(758934));
 
-      expect((await m.getLastX(100)).length, 0);
+      expect((await m.getInTimeRange(DateTime.fromMillisecondsSinceEpoch(0), DateTime.now())).length, 0);
       expect((await m.getInTimeRange(DateTime.fromMillisecondsSinceEpoch(0), DateTime.now())).length, 0);
 
     });