iota_graphql_rpc/
raw_query.rs1use diesel::{
6 query_builder::{BoxedSqlQuery, SqlQuery},
7 sql_query,
8};
9
10use crate::data::DieselBackend;
11
12pub(crate) type RawSqlQuery = BoxedSqlQuery<'static, DieselBackend, SqlQuery>;
13
14#[derive(Clone)]
28pub(crate) struct RawQuery {
29 select: String,
31 where_: Option<String>,
33 order_by: Vec<String>,
35 group_by: Vec<String>,
37 limit: Option<i64>,
39 binds: Vec<String>,
41}
42
43impl RawQuery {
44 pub(crate) fn new(select: impl Into<String>, binds: Vec<String>) -> Self {
46 Self {
47 select: select.into(),
48 where_: None,
49 order_by: Vec::new(),
50 group_by: Vec::new(),
51 limit: None,
52 binds,
53 }
54 }
55
56 pub(crate) fn filter<T: std::fmt::Display>(mut self, condition: T) -> Self {
59 self.where_ = match self.where_ {
60 Some(where_) => Some(format!("({}) AND {}", where_, condition)),
61 None => Some(condition.to_string()),
62 };
63
64 self
65 }
66
67 pub(crate) fn or_filter<T: std::fmt::Display>(mut self, condition: T) -> Self {
70 self.where_ = match self.where_ {
71 Some(where_) => Some(format!("({}) OR {}", where_, condition)),
72 None => Some(condition.to_string()),
73 };
74
75 self
76 }
77
78 pub(crate) fn order_by<T: ToString>(mut self, order: T) -> Self {
80 self.order_by.push(order.to_string());
81 self
82 }
83
84 pub(crate) fn group_by<T: ToString>(mut self, group: T) -> Self {
86 self.group_by.push(group.to_string());
87 self
88 }
89
90 pub(crate) fn limit(mut self, limit: i64) -> Self {
92 self.limit = Some(limit);
93 self
94 }
95
96 pub(crate) fn bind_value(&mut self, condition: String) {
98 self.binds.push(condition);
99 }
100
101 pub(crate) fn finish(self) -> (String, Vec<String>) {
105 let mut select = self.select;
106
107 if let Some(where_) = self.where_ {
108 select.push_str(" WHERE ");
109 select.push_str(&where_);
110 }
111
112 let mut prefix = " GROUP BY ";
113 for group in self.group_by.iter() {
114 select.push_str(prefix);
115 select.push_str(group);
116 prefix = ", ";
117 }
118
119 let mut prefix = " ORDER BY ";
120 for order in self.order_by.iter() {
121 select.push_str(prefix);
122 select.push_str(order);
123 prefix = ", ";
124 }
125
126 if let Some(limit) = self.limit {
127 select.push_str(" LIMIT ");
128 select.push_str(&limit.to_string());
129 }
130
131 (select, self.binds)
132 }
133
134 pub(crate) fn into_boxed(self) -> RawSqlQuery {
139 let (raw_sql_string, binds) = self.finish();
140
141 let mut result = String::with_capacity(raw_sql_string.len());
142
143 let mut sql_components = raw_sql_string.split("{}").enumerate();
144
145 if let Some((_, first)) = sql_components.next() {
146 result.push_str(first);
147 }
148
149 for (i, sql) in sql_components {
150 result.push_str(&format!("${}", i));
151 result.push_str(sql);
152 }
153
154 let mut diesel_query = sql_query(result).into_boxed();
155
156 for bind in binds {
157 diesel_query = diesel_query.bind::<diesel::sql_types::Text, _>(bind);
158 }
159
160 diesel_query
161 }
162}
163
164#[macro_export]
167macro_rules! filter {
168 ($query:expr, $condition:expr $(,$binds:expr)*) => {{
169 let mut query = $query;
170 query = query.filter($condition);
171 $(query.bind_value($binds.to_string());)*
172 query
173 }};
174}
175
176#[macro_export]
179macro_rules! or_filter {
180 ($query:expr, $condition:expr $(,$binds:expr)*) => {{
181 let mut query = $query;
182 query = query.or_filter($condition);
183 $(query.bind_value($binds.to_string());)*
184 query
185 }};
186}
187
188#[macro_export]
191macro_rules! inner_join {
192 ($lhs:expr, $alias:expr => $rhs_query:expr, using: [$using:expr $(, $more_using:expr)*]) => {{
193 use $crate::raw_query::RawQuery;
194
195 let (lhs_sql, mut binds) = $lhs.finish();
196 let (rhs_sql, rhs_binds) = $rhs_query.finish();
197
198 binds.extend(rhs_binds);
199
200 let sql = format!(
201 "{lhs_sql} INNER JOIN ({rhs_sql}) AS {} USING ({})",
202 $alias,
203 stringify!($using $(, $more_using)*),
204 );
205
206 RawQuery::new(sql, binds)
207 }};
208}
209
210#[macro_export]
217macro_rules! query {
218 ($select:expr) => {
221 $crate::raw_query::RawQuery::new($select, vec![])
222 };
223
224 ($select:expr $(,$subquery:expr)+) => {{
228 use $crate::raw_query::RawQuery;
229 let mut binds = vec![];
230
231 let select = format!(
232 $select,
233 $({
234 let (sub_sql, sub_binds) = $subquery.finish();
235 binds.extend(sub_binds);
236 sub_sql
237 }),*
238 );
239
240 RawQuery::new(select, binds)
241 }};
242}