Commit 1ed6020
Changed files (7)
health_data_store
health_data_store/lib/src/repositories/blood_pressure_repository_impl.dart
@@ -1,3 +1,5 @@
+import 'dart:async';
+
import 'package:health_data_store/src/database_helper.dart';
import 'package:health_data_store/src/database_manager.dart';
import 'package:health_data_store/src/extensions/datetime_seconds.dart';
@@ -15,11 +17,14 @@ class BloodPressureRepositoryImpl extends BloodPressureRepository {
/// Create [BloodPressureRecord] repository.
BloodPressureRepositoryImpl(this._db);
+ final _controller = StreamController.broadcast(); // TODO: test all streams
+
/// The [DatabaseManager] managed database
final Database _db;
@override
Future<void> add(BloodPressureRecord record) async{
+ _controller.add(null);
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.');
@@ -81,6 +86,7 @@ class BloodPressureRepositoryImpl extends BloodPressureRepository {
@override
Future<void> remove(BloodPressureRecord value) => _db.transaction((txn) async{
+ _controller.add(null);
String query = 'SELECT t.entryID FROM Timestamps AS t ';
if (value.sys != null)
query += 'LEFT JOIN Systolic AS s ON t.entryID = s.entryID ';
@@ -120,4 +126,7 @@ class BloodPressureRepositoryImpl extends BloodPressureRepository {
return Pressure.kPa(value);
}
+ @override
+ Stream subscribe() => _controller.stream;
+
}
health_data_store/lib/src/repositories/medicine_intake_repository_impl.dart
@@ -1,3 +1,5 @@
+import 'dart:async';
+
import 'package:health_data_store/src/database_helper.dart';
import 'package:health_data_store/src/database_manager.dart';
import 'package:health_data_store/src/extensions/datetime_seconds.dart';
@@ -16,11 +18,14 @@ class MedicineIntakeRepositoryImpl extends MedicineIntakeRepository {
/// Create a repository for medicine intakes.
MedicineIntakeRepositoryImpl(this._db);
+ final _controller = StreamController.broadcast();
+
/// The [DatabaseManager] managed database.
final Database _db;
@override
Future<void> add(MedicineIntake intake) => _db.transaction((txn) async {
+ _controller.add(null);
// obtain medicine id
final medIDRes = await txn.query('Medicine',
columns: ['medID'],
@@ -82,33 +87,39 @@ class MedicineIntakeRepositoryImpl extends MedicineIntakeRepository {
}
@override
- Future<void> remove(MedicineIntake intake) => _db.rawDelete(
- 'DELETE FROM Intake WHERE entryID IN ('
- 'SELECT entryID FROM Timestamps '
- 'WHERE timestampUnixS = ?'
- ') AND dosis = ? '
- 'AND medID IN ('
- 'SELECT medID FROM Medicine '
- 'WHERE designation = ?'
- 'AND color '
- + ((intake.medicine.color != null) ? '= ?' : 'IS NULL') +
- ' AND defaultDose '
- + ((intake.medicine.dosis != null) ? '= ?' : 'IS NULL') +
- ')',
- [
- intake.time.secondsSinceEpoch,
- intake.dosis.mg,
- intake.medicine.designation,
- if (intake.medicine.color != null)
- intake.medicine.color,
- if (intake.medicine.dosis != null)
- intake.medicine.dosis?.mg,
- ]
- );
+ Future<void> remove(MedicineIntake intake) {
+ _controller.add(null);
+ return _db.rawDelete(
+ 'DELETE FROM Intake WHERE entryID IN ('
+ 'SELECT entryID FROM Timestamps '
+ 'WHERE timestampUnixS = ?'
+ ') AND dosis = ? '
+ 'AND medID IN ('
+ 'SELECT medID FROM Medicine '
+ 'WHERE designation = ?'
+ 'AND color '
+ + ((intake.medicine.color != null) ? '= ?' : 'IS NULL') +
+ ' AND defaultDose '
+ + ((intake.medicine.dosis != null) ? '= ?' : 'IS NULL') +
+ ')',
+ [
+ intake.time.secondsSinceEpoch,
+ intake.dosis.mg,
+ intake.medicine.designation,
+ if (intake.medicine.color != null)
+ intake.medicine.color,
+ if (intake.medicine.dosis != null)
+ intake.medicine.dosis?.mg,
+ ]
+ );
+ }
Weight? _decode(Object? value) {
if (value is! double) return null;
return Weight.mg(value);
}
+ @override
+ Stream subscribe() => _controller.stream;
+
}
health_data_store/lib/src/repositories/note_repository_impl.dart
@@ -1,3 +1,5 @@
+import 'dart:async';
+
import 'package:health_data_store/src/database_helper.dart';
import 'package:health_data_store/src/database_manager.dart';
import 'package:health_data_store/src/extensions/datetime_seconds.dart';
@@ -12,11 +14,14 @@ class NoteRepositoryImpl extends NoteRepository {
/// Create a repository for notes.
NoteRepositoryImpl(this._db);
+ final _controller = StreamController.broadcast();
+
/// The [DatabaseManager] managed database.
final Database _db;
@override
Future<void> add(Note note) async {
+ _controller.add(null);
if (note.note == null && note.color == null) {
assert(false);
return;
@@ -60,7 +65,9 @@ class NoteRepositoryImpl extends NoteRepository {
}
@override
- Future<void> remove(Note value) => _db.rawDelete(
+ Future<void> remove(Note value) {
+ _controller.add(null);
+ return _db.rawDelete(
'DELETE FROM Notes WHERE entryID IN ('
'SELECT entryID FROM Timestamps '
'WHERE timestampUnixS = ?'
@@ -74,5 +81,8 @@ class NoteRepositoryImpl extends NoteRepository {
if (value.color != null)
value.color,
]);
+ }
+ @override
+ Stream subscribe() => _controller.stream;
}
health_data_store/lib/src/repositories/repository.dart
@@ -1,3 +1,5 @@
+import 'dart:async';
+
import 'package:health_data_store/src/database_manager.dart';
import 'package:health_data_store/src/types/date_range.dart';
@@ -20,4 +22,7 @@ abstract class Repository<T> {
/// Inclusively returns all values in the specified [range].
Future<List<T>> get(DateRange range);
+
+ /// Stream that emits events everytime the data changes.
+ Stream subscribe();
}
health_data_store/test/src/repositories/blood_pressure_repository_test.dart
@@ -1,3 +1,5 @@
+import 'dart:async';
+
import 'package:health_data_store/src/repositories/blood_pressure_repository_impl.dart';
import 'package:health_data_store/src/types/date_range.dart';
import 'package:test/test.dart';
@@ -144,4 +146,23 @@ void main() {
));
expect(values, isEmpty);
});
+ test('should emit stream events on changes', () async {
+ final db = await mockDBManager();
+ addTearDown(db.close);
+
+ int notifyCount = 0;
+
+ final repo = BloodPressureRepositoryImpl(db.db);
+ unawaited(repo.subscribe().forEach((_) => notifyCount++));
+ final r = mockRecord(time: 10000, sys: 456, dia: 457, pul: 458);
+ expect(notifyCount, 0);
+ await repo.add(r);
+ expect(notifyCount, 1);
+ await repo.add(mockRecord(time: 20000, sys: 123));
+ expect(notifyCount, 2);
+ await repo.add(mockRecord(time: 30000, sys: 788, pul: 789));
+ expect(notifyCount, 3);
+ await repo.remove(r);
+ expect(notifyCount, 4);
+ });
}
health_data_store/test/src/repositories/medicine_intake_repository_test.dart
@@ -1,3 +1,5 @@
+import 'dart:async';
+
import 'package:health_data_store/src/repositories/medicine_intake_repository_impl.dart';
import 'package:health_data_store/src/repositories/medicine_repository_impl.dart';
import 'package:health_data_store/src/types/date_range.dart';
@@ -116,4 +118,24 @@ void main() {
));
expect(values, isEmpty);
});
+ test('should emit stream events on changes', () async {
+ final db = await mockDBManager();
+ addTearDown(db.close);
+ final medRepo = MedicineRepositoryImpl(db.db);
+ final med = mockMedicine();
+ await medRepo.add(med);
+
+ int notifyCount = 0;
+
+ final repo = MedicineIntakeRepositoryImpl(db.db);
+ unawaited(repo.subscribe().forEach((_) => notifyCount++));
+ final i = mockIntake(med);
+ expect(notifyCount, 0);
+ await repo.add(i);
+ expect(notifyCount, 1);
+ await repo.add(mockIntake(med, dosis: 12345));
+ expect(notifyCount, 2);
+ await repo.remove(i);
+ expect(notifyCount, 3);
+ });
}
health_data_store/test/src/repositories/note_repository_test.dart
@@ -1,3 +1,4 @@
+import 'dart:async';
import 'package:health_data_store/src/repositories/blood_pressure_repository_impl.dart';
import 'package:health_data_store/src/repositories/note_repository_impl.dart';
@@ -77,4 +78,22 @@ void main() {
));
expect(values, isEmpty);
});
+
+ test('should emit stream events on changes', () async {
+ final db = await mockDBManager();
+ addTearDown(db.close);
+
+ int notifyCount = 0;
+
+ final repo = NoteRepositoryImpl(db.db);
+ unawaited(repo.subscribe().forEach((_) => notifyCount++));
+ final n = mockNote(time: 1000, note: 'asd');
+ expect(notifyCount, 0);
+ await repo.add(n);
+ expect(notifyCount, 1);
+ await repo.add(mockNote(time: 50000, color: 0x00FF00));
+ expect(notifyCount, 2);
+ await repo.remove(n);
+ expect(notifyCount, 3);
+ });
}