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
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
mod statement_cache;
mod transaction_manager;

use backend::Backend;
use query_builder::{AsQuery, QueryFragment, QueryId};
use query_source::Queryable;
use result::*;
use types::HasSqlType;

pub use self::transaction_manager::{TransactionManager, AnsiTransactionManager};
#[doc(hidden)]
pub use self::statement_cache::{StatementCache, StatementCacheKey, MaybeCached};

/// Perform simple operations on a backend.
pub trait SimpleConnection {
    /// Execute multiple SQL statements within the same string.
    ///
    /// This function is typically used in migrations where the statements to upgrade or
    /// downgrade the database are stored in SQL batch files.
    fn batch_execute(&self, query: &str) -> QueryResult<()>;
}

/// Perform connections to a backend.
pub trait Connection: SimpleConnection + Sized + Send {
    /// The backend this connection represents.
    type Backend: Backend;
    #[doc(hidden)]
    type TransactionManager: TransactionManager<Self>;

    /// Establishes a new connection to the database at the given URL. The URL
    /// should be a valid connection string for a given backend. See the
    /// documentation for the specific backend for specifics.
    fn establish(database_url: &str) -> ConnectionResult<Self>;

    /// Executes the given function inside of a database transaction. When
    /// a transaction is already occurring, savepoints will be used to emulate a nested
    /// transaction.
    ///
    /// The error returned from the function must implement
    /// `From<diesel::result::Error>`.
    ///
    /// # Examples:
    ///
    /// ```rust
    /// # #[macro_use] extern crate diesel;
    /// # #[macro_use] extern crate diesel_codegen;
    /// # include!("src/doctest_setup.rs");
    /// # table!(
    /// #    users(id) {
    /// #        id -> Integer,
    /// #        name -> Varchar,
    /// #    }
    /// # );
    /// # #[derive(Queryable, Debug, PartialEq)]
    /// # struct User {
    /// #     id: i32,
    /// #     name: String,
    /// # }
    /// use diesel::result::Error;
    ///
    /// fn main() {
    ///     let conn = establish_connection();
    ///     let _ = conn.transaction::<_, Error, _>(|| {
    ///         let new_user = NewUser { name: "Ruby".into() };
    ///         diesel::insert(&new_user).into(users::table).execute(&conn)?;
    ///         assert_eq!(users::table.load::<User>(&conn), Ok(vec![
    ///             User { id: 1, name: "Sean".into() },
    ///             User { id: 2, name: "Tess".into() },
    ///             User { id: 3, name: "Ruby".into() },
    ///         ]));
    ///
    ///         Ok(())
    ///     });
    ///
    ///     let _ = conn.transaction::<(), Error, _>(|| {
    ///         let new_user = NewUser { name: "Pascal".into() };
    ///         diesel::insert(&new_user).into(users::table).execute(&conn)?;
    ///
    ///         assert_eq!(users::table.load::<User>(&conn), Ok(vec![
    ///             User { id: 1, name: "Sean".into() },
    ///             User { id: 2, name: "Tess".into() },
    ///             User { id: 3, name: "Ruby".into() },
    ///             User { id: 4, name: "Pascal".into() },
    ///         ]));
    ///
    ///         Err(Error::RollbackTransaction) // Oh noeees, something bad happened :(
    ///     });
    ///
    ///     assert_eq!(users::table.load::<User>(&conn), Ok(vec![
    ///         User { id: 1, name: "Sean".into() },
    ///         User { id: 2, name: "Tess".into() },
    ///         User { id: 3, name: "Ruby".into() },
    ///     ]));
    /// }
    /// ```
    fn transaction<T, E, F>(&self, f: F) -> Result<T, E> where
        F: FnOnce() -> Result<T, E>,
        E: From<Error>,
    {
        let transaction_manager = self.transaction_manager();
        try!(transaction_manager.begin_transaction(self));
        match f() {
            Ok(value) => {
                try!(transaction_manager.commit_transaction(self));
                Ok(value)
            },
            Err(e) => {
                try!(transaction_manager.rollback_transaction(self));
                Err(e)
            },
        }
    }

    /// Creates a transaction that will never be committed. This is useful for
    /// tests. Panics if called while inside of a transaction.
    fn begin_test_transaction(&self) -> QueryResult<()> {
        let transaction_manager = self.transaction_manager();
        assert_eq!(transaction_manager.get_transaction_depth(), 0);
        transaction_manager.begin_transaction(self)
    }

    /// Executes the given function inside a transaction, but does not commit
    /// it. Panics if the given function returns an `Err`.
    fn test_transaction<T, E, F>(&self, f: F) -> T where
        F: FnOnce() -> Result<T, E>,
    {
        let mut user_result = None;
        let _ = self.transaction::<(), _, _>(|| {
            user_result = f().ok();
            Err(Error::RollbackTransaction)
        });
        user_result.expect("Transaction did not succeed")
    }

    #[doc(hidden)]
    fn execute(&self, query: &str) -> QueryResult<usize>;

    #[doc(hidden)]
    fn query_by_index<T, U>(&self, source: T) -> QueryResult<Vec<U>> where
        T: AsQuery,
        T::Query: QueryFragment<Self::Backend> + QueryId,
        Self::Backend: HasSqlType<T::SqlType>,
        U: Queryable<T::SqlType, Self::Backend>;

    #[doc(hidden)]
    fn execute_returning_count<T>(&self, source: &T) -> QueryResult<usize> where
        T: QueryFragment<Self::Backend> + QueryId;

    #[doc(hidden)] fn silence_notices<F: FnOnce() -> T, T>(&self, f: F) -> T;
    #[doc(hidden)] fn transaction_manager(&self) -> &Self::TransactionManager;
}