-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmigrate.sql
More file actions
122 lines (108 loc) · 3.91 KB
/
migrate.sql
File metadata and controls
122 lines (108 loc) · 3.91 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
-- Migration: create full database schema
-- Run with: psql earlytech < migrate.sql
BEGIN;
-- Extensions
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
CREATE EXTENSION IF NOT EXISTS vector;
-- Articles (scrapper columns + Rust alias columns)
CREATE TABLE IF NOT EXISTS articles (
id TEXT PRIMARY KEY,
source_site TEXT NOT NULL,
title TEXT,
description TEXT,
full_content TEXT,
content_hash TEXT UNIQUE,
author_info TEXT,
keywords TEXT,
content_url TEXT NOT NULL,
published_date TIMESTAMPTZ,
item_type TEXT,
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
primary_subject TEXT,
secondary_subject TEXT,
primary_organizations JSONB,
secondary_organizations JSONB,
primary_event_type TEXT,
secondary_event_type TEXT,
cluster_id INTEGER,
-- Rust server alias columns
url TEXT,
source TEXT,
summary TEXT,
authors TEXT[],
content TEXT,
scraped_at TIMESTAMPTZ
);
-- Embeddings
CREATE TABLE IF NOT EXISTS embeddings (
id SERIAL PRIMARY KEY,
article_id TEXT NOT NULL UNIQUE REFERENCES articles(id) ON DELETE CASCADE,
embedding vector(1536) NOT NULL,
embedding_model TEXT,
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX IF NOT EXISTS idx_cluster_id ON articles(cluster_id);
-- Users (UUID, auth-ready)
DROP TABLE IF EXISTS user_article_delivery CASCADE;
DROP TABLE IF EXISTS user_keyword_embeddings CASCADE;
DROP TABLE IF EXISTS user_keywords CASCADE;
DROP TABLE IF EXISTS users CASCADE;
CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
name TEXT NOT NULL,
email TEXT NOT NULL UNIQUE,
password_hash TEXT NOT NULL DEFAULT '',
role TEXT NOT NULL DEFAULT 'user',
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
);
-- User keywords
CREATE TABLE user_keywords (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
keyword TEXT NOT NULL,
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
UNIQUE(user_id, keyword)
);
-- Keyword embeddings
CREATE TABLE user_keyword_embeddings (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
keyword_id UUID NOT NULL UNIQUE REFERENCES user_keywords(id) ON DELETE CASCADE,
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
keyword TEXT NOT NULL,
embedding vector(1536) NOT NULL,
embedding_model TEXT,
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
);
-- Article delivery
CREATE TABLE user_article_delivery (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
article_id TEXT NOT NULL REFERENCES articles(id) ON DELETE CASCADE,
keyword_id UUID REFERENCES user_keywords(id) ON DELETE SET NULL,
similarity_score FLOAT NOT NULL,
delivered_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
UNIQUE(user_id, article_id)
);
-- Indexes
CREATE INDEX IF NOT EXISTS idx_user_keywords ON user_keywords(user_id);
CREATE INDEX IF NOT EXISTS idx_keyword_embeddings ON user_keyword_embeddings(user_id);
CREATE INDEX IF NOT EXISTS idx_user_article_delivery ON user_article_delivery(user_id);
-- Trigger: auto-populate Rust alias columns on article insert/update
CREATE OR REPLACE FUNCTION sync_article_aliases() RETURNS TRIGGER AS $$
BEGIN
NEW.url := COALESCE(NEW.url, NEW.content_url);
NEW.source := COALESCE(NEW.source, NEW.source_site);
NEW.summary := COALESCE(NEW.summary, NEW.description);
NEW.content := COALESCE(NEW.content, NEW.full_content);
NEW.scraped_at := COALESCE(NEW.scraped_at, NEW.created_at, CURRENT_TIMESTAMP);
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
DROP TRIGGER IF EXISTS trg_sync_article_aliases ON articles;
CREATE TRIGGER trg_sync_article_aliases
BEFORE INSERT OR UPDATE ON articles
FOR EACH ROW
EXECUTE FUNCTION sync_article_aliases();
COMMIT;