use serde_json::Value;
use super::entity_key::EntityKey;
use crate::error::{FraiseQLError, Result};
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct CascadeEntities {
pub updated: Vec<EntityKey>,
pub deleted: Vec<EntityKey>,
}
impl CascadeEntities {
#[must_use]
pub const fn new(updated: Vec<EntityKey>, deleted: Vec<EntityKey>) -> Self {
Self { updated, deleted }
}
#[must_use]
pub fn all_affected(&self) -> Vec<EntityKey> {
let mut all = self.updated.clone();
all.extend(self.deleted.clone());
all
}
#[must_use]
pub const fn has_changes(&self) -> bool {
!self.updated.is_empty() || !self.deleted.is_empty()
}
}
#[derive(Debug, Clone)]
pub struct CascadeResponseParser;
impl CascadeResponseParser {
#[must_use]
pub const fn new() -> Self {
Self
}
pub fn parse_cascade_response(&self, response: &Value) -> Result<CascadeEntities> {
let cascade = self.find_cascade_field(response)?;
if cascade.is_null() {
return Ok(CascadeEntities {
updated: Vec::new(),
deleted: Vec::new(),
});
}
let updated = self.extract_entities_list(&cascade, "updated")?;
let deleted = self.extract_entities_list(&cascade, "deleted")?;
Ok(CascadeEntities { updated, deleted })
}
fn find_cascade_field(&self, response: &Value) -> Result<Value> {
if let Some(cascade) = response.get("cascade") {
return Ok(cascade.clone());
}
if let Some(data) = response.get("data") {
if let Some(cascade) = data.get("cascade") {
return Ok(cascade.clone());
}
for (_key, value) in data.as_object().unwrap_or(&serde_json::Map::default()) {
if let Some(cascade) = value.get("cascade") {
return Ok(cascade.clone());
}
}
}
for (_key, value) in response.as_object().unwrap_or(&serde_json::Map::default()) {
if let Some(cascade) = value.get("cascade") {
return Ok(cascade.clone());
}
}
Ok(Value::Null)
}
fn extract_entities_list(&self, cascade: &Value, field_name: &str) -> Result<Vec<EntityKey>> {
let entities_array = match cascade.get(field_name) {
Some(Value::Array(arr)) => arr,
Some(Value::Null) | None => return Ok(Vec::new()),
Some(val) => {
return Err(FraiseQLError::Validation {
message: format!(
"cascade.{} should be array, got {}",
field_name,
match val {
Value::Object(_) => "object",
Value::String(_) => "string",
Value::Number(_) => "number",
Value::Bool(_) => "boolean",
Value::Null => "null",
Value::Array(_) => "unknown",
}
),
path: Some(format!("cascade.{}", field_name)),
});
},
};
let mut entities = Vec::new();
for entity_obj in entities_array {
let entity = self.parse_cascade_entity(entity_obj)?;
entities.push(entity);
}
Ok(entities)
}
fn parse_cascade_entity(&self, entity_obj: &Value) -> Result<EntityKey> {
let obj = entity_obj.as_object().ok_or_else(|| FraiseQLError::Validation {
message: "Cascade entity should be object".to_string(),
path: Some("cascade.updated[*]".to_string()),
})?;
let type_name = obj.get("__typename").and_then(Value::as_str).ok_or_else(|| {
FraiseQLError::Validation {
message: "Cascade entity missing __typename field".to_string(),
path: Some("cascade.updated[*].__typename".to_string()),
}
})?;
let entity_id =
obj.get("id").and_then(Value::as_str).ok_or_else(|| FraiseQLError::Validation {
message: "Cascade entity missing id field".to_string(),
path: Some("cascade.updated[*].id".to_string()),
})?;
EntityKey::new(type_name, entity_id)
}
}
impl Default for CascadeResponseParser {
fn default() -> Self {
Self::new()
}
}