vectorizer_sdk/
utils.rs

1//! Essential utilities for the Vectorizer SDK
2
3use crate::error::{Result, VectorizerError};
4
5/// Input validation
6pub mod validation {
7    use super::*;
8
9    /// Validate that a string is not empty
10    pub fn validate_non_empty_string(value: &str, field_name: &str) -> Result<()> {
11        if value.trim().is_empty() {
12            return Err(VectorizerError::validation(format!(
13                "{} cannot be empty",
14                field_name
15            )));
16        }
17        Ok(())
18    }
19
20    /// Validate that a number is positive
21    pub fn validate_positive_number(value: f32, field_name: &str) -> Result<()> {
22        if value.is_nan() {
23            return Err(VectorizerError::validation(format!(
24                "{} must be a valid number, got NaN",
25                field_name
26            )));
27        }
28        if value.is_infinite() {
29            return Err(VectorizerError::validation(format!(
30                "{} must be a valid number, got infinity",
31                field_name
32            )));
33        }
34        if value <= 0.0 {
35            return Err(VectorizerError::validation(format!(
36                "{} must be positive, got {}",
37                field_name, value
38            )));
39        }
40        Ok(())
41    }
42
43    /// Validate that a number is non-negative
44    pub fn validate_non_negative_number(value: f32, field_name: &str) -> Result<()> {
45        if value < 0.0 {
46            return Err(VectorizerError::validation(format!(
47                "{} must be non-negative, got {}",
48                field_name, value
49            )));
50        }
51        Ok(())
52    }
53
54    /// Validate collection name
55    pub fn validate_collection_name(name: &str) -> Result<()> {
56        validate_non_empty_string(name, "collection name")?;
57
58        // Check for specific invalid characters first (for specific error messages)
59        if name.contains(' ') {
60            return Err(VectorizerError::validation(
61                "Collection name cannot contain spaces",
62            ));
63        }
64        if name.contains('/') {
65            return Err(VectorizerError::validation(
66                "Collection name cannot contain slashes",
67            ));
68        }
69        if name.contains('\\') {
70            return Err(VectorizerError::validation(
71                "Collection name cannot contain backslashes",
72            ));
73        }
74        if name.contains('@') {
75            return Err(VectorizerError::validation(
76                "Collection name cannot contain @ symbols",
77            ));
78        }
79
80        // Only allow alphanumeric characters, hyphens, and underscores
81        if !name
82            .chars()
83            .all(|c| c.is_alphanumeric() || c == '-' || c == '_')
84        {
85            return Err(VectorizerError::validation(
86                "Collection name can only contain alphanumeric characters, hyphens, and underscores",
87            ));
88        }
89
90        Ok(())
91    }
92
93    /// Validate vector ID
94    pub fn validate_vector_id(id: &str) -> Result<()> {
95        validate_non_empty_string(id, "vector ID")
96    }
97
98    /// Validate similarity metric
99    pub fn validate_similarity_metric(metric: &str) -> Result<()> {
100        match metric {
101            "cosine" | "euclidean" | "dot_product" => Ok(()),
102            _ => Err(VectorizerError::validation(format!(
103                "Invalid similarity metric: {}. Must be: cosine, euclidean, dot_product",
104                metric
105            ))),
106        }
107    }
108}
109
110/// Serialization utilities
111pub mod serialization {
112    use super::*;
113
114    /// Serialize value to JSON
115    pub fn to_json<T: serde::Serialize>(value: &T) -> Result<String> {
116        serde_json::to_string(value).map_err(VectorizerError::from)
117    }
118
119    /// Deserialize JSON to value
120    pub fn from_json<T: for<'de> serde::Deserialize<'de>>(json: &str) -> Result<T> {
121        serde_json::from_str(json).map_err(VectorizerError::from)
122    }
123}