rjango 0.1.1

A full-stack Rust backend framework inspired by Django
Documentation
use base64::{Engine as _, engine::general_purpose::STANDARD};

use crate::core::validators::ValidationError;

use super::FieldType;

pub fn validate_binary_field(
    value: &[u8],
    max_length: Option<usize>,
) -> Result<(), ValidationError> {
    if let Some(max_length) = max_length
        && value.len() > max_length
    {
        return Err(ValidationError::new(
            "Ensure this value has at most {limit_value} bytes.",
            "max_length",
        )
        .with_param("limit_value", max_length.to_string())
        .with_param("show_value", value.len().to_string()));
    }

    Ok(())
}

#[must_use]
pub fn to_vec(value: &[u8]) -> Vec<u8> {
    value.to_vec()
}

#[must_use]
pub fn db_type(field: &FieldType, vendor: &str) -> Option<String> {
    match field {
        FieldType::Binary => Some(match vendor {
            "postgres" => "bytea".to_string(),
            "mysql" => "longblob".to_string(),
            _ => "blob".to_string(),
        }),
        _ => None,
    }
}

pub fn get_prep_value(value: &[u8]) -> Result<String, ValidationError> {
    validate_binary_field(value, None)?;
    Ok(STANDARD.encode(value))
}

pub fn from_db_value(value: &str) -> Result<Vec<u8>, ValidationError> {
    STANDARD.decode(value).map_err(|_| {
        ValidationError::new("Enter a valid base64-encoded binary value.", "invalid")
            .with_param("value", value)
    })
}

#[must_use]
pub fn formfield(field: &FieldType) -> Option<&'static str> {
    match field {
        FieldType::Binary => None,
        _ => None,
    }
}

#[cfg(test)]
mod tests {
    use super::{FieldType, db_type, formfield, from_db_value, get_prep_value};

    #[test]
    fn db_type_for_postgres_uses_bytea() {
        assert_eq!(
            db_type(&FieldType::Binary, "postgres").as_deref(),
            Some("bytea")
        );
    }

    #[test]
    fn get_prep_value_encodes_base64() {
        let prepared = get_prep_value(b"hello").expect("binary preparation should base64 encode");
        assert_eq!(prepared, "aGVsbG8=");
    }

    #[test]
    fn from_db_value_decodes_base64() {
        let parsed = from_db_value("aGVsbG8=").expect("base64 storage should decode");
        assert_eq!(parsed, b"hello");
    }

    #[test]
    fn formfield_is_not_available_for_binary() {
        assert_eq!(formfield(&FieldType::Binary), None);
    }
}