use super::OCEL;
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub struct FlatCase {
pub case_id: String,
pub trace: Vec<String>,
pub event_ids: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub struct FlatLog {
pub object_type: String,
pub cases: Vec<FlatCase>,
}
pub fn flatten(ocel: &OCEL, object_type: &str) -> Result<FlatLog, String> {
if !ocel.object_types.iter().any(|t| t.name == object_type) {
return Err(format!(
"object type '{object_type}' is not declared in objectTypes"
));
}
let mut target_ids: Vec<&str> = ocel
.objects
.iter()
.filter(|o| o.object_type == object_type)
.map(|o| o.id.as_str())
.collect();
target_ids.sort_unstable();
let mut cases = Vec::with_capacity(target_ids.len());
for oid in target_ids {
let mut rows: Vec<(chrono::DateTime<chrono::FixedOffset>, &str, &str)> = ocel
.events
.iter()
.filter(|e| e.relationships.iter().any(|r| r.object_id == oid))
.map(|e| (e.time, e.id.as_str(), e.event_type.as_str()))
.collect();
rows.sort_by(|a, b| a.0.cmp(&b.0).then_with(|| a.1.cmp(b.1)));
let trace = rows.iter().map(|(_, _, ty)| ty.to_string()).collect();
let event_ids = rows.iter().map(|(_, id, _)| id.to_string()).collect();
cases.push(FlatCase {
case_id: oid.to_string(),
trace,
event_ids,
});
}
Ok(FlatLog {
object_type: object_type.to_string(),
cases,
})
}
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub struct Triple {
pub subject: String,
pub predicate: String,
pub object: String,
}
impl Triple {
pub fn new<S: Into<String>, P: Into<String>, O: Into<String>>(
subject: S,
predicate: P,
object: O,
) -> Self {
Self {
subject: subject.into(),
predicate: predicate.into(),
object: object.into(),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize, Default)]
pub struct EventLogKnowledgeGraph {
pub triples: Vec<Triple>,
}
impl EventLogKnowledgeGraph {
pub fn new() -> Self {
Self {
triples: Vec::new(),
}
}
pub fn add_triple(&mut self, triple: Triple) {
self.triples.push(triple);
}
pub fn flatten_perspective(&self, perspective: &PerspectivePath) -> Result<FlatLog, String> {
Ok(FlatLog {
object_type: if let Some(step) = perspective.steps.first() {
step.target_type.clone()
} else {
"unknown".to_string()
},
cases: Vec::new(),
})
}
}
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub struct PerspectiveStep {
pub relationship: String,
pub target_type: String,
}
impl PerspectiveStep {
pub fn new<R: Into<String>, T: Into<String>>(relationship: R, target_type: T) -> Self {
Self {
relationship: relationship.into(),
target_type: target_type.into(),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize, Default)]
pub struct PerspectivePath {
pub steps: Vec<PerspectiveStep>,
}
impl PerspectivePath {
pub fn new() -> Self {
Self { steps: Vec::new() }
}
pub fn then(mut self, step: PerspectiveStep) -> Self {
self.steps.push(step);
self
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
pub enum TraceConstraint {
Existence,
Absence,
Exactly1,
Init,
RespondedExistence,
CoExistence,
Response,
Precedence,
Succession,
AlternateResponse,
AlternatePrecedence,
AlternateSuccession,
}