diff --git a/migrations/0001_initial_schema.sql b/migrations/0001_initial_schema.sql index edda65c77..041a452da 100644 --- a/migrations/0001_initial_schema.sql +++ b/migrations/0001_initial_schema.sql @@ -195,6 +195,15 @@ CREATE TABLE events ( kind INT NOT NULL, tags JSONB NOT NULL, content TEXT NOT NULL, + -- Full-text search vector (Typesense → Postgres FTS). Generated/STORED so + -- it is a single source of truth — no sidecar indexer to keep coherent + -- (Quinn option A, Lane-0 call). 'simple' config = no stemming/stopwords, + -- matching the existing substring-ish search semantics; the search lane can + -- revisit the config behind evidence. Tenant scoping is by the + -- community-leading btree filters BitmapAnd-ed with the GIN probe, so the + -- GIN index itself stays the minimal `GIN (search_tsv)` (Max's caveat: + -- avoid btree_gin unless EXPLAIN proves it buys something). + search_tsv TSVECTOR GENERATED ALWAYS AS (to_tsvector('simple', content)) STORED, sig BYTEA NOT NULL, received_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), channel_id UUID, @@ -242,6 +251,11 @@ CREATE INDEX idx_events_parameterized WHERE d_tag IS NOT NULL AND deleted_at IS NULL; CREATE INDEX idx_events_not_before ON events (community_id, not_before) WHERE not_before IS NOT NULL AND deleted_at IS NULL AND delivered_at IS NULL; +-- Full-text search. Minimal GIN over the generated tsvector; community scoping +-- is supplied by the community-leading btree filters above (BitmapAnd), so this +-- stays a single-column GIN. The search lane confirms the final spelling with +-- EXPLAIN before its work lands (Quinn option A; Max's index-spelling caveat). +CREATE INDEX idx_events_search_tsv ON events USING GIN (search_tsv); -- ── Event mentions ──────────────────────────────────────────────────────────── -- Conformance: "Channel-less global events and DMs" (#p fan-out). The join to diff --git a/migrations/0002_backfill_d_tag.sql b/migrations/0002_backfill_d_tag.sql deleted file mode 100644 index 74301271f..000000000 --- a/migrations/0002_backfill_d_tag.sql +++ /dev/null @@ -1,17 +0,0 @@ --- Backfill d_tag for existing NIP-33 range events (kind 30000–39999). --- Idempotent: only updates rows where d_tag is still NULL. --- Includes soft-deleted rows so the column is fully populated. --- Run once after adding the d_tag column to the events table. --- --- Managed by sqlx migrations. - -UPDATE events -SET d_tag = COALESCE( - (SELECT elem->>1 - FROM jsonb_array_elements(tags) AS elem - WHERE elem->>0 = 'd' - LIMIT 1), - '' -) -WHERE kind BETWEEN 30000 AND 39999 - AND d_tag IS NULL; diff --git a/migrations/0003_event_reminders.sql b/migrations/0003_event_reminders.sql deleted file mode 100644 index 846928c30..000000000 --- a/migrations/0003_event_reminders.sql +++ /dev/null @@ -1,17 +0,0 @@ --- Add NIP-ER event-reminder columns and due-delivery index to the events table. --- --- `not_before` is the reminder's scheduled delivery time (Unix seconds); --- `delivered_at` records when the scheduler published it. Both are nullable — --- non-reminder events leave them NULL. The partial index covers only --- undelivered, live reminders so the scheduler's due-query stays cheap. --- --- `events` is partitioned by RANGE (created_at); ALTER TABLE on the parent --- cascades the columns to every partition, and CREATE INDEX on the parent --- builds a partitioned index that propagates to each partition. --- --- Managed by sqlx migrations. - -ALTER TABLE events ADD COLUMN not_before BIGINT; -ALTER TABLE events ADD COLUMN delivered_at BIGINT; -CREATE INDEX idx_events_not_before ON events (not_before) - WHERE not_before IS NOT NULL AND deleted_at IS NULL AND delivered_at IS NULL;