rjango 0.1.1

A full-stack Rust backend framework inspired by Django
Documentation
use std::path::Path;

use crate::core::validators::{
    FileExtensionValidator, ProhibitNullCharactersValidator, ValidationError, Validator,
};

use super::FieldType;

pub fn validate_file_field(
    path: &Path,
    allowed_extensions: Option<&[&str]>,
) -> Result<(), ValidationError> {
    let rendered = path.display().to_string();
    if rendered.is_empty() {
        return Err(ValidationError::new(
            "File paths cannot be empty.",
            "required",
        ));
    }

    ProhibitNullCharactersValidator::default().validate(&rendered)?;

    if let Some(allowed_extensions) = allowed_extensions {
        FileExtensionValidator::new(allowed_extensions.iter().copied()).validate(&path)?;
    }

    Ok(())
}

#[must_use]
pub fn upload_to_path(upload_to: &str, filename: &str) -> String {
    let base = upload_to.trim_end_matches('/');
    if base.is_empty() {
        filename.to_string()
    } else {
        format!("{base}/{filename}")
    }
}

#[must_use]
pub fn db_type(field: &FieldType, vendor: &str) -> Option<String> {
    let _ = vendor;

    match field {
        FieldType::File { .. } | FieldType::Image { .. } | FieldType::FilePath { .. } => {
            Some("varchar(100)".to_string())
        }
        _ => None,
    }
}

pub fn get_prep_value(value: &str) -> Result<String, ValidationError> {
    let path = Path::new(value);
    validate_file_field(path, None)?;
    Ok(path.display().to_string())
}

pub fn from_db_value(value: &str) -> Result<String, ValidationError> {
    get_prep_value(value)
}

#[must_use]
pub fn formfield(field: &FieldType) -> Option<&'static str> {
    match field {
        FieldType::File { .. } => Some("FileField"),
        FieldType::Image { .. } => Some("ImageField"),
        FieldType::FilePath { .. } => Some("FilePathField"),
        _ => None,
    }
}

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

    #[test]
    fn db_type_for_sqlite_uses_varchar() {
        let field = FieldType::File {
            upload_to: "uploads".to_string(),
        };
        assert_eq!(db_type(&field, "sqlite").as_deref(), Some("varchar(100)"));
    }

    #[test]
    fn get_prep_value_normalizes_file_path() {
        let prepared = get_prep_value("media/avatar.png").expect("file paths should validate");
        assert_eq!(prepared, "media/avatar.png");
    }

    #[test]
    fn from_db_value_returns_path_string() {
        let stored = from_db_value("media/image.jpg").expect("stored file path should round-trip");
        assert_eq!(stored, "media/image.jpg");
    }

    #[test]
    fn formfield_returns_correct_type() {
        let field = FieldType::Image {
            upload_to: "images".to_string(),
        };
        assert_eq!(formfield(&field), Some("ImageField"));
    }
}