pub mod types;
pub use types::{ExperienceRelation, NewExperienceRelation, RelationDirection, RelationType};
use crate::error::{PulseDBError, ValidationError};
use crate::storage::schema::MAX_RELATION_METADATA_SIZE;
pub(crate) fn validate_new_relation(rel: &NewExperienceRelation) -> Result<(), PulseDBError> {
if rel.source_id == rel.target_id {
return Err(ValidationError::invalid_field(
"target_id",
"cannot create a self-relation (source_id == target_id)",
)
.into());
}
if !(0.0..=1.0).contains(&rel.strength) {
return Err(ValidationError::invalid_field(
"strength",
format!("must be between 0.0 and 1.0, got {}", rel.strength),
)
.into());
}
if let Some(ref metadata) = rel.metadata {
if metadata.len() > MAX_RELATION_METADATA_SIZE {
return Err(ValidationError::content_too_large(
metadata.len(),
MAX_RELATION_METADATA_SIZE,
)
.into());
}
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
use crate::types::ExperienceId;
fn valid_new_relation() -> NewExperienceRelation {
NewExperienceRelation {
source_id: ExperienceId::new(),
target_id: ExperienceId::new(),
relation_type: RelationType::Supports,
strength: 0.8,
metadata: None,
}
}
#[test]
fn test_valid_relation_passes() {
let rel = valid_new_relation();
assert!(validate_new_relation(&rel).is_ok());
}
#[test]
fn test_self_relation_rejected() {
let id = ExperienceId::new();
let rel = NewExperienceRelation {
source_id: id,
target_id: id, relation_type: RelationType::Supports,
strength: 0.5,
metadata: None,
};
let err = validate_new_relation(&rel).unwrap_err();
assert!(err.is_validation());
assert!(err.to_string().contains("self-relation"));
}
#[test]
fn test_strength_below_zero_rejected() {
let mut rel = valid_new_relation();
rel.strength = -0.1;
let err = validate_new_relation(&rel).unwrap_err();
assert!(err.is_validation());
assert!(err.to_string().contains("strength"));
}
#[test]
fn test_strength_above_one_rejected() {
let mut rel = valid_new_relation();
rel.strength = 1.1;
let err = validate_new_relation(&rel).unwrap_err();
assert!(err.is_validation());
}
#[test]
fn test_strength_boundary_values() {
let mut rel = valid_new_relation();
rel.strength = 0.0;
assert!(validate_new_relation(&rel).is_ok());
rel.strength = 1.0;
assert!(validate_new_relation(&rel).is_ok());
}
#[test]
fn test_metadata_too_large_rejected() {
let mut rel = valid_new_relation();
rel.metadata = Some("x".repeat(MAX_RELATION_METADATA_SIZE + 1));
let err = validate_new_relation(&rel).unwrap_err();
assert!(err.is_validation());
assert!(err.to_string().contains("too large"));
}
#[test]
fn test_metadata_at_limit_passes() {
let mut rel = valid_new_relation();
rel.metadata = Some("x".repeat(MAX_RELATION_METADATA_SIZE));
assert!(validate_new_relation(&rel).is_ok());
}
}