rsfbclient_diesel/fb/
query_builder.rs

1//! The Firebird query builder
2
3use super::backend::{Fb, FbReturningClause};
4use diesel::backend::sql_dialect::default_keyword_for_insert::DoesNotSupportDefaultKeyword;
5use diesel::insertable::ColumnInsertValue;
6use diesel::insertable::DefaultableColumnInsertValue;
7use diesel::insertable::InsertValues;
8use diesel::query_builder::*;
9use diesel::AppearsOnTable;
10use diesel::Column;
11use diesel::Expression;
12use diesel::QueryResult;
13
14pub struct FbQueryBuilder {
15    query: String,
16    pub has_cursor: bool,
17}
18
19impl FbQueryBuilder {
20    pub fn new() -> Self {
21        FbQueryBuilder {
22            query: String::new(),
23            has_cursor: true,
24        }
25    }
26}
27
28impl Default for FbQueryBuilder {
29    fn default() -> Self {
30        FbQueryBuilder::new()
31    }
32}
33
34impl QueryBuilder<Fb> for FbQueryBuilder {
35    fn push_sql(&mut self, sql: &str) {
36        self.query.push_str(sql);
37
38        if sql.trim().to_lowercase() == "returning" {
39            self.has_cursor = false;
40        }
41    }
42
43    fn push_identifier(&mut self, identifier: &str) -> QueryResult<()> {
44        self.query.push_str(identifier);
45
46        Ok(())
47    }
48
49    fn push_bind_param(&mut self) {
50        self.query.push('?');
51    }
52
53    fn finish(self) -> String {
54        self.query
55    }
56}
57
58impl QueryFragment<Fb> for LimitOffsetClause<NoLimitClause, NoOffsetClause> {
59    fn walk_ast(&self, _out: AstPass<Fb>) -> QueryResult<()> {
60        Ok(())
61    }
62}
63
64impl<L> QueryFragment<Fb> for LimitOffsetClause<LimitClause<L>, NoOffsetClause>
65where
66    L: QueryFragment<Fb>,
67{
68    fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, Fb>) -> QueryResult<()> {
69        out.push_sql(" FIRST ");
70        self.limit_clause.0.walk_ast(out.reborrow())?;
71        out.push_sql(" ");
72        Ok(())
73    }
74}
75
76impl<L> QueryFragment<Fb> for LimitOffsetClause<LimitClause<L>, OffsetClause<L>>
77where
78    L: QueryFragment<Fb>,
79{
80    fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, Fb>) -> QueryResult<()> {
81        out.push_sql(" FIRST ");
82        self.limit_clause.0.walk_ast(out.reborrow())?;
83        out.push_sql(" SKIP ");
84        self.offset_clause.0.walk_ast(out.reborrow())?;
85        out.push_sql(" ");
86        Ok(())
87    }
88}
89
90impl<F, S, D, W, O, LOf, G, H, LC> QueryFragment<Fb, crate::fb::backend::FbSelectStatementSyntax>
91    for SelectStatement<F, S, D, W, O, LOf, G, H, LC>
92where
93    S: QueryFragment<Fb>,
94    F: QueryFragment<Fb>,
95    D: QueryFragment<Fb>,
96    W: QueryFragment<Fb>,
97    O: QueryFragment<Fb>,
98    LOf: QueryFragment<Fb>,
99    G: QueryFragment<Fb>,
100    H: QueryFragment<Fb>,
101    LC: QueryFragment<Fb>,
102{
103    fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, Fb>) -> QueryResult<()> {
104        out.push_sql("SELECT ");
105        self.limit_offset.walk_ast(out.reborrow())?;
106        self.distinct.walk_ast(out.reborrow())?;
107        self.select.walk_ast(out.reborrow())?;
108        self.from.walk_ast(out.reborrow())?;
109        self.where_clause.walk_ast(out.reborrow())?;
110        self.group_by.walk_ast(out.reborrow())?;
111        self.having.walk_ast(out.reborrow())?;
112        self.order.walk_ast(out.reborrow())?;
113        self.locking.walk_ast(out.reborrow())?;
114        Ok(())
115    }
116}
117
118impl<'a, ST, QS, GB> QueryFragment<Fb, crate::fb::backend::FbSelectStatementSyntax>
119    for BoxedSelectStatement<'a, ST, QS, Fb, GB>
120where
121    QS: QueryFragment<Fb>,
122    BoxedLimitOffsetClause<'a, Fb>: QueryFragment<Fb>,
123{
124    fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, Fb>) -> QueryResult<()> {
125        out.push_sql("SELECT ");
126        self.limit_offset.walk_ast(out.reborrow())?;
127        self.distinct.walk_ast(out.reborrow())?;
128        self.select.walk_ast(out.reborrow())?;
129        self.from.walk_ast(out.reborrow())?;
130        self.where_clause.walk_ast(out.reborrow())?;
131        self.group_by.walk_ast(out.reborrow())?;
132        self.having.walk_ast(out.reborrow())?;
133        self.order.walk_ast(out.reborrow())?;
134        Ok(())
135    }
136}
137
138impl<Col, Expr> InsertValues<Col::Table, Fb>
139    for DefaultableColumnInsertValue<ColumnInsertValue<Col, Expr>>
140where
141    Col: Column,
142    Expr: Expression<SqlType = Col::SqlType> + AppearsOnTable<NoFromClause>,
143    Self: QueryFragment<Fb>,
144{
145    fn column_names(&self, mut out: AstPass<'_, '_, Fb>) -> QueryResult<()> {
146        if let Self::Expression(..) = *self {
147            out.push_identifier(Col::NAME)?;
148        }
149        Ok(())
150    }
151}
152
153impl<Col, Expr> QueryFragment<Fb, DoesNotSupportDefaultKeyword>
154    for DefaultableColumnInsertValue<ColumnInsertValue<Col, Expr>>
155where
156    Expr: QueryFragment<Fb>,
157{
158    fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, Fb>) -> QueryResult<()> {
159        if let Self::Expression(ref inner) = *self {
160            inner.walk_ast(out.reborrow())?;
161        }
162        Ok(())
163    }
164}
165
166impl<Expr> QueryFragment<Fb, FbReturningClause> for ReturningClause<Expr>
167where
168    Expr: QueryFragment<Fb>,
169{
170    fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, Fb>) -> QueryResult<()> {
171        out.push_sql(" RETURNING ");
172        self.0.walk_ast(out.reborrow())?;
173        Ok(())
174    }
175}