Skip to main content

khive_storage/
note.rs

1//! Note storage capability — temporal-referential record 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/// A storage-level note record. Flat, SQL-friendly representation.
11#[derive(Clone, Debug, Serialize, Deserialize)]
12pub struct Note {
13    pub id: Uuid,
14    pub namespace: String,
15    pub kind: String,
16    pub status: String,
17    pub name: Option<String>,
18    pub content: String,
19    pub salience: Option<f64>,
20    pub decay_factor: Option<f64>,
21    pub expires_at: Option<i64>,
22    pub properties: Option<Value>,
23    pub created_at: i64,
24    pub updated_at: i64,
25    pub deleted_at: Option<i64>,
26}
27
28impl Note {
29    pub fn new(
30        namespace: impl Into<String>,
31        kind: impl Into<String>,
32        content: impl Into<String>,
33    ) -> Self {
34        let now = chrono::Utc::now().timestamp_micros();
35        Self {
36            id: Uuid::new_v4(),
37            namespace: namespace.into(),
38            kind: kind.into(),
39            status: "active".to_string(),
40            name: None,
41            content: content.into(),
42            salience: None,
43            decay_factor: None,
44            expires_at: None,
45            properties: None,
46            created_at: now,
47            updated_at: now,
48            deleted_at: None,
49        }
50    }
51
52    pub fn with_name(mut self, n: impl Into<String>) -> Self {
53        self.name = Some(n.into());
54        self
55    }
56
57    pub fn with_salience(mut self, s: f64) -> Self {
58        self.salience = Some(s.clamp(0.0, 1.0));
59        self
60    }
61
62    pub fn with_decay(mut self, d: f64) -> Self {
63        self.decay_factor = Some(d.max(0.0));
64        self
65    }
66
67    pub fn with_properties(mut self, p: Value) -> Self {
68        self.properties = Some(p);
69        self
70    }
71}
72
73#[async_trait]
74pub trait NoteStore: Send + Sync + 'static {
75    async fn upsert_note(&self, note: Note) -> StorageResult<()>;
76    async fn upsert_notes(&self, notes: Vec<Note>) -> StorageResult<BatchWriteSummary>;
77    async fn get_note(&self, id: Uuid) -> StorageResult<Option<Note>>;
78    async fn delete_note(&self, id: Uuid, mode: DeleteMode) -> StorageResult<bool>;
79    async fn query_notes(
80        &self,
81        namespace: &str,
82        kind: Option<&str>,
83        page: PageRequest,
84    ) -> StorageResult<Page<Note>>;
85    async fn count_notes(&self, namespace: &str, kind: Option<&str>) -> StorageResult<u64>;
86
87    async fn get_notes_batch(&self, ids: &[Uuid]) -> StorageResult<Vec<Note>> {
88        let mut out = Vec::with_capacity(ids.len());
89        for &id in ids {
90            if let Some(n) = self.get_note(id).await? {
91                out.push(n);
92            }
93        }
94        Ok(out)
95    }
96}