use std::time::Duration;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PostgresConfig {
pub database_url: String,
pub pool: PoolConfig,
pub table: TableConfig,
pub performance: PerformanceConfig,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PoolConfig {
pub max_connections: u32,
pub min_connections: u32,
pub connect_timeout: Duration,
pub idle_timeout: Option<Duration>,
pub max_lifetime: Option<Duration>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TableConfig {
pub schema: String,
pub table_prefix: Option<String>,
pub auto_create_tables: bool,
pub auto_create_indexes: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PerformanceConfig {
pub batch_size: usize,
pub index_type: VectorIndexType,
pub index_params: IndexParams,
pub use_prepared_statements: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum VectorIndexType {
IvfFlat,
Hnsw,
None,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct IndexParams {
pub ivf_flat: IvfFlatParams,
pub hnsw: HnswParams,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct IvfFlatParams {
pub lists: u32,
pub probes: u32,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HnswParams {
pub m: u32,
pub ef_construction: u32,
pub ef_search: u32,
}
impl Default for PostgresConfig {
fn default() -> Self {
Self {
database_url: "postgresql://localhost/lumos_vector".to_string(),
pool: PoolConfig::default(),
table: TableConfig::default(),
performance: PerformanceConfig::default(),
}
}
}
impl Default for PoolConfig {
fn default() -> Self {
Self {
max_connections: 10,
min_connections: 1,
connect_timeout: Duration::from_secs(30),
idle_timeout: Some(Duration::from_secs(600)),
max_lifetime: Some(Duration::from_secs(1800)),
}
}
}
impl Default for TableConfig {
fn default() -> Self {
Self {
schema: "public".to_string(),
table_prefix: Some("lumos_".to_string()),
auto_create_tables: true,
auto_create_indexes: true,
}
}
}
impl Default for PerformanceConfig {
fn default() -> Self {
Self {
batch_size: 1000,
index_type: VectorIndexType::Hnsw,
index_params: IndexParams::default(),
use_prepared_statements: true,
}
}
}
impl Default for IndexParams {
fn default() -> Self {
Self {
ivf_flat: IvfFlatParams::default(),
hnsw: HnswParams::default(),
}
}
}
impl Default for IvfFlatParams {
fn default() -> Self {
Self {
lists: 100,
probes: 10,
}
}
}
impl Default for HnswParams {
fn default() -> Self {
Self {
m: 16,
ef_construction: 64,
ef_search: 40,
}
}
}
impl PostgresConfig {
pub fn new(database_url: impl Into<String>) -> Self {
Self {
database_url: database_url.into(),
..Default::default()
}
}
pub fn with_pool(mut self, pool: PoolConfig) -> Self {
self.pool = pool;
self
}
pub fn with_table(mut self, table: TableConfig) -> Self {
self.table = table;
self
}
pub fn with_performance(mut self, performance: PerformanceConfig) -> Self {
self.performance = performance;
self
}
pub fn table_name(&self, name: &str) -> String {
let prefix = self.table.table_prefix.as_deref().unwrap_or("");
format!("{}.{}{}", self.table.schema, prefix, name)
}
pub fn index_name(&self, table_name: &str, index_type: &str) -> String {
let prefix = self.table.table_prefix.as_deref().unwrap_or("");
format!("{}{}_{}_idx", prefix, table_name, index_type)
}
}
impl VectorIndexType {
pub fn create_index_sql(&self, table_name: &str, index_name: &str, params: &IndexParams) -> String {
match self {
VectorIndexType::IvfFlat => {
format!(
"CREATE INDEX {} ON {} USING ivfflat (embedding vector_cosine_ops) WITH (lists = {})",
index_name, table_name, params.ivf_flat.lists
)
},
VectorIndexType::Hnsw => {
format!(
"CREATE INDEX {} ON {} USING hnsw (embedding vector_cosine_ops) WITH (m = {}, ef_construction = {})",
index_name, table_name, params.hnsw.m, params.hnsw.ef_construction
)
},
VectorIndexType::None => String::new(),
}
}
pub fn search_params_sql(&self, params: &IndexParams) -> Vec<String> {
match self {
VectorIndexType::IvfFlat => {
vec![format!("SET ivfflat.probes = {}", params.ivf_flat.probes)]
},
VectorIndexType::Hnsw => {
vec![format!("SET hnsw.ef_search = {}", params.hnsw.ef_search)]
},
VectorIndexType::None => vec![],
}
}
}