Files
HealthLog/prisma/migrations/0223_custom_metrics/migration.sql
T
Marc-André Bombeck c306d42347 chore(release): v1.25.9 — custom metrics
Renumber the custom-metrics migration to 0223 (the next free slot on the
trunk) and cut the release: version bump, regenerated OpenAPI contract,
service-worker stamp, and CHANGELOG entry.
2026-06-30 08:59:44 +02:00

82 lines
3.4 KiB
SQL

-- v1.25.5 — user-defined custom metrics: catalog + values.
--
-- A self-hoster defines an arbitrary measurement (name, unit, optional target
-- window, decimals, description), logs values against it, and charts them. A
-- SEPARATE generic store from the closed `MeasurementType` enum + `measurements`
-- table: custom metrics are NOT synced, NOT in FHIR, NOT in AI insights — log +
-- chart only. `name` / `unit` / `description` stay plaintext (like the
-- biomarker catalog) so the list can sort + search.
--
-- `custom_metrics` — the per-user catalog (soft-deleted via deleted_at).
-- `custom_metric_entries` — the logged values (hard-deleted; cascade from both
-- the owning user and the parent metric).
--
-- Additive; no existing row touched. Idempotent guards (`IF NOT EXISTS` /
-- `DO $$`) so reruns are safe on prod. No backfill.
--
-- Reversibility (down):
-- DROP TABLE IF EXISTS "custom_metric_entries";
-- DROP TABLE IF EXISTS "custom_metrics";
-- A roll-back drops the feature wholesale — no other domain depends on it.
-- CreateTable: the per-user custom-metric catalog.
CREATE TABLE IF NOT EXISTS "custom_metrics" (
"id" TEXT NOT NULL,
"user_id" TEXT NOT NULL,
"name" TEXT NOT NULL,
"unit" TEXT NOT NULL,
"target_low" DOUBLE PRECISION,
"target_high" DOUBLE PRECISION,
"decimals" INTEGER,
"description" TEXT,
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_at" TIMESTAMP(3) NOT NULL,
"deleted_at" TIMESTAMP(3),
CONSTRAINT "custom_metrics_pkey" PRIMARY KEY ("id")
);
-- CreateTable: the logged values for each custom metric.
CREATE TABLE IF NOT EXISTS "custom_metric_entries" (
"id" TEXT NOT NULL,
"user_id" TEXT NOT NULL,
"custom_metric_id" TEXT NOT NULL,
"value" DOUBLE PRECISION NOT NULL,
"unit" TEXT NOT NULL,
"measured_at" TIMESTAMP(3) NOT NULL,
"note" TEXT,
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "custom_metric_entries_pkey" PRIMARY KEY ("id")
);
-- CreateIndex: owner scope on the catalog.
CREATE INDEX IF NOT EXISTS "custom_metrics_user_id_idx" ON "custom_metrics"("user_id");
-- CreateIndex: one catalog definition per (user, name).
CREATE UNIQUE INDEX IF NOT EXISTS "custom_metrics_user_id_name_key" ON "custom_metrics"("user_id", "name");
-- CreateIndex: the chart / list read path (owner + metric + time).
CREATE INDEX IF NOT EXISTS "custom_metric_entries_user_id_custom_metric_id_measured_at_idx" ON "custom_metric_entries"("user_id", "custom_metric_id", "measured_at");
-- AddForeignKey: catalog → user (cascade).
DO $$ BEGIN
ALTER TABLE "custom_metrics" ADD CONSTRAINT "custom_metrics_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
-- AddForeignKey: entry → user (cascade).
DO $$ BEGIN
ALTER TABLE "custom_metric_entries" ADD CONSTRAINT "custom_metric_entries_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
-- AddForeignKey: entry → metric (cascade).
DO $$ BEGIN
ALTER TABLE "custom_metric_entries" ADD CONSTRAINT "custom_metric_entries_custom_metric_id_fkey" FOREIGN KEY ("custom_metric_id") REFERENCES "custom_metrics"("id") ON DELETE CASCADE ON UPDATE CASCADE;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;