Skip to main content

nexus_sdk/
models.rs

1//! Data models for Nexus SDK
2
3use serde::{Deserialize, Serialize};
4use std::collections::HashMap;
5
6/// Cypher query result
7#[derive(Debug, Clone, Serialize, Deserialize)]
8pub struct QueryResult {
9    /// Column names
10    pub columns: Vec<String>,
11    /// Result rows (each row is an array of values)
12    pub rows: Vec<serde_json::Value>,
13    /// Execution time in milliseconds
14    #[serde(rename = "execution_time_ms")]
15    pub execution_time_ms: Option<u64>,
16    /// Error message if any
17    #[serde(skip_serializing_if = "Option::is_none")]
18    pub error: Option<String>,
19}
20
21/// A single row in a query result (helper for accessing row values)
22#[derive(Debug, Clone)]
23pub struct Row {
24    /// Row values
25    pub values: Vec<Value>,
26}
27
28impl Row {
29    /// Convert from serde_json::Value (array) to Row
30    pub fn from_json_value(value: &serde_json::Value) -> Option<Self> {
31        if let serde_json::Value::Array(arr) = value {
32            let values: Result<Vec<Value>, _> = arr
33                .iter()
34                .map(|v| serde_json::from_value(v.clone()))
35                .collect();
36            values.ok().map(|values| Row { values })
37        } else {
38            None
39        }
40    }
41}
42
43/// Value types in query results
44#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
45#[serde(untagged)]
46pub enum Value {
47    /// Null value
48    Null,
49    /// Boolean value
50    Bool(bool),
51    /// Integer value
52    Int(i64),
53    /// Float value
54    Float(f64),
55    /// String value
56    String(String),
57    /// Array value
58    Array(Vec<Value>),
59    /// Object value
60    Object(HashMap<String, Value>),
61}
62
63impl From<&str> for Value {
64    fn from(s: &str) -> Self {
65        Value::String(s.to_string())
66    }
67}
68
69impl From<String> for Value {
70    fn from(s: String) -> Self {
71        Value::String(s)
72    }
73}
74
75impl From<bool> for Value {
76    fn from(b: bool) -> Self {
77        Value::Bool(b)
78    }
79}
80
81impl From<i64> for Value {
82    fn from(i: i64) -> Self {
83        Value::Int(i)
84    }
85}
86
87impl From<i32> for Value {
88    fn from(i: i32) -> Self {
89        Value::Int(i as i64)
90    }
91}
92
93impl From<usize> for Value {
94    fn from(u: usize) -> Self {
95        Value::Int(u as i64)
96    }
97}
98
99impl From<f64> for Value {
100    fn from(f: f64) -> Self {
101        Value::Float(f)
102    }
103}
104
105impl From<f32> for Value {
106    fn from(f: f32) -> Self {
107        Value::Float(f as f64)
108    }
109}
110
111/// Node representation
112#[derive(Debug, Clone, Serialize, Deserialize)]
113pub struct Node {
114    /// Node ID
115    pub id: u64,
116    /// Node labels
117    pub labels: Vec<String>,
118    /// Node properties
119    pub properties: HashMap<String, Value>,
120}
121
122/// Relationship representation
123#[derive(Debug, Clone, Serialize, Deserialize)]
124pub struct Relationship {
125    /// Relationship ID
126    pub id: u64,
127    /// Relationship type
128    #[serde(rename = "type")]
129    pub rel_type: String,
130    /// Source node ID
131    pub source_id: u64,
132    /// Target node ID
133    pub target_id: u64,
134    /// Relationship properties
135    pub properties: HashMap<String, Value>,
136}
137
138/// Database statistics
139#[derive(Debug, Clone, Serialize, Deserialize)]
140pub struct DatabaseStats {
141    /// Catalog statistics
142    pub catalog: CatalogStats,
143    /// Label index statistics
144    #[serde(rename = "label_index")]
145    pub label_index: LabelIndexStats,
146    /// KNN index statistics
147    #[serde(rename = "knn_index")]
148    pub knn_index: KnnIndexStats,
149}
150
151/// Catalog statistics
152#[derive(Debug, Clone, Default, Serialize, Deserialize)]
153pub struct CatalogStats {
154    /// Number of labels
155    #[serde(rename = "label_count")]
156    pub label_count: usize,
157    /// Number of relationship types
158    #[serde(rename = "rel_type_count")]
159    pub rel_type_count: usize,
160    /// Number of nodes
161    #[serde(rename = "node_count")]
162    pub node_count: usize,
163    /// Number of relationships
164    #[serde(rename = "rel_count")]
165    pub rel_count: usize,
166}
167
168/// Label index statistics
169#[derive(Debug, Clone, Default, Serialize, Deserialize)]
170pub struct LabelIndexStats {
171    /// Number of indexed labels
172    #[serde(rename = "indexed_labels")]
173    pub indexed_labels: usize,
174    /// Total number of nodes
175    #[serde(rename = "total_nodes")]
176    pub total_nodes: usize,
177}
178
179/// KNN index statistics
180#[derive(Debug, Clone, Default, Serialize, Deserialize)]
181pub struct KnnIndexStats {
182    /// Total number of vectors
183    #[serde(rename = "total_vectors")]
184    pub total_vectors: usize,
185    /// Vector dimension
186    pub dimension: usize,
187    /// Average search time in microseconds
188    #[serde(rename = "avg_search_time_us")]
189    pub avg_search_time_us: f64,
190}
191
192/// Client configuration
193#[derive(Debug, Clone)]
194pub struct ClientConfig {
195    /// Endpoint URL. Accepts `nexus://host[:port]` (RPC default),
196    /// `http://host[:port]`, `https://host[:port]`, or bare
197    /// `host[:port]` (treated as `nexus://`).
198    pub base_url: String,
199    /// Explicit transport override. `None` means "infer from URL
200    /// scheme or NEXUS_SDK_TRANSPORT env var". See
201    /// [`docs/specs/sdk-transport.md`] for the precedence rules.
202    pub transport: Option<crate::transport::TransportMode>,
203    /// Default RPC port when the URL does not carry one.
204    pub rpc_port: u16,
205    /// Default RESP3 port when the URL does not carry one. Reserved;
206    /// not yet used by the SDK but accepted so a config that targets
207    /// a non-default RESP3 port compiles cleanly.
208    pub resp3_port: u16,
209    /// API key for authentication (optional)
210    pub api_key: Option<String>,
211    /// Username for authentication (optional)
212    pub username: Option<String>,
213    /// Password for authentication (optional)
214    pub password: Option<String>,
215    /// Request timeout in seconds
216    pub timeout_secs: u64,
217    /// Maximum number of retries
218    pub max_retries: u32,
219}
220
221impl Default for ClientConfig {
222    /// Default endpoint points at the native Nexus RPC listener on
223    /// the loopback. New SDK users get the fastest transport without
224    /// code changes; callers who need HTTP pass `http://host:15474`
225    /// or set `transport = Some(TransportMode::Http)`.
226    fn default() -> Self {
227        Self {
228            base_url: "nexus://127.0.0.1:15475".to_string(),
229            transport: None,
230            rpc_port: 15475,
231            resp3_port: 15476,
232            api_key: None,
233            username: None,
234            password: None,
235            timeout_secs: 30,
236            max_retries: 3,
237        }
238    }
239}
240
241/// Cypher query request
242#[derive(Debug, Clone, Serialize)]
243pub struct CypherRequest {
244    /// Cypher query string
245    pub query: String,
246    /// Query parameters (optional)
247    #[serde(skip_serializing_if = "Option::is_none")]
248    pub parameters: Option<HashMap<String, Value>>,
249}
250
251// ============================================================================
252// Database Management Models
253// ============================================================================
254
255/// Database information
256#[derive(Debug, Clone, Serialize, Deserialize)]
257pub struct DatabaseInfo {
258    /// Database name
259    pub name: String,
260    /// Database path
261    pub path: String,
262    /// Creation timestamp
263    #[serde(rename = "created_at")]
264    pub created_at: i64,
265    /// Number of nodes
266    #[serde(rename = "node_count")]
267    pub node_count: u64,
268    /// Number of relationships
269    #[serde(rename = "relationship_count")]
270    pub relationship_count: u64,
271    /// Storage size in bytes
272    #[serde(rename = "storage_size")]
273    pub storage_size: u64,
274}
275
276/// Response for listing databases
277#[derive(Debug, Clone, Serialize, Deserialize)]
278pub struct ListDatabasesResponse {
279    /// List of databases
280    pub databases: Vec<DatabaseInfo>,
281    /// Default database name
282    #[serde(rename = "default_database")]
283    pub default_database: String,
284}
285
286/// Request to create a database
287#[derive(Debug, Clone, Serialize)]
288pub struct CreateDatabaseRequest {
289    /// Database name
290    pub name: String,
291}
292
293/// Response for creating a database
294#[derive(Debug, Clone, Serialize, Deserialize)]
295pub struct CreateDatabaseResponse {
296    /// Success flag
297    pub success: bool,
298    /// Database name
299    pub name: String,
300    /// Message
301    pub message: String,
302}
303
304/// Response for dropping a database
305#[derive(Debug, Clone, Serialize, Deserialize)]
306pub struct DropDatabaseResponse {
307    /// Success flag
308    pub success: bool,
309    /// Message
310    pub message: String,
311}
312
313/// Response for session database
314#[derive(Debug, Clone, Serialize, Deserialize)]
315pub struct SessionDatabaseResponse {
316    /// Current database name
317    pub database: String,
318}
319
320/// Request to switch database
321#[derive(Debug, Clone, Serialize)]
322pub struct SwitchDatabaseRequest {
323    /// Database name to switch to
324    pub name: String,
325}
326
327/// Response for switching database
328#[derive(Debug, Clone, Serialize, Deserialize)]
329pub struct SwitchDatabaseResponse {
330    /// Success flag
331    pub success: bool,
332    /// Message
333    pub message: String,
334}