Commit 942b096
Changed files (3)
health_data_store
lib
src
repositories
test
src
repositories
types
health_data_store/lib/src/repositories/note_repository.dart
@@ -0,0 +1,78 @@
+
+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';
+import 'package:health_data_store/src/repositories/repository.dart';
+import 'package:health_data_store/src/types/date_range.dart';
+import 'package:health_data_store/src/types/note.dart';
+import 'package:sqflite_common/sqflite.dart';
+
+/// Repository for accessing [Note]s stored in a [DatabaseManager] managed db.
+class NoteRepository extends Repository<Note> {
+ /// Create a repository for notes.
+ NoteRepository(this._db);
+
+ /// The [DatabaseManager] managed database.
+ final Database _db;
+
+ @override
+ Future<void> add(Note note) async {
+ if (note.note == null && note.color == null) {
+ assert(false);
+ return;
+ }
+ await _db.transaction((txn) async {
+ final id = await DBHelper.getEntryID(
+ txn, note.time.secondsSinceEpoch,
+ ['Notes'],
+ );
+ await txn.insert('Notes', {
+ 'entryID': id,
+ if (note.note != null)
+ 'note': note.note,
+ if (note.color != null)
+ 'color': note.color,
+ });
+ });
+ }
+
+ @override
+ Future<List<Note>> get(DateRange range) async {
+ final result = await _db.rawQuery(
+ 'SELECT t.timestampUnixS AS time, note, color '
+ 'FROM Timestamps AS t '
+ 'JOIN Notes AS n ON t.entryID = n.entryID '
+ 'WHERE t.timestampUnixS BETWEEN ? AND ?'
+ 'AND (n.note IS NOT NULL OR n.color IS NOT NULL)', [
+ range.startStamp,
+ range.endStamp,
+ ]
+ );
+ final notes = <Note>[];
+ for (final row in result) {
+ notes.add(Note(
+ time: DateTimeS.fromSecondsSinceEpoch(row['time'] as int),
+ note: row['note'] as String?,
+ color: row['color'] as int?,
+ ));
+ }
+ return notes;
+ }
+
+ @override
+ Future<void> remove(Note value) => _db.rawDelete(
+ 'DELETE FROM Notes WHERE entryID IN ('
+ 'SELECT entryID FROM Timestamps '
+ 'WHERE timestampUnixS = ?'
+ ') AND note '
+ + ((value.note == null) ? 'IS NULL' : '= ?')
+ + ' AND color '
+ + ((value.color == null) ? 'IS NULL' : '= ?'), [
+ value.time.secondsSinceEpoch,
+ if (value.note != null)
+ value.note,
+ if (value.color != null)
+ value.color,
+ ]);
+
+}
health_data_store/test/src/repositories/note_repository_test.dart
@@ -0,0 +1,78 @@
+import 'package:health_data_store/health_data_store.dart';
+import 'package:health_data_store/src/repositories/note_repository.dart';
+import 'package:test/test.dart';
+
+import '../database_manager_test.dart';
+import '../types/blood_pressure_record_test.dart';
+import '../types/note_test.dart';
+
+void main() {
+ sqfliteTestInit();
+ test('should initialize', () async {
+ final db = await mockDBManager();
+ addTearDown(db.close);
+ NoteRepository(db.db);
+ });
+ test('should store notes', () async {
+ final db = await mockDBManager();
+ addTearDown(db.close);
+ final repo = NoteRepository(db.db);
+ await repo.add(mockNote(color: 0x00FF00));
+ await repo.add(mockNote(note: 'test'));
+ expect(() async => repo.add(mockNote()), throwsA(isA<AssertionError>()));
+ });
+ test('should return stored notes', () async {
+ final db = await mockDBManager();
+ addTearDown(db.close);
+ final repo = NoteRepository(db.db);
+ final note1 = mockNote(time: 100000, color: 0x00FF00);
+ await repo.add(note1);
+ final note2 = mockNote(time: 700000, note: 'test');
+ await repo.add(note2);
+ final note3 = mockNote(time: 530000, note: 'test2');
+ await repo.add(note3);
+
+ final values = await repo.get(DateRange(
+ start: DateTime.fromMillisecondsSinceEpoch(100000),
+ end: DateTime.fromMillisecondsSinceEpoch(800000),
+ ));
+
+ expect(values, hasLength(3));
+ expect(values, containsAll([note1, note2, note3]));
+ });
+ test('should remove notes', () async {
+ final db = await mockDBManager();
+ addTearDown(db.close);
+ final repo = NoteRepository(db.db);
+ final note1 = mockNote(time: 100000, color: 0x00FF00);
+ await repo.add(note1);
+ final note2 = mockNote(time: 700000, note: 'test');
+ await repo.add(note2);
+ final note3 = mockNote(time: 530000, note: 'test2');
+ await repo.add(note3);
+
+ await repo.remove(note1);
+ await repo.remove(note3);
+ await repo.remove(mockNote());
+
+ final values = await repo.get(DateRange(
+ start: DateTime.fromMillisecondsSinceEpoch(100000),
+ end: DateTime.fromMillisecondsSinceEpoch(800000),
+ ));
+ expect(values, hasLength(1));
+ expect(values, contains(note2));
+ });
+ test('should not return notes when only other data is present', () async {
+ final db = await mockDBManager();
+ addTearDown(db.close);
+ final bpRepo = BloodPressureRepository(db.db);
+ final r1 = mockRecord(time: 200000, sys: 456, dia: 457, pul: 458);
+ await bpRepo.add(r1);
+ final repo = NoteRepository(db.db);
+ final values = await repo.get(DateRange(
+ start: DateTime.fromMillisecondsSinceEpoch(100000),
+ end: DateTime.fromMillisecondsSinceEpoch(800000),
+ ));
+ expect(values, isEmpty);
+ });
+}
health_data_store/test/src/types/note_test.dart
@@ -19,3 +19,13 @@ void main() {
)));
});
}
+
+Note mockNote({
+ int? time,
+ String? note,
+ int? color,
+}) => Note(
+ time: time!=null ? DateTime.fromMillisecondsSinceEpoch(time) : DateTime.now(),
+ note: note,
+ color: color,
+);