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