Skip to main content

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}