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