Commit e6e07af
Changed files (38)
health_data_store
lib
src
extensions
repositories
types
test
src
repositories
types
health_data_store/lib/src/extensions/datetime_seconds.dart
@@ -4,6 +4,6 @@ extension DateTimeS on DateTime {
int get secondsSinceEpoch => millisecondsSinceEpoch ~/ 1000;
/// Constructs a new DateTime instance with the given [secondsSinceEpoch].
- static DateTime fromSecondsSinceEpoch(int secondsSinceEpoch)
- => DateTime.fromMillisecondsSinceEpoch(secondsSinceEpoch * 1000);
+ static DateTime fromSecondsSinceEpoch(int secondsSinceEpoch) =>
+ DateTime.fromMillisecondsSinceEpoch(secondsSinceEpoch * 1000);
}
health_data_store/lib/src/repositories/blood_pressure_repository.dart
@@ -3,7 +3,8 @@ import 'package:health_data_store/src/repositories/repository.dart';
import 'package:health_data_store/src/types/blood_pressure_record.dart';
/// Repository for [BloodPressureRecord]s.
-///
-/// Provides high level access on [BloodPressureRecord]s saved in a
+///
+/// Provides high level access on [BloodPressureRecord]s saved in a
/// [DatabaseManager] managed database. Allows to store and query records.
-abstract class BloodPressureRepository extends Repository<BloodPressureRecord>{}
+abstract class BloodPressureRepository
+ extends Repository<BloodPressureRecord> {}
health_data_store/lib/src/repositories/blood_pressure_repository_impl.dart
@@ -10,8 +10,8 @@ import 'package:health_data_store/src/types/units/pressure.dart';
import 'package:sqflite_common/sqflite.dart';
/// Implementation of repository for [BloodPressureRecord]s.
-///
-/// Provides high level access on [BloodPressureRecord]s saved in a
+///
+/// Provides high level access on [BloodPressureRecord]s saved in a
/// [DatabaseManager] managed database. Allows to store and query records.
class BloodPressureRepositoryImpl extends BloodPressureRepository {
/// Create [BloodPressureRecord] repository.
@@ -21,13 +21,14 @@ class BloodPressureRepositoryImpl extends BloodPressureRepository {
/// The [DatabaseManager] managed database
final Database _db;
-
+
@override
- Future<void> add(BloodPressureRecord record) async{
+ 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.');
+ 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.secondsSinceEpoch;
await _db.transaction((txn) async {
final entryID = await DBHelper.getEntryID(
@@ -35,7 +36,9 @@ class BloodPressureRepositoryImpl extends BloodPressureRepository {
timeSec,
);
if (record.sys != null) {
- await txn.delete('Systolic', where: 'entryID = ?',
+ await txn.delete(
+ 'Systolic',
+ where: 'entryID = ?',
whereArgs: [entryID],
);
await txn.insert('Systolic', {
@@ -44,7 +47,9 @@ class BloodPressureRepositoryImpl extends BloodPressureRepository {
});
}
if (record.dia != null) {
- await txn.delete('Diastolic', where: 'entryID = ?',
+ await txn.delete(
+ 'Diastolic',
+ where: 'entryID = ?',
whereArgs: [entryID],
);
await txn.insert('Diastolic', {
@@ -53,7 +58,9 @@ class BloodPressureRepositoryImpl extends BloodPressureRepository {
});
}
if (record.pul != null) {
- await txn.delete('Pulse', where: 'entryID = ?',
+ await txn.delete(
+ 'Pulse',
+ where: 'entryID = ?',
whereArgs: [entryID],
);
await txn.insert('Pulse', {
@@ -67,14 +74,13 @@ class BloodPressureRepositoryImpl extends BloodPressureRepository {
@override
Future<List<BloodPressureRecord>> get(DateRange range) async {
final results = await _db.rawQuery(
- 'SELECT timestampUnixS, sys, dia, pul '
+ '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]
- );
+ 'WHERE timestampUnixS BETWEEN ? AND ?',
+ [range.startStamp, range.endStamp]);
final records = <BloodPressureRecord>[];
for (final r in results) {
final timeS = r['timestampUnixS'] as int;
@@ -84,7 +90,7 @@ class BloodPressureRepositoryImpl extends BloodPressureRepository {
dia: _decodePressure(r['dia']),
pul: _decodeInt(r['pul']),
);
- if (newRec.sys !=null || newRec.dia != null || newRec.pul != null) {
+ if (newRec.sys != null || newRec.dia != null || newRec.pul != null) {
records.add(newRec);
}
}
@@ -93,41 +99,38 @@ 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 ';
- if (value.dia != null)
- query += 'LEFT JOIN Diastolic AS d ON t.entryID = d.entryID ';
- if (value.pul != null)
- query += 'LEFT JOIN Pulse AS p ON t.entryID = p.entryID ';
- query += 'WHERE timestampUnixS = ? ';
- if (value.sys != null)
- query += 'AND sys = ? ';
- if (value.dia != null)
- query += 'AND dia = ? ';
- if (value.pul != null)
- query += 'AND pul = ? ';
+ 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 ';
+ if (value.dia != null)
+ query += 'LEFT JOIN Diastolic AS d ON t.entryID = d.entryID ';
+ if (value.pul != null)
+ query += 'LEFT JOIN Pulse AS p ON t.entryID = p.entryID ';
+ query += 'WHERE timestampUnixS = ? ';
+ if (value.sys != null) query += 'AND sys = ? ';
+ if (value.dia != null) query += 'AND dia = ? ';
+ if (value.pul != null) query += 'AND pul = ? ';
- final entryResult = await txn.rawQuery(query, [
- value.time.secondsSinceEpoch,
- if (value.sys != null)
- value.sys!.kPa,
- if (value.dia != null)
- value.dia!.kPa,
- if (value.pul != null)
- value.pul,
- ]);
- if (entryResult.isEmpty) return;
- final entryID = entryResult.first['entryID'];
- if (value.sys != null)
- await txn.delete('Systolic', where: 'entryID = ?', whereArgs:[entryID]);
- if (value.dia != null)
- await txn.delete('Diastolic', where:'entryID = ?', whereArgs:[entryID]);
- if (value.pul != null)
- await txn.delete('Pulse', where: 'entryID = ?', whereArgs: [entryID]);
- });
+ final entryResult = await txn.rawQuery(query, [
+ value.time.secondsSinceEpoch,
+ if (value.sys != null) value.sys!.kPa,
+ if (value.dia != null) value.dia!.kPa,
+ if (value.pul != null) value.pul,
+ ]);
+ if (entryResult.isEmpty) return;
+ final entryID = entryResult.first['entryID'];
+ if (value.sys != null)
+ await txn
+ .delete('Systolic', where: 'entryID = ?', whereArgs: [entryID]);
+ if (value.dia != null)
+ await txn
+ .delete('Diastolic', where: 'entryID = ?', whereArgs: [entryID]);
+ if (value.pul != null)
+ await txn.delete('Pulse', where: 'entryID = ?', whereArgs: [entryID]);
+ });
Pressure? _decodePressure(Object? value) {
if (value is! double) return null;
@@ -143,5 +146,4 @@ class BloodPressureRepositoryImpl extends BloodPressureRepository {
@override
Stream subscribe() => _controller.stream;
-
}
health_data_store/lib/src/repositories/bodyweight_repository_impl.dart
@@ -15,7 +15,7 @@ class BodyweightRepositoryImpl extends BodyweightRepository {
/// The [DatabaseManager] managed database.
final Database _db;
-
+
@override
Future<void> add(BodyweightRecord record) async {
_controller.add(null);
@@ -24,7 +24,9 @@ class BodyweightRepositoryImpl extends BodyweightRepository {
txn,
record.time.secondsSinceEpoch,
);
- await txn.delete('Weight', where: 'entryID = ?',
+ await txn.delete(
+ 'Weight',
+ where: 'entryID = ?',
whereArgs: [entryID],
);
await txn.insert('Weight', {
@@ -37,18 +39,16 @@ class BodyweightRepositoryImpl extends BodyweightRepository {
@override
Future<List<BodyweightRecord>> get(DateRange range) async {
final results = await _db.rawQuery(
- 'SELECT timestampUnixS, weightKg '
+ 'SELECT timestampUnixS, weightKg '
'FROM Timestamps AS t '
'INNER JOIN Weight AS w ON t.entryID = w.entryID '
- 'WHERE timestampUnixS BETWEEN ? AND ?',
- [range.startStamp, range.endStamp]
- );
+ 'WHERE timestampUnixS BETWEEN ? AND ?',
+ [range.startStamp, range.endStamp]);
return <BodyweightRecord>[
for (final r in results)
BodyweightRecord(
- time: DateTimeS.fromSecondsSinceEpoch(r['timestampUnixS'] as int),
- weight: Weight.kg(r['weightKg'] as double)
- ),
+ time: DateTimeS.fromSecondsSinceEpoch(r['timestampUnixS'] as int),
+ weight: Weight.kg(r['weightKg'] as double)),
];
}
@@ -57,8 +57,8 @@ class BodyweightRepositoryImpl extends BodyweightRepository {
_controller.add(null);
await _db.rawDelete(
'DELETE FROM Weight WHERE entryID IN ('
- 'SELECT entryID FROM Timestamps '
- 'WHERE timestampUnixS = ?'
+ 'SELECT entryID FROM Timestamps '
+ 'WHERE timestampUnixS = ?'
') AND weightKg = ?',
[
record.time.secondsSinceEpoch,
@@ -69,5 +69,4 @@ class BodyweightRepositoryImpl extends BodyweightRepository {
@override
Stream subscribe() => _controller.stream;
-
}
health_data_store/lib/src/repositories/medicine_intake_repository_impl.dart
@@ -25,49 +25,52 @@ class MedicineIntakeRepositoryImpl extends MedicineIntakeRepository {
@override
Future<void> add(MedicineIntake intake) => _db.transaction((txn) async {
- _controller.add(null);
- // obtain medicine id
- 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 '
- 'NULL'),
- whereArgs: [
- intake.medicine.designation,
- if (intake.medicine.color != null)
- intake.medicine.color,
- if (intake.medicine.dosis != null)
- intake.medicine.dosis!.mg,
- ],
- );
- assert(medIDRes.isNotEmpty);
- // Assuming intakes only contain medications that have been added
- final medID = medIDRes.first['medID'];
+ _controller.add(null);
+ // obtain medicine id
+ 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 '
+ 'NULL'),
+ whereArgs: [
+ intake.medicine.designation,
+ if (intake.medicine.color != null) intake.medicine.color,
+ if (intake.medicine.dosis != null) intake.medicine.dosis!.mg,
+ ],
+ );
+ assert(medIDRes.isNotEmpty);
+ // Assuming intakes only contain medications that have been added
+ final medID = medIDRes.first['medID'];
- // obtain free entry id
- final id = await DBHelper.getEntryID(txn, intake.time.secondsSinceEpoch);
- await txn.delete('Intake', where: 'entryID = ?', whereArgs: [id]);
+ // obtain free entry id
+ final id =
+ await DBHelper.getEntryID(txn, intake.time.secondsSinceEpoch);
+ await txn.delete('Intake', where: 'entryID = ?', whereArgs: [id]);
- // store to db
- await txn.insert('Intake', {
- 'entryID': id,
- 'medID': medID,
- 'dosis': intake.dosis.mg,
- });
- });
+ // store to db
+ await txn.insert('Intake', {
+ 'entryID': id,
+ 'medID': medID,
+ 'dosis': intake.dosis.mg,
+ });
+ });
@override
Future<List<MedicineIntake>> get(DateRange range) async {
final results = await _db.rawQuery(
- 'SELECT t.timestampUnixS, dosis, defaultDose, designation, color '
+ 'SELECT t.timestampUnixS, dosis, defaultDose, designation, color '
'FROM Timestamps AS t '
'JOIN Intake AS i ON t.entryID = i.entryID '
'JOIN Medicine AS m ON m.medID = i.medID '
- 'WHERE t.timestampUnixS BETWEEN ? AND ?'
- 'AND i.dosis IS NOT NULL', // deleted intakes
- [range.startStamp, range.endStamp]
- );
+ 'WHERE t.timestampUnixS BETWEEN ? AND ?'
+ 'AND i.dosis IS NOT NULL', // deleted intakes
+ [range.startStamp, range.endStamp]);
final intakes = <MedicineIntake>[];
for (final r in results) {
final timeS = r['timestampUnixS'] as int;
@@ -88,28 +91,25 @@ class MedicineIntakeRepositoryImpl extends MedicineIntakeRepository {
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,
- ]
- );
+ '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) {
@@ -119,5 +119,4 @@ class MedicineIntakeRepositoryImpl extends MedicineIntakeRepository {
@override
Stream subscribe() => _controller.stream;
-
}
health_data_store/lib/src/repositories/medicine_repository.dart
@@ -4,7 +4,6 @@ import 'package:health_data_store/src/types/medicine_intake.dart';
/// Repository for medicines that are taken by the user.
abstract class MedicineRepository extends Repository<Medicine> {
-
/// Store a [Medicine] in the repository.
@override
Future<void> add(Medicine medicine);
@@ -19,5 +18,4 @@ abstract class MedicineRepository extends Repository<Medicine> {
/// still displayed correctly.
@override
Future<void> remove(Medicine value);
-
}
health_data_store/lib/src/repositories/medicine_repository_impl.dart
@@ -20,24 +20,23 @@ class MedicineRepositoryImpl extends MedicineRepository {
@override
Future<void> add(Medicine medicine) => _db.transaction((txn) async {
- final idRes = await txn.query('Medicine', columns: ['MAX(medID)']);
- final id = (idRes.firstOrNull?['MAX(medID)']?.castOrNull<int>() ?? 0) + 1;
- _controller.add(null);
- await txn.insert('Medicine', {
- 'medID': id,
- 'designation': medicine.designation,
- 'defaultDose': medicine.dosis?.mg,
- 'color': medicine.color,
- 'removed': 0,
- });
- });
+ final idRes = await txn.query('Medicine', columns: ['MAX(medID)']);
+ final id =
+ (idRes.firstOrNull?['MAX(medID)']?.castOrNull<int>() ?? 0) + 1;
+ _controller.add(null);
+ await txn.insert('Medicine', {
+ 'medID': id,
+ 'designation': medicine.designation,
+ 'defaultDose': medicine.dosis?.mg,
+ 'color': medicine.color,
+ 'removed': 0,
+ });
+ });
@override
Future<List<Medicine>> getAll() async {
final medData = await _db.query('Medicine',
- columns: ['designation', 'defaultDose', 'color'],
- where: 'removed = 0'
- );
+ columns: ['designation', 'defaultDose', 'color'], where: 'removed = 0');
final meds = <Medicine>[];
for (final m in medData) {
meds.add(Medicine(
@@ -53,19 +52,19 @@ class MedicineRepositoryImpl extends MedicineRepository {
@override
Future<void> remove(Medicine value) async {
_controller.add(null);
- await _db.update('Medicine', {
+ await _db.update(
+ 'Medicine',
+ {
'removed': 1,
},
- where: 'designation = ? AND color '
- + (value.color == null ? 'IS NULL' : '= ?')
- + ' AND defaultDose '
- + (value.dosis == null ? 'IS NULL' : '= ?'),
+ where: 'designation = ? AND color ' +
+ (value.color == null ? 'IS NULL' : '= ?') +
+ ' AND defaultDose ' +
+ (value.dosis == null ? 'IS NULL' : '= ?'),
whereArgs: [
value.designation,
- if (value.color != null)
- value.color,
- if (value.dosis != null)
- value.dosis!.mg,
+ if (value.color != null) value.color,
+ if (value.dosis != null) value.dosis!.mg,
],
);
}
health_data_store/lib/src/repositories/note_repository_impl.dart
@@ -28,15 +28,15 @@ class NoteRepositoryImpl extends NoteRepository {
}
await _db.transaction((txn) async {
final id = await DBHelper.getEntryID(txn, note.time.secondsSinceEpoch);
- await txn.delete('Notes', where: 'entryID = ?',
+ await txn.delete(
+ 'Notes',
+ where: 'entryID = ?',
whereArgs: [id],
);
await txn.insert('Notes', {
'entryID': id,
- if (note.note != null)
- 'note': note.note,
- if (note.color != null)
- 'color': note.color,
+ if (note.note != null) 'note': note.note,
+ if (note.color != null) 'color': note.color,
});
});
}
@@ -44,15 +44,15 @@ class NoteRepositoryImpl extends NoteRepository {
@override
Future<List<Note>> get(DateRange range) async {
final result = await _db.rawQuery(
- 'SELECT t.timestampUnixS AS time, note, color '
+ '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,
- ]
- );
+ '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(
@@ -68,19 +68,18 @@ class NoteRepositoryImpl extends NoteRepository {
Future<void> remove(Note value) {
_controller.add(null);
return _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,
- ]);
+ '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,
+ ]);
}
@override
health_data_store/lib/src/types/units/pressure.dart
@@ -1,14 +1,14 @@
/// Class representing and converting [pressure](https://en.wikipedia.org/wiki/Pressure).
class Pressure {
- /// Create pressure from kilopascal.
- Pressure.kPa(double value): _valPa = value * 1000;
+ /// Create pressure from kilopascal.
+ Pressure.kPa(double value) : _valPa = value * 1000;
/// Create pressure from [Millimetre of mercury](https://en.wikipedia.org/wiki/Millimetre_of_mercury).
- Pressure.mmHg(int value): _valPa = value * 133.322;
+ Pressure.mmHg(int value) : _valPa = value * 133.322;
/// Currently stored value in pascal.
double _valPa;
-
+
/// Get value in kilopascal.
double get kPa => _valPa / 1000;
@@ -17,18 +17,14 @@ class Pressure {
@override
bool operator ==(Object other) =>
- identical(this, other)
- || other is Pressure
- && runtimeType == other.runtimeType
- && _valPa == other._valPa;
+ identical(this, other) ||
+ other is Pressure &&
+ runtimeType == other.runtimeType &&
+ _valPa == other._valPa;
@override
int get hashCode => _valPa.hashCode;
@override
- String toString() {
- assert(true, 'Avoid calling toString on Pressure directly as this may not'
- 'respect the users preferences.');
- return mmHg.toString();
- }
+ String toString() => mmHg.toString();
}
health_data_store/lib/src/types/units/weight.dart
@@ -4,13 +4,13 @@ class Weight {
Weight.mg(this._value);
/// Create a weight from grams.
- Weight.g(double value): _value = value * 1000;
+ Weight.g(double value) : _value = value * 1000;
/// Create a weight from kilograms.
- Weight.kg(double value): _value = value * 1000 * 1000;
+ Weight.kg(double value) : _value = value * 1000 * 1000;
/// Create a weight from [grain](https://en.wikipedia.org/wiki/Grain_(unit)).
- Weight.gr(double value): _value = value * 64.79891;
+ Weight.gr(double value) : _value = value * 64.79891;
/// Currently stored weight in milligrams.
double _value;
@@ -30,9 +30,9 @@ class Weight {
@override
bool operator ==(Object other) =>
identical(this, other) ||
- other is Weight
- && runtimeType == other.runtimeType
- && _value == other._value;
+ other is Weight &&
+ runtimeType == other.runtimeType &&
+ _value == other._value;
@override
int get hashCode => _value.hashCode;
health_data_store/lib/src/types/blood_pressure_record.dart
@@ -10,10 +10,13 @@ class BloodPressureRecord with _$BloodPressureRecord {
const factory BloodPressureRecord({
/// Timestamp when the measurement was taken.
required DateTime time,
+
/// Systolic value of the measurement.
Pressure? sys,
+
/// Diastolic value of the measurement.
Pressure? dia,
+
/// Pulse value of the measurement in bpm.
int? pul,
}) = _BloodPressureRecord;
health_data_store/lib/src/types/bodyweight_record.dart
@@ -10,6 +10,7 @@ class BodyweightRecord with _$BodyweightRecord {
const factory BodyweightRecord({
/// Timestamp when the weight was measured.
required DateTime time,
+
/// Weight at [time].
required Weight weight,
}) = _BodyweightRecord;
health_data_store/lib/src/types/date_range.dart
@@ -18,15 +18,16 @@ class DateRange with _$DateRange {
factory DateRange({
/// The start of the range of dates.
required DateTime start,
+
/// The end of the range of dates.
required DateTime end,
}) = _DateRange;
/// Creates a date range from unix epoch to now.
factory DateRange.all() => DateRange(
- start: DateTime.fromMillisecondsSinceEpoch(0),
- end: DateTime.now(),
- );
+ start: DateTime.fromMillisecondsSinceEpoch(0),
+ end: DateTime.now(),
+ );
/// Returns a [Duration] of the time between [start] and [end].
///
health_data_store/lib/src/types/full_entry.dart
@@ -51,8 +51,8 @@ extension FullEntryList on List<FullEntry> {
List<Medicine> get distinctMedicines {
final Set<Medicine> meds = Set();
forEach((e) => e.$3.forEach((m) {
- meds.add(m.medicine);
- }));
+ meds.add(m.medicine);
+ }));
return meds.toList();
}
@@ -83,11 +83,9 @@ extension FullEntryList on List<FullEntry> {
for (int i = 0; i < count; i++) {
entries.add((
recordsAtTimeIt.moveNext()
- ? recordsAtTimeIt.current
- : BloodPressureRecord(time: time),
- notesAtTimeIt.moveNext()
- ? notesAtTimeIt.current
- : Note(time: time),
+ ? recordsAtTimeIt.current
+ : BloodPressureRecord(time: time),
+ notesAtTimeIt.moveNext() ? notesAtTimeIt.current : Note(time: time),
[],
));
}
health_data_store/lib/src/types/medicine.dart
@@ -10,11 +10,13 @@ class Medicine with _$Medicine {
const factory Medicine({
/// Name of the medicine.
required String designation,
+
/// ARGB color in number format.
///
/// Can also be obtained through the `dart:ui` Colors `value` attribute.
/// Sample value: `0xFF42A5F5`
int? color,
+
/// Default dosis of medication.
Weight? dosis,
}) = _Medicine;
health_data_store/lib/src/types/medicine_intake.dart
@@ -11,8 +11,10 @@ class MedicineIntake with _$MedicineIntake {
const factory MedicineIntake({
/// Timestamp when the medicine was taken.
required DateTime time,
+
/// Description of the taken medicine.
required Medicine medicine,
+
/// Amount of medicine taken.
///
/// When the medication has a default value, this must be set to that value,
health_data_store/lib/src/types/note.dart
@@ -9,8 +9,10 @@ class Note with _$Note {
const factory Note({
/// Timestamp when the note was taken.
required DateTime time,
+
/// Content of the note.
String? note,
+
/// ARGB color in number format.
///
/// Can also be obtained through the `dart:ui` Colors `value` attribute.
health_data_store/lib/src/database_helper.dart
@@ -1,4 +1,3 @@
-
import 'package:sqflite_common/sqflite.dart';
/// Helper methods for database interaction to allow code reuse.
@@ -19,9 +18,7 @@ class DBHelper {
);
int entryID;
if (existing.isEmpty) {
- final result = await txn.query('Timestamps',
- columns: ['MAX(entryID)']
- );
+ final result = await txn.query('Timestamps', columns: ['MAX(entryID)']);
final highestID = result.first['MAX(entryID)'] as int?;
entryID = (highestID ?? 0) + 1;
await txn.insert('Timestamps', {
health_data_store/lib/src/database_manager.dart
@@ -1,8 +1,8 @@
import 'package:sqflite_common/sqlite_api.dart';
/// Manager for the database.
-///
-/// Responsible for setting up the database and performing schema and version
+///
+/// Responsible for setting up the database and performing schema and version
/// updates.
///
/// ## DB scheme
@@ -26,7 +26,8 @@ class DatabaseManager {
///
/// If [db] doesn't contain a scheme or contains an outdated scheme, one will
/// be created.
- static Future<DatabaseManager> load(Database db, [bool isReadOnly = false]) async {
+ static Future<DatabaseManager> load(Database db,
+ [bool isReadOnly = false]) async {
final dbMngr = DatabaseManager._create(db);
final tables = await dbMngr._db.query('"main".sqlite_master');
@@ -42,7 +43,7 @@ class DatabaseManager {
await dbMngr._setupWeightTable(dbMngr._db);
await dbMngr._db.setVersion(4);
}
- // When updating the schema the update steps are maintained for ensured
+ // When updating the schema the update steps are maintained for ensured
// compatability.
// TODO: develop strategy for loading older db versions as read only.
return dbMngr;
@@ -52,63 +53,63 @@ class DatabaseManager {
/// Get the database.
Database get db => _db.database;
-
+
Future<void> _setUpTables() => _db.transaction((txn) async {
- await txn.execute('CREATE TABLE "Medicine" ('
- '"medID" INTEGER NOT NULL UNIQUE,'
- '"designation" TEXT NOT NULL,'
- '"defaultDose" REAL,'
- '"color" INTEGER,'
- '"removed" BOOLEAN,'
- 'PRIMARY KEY("medID")'
- ');');
- await txn.execute('CREATE TABLE "Timestamps" ('
- '"entryID" INTEGER NOT NULL UNIQUE,'
- '"timestampUnixS" INTEGER NOT NULL,'
- 'PRIMARY KEY("entryID")'
- ');');
- await txn.execute('CREATE TABLE "Intake" ('
- '"entryID" INTEGER NOT NULL,'
- '"medID" INTEGER NOT NULL,'
- '"dosis" REAL NOT NULL,'
- 'PRIMARY KEY("entryID"),'
- 'FOREIGN KEY("entryID") REFERENCES "Timestamps"("entryID"),'
- 'FOREIGN KEY("medID") REFERENCES "Medicine"("medID")'
- ');');
- for (final info in [
- ('Systolic','sys'),
- ('Diastolic', 'dia'),
- // Pulse is stored as a double because bpm could be measured over
- // non one-minute intervalls which might be necessary to support in the
- // future.
- ('Pulse','pul'),
- ]) {
- await txn.execute('CREATE TABLE "${info.$1}" ('
- '"entryID" INTEGER NOT NULL,'
- '"${info.$2}" REAL,'
- 'FOREIGN KEY("entryID") REFERENCES "Timestamps"("entryID"),'
- 'PRIMARY KEY("entryID")'
- ');');
- }
- await txn.execute('CREATE TABLE "Notes" ('
- '"entryID" INTEGER NOT NULL,'
- '"note" TEXT,'
- // When implementing attachments instead of updating this scheme note text
- // can be interpreted as markdown and support formatting as well as files.
- '"color" INTEGER,'
- 'FOREIGN KEY("entryID") REFERENCES "Timestamps"("entryID"),'
- 'PRIMARY KEY("entryID")'
- ');');
- await _setupWeightTable(txn);
- });
+ await txn.execute('CREATE TABLE "Medicine" ('
+ '"medID" INTEGER NOT NULL UNIQUE,'
+ '"designation" TEXT NOT NULL,'
+ '"defaultDose" REAL,'
+ '"color" INTEGER,'
+ '"removed" BOOLEAN,'
+ 'PRIMARY KEY("medID")'
+ ');');
+ await txn.execute('CREATE TABLE "Timestamps" ('
+ '"entryID" INTEGER NOT NULL UNIQUE,'
+ '"timestampUnixS" INTEGER NOT NULL,'
+ 'PRIMARY KEY("entryID")'
+ ');');
+ await txn.execute('CREATE TABLE "Intake" ('
+ '"entryID" INTEGER NOT NULL,'
+ '"medID" INTEGER NOT NULL,'
+ '"dosis" REAL NOT NULL,'
+ 'PRIMARY KEY("entryID"),'
+ 'FOREIGN KEY("entryID") REFERENCES "Timestamps"("entryID"),'
+ 'FOREIGN KEY("medID") REFERENCES "Medicine"("medID")'
+ ');');
+ for (final info in [
+ ('Systolic', 'sys'),
+ ('Diastolic', 'dia'),
+ // Pulse is stored as a double because bpm could be measured over
+ // non one-minute intervalls which might be necessary to support in the
+ // future.
+ ('Pulse', 'pul'),
+ ]) {
+ await txn.execute('CREATE TABLE "${info.$1}" ('
+ '"entryID" INTEGER NOT NULL,'
+ '"${info.$2}" REAL,'
+ 'FOREIGN KEY("entryID") REFERENCES "Timestamps"("entryID"),'
+ 'PRIMARY KEY("entryID")'
+ ');');
+ }
+ await txn.execute('CREATE TABLE "Notes" ('
+ '"entryID" INTEGER NOT NULL,'
+ '"note" TEXT,'
+ // When implementing attachments instead of updating this scheme note text
+ // can be interpreted as markdown and support formatting as well as files.
+ '"color" INTEGER,'
+ 'FOREIGN KEY("entryID") REFERENCES "Timestamps"("entryID"),'
+ 'PRIMARY KEY("entryID")'
+ ');');
+ await _setupWeightTable(txn);
+ });
Future<void> _setupWeightTable(DatabaseExecutor executor) async {
await executor.execute('CREATE TABLE "Weight" ('
- '"entryID" INTEGER NOT NULL,'
- '"weightKg" REAL NOT NULL,'
- 'FOREIGN KEY("entryID") REFERENCES "Timestamps"("entryID"),'
- 'PRIMARY KEY("entryID")'
- ');');
+ '"entryID" INTEGER NOT NULL,'
+ '"weightKg" REAL NOT NULL,'
+ 'FOREIGN KEY("entryID") REFERENCES "Timestamps"("entryID"),'
+ 'PRIMARY KEY("entryID")'
+ ');');
}
/// Removes unused and deleted entries rows.
@@ -117,21 +118,23 @@ 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) '
- 'AND entryID NOT IN (SELECT entryID FROM Diastolic) '
- 'AND entryID NOT IN (SELECT entryID FROM Pulse) '
- 'AND entryID NOT IN (SELECT entryID FROM Weight) '
- 'AND entryID NOT IN (SELECT entryID FROM Notes);',
- );
- });
+ // 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) '
+ 'AND entryID NOT IN (SELECT entryID FROM Diastolic) '
+ 'AND entryID NOT IN (SELECT entryID FROM Pulse) '
+ 'AND entryID NOT IN (SELECT entryID FROM Weight) '
+ 'AND entryID NOT IN (SELECT entryID FROM Notes);',
+ );
+ });
/// Closes the database.
Future<void> close() => _db.close();
health_data_store/lib/src/health_data_store.dart
@@ -37,7 +37,8 @@ class HealthDataStore {
/// When loading a database as [isReadOnly] no automatic changes to the
/// database are made. It will however not protect you from manually
/// attempting to modify the stored contents (e.g. in [Repository] methods).
- static Future<HealthDataStore> load(Database db, [bool isReadOnly = false]) async {
+ static Future<HealthDataStore> load(Database db,
+ [bool isReadOnly = false]) async {
// TODO: loading readOnly dbs
assert(db.isOpen);
final mngr = await DatabaseManager.load(db);
@@ -48,22 +49,18 @@ class HealthDataStore {
}
/// Repository for blood pressure data.
- BloodPressureRepository get bpRepo =>
- BloodPressureRepositoryImpl(_dbMngr.db);
+ BloodPressureRepository get bpRepo => BloodPressureRepositoryImpl(_dbMngr.db);
/// Repository for notes.
- NoteRepository get noteRepo =>
- NoteRepositoryImpl(_dbMngr.db);
+ NoteRepository get noteRepo => NoteRepositoryImpl(_dbMngr.db);
/// Repository for medicines.
- MedicineRepository get medRepo =>
- MedicineRepositoryImpl(_dbMngr.db);
+ MedicineRepository get medRepo => MedicineRepositoryImpl(_dbMngr.db);
/// Repository for intakes.
MedicineIntakeRepository get intakeRepo =>
- MedicineIntakeRepositoryImpl(_dbMngr.db);
+ MedicineIntakeRepositoryImpl(_dbMngr.db);
/// Repository for weight data.
- BodyweightRepository get weightRepo =>
- BodyweightRepositoryImpl(_dbMngr.db);
+ BodyweightRepository get weightRepo => BodyweightRepositoryImpl(_dbMngr.db);
}
health_data_store/test/src/repositories/blood_pressure_repository_test.dart
@@ -39,7 +39,7 @@ void main() {
end: DateTime.fromMillisecondsSinceEpoch(80000),
));
expect(values, hasLength(3));
- expect(values, containsAll([r1,r2,r3]));
+ expect(values, containsAll([r1, r2, r3]));
});
test('should remove records', () async {
final db = await mockDBManager();
@@ -78,7 +78,7 @@ void main() {
end: DateTime.fromMillisecondsSinceEpoch(80000),
));
expect(values0, hasLength(3));
- expect(values0, containsAll([r1,r2,r3]));
+ expect(values0, containsAll([r1, r2, r3]));
await repo.remove(r1);
final values1 = await repo.get(DateRange(
@@ -86,7 +86,7 @@ void main() {
end: DateTime.fromMillisecondsSinceEpoch(80000),
));
expect(values1, hasLength(2));
- expect(values1, containsAll([r2,r3]));
+ expect(values1, containsAll([r2, r3]));
await repo.remove(r2);
final values2 = await repo.get(DateRange(
health_data_store/test/src/repositories/bodyweight_repository_test.dart
@@ -28,7 +28,7 @@ void main() {
end: DateTime.fromMillisecondsSinceEpoch(1234570000),
));
expect(values, hasLength(2));
- expect(values, containsAll([r1,r2]));
+ expect(values, containsAll([r1, r2]));
});
test('removes records', () async {
final db = await mockDBManager();
health_data_store/test/src/repositories/medicine_intake_repository_test.dart
@@ -20,7 +20,9 @@ void main() {
final db = await mockDBManager();
addTearDown(db.close);
final med1 = mockMedicine(designation: 'med1', dosis: 2.4);
- final med2 = mockMedicine(designation: 'med2',);
+ final med2 = mockMedicine(
+ designation: 'med2',
+ );
final medRepo = MedicineRepositoryImpl(db.db);
await medRepo.add(med1);
await medRepo.add(med2);
@@ -45,7 +47,11 @@ void main() {
final repo = MedicineIntakeRepositoryImpl(db.db);
final t1 = mockIntake(med1, time: 20000);
final t2 = mockIntake(med2, time: 76000);
- final t3 = mockIntake(med1, dosis: 123, time: 50000,);
+ final t3 = mockIntake(
+ med1,
+ dosis: 123,
+ time: 50000,
+ );
await repo.add(t1);
await repo.add(t2);
await repo.add(t3);
@@ -56,7 +62,13 @@ void main() {
end: DateTime.fromMillisecondsSinceEpoch(80000),
));
expect(values, hasLength(3));
- expect(values, containsAll([t1, t2, t3,]));
+ expect(
+ values,
+ containsAll([
+ t1,
+ t2,
+ t3,
+ ]));
});
test('should remove intakes', () async {
final db = await mockDBManager();
health_data_store/test/src/repositories/medicine_repository_test.dart
@@ -24,52 +24,64 @@ void main() {
final db = await mockDBManager();
addTearDown(db.close);
final repo = MedicineRepositoryImpl(db.db);
- await repo.add(mockMedicine(designation:'med1', color:0xFF226A, dosis:42));
- await repo.add(mockMedicine(designation:'med2', color:0xAF226B, dosis:43));
+ await repo
+ .add(mockMedicine(designation: 'med1', color: 0xFF226A, dosis: 42));
+ await repo
+ .add(mockMedicine(designation: 'med2', color: 0xAF226B, dosis: 43));
final all = await repo.getAll();
expect(all, hasLength(2));
- expect(all, containsAll([
- isA<Medicine>()
- .having((p0) => p0.designation, 'designation', 'med1')
- .having((p0) => p0.color, 'color', 0xFF226A)
- .having((p0) => p0.dosis?.mg, 'dosis', 42),
- isA<Medicine>()
- .having((p0) => p0.designation, 'designation', 'med2')
- .having((p0) => p0.color, 'color', 0xAF226B)
- .having((p0) => p0.dosis?.mg, 'dosis', 43),
- ]));
+ expect(
+ all,
+ containsAll([
+ isA<Medicine>()
+ .having((p0) => p0.designation, 'designation', 'med1')
+ .having((p0) => p0.color, 'color', 0xFF226A)
+ .having((p0) => p0.dosis?.mg, 'dosis', 42),
+ isA<Medicine>()
+ .having((p0) => p0.designation, 'designation', 'med2')
+ .having((p0) => p0.color, 'color', 0xAF226B)
+ .having((p0) => p0.dosis?.mg, 'dosis', 43),
+ ]));
});
test('should store all incomplete medicines', () async {
final db = await mockDBManager();
addTearDown(db.close);
final repo = MedicineRepositoryImpl(db.db);
- await repo.add(Medicine(designation: 'med1', color: 0xFF226A,));
+ await repo.add(Medicine(
+ designation: 'med1',
+ color: 0xFF226A,
+ ));
await repo.add(mockMedicine(designation: 'med2', dosis: 43));
- await repo.add(Medicine(designation: 'med3',));
+ await repo.add(Medicine(
+ designation: 'med3',
+ ));
final all = await repo.getAll();
expect(all, hasLength(3));
- expect(all, containsAll([
- isA<Medicine>()
- .having((p0) => p0.designation, 'designation', 'med1')
- .having((p0) => p0.color, 'color', 0xFF226A)
- .having((p0) => p0.dosis?.mg, 'dosis', null),
- isA<Medicine>()
- .having((p0) => p0.designation, 'designation', 'med2')
- .having((p0) => p0.color, 'color', null)
- .having((p0) => p0.dosis?.mg, 'dosis', 43),
- isA<Medicine>()
- .having((p0) => p0.designation, 'designation', 'med3')
- .having((p0) => p0.color, 'color', null)
- .having((p0) => p0.dosis?.mg, 'dosis', null),
- ]));
+ expect(
+ all,
+ containsAll([
+ isA<Medicine>()
+ .having((p0) => p0.designation, 'designation', 'med1')
+ .having((p0) => p0.color, 'color', 0xFF226A)
+ .having((p0) => p0.dosis?.mg, 'dosis', null),
+ isA<Medicine>()
+ .having((p0) => p0.designation, 'designation', 'med2')
+ .having((p0) => p0.color, 'color', null)
+ .having((p0) => p0.dosis?.mg, 'dosis', 43),
+ isA<Medicine>()
+ .having((p0) => p0.designation, 'designation', 'med3')
+ .having((p0) => p0.color, 'color', null)
+ .having((p0) => p0.dosis?.mg, 'dosis', null),
+ ]));
});
test('should mark medicines as deleted', () async {
final db = await mockDBManager();
addTearDown(db.close);
final repo = MedicineRepositoryImpl(db.db);
- final med1= mockMedicine(designation: 'med1', color: 0xFF226A, dosis: 42);
+ final med1 = mockMedicine(designation: 'med1', color: 0xFF226A, dosis: 42);
await repo.add(med1);
- await repo.add(mockMedicine(designation:'med2', color:0xAF226B, dosis:43));
+ await repo
+ .add(mockMedicine(designation: 'med2', color: 0xAF226B, dosis: 43));
expect(await repo.getAll(), hasLength(2));
await repo.remove(med1);
expect(await repo.getAll(), hasLength(1));
@@ -78,11 +90,16 @@ void main() {
final db = await mockDBManager();
addTearDown(db.close);
final repo = MedicineRepositoryImpl(db.db);
- final med1 = Medicine(designation: 'med1', color: 0xFF226A,);
+ final med1 = Medicine(
+ designation: 'med1',
+ color: 0xFF226A,
+ );
await repo.add(med1);
final med2 = mockMedicine(designation: 'med2', dosis: 43);
await repo.add(med2);
- final med3 = Medicine(designation: 'med3',);
+ final med3 = Medicine(
+ designation: 'med3',
+ );
await repo.add(med3);
expect(await repo.getAll(), hasLength(3));
await repo.remove(med1);
@@ -96,7 +113,10 @@ void main() {
final repo = MedicineRepositoryImpl(db.db);
int calls = 0;
repo.subscribe().listen((_) => calls++);
- final med1 = Medicine(designation: 'med1', color: 0xFF226A,);
+ final med1 = Medicine(
+ designation: 'med1',
+ color: 0xFF226A,
+ );
await repo.add(med1);
expect(calls, 1);
await repo.add(mockMedicine(designation: 'med2', dosis: 43));
@@ -105,5 +125,4 @@ void main() {
await repo.remove(med1);
expect(calls, 4);
});
-
}
health_data_store/test/src/types/units/pressure_test.dart
@@ -16,8 +16,4 @@ void main() {
expect(Pressure.kPa(15.9987).mmHg, 120);
expect(Pressure.kPa(10.0).mmHg, 75);
});
-
- test('should attempt to avoid printing', () {
- expect(() => Pressure.mmHg(120).toString(), throwsA(isA<AssertionError>()));
- });
}
health_data_store/test/src/types/units/weight_test.dart
@@ -4,7 +4,7 @@ import 'package:test/test.dart';
void main() {
test('returns the same value as constructed with', () {
expect(Weight.mg(1234.45).mg, 1234.45);
- expect(Weight.g(1234.45).g, 1234.45);
+ expect(Weight.g(1234.45).g, 1234.45);
expect(Weight.kg(1234.45).kg, 1234.45);
expect(Weight.gr(1234.45).gr, 1234.45);
});
health_data_store/test/src/types/blood_pressure_record_test.dart
@@ -15,12 +15,14 @@ void main() {
expect(record.sys?.mmHg, 123);
expect(record.dia?.mmHg, 56);
expect(record.pul, 78);
- expect(record, equals(BloodPressureRecord(
- time: time,
- sys: Pressure.mmHg(123),
- dia: Pressure.mmHg(56),
- pul: 78,
- )));
+ expect(
+ record,
+ equals(BloodPressureRecord(
+ time: time,
+ sys: Pressure.mmHg(123),
+ dia: Pressure.mmHg(56),
+ pul: 78,
+ )));
});
test('should initialize with partial data', () {
final time = DateTime.now();
@@ -32,12 +34,14 @@ void main() {
expect(record.sys?.mmHg, null);
expect(record.dia?.mmHg, 56);
expect(record.pul, null);
- expect(record, isNot(equals(BloodPressureRecord(
- time: time,
- sys: Pressure.mmHg(123),
- dia: Pressure.mmHg(56),
- pul: 78,
- ))));
+ expect(
+ record,
+ isNot(equals(BloodPressureRecord(
+ time: time,
+ sys: Pressure.mmHg(123),
+ dia: Pressure.mmHg(56),
+ pul: 78,
+ ))));
});
}
@@ -46,9 +50,12 @@ BloodPressureRecord mockRecord({
int? sys,
int? dia,
int? pul,
-}) => BloodPressureRecord(
- time: time!=null ? DateTime.fromMillisecondsSinceEpoch(time) : DateTime.now(),
- sys: sys == null ? null : Pressure.mmHg(sys),
- dia: dia == null ? null : Pressure.mmHg(dia),
- pul: pul,
-);
+}) =>
+ BloodPressureRecord(
+ time: time != null
+ ? DateTime.fromMillisecondsSinceEpoch(time)
+ : DateTime.now(),
+ sys: sys == null ? null : Pressure.mmHg(sys),
+ dia: dia == null ? null : Pressure.mmHg(dia),
+ pul: pul,
+ );
health_data_store/test/src/types/bodyweight_record_test.dart
@@ -15,7 +15,10 @@ void main() {
BodyweightRecord mockWeight({
int? time,
double? kg,
-}) => BodyweightRecord(
- time: time!=null ? DateTime.fromMillisecondsSinceEpoch(time) : DateTime.now(),
- weight: Weight.kg(kg ?? 42.0),
-);
+}) =>
+ BodyweightRecord(
+ time: time != null
+ ? DateTime.fromMillisecondsSinceEpoch(time)
+ : DateTime.now(),
+ weight: Weight.kg(kg ?? 42.0),
+ );
health_data_store/test/src/types/date_range_test.dart
@@ -14,7 +14,7 @@ void main() {
final start = DateTime.now();
final end = start.subtract(Duration(hours: 20));
expect(end.isBefore(start), true);
- expect(() => DateRange(start: start,end: end),
+ expect(() => DateRange(start: start, end: end),
throwsA(isA<AssertionError>()));
});
test('should calculate difference', () {
health_data_store/test/src/types/full_entry_test.dart
@@ -72,7 +72,7 @@ void main() {
final med3 = mockMedicine();
final List<FullEntry> list = [
- (record, note, [mockIntake(med1),mockIntake(med2)]),
+ (record, note, [mockIntake(med1), mockIntake(med2)]),
(record, note, [mockIntake(med1)]),
(record, note, []),
(record, note, [mockIntake(med3), mockIntake(med1)]),
@@ -118,11 +118,26 @@ void main() {
mockNote(time: 70000, color: 123),
];
final intakes = [
- mockIntake(mockMedicine(), time: 10000,),
- mockIntake(mockMedicine(), time: 20000,),
- mockIntake(mockMedicine(), time: 30000,),
- mockIntake(mockMedicine(), time: 50000,),
- mockIntake(mockMedicine(), time: 50000,),
+ mockIntake(
+ mockMedicine(),
+ time: 10000,
+ ),
+ mockIntake(
+ mockMedicine(),
+ time: 20000,
+ ),
+ mockIntake(
+ mockMedicine(),
+ time: 30000,
+ ),
+ mockIntake(
+ mockMedicine(),
+ time: 50000,
+ ),
+ mockIntake(
+ mockMedicine(),
+ time: 50000,
+ ),
mockIntake(mockMedicine(), time: 60000, dosis: 12343.0),
mockIntake(mockMedicine(), time: 70000),
mockIntake(mockMedicine(), time: 70000),
@@ -130,74 +145,79 @@ void main() {
];
final list = FullEntryList.merged(records, notes, intakes);
expect(list, hasLength(8));
- expect(list, containsAll([
- isA<FullEntry>()
- .having((e) => e.time.millisecondsSinceEpoch, 'time', 10000)
- .having((e) => e.sys?.mmHg, 'sys', 123)
- .having((e) => e.dia?.mmHg, 'dia', 456)
- .having((e) => e.pul, 'pul', null)
- .having((e) => e.note, 'note', 'testnote')
- .having((e) => e.color, 'color', 123)
- .having((e) => e.intakes, 'intakes', hasLength(1)),
- isA<FullEntry>()
- .having((e) => e.time.millisecondsSinceEpoch, 'time', 20000)
- .having((e) => e.sys?.mmHg, 'sys', null)
- .having((e) => e.dia?.mmHg, 'dia', null)
- .having((e) => e.pul, 'pul', null)
- .having((e) => e.note, 'note', 'testnote')
- .having((e) => e.color, 'color', 123)
- .having((e) => e.intakes, 'intakes', hasLength(1)),
- isA<FullEntry>()
- .having((e) => e.time.millisecondsSinceEpoch, 'time', 30000)
- .having((e) => e.sys?.mmHg, 'sys', null)
- .having((e) => e.dia?.mmHg, 'dia', 456)
- .having((e) => e.pul, 'pul', null)
- .having((e) => e.note, 'note', null)
- .having((e) => e.color, 'color', null)
- .having((e) => e.intakes, 'intakes', hasLength(1)),
- isA<FullEntry>()
- .having((e) => e.time.millisecondsSinceEpoch, 'time', 40000)
- .having((e) => e.sys?.mmHg, 'sys', 123)
- .having((e) => e.dia?.mmHg, 'dia', 456)
- .having((e) => e.pul, 'pul', null)
- .having((e) => e.note, 'note', null)
- .having((e) => e.color, 'color', null)
- .having((e) => e.intakes, 'intakes', isEmpty),
- isA<FullEntry>()
- .having((e) => e.time.millisecondsSinceEpoch, 'time', 50000)
- .having((e) => e.sys?.mmHg, 'sys', null)
- .having((e) => e.dia?.mmHg, 'dia', null)
- .having((e) => e.pul, 'pul', null)
- .having((e) => e.note, 'note', null)
- .having((e) => e.color, 'color', null)
- .having((e) => e.intakes, 'intakes', hasLength(2)),
- isA<FullEntry>()
- .having((e) => e.time.millisecondsSinceEpoch, 'time', 60000)
- .having((e) => e.sys?.mmHg, 'sys', null)
- .having((e) => e.dia?.mmHg, 'dia', null)
- .having((e) => e.pul, 'pul', null)
- .having((e) => e.note, 'note', null)
- .having((e) => e.color, 'color', null)
- .having((e) => e.intakes, 'intakes', hasLength(1))
- .having((e) => e.intakes, 'intakes', contains(isA<MedicineIntake>()
- .having((i) => i.dosis.mg, 'dosis', 12343.0))),
- isA<FullEntry>()
- .having((e) => e.time.millisecondsSinceEpoch, 'time', 70000)
- .having((e) => e.sys?.mmHg, 'sys', null)
- .having((e) => e.dia?.mmHg, 'dia', null)
- .having((e) => e.pul, 'pul', null)
- .having((e) => e.note, 'note', null)
- .having((e) => e.color, 'color', 123)
- .having((e) => e.intakes, 'intakes', hasLength(3)),
- isA<FullEntry>()
- .having((e) => e.time.millisecondsSinceEpoch, 'time', 80000)
- .having((e) => e.sys?.mmHg, 'sys', 123)
- .having((e) => e.dia?.mmHg, 'dia', 456)
- .having((e) => e.pul, 'pul', 567)
- .having((e) => e.note, 'note', null)
- .having((e) => e.color, 'color', null)
- .having((e) => e.intakes, 'intakes', isEmpty),
- ]));
+ expect(
+ list,
+ containsAll([
+ isA<FullEntry>()
+ .having((e) => e.time.millisecondsSinceEpoch, 'time', 10000)
+ .having((e) => e.sys?.mmHg, 'sys', 123)
+ .having((e) => e.dia?.mmHg, 'dia', 456)
+ .having((e) => e.pul, 'pul', null)
+ .having((e) => e.note, 'note', 'testnote')
+ .having((e) => e.color, 'color', 123)
+ .having((e) => e.intakes, 'intakes', hasLength(1)),
+ isA<FullEntry>()
+ .having((e) => e.time.millisecondsSinceEpoch, 'time', 20000)
+ .having((e) => e.sys?.mmHg, 'sys', null)
+ .having((e) => e.dia?.mmHg, 'dia', null)
+ .having((e) => e.pul, 'pul', null)
+ .having((e) => e.note, 'note', 'testnote')
+ .having((e) => e.color, 'color', 123)
+ .having((e) => e.intakes, 'intakes', hasLength(1)),
+ isA<FullEntry>()
+ .having((e) => e.time.millisecondsSinceEpoch, 'time', 30000)
+ .having((e) => e.sys?.mmHg, 'sys', null)
+ .having((e) => e.dia?.mmHg, 'dia', 456)
+ .having((e) => e.pul, 'pul', null)
+ .having((e) => e.note, 'note', null)
+ .having((e) => e.color, 'color', null)
+ .having((e) => e.intakes, 'intakes', hasLength(1)),
+ isA<FullEntry>()
+ .having((e) => e.time.millisecondsSinceEpoch, 'time', 40000)
+ .having((e) => e.sys?.mmHg, 'sys', 123)
+ .having((e) => e.dia?.mmHg, 'dia', 456)
+ .having((e) => e.pul, 'pul', null)
+ .having((e) => e.note, 'note', null)
+ .having((e) => e.color, 'color', null)
+ .having((e) => e.intakes, 'intakes', isEmpty),
+ isA<FullEntry>()
+ .having((e) => e.time.millisecondsSinceEpoch, 'time', 50000)
+ .having((e) => e.sys?.mmHg, 'sys', null)
+ .having((e) => e.dia?.mmHg, 'dia', null)
+ .having((e) => e.pul, 'pul', null)
+ .having((e) => e.note, 'note', null)
+ .having((e) => e.color, 'color', null)
+ .having((e) => e.intakes, 'intakes', hasLength(2)),
+ isA<FullEntry>()
+ .having((e) => e.time.millisecondsSinceEpoch, 'time', 60000)
+ .having((e) => e.sys?.mmHg, 'sys', null)
+ .having((e) => e.dia?.mmHg, 'dia', null)
+ .having((e) => e.pul, 'pul', null)
+ .having((e) => e.note, 'note', null)
+ .having((e) => e.color, 'color', null)
+ .having((e) => e.intakes, 'intakes', hasLength(1))
+ .having(
+ (e) => e.intakes,
+ 'intakes',
+ contains(isA<MedicineIntake>()
+ .having((i) => i.dosis.mg, 'dosis', 12343.0))),
+ isA<FullEntry>()
+ .having((e) => e.time.millisecondsSinceEpoch, 'time', 70000)
+ .having((e) => e.sys?.mmHg, 'sys', null)
+ .having((e) => e.dia?.mmHg, 'dia', null)
+ .having((e) => e.pul, 'pul', null)
+ .having((e) => e.note, 'note', null)
+ .having((e) => e.color, 'color', 123)
+ .having((e) => e.intakes, 'intakes', hasLength(3)),
+ isA<FullEntry>()
+ .having((e) => e.time.millisecondsSinceEpoch, 'time', 80000)
+ .having((e) => e.sys?.mmHg, 'sys', 123)
+ .having((e) => e.dia?.mmHg, 'dia', 456)
+ .having((e) => e.pul, 'pul', 567)
+ .having((e) => e.note, 'note', null)
+ .having((e) => e.color, 'color', null)
+ .having((e) => e.intakes, 'intakes', isEmpty),
+ ]));
});
test('merges lists with entries at same time', () {
final list = FullEntryList.merged(
@@ -207,6 +227,7 @@ void main() {
);
expect(list, hasLength(2));
expect(list, contains(isA<FullEntry>().having((e) => e.color, 'color', 1)));
- expect(list, contains(isA<FullEntry>().having((e) =>e.color, 'note',null)));
+ expect(
+ list, contains(isA<FullEntry>().having((e) => e.color, 'note', null)));
});
}
health_data_store/test/src/types/medicine_intake_test.dart
@@ -10,19 +10,25 @@ void main() {
medicine: Medicine(designation: 'test', dosis: Weight.mg(42)),
dosis: Weight.mg(42),
);
- expect(intake.medicine, equals(Medicine(
- designation: 'test',
- dosis: Weight.mg(42),
- )));
+ expect(
+ intake.medicine,
+ equals(Medicine(
+ designation: 'test',
+ dosis: Weight.mg(42),
+ )));
expect(intake.dosis.mg, equals(42));
});
}
-MedicineIntake mockIntake(Medicine medicine, {
+MedicineIntake mockIntake(
+ Medicine medicine, {
int? time,
double? dosis,
-}) => MedicineIntake(
- time: time!=null ? DateTime.fromMillisecondsSinceEpoch(time) : DateTime.now(),
- medicine: medicine,
- dosis: Weight.mg(dosis ?? medicine.dosis?.mg ?? 42.0),
-);
+}) =>
+ MedicineIntake(
+ time: time != null
+ ? DateTime.fromMillisecondsSinceEpoch(time)
+ : DateTime.now(),
+ medicine: medicine,
+ dosis: Weight.mg(dosis ?? medicine.dosis?.mg ?? 42.0),
+ );
health_data_store/test/src/types/medicine_test.dart
@@ -13,13 +13,10 @@ void main() {
}
/// Creates a new medicine with a random designation if none is specified.
-Medicine mockMedicine({
- String? designation,
- double? dosis,
- int? color
-}) => Medicine(
- designation: designation ??
- 'med'+(Random().nextInt(899999) + 100000).toString(),
- dosis: dosis == null ? null : Weight.mg(dosis),
- color: color,
-);
+Medicine mockMedicine({String? designation, double? dosis, int? color}) =>
+ Medicine(
+ designation:
+ designation ?? 'med' + (Random().nextInt(899999) + 100000).toString(),
+ dosis: dosis == null ? null : Weight.mg(dosis),
+ color: color,
+ );
health_data_store/test/src/types/note_test.dart
@@ -12,11 +12,13 @@ void main() {
expect(note.time, equals(time));
expect(note.color, equals(0xFF42A5F5));
expect(note.note, equals('testNote'));
- expect(note, equals(Note(
- time: time,
- note: 'testNote',
- color: 0xFF42A5F5,
- )));
+ expect(
+ note,
+ equals(Note(
+ time: time,
+ note: 'testNote',
+ color: 0xFF42A5F5,
+ )));
});
}
@@ -24,8 +26,11 @@ Note mockNote({
int? time,
String? note,
int? color,
-}) => Note(
- time: time!=null ? DateTime.fromMillisecondsSinceEpoch(time) : DateTime.now(),
- note: note,
- color: color,
-);
+}) =>
+ Note(
+ time: time != null
+ ? DateTime.fromMillisecondsSinceEpoch(time)
+ : DateTime.now(),
+ note: note,
+ color: color,
+ );
health_data_store/test/src/database_helper_test.dart
@@ -1,4 +1,3 @@
-
import 'package:health_data_store/src/database_helper.dart';
import 'package:health_data_store/src/database_manager.dart';
import 'package:sqflite_common/sqflite.dart';
health_data_store/test/src/database_manager_test.dart
@@ -46,11 +46,7 @@ void main() {
};
final id2 = await db.db.insert('medicine', item2);
- final item3 = {
- 'medID': 3,
- 'designation': 'test2',
- 'defaultDose': null
- };
+ final item3 = {'medID': 3, 'designation': 'test2', 'defaultDose': null};
final id3 = await db.db.insert('medicine', item3);
expect(id2, greaterThan(id1));
expect(id3, greaterThan(id2));
@@ -58,33 +54,36 @@ void main() {
final resultCols = await db.db
.query('medicine', columns: ['medID', 'designation', 'defaultDose']);
expect(resultCols, hasLength(equals(3)));
- expect(resultCols.first.keys, containsAll([
- 'medID',
- 'designation',
- 'defaultDose',
- ]));
- expect(resultCols, containsAllInOrder([item1, item2, item3,]));
+ expect(
+ resultCols.first.keys,
+ containsAll([
+ 'medID',
+ 'designation',
+ 'defaultDose',
+ ]));
+ expect(
+ resultCols,
+ containsAllInOrder([
+ item1,
+ item2,
+ item3,
+ ]));
final resultAll = await db.db.query('medicine');
expect(resultAll, hasLength(equals(3)));
- expect(resultCols.first.keys, containsAll([
- 'medID',
- 'designation',
- 'defaultDose',
- ]));
expect(
- resultCols.first.keys,
- hasLength(resultCols.first.keys.length),
- reason: 'no extra columns.'
- );
-
- final item4 = {
- 'medID': 1,
- 'designation': null,
- 'defaultDose': null
- };
- await expectLater(() async => db.db.insert('medicine', item4),
- throwsException);
+ resultCols.first.keys,
+ containsAll([
+ 'medID',
+ 'designation',
+ 'defaultDose',
+ ]));
+ expect(resultCols.first.keys, hasLength(resultCols.first.keys.length),
+ reason: 'no extra columns.');
+
+ final item4 = {'medID': 1, 'designation': null, 'defaultDose': null};
+ await expectLater(
+ () async => db.db.insert('medicine', item4), throwsException);
});
test('creates timestamps table correctly', () async {
final db = await mockDBManager();
@@ -97,14 +96,18 @@ void main() {
expect(data, hasLength(1));
expect(data.first.keys, hasLength(2));
- await expectLater(() async => db.db.insert('Timestamps', {
- 'entryID': 1,
- 'timestampUnixS': DateTime.now().secondsSinceEpoch,
- }), throwsException);
- await expectLater(() async => db.db.insert('Timestamps', {
- 'entryID': 1,
- 'timestampUnixS': null,
- }), throwsException);
+ await expectLater(
+ () async => db.db.insert('Timestamps', {
+ 'entryID': 1,
+ 'timestampUnixS': DateTime.now().secondsSinceEpoch,
+ }),
+ throwsException);
+ await expectLater(
+ () async => db.db.insert('Timestamps', {
+ 'entryID': 1,
+ 'timestampUnixS': null,
+ }),
+ throwsException);
});
test('creates intake table correctly', () async {
final db = await mockDBManager();
@@ -123,9 +126,9 @@ void main() {
final db = await mockDBManager();
addTearDown(db.close);
for (final t in [
- ('Systolic','sys'),
+ ('Systolic', 'sys'),
('Diastolic', 'dia'),
- ('Pulse','pul')
+ ('Pulse', 'pul')
]) {
await db.db.insert(t.$1, {
'entryID': 1,
@@ -200,7 +203,6 @@ void main() {
'dosis': 1,
});
-
expect(await db.db.query('Medicine'), hasLength(2));
await db.performCleanup();
final data = await db.db.query('Medicine');
@@ -222,10 +224,18 @@ void main() {
'medID': 0,
'dosis': 0,
});
- await db.db.insert('Systolic', {'entryID': 2,});
- await db.db.insert('Diastolic', {'entryID': 3,});
- await db.db.insert('Pulse', {'entryID': 4,});
- await db.db.insert('Notes', {'entryID': 5,});
+ await db.db.insert('Systolic', {
+ 'entryID': 2,
+ });
+ await db.db.insert('Diastolic', {
+ 'entryID': 3,
+ });
+ await db.db.insert('Pulse', {
+ 'entryID': 4,
+ });
+ await db.db.insert('Notes', {
+ 'entryID': 5,
+ });
await db.db.insert('Weight', {'entryID': 6, 'weightKg': 1.0});
expect(await db.db.query('Timestamps'), hasLength(7));
@@ -236,5 +246,5 @@ void main() {
}
Future<DatabaseManager> mockDBManager() async => DatabaseManager.load(
- await openDatabase(inMemoryDatabasePath),
-);
+ await openDatabase(inMemoryDatabasePath),
+ );
health_data_store/test/src/health_data_store_test.dart
@@ -7,40 +7,40 @@ import 'database_manager_test.dart';
import 'types/blood_pressure_record_test.dart';
void main() {
- sqfliteTestInit();
- test('should initialize with new db', () async {
- final store = await HealthDataStore.load(
- await openDatabase(inMemoryDatabasePath));
- expect(store, isNotNull);
- });
- test('should construct repositories', () async {
- final store = await HealthDataStore.load(
- await openDatabase(inMemoryDatabasePath));
- expect(store, isNotNull);
- expect(() => store.medRepo, returnsNormally);
- expect(() => store.intakeRepo, returnsNormally);
- expect(() => store.bpRepo, returnsNormally);
- expect(() => store.noteRepo, returnsNormally);
- expect(() => store.weightRepo, returnsNormally);
- });
- test('constructed repos should work', () async {
- final store = await HealthDataStore.load(
- await openDatabase(inMemoryDatabasePath));
- expect(store, isNotNull);
- final bpRepo = store.bpRepo;
- final r = mockRecord(time: 10000, sys: 123, dia: 45, pul: 67);
- await bpRepo.add(r);
- final data = await bpRepo.get(DateRange(
- start: DateTime.fromMillisecondsSinceEpoch(5000),
- end: DateTime.fromMillisecondsSinceEpoch(20000),
- ));
- expect(data.length, 1);
- expect(data, contains(r));
- });
- test('should not modify read-only databases', () async {
- final db = await openReadOnlyDatabase(inMemoryDatabasePath);
- await HealthDataStore.load(db, true);
- await db.close();
- // Potential unawaited async exceptions would cause the method to fail.
- });
+ sqfliteTestInit();
+ test('should initialize with new db', () async {
+ final store =
+ await HealthDataStore.load(await openDatabase(inMemoryDatabasePath));
+ expect(store, isNotNull);
+ });
+ test('should construct repositories', () async {
+ final store =
+ await HealthDataStore.load(await openDatabase(inMemoryDatabasePath));
+ expect(store, isNotNull);
+ expect(() => store.medRepo, returnsNormally);
+ expect(() => store.intakeRepo, returnsNormally);
+ expect(() => store.bpRepo, returnsNormally);
+ expect(() => store.noteRepo, returnsNormally);
+ expect(() => store.weightRepo, returnsNormally);
+ });
+ test('constructed repos should work', () async {
+ final store =
+ await HealthDataStore.load(await openDatabase(inMemoryDatabasePath));
+ expect(store, isNotNull);
+ final bpRepo = store.bpRepo;
+ final r = mockRecord(time: 10000, sys: 123, dia: 45, pul: 67);
+ await bpRepo.add(r);
+ final data = await bpRepo.get(DateRange(
+ start: DateTime.fromMillisecondsSinceEpoch(5000),
+ end: DateTime.fromMillisecondsSinceEpoch(20000),
+ ));
+ expect(data.length, 1);
+ expect(data, contains(r));
+ });
+ test('should not modify read-only databases', () async {
+ final db = await openReadOnlyDatabase(inMemoryDatabasePath);
+ await HealthDataStore.load(db, true);
+ await db.close();
+ // Potential unawaited async exceptions would cause the method to fail.
+ });
}
health_data_store/CHANGELOG.md
@@ -0,0 +1,4 @@
+# Changelog
+
+## 1.0.2
+- Remove `toString` restrictions on pressure type
health_data_store/pubspec.yaml
@@ -1,6 +1,6 @@
name: health_data_store
description: A package to easily store health related data.
-version: 1.0.1+1
+version: 1.0.2
publish_to: none
environment: