lc_vector_stores/
pgvector.rs1use std::sync::LazyLock;
18
19use regex::Regex;
20
21use crate::VectorStoreError;
22
23static TABLE_NAME_RE: LazyLock<Regex> =
24 LazyLock::new(|| Regex::new(r"^[a-zA-Z_][a-zA-Z0-9_]*$").unwrap());
25
26pub fn validate_table_name(table: &str) -> Result<(), VectorStoreError> {
31 if TABLE_NAME_RE.is_match(table) {
32 Ok(())
33 } else {
34 Err(VectorStoreError::ConfigError(format!(
35 "Invalid table name '{}': must match ^[a-zA-Z_][a-zA-Z0-9_]*$",
36 table
37 )))
38 }
39}
40
41pub fn build_table_sql(table: &str, dim: usize) -> String {
43 format!(
44 "CREATE TABLE IF NOT EXISTS {} (id TEXT PRIMARY KEY, content TEXT, metadata JSONB, embedding vector({}))",
45 table, dim
46 )
47}
48
49#[cfg(test)]
50mod tests {
51 use super::*;
52
53 #[test]
54 fn test_build_table_sql() {
55 let sql = build_table_sql("docs", 1536);
56 assert!(sql.contains("CREATE TABLE"));
57 assert!(sql.contains("vector(1536)"));
58 assert!(sql.contains("docs"));
59 }
60
61 #[test]
62 fn test_build_table_sql_different_dim() {
63 let sql = build_table_sql("embeddings", 768);
64 assert!(sql.contains("vector(768)"));
65 assert!(sql.contains("embeddings"));
66 }
67
68 #[test]
69 fn test_build_table_sql_contains_metadata() {
70 let sql = build_table_sql("docs", 1536);
71 assert!(sql.contains("metadata JSONB"));
72 assert!(sql.contains("id TEXT PRIMARY KEY"));
73 }
74
75 #[test]
76 fn test_validate_table_name_valid() {
77 assert!(validate_table_name("users").is_ok());
78 assert!(validate_table_name("my_table").is_ok());
79 assert!(validate_table_name("_private").is_ok());
80 assert!(validate_table_name("Table123").is_ok());
81 }
82
83 #[test]
84 fn test_validate_table_name_invalid() {
85 assert!(validate_table_name("users; DROP TABLE users--").is_err());
87 assert!(validate_table_name("users; DROP TABLE users").is_err());
88 assert!(validate_table_name("123table").is_err()); assert!(validate_table_name("user-table").is_err()); assert!(validate_table_name("user.table").is_err()); assert!(validate_table_name("").is_err()); }
93}