cache_any/caches/
mysql.rs1use std::sync::Arc;
2use crate::{Cache, Cacheable};
3
4#[derive(Debug, Clone)]
40pub struct MySqlCache {
41 inner: Arc<Inner>,
42}
43
44#[async_trait::async_trait]
45impl Cache for MySqlCache {
46 async fn get<T: Cacheable + Send + Sync>(&self, key: &str) -> anyhow::Result<Option<T>> {
47 let sql = format!(r#"
48 SELECT {}
49 FROM {}
50 WHERE {} = ?
51 LIMIT 1
52 "#, &self.inner.value_field, &self.inner.table, &self.inner.key_field);
53
54 let value: Option<(String,)> = sqlx::query_as(&sql)
55 .bind(key)
56 .fetch_optional(&self.inner.pool)
57 .await?;
58
59 let result = value.as_ref()
60 .map(|value| &value.0)
61 .map(|value| value.as_str())
62 .map(T::from_hex)
63 .transpose()?;
64
65 Ok(result)
66 }
67
68 async fn set<T: Cacheable + Send + Sync>(&self, key: &str, value: T) -> anyhow::Result<()> {
69 let value = value.to_hex();
70
71 let sql = format!(r#"
72 INSERT INTO {} ({}, {})
73 VALUES (?, ?)
74 ON DUPLICATE KEY UPDATE {} = ?
75 "#,
76 &self.inner.table,
77 &self.inner.key_field,
78 &self.inner.value_field,
79 &self.inner.value_field,
80 );
81
82 sqlx::query(&sql)
83 .bind(key)
84 .bind(&value)
85 .bind(&value)
86 .execute(&self.inner.pool)
87 .await?;
88
89 Ok(())
90 }
91
92 async fn delete(&self, key: &str) -> anyhow::Result<()> {
93 let sql = format!(r#"
94 DELETE FROM {}
95 WHERE {} = ?
96 "#, &self.inner.table, &self.inner.key_field);
97
98 sqlx::query(&sql)
99 .bind(key)
100 .execute(&self.inner.pool)
101 .await?;
102
103 Ok(())
104 }
105
106 async fn len(&self) -> anyhow::Result<usize> {
107 let sql = format!(r#"
108 SELECT COUNT(*)
109 FROM {}
110 "#, &self.inner.table);
111
112 let count: (i64,) = sqlx::query_as(&sql).fetch_optional(&self.inner.pool).await?.unwrap_or_default();
113
114 Ok(count.0 as usize)
115 }
116}
117
118#[derive(Debug, Clone)]
120pub struct MySqlCacheBuilder {
121 key_field: String,
122 value_field: String,
123 table: String,
124 pool: sqlx::MySqlPool,
125}
126
127impl MySqlCacheBuilder {
128 pub fn new(pool: sqlx::MySqlPool) -> Self {
130 Self {
131 key_field: String::from("name"),
132 value_field: String::from("val"),
133 table: String::from("cache"),
134 pool,
135 }
136 }
137
138 pub fn key_field<S: ToString>(mut self, key: S) -> Self {
140 self.key_field = key.to_string();
141 self
142 }
143
144 pub fn value_field<S: ToString>(mut self, value: S) -> Self {
146 self.value_field = value.to_string();
147 self
148 }
149
150 pub fn table<S: ToString>(mut self, table: S) -> Self {
152 self.table = table.to_string();
153 self
154 }
155
156 pub fn finish(self) -> MySqlCache {
158 MySqlCache {
159 inner: Arc::new(Inner {
160 key_field: self.key_field,
161 value_field: self.value_field,
162 table: self.table,
163 pool: self.pool,
164 })
165 }
166 }
167}
168
169#[derive(Debug)]
170struct Inner {
171 key_field: String,
172 value_field: String,
173 table: String,
174 pool: sqlx::MySqlPool,
175}
176
177#[cfg(test)]
178mod tests {
179 use sqlx::MySqlPool;
180 use super::*;
181
182 #[tokio::test]
183 async fn test_mysql_cache_builder() -> anyhow::Result<()> {
184 let pool = MySqlPool::connect("mysql://test:123456@127.0.0.1:3306/dev").await?;
185 let cache = MySqlCacheBuilder::new(pool)
186 .table("my_cache")
187 .key_field("name")
188 .value_field("val")
189 .finish();
190
191 assert_eq!(cache.inner.table, String::from("my_cache"));
192 assert_eq!(cache.inner.key_field, String::from("name"));
193 assert_eq!(cache.inner.value_field, String::from("val"));
194
195 let cloned_cache = cache.clone();
196 assert_eq!(cloned_cache.inner.table, String::from("my_cache"));
197 assert_eq!(cloned_cache.inner.key_field, String::from("name"));
198 assert_eq!(cloned_cache.inner.value_field, String::from("val"));
199
200 println!("{:?}", cloned_cache);
201
202 Ok(())
203 }
204
205 #[tokio::test]
206 async fn test_mysql_cache() -> anyhow::Result<()> {
207 let pool = MySqlPool::connect("mysql://test:123456@127.0.0.1:3306/dev").await?;
218
219 let cache = MySqlCacheBuilder::new(pool)
220 .table("my_cache")
221 .key_field("name")
222 .value_field("val")
223 .finish();
224
225 cache.set("user_id", 114514).await?;
226 cache.set("username", String::from("jack")).await?;
227
228 let user_id: usize = cache.get("user_id").await?.unwrap();
229 let username: String = cache.get("username").await?.unwrap();
230
231 assert_eq!(user_id, 114514);
232 assert_eq!(username, String::from("jack"));
233
234 cache.delete("user_id").await?;
235 let user_id: Option<()> = cache.get("user_id").await?;
236 assert_eq!(user_id, None);
237
238 let len = cache.len().await?;
239 println!("len = {}", len);
240
241 Ok(())
242 }
243}