nexus_sdk/transaction.rs
1//! Transaction support for Nexus SDK
2
3use crate::client::NexusClient;
4use crate::error::{NexusError, Result};
5
6/// Transaction handle for managing database transactions
7#[derive(Debug, Clone)]
8pub struct Transaction {
9 client: NexusClient,
10 transaction_id: Option<String>,
11 active: bool,
12}
13
14/// Transaction status
15#[derive(Debug, Clone, Copy, PartialEq, Eq)]
16pub enum TransactionStatus {
17 /// Transaction is active
18 Active,
19 /// Transaction has been committed
20 Committed,
21 /// Transaction has been rolled back
22 RolledBack,
23 /// Transaction is not started
24 NotStarted,
25}
26
27impl Transaction {
28 /// Create a new transaction handle
29 pub(crate) fn new(client: NexusClient) -> Self {
30 Self {
31 client,
32 transaction_id: None,
33 active: false,
34 }
35 }
36
37 /// Begin a new transaction
38 ///
39 /// # Example
40 ///
41 /// ```no_run
42 /// # use nexus_sdk::NexusClient;
43 /// # #[tokio::main]
44 /// # async fn main() -> Result<(), nexus_sdk::NexusError> {
45 /// # let client = NexusClient::new("http://localhost:15474")?;
46 /// let mut tx = client.begin_transaction().await?;
47 /// // Perform operations...
48 /// tx.commit().await?;
49 /// # Ok(())
50 /// # }
51 /// ```
52 pub async fn begin(&mut self) -> Result<()> {
53 if self.active {
54 return Err(NexusError::Validation(
55 "Transaction already active".to_string(),
56 ));
57 }
58
59 let _result = self
60 .client
61 .execute_cypher("BEGIN TRANSACTION", None)
62 .await?;
63
64 self.active = true;
65 self.transaction_id = Some(format!(
66 "tx_{}",
67 std::time::SystemTime::now()
68 .duration_since(std::time::UNIX_EPOCH)
69 .unwrap()
70 .as_nanos()
71 ));
72
73 Ok(())
74 }
75
76 /// Commit the transaction
77 ///
78 /// # Example
79 ///
80 /// ```no_run
81 /// # use nexus_sdk::{NexusClient, Transaction};
82 /// # #[tokio::main]
83 /// # async fn main() -> Result<(), nexus_sdk::NexusError> {
84 /// # let client = NexusClient::new("http://localhost:15474")?;
85 /// # let mut tx: Transaction = client.begin_transaction().await?;
86 /// tx.commit().await?;
87 /// # Ok(())
88 /// # }
89 /// ```
90 pub async fn commit(&mut self) -> Result<()> {
91 if !self.active {
92 return Err(NexusError::Validation(
93 "No active transaction to commit".to_string(),
94 ));
95 }
96
97 let _result = self
98 .client
99 .execute_cypher("COMMIT TRANSACTION", None)
100 .await?;
101
102 self.active = false;
103 self.transaction_id = None;
104
105 Ok(())
106 }
107
108 /// Rollback the transaction
109 ///
110 /// # Example
111 ///
112 /// ```no_run
113 /// # use nexus_sdk::{NexusClient, Transaction};
114 /// # #[tokio::main]
115 /// # async fn main() -> Result<(), nexus_sdk::NexusError> {
116 /// # let client = NexusClient::new("http://localhost:15474")?;
117 /// # let mut tx: Transaction = client.begin_transaction().await?;
118 /// tx.rollback().await?;
119 /// # Ok(())
120 /// # }
121 /// ```
122 pub async fn rollback(&mut self) -> Result<()> {
123 if !self.active {
124 return Err(NexusError::Validation(
125 "No active transaction to rollback".to_string(),
126 ));
127 }
128
129 let _result = self
130 .client
131 .execute_cypher("ROLLBACK TRANSACTION", None)
132 .await?;
133
134 self.active = false;
135 self.transaction_id = None;
136
137 Ok(())
138 }
139
140 /// Check if transaction is active
141 pub fn is_active(&self) -> bool {
142 self.active
143 }
144
145 /// Get transaction status
146 pub fn status(&self) -> TransactionStatus {
147 if self.active {
148 TransactionStatus::Active
149 } else if self.transaction_id.is_some() {
150 TransactionStatus::Committed
151 } else {
152 TransactionStatus::NotStarted
153 }
154 }
155
156 /// Execute a Cypher query within this transaction
157 ///
158 /// # Example
159 ///
160 /// ```no_run
161 /// # use nexus_sdk::{NexusClient, Transaction};
162 /// # use std::collections::HashMap;
163 /// # #[tokio::main]
164 /// # async fn main() -> Result<(), nexus_sdk::NexusError> {
165 /// # let client = NexusClient::new("http://localhost:15474")?;
166 /// # let mut tx: Transaction = client.begin_transaction().await?;
167 /// let result = tx.execute("CREATE (n:Person {name: 'Alice'}) RETURN n", None).await?;
168 /// tx.commit().await?;
169 /// # Ok(())
170 /// # }
171 /// ```
172 pub async fn execute(
173 &self,
174 query: &str,
175 params: Option<std::collections::HashMap<String, crate::models::Value>>,
176 ) -> Result<crate::models::QueryResult> {
177 if !self.active {
178 return Err(NexusError::Validation(
179 "Transaction is not active".to_string(),
180 ));
181 }
182
183 self.client.execute_cypher(query, params).await
184 }
185}
186
187impl NexusClient {
188 /// Begin a new transaction
189 ///
190 /// # Example
191 ///
192 /// ```no_run
193 /// # use nexus_sdk::{NexusClient, Transaction};
194 /// # #[tokio::main]
195 /// # async fn main() -> Result<(), nexus_sdk::NexusError> {
196 /// # let client = NexusClient::new("http://localhost:15474")?;
197 /// let mut tx: Transaction = client.begin_transaction().await?;
198 /// // Perform operations...
199 /// tx.commit().await?;
200 /// # Ok(())
201 /// # }
202 /// ```
203 pub async fn begin_transaction(&self) -> Result<Transaction> {
204 let mut tx = Transaction::new(self.clone());
205 tx.begin().await?;
206 Ok(tx)
207 }
208}