1use std::marker::PhantomData;
2
3use crate::{CompiledQuery, Dialect, Error, Query, Result, Value};
4
5#[derive(Clone, Debug)]
6enum SqlPart {
7 Trusted(&'static str),
8 Value(Value),
9}
10
11#[derive(Clone, Debug)]
16pub struct SqlQuery<O> {
17 parts: Vec<SqlPart>,
18 marker: PhantomData<fn() -> O>,
19}
20
21pub fn sql_query<O>(sql: &'static str) -> SqlQuery<O> {
22 SqlQuery {
23 parts: vec![SqlPart::Trusted(sql)],
24 marker: PhantomData,
25 }
26}
27
28impl<O> SqlQuery<O> {
29 pub fn append(mut self, sql: &'static str) -> Self {
30 self.parts.push(SqlPart::Trusted(sql));
31 self
32 }
33
34 pub fn bind(mut self, value: impl Into<Value>) -> Self {
35 self.parts.push(SqlPart::Value(value.into()));
36 self
37 }
38}
39
40impl<O> Query for SqlQuery<O> {
41 type Output = O;
42
43 fn compile(self, dialect: &impl Dialect) -> Result<CompiledQuery> {
44 let mut sql = String::new();
45 let mut parameters = Vec::new();
46 for part in self.parts {
47 match part {
48 SqlPart::Trusted(part) => sql.push_str(part),
49 SqlPart::Value(value) => {
50 parameters.push(value);
51 sql.push_str(&dialect.placeholder(parameters.len()));
52 }
53 }
54 }
55 if sql.trim().is_empty() {
56 return Err(Error::EmptyRawQuery);
57 }
58 Ok(CompiledQuery { sql, parameters })
59 }
60}