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