1use rusqlite::OptionalExtension;
6
7use crate::common::{Error, SizeT, check_constraint_violation};
8use crate::rusqlite::{Connection, Transaction};
9
10const SQL_CREATE_TBL: &str = "CREATE TABLE data (key TEXT PRIMARY KEY NOT NULL, value TEXT NOT NULL) WITHOUT ROWID;";
15const SQL_CREATE_NOC: &str = "CREATE TABLE data (key TEXT PRIMARY KEY NOT NULL COLLATE NOCASE, value TEXT NOT NULL) WITHOUT ROWID;";
16const SQL_COUNT_KEYS: &str = "SELECT COUNT(*) FROM data;";
17const SQL_INSERT_KEY: &str = "INSERT INTO data (key, value) VALUES (?1, ?2);";
18const SQL_UPSERT_KEY: &str = "INSERT INTO data (key, value) VALUES (?1, ?2) ON CONFLICT(key) DO UPDATE SET value = excluded.value;";
19const SQL_EXISTS_KEY: &str = "SELECT 1 FROM data WHERE key = ? LIMIT 1;";
20const SQL_EXISTS_NOC: &str = "SELECT 1 FROM data WHERE key COLLATE NOCASE = ? LIMIT 1;";
21const SQL_LOOKUP_KEY: &str = "SELECT value FROM data WHERE key = ? LIMIT 1;";
22const SQL_LOOKUP_NOC: &str = "SELECT value FROM data WHERE key COLLATE NOCASE = ? LIMIT 1;";
23const SQL_QUERY_KEYS: &str = "SELECT key, value FROM data;";
24const SQL_DELETE_KEY: &str = "DELETE FROM data WHERE key = ?;";
25const SQL_DELETE_NOC: &str = "DELETE FROM data WHERE key COLLATE NOCASE = ?;";
26const SQL_DELETE_ALL: &str = "DELETE FROM data;";
27
28pub struct SQLiteMap {
42 connection: Connection,
43}
44
45impl SQLiteMap {
46 #[inline]
48 pub fn new() -> Result<Self, Error> {
49 Ok(Self { connection: Self::initialize_connection(false)? })
50 }
51
52 #[inline]
54 pub fn with_nocase() -> Result<Self, Error> {
55 Ok(Self { connection: Self::initialize_connection(true)? })
56 }
57
58 #[inline]
59 fn initialize_connection(no_case: bool) -> Result<Connection, Error> {
60 let connection = Connection::open_in_memory()?;
61 connection.pragma_update(None, "journal_mode", "OFF")?;
62 connection.pragma_update(None, "synchronous", "OFF")?;
63 connection.pragma_update(None, "temp_store", "MEMORY")?;
64 if !no_case {
65 connection.execute(SQL_CREATE_TBL, [])?;
66 } else {
67 connection.execute(SQL_CREATE_NOC, [])?;
68 }
69 Ok(connection)
70 }
71
72 #[inline]
78 pub fn transaction(&mut self) -> Result<SQLiteMapTransaction<'_>, Error> {
79 SQLiteMapTransaction::from(&mut self.connection)
80 }
81
82 #[inline]
90 pub fn insert(&mut self, key: &str, value: &str) -> Result<bool, Error> {
91 let mut insert = self.connection.prepare_cached(SQL_INSERT_KEY)?;
92 match insert.execute([key, value]) {
93 Ok(_) => Ok(true),
94 Err(error) => check_constraint_violation(error),
95 }
96 }
97
98 #[inline]
104 pub fn update(&mut self, key: &str, value: &str) -> Result<(), Error> {
105 let mut update = self.connection.prepare_cached(SQL_UPSERT_KEY)?;
106 update.execute([key, value])?;
107 Ok(())
108 }
109
110 #[inline]
116 pub fn contains(&self, key: &str) -> Result<bool, Error> {
117 let mut contains = self.connection.prepare_cached(SQL_EXISTS_KEY)?;
118 Ok(contains.exists([key])?)
119 }
120
121 #[inline]
127 pub fn contains_nocase(&self, key: &str) -> Result<bool, Error> {
128 let mut contains = self.connection.prepare_cached(SQL_EXISTS_NOC)?;
129 Ok(contains.exists([key])?)
130 }
131
132 #[inline]
138 pub fn get(&self, key: &str) -> Result<Option<String>, Error> {
139 let mut get = self.connection.prepare_cached(SQL_LOOKUP_KEY)?;
140 Ok(get.query_one([key], |row| row.get(0)).optional()?)
141 }
142
143 #[inline]
149 pub fn get_nocase(&self, key: &str) -> Result<Option<String>, Error> {
150 let mut get = self.connection.prepare_cached(SQL_LOOKUP_NOC)?;
151 Ok(get.query_one([key], |row| row.get(0)).optional()?)
152 }
153
154 #[inline]
160 pub fn remove(&mut self, key: &str) -> Result<bool, Error> {
161 let mut contains = self.connection.prepare_cached(SQL_DELETE_KEY)?;
162 Ok(contains.execute([key])? != 0)
163 }
164
165 #[inline]
171 pub fn remove_nocase(&mut self, key: &str) -> Result<bool, Error> {
172 let mut contains = self.connection.prepare_cached(SQL_DELETE_NOC)?;
173 Ok(contains.execute([key])? != 0)
174 }
175
176 #[inline]
180 pub fn for_each<F>(&self, mut callback: F) -> Result<(), Error>
181 where
182 F: FnMut(&str, &str),
183 {
184 let mut iter = self.connection.prepare_cached(SQL_QUERY_KEYS)?;
185 let mut result = iter.query([])?;
186 while let Some(current_item) = result.next()? {
187 let key: String = current_item.get(0)?;
188 let value: String = current_item.get(1)?;
189 callback(&key, &value);
190 }
191 Ok(())
192 }
193
194 #[inline]
202 pub fn find<P>(&self, predicate: P) -> Result<Option<(String, String)>, Error>
203 where
204 P: Fn(&str, &str) -> bool,
205 {
206 let mut iter = self.connection.prepare_cached(SQL_QUERY_KEYS)?;
207 let mut result = iter.query([])?;
208 while let Some(current_item) = result.next()? {
209 let key: String = current_item.get(0)?;
210 let value: String = current_item.get(1)?;
211 if predicate(&key, &value) {
212 return Ok(Some((key, value)));
213 }
214 }
215 Ok(None)
216 }
217
218 #[inline]
220 pub fn len(&self) -> Result<SizeT, Error> {
221 let mut query_count = self.connection.prepare_cached(SQL_COUNT_KEYS)?;
222 let count: i64 = query_count.query_one([], |row| row.get(0))?;
223 Ok(count.try_into().unwrap_or_default())
224 }
225
226 #[inline]
228 pub fn is_empty(&self) -> Result<bool, Error> {
229 Ok(self.len()? == 0)
230 }
231
232 #[inline]
234 pub fn clear(&mut self) -> Result<(), Error> {
235 let mut clear = self.connection.prepare_cached(SQL_DELETE_ALL)?;
236 clear.execute([])?;
237 Ok(())
238 }
239}
240
241impl Default for SQLiteMap {
242 #[inline]
248 fn default() -> Self {
249 Self::new().expect("Failed to create SQLiteMap instance!")
250 }
251}
252
253pub struct SQLiteMapTransaction<'a> {
263 transaction: Transaction<'a>,
264}
265
266impl<'a> SQLiteMapTransaction<'a> {
267 #[inline]
268 fn from(connection: &'a mut Connection) -> Result<Self, Error> {
269 let mut transaction = connection.transaction()?;
270 transaction.set_drop_behavior(rusqlite::DropBehavior::Commit);
271 Ok(Self { transaction })
272 }
273
274 #[inline]
276 pub fn commit(self) {}
277
278 #[inline]
280 pub fn insert(&mut self, key: &str, value: &str) -> Result<bool, Error> {
281 let mut insert = self.transaction.prepare_cached(SQL_INSERT_KEY)?;
282 match insert.execute([key, value]) {
283 Ok(_) => Ok(true),
284 Err(error) => check_constraint_violation(error),
285 }
286 }
287
288 #[inline]
290 pub fn update(&mut self, key: &str, value: &str) -> Result<(), Error> {
291 let mut update = self.transaction.prepare_cached(SQL_UPSERT_KEY)?;
292 update.execute([key, value])?;
293 Ok(())
294 }
295
296 #[inline]
298 pub fn contains(&self, key: &str) -> Result<bool, Error> {
299 let mut contains = self.transaction.prepare_cached(SQL_EXISTS_KEY)?;
300 Ok(contains.exists([key])?)
301 }
302
303 #[inline]
305 pub fn contains_nocase(&self, key: &str) -> Result<bool, Error> {
306 let mut contains = self.transaction.prepare_cached(SQL_EXISTS_NOC)?;
307 Ok(contains.exists([key])?)
308 }
309
310 #[inline]
312 pub fn get(&self, key: &str) -> Result<Option<String>, Error> {
313 let mut get = self.transaction.prepare_cached(SQL_LOOKUP_KEY)?;
314 Ok(get.query_one([key], |row| row.get(0)).optional()?)
315 }
316
317 #[inline]
319 pub fn get_nocase(&self, key: &str) -> Result<Option<String>, Error> {
320 let mut get = self.transaction.prepare_cached(SQL_LOOKUP_NOC)?;
321 Ok(get.query_one([key], |row| row.get(0)).optional()?)
322 }
323
324 #[inline]
326 pub fn remove(&mut self, key: &str) -> Result<bool, Error> {
327 let mut contains = self.transaction.prepare_cached(SQL_DELETE_KEY)?;
328 Ok(contains.execute([key])? != 0)
329 }
330
331 #[inline]
333 pub fn remove_nocase(&mut self, key: &str) -> Result<bool, Error> {
334 let mut contains = self.transaction.prepare_cached(SQL_DELETE_NOC)?;
335 Ok(contains.execute([key])? != 0)
336 }
337
338 #[inline]
340 pub fn for_each<F>(&self, mut callback: F) -> Result<(), Error>
341 where
342 F: FnMut(&str, &str),
343 {
344 let mut iter = self.transaction.prepare_cached(SQL_QUERY_KEYS)?;
345 let mut result = iter.query([])?;
346 while let Some(current_item) = result.next()? {
347 let key: String = current_item.get(0)?;
348 let value: String = current_item.get(1)?;
349 callback(&key, &value);
350 }
351 Ok(())
352 }
353
354 #[inline]
356 pub fn find<P>(&self, predicate: P) -> Result<Option<(String, String)>, Error>
357 where
358 P: Fn(&str, &str) -> bool,
359 {
360 let mut iter = self.transaction.prepare_cached(SQL_QUERY_KEYS)?;
361 let mut result = iter.query([])?;
362 while let Some(current_item) = result.next()? {
363 let key: String = current_item.get(0)?;
364 let value: String = current_item.get(1)?;
365 if predicate(&key, &value) {
366 return Ok(Some((key, value)));
367 }
368 }
369 Ok(None)
370 }
371
372 #[inline]
374 pub fn len(&self) -> Result<SizeT, Error> {
375 let mut query_count = self.transaction.prepare_cached(SQL_COUNT_KEYS)?;
376 let count: i64 = query_count.query_one([], |row| row.get(0))?;
377 Ok(count.try_into().unwrap_or_default())
378 }
379
380 #[inline]
382 pub fn is_empty(&self) -> Result<bool, Error> {
383 Ok(self.len()? == 0)
384 }
385
386 #[inline]
388 pub fn clear(&mut self) -> Result<(), Error> {
389 let mut clear = self.transaction.prepare_cached(SQL_DELETE_ALL)?;
390 clear.execute([])?;
391 Ok(())
392 }
393}