Skip to main content

nexus_sdk/
schema.rs

1//! Schema management operations
2
3use crate::client::NexusClient;
4use crate::error::{NexusError, Result};
5use serde::{Deserialize, Serialize};
6
7/// Create label request
8#[derive(Debug, Clone, Serialize)]
9pub struct CreateLabelRequest {
10    /// Label name
11    pub name: String,
12}
13
14/// Create label response
15#[derive(Debug, Clone, Deserialize)]
16pub struct CreateLabelResponse {
17    /// Label ID (may be 0 if error)
18    #[serde(default)]
19    pub label_id: u32,
20    /// Success message
21    pub message: String,
22    /// Error message if any
23    #[serde(skip_serializing_if = "Option::is_none")]
24    pub error: Option<String>,
25}
26
27/// One entry returned by `GET /schema/labels`.
28///
29/// The wire shape is `{"name": "Person", "id": 0}`. Earlier versions
30/// of the SDK exposed this as `Vec<(String, u32)>` and external
31/// callers split the tuple as `(name, count)` because the second
32/// member was unnamed (issue #2). The struct form keeps the meaning
33/// explicit and lets us add fields (e.g. `count`) without another
34/// breaking rename.
35#[derive(Debug, Clone, Deserialize, Serialize)]
36pub struct LabelInfo {
37    /// Label name as registered in the engine catalog.
38    pub name: String,
39    /// Catalog id allocated to this label.
40    pub id: u32,
41}
42
43/// List labels response
44#[derive(Debug, Clone, Deserialize)]
45pub struct ListLabelsResponse {
46    /// Labels registered in the catalog with their allocated ids.
47    pub labels: Vec<LabelInfo>,
48    /// Error message if any
49    #[serde(skip_serializing_if = "Option::is_none")]
50    pub error: Option<String>,
51}
52
53/// Create relationship type request
54#[derive(Debug, Clone, Serialize)]
55pub struct CreateRelTypeRequest {
56    /// Relationship type name
57    pub name: String,
58}
59
60/// Create relationship type response
61#[derive(Debug, Clone, Deserialize)]
62pub struct CreateRelTypeResponse {
63    /// Relationship type ID (may be 0 if error)
64    #[serde(default)]
65    pub type_id: u32,
66    /// Success message
67    pub message: String,
68    /// Error message if any
69    #[serde(skip_serializing_if = "Option::is_none")]
70    pub error: Option<String>,
71}
72
73/// One entry returned by `GET /schema/rel_types`.
74///
75/// Mirrors `LabelInfo` — same rationale, see issue #2.
76#[derive(Debug, Clone, Deserialize, Serialize)]
77pub struct RelTypeInfo {
78    /// Relationship type name as registered in the catalog.
79    pub name: String,
80    /// Catalog id allocated to this relationship type.
81    pub id: u32,
82}
83
84/// List relationship types response
85#[derive(Debug, Clone, Deserialize)]
86pub struct ListRelTypesResponse {
87    /// Relationship types registered in the catalog with their ids.
88    pub types: Vec<RelTypeInfo>,
89    /// Error message if any
90    #[serde(skip_serializing_if = "Option::is_none")]
91    pub error: Option<String>,
92}
93
94impl NexusClient {
95    /// Create a new label
96    ///
97    /// # Arguments
98    ///
99    /// * `name` - Label name
100    ///
101    /// # Example
102    ///
103    /// ```no_run
104    /// # use nexus_sdk::NexusClient;
105    /// # #[tokio::main]
106    /// # async fn main() -> Result<(), nexus_sdk::NexusError> {
107    /// # let client = NexusClient::new("http://localhost:15474")?;
108    /// let response = client.create_label("Person".to_string()).await?;
109    /// tracing::info!("Create label result: {}", response.message);
110    /// # Ok(())
111    /// # }
112    /// ```
113    pub async fn create_label(&self, name: String) -> Result<CreateLabelResponse> {
114        let request = CreateLabelRequest { name };
115
116        let url = self.get_base_url().join("/schema/labels")?;
117        let mut request_builder = self.get_client().post(url).json(&request);
118
119        request_builder = self.add_auth_headers(request_builder)?;
120
121        let response = self.execute_with_retry(request_builder).await?;
122        let status = response.status();
123
124        if status.is_success() {
125            let result: CreateLabelResponse = response.json().await?;
126            Ok(result)
127        } else {
128            let error_text = response
129                .text()
130                .await
131                .unwrap_or_else(|_| "Unknown error".to_string());
132            Err(NexusError::Api {
133                message: error_text,
134                status: status.as_u16(),
135            })
136        }
137    }
138
139    /// List all labels
140    ///
141    /// # Example
142    ///
143    /// ```no_run
144    /// # use nexus_sdk::NexusClient;
145    /// # #[tokio::main]
146    /// # async fn main() -> Result<(), nexus_sdk::NexusError> {
147    /// # let client = NexusClient::new("http://localhost:15474")?;
148    /// let response = client.list_labels().await?;
149    /// tracing::info!("Labels: {:?}", response.labels);
150    /// # Ok(())
151    /// # }
152    /// ```
153    pub async fn list_labels(&self) -> Result<ListLabelsResponse> {
154        let url = self.get_base_url().join("/schema/labels")?;
155        let mut request_builder = self.get_client().get(url);
156
157        request_builder = self.add_auth_headers(request_builder)?;
158
159        let response = self.execute_with_retry(request_builder).await?;
160        let status = response.status();
161
162        if status.is_success() {
163            let result: ListLabelsResponse = response.json().await?;
164            Ok(result)
165        } else {
166            let error_text = response
167                .text()
168                .await
169                .unwrap_or_else(|_| "Unknown error".to_string());
170            Err(NexusError::Api {
171                message: error_text,
172                status: status.as_u16(),
173            })
174        }
175    }
176
177    /// Create a new relationship type
178    ///
179    /// # Arguments
180    ///
181    /// * `name` - Relationship type name
182    ///
183    /// # Example
184    ///
185    /// ```no_run
186    /// # use nexus_sdk::NexusClient;
187    /// # #[tokio::main]
188    /// # async fn main() -> Result<(), nexus_sdk::NexusError> {
189    /// # let client = NexusClient::new("http://localhost:15474")?;
190    /// let response = client.create_rel_type("KNOWS".to_string()).await?;
191    /// tracing::info!("Create rel type result: {}", response.message);
192    /// # Ok(())
193    /// # }
194    /// ```
195    pub async fn create_rel_type(&self, name: String) -> Result<CreateRelTypeResponse> {
196        let request = CreateRelTypeRequest { name };
197
198        let url = self.get_base_url().join("/schema/rel_types")?;
199        let mut request_builder = self.get_client().post(url).json(&request);
200
201        request_builder = self.add_auth_headers(request_builder)?;
202
203        let response = self.execute_with_retry(request_builder).await?;
204        let status = response.status();
205
206        if status.is_success() {
207            let result: CreateRelTypeResponse = response.json().await?;
208            Ok(result)
209        } else {
210            let error_text = response
211                .text()
212                .await
213                .unwrap_or_else(|_| "Unknown error".to_string());
214            Err(NexusError::Api {
215                message: error_text,
216                status: status.as_u16(),
217            })
218        }
219    }
220
221    /// List all relationship types
222    ///
223    /// # Example
224    ///
225    /// ```no_run
226    /// # use nexus_sdk::NexusClient;
227    /// # #[tokio::main]
228    /// # async fn main() -> Result<(), nexus_sdk::NexusError> {
229    /// # let client = NexusClient::new("http://localhost:15474")?;
230    /// let response = client.list_rel_types().await?;
231    /// tracing::info!("Relationship types: {:?}", response.types);
232    /// # Ok(())
233    /// # }
234    /// ```
235    pub async fn list_rel_types(&self) -> Result<ListRelTypesResponse> {
236        let url = self.get_base_url().join("/schema/rel_types")?;
237        let mut request_builder = self.get_client().get(url);
238
239        request_builder = self.add_auth_headers(request_builder)?;
240
241        let response = self.execute_with_retry(request_builder).await?;
242        let status = response.status();
243
244        if status.is_success() {
245            let result: ListRelTypesResponse = response.json().await?;
246            Ok(result)
247        } else {
248            let error_text = response
249                .text()
250                .await
251                .unwrap_or_else(|_| "Unknown error".to_string());
252            Err(NexusError::Api {
253                message: error_text,
254                status: status.as_u16(),
255            })
256        }
257    }
258}