use std::collections::BTreeMap;
use openquiver_graph::NodeName;
use serde::{Deserialize, Serialize};
use crate::RunValue;
pub const RUN_STARTED: &str = "run.started";
pub const NODE_ENTERED: &str = "node.entered";
pub const NODE_EXITED: &str = "node.exited";
pub const PRINT: &str = "print";
pub const RUN_FINISHED: &str = "run.finished";
#[derive(Debug, Clone, PartialEq)]
pub(crate) enum Record {
Started(Started),
Entered(Entered),
Exited(Exited),
Printed(Printed),
Finished,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub(crate) struct Started {
pub plan: String,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub(crate) struct Entered {
pub node: NodeName,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub(crate) struct Exited {
pub node: NodeName,
pub outputs: BTreeMap<String, RunValue>,
pub exec: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub(crate) struct Printed {
pub text: String,
}
#[derive(Debug, thiserror::Error)]
pub enum JournalError {
#[error("this journal has a `{0}` entry, which this version does not understand")]
UnknownKind(String),
#[error("a `{kind}` entry could not be read: {source}")]
Malformed {
kind: String,
source: serde_json::Error,
},
}
impl Record {
pub(crate) fn kind(&self) -> &'static str {
match self {
Record::Started(_) => RUN_STARTED,
Record::Entered(_) => NODE_ENTERED,
Record::Exited(_) => NODE_EXITED,
Record::Printed(_) => PRINT,
Record::Finished => RUN_FINISHED,
}
}
pub(crate) fn payload(&self) -> Result<serde_json::Value, serde_json::Error> {
match self {
Record::Started(it) => serde_json::to_value(it),
Record::Entered(it) => serde_json::to_value(it),
Record::Exited(it) => serde_json::to_value(it),
Record::Printed(it) => serde_json::to_value(it),
Record::Finished => Ok(serde_json::Value::Object(Default::default())),
}
}
pub(crate) fn decode(kind: &str, payload: &serde_json::Value) -> Result<Self, JournalError> {
fn read<T: serde::de::DeserializeOwned>(
kind: &str,
payload: &serde_json::Value,
) -> Result<T, JournalError> {
serde_json::from_value(payload.clone()).map_err(|source| JournalError::Malformed {
kind: kind.to_owned(),
source,
})
}
Ok(match kind {
RUN_STARTED => Record::Started(read(kind, payload)?),
NODE_ENTERED => Record::Entered(read(kind, payload)?),
NODE_EXITED => Record::Exited(read(kind, payload)?),
PRINT => Record::Printed(read(kind, payload)?),
RUN_FINISHED => Record::Finished,
other => return Err(JournalError::UnknownKind(other.to_owned())),
})
}
}