use crate::core::validators::ValidationError;
use super::{
FieldDescriptor, FieldType, binary, boolean, char, datetime, file, float, integer, json,
related, text, uuid,
};
#[must_use]
pub fn build_field_descriptor(name: impl Into<String>, field_type: FieldType) -> FieldDescriptor {
FieldDescriptor::new(name, field_type)
}
pub fn validate_composite_field(field_type: &FieldType) -> Result<(), ValidationError> {
match field_type {
FieldType::ForeignKey { to, .. }
| FieldType::OneToOne { to, .. }
| FieldType::ManyToMany { to, .. } => related::validate_related_target(to),
_ => Ok(()),
}
}
#[must_use]
pub fn db_type(field: &FieldType, vendor: &str) -> Option<String> {
match field {
FieldType::Char { .. }
| FieldType::Email
| FieldType::Url
| FieldType::Slug { .. }
| FieldType::Ip
| FieldType::GenericIp
| FieldType::CommaSeparatedInteger { .. } => char::db_type(field, vendor),
FieldType::Text => text::db_type(field, vendor),
FieldType::Auto
| FieldType::BigAuto
| FieldType::SmallAuto
| FieldType::Integer
| FieldType::BigInteger
| FieldType::SmallInteger
| FieldType::PositiveInteger
| FieldType::PositiveBigInteger
| FieldType::PositiveSmallInteger => integer::db_type(field, vendor),
FieldType::Float | FieldType::Decimal { .. } => float::db_type(field, vendor),
FieldType::Boolean | FieldType::NullBoolean => boolean::db_type(field, vendor),
FieldType::DateTime { .. }
| FieldType::Date { .. }
| FieldType::Time
| FieldType::Duration => datetime::db_type(field, vendor),
FieldType::Uuid => uuid::db_type(field, vendor),
FieldType::Binary => binary::db_type(field, vendor),
FieldType::Json => json::db_type(field, vendor),
FieldType::File { .. } | FieldType::Image { .. } | FieldType::FilePath { .. } => {
file::db_type(field, vendor)
}
FieldType::ForeignKey { .. }
| FieldType::OneToOne { .. }
| FieldType::ManyToMany { .. } => related::db_type(field, vendor),
}
}
pub fn get_prep_value(field: &FieldType, value: &str) -> Result<String, ValidationError> {
match field {
FieldType::Char { .. }
| FieldType::Email
| FieldType::Url
| FieldType::Slug { .. }
| FieldType::Ip
| FieldType::GenericIp
| FieldType::CommaSeparatedInteger { .. } => char::get_prep_value(field, value),
FieldType::Text => text::get_prep_value(value),
FieldType::Auto
| FieldType::BigAuto
| FieldType::SmallAuto
| FieldType::Integer
| FieldType::BigInteger
| FieldType::SmallInteger
| FieldType::PositiveInteger
| FieldType::PositiveBigInteger
| FieldType::PositiveSmallInteger => integer::get_prep_value(field, value),
FieldType::Float | FieldType::Decimal { .. } => float::get_prep_value(field, value),
FieldType::Boolean | FieldType::NullBoolean => boolean::get_prep_value(value),
FieldType::DateTime { .. }
| FieldType::Date { .. }
| FieldType::Time
| FieldType::Duration => datetime::get_prep_value(field, value),
FieldType::Uuid => uuid::get_prep_value(value, "postgres"),
FieldType::Binary => binary::get_prep_value(value.as_bytes()),
FieldType::Json => json::get_prep_value(value),
FieldType::File { .. } | FieldType::Image { .. } | FieldType::FilePath { .. } => {
file::get_prep_value(value)
}
FieldType::ForeignKey { .. }
| FieldType::OneToOne { .. }
| FieldType::ManyToMany { .. } => related::get_prep_value(value),
}
}
pub fn from_db_value(field: &FieldType, value: &str) -> Result<String, ValidationError> {
match field {
FieldType::Char { .. }
| FieldType::Email
| FieldType::Url
| FieldType::Slug { .. }
| FieldType::Ip
| FieldType::GenericIp
| FieldType::CommaSeparatedInteger { .. } => char::from_db_value(value),
FieldType::Text => text::from_db_value(value),
FieldType::Auto
| FieldType::BigAuto
| FieldType::SmallAuto
| FieldType::Integer
| FieldType::BigInteger
| FieldType::SmallInteger
| FieldType::PositiveInteger
| FieldType::PositiveBigInteger
| FieldType::PositiveSmallInteger => {
integer::from_db_value(value).map(|parsed| parsed.to_string())
}
FieldType::Float | FieldType::Decimal { .. } => float::from_db_value(field, value),
FieldType::Boolean | FieldType::NullBoolean => {
boolean::from_db_value(value).map(|parsed| parsed.to_string())
}
FieldType::DateTime { .. }
| FieldType::Date { .. }
| FieldType::Time
| FieldType::Duration => datetime::from_db_value(field, value),
FieldType::Uuid => uuid::from_db_value(value),
FieldType::Binary => {
binary::from_db_value(value)?;
Ok(value.to_string())
}
FieldType::Json => json::from_db_value(value).map(|parsed| parsed.to_string()),
FieldType::File { .. } | FieldType::Image { .. } | FieldType::FilePath { .. } => {
file::from_db_value(value)
}
FieldType::ForeignKey { .. }
| FieldType::OneToOne { .. }
| FieldType::ManyToMany { .. } => related::from_db_value(value),
}
}
#[must_use]
pub fn formfield(field: &FieldType) -> Option<&'static str> {
match field {
FieldType::Char { .. }
| FieldType::Email
| FieldType::Url
| FieldType::Slug { .. }
| FieldType::Ip
| FieldType::GenericIp
| FieldType::CommaSeparatedInteger { .. } => char::formfield(field),
FieldType::Text => text::formfield(field),
FieldType::Auto
| FieldType::BigAuto
| FieldType::SmallAuto
| FieldType::Integer
| FieldType::BigInteger
| FieldType::SmallInteger
| FieldType::PositiveInteger
| FieldType::PositiveBigInteger
| FieldType::PositiveSmallInteger => integer::formfield(field),
FieldType::Float | FieldType::Decimal { .. } => float::formfield(field),
FieldType::Boolean | FieldType::NullBoolean => boolean::formfield(field),
FieldType::DateTime { .. }
| FieldType::Date { .. }
| FieldType::Time
| FieldType::Duration => datetime::formfield(field),
FieldType::Uuid => uuid::formfield(field),
FieldType::Binary => binary::formfield(field),
FieldType::Json => json::formfield(field),
FieldType::File { .. } | FieldType::Image { .. } | FieldType::FilePath { .. } => {
file::formfield(field)
}
FieldType::ForeignKey { .. }
| FieldType::OneToOne { .. }
| FieldType::ManyToMany { .. } => related::formfield(field),
}
}
#[cfg(test)]
mod tests {
use super::{FieldType, db_type, formfield, from_db_value, get_prep_value};
use crate::db::models::fields::OnDelete;
#[test]
fn db_type_delegates_to_char_fields() {
let field = FieldType::Char { max_length: 8 };
assert_eq!(db_type(&field, "sqlite").as_deref(), Some("varchar(8)"));
}
#[test]
fn get_prep_value_dispatches_integer_processing() {
let prepared = get_prep_value(&FieldType::PositiveInteger, "9")
.expect("composite preparation should delegate integer parsing");
assert_eq!(prepared, "9");
}
#[test]
fn from_db_value_dispatches_boolean_processing() {
let parsed = from_db_value(&FieldType::Boolean, "1")
.expect("composite conversion should delegate boolean parsing");
assert_eq!(parsed, "true");
}
#[test]
fn formfield_dispatches_related_fields() {
let field = FieldType::ForeignKey {
to: "Author".to_string(),
on_delete: OnDelete::Cascade,
};
assert_eq!(formfield(&field), Some("ModelChoiceField"));
}
}