Data layer: Room entities, DAOs, database with exported schema
Milestone 2. Medication / DoseTime / DoseLog per the brief's model. DoseLog.doseTimeId is SET_NULL (schedule edits must not erase adherence history) while medId CASCADEs; DoseLog.amount is snapshotted at logging time so later dose changes don't rewrite the record. Inventory decrement is a single SQL UPDATE clamped at 0 to stay race-free under escalating notifications. Enums stored as TEXT; schema exported to app/schemas as the migration baseline. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
7256c49112
commit
b884885e40
10 changed files with 614 additions and 2 deletions
57
app/src/main/java/no/naiv/meddetsamme/data/DoseLog.kt
Normal file
57
app/src/main/java/no/naiv/meddetsamme/data/DoseLog.kt
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
package no.naiv.meddetsamme.data
|
||||
|
||||
import androidx.room.Entity
|
||||
import androidx.room.ForeignKey
|
||||
import androidx.room.Index
|
||||
import androidx.room.PrimaryKey
|
||||
|
||||
enum class DoseStatus { PENDING, TAKEN, SKIPPED, SNOOZED }
|
||||
|
||||
/**
|
||||
* One scheduled occurrence of a dose and what happened to it. Created PENDING
|
||||
* when the reminder fires (the escalation anchor), resolved by user action.
|
||||
*
|
||||
* SNOOZED is a *resting* state between nags — the alarm layer treats it like
|
||||
* PENDING (keeps nagging after the snooze interval) but the UI can distinguish
|
||||
* "I saw it and deferred" from "never reacted".
|
||||
*
|
||||
* [doseTimeId] is nullable and SET_NULL on delete: editing a schedule away must
|
||||
* not erase adherence history. [medId] CASCADE instead — deleting a med (vs.
|
||||
* deactivating) is an explicit "forget everything" action.
|
||||
*/
|
||||
@Entity(
|
||||
tableName = "dose_log",
|
||||
foreignKeys = [
|
||||
ForeignKey(
|
||||
entity = Medication::class,
|
||||
parentColumns = ["id"],
|
||||
childColumns = ["medId"],
|
||||
onDelete = ForeignKey.CASCADE,
|
||||
),
|
||||
ForeignKey(
|
||||
entity = DoseTime::class,
|
||||
parentColumns = ["id"],
|
||||
childColumns = ["doseTimeId"],
|
||||
onDelete = ForeignKey.SET_NULL,
|
||||
),
|
||||
],
|
||||
indices = [
|
||||
Index("medId"),
|
||||
Index("doseTimeId"),
|
||||
// The reminder layer's hot path: "is there already a log for this occurrence?"
|
||||
Index(value = ["doseTimeId", "scheduledAtMillis"]),
|
||||
Index("status"),
|
||||
],
|
||||
)
|
||||
data class DoseLog(
|
||||
@PrimaryKey(autoGenerate = true) val id: Long = 0,
|
||||
val medId: Long,
|
||||
val doseTimeId: Long?,
|
||||
/** The occurrence this log is for (epoch millis of the scheduled local time). */
|
||||
val scheduledAtMillis: Long,
|
||||
/** Dose size at the time of logging — schedule edits must not rewrite history. */
|
||||
val amount: Double,
|
||||
val status: DoseStatus = DoseStatus.PENDING,
|
||||
/** When the user last acted on it (Taken/Skipped/Snoozed), null while untouched. */
|
||||
val actionedAtMillis: Long? = null,
|
||||
)
|
||||
Loading…
Add table
Add a link
Reference in a new issue