mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-09 04:50:59 +00:00
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.
82 lines
3.4 KiB
SQL
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 $$;
|