use std::marker::PhantomData;
use super::{Select, Selection};
use crate::dialect::Dialect;
use crate::expr::Value;
pub trait PreparedParams {
fn into_named_values(self) -> Vec<(&'static str, Value)>;
}
pub struct Prepared<D, Params, Output> {
sql: String,
template: Vec<Value>,
_marker: PhantomData<fn() -> (D, Params, Output)>,
}
impl<D, Scope, Sel> Select<D, Scope, Sel> {
pub fn prepare<Params, Idx>(&self, _dialect: D) -> Prepared<D, Params, Sel::Output>
where
D: Dialect,
Sel: Selection<Scope, Idx>,
{
let (sql, template) = self.render_as::<Idx>();
Prepared {
sql,
template,
_marker: PhantomData,
}
}
pub fn prepare_count<Params, Idx>(&self, _dialect: D) -> Prepared<D, Params, Total>
where
D: Dialect,
Sel: Selection<Scope, Idx>,
{
let (sql, template) = self.count_sql::<Idx>(D::default());
Prepared {
sql,
template,
_marker: PhantomData,
}
}
}
pub struct Total;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct UnresolvedPlaceholder(pub &'static str);
impl std::fmt::Display for UnresolvedPlaceholder {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "no value provided for placeholder `{}`", self.0)
}
}
impl std::error::Error for UnresolvedPlaceholder {}
impl<D, Params: PreparedParams, Output> Prepared<D, Params, Output> {
pub fn resolve(&self, params: Params) -> Result<(String, Vec<Value>), UnresolvedPlaceholder> {
let named = params.into_named_values();
let mut resolved = Vec::with_capacity(self.template.len());
for v in &self.template {
match v {
Value::Placeholder(name) => {
let found = named
.iter()
.find(|(n, _)| n == name)
.map(|(_, v)| v.clone())
.ok_or(UnresolvedPlaceholder(name))?;
resolved.push(found);
}
other => resolved.push(other.clone()),
}
}
Ok((self.sql.clone(), resolved))
}
}