import 'package:drift/drift.dart'; import '../../../core/id.dart'; import '../../../core/time.dart'; import '../app_database.dart'; import '../tables/user_tables.dart'; part 'tracker_dao.g.dart'; class TrackerEntryDraft { final String habitId; final String date; // YYYY-MM-DD final String value; // done | blank final String? variantId; final String? ctxLocation; final String? ctxCondition; final String? note; const TrackerEntryDraft({ required this.habitId, required this.date, required this.value, this.variantId, this.ctxLocation, this.ctxCondition, this.note, }); } @DriftAccessor(tables: [TrackerEntries]) class TrackerDao extends DatabaseAccessor with _$TrackerDaoMixin { TrackerDao(super.db); Future recordCheckIn(TrackerEntryDraft draft) async { final id = generateUlid('te'); await into(trackerEntries).insert(TrackerEntriesCompanion.insert( id: id, habitId: draft.habitId, date: draft.date, value: draft.value, loggedAt: Value(nowKst().toIso8601String()), variantId: Value(draft.variantId), ctxLocation: Value(draft.ctxLocation), ctxCondition: Value(draft.ctxCondition), note: Value(draft.note), )); return id; } Future> entriesForHabit(String habitId) { return (select(trackerEntries) ..where((t) => t.habitId.equals(habitId)) ..orderBy([(t) => OrderingTerm.asc(t.date)])) .get(); } /// Done entries in [start, end) for one user. /// [start]/[end] are YYYY-MM-DD strings. Future> findDoneInRangeForUser({ required String userId, required String startDate, required String endDate, String? habitId, }) async { final habitIds = await (select(db.habits) ..where((t) => t.userId.equals(userId))) .map((h) => h.id) .get(); if (habitIds.isEmpty) return const []; final query = select(trackerEntries) ..where((t) => t.habitId.isIn(habitIds)) ..where((t) => t.value.equals('done')) ..where((t) => t.date.isBiggerOrEqualValue(startDate) & t.date.isSmallerThanValue(endDate)); if (habitId != null) { query.where((t) => t.habitId.equals(habitId)); } return query.get(); } }