1use std::future::Future;
2
3use keelson_core::{FromValue, Query};
4
5use crate::error::ExecError;
6use crate::executor::{ExecResult, Executor, Statement};
7use crate::row::{FromRow, Row};
8
9pub trait Execute: Query {
23 fn fetch_all<T: FromRow>(
25 &self,
26 db: &(impl Executor + ?Sized),
27 ) -> impl Future<Output = Result<Vec<T>, ExecError>> + Send {
28 let stmt = Statement::from_query(self);
29 async move {
30 let rows = run_fetch(db, stmt?).await?;
31 rows.into_iter().map(|mut r| T::from_row(&mut r)).collect()
32 }
33 }
34
35 fn fetch_rows(
44 &self,
45 db: &(impl Executor + ?Sized),
46 ) -> impl Future<Output = Result<Vec<Row>, ExecError>> + Send {
47 let stmt = Statement::from_query(self);
48 async move { run_fetch(db, stmt?).await }
49 }
50
51 fn fetch_one<T: FromRow>(
54 &self,
55 db: &(impl Executor + ?Sized),
56 ) -> impl Future<Output = Result<T, ExecError>> + Send {
57 let stmt = Statement::from_query(self);
58 async move {
59 let mut rows = run_fetch(db, stmt?).await?;
60 match rows.len() {
61 0 => Err(ExecError::RowNotFound),
62 1 => T::from_row(&mut rows[0]),
63 _ => Err(ExecError::TooManyRows),
64 }
65 }
66 }
67
68 fn fetch_optional<T: FromRow>(
70 &self,
71 db: &(impl Executor + ?Sized),
72 ) -> impl Future<Output = Result<Option<T>, ExecError>> + Send {
73 let stmt = Statement::from_query(self);
74 async move {
75 let mut rows = run_fetch(db, stmt?).await?;
76 match rows.len() {
77 0 => Ok(None),
78 1 => T::from_row(&mut rows[0]).map(Some),
79 _ => Err(ExecError::TooManyRows),
80 }
81 }
82 }
83
84 fn fetch_scalar<T: FromValue>(
91 &self,
92 db: &(impl Executor + ?Sized),
93 ) -> impl Future<Output = Result<T, ExecError>> + Send {
94 let stmt = Statement::from_query(self);
95 async move {
96 let mut rows = run_fetch(db, stmt?).await?;
97 match rows.len() {
98 0 => Err(ExecError::RowNotFound),
99 1 => rows[0].take_at(0),
100 _ => Err(ExecError::TooManyRows),
101 }
102 }
103 }
104
105 fn fetch_scalars<T: FromValue>(
107 &self,
108 db: &(impl Executor + ?Sized),
109 ) -> impl Future<Output = Result<Vec<T>, ExecError>> + Send {
110 let stmt = Statement::from_query(self);
111 async move {
112 let rows = run_fetch(db, stmt?).await?;
113 rows.into_iter().map(|mut r| r.take_at(0)).collect()
114 }
115 }
116
117 fn execute(
119 &self,
120 db: &(impl Executor + ?Sized),
121 ) -> impl Future<Output = Result<ExecResult, ExecError>> + Send {
122 let stmt = Statement::from_query(self);
123 async move { run_execute(db, stmt?).await }
124 }
125}
126
127impl<Q: Query + ?Sized> Execute for Q {}
128
129pub(crate) async fn run_fetch<E: Executor + ?Sized>(
131 db: &E,
132 stmt: Statement,
133) -> Result<Vec<Row>, ExecError> {
134 #[cfg(feature = "tracing")]
135 {
136 use tracing::Instrument as _;
137 let span = query_span(db, &stmt);
138 let res = db.fetch(stmt).instrument(span.clone()).await;
141 match &res {
142 Ok(rows) => span.record("keelson.rows", rows.len() as u64),
143 Err(e) => span.record("error", tracing::field::display(e)),
144 };
145 res
146 }
147 #[cfg(not(feature = "tracing"))]
148 {
149 db.fetch(stmt).await
150 }
151}
152
153pub(crate) async fn run_execute<E: Executor + ?Sized>(
155 db: &E,
156 stmt: Statement,
157) -> Result<ExecResult, ExecError> {
158 #[cfg(feature = "tracing")]
159 {
160 use tracing::Instrument as _;
161 let span = query_span(db, &stmt);
162 let res = db.execute(stmt).instrument(span.clone()).await;
163 match &res {
164 Ok(done) => span.record("keelson.rows_affected", done.rows_affected),
165 Err(e) => span.record("error", tracing::field::display(e)),
166 };
167 res
168 }
169 #[cfg(not(feature = "tracing"))]
170 {
171 db.execute(stmt).await
172 }
173}
174
175#[cfg(feature = "tracing")]
186fn query_span<E: Executor + ?Sized>(db: &E, stmt: &Statement) -> tracing::Span {
187 tracing::info_span!(
188 "keelson.query",
189 db.system = db.family().as_str(),
190 db.query.text = %stmt.sql,
191 keelson.query_type = %stmt.query_type,
192 keelson.args.count = stmt.args.len() as u64,
193 keelson.rows = tracing::field::Empty,
194 keelson.rows_affected = tracing::field::Empty,
195 error = tracing::field::Empty,
196 )
197}