1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
use crate::transaction::{Transaction, TransactionPool};
use crate::{DatabaseConnectionPool, ServiceError};
use arangors::transaction::{TransactionCollections, TransactionSettings};
use std::collections::HashMap;

const LOCK_TIMEOUT: usize = 60000;

/// Builder for Aragog [`Transaction`]
///
/// [`Transaction`]: struct.Transaction.html
pub struct TransactionBuilder {
    collections: Option<Vec<String>>,
    wait_for_sync: Option<bool>,
    lock_timeout: Option<usize>,
}

impl TransactionBuilder {
    /// Instantiates a new builder for a [`Transaction`]
    ///
    /// [`Transaction`]: struct.Transaction.html
    pub fn new() -> Self {
        Self::default()
    }

    /// The built transaction will be restricted to the specified collection names
    pub fn collections(mut self, collections: Vec<String>) -> Self {
        self.collections = Some(collections);
        self
    }

    /// The built transaction will wait for Database synchronization
    pub fn wait_for_sync(mut self) -> Self {
        self.wait_for_sync = Some(true);
        self
    }

    /// Defines the transaction lock timeout (default value: 60 000)
    pub fn lock_timeout(mut self, lock_timeout: usize) -> Self {
        self.lock_timeout = Some(lock_timeout);
        self
    }

    /// Builds the transaction with the database connection pool
    #[maybe_async::maybe_async]
    pub async fn build(
        self,
        db_pool: &DatabaseConnectionPool,
    ) -> Result<Transaction, ServiceError> {
        let collection_names = self.collections.unwrap_or(db_pool.collections_names());
        let accessor = db_pool
            .database
            .begin_transaction(
                TransactionSettings::builder()
                    .lock_timeout(self.lock_timeout.unwrap_or(LOCK_TIMEOUT))
                    .wait_for_sync(self.wait_for_sync.unwrap_or(false))
                    .collections(
                        TransactionCollections::builder()
                            .write(collection_names.clone())
                            .build(),
                    )
                    .build(),
            )
            .await?;
        log::trace!("Initialized ArangoDB transaction {}", accessor.id());
        // TODO: Change this for direct Collection<> transition when `arangors` supports it
        let mut collections = HashMap::new();
        for collections_name in db_pool.collections_names().iter() {
            let collection = accessor.collection(collections_name).await?;
            collections.insert(collections_name.clone(), collection);
        }
        //
        log::trace!("Initialized Aragog transaction pool");
        let database = db_pool.database.clone();
        Ok(Transaction {
            accessor,
            pool: TransactionPool {
                collections,
                database,
            },
        })
    }
}

impl Default for TransactionBuilder {
    fn default() -> Self {
        Self {
            collections: None,
            wait_for_sync: None,
            lock_timeout: None,
        }
    }
}