use super::introspection::{FieldInfo, FieldIntrospector};
use super::meta::MetaConfig;
use super::nested_config::{NestedFieldConfig, NestedSerializerConfig};
use super::validator_config::{ModelLevelValidator, ValidatorConfig};
use super::validators::{UniqueTogetherValidator, UniqueValidator};
use super::{Serializer, SerializerError, ValidatorError};
use reinhardt_db::backends::DatabaseConnection;
use reinhardt_db::orm::Model;
use std::collections::HashMap;
use std::marker::PhantomData;
use std::sync::Arc;
pub struct ModelSerializer<M>
where
M: Model,
{
meta: MetaConfig,
introspector: Option<FieldIntrospector>,
nested_config: NestedSerializerConfig,
validator_config: ValidatorConfig<M>,
_phantom: PhantomData<M>,
}
impl<M> ModelSerializer<M>
where
M: Model,
{
pub fn new() -> Self {
Self {
meta: MetaConfig::new(),
introspector: None,
nested_config: NestedSerializerConfig::new(),
validator_config: ValidatorConfig::new(),
_phantom: PhantomData,
}
}
pub fn with_fields(mut self, fields: Vec<String>) -> Self {
self.meta = self.meta.with_fields(fields);
self
}
pub fn with_exclude(mut self, exclude: Vec<String>) -> Self {
self.meta = self.meta.with_exclude(exclude);
self
}
pub fn with_read_only_fields(mut self, fields: Vec<String>) -> Self {
self.meta = self.meta.with_read_only_fields(fields);
self
}
pub fn with_write_only_fields(mut self, fields: Vec<String>) -> Self {
self.meta = self.meta.with_write_only_fields(fields);
self
}
pub fn meta(&self) -> &MetaConfig {
&self.meta
}
pub fn with_nested_field(mut self, field_config: NestedFieldConfig) -> Self {
self.nested_config.add_nested_field(field_config);
self
}
pub fn nested_config(&self) -> &NestedSerializerConfig {
&self.nested_config
}
pub fn is_nested_field(&self, field_name: &str) -> bool {
self.nested_config.is_nested_field(field_name)
}
pub fn with_introspector(mut self, introspector: FieldIntrospector) -> Self {
self.introspector = Some(introspector);
self
}
pub fn introspector(&self) -> Option<&FieldIntrospector> {
self.introspector.as_ref()
}
pub fn field_names(&self) -> Vec<String> {
if let Some(introspector) = &self.introspector {
introspector.field_names()
} else if let Some(fields) = self.meta.fields() {
fields.clone()
} else {
vec![]
}
}
pub fn required_fields(&self) -> Vec<&FieldInfo> {
if let Some(introspector) = &self.introspector {
introspector.required_fields()
} else {
vec![]
}
}
pub fn optional_fields(&self) -> Vec<&FieldInfo> {
if let Some(introspector) = &self.introspector {
introspector.optional_fields()
} else {
vec![]
}
}
pub fn primary_key_field(&self) -> Option<&FieldInfo> {
self.introspector
.as_ref()
.and_then(|i| i.primary_key_field())
}
pub fn with_unique_validator(mut self, validator: UniqueValidator<M>) -> Self {
self.validator_config.add_unique_validator(validator);
self
}
pub fn with_unique_together_validator(mut self, validator: UniqueTogetherValidator<M>) -> Self {
self.validator_config
.add_unique_together_validator(validator);
self
}
pub fn with_model_validator<V>(mut self, validator: V) -> Self
where
V: ModelLevelValidator<M> + 'static,
{
self.validator_config
.add_sync_model_validator(Arc::new(validator));
self
}
pub fn validators(&self) -> &ValidatorConfig<M> {
&self.validator_config
}
pub fn validate(&self, instance: &M) -> Result<(), SerializerError> {
self.validator_config
.validate(instance)
.map_err(SerializerError::Validation)
}
pub async fn validate_async(
&self,
connection: &DatabaseConnection,
instance: &M,
) -> Result<(), SerializerError>
where
M::PrimaryKey: std::fmt::Display,
{
self.validate(instance)?;
let json_value = serde_json::to_value(instance).map_err(|e| SerializerError::Serde {
message: format!("Failed to serialize instance for validation: {}", e),
})?;
for validator in self.validator_config.unique_validators() {
let field_name = validator.field_name();
if let Some(field_value) = json_value.get(field_name) {
let value_str = match field_value {
serde_json::Value::String(s) => s.clone(),
other => other.to_string().trim_matches('"').to_string(),
};
validator
.validate(connection, &value_str, instance.primary_key().as_ref())
.await
.map_err(|e| {
SerializerError::Validation(ValidatorError::UniqueViolation {
field_name: field_name.to_string(),
value: value_str.clone(),
message: e.to_string(),
})
})?;
}
}
for validator in self.validator_config.unique_together_validators() {
let field_names = validator.field_names();
let mut values: HashMap<String, String> = HashMap::new();
for field_name in field_names {
if let Some(field_value) = json_value.get(field_name) {
let value_str = match field_value {
serde_json::Value::String(s) => s.clone(),
other => other.to_string().trim_matches('"').to_string(),
};
values.insert(field_name.to_string(), value_str);
}
}
validator
.validate(connection, &values, instance.primary_key().as_ref())
.await
.map_err(|e| {
SerializerError::Validation(ValidatorError::UniqueTogetherViolation {
field_names: field_names.iter().map(|s| s.to_string()).collect(),
values: values.clone(),
message: e.to_string(),
})
})?;
}
Ok(())
}
}
impl<M> Default for ModelSerializer<M>
where
M: Model,
{
fn default() -> Self {
Self::new()
}
}
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
enum FilterDirection {
Output,
Input,
}
fn apply_meta_filter(
value: &mut serde_json::Value,
meta: &MetaConfig,
introspector_field_names: Option<&[String]>,
direction: FilterDirection,
) {
let serde_json::Value::Object(map) = value else {
return;
};
let implicit_allowlist: Option<&[String]> = match (meta.fields(), introspector_field_names) {
(Some(_), _) => None,
(None, Some(names)) if !names.is_empty() => Some(names),
_ => None,
};
map.retain(|key, _| {
if !meta.is_field_included(key) {
return false;
}
if let Some(allowed) = implicit_allowlist
&& !allowed.iter().any(|n| n == key)
{
return false;
}
match direction {
FilterDirection::Output => !meta.is_write_only(key),
FilterDirection::Input => !meta.is_read_only(key),
}
});
}
impl<M> Serializer for ModelSerializer<M>
where
M: Model,
{
type Input = M;
type Output = String;
fn serialize(&self, input: &Self::Input) -> Result<Self::Output, SerializerError> {
let mut value = serde_json::to_value(input).map_err(|e| SerializerError::Serde {
message: format!("Serialization error: {}", e),
})?;
let introspector_names = self.introspector.as_ref().map(|i| i.field_names());
apply_meta_filter(
&mut value,
&self.meta,
introspector_names.as_deref(),
FilterDirection::Output,
);
serde_json::to_string(&value).map_err(|e| SerializerError::Serde {
message: format!("Serialization error: {}", e),
})
}
fn deserialize(&self, output: &Self::Output) -> Result<Self::Input, SerializerError> {
let mut value: serde_json::Value =
serde_json::from_str(output).map_err(|e| SerializerError::Serde {
message: format!("Deserialization error: {}", e),
})?;
let introspector_names = self.introspector.as_ref().map(|i| i.field_names());
apply_meta_filter(
&mut value,
&self.meta,
introspector_names.as_deref(),
FilterDirection::Input,
);
serde_json::from_value(value).map_err(|e| SerializerError::Serde {
message: format!("Deserialization error: {}", e),
})
}
}