1use crate::{
6 CharType, Error, Size, SizeExt, Type,
7 common::{SQL_TYPE_TEXT, SQL_TYPES, SqlType, check_constraint_violation},
8 rusqlite::{Connection, OptionalExtension, ToSql, Transaction, params},
9};
10use cfg_if::cfg_if;
11use std::{borrow::Borrow, collections::BTreeMap, marker::PhantomData, sync::LazyLock};
12
13static SQL_CREATE_TBL: LazyLock<BTreeMap<(SqlType, SqlType), String>> = LazyLock::new(|| {
18 let mut map = BTreeMap::<(SqlType, SqlType), String>::new();
19 for key_type in SQL_TYPES {
20 for value_type in SQL_TYPES {
21 cfg_if! {
22 if #[cfg(feature = "with_rowid")] {
23 map.insert((key_type, value_type), format!("CREATE TABLE data (key {key_type} PRIMARY KEY NOT NULL, value {value_type} NOT NULL);"));
24 } else {
25 map.insert((key_type, value_type), format!("CREATE TABLE data (key {key_type} PRIMARY KEY NOT NULL, value {value_type} NOT NULL) WITHOUT ROWID;"));
26 }
27 }
28 }
29 }
30 map
31});
32
33static SQL_CREATE_NOC: LazyLock<BTreeMap<SqlType, String>> = LazyLock::new(|| {
34 let mut map = BTreeMap::<SqlType, String>::new();
35 for value_type in SQL_TYPES {
36 cfg_if! {
37 if #[cfg(feature = "with_rowid")] {
38 map.insert(value_type, format!("CREATE TABLE data (key TEXT PRIMARY KEY NOT NULL COLLATE NOCASE, value {value_type} NOT NULL);"));
39 } else {
40 map.insert(value_type, format!("CREATE TABLE data (key TEXT PRIMARY KEY NOT NULL COLLATE NOCASE, value {value_type} NOT NULL) WITHOUT ROWID;"));
41 }
42 }
43 }
44 map
45});
46
47const SQL_COUNT_KEYS: &str = "SELECT COUNT(*) FROM data;";
48const SQL_INSERT_KEY: &str = "INSERT INTO data (key, value) VALUES (?1, ?2);";
49const SQL_UPSERT_KEY: &str = "INSERT INTO data (key, value) VALUES (?1, ?2) ON CONFLICT(key) DO UPDATE SET value = excluded.value;";
50const SQL_EXISTS_KEY: &str = "SELECT 1 FROM data WHERE key = ? LIMIT 1;";
51const SQL_EXISTS_NOC: &str = "SELECT 1 FROM data WHERE key COLLATE NOCASE = ? LIMIT 1;";
52const SQL_LOOKUP_KEY: &str = "SELECT value FROM data WHERE key = ? LIMIT 1;";
53const SQL_LOOKUP_NOC: &str = "SELECT value FROM data WHERE key COLLATE NOCASE = ? LIMIT 1;";
54const SQL_QUERY_KEYS: &str = "SELECT key FROM data;";
55const SQL_WHERE_KEYS: &str = "SELECT key FROM data WHERE key LIKE ?1 ESCAPE '\\';";
56const SQL_QUERY_PAIR: &str = "SELECT key, value FROM data;";
57const SQL_WHERE_PAIR: &str = "SELECT key, value FROM data WHERE key LIKE ?1 ESCAPE '\\';";
58const SQL_DELETE_KEY: &str = "DELETE FROM data WHERE key = ?;";
59const SQL_DELETE_NOC: &str = "DELETE FROM data WHERE key COLLATE NOCASE = ?;";
60const SQL_DELETE_ALL: &str = "DELETE FROM data;";
61
62pub struct SQLiteMap<K, V>
80where
81 K: Type,
82 V: Type,
83{
84 _types: (PhantomData<K>, PhantomData<V>),
85 connection: Connection,
86}
87
88impl<K, V> SQLiteMap<K, V>
89where
90 K: Type,
91 V: Type,
92{
93 #[inline]
95 pub fn new() -> Result<Self, Error> {
96 Ok(Self { _types: (PhantomData, PhantomData), connection: Self::initialize_connection::<false>()? })
97 }
98
99 #[inline]
103 pub fn with_nocase() -> Result<Self, Error>
104 where
105 K: CharType,
106 {
107 Ok(Self { _types: (PhantomData, PhantomData), connection: Self::initialize_connection::<true>()? })
108 }
109
110 #[inline]
111 fn initialize_connection<const NO_CASE: bool>() -> Result<Connection, Error> {
112 let connection = Connection::open_in_memory()?;
113 connection.pragma_update(None, "journal_mode", "OFF")?;
114 connection.pragma_update(None, "synchronous", "OFF")?;
115 connection.pragma_update(None, "temp_store", "MEMORY")?;
116 if !NO_CASE {
117 connection.execute(SQL_CREATE_TBL.get(&(K::SQL_TYPE, V::SQL_TYPE)).unwrap(), [])?;
118 } else {
119 assert_eq!(K::SQL_TYPE, SQL_TYPE_TEXT);
120 connection.execute(SQL_CREATE_NOC.get(&V::SQL_TYPE).unwrap(), [])?;
121 }
122 Ok(connection)
123 }
124
125 #[inline]
131 pub fn transaction(&mut self) -> Result<SQLiteMapTransaction<'_, K, V>, Error> {
132 SQLiteMapTransaction::from(&mut self.connection)
133 }
134
135 #[inline]
143 pub fn insert<Q, R>(&mut self, key: &Q, value: &R) -> Result<bool, Error>
144 where
145 K: Borrow<Q>,
146 Q: ?Sized + ToSql,
147 V: Borrow<R>,
148 R: ?Sized + ToSql,
149 {
150 let mut statement = self.connection.prepare_cached(SQL_INSERT_KEY)?;
151 match statement.execute(params![key, value]) {
152 Ok(_) => Ok(true),
153 Err(error) => check_constraint_violation(error),
154 }
155 }
156
157 #[inline]
163 pub fn update<Q, R>(&mut self, key: &Q, value: &R) -> Result<(), Error>
164 where
165 K: Borrow<Q>,
166 Q: ?Sized + ToSql,
167 V: Borrow<R>,
168 R: ?Sized + ToSql,
169 {
170 let mut statement = self.connection.prepare_cached(SQL_UPSERT_KEY)?;
171 statement.execute(params![key, value])?;
172 Ok(())
173 }
174
175 #[inline]
181 pub fn contains_key<Q>(&self, key: &Q) -> Result<bool, Error>
182 where
183 K: Borrow<Q>,
184 Q: ?Sized + ToSql,
185 {
186 let mut statement = self.connection.prepare_cached(SQL_EXISTS_KEY)?;
187 Ok(statement.exists([key])?)
188 }
189
190 #[inline]
196 pub fn contains_key_nocase<Q>(&self, key: &Q) -> Result<bool, Error>
197 where
198 K: Borrow<Q> + CharType,
199 Q: ?Sized + ToSql,
200 {
201 let mut statement = self.connection.prepare_cached(SQL_EXISTS_NOC)?;
202 Ok(statement.exists([key])?)
203 }
204
205 #[inline]
211 pub fn get<Q>(&self, key: &Q) -> Result<Option<V>, Error>
212 where
213 K: Borrow<Q>,
214 Q: ?Sized + ToSql,
215 {
216 let mut statement = self.connection.prepare_cached(SQL_LOOKUP_KEY)?;
217 Ok(statement.query_one([key], |row| row.get(0)).optional()?)
218 }
219
220 #[inline]
226 pub fn get_nocase<Q>(&self, key: &Q) -> Result<Option<V>, Error>
227 where
228 K: Borrow<Q> + CharType,
229 Q: ?Sized + ToSql,
230 {
231 let mut statement = self.connection.prepare_cached(SQL_LOOKUP_NOC)?;
232 Ok(statement.query_one([key], |row| row.get(0)).optional()?)
233 }
234
235 #[inline]
241 pub fn remove<Q>(&mut self, key: &Q) -> Result<bool, Error>
242 where
243 K: Borrow<Q>,
244 Q: ?Sized + ToSql,
245 {
246 let mut statement = self.connection.prepare_cached(SQL_DELETE_KEY)?;
247 Ok(statement.execute([key])? != 0)
248 }
249
250 #[inline]
256 pub fn remove_nocase<Q>(&mut self, key: &Q) -> Result<bool, Error>
257 where
258 K: Borrow<Q> + CharType,
259 Q: ?Sized + ToSql,
260 {
261 let mut statement = self.connection.prepare_cached(SQL_DELETE_NOC)?;
262 Ok(statement.execute([key])? != 0)
263 }
264
265 #[inline]
269 pub fn for_each_key<F>(&self, mut callback: F) -> Result<(), Error>
270 where
271 F: FnMut(K),
272 {
273 let mut statement = self.connection.prepare_cached(SQL_QUERY_KEYS)?;
274 for key in statement.query_map([], |row| row.get(0))? {
275 callback(key?);
276 }
277 Ok(())
278 }
279
280 #[inline]
284 pub fn for_each_entry<F>(&self, mut callback: F) -> Result<(), Error>
285 where
286 F: FnMut(K, V),
287 {
288 let mut statement = self.connection.prepare_cached(SQL_QUERY_PAIR)?;
289 let mut result = statement.query([])?;
290 while let Some(key_value) = result.next()? {
291 let (key, value): (K, V) = (key_value.get(0)?, key_value.get(1)?);
292 callback(key, value);
293 }
294 Ok(())
295 }
296
297 #[inline]
305 pub fn find_key<P>(&self, predicate: P) -> Result<Option<K>, Error>
306 where
307 P: Fn(&K) -> bool,
308 {
309 let mut statement = self.connection.prepare_cached(SQL_QUERY_KEYS)?;
310 for key in statement.query_map([], |row| row.get(0))? {
311 let key: K = key?;
312 if predicate(key.borrow()) {
313 return Ok(Some(key));
314 }
315 }
316 Ok(None)
317 }
318
319 #[inline]
327 pub fn find_entry<P>(&self, predicate: P) -> Result<Option<(K, V)>, Error>
328 where
329 P: Fn(&K, &V) -> bool,
330 {
331 let mut statement = self.connection.prepare_cached(SQL_QUERY_PAIR)?;
332 let mut result = statement.query([])?;
333 while let Some(key_value) = result.next()? {
334 let (key, value): (K, V) = (key_value.get(0)?, key_value.get(1)?);
335 if predicate(&key, &value) {
336 return Ok(Some((key, value)));
337 }
338 }
339 Ok(None)
340 }
341
342 #[inline]
352 pub fn filter_keys<F, Q>(&self, pattern: &Q, mut callback: F) -> Result<(), Error>
353 where
354 F: FnMut(K),
355 K: Borrow<Q> + CharType,
356 Q: ?Sized + ToSql,
357 {
358 let mut statement = self.connection.prepare_cached(SQL_WHERE_KEYS)?;
359 for key in statement.query_map([pattern], |row| row.get(0))? {
360 callback(key?);
361 }
362 Ok(())
363 }
364
365 #[inline]
375 pub fn filter_entries<F, Q>(&self, pattern: &Q, mut callback: F) -> Result<(), Error>
376 where
377 F: FnMut(K, V),
378 K: Borrow<Q> + CharType,
379 Q: ?Sized + ToSql,
380 {
381 let mut statement = self.connection.prepare_cached(SQL_WHERE_PAIR)?;
382 let mut result = statement.query([pattern])?;
383 while let Some(key_value) = result.next()? {
384 let (key, value): (K, V) = (key_value.get(0)?, key_value.get(1)?);
385 callback(key, value);
386 }
387 Ok(())
388 }
389
390 #[inline]
392 pub fn len(&self) -> Result<Size, Error> {
393 let mut statement = self.connection.prepare_cached(SQL_COUNT_KEYS)?;
394 let count: i64 = statement.query_one([], |row| row.get(0))?;
395 Ok(Size::from_i64(count))
396 }
397
398 #[inline]
400 pub fn is_empty(&self) -> Result<bool, Error> {
401 Ok(self.len()? == 0)
402 }
403
404 #[inline]
406 pub fn clear(&mut self) -> Result<(), Error> {
407 let mut statement = self.connection.prepare_cached(SQL_DELETE_ALL)?;
408 statement.execute([])?;
409 Ok(())
410 }
411}
412
413pub struct SQLiteMapTransaction<'a, K, V>
423where
424 K: Type,
425 V: Type,
426{
427 _types: (PhantomData<K>, PhantomData<V>),
428 transaction: Transaction<'a>,
429}
430
431impl<'a, K, V> SQLiteMapTransaction<'a, K, V>
432where
433 K: Type,
434 V: Type,
435{
436 #[inline]
437 fn from(connection: &'a mut Connection) -> Result<Self, Error> {
438 let mut transaction = connection.transaction()?;
439 transaction.set_drop_behavior(rusqlite::DropBehavior::Commit);
440 Ok(Self { _types: (PhantomData, PhantomData), transaction })
441 }
442
443 #[inline]
445 pub fn commit(self) {}
446
447 #[inline]
449 pub fn insert<Q, R>(&mut self, key: &Q, value: &R) -> Result<bool, Error>
450 where
451 K: Borrow<Q>,
452 Q: ?Sized + ToSql,
453 V: Borrow<R>,
454 R: ?Sized + ToSql,
455 {
456 let mut statement = self.transaction.prepare_cached(SQL_INSERT_KEY)?;
457 match statement.execute(params![key, value]) {
458 Ok(_) => Ok(true),
459 Err(error) => check_constraint_violation(error),
460 }
461 }
462
463 #[inline]
465 pub fn update<Q, R>(&mut self, key: &Q, value: &R) -> Result<(), Error>
466 where
467 K: Borrow<Q>,
468 Q: ?Sized + ToSql,
469 V: Borrow<R>,
470 R: ?Sized + ToSql,
471 {
472 let mut statement = self.transaction.prepare_cached(SQL_UPSERT_KEY)?;
473 statement.execute(params![key, value])?;
474 Ok(())
475 }
476
477 #[inline]
479 pub fn contains_key<Q>(&self, key: &Q) -> Result<bool, Error>
480 where
481 K: Borrow<Q>,
482 Q: ?Sized + ToSql,
483 {
484 let mut statement = self.transaction.prepare_cached(SQL_EXISTS_KEY)?;
485 Ok(statement.exists([key])?)
486 }
487
488 #[inline]
490 pub fn contains_key_nocase<Q>(&self, key: &Q) -> Result<bool, Error>
491 where
492 K: Borrow<Q> + CharType,
493 Q: ?Sized + ToSql,
494 {
495 let mut statement = self.transaction.prepare_cached(SQL_EXISTS_NOC)?;
496 Ok(statement.exists([key])?)
497 }
498
499 #[inline]
501 pub fn get<Q>(&self, key: &Q) -> Result<Option<V>, Error>
502 where
503 K: Borrow<Q>,
504 Q: ?Sized + ToSql,
505 {
506 let mut statement = self.transaction.prepare_cached(SQL_LOOKUP_KEY)?;
507 Ok(statement.query_one([key], |row| row.get(0)).optional()?)
508 }
509
510 #[inline]
512 pub fn get_nocase<Q>(&self, key: &Q) -> Result<Option<V>, Error>
513 where
514 K: Borrow<Q> + CharType,
515 Q: ?Sized + ToSql,
516 {
517 let mut statement = self.transaction.prepare_cached(SQL_LOOKUP_NOC)?;
518 Ok(statement.query_one([key], |row| row.get(0)).optional()?)
519 }
520
521 #[inline]
523 pub fn remove<Q>(&mut self, key: &Q) -> Result<bool, Error>
524 where
525 K: Borrow<Q>,
526 Q: ?Sized + ToSql,
527 {
528 let mut statement = self.transaction.prepare_cached(SQL_DELETE_KEY)?;
529 Ok(statement.execute([key])? != 0)
530 }
531
532 #[inline]
534 pub fn remove_nocase<Q>(&mut self, key: &Q) -> Result<bool, Error>
535 where
536 K: Borrow<Q> + CharType,
537 Q: ?Sized + ToSql,
538 {
539 let mut statement = self.transaction.prepare_cached(SQL_DELETE_NOC)?;
540 Ok(statement.execute([key])? != 0)
541 }
542
543 #[inline]
545 pub fn for_each_key<F>(&self, mut callback: F) -> Result<(), Error>
546 where
547 F: FnMut(K),
548 {
549 let mut statement = self.transaction.prepare_cached(SQL_QUERY_KEYS)?;
550 for key in statement.query_map([], |row| row.get(0))? {
551 callback(key?);
552 }
553 Ok(())
554 }
555
556 #[inline]
558 pub fn for_each_entry<F>(&self, mut callback: F) -> Result<(), Error>
559 where
560 F: FnMut(K, V),
561 {
562 let mut statement = self.transaction.prepare_cached(SQL_QUERY_PAIR)?;
563 let mut result = statement.query([])?;
564 while let Some(key_value) = result.next()? {
565 let (key, value): (K, V) = (key_value.get(0)?, key_value.get(1)?);
566 callback(key, value);
567 }
568 Ok(())
569 }
570
571 #[inline]
573 pub fn find_key<P>(&self, predicate: P) -> Result<Option<K>, Error>
574 where
575 P: Fn(&K) -> bool,
576 {
577 let mut statement = self.transaction.prepare_cached(SQL_QUERY_KEYS)?;
578 for key in statement.query_map([], |row| row.get(0))? {
579 let key: K = key?;
580 if predicate(key.borrow()) {
581 return Ok(Some(key));
582 }
583 }
584 Ok(None)
585 }
586
587 #[inline]
589 pub fn find_entry<P>(&self, predicate: P) -> Result<Option<(K, V)>, Error>
590 where
591 P: Fn(&K, &V) -> bool,
592 {
593 let mut statement = self.transaction.prepare_cached(SQL_QUERY_PAIR)?;
594 let mut result = statement.query([])?;
595 while let Some(key_value) = result.next()? {
596 let (key, value): (K, V) = (key_value.get(0)?, key_value.get(1)?);
597 if predicate(&key, &value) {
598 return Ok(Some((key, value)));
599 }
600 }
601 Ok(None)
602 }
603
604 #[inline]
606 pub fn filter_keys<F, Q>(&self, pattern: &Q, mut callback: F) -> Result<(), Error>
607 where
608 F: FnMut(K),
609 K: Borrow<Q> + CharType,
610 Q: ?Sized + ToSql,
611 {
612 let mut statement = self.transaction.prepare_cached(SQL_WHERE_KEYS)?;
613 for key in statement.query_map([pattern], |row| row.get(0))? {
614 callback(key?);
615 }
616 Ok(())
617 }
618
619 #[inline]
621 pub fn filter_entries<F, Q>(&self, pattern: &Q, mut callback: F) -> Result<(), Error>
622 where
623 F: FnMut(K, V),
624 K: Borrow<Q> + CharType,
625 Q: ?Sized + ToSql,
626 {
627 let mut statement = self.transaction.prepare_cached(SQL_WHERE_PAIR)?;
628 let mut result = statement.query([pattern])?;
629 while let Some(key_value) = result.next()? {
630 let (key, value): (K, V) = (key_value.get(0)?, key_value.get(1)?);
631 callback(key, value);
632 }
633 Ok(())
634 }
635
636 #[inline]
638 pub fn len(&self) -> Result<Size, Error> {
639 let mut statement = self.transaction.prepare_cached(SQL_COUNT_KEYS)?;
640 let count: i64 = statement.query_one([], |row| row.get(0))?;
641 Ok(Size::from_i64(count))
642 }
643
644 #[inline]
646 pub fn is_empty(&self) -> Result<bool, Error> {
647 Ok(self.len()? == 0)
648 }
649
650 #[inline]
652 pub fn clear(&mut self) -> Result<(), Error> {
653 let mut statement = self.transaction.prepare_cached(SQL_DELETE_ALL)?;
654 statement.execute([])?;
655 Ok(())
656 }
657}