diff --git a/sqlx-core/src/blocking/executor.rs b/sqlx-core/src/blocking/executor.rs index 429d4930..651254a1 100644 --- a/sqlx-core/src/blocking/executor.rs +++ b/sqlx-core/src/blocking/executor.rs @@ -12,4 +12,20 @@ where where 'e: 'x, 'q: 'x; + + fn fetch_all<'x, 'e, 'q>( + &'e mut self, + sql: &'q str, + ) -> crate::Result>::Row>> + where + 'e: 'x, + 'q: 'x; + + fn fetch_optional<'x, 'e, 'q>( + &'e mut self, + sql: &'q str, + ) -> crate::Result>::Row>> + where + 'e: 'x, + 'q: 'x; } diff --git a/sqlx-core/src/error.rs b/sqlx-core/src/error.rs index c19c9d56..249161dc 100644 --- a/sqlx-core/src/error.rs +++ b/sqlx-core/src/error.rs @@ -12,11 +12,20 @@ pub type Result = std::result::Result; #[derive(Debug)] #[non_exhaustive] pub enum Error { - Configuration { message: Cow<'static, str>, source: Option> }, + Configuration { + message: Cow<'static, str>, + source: Option>, + }, Connect(Box), Network(std::io::Error), + + /// Returned by `fetch_one` when no row was returned from the query. + /// + /// Use `fetch_optional` to return `None` instead of signaling an error. + /// + RowNotFound, } impl Error { @@ -56,6 +65,10 @@ impl Display for Error { Self::Configuration { message, source: Some(source) } => { write!(f, "{}: {}", message, source) } + + Self::RowNotFound => { + f.write_str("no row returned by a query required to return at least one row") + } } } } diff --git a/sqlx-core/src/executor.rs b/sqlx-core/src/executor.rs index 6151306f..deb0527b 100644 --- a/sqlx-core/src/executor.rs +++ b/sqlx-core/src/executor.rs @@ -1,7 +1,7 @@ #[cfg(feature = "async")] -use futures_core::future::BoxFuture; +use futures_util::future::{self, BoxFuture, FutureExt, TryFutureExt}; -use crate::{Database, Result, Runtime}; +use crate::{Database, Error, Result, Runtime}; /// Describes a type that can execute SQL queries on a self-provided database connection. /// @@ -55,5 +55,13 @@ pub trait Executor { where Rt: crate::Async, 'e: 'x, - 'q: 'x; + 'q: 'x, + { + self.fetch_optional(sql) + .and_then(|maybe_row| match maybe_row { + Some(row) => future::ok(row), + None => future::err(Error::RowNotFound), + }) + .boxed() + } } diff --git a/sqlx-core/src/row.rs b/sqlx-core/src/row.rs index 7bbeefa4..5631bedb 100644 --- a/sqlx-core/src/row.rs +++ b/sqlx-core/src/row.rs @@ -1,6 +1,6 @@ use crate::{Column, Database, Runtime}; -pub trait Row { +pub trait Row: 'static + Send + Sync { type Column: Column; /// Returns `true` if the row contains only `NULL` values.