-- Gruppenordner: ein Ordner, der keinem einzelnen Konto gehört, sondern einer -- Gruppe. Wer Mitglied ist, sieht ihn; wer die Gruppe verlässt, nicht mehr. -- -- Ordner und Dateien gehören ab jetzt entweder einem Nutzer ODER einer Gruppe, -- nie beidem und nie keinem. Deshalb wird owner_id nullbar und bekommt eine -- CHECK-Bedingung als Gegengewicht – ohne die könnte ein Datensatz herrenlos -- werden und wäre über keine Abfrage mehr erreichbar. ALTER TABLE folders ALTER COLUMN owner_id DROP NOT NULL; ALTER TABLE files ALTER COLUMN owner_id DROP NOT NULL; ALTER TABLE folders ADD COLUMN group_id UUID REFERENCES groups(id) ON DELETE CASCADE; ALTER TABLE files ADD COLUMN group_id UUID REFERENCES groups(id) ON DELETE CASCADE; ALTER TABLE folders ADD CONSTRAINT folders_one_principal CHECK (num_nonnulls(owner_id, group_id) = 1); ALTER TABLE files ADD CONSTRAINT files_one_principal CHECK (num_nonnulls(owner_id, group_id) = 1); -- Gruppen bekommen ein eigenes Kontingent. Die Alternative – „zählt beim -- Ersteller" – wäre für die Mitglieder nicht nachvollziehbar: Der Ordner wäre -- plötzlich voll, weil jemand anders privat etwas hochgeladen hat. ALTER TABLE groups ADD COLUMN quota_bytes BIGINT NOT NULL DEFAULT 10737418240; -- Die bestehende UNIQUE (owner_id, parent_id, name) greift für Gruppenordner -- nicht: In SQL kollidiert NULL nicht mit NULL, zwei Gruppenordner gleichen -- Namens rutschten also durch. CREATE UNIQUE INDEX idx_folders_group_name ON folders (group_id, parent_id, name) WHERE group_id IS NOT NULL AND parent_id IS NOT NULL; -- Auf oberster Ebene ist parent_id NULL, das braucht einen eigenen Index. CREATE UNIQUE INDEX idx_folders_group_root_name ON folders (group_id, name) WHERE group_id IS NOT NULL AND parent_id IS NULL; CREATE INDEX idx_folders_group ON folders (group_id) WHERE group_id IS NOT NULL; CREATE INDEX idx_files_group ON files (group_id) WHERE group_id IS NOT NULL;