sqlite_knowledge_graph/
schema.rs1use rusqlite::Connection;
4
5use crate::error::Result;
6
7pub fn create_schema(conn: &Connection) -> Result<()> {
9 let tx = conn.unchecked_transaction()?;
10
11 tx.execute(
13 r#"
14 CREATE TABLE IF NOT EXISTS kg_entities (
15 id INTEGER PRIMARY KEY AUTOINCREMENT,
16 entity_type TEXT NOT NULL,
17 name TEXT NOT NULL,
18 properties TEXT, -- JSON
19 created_at INTEGER DEFAULT (strftime('%s', 'now')),
20 updated_at INTEGER DEFAULT (strftime('%s', 'now'))
21 )
22 "#,
23 [],
24 )?;
25
26 tx.execute(
28 r#"
29 CREATE TABLE IF NOT EXISTS kg_relations (
30 id INTEGER PRIMARY KEY AUTOINCREMENT,
31 source_id INTEGER NOT NULL,
32 target_id INTEGER NOT NULL,
33 rel_type TEXT NOT NULL,
34 weight REAL DEFAULT 1.0,
35 properties TEXT, -- JSON
36 created_at INTEGER DEFAULT (strftime('%s', 'now')),
37 FOREIGN KEY (source_id) REFERENCES kg_entities(id) ON DELETE CASCADE,
38 FOREIGN KEY (target_id) REFERENCES kg_entities(id) ON DELETE CASCADE
39 )
40 "#,
41 [],
42 )?;
43
44 tx.execute(
46 r#"
47 CREATE TABLE IF NOT EXISTS kg_vectors (
48 entity_id INTEGER NOT NULL PRIMARY KEY,
49 vector BLOB NOT NULL,
50 dimension INTEGER NOT NULL,
51 created_at INTEGER DEFAULT (strftime('%s', 'now')),
52 FOREIGN KEY (entity_id) REFERENCES kg_entities(id) ON DELETE CASCADE
53 )
54 "#,
55 [],
56 )?;
57
58 tx.execute(
60 "CREATE INDEX IF NOT EXISTS idx_entities_type ON kg_entities(entity_type)",
61 [],
62 )?;
63
64 tx.execute(
65 "CREATE INDEX IF NOT EXISTS idx_entities_name ON kg_entities(name)",
66 [],
67 )?;
68
69 tx.execute(
70 "CREATE INDEX IF NOT EXISTS idx_relations_source ON kg_relations(source_id)",
71 [],
72 )?;
73
74 tx.execute(
75 "CREATE INDEX IF NOT EXISTS idx_relations_target ON kg_relations(target_id)",
76 [],
77 )?;
78
79 tx.execute(
80 "CREATE INDEX IF NOT EXISTS idx_relations_type ON kg_relations(rel_type)",
81 [],
82 )?;
83
84 tx.execute(
86 r#"
87 CREATE TABLE IF NOT EXISTS kg_hyperedges (
88 id INTEGER PRIMARY KEY AUTOINCREMENT,
89 hyperedge_type TEXT NOT NULL,
90 entity_ids TEXT NOT NULL,
91 weight REAL DEFAULT 1.0,
92 arity INTEGER NOT NULL,
93 properties TEXT,
94 created_at INTEGER DEFAULT (strftime('%s', 'now')),
95 updated_at INTEGER DEFAULT (strftime('%s', 'now'))
96 )
97 "#,
98 [],
99 )?;
100
101 tx.execute(
103 r#"
104 CREATE TABLE IF NOT EXISTS kg_hyperedge_entities (
105 hyperedge_id INTEGER NOT NULL,
106 entity_id INTEGER NOT NULL,
107 position INTEGER NOT NULL,
108 PRIMARY KEY (hyperedge_id, entity_id),
109 FOREIGN KEY (hyperedge_id) REFERENCES kg_hyperedges(id) ON DELETE CASCADE,
110 FOREIGN KEY (entity_id) REFERENCES kg_entities(id) ON DELETE CASCADE
111 )
112 "#,
113 [],
114 )?;
115
116 tx.execute(
118 "CREATE INDEX IF NOT EXISTS idx_hyperedges_type ON kg_hyperedges(hyperedge_type)",
119 [],
120 )?;
121 tx.execute(
122 "CREATE INDEX IF NOT EXISTS idx_hyperedges_arity ON kg_hyperedges(arity)",
123 [],
124 )?;
125 tx.execute(
126 "CREATE INDEX IF NOT EXISTS idx_he_entities_entity ON kg_hyperedge_entities(entity_id)",
127 [],
128 )?;
129 tx.execute(
130 "CREATE INDEX IF NOT EXISTS idx_he_entities_hyperedge ON kg_hyperedge_entities(hyperedge_id)",
131 [],
132 )?;
133
134 tx.commit()?;
135 Ok(())
136}
137
138pub fn schema_exists(conn: &Connection) -> Result<bool> {
140 let mut stmt = conn
141 .prepare("SELECT COUNT(*) FROM sqlite_master WHERE type='table' AND name='kg_entities'")?;
142 let count: i64 = stmt.query_row([], |row| row.get(0))?;
143 Ok(count > 0)
144}