datastore_mysql/
lib.rs

1//! # datastore-mysql
2//!
3//! This crate provides [`MySqlStore`] which is a [`Store`] implementation using the MySQL
4//! database.
5//!
6//! [`MySqlStore`] supports these types:
7//! - `bool`
8//! - `i8`, `i16`, `i32`, `i64`
9//! - `u8`, `u16`, `u32`, `u64`
10//! - `f32`, `f64`
11//! - `&str`, `String`
12//! - `&[u8]`, `Vec<u8>`
13//!
14//! ## Examples
15//!
16//! ```ignore
17//! use datastore::{Store, StoreExt, StoreData};
18//! use datastore_mysql::MySqlStore;
19//!
20//! #[derive(Debug, StoreData)]
21//! pub struct Person {
22//!     id: i64,
23//!     name: String,
24//! }
25//!
26//! #[tokio::main]
27//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
28//!     let store = MySqlStore::connect("mysql://user:password@host/database").await?;
29//!
30//!     let person = Person {
31//!         id: 1,
32//!         name: String::from("Robb"),
33//!     };
34//!
35//!     store.insert(store.descriptor::<Person>(), person).await?;
36//!
37//!     let persons: Vec<Person> = store.get_all(store.descriptor::<Person>()).await?;
38//!     println!("{:?}", persons);
39//!
40//!     Ok(())
41//! }
42//! ```
43//!
44//! [`Store`]: datastore::Store
45
46use std::fmt::{self, Display, Formatter};
47
48mod mysql;
49mod types;
50
51pub use mysql::MySqlStore;
52
53#[derive(Debug)]
54pub struct Error(ErrorKind);
55
56impl Display for Error {
57    #[inline]
58    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
59        match &self.0 {
60            ErrorKind::Sqlx(err) => write!(f, "{}", err),
61            ErrorKind::Custom(s) => write!(f, "{}", s),
62        }
63    }
64}
65
66impl std::error::Error for Error {}
67
68impl datastore::Error for Error {
69    fn custom<T>(msg: T) -> Self
70    where
71        T: Display,
72    {
73        Self(ErrorKind::Custom(msg.to_string()))
74    }
75}
76
77#[derive(Debug)]
78pub(crate) enum ErrorKind {
79    Sqlx(sqlx::Error),
80    Custom(String),
81}
82
83#[derive(Clone, Debug)]
84struct Query<'a> {
85    table: &'a str,
86    inner: QueryInner,
87}
88
89#[derive(Clone, Debug)]
90enum QueryInner {
91    Create {
92        columns: Vec<String>,
93        values: Vec<String>,
94    },
95    Delete {
96        conditions: Conditions,
97    },
98    Insert {
99        columns: Vec<String>,
100        values: Vec<String>,
101    },
102    Select {
103        columns: Vec<String>,
104        conditions: Conditions,
105    },
106}
107
108impl<'a> Query<'a> {
109    pub fn new(table: &'a str, kind: QueryKind) -> Self {
110        let inner = match kind {
111            QueryKind::Create => QueryInner::Create {
112                columns: Vec::new(),
113                values: Vec::new(),
114            },
115            QueryKind::Delete => QueryInner::Delete {
116                conditions: Conditions::default(),
117            },
118            QueryKind::Insert => QueryInner::Insert {
119                columns: Vec::new(),
120                values: Vec::new(),
121            },
122            QueryKind::Select => QueryInner::Select {
123                columns: Vec::new(),
124                conditions: Conditions::default(),
125            },
126        };
127
128        Self { table, inner }
129    }
130
131    pub fn push(&mut self, key: String, value: String) {
132        match &mut self.inner {
133            QueryInner::Create { columns, values } => {
134                columns.push(key);
135                values.push(value);
136            }
137            QueryInner::Delete { conditions: _ } => {
138                unreachable!()
139            }
140            QueryInner::Insert { columns, values } => {
141                columns.push(key);
142                values.push(value);
143            }
144            QueryInner::Select {
145                columns,
146                conditions: _,
147            } => {
148                columns.push(key);
149            }
150        }
151    }
152
153    pub fn push_condition(&mut self, condition: Condition) {
154        match &mut self.inner {
155            QueryInner::Create {
156                columns: _,
157                values: _,
158            } => unreachable!(),
159            QueryInner::Delete { conditions } => {
160                conditions.push(condition);
161            }
162            QueryInner::Insert {
163                columns: _,
164                values: _,
165            } => {
166                unreachable!()
167            }
168            QueryInner::Select {
169                columns: _,
170                conditions,
171            } => {
172                conditions.push(condition);
173            }
174        }
175    }
176}
177
178impl<'a> Display for Query<'a> {
179    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
180        match &self.inner {
181            QueryInner::Create { columns, values } => write!(
182                f,
183                "CREATE TABLE IF NOT EXISTS {} ({})",
184                self.table,
185                columns
186                    .iter()
187                    .zip(values)
188                    .map(|(column, value)| format!("{} {}", column, value))
189                    .collect::<Vec<String>>()
190                    .join(",")
191            ),
192            QueryInner::Delete { conditions } => {
193                write!(f, "DELETE FROM {}{}", self.table, conditions)
194            }
195            QueryInner::Insert { columns, values } => write!(
196                f,
197                "INSERT INTO {} ({}) VALUES ({})",
198                self.table,
199                columns.join(","),
200                values.join(",")
201            ),
202            QueryInner::Select {
203                columns,
204                conditions,
205            } => write!(
206                f,
207                "SELECT {} FROM {}{}",
208                columns.join(","),
209                self.table,
210                conditions
211            ),
212        }
213    }
214}
215
216#[derive(Clone, Debug, Default)]
217struct Conditions {
218    conditions: Vec<Condition>,
219}
220
221impl Conditions {
222    pub fn push(&mut self, value: Condition) {
223        self.conditions.push(value);
224    }
225}
226
227impl Display for Conditions {
228    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
229        if self.conditions.is_empty() {
230            return Ok(());
231        }
232
233        write!(f, " WHERE {}", self.conditions[0])?;
234
235        for condition in self.conditions.iter().skip(1) {
236            write!(f, " AND {}", condition)?;
237        }
238
239        Ok(())
240    }
241}
242
243/// A single sql condition. (e.g. id = 1)
244#[derive(Clone, Debug)]
245struct Condition {
246    column: String,
247    value: String,
248    comparator: Comparator,
249}
250
251impl Condition {
252    pub fn new(column: String, value: String, comparator: Comparator) -> Self {
253        Self {
254            column,
255            value,
256            comparator,
257        }
258    }
259}
260
261impl Display for Condition {
262    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
263        write!(f, "{} {} {}", self.column, self.comparator, self.value)
264    }
265}
266
267#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
268enum Comparator {
269    Eq,
270}
271
272impl Display for Comparator {
273    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
274        let string = match self {
275            Self::Eq => "=",
276        };
277
278        write!(f, "{}", string)
279    }
280}
281
282#[derive(Debug)]
283pub(crate) enum QueryKind {
284    Create,
285    Delete,
286    Insert,
287    Select,
288}