Skip to main content

cvx_graph/
entity.rs

1//! Typed entities (nodes) in the knowledge graph.
2
3use serde::{Deserialize, Serialize};
4use std::collections::HashMap;
5
6/// Unique entity identifier.
7pub type EntityId = u64;
8
9/// Entity type label.
10#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
11pub enum EntityType {
12    /// A task type (e.g., "heat_then_place").
13    Task,
14    /// An abstract action (e.g., "navigate", "take").
15    Action,
16    /// A step in a plan (ordered).
17    Step,
18    /// A physical object (e.g., "tomato", "mug").
19    Object,
20    /// A location (e.g., "countertop 1", "fridge").
21    Location,
22    /// A tool or appliance (e.g., "microwave", "sinkbasin").
23    Appliance,
24    /// Custom type.
25    Custom(String),
26}
27
28/// An entity (node) in the knowledge graph.
29#[derive(Debug, Clone, Serialize, Deserialize)]
30pub struct Entity {
31    /// Unique identifier.
32    pub id: EntityId,
33    /// Entity type.
34    pub entity_type: EntityType,
35    /// Name / label.
36    pub name: String,
37    /// Arbitrary key-value properties.
38    pub properties: HashMap<String, String>,
39}
40
41impl Entity {
42    /// Create a new entity.
43    pub fn new(id: EntityId, entity_type: EntityType, name: impl Into<String>) -> Self {
44        Self {
45            id,
46            entity_type,
47            name: name.into(),
48            properties: HashMap::new(),
49        }
50    }
51
52    /// Add a property.
53    pub fn with_property(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
54        self.properties.insert(key.into(), value.into());
55        self
56    }
57
58    /// Get a property value.
59    pub fn property(&self, key: &str) -> Option<&str> {
60        self.properties.get(key).map(|s| s.as_str())
61    }
62}
63
64#[cfg(test)]
65mod tests {
66    use super::*;
67
68    #[test]
69    fn entity_creation() {
70        let e = Entity::new(1, EntityType::Task, "heat_then_place")
71            .with_property("n_steps", "7")
72            .with_property("difficulty", "hard");
73
74        assert_eq!(e.id, 1);
75        assert_eq!(e.entity_type, EntityType::Task);
76        assert_eq!(e.name, "heat_then_place");
77        assert_eq!(e.property("n_steps"), Some("7"));
78        assert_eq!(e.property("missing"), None);
79    }
80}