diesel_dynamic_schema/
dynamic_select.rs

1use diesel::backend::Backend;
2use diesel::expression::{is_aggregate, NonAggregate, ValidGrouping};
3use diesel::query_builder::{AstPass, QueryFragment, QueryId};
4use diesel::sql_types::Untyped;
5use diesel::{AppearsOnTable, Expression, QueryResult, SelectableExpression};
6use std::marker::PhantomData;
7
8/// Represents a dynamically sized select clause
9#[allow(missing_debug_implementations)]
10pub struct DynamicSelectClause<'a, DB, QS> {
11    selects: Vec<Box<dyn QueryFragment<DB> + Send + 'a>>,
12    p: PhantomData<QS>,
13}
14
15impl<DB, QS> QueryId for DynamicSelectClause<'_, DB, QS> {
16    const HAS_STATIC_QUERY_ID: bool = false;
17    type QueryId = ();
18}
19
20impl<DB, QS> Default for DynamicSelectClause<'_, DB, QS> {
21    fn default() -> Self {
22        Self::new()
23    }
24}
25
26impl<'a, DB, QS> DynamicSelectClause<'a, DB, QS> {
27    /// Constructs a new dynamically sized select clause without any fields
28    pub fn new() -> Self {
29        Self {
30            selects: Vec::new(),
31            p: PhantomData,
32        }
33    }
34
35    /// Adds the field to the dynamically sized select clause
36    pub fn add_field<F>(&mut self, field: F)
37    where
38        F: QueryFragment<DB> + SelectableExpression<QS> + NonAggregate + Send + 'a,
39        DB: Backend,
40    {
41        self.selects.push(Box::new(field))
42    }
43}
44
45impl<DB, QS> AppearsOnTable<QS> for DynamicSelectClause<'_, DB, QS> where Self: Expression {}
46
47impl<DB, QS> SelectableExpression<QS> for DynamicSelectClause<'_, DB, QS> where
48    Self: AppearsOnTable<QS>
49{
50}
51
52impl<QS, DB> Expression for DynamicSelectClause<'_, DB, QS> {
53    type SqlType = Untyped;
54}
55
56impl<DB, QS> QueryFragment<DB> for DynamicSelectClause<'_, DB, QS>
57where
58    DB: Backend,
59{
60    fn walk_ast<'b>(&'b self, mut pass: AstPass<'_, 'b, DB>) -> QueryResult<()> {
61        let mut first = true;
62        for s in &self.selects {
63            if first {
64                first = false;
65            } else {
66                pass.push_sql(", ");
67            }
68            s.walk_ast(pass.reborrow())?;
69        }
70        Ok(())
71    }
72}
73
74impl<DB, QS> ValidGrouping<()> for DynamicSelectClause<'_, DB, QS> {
75    type IsAggregate = is_aggregate::No;
76}