Skip to main content

agent_office/domain/
mod.rs

1use serde::{Deserialize, Serialize};
2use std::collections::HashMap;
3
4pub type NodeId = uuid::Uuid;
5pub type EdgeId = uuid::Uuid;
6pub type Timestamp = chrono::DateTime<chrono::Utc>;
7
8#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
9#[serde(untagged)]
10pub enum PropertyValue {
11    // Order matters for untagged enums - more specific types first
12    Null,
13    Timestamp(Timestamp),
14    Boolean(bool),
15    Integer(i64),
16    Float(f64),
17    String(String),
18    List(Vec<PropertyValue>),
19    Map(HashMap<String, PropertyValue>),
20}
21
22pub type Properties = HashMap<String, PropertyValue>;
23
24impl PropertyValue {
25    pub fn as_str(&self) -> Option<&str> {
26        match self {
27            PropertyValue::String(s) => Some(s.as_str()),
28            _ => None,
29        }
30    }
31}
32
33#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
34pub struct Node {
35    pub id: NodeId,
36    pub node_type: String,
37    pub properties: Properties,
38    pub created_at: Timestamp,
39    pub updated_at: Timestamp,
40}
41
42impl Node {
43    pub fn new(node_type: impl Into<String>, properties: Properties) -> Self {
44        let now = chrono::Utc::now();
45        Self {
46            id: NodeId::new_v4(),
47            node_type: node_type.into(),
48            properties,
49            created_at: now,
50            updated_at: now,
51        }
52    }
53
54    pub fn get_property(&self, key: &str) -> Option<&PropertyValue> {
55        self.properties.get(key)
56    }
57}
58
59#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
60pub struct Edge {
61    pub id: EdgeId,
62    pub edge_type: String,
63    pub from_node_id: NodeId,
64    pub to_node_id: NodeId,
65    pub properties: Properties,
66    pub created_at: Timestamp,
67}
68
69impl Edge {
70    pub fn new(
71        edge_type: impl Into<String>,
72        from_node_id: NodeId,
73        to_node_id: NodeId,
74        properties: Properties,
75    ) -> Self {
76        Self {
77            id: EdgeId::new_v4(),
78            edge_type: edge_type.into(),
79            from_node_id,
80            to_node_id,
81            properties,
82            created_at: chrono::Utc::now(),
83        }
84    }
85}
86
87#[derive(Debug, Clone, Serialize, Deserialize)]
88pub struct GraphQuery {
89    pub node_types: Option<Vec<String>>,
90    pub edge_types: Option<Vec<String>>,
91    pub property_filters: Option<HashMap<String, PropertyValue>>,
92    pub limit: Option<usize>,
93}
94
95impl GraphQuery {
96    pub fn new() -> Self {
97        Self {
98            node_types: None,
99            edge_types: None,
100            property_filters: None,
101            limit: None,
102        }
103    }
104
105    pub fn with_node_type(mut self, node_type: impl Into<String>) -> Self {
106        self.node_types = Some(vec![node_type.into()]);
107        self
108    }
109}
110
111impl Default for GraphQuery {
112    fn default() -> Self {
113        Self::new()
114    }
115}
116
117/// Convert a string ID (like "intern_0") to a deterministic UUID
118/// This allows using string identifiers while maintaining UUID-based storage
119pub fn string_to_node_id(s: &str) -> NodeId {
120    // Use UUID v5 with a custom namespace for our application
121    // The namespace is a fixed UUID: 6ba7b810-9dad-11d1-80b4-00c04fd430c8 (OID namespace)
122    let namespace = uuid::Uuid::from_bytes([
123        0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30,
124        0xc8,
125    ]);
126    uuid::Uuid::new_v5(&namespace, s.as_bytes())
127}