real_time_sqlx/
database.rs1use serde::Serialize;
5use sqlx::FromRow;
6
7use crate::{
8 queries::serialize::{
9 Condition, Constraint, ConstraintValue, FinalType, OrderBy, PaginateOptions, QueryData,
10 QueryTree,
11 },
12 utils::{placeholders, sanitize_identifier},
13};
14
15#[cfg(feature = "mysql")]
16pub mod mysql;
17
18#[cfg(feature = "postgres")]
19pub mod postgres;
20
21#[cfg(feature = "sqlite")]
22pub mod sqlite;
23
24fn prepare_sqlx_query(query: &QueryTree) -> (String, Vec<FinalType>) {
27 let mut string_query = "SELECT * FROM ".to_string();
28 let mut values = vec![];
29 string_query.push_str(&sanitize_identifier(&query.table));
30
31 if let Some(condition) = &query.condition {
32 string_query.push_str(" WHERE ");
33 let (placeholders, args) = condition.traverse();
34 string_query.push_str(&placeholders);
35 values.extend(args);
36 }
37
38 if let Some(paginate) = &query.paginate {
39 string_query.push_str(" ");
40 let pagination = paginate.traverse();
41 string_query.push_str(&pagination.0);
42 values.extend(pagination.1);
43 }
44
45 (string_query, values)
46}
47
48pub fn serialize_rows<T, R>(data: &QueryData<R>) -> serde_json::Value
50where
51 T: for<'r> FromRow<'r, R> + Serialize,
52 R: sqlx::Row,
53{
54 match data {
55 QueryData::Single(row) => match row {
56 Some(row) => serde_json::json!(QueryData::Single(Some(T::from_row(row).unwrap()))),
57 None => serde_json::json!(QueryData::Single(None::<T>)),
58 },
59 QueryData::Many(rows) => serde_json::json!(QueryData::Many(
60 rows.iter()
61 .map(|row| T::from_row(row).unwrap())
62 .collect::<Vec<T>>()
63 )),
64 }
65}
66
67trait Traversable {
73 fn traverse(&self) -> (String, Vec<FinalType>);
74}
75
76impl Traversable for FinalType {
77 fn traverse(&self) -> (String, Vec<FinalType>) {
79 ("?".to_string(), vec![self.clone()])
80 }
81}
82
83impl Traversable for ConstraintValue {
84 fn traverse(&self) -> (String, Vec<FinalType>) {
86 match self {
87 ConstraintValue::List(list) => (placeholders(list.len()), list.clone()),
88 ConstraintValue::Final(value) => value.traverse(),
89 }
90 }
91}
92
93impl Traversable for Constraint {
94 fn traverse(&self) -> (String, Vec<FinalType>) {
96 let (values_string_query, values) = self.value.traverse();
97
98 (
99 format!(
100 "\"{}\" {} {}",
101 self.column, self.operator, values_string_query
102 ),
103 values,
104 )
105 }
106}
107
108impl Traversable for Condition {
109 fn traverse(&self) -> (String, Vec<FinalType>) {
111 match self {
112 Condition::Single { constraint } => constraint.traverse(),
113 Condition::Or { conditions } => reduce_constraints_list(conditions, " OR "),
114 Condition::And { conditions } => reduce_constraints_list(conditions, " AND "),
115 }
116 }
117}
118
119impl Traversable for PaginateOptions {
120 fn traverse(&self) -> (String, Vec<FinalType>) {
122 let mut query_string = "".to_string();
123 let mut values: Vec<FinalType> = vec![];
124
125 if let Some(order) = &self.order_by {
126 query_string.push_str(
127 match order {
128 OrderBy::Asc(col) => format!("ORDER BY {} ASC ", sanitize_identifier(col)),
129 OrderBy::Desc(col) => format!("ORDER BY {} DESC ", sanitize_identifier(col)),
130 }
131 .as_str(),
132 );
133 } else {
134 query_string.push_str("ORDER BY id DESC ");
136 }
137
138 query_string.push_str("LIMIT ? ");
139 values.push(FinalType::Number(self.per_page.into()));
140
141 if let Some(offset) = self.offset {
142 query_string.push_str("OFFSET ? ");
143 values.push(FinalType::Number(offset.into()));
144 }
145
146 (query_string, values)
147 }
148}
149
150fn reduce_constraints_list(conditions: &[Condition], sep: &str) -> (String, Vec<FinalType>) {
153 let mut placeholder_strings: Vec<String> = vec![];
154 let mut total_values: Vec<FinalType> = vec![];
155
156 conditions.iter().for_each(|condition| {
157 let (string_query, values) = condition.traverse();
158 placeholder_strings.push(string_query);
159 total_values.extend(values);
160 });
161
162 (format!("({})", placeholder_strings.join(sep)), total_values)
163}