1use std::time::Duration;
4use serde::{Deserialize, Serialize};
5
6#[derive(Debug, Clone, Serialize, Deserialize)]
8pub struct PostgresConfig {
9 pub database_url: String,
11
12 pub pool: PoolConfig,
14
15 pub table: TableConfig,
17
18 pub performance: PerformanceConfig,
20}
21
22#[derive(Debug, Clone, Serialize, Deserialize)]
24pub struct PoolConfig {
25 pub max_connections: u32,
27
28 pub min_connections: u32,
30
31 pub connect_timeout: Duration,
33
34 pub idle_timeout: Option<Duration>,
36
37 pub max_lifetime: Option<Duration>,
39}
40
41#[derive(Debug, Clone, Serialize, Deserialize)]
43pub struct TableConfig {
44 pub schema: String,
46
47 pub table_prefix: Option<String>,
49
50 pub auto_create_tables: bool,
52
53 pub auto_create_indexes: bool,
55}
56
57#[derive(Debug, Clone, Serialize, Deserialize)]
59pub struct PerformanceConfig {
60 pub batch_size: usize,
62
63 pub index_type: VectorIndexType,
65
66 pub index_params: IndexParams,
68
69 pub use_prepared_statements: bool,
71}
72
73#[derive(Debug, Clone, Serialize, Deserialize)]
75pub enum VectorIndexType {
76 IvfFlat,
78 Hnsw,
80 None,
82}
83
84#[derive(Debug, Clone, Serialize, Deserialize)]
86pub struct IndexParams {
87 pub ivf_flat: IvfFlatParams,
89
90 pub hnsw: HnswParams,
92}
93
94#[derive(Debug, Clone, Serialize, Deserialize)]
96pub struct IvfFlatParams {
97 pub lists: u32,
99
100 pub probes: u32,
102}
103
104#[derive(Debug, Clone, Serialize, Deserialize)]
106pub struct HnswParams {
107 pub m: u32,
109
110 pub ef_construction: u32,
112
113 pub ef_search: u32,
115}
116
117impl Default for PostgresConfig {
118 fn default() -> Self {
119 Self {
120 database_url: "postgresql://localhost/lumos_vector".to_string(),
121 pool: PoolConfig::default(),
122 table: TableConfig::default(),
123 performance: PerformanceConfig::default(),
124 }
125 }
126}
127
128impl Default for PoolConfig {
129 fn default() -> Self {
130 Self {
131 max_connections: 10,
132 min_connections: 1,
133 connect_timeout: Duration::from_secs(30),
134 idle_timeout: Some(Duration::from_secs(600)),
135 max_lifetime: Some(Duration::from_secs(1800)),
136 }
137 }
138}
139
140impl Default for TableConfig {
141 fn default() -> Self {
142 Self {
143 schema: "public".to_string(),
144 table_prefix: Some("lumos_".to_string()),
145 auto_create_tables: true,
146 auto_create_indexes: true,
147 }
148 }
149}
150
151impl Default for PerformanceConfig {
152 fn default() -> Self {
153 Self {
154 batch_size: 1000,
155 index_type: VectorIndexType::Hnsw,
156 index_params: IndexParams::default(),
157 use_prepared_statements: true,
158 }
159 }
160}
161
162impl Default for IndexParams {
163 fn default() -> Self {
164 Self {
165 ivf_flat: IvfFlatParams::default(),
166 hnsw: HnswParams::default(),
167 }
168 }
169}
170
171impl Default for IvfFlatParams {
172 fn default() -> Self {
173 Self {
174 lists: 100,
175 probes: 10,
176 }
177 }
178}
179
180impl Default for HnswParams {
181 fn default() -> Self {
182 Self {
183 m: 16,
184 ef_construction: 64,
185 ef_search: 40,
186 }
187 }
188}
189
190impl PostgresConfig {
191 pub fn new(database_url: impl Into<String>) -> Self {
193 Self {
194 database_url: database_url.into(),
195 ..Default::default()
196 }
197 }
198
199 pub fn with_pool(mut self, pool: PoolConfig) -> Self {
201 self.pool = pool;
202 self
203 }
204
205 pub fn with_table(mut self, table: TableConfig) -> Self {
207 self.table = table;
208 self
209 }
210
211 pub fn with_performance(mut self, performance: PerformanceConfig) -> Self {
213 self.performance = performance;
214 self
215 }
216
217 pub fn table_name(&self, name: &str) -> String {
219 let prefix = self.table.table_prefix.as_deref().unwrap_or("");
220 format!("{}.{}{}", self.table.schema, prefix, name)
221 }
222
223 pub fn index_name(&self, table_name: &str, index_type: &str) -> String {
225 let prefix = self.table.table_prefix.as_deref().unwrap_or("");
226 format!("{}{}_{}_idx", prefix, table_name, index_type)
227 }
228}
229
230impl VectorIndexType {
231 pub fn create_index_sql(&self, table_name: &str, index_name: &str, params: &IndexParams) -> String {
233 match self {
234 VectorIndexType::IvfFlat => {
235 format!(
236 "CREATE INDEX {} ON {} USING ivfflat (embedding vector_cosine_ops) WITH (lists = {})",
237 index_name, table_name, params.ivf_flat.lists
238 )
239 },
240 VectorIndexType::Hnsw => {
241 format!(
242 "CREATE INDEX {} ON {} USING hnsw (embedding vector_cosine_ops) WITH (m = {}, ef_construction = {})",
243 index_name, table_name, params.hnsw.m, params.hnsw.ef_construction
244 )
245 },
246 VectorIndexType::None => String::new(),
247 }
248 }
249
250 pub fn search_params_sql(&self, params: &IndexParams) -> Vec<String> {
252 match self {
253 VectorIndexType::IvfFlat => {
254 vec![format!("SET ivfflat.probes = {}", params.ivf_flat.probes)]
255 },
256 VectorIndexType::Hnsw => {
257 vec![format!("SET hnsw.ef_search = {}", params.hnsw.ef_search)]
258 },
259 VectorIndexType::None => vec![],
260 }
261 }
262}