entity_graph_tauri/
state.rs

1//! state.rs
2//!
3//! `GraphPluginState` — the Tauri-managed plugin state.
4//!
5//! Holds in-memory entity and list snapshots so the Rust side can serve
6//! `graph_get_entity` / `graph_get_list` without a round-trip to SQLite.
7//! The canonical source of truth is the TS graph store; this is a mirror
8//! kept up-to-date by command handlers.
9
10use std::collections::HashMap;
11use tokio::sync::RwLock;
12
13use crate::types::JsonObject;
14
15/// Per-entity storage keyed by `(entity_type, entity_id)`.
16pub type EntityMap = HashMap<(String, String), JsonObject>;
17
18/// Per-list storage keyed by `query_key`.
19#[derive(Debug, Default, Clone)]
20pub struct ListEntry {
21    pub ids: Vec<String>,
22    pub total: Option<i64>,
23}
24
25pub type ListMap = HashMap<String, ListEntry>;
26
27/// Per-snapshot storage keyed by `storage_key`.
28pub type SnapshotMap = HashMap<String, String>;
29
30/// Plugin-managed state, guarded by async `RwLock` for multi-window safety.
31#[derive(Debug, Default)]
32pub struct GraphPluginState {
33    pub entities: RwLock<EntityMap>,
34    pub lists: RwLock<ListMap>,
35    pub snapshots: RwLock<SnapshotMap>,
36}
37
38impl GraphPluginState {
39    pub fn new() -> Self {
40        Self::default()
41    }
42
43    // ── Entity helpers ────────────────────────────────────────────────────────
44
45    pub async fn upsert_entity(&self, entity_type: &str, entity_id: &str, data: JsonObject) {
46        let mut guard = self.entities.write().await;
47        let entry = guard
48            .entry((entity_type.to_owned(), entity_id.to_owned()))
49            .or_default();
50        for (k, v) in data {
51            entry.insert(k, v);
52        }
53    }
54
55    pub async fn remove_entity(&self, entity_type: &str, entity_id: &str) {
56        let mut guard = self.entities.write().await;
57        guard.remove(&(entity_type.to_owned(), entity_id.to_owned()));
58    }
59
60    pub async fn get_entity(&self, entity_type: &str, entity_id: &str) -> Option<JsonObject> {
61        let guard = self.entities.read().await;
62        guard
63            .get(&(entity_type.to_owned(), entity_id.to_owned()))
64            .cloned()
65    }
66
67    pub async fn clear_entities(&self) {
68        self.entities.write().await.clear();
69    }
70
71    // ── List helpers ──────────────────────────────────────────────────────────
72
73    pub async fn set_list(&self, query_key: &str, ids: Vec<String>, total: Option<i64>) {
74        let mut guard = self.lists.write().await;
75        guard.insert(query_key.to_owned(), ListEntry { ids, total });
76    }
77
78    pub async fn get_list(&self, query_key: &str) -> Option<ListEntry> {
79        let guard = self.lists.read().await;
80        guard.get(query_key).cloned()
81    }
82
83    pub async fn clear_lists(&self) {
84        self.lists.write().await.clear();
85    }
86
87    // ── Snapshot helpers ──────────────────────────────────────────────────────
88
89    pub async fn set_snapshot(&self, key: &str, snapshot: String) {
90        let mut guard = self.snapshots.write().await;
91        guard.insert(key.to_owned(), snapshot);
92    }
93
94    pub async fn get_snapshot(&self, key: &str) -> Option<String> {
95        let guard = self.snapshots.read().await;
96        guard.get(key).cloned()
97    }
98}