use std::{
collections::HashSet,
fmt,
ops::{Deref, DerefMut},
};
use async_trait::async_trait;
use either::Either;
use futures_core::stream::BoxStream;
use crate::{
Arguments, QueryResult, Result, Row,
encode::Encode,
executor::Execute,
pool::PoolConnection,
sqlite::{Value, statement::Statement},
};
#[must_use = "query must be executed to affect database"]
#[derive(Clone)]
pub struct Query {
pub(crate) statement: Either<String, Statement>,
pub(crate) arguments: Option<Arguments>,
pub(crate) tainted: bool,
}
impl fmt::Debug for Query {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write_query_debug(f, self.sql(), &self.arguments, self.tainted)
}
}
fn write_query_debug(
f: &mut fmt::Formatter<'_>,
sql: &str,
arguments: &Option<Arguments>,
tainted: bool,
) -> fmt::Result {
let multi_line = sql.contains('\n');
if multi_line && f.alternate() {
writeln!(f, "Query {{")?;
writeln!(f, " statement:")?;
for line in sql.lines() {
writeln!(f, " {line}")?;
}
write_optional_fields(f, arguments, tainted, " ", ",\n")?;
write!(f, "}}")
} else if multi_line {
write!(f, "Query {{ statement: ")?;
for (i, line) in sql.lines().enumerate() {
if i == 0 {
writeln!(f, "{line}")?
} else {
writeln!(f, " {line}")?
}
}
write_optional_fields(f, arguments, tainted, ", ", " ")?;
write!(f, "}}")
} else {
let mut debug_struct = f.debug_struct("Query");
debug_struct.field("statement", &sql);
if let Some(args) = arguments
&& !args.values.is_empty()
{
debug_struct.field("arguments", &format_args!("{}", FormatArguments(args)));
}
if tainted {
debug_struct.field("tainted", &tainted);
}
debug_struct.finish()
}
}
fn write_optional_fields(
f: &mut fmt::Formatter<'_>,
arguments: &Option<Arguments>,
tainted: bool,
prefix: &str,
suffix: &str,
) -> fmt::Result {
if let Some(args) = arguments
&& !args.values.is_empty()
{
write!(
f,
"{}arguments: {}{}",
prefix,
FormatArguments(args),
suffix
)?;
}
if tainted {
write!(f, "{prefix}tainted: {tainted}{suffix}")?;
}
Ok(())
}
struct FormatArguments<'a>(&'a Arguments);
impl<'a> fmt::Display for FormatArguments<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let named_indices: HashSet<_> = self.0.named.values().copied().collect();
let mut first = true;
write!(f, "[")?;
for (i, value) in self.0.values.iter().enumerate() {
if !named_indices.contains(&(i + 1)) {
if !first {
write!(f, ", ")?
}
write!(f, "{}", FormatValue(value))?;
first = false;
}
}
let mut named: Vec<_> = self.0.named.iter().collect();
named.sort_by_key(|&(_, &idx)| idx);
for (name, &idx) in named {
if !first {
write!(f, ", ")?
}
if let Some(value) = self.0.values.get(idx - 1) {
write!(f, "{}={}", name, FormatValue(value))?;
first = false;
}
}
write!(f, "]")
}
}
struct FormatValue<'a>(&'a Value);
impl<'a> fmt::Display for FormatValue<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.0 {
Value::Null { .. } => write!(f, "NULL"),
Value::Integer { value, .. } => write!(f, "{value}"),
Value::Double { value, .. } => write!(f, "{value}"),
Value::Text { .. } => match self.0.text() {
Ok(text) => write!(f, "{text:?}"),
Err(err) => write!(f, "<invalid utf-8: {err}>"),
},
Value::Blob { value, .. } => {
write!(f, "0x")?;
let display_bytes =
value
.iter()
.take(if value.len() <= 16 { value.len() } else { 8 });
for byte in display_bytes {
write!(f, "{byte:02x}")?;
}
if value.len() > 16 {
write!(f, "...({} bytes)", value.len())?;
}
Ok(())
}
}
}
}
#[must_use = "query must be executed to affect database"]
pub struct Map<F> {
inner: Query,
mapper: F,
}
#[async_trait]
pub trait QueryExecutor {
async fn execute_query(self, query: Query) -> Result<QueryResult>;
fn fetch_query<'c>(self, query: Query) -> BoxStream<'c, Result<Row>>
where
Self: 'c;
async fn fetch_all_query(self, query: Query) -> Result<Vec<Row>>;
async fn fetch_one_query(self, query: Query) -> Result<Row>;
async fn fetch_optional_query(self, query: Query) -> Result<Option<Row>>;
}
#[async_trait]
impl QueryExecutor for &crate::Pool {
async fn execute_query(self, query: Query) -> Result<QueryResult> {
let conn = self.acquire().await?;
conn.execute(query).await
}
fn fetch_query<'c>(self, query: Query) -> BoxStream<'c, Result<Row>>
where
Self: 'c,
{
use futures_util::TryStreamExt;
Box::pin(async_stream::try_stream! {
let conn = self.acquire().await?;
let mut stream = conn.fetch(query);
while let Some(row) = stream.try_next().await? {
yield row;
}
})
}
async fn fetch_all_query(self, query: Query) -> Result<Vec<Row>> {
let conn = self.acquire().await?;
conn.fetch_all(query).await
}
async fn fetch_one_query(self, query: Query) -> Result<Row> {
let conn = self.acquire().await?;
conn.fetch_one(query).await
}
async fn fetch_optional_query(self, query: Query) -> Result<Option<Row>> {
let conn = self.acquire().await?;
conn.fetch_optional(query).await
}
}
#[async_trait]
impl QueryExecutor for &crate::Connection {
async fn execute_query(self, query: Query) -> Result<QueryResult> {
self.execute(query).await
}
fn fetch_query<'c>(self, query: Query) -> BoxStream<'c, Result<Row>>
where
Self: 'c,
{
self.fetch(query)
}
async fn fetch_all_query(self, query: Query) -> Result<Vec<Row>> {
self.fetch_all(query).await
}
async fn fetch_one_query(self, query: Query) -> Result<Row> {
self.fetch_one(query).await
}
async fn fetch_optional_query(self, query: Query) -> Result<Option<Row>> {
self.fetch_optional(query).await
}
}
#[async_trait]
impl QueryExecutor for &PoolConnection {
async fn execute_query(self, query: Query) -> Result<QueryResult> {
self.execute(query).await
}
fn fetch_query<'c>(self, query: Query) -> BoxStream<'c, Result<Row>>
where
Self: 'c,
{
self.fetch(query)
}
async fn fetch_all_query(self, query: Query) -> Result<Vec<Row>> {
self.fetch_all(query).await
}
async fn fetch_one_query(self, query: Query) -> Result<Row> {
self.fetch_one(query).await
}
async fn fetch_optional_query(self, query: Query) -> Result<Option<Row>> {
self.fetch_optional(query).await
}
}
#[async_trait]
impl<C> QueryExecutor for &crate::Transaction<C>
where
C: DerefMut<Target = crate::Connection> + Send + Sync,
{
async fn execute_query(self, query: Query) -> Result<QueryResult> {
let conn: &crate::Connection = self.deref();
conn.execute(query).await
}
fn fetch_query<'c>(self, query: Query) -> BoxStream<'c, Result<Row>>
where
Self: 'c,
{
use futures_util::TryStreamExt;
Box::pin(async_stream::try_stream! {
let conn: &crate::Connection = self.deref();
let mut stream = conn.fetch(query);
while let Some(row) = stream.try_next().await? {
yield row;
}
})
}
async fn fetch_all_query(self, query: Query) -> Result<Vec<Row>> {
let conn: &crate::Connection = self.deref();
conn.fetch_all(query).await
}
async fn fetch_one_query(self, query: Query) -> Result<Row> {
let conn: &crate::Connection = self.deref();
conn.fetch_one(query).await
}
async fn fetch_optional_query(self, query: Query) -> Result<Option<Row>> {
let conn: &crate::Connection = self.deref();
conn.fetch_optional(query).await
}
}
#[async_trait]
impl<C> QueryExecutor for &mut crate::Transaction<C>
where
C: DerefMut<Target = crate::Connection> + Send + Sync,
{
async fn execute_query(self, query: Query) -> Result<QueryResult> {
let conn: &crate::Connection = self.deref();
conn.execute(query).await
}
fn fetch_query<'c>(self, query: Query) -> BoxStream<'c, Result<Row>>
where
Self: 'c,
{
use futures_util::TryStreamExt;
Box::pin(async_stream::try_stream! {
let conn: &crate::Connection = self.deref();
let mut stream = conn.fetch(query);
while let Some(row) = stream.try_next().await? {
yield row;
}
})
}
async fn fetch_all_query(self, query: Query) -> Result<Vec<Row>> {
let conn: &crate::Connection = self.deref();
conn.fetch_all(query).await
}
async fn fetch_one_query(self, query: Query) -> Result<Row> {
let conn: &crate::Connection = self.deref();
conn.fetch_one(query).await
}
async fn fetch_optional_query(self, query: Query) -> Result<Option<Row>> {
let conn: &crate::Connection = self.deref();
conn.fetch_optional(query).await
}
}
impl Execute for Query {
fn sql(&self) -> &str {
match &self.statement {
Either::Right(statement) => statement.sql(),
Either::Left(sql) => sql,
}
}
fn arguments(&mut self) -> Option<Arguments> {
self.arguments.take()
}
}
impl<F> Map<F> {
pub fn try_bind<'q, T: 'q + Send + Encode>(mut self, value: T) -> Result<Self> {
self.inner = self.inner.try_bind(value)?;
Ok(self)
}
pub fn bind<'q, T: 'q + Send + Encode>(self, value: T) -> Self {
self.try_bind(value)
.expect("failed to bind query parameter")
}
pub fn try_bind_named<'q, T: 'q + Send + Encode>(
mut self,
name: &str,
value: T,
) -> Result<Self> {
self.inner = self.inner.try_bind_named(name, value)?;
Ok(self)
}
pub fn bind_named<'q, T: 'q + Send + Encode>(self, name: &str, value: T) -> Self {
self.try_bind_named(name, value)
.expect("failed to bind named query parameter")
}
}
impl Query {
pub fn is_tainted(&self) -> bool {
self.tainted
}
pub fn into_builder(self) -> crate::QueryBuilder {
crate::QueryBuilder::from_parts(
self.sql().to_string(),
self.arguments.unwrap_or_default(),
self.tainted,
)
}
pub fn join(self, other: Self) -> Self {
self.try_join(other)
.expect("failed to join query fragments")
}
pub fn try_join(self, other: Self) -> Result<Self> {
let mut builder = self.into_builder();
builder.try_push_query(other)?;
Ok(builder.build())
}
pub fn try_bind<'q, T: 'q + Send + Encode>(mut self, value: T) -> Result<Self> {
if let Some(arguments) = &mut self.arguments {
arguments.add(&value)?;
}
drop(value);
Ok(self)
}
pub fn bind<'q, T: 'q + Send + Encode>(self, value: T) -> Self {
self.try_bind(value)
.expect("failed to bind query parameter")
}
pub fn try_bind_named<'q, T: 'q + Send + Encode>(
mut self,
name: &str,
value: T,
) -> Result<Self> {
if let Some(arguments) = &mut self.arguments {
arguments.add_named(name, &value)?;
}
drop(value);
Ok(self)
}
pub fn bind_named<'q, T: 'q + Send + Encode>(self, name: &str, value: T) -> Self {
self.try_bind_named(name, value)
.expect("failed to bind named query parameter")
}
pub fn map<F, O>(self, mut f: F) -> Map<impl FnMut(Row) -> Result<O> + Send>
where
F: FnMut(Row) -> O + Send,
O: Unpin,
{
self.try_map(move |row| Ok(f(row)))
}
pub fn try_map<F, O>(self, f: F) -> Map<F>
where
F: FnMut(Row) -> Result<O> + Send,
O: Unpin,
{
Map {
inner: self,
mapper: f,
}
}
pub async fn execute<E>(self, executor: E) -> Result<QueryResult>
where
E: QueryExecutor,
{
executor.execute_query(self).await
}
pub fn fetch<'c, E>(self, executor: E) -> BoxStream<'c, Result<Row>>
where
E: QueryExecutor + 'c,
{
executor.fetch_query(self)
}
pub async fn fetch_all<E>(self, executor: E) -> Result<Vec<Row>>
where
E: QueryExecutor,
{
executor.fetch_all_query(self).await
}
pub async fn fetch_one<E>(self, executor: E) -> Result<Row>
where
E: QueryExecutor,
{
executor.fetch_one_query(self).await
}
pub async fn fetch_optional<E>(self, executor: E) -> Result<Option<Row>>
where
E: QueryExecutor,
{
executor.fetch_optional_query(self).await
}
}
impl<F: Send> Execute for Map<F> {
fn sql(&self) -> &str {
self.inner.sql()
}
fn arguments(&mut self) -> Option<Arguments> {
self.inner.arguments()
}
}
impl<F, O> Map<F>
where
F: FnMut(Row) -> Result<O> + Send,
O: Send + Unpin,
{
pub fn map<G, P>(self, mut g: G) -> Map<impl FnMut(Row) -> Result<P> + Send>
where
G: FnMut(O) -> P + Send,
P: Unpin,
{
self.try_map(move |data| Ok(g(data)))
}
pub fn try_map<G, P>(self, mut g: G) -> Map<impl FnMut(Row) -> Result<P> + Send>
where
G: FnMut(O) -> Result<P> + Send,
P: Unpin,
{
let mut f = self.mapper;
Map {
inner: self.inner,
mapper: move |row| f(row).and_then(&mut g),
}
}
pub async fn fetch_all<E>(mut self, executor: E) -> Result<Vec<O>>
where
E: QueryExecutor,
{
let rows = self.inner.fetch_all(executor).await?;
let mut results = Vec::with_capacity(rows.len());
for row in rows {
results.push((self.mapper)(row)?);
}
Ok(results)
}
pub async fn fetch_one<E>(self, executor: E) -> Result<O>
where
E: QueryExecutor,
{
match self.fetch_optional(executor).await? {
Some(row) => Ok(row),
None => Err(crate::Error::RowNotFound),
}
}
pub async fn fetch_optional<E>(mut self, executor: E) -> Result<Option<O>>
where
E: QueryExecutor,
{
let row = self.inner.fetch_optional(executor).await?;
if let Some(row) = row {
(self.mapper)(row).map(Some)
} else {
Ok(None)
}
}
}
pub(crate) fn query_statement(statement: &Statement) -> Query {
Query {
arguments: Some(Default::default()),
statement: Either::Right(statement.clone()),
tainted: false,
}
}
pub(crate) fn query_statement_with(statement: &Statement, arguments: Arguments) -> Query {
Query {
arguments: Some(arguments),
statement: Either::Right(statement.clone()),
tainted: false,
}
}
pub fn query(sql: &str) -> Query {
Query {
arguments: Some(Default::default()),
statement: Either::Left(sql.to_string()),
tainted: false,
}
}
pub fn query_with(sql: &str, arguments: Arguments) -> Query {
Query {
arguments: Some(arguments),
statement: Either::Left(sql.to_string()),
tainted: false,
}
}
use crate::from_row::FromRow;
pub fn query_as<'q, O>(sql: &'q str) -> Map<impl FnMut(Row) -> Result<O> + Send>
where
O: Send + Unpin + for<'r> FromRow<'r>,
{
query(sql).try_map(|row| O::from_row("", &row))
}
pub fn query_as_with<'q, O>(
sql: &'q str,
arguments: Arguments,
) -> Map<impl FnMut(Row) -> Result<O> + Send>
where
O: Send + Unpin + for<'r> FromRow<'r>,
{
query_with(sql, arguments).try_map(|row| O::from_row("", &row))
}
pub(crate) fn query_statement_as<'q, O>(
statement: &'q Statement,
) -> Map<impl FnMut(Row) -> Result<O> + Send>
where
O: Send + Unpin + for<'r> FromRow<'r>,
{
query_statement(statement).try_map(|row| O::from_row("", &row))
}
pub(crate) fn query_statement_as_with<'q, O>(
statement: &'q Statement,
arguments: Arguments,
) -> Map<impl FnMut(Row) -> Result<O> + Send>
where
O: Send + Unpin + for<'r> FromRow<'r>,
{
query_statement_with(statement, arguments).try_map(|row| O::from_row("", &row))
}
pub fn query_scalar<'q, O>(sql: &'q str) -> Map<impl FnMut(Row) -> Result<O> + Send>
where
(O,): for<'r> FromRow<'r>,
O: Send + Unpin,
{
query_as(sql).map(|(o,)| o)
}
pub fn query_scalar_with<'q, O>(
sql: &'q str,
arguments: Arguments,
) -> Map<impl FnMut(Row) -> Result<O> + Send>
where
(O,): for<'r> FromRow<'r>,
O: Send + Unpin,
{
query_as_with(sql, arguments).map(|(o,)| o)
}
pub(crate) fn query_statement_scalar<'q, O>(
statement: &'q Statement,
) -> Map<impl FnMut(Row) -> Result<O> + Send>
where
(O,): for<'r> FromRow<'r>,
O: Send + Unpin,
{
query_statement_as(statement).map(|(o,)| o)
}
pub(crate) fn query_statement_scalar_with<'q, O>(
statement: &'q Statement,
arguments: Arguments,
) -> Map<impl FnMut(Row) -> Result<O> + Send>
where
(O,): for<'r> FromRow<'r>,
O: Send + Unpin,
{
query_statement_as_with(statement, arguments).map(|(o,)| o)
}
pub fn quote_identifier(ident: &str) -> String {
let escaped = ident.replace('"', "\"\"");
format!("\"{escaped}\"")
}