Repository navigation
Expand file tree
/
Copy pathexecutor.rs
More file actions
142 lines (128 loc) · 4.11 KB
/
Copy pathexecutor.rs
File metadata and controls
142 lines (128 loc) · 4.11 KB
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
use std::fmt::Debug;
use either::Either;
use futures_core::future::BoxFuture;
use futures_core::stream::BoxStream;
use futures_util::{future, FutureExt, StreamExt, TryFutureExt, TryStreamExt};
use crate::database::{Database, HasArguments, HasRawValue};
use crate::error::Error;
use crate::value::RawValue;
/// A type that contains or can provide a database
/// connection to use for executing queries against the database.
///
/// No guarantees are provided that successive queries run on the same
/// physical database connection.
///
/// A [`Connection`](crate::connection::Connection) is an `Executor` that guarantees that
/// successive queries are ran on the same physical database connection.
///
/// Implemented for the following:
///
/// * [`&Pool`]
/// * [`&mut PoolConnection`]
/// * [`&mut Connection`]
/// * [`&mut Transaction`]
///
pub trait Executor<'c>: Send + Debug + Sized {
type Database: Database;
/// Execute the query and return the total number of rows affected.
fn execute<'q: 'c, E>(self, query: E) -> BoxFuture<'c, Result<u64, Error>>
where
E: Execute<'q, Self::Database>,
{
self.execute_many(query)
.try_fold(0, |acc, x| async move { Ok(acc + x) })
.boxed()
}
/// Execute multiple queries and return the rows affected from each query, in a stream.
fn execute_many<'q: 'c, E>(self, query: E) -> BoxStream<'c, Result<u64, Error>>
where
E: Execute<'q, Self::Database>,
{
self.fetch_many(query)
.try_filter_map(|step| async move {
Ok(match step {
Either::Left(rows) => Some(rows),
Either::Right(row) => None,
})
})
.boxed()
}
/// Execute the query and return the generated results as a stream.
fn fetch<'q: 'c, E>(
self,
query: E,
) -> BoxStream<'c, Result<<Self::Database as Database>::Row, Error>>
where
E: Execute<'q, Self::Database>,
{
self.fetch_many(query)
.try_filter_map(|step| async move {
Ok(match step {
Either::Left(_) => None,
Either::Right(row) => Some(row),
})
})
.boxed()
}
/// Execute multiple queries and return the generated results as a stream
/// from each query, in a stream.
fn fetch_many<'q: 'c, E>(
self,
query: E,
) -> BoxStream<'c, Result<Either<u64, <Self::Database as Database>::Row>, Error>>
where
E: Execute<'q, Self::Database>;
/// Execute the query and return all the generated results, collected into a [`Vec`].
fn fetch_all<'q: 'c, E>(
self,
query: E,
) -> BoxFuture<'c, Result<Vec<<Self::Database as Database>::Row>, Error>>
where
E: Execute<'q, Self::Database>,
{
self.fetch(query).try_collect().boxed()
}
/// Execute the query and returns exactly one row.
fn fetch_one<'q: 'c, E>(
self,
query: E,
) -> BoxFuture<'c, Result<<Self::Database as Database>::Row, Error>>
where
E: Execute<'q, Self::Database>,
{
self.fetch_optional(query)
.and_then(|row| match row {
Some(row) => future::ok(row),
None => future::err(Error::RowNotFound),
})
.boxed()
}
/// Execute the query and returns at most one row.
fn fetch_optional<'q: 'c, E>(
self,
query: E,
) -> BoxFuture<'c, Result<Option<<Self::Database as Database>::Row>, Error>>
where
E: Execute<'q, Self::Database>;
}
/// A type that may be executed against a database connection.
///
/// Implemented for the following:
///
/// * [`&str`]
/// * [`Query`]
///
pub trait Execute<'q, DB: Database>: Send {
fn query(&self) -> &'q str;
fn take_arguments(&mut self) -> Option<<DB as HasArguments<'q>>::Arguments>;
}
impl<'q, DB: Database> Execute<'q, DB> for &'q str {
#[inline]
fn query(&self) -> &'q str {
self
}
#[inline]
fn take_arguments(&mut self) -> Option<<DB as HasArguments<'q>>::Arguments> {
None
}
}