Skip to main content

khive_storage/
entity.rs

1//! Entity storage capability — graph node CRUD.
2
3use async_trait::async_trait;
4use serde::{Deserialize, Serialize};
5use serde_json::Value;
6use uuid::Uuid;
7
8use khive_types::EntityKind;
9
10use crate::types::{BatchWriteSummary, DeleteMode, Page, PageRequest, StorageResult};
11
12/// Storage-level entity record. Flat SQL-friendly representation.
13/// Maps to the `entities` substrate table.
14#[derive(Clone, Debug, Serialize, Deserialize)]
15pub struct Entity {
16    pub id: Uuid,
17    pub namespace: String,
18    pub kind: EntityKind,
19    pub name: String,
20    pub description: Option<String>,
21    pub properties: Option<Value>,
22    pub tags: Vec<String>,
23    pub created_at: i64,
24    pub updated_at: i64,
25    pub deleted_at: Option<i64>,
26}
27
28impl Entity {
29    pub fn new(namespace: impl Into<String>, kind: EntityKind, name: impl Into<String>) -> Self {
30        let now = chrono::Utc::now().timestamp_micros();
31        Self {
32            id: Uuid::new_v4(),
33            namespace: namespace.into(),
34            kind,
35            name: name.into(),
36            description: None,
37            properties: None,
38            tags: Vec::new(),
39            created_at: now,
40            updated_at: now,
41            deleted_at: None,
42        }
43    }
44
45    pub fn with_description(mut self, d: impl Into<String>) -> Self {
46        self.description = Some(d.into());
47        self
48    }
49
50    pub fn with_properties(mut self, p: Value) -> Self {
51        self.properties = Some(p);
52        self
53    }
54
55    pub fn with_tags(mut self, t: Vec<String>) -> Self {
56        self.tags = t;
57        self
58    }
59}
60
61/// Entity filter for query operations.
62#[derive(Clone, Debug, Default, Serialize, Deserialize)]
63pub struct EntityFilter {
64    pub ids: Vec<Uuid>,
65    pub kinds: Vec<EntityKind>,
66    pub name_prefix: Option<String>,
67    pub tags_any: Vec<String>,
68}
69
70#[async_trait]
71pub trait EntityStore: Send + Sync + 'static {
72    async fn upsert_entity(&self, entity: Entity) -> StorageResult<()>;
73    async fn upsert_entities(&self, entities: Vec<Entity>) -> StorageResult<BatchWriteSummary>;
74    async fn get_entity(&self, id: Uuid) -> StorageResult<Option<Entity>>;
75    async fn delete_entity(&self, id: Uuid, mode: DeleteMode) -> StorageResult<bool>;
76    async fn query_entities(
77        &self,
78        namespace: &str,
79        filter: EntityFilter,
80        page: PageRequest,
81    ) -> StorageResult<Page<Entity>>;
82    async fn count_entities(&self, namespace: &str, filter: EntityFilter) -> StorageResult<u64>;
83}