use serde::{Deserialize, Serialize};
#[derive(Debug, Clone)]
pub struct CreateResult<T> {
pub id: String,
pub entity: T,
}
#[derive(Debug, Clone)]
pub enum CreateOutput<T> {
Single(CreateResult<T>),
Bulk(BatchResult),
}
#[derive(Debug, Clone, Serialize)]
#[serde(untagged)]
pub enum MergeOutput {
Single(MergeResult),
Bulk(BatchResult),
}
#[derive(Debug, Clone, Serialize)]
pub struct MergeResult {
pub id: String,
pub updated_fields: Vec<String>,
}
#[derive(Debug, Clone, Serialize)]
pub struct RemoveResult {
pub id: String,
pub removed_from: Vec<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct BatchResult {
pub created: u32,
pub updated: u32,
pub skipped: u32,
pub errors: u32,
pub items: Vec<BatchResultItem>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BatchResultItem {
pub id: String,
pub status: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub error: Option<String>,
}
impl BatchResult {
pub fn new() -> Self {
Self::default()
}
pub fn exit_code(&self) -> i32 {
if self.errors > 0 { 1 } else { 0 }
}
pub fn record_created(&mut self, id: String) {
self.created += 1;
self.items.push(BatchResultItem {
id,
status: "created".to_string(),
error: None,
});
}
pub fn record_updated(&mut self, id: String) {
self.updated += 1;
self.items.push(BatchResultItem {
id,
status: "updated".to_string(),
error: None,
});
}
pub fn record_skipped(&mut self, id: String) {
self.skipped += 1;
self.items.push(BatchResultItem {
id,
status: "skipped".to_string(),
error: None,
});
}
pub fn record_error(&mut self, id: String, error: String) {
self.errors += 1;
self.items.push(BatchResultItem {
id,
status: "error".to_string(),
error: Some(error),
});
}
}
#[derive(Debug, Serialize)]
pub struct BulkResult<T: Serialize> {
pub action: String,
pub results: Vec<ItemOutcome<T>>,
pub summary: BulkSummary,
}
#[derive(Debug, Serialize)]
pub struct ItemOutcome<T: Serialize> {
pub id: String,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(flatten)]
pub result: Option<T>,
#[serde(skip_serializing_if = "Option::is_none")]
pub error: Option<String>,
}
#[derive(Debug, Clone, Serialize)]
pub struct BulkSummary {
pub total: usize,
pub succeeded: usize,
pub failed: usize,
}
#[derive(Debug, Default, Serialize)]
pub struct NoExtra;
#[derive(Debug, Serialize)]
pub struct EntityCrudOutput<T: Serialize, E: Serialize + Default = NoExtra> {
pub command: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub entity: Option<T>,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub entities: Vec<T>,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub updated_fields: Vec<String>,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub deleted: Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub import: Option<BatchResult>,
#[serde(skip_serializing_if = "Option::is_none")]
pub batch: Option<BatchResult>,
#[serde(skip_serializing_if = "Option::is_none")]
pub hint: Option<String>,
#[serde(flatten)]
pub extra: E,
}
impl<T: Serialize, E: Serialize + Default> Default for EntityCrudOutput<T, E> {
fn default() -> Self {
Self {
command: String::new(),
id: None,
entity: None,
entities: Vec::new(),
updated_fields: Vec::new(),
deleted: Vec::new(),
import: None,
batch: None,
hint: None,
extra: E::default(),
}
}
}