use nutype::nutype;
use serde::{Deserialize, Serialize};
use crate::domain::metrics::constants;
#[nutype(
validate(greater_or_equal = 0, less_or_equal = 1000),
derive(
Debug,
Clone,
Copy,
PartialEq,
Eq,
PartialOrd,
Ord,
Serialize,
Deserialize,
Hash
)
)]
pub struct ModelCount(usize);
impl ModelCount {
pub fn none() -> Self {
Self::try_new(0).unwrap()
}
pub fn small_deployment() -> Self {
Self::try_new(3).unwrap()
}
pub fn medium_deployment() -> Self {
Self::try_new(10).unwrap()
}
pub fn large_deployment() -> Self {
Self::try_new(50).unwrap()
}
}
#[nutype(
validate(greater_or_equal = 0, less_or_equal = 10000),
derive(
Debug,
Clone,
Copy,
PartialEq,
Eq,
PartialOrd,
Ord,
Serialize,
Deserialize,
Hash
)
)]
pub struct ApplicationCount(usize);
impl ApplicationCount {
pub fn none() -> Self {
Self::try_new(0).unwrap()
}
pub fn small_team() -> Self {
Self::try_new(5).unwrap()
}
pub fn medium_organization() -> Self {
Self::try_new(25).unwrap()
}
pub fn large_enterprise() -> Self {
Self::try_new(100).unwrap()
}
}
#[nutype(
validate(greater_or_equal = 0),
derive(
Debug,
Clone,
Copy,
PartialEq,
Eq,
PartialOrd,
Ord,
Serialize,
Deserialize,
Hash
)
)]
pub struct DataPointCount(usize);
impl DataPointCount {
pub fn none() -> Self {
Self::try_new(0).unwrap()
}
pub fn limited() -> Self {
Self::try_new(100).unwrap()
}
pub fn moderate() -> Self {
Self::try_new(1000).unwrap()
}
pub fn large() -> Self {
Self::try_new(10000).unwrap()
}
pub fn very_large() -> Self {
Self::try_new(100000).unwrap()
}
pub fn is_sufficient_for_analysis(&self) -> bool {
self.into_inner() >= constants::statistical::MIN_SIGNIFICANT_SAMPLE_SIZE as usize
}
pub fn quality_level(&self) -> DataQuality {
let min_significant = constants::statistical::MIN_SIGNIFICANT_SAMPLE_SIZE as usize;
let recommended_min = constants::statistical::RECOMMENDED_MIN_SAMPLE_SIZE as usize;
let large_threshold = constants::statistical::LARGE_SAMPLE_THRESHOLD as usize;
match self.into_inner() {
0 => DataQuality::NoData,
n if n < min_significant => DataQuality::Insufficient,
n if n < recommended_min => DataQuality::Limited,
n if n < large_threshold => DataQuality::Good,
n if n < large_threshold * 10 => DataQuality::Excellent,
_ => DataQuality::Exceptional,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum DataQuality {
NoData,
Insufficient,
Limited,
Good,
Excellent,
Exceptional,
}
impl DataQuality {
pub fn confidence_description(&self) -> &'static str {
match self {
Self::NoData => "No data available",
Self::Insufficient => "Insufficient data for reliable analysis",
Self::Limited => "Limited data - use with caution",
Self::Good => "Good quality data - reliable for analysis",
Self::Excellent => "Excellent quality data - high confidence",
Self::Exceptional => "Exceptional quality data - very high confidence",
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_model_count_validation() {
assert!(ModelCount::try_new(0).is_ok());
assert!(ModelCount::try_new(100).is_ok());
assert!(ModelCount::try_new(1000).is_ok());
assert!(ModelCount::try_new(1001).is_err());
}
#[test]
fn test_application_count_validation() {
assert!(ApplicationCount::try_new(0).is_ok());
assert!(ApplicationCount::try_new(5000).is_ok());
assert!(ApplicationCount::try_new(10000).is_ok());
assert!(ApplicationCount::try_new(10001).is_err());
}
#[test]
fn test_data_point_count_validation() {
assert!(DataPointCount::try_new(0).is_ok());
assert!(DataPointCount::try_new(usize::MAX).is_ok());
}
#[test]
fn test_data_quality_levels() {
assert_eq!(
DataPointCount::try_new(0).unwrap().quality_level(),
DataQuality::NoData
);
assert_eq!(
DataPointCount::try_new(15).unwrap().quality_level(),
DataQuality::Insufficient
);
assert_eq!(
DataPointCount::try_new(50).unwrap().quality_level(),
DataQuality::Limited
);
assert_eq!(
DataPointCount::try_new(500).unwrap().quality_level(),
DataQuality::Good
);
}
#[test]
fn test_sufficient_for_analysis() {
assert!(!DataPointCount::try_new(10)
.unwrap()
.is_sufficient_for_analysis());
assert!(DataPointCount::try_new(50)
.unwrap()
.is_sufficient_for_analysis());
}
}