use super::bridge::SendToTransactionClientActor;
use super::interface::{Committed, InProgress, RolledBack, Transaction};
use nanoservices_utils::errors::NanoServiceError;
use std::marker::PhantomData;
use surrealcs_kernel::messages::server::interface::{ServerMessage, ServerTransactionMessage};
impl Transaction<InProgress> {
pub async fn send<T: SendToTransactionClientActor>(
&mut self,
message: ServerTransactionMessage,
) -> Result<ServerTransactionMessage, NanoServiceError> {
let message = ServerMessage::SendOperation(message);
T::send_to_transaction_client_actor(self, message).await
}
pub async fn commit<T: SendToTransactionClientActor>(
mut self,
) -> Result<(ServerTransactionMessage, Transaction<Committed>), NanoServiceError> {
let message = ServerMessage::CommitTransaction;
let outcome = T::send_to_transaction_client_actor(&mut self, message).await?;
let committed_transaction = Transaction {
client_id: self.client_id,
server_id: self.server_id,
receiver: self.receiver,
sender: self.sender.clone(),
connection_id: self.connection_id,
transaction_id: self.transaction_id,
state: PhantomData,
};
Ok((outcome, committed_transaction))
}
#[allow(dead_code)]
pub async fn rollback<T: SendToTransactionClientActor>(
mut self,
) -> Result<Transaction<RolledBack>, NanoServiceError> {
let message = ServerMessage::RollbackTransaction;
let _ = T::send_to_transaction_client_actor(&mut self, message).await?;
let rolled_back_transaction = Transaction {
client_id: self.client_id,
server_id: self.server_id,
receiver: self.receiver,
sender: self.sender.clone(),
connection_id: self.connection_id,
transaction_id: self.transaction_id,
state: PhantomData,
};
Ok(rolled_back_transaction)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::generate_mock_handle;
use std::future::Future;
use surrealcs_kernel::messages::server::interface::ServerTransactionMessage;
use surrealcs_kernel::messages::server::kv_operations::{MessageGet, ResponseGet};
use tokio::sync::mpsc;
#[tokio::test]
async fn test_send() {
generate_mock_handle! {
struct MockHandle;
match ServerMessage::SendOperation(message) => {
match message {
ServerTransactionMessage::Get(message) => {
assert_eq!(message.key, b"keys".to_vec());
}
_ => {
panic!("message not as expected: {:?}", message);
}
}
}
return Ok(ServerTransactionMessage::ResponseGet(
ResponseGet { value: Some(b"value".to_vec()) }
));
}
let (tx, _rx) = mpsc::channel(32);
let (_h_tx, h_rx) = mpsc::channel(32);
let mut transaction = Transaction::<InProgress> {
client_id: 1,
server_id: None,
receiver: h_rx,
sender: tx,
connection_id: "connection_id".to_string(),
transaction_id: "transaction_id".to_string(),
state: PhantomData,
};
let message = ServerTransactionMessage::Get(MessageGet {
key: b"keys".to_vec(),
version: None,
});
let outcome = transaction.send::<MockHandle>(message).await.unwrap();
let response = match outcome {
ServerTransactionMessage::ResponseGet(response) => response,
_ => panic!("Response not Get"),
};
assert_eq!(response.value, Some(b"value".to_vec()));
}
#[tokio::test]
async fn test_commit() {
generate_mock_handle! {
struct MockHandle;
match ServerMessage::CommitTransaction => {}
return Ok(ServerTransactionMessage::EmptyResponse);
}
let (tx, _rx) = mpsc::channel(32);
let (_h_tx, h_rx) = mpsc::channel(32);
let transaction = Transaction::<InProgress> {
client_id: 1,
server_id: None,
receiver: h_rx,
sender: tx,
connection_id: "connection_id".to_string(),
transaction_id: "transaction_id".to_string(),
state: PhantomData,
};
let _transaction = transaction.commit::<MockHandle>().await.unwrap();
}
#[tokio::test]
async fn test_rollback() {
generate_mock_handle! {
struct MockHandle;
match ServerMessage::RollbackTransaction => {}
return Ok(ServerTransactionMessage::ResponseRolledBack(
true
));
}
let (tx, _rx) = mpsc::channel(32);
let (_h_tx, h_rx) = mpsc::channel(32);
let transaction = Transaction::<InProgress> {
client_id: 1,
server_id: None,
receiver: h_rx,
sender: tx,
connection_id: "connection_id".to_string(),
transaction_id: "transaction_id".to_string(),
state: PhantomData,
};
let _transaction = transaction.rollback::<MockHandle>().await.unwrap();
}
}