use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use serde_json::json;
use super::NodeId;
use crate::hash::node_id;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Intent {
pub id: NodeId,
pub source: String,
pub text: String,
pub created_at: DateTime<Utc>,
pub parent_ids: Vec<NodeId>,
#[serde(default = "default_schema_version")]
pub schema_version: String,
}
fn default_schema_version() -> String {
"1".to_string()
}
impl Intent {
pub fn new(source: String, text: String, parent_ids: Vec<NodeId>) -> Self {
Self::new_at(source, text, Utc::now(), parent_ids)
}
pub fn new_at(
source: String,
text: String,
created_at: DateTime<Utc>,
parent_ids: Vec<NodeId>,
) -> Self {
let id = NodeId(node_id(&Self::hash_input(
&source,
&text,
&created_at,
&parent_ids,
)));
Self {
id,
source,
text,
created_at,
parent_ids,
schema_version: default_schema_version(),
}
}
fn hash_input(
source: &str,
text: &str,
created_at: &DateTime<Utc>,
parent_ids: &[NodeId],
) -> serde_json::Value {
json!({
"type": "intent",
"source": source,
"text": text,
"created_at": created_at.to_rfc3339(),
"parent_ids": parent_ids.iter().map(|id| id.as_str()).collect::<Vec<_>>(),
})
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn id_is_deterministic_for_same_timestamp() {
let ts = Utc::now();
let parents: Vec<NodeId> = vec![];
let a = Intent {
id: NodeId(node_id(&Intent::hash_input(
"ACME-411",
"Add JWT verification",
&ts,
&parents,
))),
source: "ACME-411".into(),
text: "Add JWT verification".into(),
created_at: ts,
parent_ids: parents.clone(),
schema_version: "1".into(),
};
let b = Intent {
id: NodeId(node_id(&Intent::hash_input(
"ACME-411",
"Add JWT verification",
&ts,
&parents,
))),
source: "ACME-411".into(),
text: "Add JWT verification".into(),
created_at: ts,
parent_ids: parents,
schema_version: "1".into(),
};
assert_eq!(a.id, b.id);
}
}