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
use crate::arguments::Arguments;
use crate::arguments::IntoArguments;
use crate::database::Database;
use crate::encode::Encode;
use crate::executor::Executor;
use crate::types::HasSqlType;
use futures_core::stream::BoxStream;
use futures_util::TryStreamExt;
use std::marker::PhantomData;

/// Dynamic SQL query with bind parameters. Returned by [query].
///
/// The methods on this struct should be passed a reference to [crate::Pool] or one of
/// the connection types.
pub struct Query<'q, DB, T = <DB as Database>::Arguments>
where
    DB: Database,
{
    query: &'q str,
    arguments: T,
    database: PhantomData<DB>,
}

impl<'q, DB, P> Query<'q, DB, P>
where
    DB: Database,
    P: IntoArguments<DB> + Send,
{
    /// Execute the query for its side-effects.
    ///
    /// Returns the number of rows affected, or 0 if not applicable.
    pub async fn execute<E>(self, executor: &mut E) -> crate::Result<u64>
    where
        E: Executor<Database = DB>,
    {
        executor
            .execute(self.query, self.arguments.into_arguments())
            .await
    }

    /// Execute the query, returning the rows as a futures `Stream`.
    ///
    /// Use [fetch_all] if you want a `Vec` instead.
    pub fn fetch<'e, E>(self, executor: &'e mut E) -> BoxStream<'e, crate::Result<DB::Row>>
    where
        E: Executor<Database = DB>,
        'q: 'e,
    {
        executor.fetch(self.query, self.arguments.into_arguments())
    }

    /// Execute the query and get all rows from the result as a `Vec`.
    pub async fn fetch_all<E>(self, executor: &mut E) -> crate::Result<Vec<DB::Row>>
    where
        E: Executor<Database = DB>,
    {
        executor
            .fetch(self.query, self.arguments.into_arguments())
            .try_collect()
            .await
    }

    /// Execute a query which should return either 0 or 1 rows.
    ///
    /// Returns [crate::Error::FoundMoreThanOne] if more than 1 row is returned.
    /// Use `.fetch().try_next()` if you just want one row.
    pub async fn fetch_optional<E>(self, executor: &mut E) -> crate::Result<Option<DB::Row>>
    where
        E: Executor<Database = DB>,
    {
        executor
            .fetch_optional(self.query, self.arguments.into_arguments())
            .await
    }

    /// Execute a query which should return exactly 1 row.
    ///
    /// * Returns [crate::Error::NotFound] if 0 rows are returned.
    /// * Returns [crate::Error::FoundMoreThanOne] if more than one row is returned.
    pub async fn fetch_one<E>(self, executor: &mut E) -> crate::Result<DB::Row>
    where
        E: Executor<Database = DB>,
    {
        executor
            .fetch_one(self.query, self.arguments.into_arguments())
            .await
    }
}

impl<'q, DB> Query<'q, DB>
where
    DB: Database,
{
    /// Bind a value for use with this SQL query.
    ///
    /// # Logic Safety
    ///
    /// This function should be used with care, as SQLx cannot validate
    /// that the value is of the right type nor can it validate that you have
    /// passed the correct number of parameters.
    pub fn bind<T>(mut self, value: T) -> Self
    where
        DB: HasSqlType<T>,
        T: Encode<DB>,
    {
        self.arguments.add(value);
        self
    }
}

/// Construct a full SQL query that can be chained to bind parameters and executed.
///
/// # Examples
///
/// ```ignore
/// let names: Vec<String> = sqlx::query("SELECT name FROM users WHERE active = ?")
///     .bind(false) // [active = ?]
///     .fetch(&mut connection) // -> Stream<Item = impl Row>
///     .map_ok(|row| row.name("name")) // -> Stream<Item = String>
///     .try_collect().await?; // -> Vec<String>
/// ```
pub fn query<DB>(sql: &str) -> Query<DB>
where
    DB: Database,
{
    Query {
        database: PhantomData,
        arguments: Default::default(),
        query: sql,
    }
}