use crate::parser::ParsedModel;
use proc_macro2::TokenStream;
use quote::quote;
#[cfg_attr(test, mutants::skip)]
pub fn generate_json_methods(parsed: &ParsedModel) -> TokenStream {
let normal_fields = &parsed.normal_fields;
let hidden_fields = &parsed.hidden_fields;
let skipped_fields = &parsed.skipped_fields;
let mut relation_field_idents = vec![];
for rel in &parsed.relations {
relation_field_idents.push(rel.field_name.clone());
}
let mut to_json_fields = vec![];
let mut search_fields = vec![];
for field_name in normal_fields {
let field_name_str = field_name.to_string();
if hidden_fields.contains(field_name) {
continue;
}
if parsed.is_redacted(field_name) {
to_json_fields.push(quote! {
map.insert(
#field_name_str.to_string(),
rullst_orm::_serde_json::Value::String(rullst_orm::audit::REDACTED_VALUE.to_string()),
);
});
} else {
let insert = quote! {
map.insert(#field_name_str.to_string(), rullst_orm::_serde_json::json!(self.#field_name));
};
to_json_fields.push(insert.clone());
search_fields.push(insert);
}
}
let search_json = if parsed.searchable {
quote! {
fn __rullst_search_json(&self) -> String {
rullst_orm::privacy::with_redacted_secrets(|| {
let mut map = rullst_orm::_serde_json::Map::new();
#(#search_fields)*
rullst_orm::_serde_json::Value::Object(map).to_string()
})
}
}
} else {
quote! {}
};
let redacted_changes = if parsed.auditable {
let comparisons = normal_fields
.iter()
.filter(|field| !hidden_fields.contains(field) && parsed.is_redacted(field))
.map(|field| {
let key = field.to_string();
let compared_in_memory = parsed.secret_fields.contains(field)
|| parsed.encrypted_fields.iter().any(|encrypted| encrypted.name == *field);
if compared_in_memory {
quote! {
if self.#field != previous.#field {
changed.push(#key);
}
}
} else {
quote! {
if rullst_orm::audit::redacted_value_changed(&self.#field, &previous.#field) {
changed.push(#key);
}
}
}
});
quote! {
fn __rullst_redacted_changes(&self, previous: &Self) -> Vec<&'static str> {
#[allow(unused_mut)]
let mut changed = Vec::new();
#(#comparisons)*
changed
}
}
} else {
quote! {}
};
let skip_tail = if skipped_fields.is_empty() {
quote! {}
} else {
quote! { ..Default::default() }
};
quote! {
pub fn from_json(json_str: &str) -> Result<Self, rullst_orm::_serde_json::Error> {
let value: rullst_orm::_serde_json::Value = rullst_orm::_serde_json::from_str(json_str)?;
Self::from_json_value(value)
}
pub fn from_json_value(value: rullst_orm::_serde_json::Value) -> Result<Self, rullst_orm::_serde_json::Error> {
Ok(Self {
#(
#normal_fields: rullst_orm::_serde_json::from_value(value[stringify!(#normal_fields)].clone())?,
)*
#(
#relation_field_idents: None,
)*
#skip_tail
})
}
pub fn from_json_array(json_str: &str) -> Result<Vec<Self>, rullst_orm::_serde_json::Error> {
let value: rullst_orm::_serde_json::Value = rullst_orm::_serde_json::from_str(json_str)?;
if let rullst_orm::_serde_json::Value::Array(arr) = value {
let mut results = Vec::with_capacity(arr.len());
for item in arr {
results.push(Self::from_json_value(item)?);
}
Ok(results)
} else {
Ok(vec![])
}
}
fn __rullst_cache_json_value(&self) -> Result<rullst_orm::_serde_json::Value, rullst_orm::_serde_json::Error> {
let mut map = rullst_orm::_serde_json::Map::new();
#(
map.insert(
stringify!(#normal_fields).to_string(),
rullst_orm::_serde_json::to_value(&self.#normal_fields)?,
);
)*
Ok(rullst_orm::_serde_json::Value::Object(map))
}
fn __rullst_try_cache_json_array(models: &[Self]) -> Result<String, rullst_orm::_serde_json::Error> {
let values = models
.iter()
.map(Self::__rullst_cache_json_value)
.collect::<Result<Vec<_>, _>>()?;
Ok(rullst_orm::_serde_json::Value::Array(values).to_string())
}
pub fn to_cache_json(&self) -> String {
self.__rullst_cache_json_value()
.map(|value| value.to_string())
.unwrap_or_default()
}
pub fn to_cache_json_array(models: &[Self]) -> String {
Self::__rullst_try_cache_json_array(models).unwrap_or_default()
}
pub fn from_cache_json(json_str: &str) -> Result<Self, rullst_orm::_serde_json::Error> {
Self::from_json(json_str)
}
pub fn from_cache_json_array(json_str: &str) -> Result<Vec<Self>, rullst_orm::_serde_json::Error> {
Self::from_json_array(json_str)
}
pub fn to_json(&self) -> String {
rullst_orm::privacy::with_redacted_secrets(|| {
let mut map = rullst_orm::_serde_json::Map::new();
#(#to_json_fields)*
rullst_orm::_serde_json::Value::Object(map).to_string()
})
}
#search_json
#redacted_changes
}
}