Files
gupi-osint-board/migrations/004_folders_and_publication_time.sql
T
2026-08-14 12:43:11 +02:00

57 lines
2.8 KiB
SQL

-- Widget kinds are intentionally data-driven. Removing enum-like checks means
-- future widget types do not require a table rewrite merely to exist.
ALTER TABLE osint.widgets DROP CONSTRAINT IF EXISTS widgets_widget_type_check;
ALTER TABLE osint.playthrough_widgets DROP CONSTRAINT IF EXISTS playthrough_widgets_widget_type_check;
ALTER TABLE osint.widgets ADD COLUMN published_at TIMESTAMPTZ;
UPDATE osint.widgets
SET published_at = event_date::timestamp AT TIME ZONE 'UTC'
WHERE widget_type = 'document' AND event_date IS NOT NULL;
CREATE TABLE osint.widget_relations (
id TEXT PRIMARY KEY,
level_id TEXT NOT NULL REFERENCES osint.levels(id) ON DELETE CASCADE,
from_widget_id TEXT NOT NULL REFERENCES osint.widgets(id) ON DELETE CASCADE,
to_widget_id TEXT NOT NULL REFERENCES osint.widgets(id) ON DELETE CASCADE,
relation_type TEXT NOT NULL,
sort_order INTEGER NOT NULL DEFAULT 0,
config JSONB NOT NULL DEFAULT '{}'::jsonb,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
UNIQUE (from_widget_id, to_widget_id, relation_type)
);
CREATE INDEX widget_relations_from_idx ON osint.widget_relations(level_id, from_widget_id, relation_type);
CREATE INDEX widget_relations_to_idx ON osint.widget_relations(level_id, to_widget_id, relation_type);
CREATE TABLE osint.playthrough_widget_relations (
id TEXT PRIMARY KEY,
playthrough_id TEXT NOT NULL REFERENCES osint.playthroughs(id) ON DELETE CASCADE,
from_widget_id TEXT NOT NULL,
to_widget_id TEXT NOT NULL,
relation_type TEXT NOT NULL,
sort_order INTEGER NOT NULL DEFAULT 0,
config JSONB NOT NULL DEFAULT '{}'::jsonb,
UNIQUE (playthrough_id, from_widget_id, to_widget_id, relation_type)
);
UPDATE osint.widgets SET widget_type = 'folder' WHERE widget_type = 'evidence';
UPDATE osint.playthrough_widgets SET widget_type = 'folder' WHERE widget_type = 'evidence';
INSERT INTO osint.widget_relations (id, level_id, from_widget_id, to_widget_id, relation_type)
SELECT 'contains:' || id || ':' || source_widget_id, level_id, id, source_widget_id, 'contains'
FROM osint.widgets
WHERE widget_type = 'folder' AND source_widget_id IS NOT NULL
ON CONFLICT (from_widget_id, to_widget_id, relation_type) DO NOTHING;
INSERT INTO osint.playthrough_widget_relations
(id, playthrough_id, from_widget_id, to_widget_id, relation_type)
SELECT 'contains:' || playthrough_id || ':' || id || ':' || source_widget_id,
playthrough_id, id, source_widget_id, 'contains'
FROM osint.playthrough_widgets
WHERE widget_type = 'folder' AND source_widget_id IS NOT NULL
ON CONFLICT (playthrough_id, from_widget_id, to_widget_id, relation_type) DO NOTHING;
COMMENT ON COLUMN osint.widgets.published_at IS 'Publication/creation time of a source document; chronology belongs to documents, not folders';
COMMENT ON TABLE osint.widget_relations IS 'Generic authored widget graph; contains is the first relation type';