Skip to main content

parsnip_core/
graph.rs

1//! Knowledge graph trait definition
2
3use crate::entity::{Entity, NewEntity};
4use crate::error::Result;
5use crate::project::{Project, ProjectId};
6use crate::query::{PaginatedResults, SearchQuery};
7use crate::relation::{Direction, NewRelation, Relation};
8use async_trait::async_trait;
9
10/// Graph containing entities and their relations
11#[derive(Debug, Clone, Default)]
12pub struct Graph {
13    pub entities: Vec<Entity>,
14    pub relations: Vec<Relation>,
15}
16
17impl Graph {
18    pub fn new() -> Self {
19        Self::default()
20    }
21
22    pub fn with_entities(mut self, entities: Vec<Entity>) -> Self {
23        self.entities = entities;
24        self
25    }
26
27    pub fn with_relations(mut self, relations: Vec<Relation>) -> Self {
28        self.relations = relations;
29        self
30    }
31}
32
33/// Main trait for knowledge graph operations
34///
35/// All storage backends implement this trait.
36#[async_trait]
37pub trait KnowledgeGraph: Send + Sync {
38    // ─────────────────────────────────────────────────────────────────────────
39    // Entity Operations
40    // ─────────────────────────────────────────────────────────────────────────
41
42    /// Create a new entity
43    async fn create_entity(&self, entity: NewEntity, project: &ProjectId) -> Result<Entity>;
44
45    /// Get an entity by name
46    async fn get_entity(&self, name: &str, project: &ProjectId) -> Result<Option<Entity>>;
47
48    /// Get multiple entities by name
49    async fn get_entities(&self, names: &[String], project: &ProjectId) -> Result<Vec<Entity>>;
50
51    /// Update an entity
52    async fn update_entity(&self, entity: &Entity) -> Result<Entity>;
53
54    /// Delete an entity and its relations
55    async fn delete_entity(&self, name: &str, project: &ProjectId) -> Result<()>;
56
57    /// Add observations to an entity
58    async fn add_observations(
59        &self,
60        name: &str,
61        observations: Vec<String>,
62        project: &ProjectId,
63    ) -> Result<Entity>;
64
65    /// Remove specific observations from an entity
66    async fn remove_observations(
67        &self,
68        name: &str,
69        observation_ids: &[String],
70        project: &ProjectId,
71    ) -> Result<Entity>;
72
73    /// Add tags to an entity
74    async fn add_tags(&self, name: &str, tags: Vec<String>, project: &ProjectId) -> Result<Entity>;
75
76    /// Remove tags from an entity
77    async fn remove_tags(
78        &self,
79        name: &str,
80        tags: &[String],
81        project: &ProjectId,
82    ) -> Result<Entity>;
83
84    // ─────────────────────────────────────────────────────────────────────────
85    // Relation Operations
86    // ─────────────────────────────────────────────────────────────────────────
87
88    /// Create a new relation
89    async fn create_relation(&self, relation: NewRelation, project: &ProjectId)
90        -> Result<Relation>;
91
92    /// Get relations for an entity
93    async fn get_relations(
94        &self,
95        entity_name: &str,
96        direction: Direction,
97        project: &ProjectId,
98    ) -> Result<Vec<Relation>>;
99
100    /// Delete a relation
101    async fn delete_relation(
102        &self,
103        from: &str,
104        to: &str,
105        relation_type: &str,
106        project: &ProjectId,
107    ) -> Result<()>;
108
109    // ─────────────────────────────────────────────────────────────────────────
110    // Graph Operations
111    // ─────────────────────────────────────────────────────────────────────────
112
113    /// Read the entire graph for a project
114    async fn read_graph(&self, project: &ProjectId) -> Result<Graph>;
115
116    /// Traverse the graph from a starting entity
117    async fn traverse(
118        &self,
119        start: &str,
120        depth: u32,
121        direction: Direction,
122        project: &ProjectId,
123    ) -> Result<Graph>;
124
125    // ─────────────────────────────────────────────────────────────────────────
126    // Search Operations
127    // ─────────────────────────────────────────────────────────────────────────
128
129    /// Search entities
130    async fn search(&self, query: SearchQuery) -> Result<PaginatedResults<Entity>>;
131
132    // ─────────────────────────────────────────────────────────────────────────
133    // Project Operations
134    // ─────────────────────────────────────────────────────────────────────────
135
136    /// List all projects
137    async fn list_projects(&self) -> Result<Vec<Project>>;
138
139    /// Create a new project
140    async fn create_project(&self, name: &str, description: Option<&str>) -> Result<Project>;
141
142    /// Get a project by name
143    async fn get_project(&self, name: &str) -> Result<Option<Project>>;
144
145    /// Get a project by ID
146    async fn get_project_by_id(&self, id: &ProjectId) -> Result<Option<Project>>;
147
148    /// Delete a project and all its data
149    async fn delete_project(&self, name: &str) -> Result<()>;
150
151    /// Get or create the default project
152    async fn get_or_create_default_project(&self) -> Result<Project>;
153}
154
155#[cfg(test)]
156mod tests {
157    use super::*;
158
159    #[test]
160    fn test_graph_builder() {
161        let graph = Graph::new()
162            .with_entities(vec![])
163            .with_relations(vec![]);
164
165        assert!(graph.entities.is_empty());
166        assert!(graph.relations.is_empty());
167    }
168}