161 lines
6.3 KiB
PL/PgSQL
161 lines
6.3 KiB
PL/PgSQL
-- ---------------------------------------------------------------------------
|
||
-- HANDGESCHRIEBEN. Prisma erzeugt hier zusaetzlich Loeschbefehle fuer die
|
||
-- zusammengesetzten Fremdschluessel (Mandantengrenze), die Trigramm-Indizes
|
||
-- (Archivsuche), die partiellen eindeutigen Indizes und die Trigger auf
|
||
-- veroeffentlichten Versionen: es kennt sie nicht, weil sie sich im Schema nicht
|
||
-- ausdruecken lassen. Diese Loeschbefehle sind bewusst gestrichen.
|
||
--
|
||
-- tests/datenbankregeln.test.ts prueft, dass alle diese Objekte vorhanden sind –
|
||
-- ein versehentlich stehengelassener Loeschbefehl faellt dort sofort auf.
|
||
-- ---------------------------------------------------------------------------
|
||
|
||
-- Wiederverwendbare Bausteine (#030).
|
||
|
||
CREATE TABLE "Baustein" (
|
||
"id" TEXT NOT NULL,
|
||
"name" TEXT NOT NULL,
|
||
"beschreibung" TEXT,
|
||
"archiviert" BOOLEAN NOT NULL DEFAULT false,
|
||
"erstelltAm" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
"geaendertAm" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
CONSTRAINT "Baustein_pkey" PRIMARY KEY ("id")
|
||
);
|
||
|
||
CREATE UNIQUE INDEX "Baustein_name_key" ON "Baustein"("name");
|
||
CREATE INDEX "Baustein_archiviert_idx" ON "Baustein"("archiviert");
|
||
|
||
CREATE TABLE "BausteinVersion" (
|
||
"id" TEXT NOT NULL,
|
||
"bausteinId" TEXT NOT NULL,
|
||
"version" INTEGER NOT NULL,
|
||
"status" "VersionStatus" NOT NULL DEFAULT 'ENTWURF',
|
||
"titel" TEXT NOT NULL,
|
||
"aenderungsnotiz" TEXT,
|
||
"veroeffentlichtAm" TIMESTAMP(3),
|
||
"erstelltAm" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
"geaendertAm" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
CONSTRAINT "BausteinVersion_pkey" PRIMARY KEY ("id")
|
||
);
|
||
|
||
CREATE UNIQUE INDEX "BausteinVersion_bausteinId_version_key"
|
||
ON "BausteinVersion"("bausteinId", "version");
|
||
CREATE INDEX "BausteinVersion_bausteinId_status_idx"
|
||
ON "BausteinVersion"("bausteinId", "status");
|
||
|
||
CREATE TABLE "BausteinSchritt" (
|
||
"id" TEXT NOT NULL,
|
||
"versionId" TEXT NOT NULL,
|
||
"position" INTEGER NOT NULL DEFAULT 0,
|
||
"titel" TEXT NOT NULL,
|
||
"hilfetext" TEXT,
|
||
"typ" "SchrittTyp" NOT NULL DEFAULT 'HAKEN',
|
||
"pflicht" BOOLEAN NOT NULL DEFAULT false,
|
||
"konfig" JSONB NOT NULL DEFAULT '{}',
|
||
"dokuUrl" TEXT,
|
||
CONSTRAINT "BausteinSchritt_pkey" PRIMARY KEY ("id")
|
||
);
|
||
|
||
CREATE INDEX "BausteinSchritt_versionId_position_idx"
|
||
ON "BausteinSchritt"("versionId", "position");
|
||
|
||
ALTER TABLE "BausteinVersion"
|
||
ADD CONSTRAINT "BausteinVersion_bausteinId_fkey"
|
||
FOREIGN KEY ("bausteinId") REFERENCES "Baustein"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||
|
||
ALTER TABLE "BausteinSchritt"
|
||
ADD CONSTRAINT "BausteinSchritt_versionId_fkey"
|
||
FOREIGN KEY ("versionId") REFERENCES "BausteinVersion"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||
|
||
-- Der Verweis am Abschnitt. RESTRICT, nicht CASCADE: eine Baustein-Version, auf
|
||
-- die eine Vorlage zeigt, darf nicht unter ihr wegbrechen.
|
||
ALTER TABLE "VorlagenAbschnitt"
|
||
ADD COLUMN "bausteinVersionId" TEXT;
|
||
|
||
CREATE INDEX "VorlagenAbschnitt_bausteinVersionId_idx"
|
||
ON "VorlagenAbschnitt"("bausteinVersionId");
|
||
|
||
ALTER TABLE "VorlagenAbschnitt"
|
||
ADD CONSTRAINT "VorlagenAbschnitt_bausteinVersionId_fkey"
|
||
FOREIGN KEY ("bausteinVersionId") REFERENCES "BausteinVersion"("id")
|
||
ON DELETE RESTRICT ON UPDATE CASCADE;
|
||
|
||
-- ---------------------------------------------------------------------------
|
||
-- Dieselben Garantien wie bei Vorlagen, und zwar in der Datenbank.
|
||
--
|
||
-- Ein Baustein ist eine Quelle fuer Schritte, die in Laeufe wandern. Stuende
|
||
-- seine Unveraenderlichkeit nur im Dienst, liesse sich die Nachvollziehbarkeit
|
||
-- des Archivs ueber eine Baustein-Aenderung aushebeln.
|
||
-- ---------------------------------------------------------------------------
|
||
|
||
-- Je Baustein hoechstens ein Entwurf.
|
||
CREATE UNIQUE INDEX "BausteinVersion_ein_entwurf"
|
||
ON "BausteinVersion" ("bausteinId")
|
||
WHERE "status" = 'ENTWURF';
|
||
|
||
-- Eine veroeffentlichte Baustein-Version ist unveraenderlich.
|
||
CREATE OR REPLACE FUNCTION laufzettel_baustein_unveraenderlich() RETURNS trigger AS $$
|
||
DECLARE
|
||
betroffene_version TEXT;
|
||
aktueller_status TEXT;
|
||
BEGIN
|
||
betroffene_version := COALESCE(NEW."versionId", OLD."versionId");
|
||
SELECT status::TEXT INTO aktueller_status
|
||
FROM "BausteinVersion" WHERE id = betroffene_version;
|
||
|
||
IF aktueller_status = 'VEROEFFENTLICHT' THEN
|
||
RAISE EXCEPTION
|
||
'Baustein-Version % ist veroeffentlicht und unveraenderlich (%).',
|
||
betroffene_version, TG_TABLE_NAME
|
||
USING ERRCODE = 'integrity_constraint_violation';
|
||
END IF;
|
||
RETURN COALESCE(NEW, OLD);
|
||
END;
|
||
$$ LANGUAGE plpgsql;
|
||
|
||
CREATE TRIGGER "BausteinSchritt_unveraenderlich"
|
||
BEFORE INSERT OR UPDATE OR DELETE ON "BausteinSchritt"
|
||
FOR EACH ROW EXECUTE FUNCTION laufzettel_baustein_unveraenderlich();
|
||
|
||
-- Der Weg zurueck waere die Hintertuer, durch die sich das Obige aushebeln
|
||
-- liesse. Dieselbe Regel wie bei VorlagenVersion.
|
||
CREATE OR REPLACE FUNCTION laufzettel_baustein_status_einbahn() RETURNS trigger AS $$
|
||
BEGIN
|
||
IF OLD.status = 'VEROEFFENTLICHT' AND NEW.status <> 'VEROEFFENTLICHT' THEN
|
||
RAISE EXCEPTION
|
||
'Eine veroeffentlichte Baustein-Version laesst sich nicht wieder zum Entwurf machen.'
|
||
USING ERRCODE = 'integrity_constraint_violation';
|
||
END IF;
|
||
RETURN NEW;
|
||
END;
|
||
$$ LANGUAGE plpgsql;
|
||
|
||
CREATE TRIGGER "BausteinVersion_status_einbahn"
|
||
BEFORE UPDATE ON "BausteinVersion"
|
||
FOR EACH ROW EXECUTE FUNCTION laufzettel_baustein_status_einbahn();
|
||
|
||
-- Ein Verweis zeigt nur auf eine **veroeffentlichte** Baustein-Version. Einen
|
||
-- Entwurf einzusetzen hiesse, beim Veroeffentlichen etwas zu kopieren, das sich
|
||
-- danach noch aendert.
|
||
CREATE OR REPLACE FUNCTION laufzettel_baustein_verweis_veroeffentlicht() RETURNS trigger AS $$
|
||
DECLARE
|
||
verwiesener_status TEXT;
|
||
BEGIN
|
||
IF NEW."bausteinVersionId" IS NULL THEN
|
||
RETURN NEW;
|
||
END IF;
|
||
SELECT status::TEXT INTO verwiesener_status
|
||
FROM "BausteinVersion" WHERE id = NEW."bausteinVersionId";
|
||
|
||
IF verwiesener_status <> 'VEROEFFENTLICHT' THEN
|
||
RAISE EXCEPTION
|
||
'Ein Abschnitt kann nur auf eine veroeffentlichte Baustein-Version verweisen.'
|
||
USING ERRCODE = 'integrity_constraint_violation';
|
||
END IF;
|
||
RETURN NEW;
|
||
END;
|
||
$$ LANGUAGE plpgsql;
|
||
|
||
CREATE TRIGGER "VorlagenAbschnitt_baustein_veroeffentlicht"
|
||
BEFORE INSERT OR UPDATE ON "VorlagenAbschnitt"
|
||
FOR EACH ROW EXECUTE FUNCTION laufzettel_baustein_verweis_veroeffentlicht();
|