1use crate::{
6 CharType, Error, Size, SizeExt, Type,
7 common::{OPEN_FLAGS, SQL_TYPE_TEXT, SQL_TYPES, SqlType, check_constraint_violation},
8 rusqlite::{Connection, OptionalExtension, ToSql, Transaction, params},
9};
10use cfg_if::cfg_if;
11use const_format::concatcp;
12use std::{borrow::Borrow, collections::BTreeMap, marker::PhantomData, path::Path, sync::LazyLock};
13
14const TABLE_NAME: &str = "rusqlite_map_v2";
19
20static SQL_CREATE_TBL: LazyLock<BTreeMap<(SqlType, SqlType), String>> = LazyLock::new(|| {
21 let mut map = BTreeMap::<(SqlType, SqlType), String>::new();
22 for key_type in SQL_TYPES {
23 for value_type in SQL_TYPES {
24 cfg_if! {
25 if #[cfg(feature = "with_rowid")] {
26 map.insert((key_type, value_type), format!("CREATE TABLE IF NOT EXISTS {TABLE_NAME} (key {key_type} PRIMARY KEY NOT NULL, value {value_type} NOT NULL);"));
27 } else {
28 map.insert((key_type, value_type), format!("CREATE TABLE IF NOT EXISTS {TABLE_NAME} (key {key_type} PRIMARY KEY NOT NULL, value {value_type} NOT NULL) WITHOUT ROWID;"));
29 }
30 }
31 }
32 }
33 map
34});
35
36static SQL_CREATE_NOC: LazyLock<BTreeMap<SqlType, String>> = LazyLock::new(|| {
37 let mut map = BTreeMap::<SqlType, String>::new();
38 for value_type in SQL_TYPES {
39 cfg_if! {
40 if #[cfg(feature = "with_rowid")] {
41 map.insert(value_type, format!("CREATE TABLE IF NOT EXISTS {TABLE_NAME} (key TEXT PRIMARY KEY NOT NULL COLLATE NOCASE, value {value_type} NOT NULL);"));
42 } else {
43 map.insert(value_type, format!("CREATE TABLE IF NOT EXISTS {TABLE_NAME} (key TEXT PRIMARY KEY NOT NULL COLLATE NOCASE, value {value_type} NOT NULL) WITHOUT ROWID;"));
44 }
45 }
46 }
47 map
48});
49
50const SQL_COUNT_KEYS: &str = concatcp!("SELECT COUNT(*) FROM ", TABLE_NAME, ";");
51const SQL_EXIST_KEYS: &str = concatcp!("SELECT EXISTS (SELECT 1 FROM ", TABLE_NAME, ");");
52const SQL_INSERT_KEY: &str = concatcp!("INSERT INTO ", TABLE_NAME, " (key, value) VALUES (?1, ?2);");
53const SQL_UPSERT_KEY: &str = concatcp!("INSERT INTO ", TABLE_NAME, " (key, value) VALUES (?1, ?2) ON CONFLICT(key) DO UPDATE SET value = excluded.value;");
54const SQL_EXISTS_KEY: &str = concatcp!("SELECT 1 FROM ", TABLE_NAME, " WHERE key = ? LIMIT 1;");
55const SQL_EXISTS_NOC: &str = concatcp!("SELECT 1 FROM ", TABLE_NAME, " WHERE key COLLATE NOCASE = ? LIMIT 1;");
56const SQL_LOOKUP_KEY: &str = concatcp!("SELECT value FROM ", TABLE_NAME, " WHERE key = ? LIMIT 1;");
57const SQL_LOOKUP_NOC: &str = concatcp!("SELECT value FROM ", TABLE_NAME, " WHERE key COLLATE NOCASE = ? LIMIT 1;");
58const SQL_QUERY_KEYS: &str = concatcp!("SELECT key FROM ", TABLE_NAME, ";");
59const SQL_QUERY_PAIR: &str = concatcp!("SELECT key, value FROM ", TABLE_NAME, ";");
60const SQL_GLOBA_KEYS: &str = concatcp!("SELECT key FROM ", TABLE_NAME, " WHERE key GLOB ?1;");
61const SQL_GLOBN_KEYS: &str = concatcp!("SELECT key FROM ", TABLE_NAME, " WHERE key NOT GLOB ?1;");
62const SQL_GLOBA_PAIR: &str = concatcp!("SELECT key, value FROM ", TABLE_NAME, " WHERE key GLOB ?1;");
63const SQL_GLOBN_PAIR: &str = concatcp!("SELECT key, value FROM ", TABLE_NAME, " WHERE key NOT GLOB ?1;");
64const SQL_DELETE_KEY: &str = concatcp!("DELETE FROM ", TABLE_NAME, " WHERE key = ?;");
65const SQL_DELETE_NOC: &str = concatcp!("DELETE FROM ", TABLE_NAME, " WHERE key COLLATE NOCASE = ?;");
66const SQL_DELETE_ALL: &str = concatcp!("DELETE FROM ", TABLE_NAME, ";");
67
68pub struct SQLiteMap<K, V>
86where
87 K: Type,
88 V: Type,
89{
90 _types: (PhantomData<K>, PhantomData<V>),
91 connection: Connection,
92}
93
94impl<K, V> SQLiteMap<K, V>
95where
96 K: Type,
97 V: Type,
98{
99 #[inline]
101 pub fn new() -> Result<Self, Error> {
102 Ok(Self { _types: (PhantomData, PhantomData), connection: Self::initialize_connection::<false, &Path>(None)? })
103 }
104
105 #[inline]
109 pub fn with_nocase() -> Result<Self, Error>
110 where
111 K: CharType,
112 {
113 Ok(Self { _types: (PhantomData, PhantomData), connection: Self::initialize_connection::<true, &Path>(None)? })
114 }
115
116 #[inline]
120 pub fn with_file<P>(path: P) -> Result<Self, Error>
121 where
122 P: AsRef<Path>,
123 {
124 Ok(Self { _types: (PhantomData, PhantomData), connection: Self::initialize_connection::<false, _>(Some(path))? })
125 }
126
127 #[inline]
133 pub fn with_file_nocase<P>(path: P) -> Result<Self, Error>
134 where
135 K: CharType,
136 P: AsRef<Path>,
137 {
138 Ok(Self { _types: (PhantomData, PhantomData), connection: Self::initialize_connection::<true, _>(Some(path))? })
139 }
140
141 #[inline(always)]
142 fn initialize_connection<const NO_CASE: bool, P>(path_option: Option<P>) -> Result<Connection, Error>
143 where
144 P: AsRef<Path>,
145 {
146 let connection = if let Some(path) = path_option.as_ref() { Connection::open_with_flags(path, *OPEN_FLAGS)? } else { Connection::open_in_memory()? };
147
148 connection.pragma_update(None, "journal_mode", "OFF")?;
149 connection.pragma_update(None, "synchronous", "OFF")?;
150
151 if path_option.is_some() {
152 connection.pragma_update(None, "temp_store", "MEMORY")?;
153 }
154
155 if !NO_CASE {
156 connection.execute(SQL_CREATE_TBL.get(&(K::SQL_TYPE, V::SQL_TYPE)).unwrap(), [])?;
157 } else {
158 assert_eq!(K::SQL_TYPE, SQL_TYPE_TEXT);
159 connection.execute(SQL_CREATE_NOC.get(&V::SQL_TYPE).unwrap(), [])?;
160 }
161
162 Ok(connection)
163 }
164
165 #[inline]
171 pub fn transaction(&mut self) -> Result<SQLiteMapTransaction<'_, K, V>, Error> {
172 SQLiteMapTransaction::from(&mut self.connection)
173 }
174
175 #[inline]
183 pub fn insert<Q, R>(&mut self, key: &Q, value: &R) -> Result<bool, Error>
184 where
185 K: Borrow<Q>,
186 Q: ?Sized + ToSql,
187 V: Borrow<R>,
188 R: ?Sized + ToSql,
189 {
190 let mut statement = self.connection.prepare_cached(SQL_INSERT_KEY)?;
191 match statement.execute(params![key, value]) {
192 Ok(_) => Ok(true),
193 Err(error) => check_constraint_violation(error),
194 }
195 }
196
197 #[inline]
203 pub fn update<Q, R>(&mut self, key: &Q, value: &R) -> Result<(), Error>
204 where
205 K: Borrow<Q>,
206 Q: ?Sized + ToSql,
207 V: Borrow<R>,
208 R: ?Sized + ToSql,
209 {
210 let mut statement = self.connection.prepare_cached(SQL_UPSERT_KEY)?;
211 statement.execute(params![key, value])?;
212 Ok(())
213 }
214
215 #[inline]
221 pub fn contains_key<Q>(&self, key: &Q) -> Result<bool, Error>
222 where
223 K: Borrow<Q>,
224 Q: ?Sized + ToSql,
225 {
226 let mut statement = self.connection.prepare_cached(SQL_EXISTS_KEY)?;
227 Ok(statement.exists([key])?)
228 }
229
230 #[inline]
236 pub fn contains_key_nocase<Q>(&self, key: &Q) -> Result<bool, Error>
237 where
238 K: Borrow<Q> + CharType,
239 Q: ?Sized + ToSql,
240 {
241 let mut statement = self.connection.prepare_cached(SQL_EXISTS_NOC)?;
242 Ok(statement.exists([key])?)
243 }
244
245 #[inline]
251 pub fn get<Q>(&self, key: &Q) -> Result<Option<V>, Error>
252 where
253 K: Borrow<Q>,
254 Q: ?Sized + ToSql,
255 {
256 let mut statement = self.connection.prepare_cached(SQL_LOOKUP_KEY)?;
257 Ok(statement.query_one([key], |row| row.get(0)).optional()?)
258 }
259
260 #[inline]
266 pub fn get_nocase<Q>(&self, key: &Q) -> Result<Option<V>, Error>
267 where
268 K: Borrow<Q> + CharType,
269 Q: ?Sized + ToSql,
270 {
271 let mut statement = self.connection.prepare_cached(SQL_LOOKUP_NOC)?;
272 Ok(statement.query_one([key], |row| row.get(0)).optional()?)
273 }
274
275 #[inline]
281 pub fn remove<Q>(&mut self, key: &Q) -> Result<bool, Error>
282 where
283 K: Borrow<Q>,
284 Q: ?Sized + ToSql,
285 {
286 let mut statement = self.connection.prepare_cached(SQL_DELETE_KEY)?;
287 Ok(statement.execute([key])? != 0)
288 }
289
290 #[inline]
296 pub fn remove_nocase<Q>(&mut self, key: &Q) -> Result<bool, Error>
297 where
298 K: Borrow<Q> + CharType,
299 Q: ?Sized + ToSql,
300 {
301 let mut statement = self.connection.prepare_cached(SQL_DELETE_NOC)?;
302 Ok(statement.execute([key])? != 0)
303 }
304
305 #[inline]
309 pub fn for_each_key<F>(&self, mut callback: F) -> Result<(), Error>
310 where
311 F: FnMut(K),
312 {
313 let mut statement = self.connection.prepare_cached(SQL_QUERY_KEYS)?;
314 for key in statement.query_map([], |row| row.get(0))? {
315 callback(key?);
316 }
317 Ok(())
318 }
319
320 #[inline]
324 pub fn for_each_entry<F>(&self, mut callback: F) -> Result<(), Error>
325 where
326 F: FnMut(K, V),
327 {
328 let mut statement = self.connection.prepare_cached(SQL_QUERY_PAIR)?;
329 let mut result = statement.query([])?;
330 while let Some(key_value) = result.next()? {
331 let (key, value): (K, V) = (key_value.get(0)?, key_value.get(1)?);
332 callback(key, value);
333 }
334 Ok(())
335 }
336
337 #[inline]
345 pub fn find_key<P>(&self, predicate: P) -> Result<Option<K>, Error>
346 where
347 P: Fn(&K) -> bool,
348 {
349 let mut statement = self.connection.prepare_cached(SQL_QUERY_KEYS)?;
350 for key in statement.query_map([], |row| row.get(0))? {
351 let key: K = key?;
352 if predicate(key.borrow()) {
353 return Ok(Some(key));
354 }
355 }
356 Ok(None)
357 }
358
359 #[inline]
367 pub fn find_entry<P>(&self, predicate: P) -> Result<Option<(K, V)>, Error>
368 where
369 P: Fn(&K, &V) -> bool,
370 {
371 let mut statement = self.connection.prepare_cached(SQL_QUERY_PAIR)?;
372 let mut result = statement.query([])?;
373 while let Some(key_value) = result.next()? {
374 let (key, value): (K, V) = (key_value.get(0)?, key_value.get(1)?);
375 if predicate(&key, &value) {
376 return Ok(Some((key, value)));
377 }
378 }
379 Ok(None)
380 }
381
382 #[inline]
390 pub fn glob_keys<F, Q>(&self, invert: bool, pattern: &Q, mut callback: F) -> Result<(), Error>
391 where
392 F: FnMut(K),
393 K: Borrow<Q> + CharType,
394 Q: ?Sized + ToSql,
395 {
396 let mut statement = self.connection.prepare_cached(if invert { SQL_GLOBN_KEYS } else { SQL_GLOBA_KEYS })?;
397 for key in statement.query_map([pattern], |row| row.get(0))? {
398 callback(key?);
399 }
400 Ok(())
401 }
402
403 #[inline]
411 pub fn glob_entries<F, Q>(&self, invert: bool, pattern: &Q, mut callback: F) -> Result<(), Error>
412 where
413 F: FnMut(K, V),
414 K: Borrow<Q> + CharType,
415 Q: ?Sized + ToSql,
416 {
417 let mut statement = self.connection.prepare_cached(if invert { SQL_GLOBN_PAIR } else { SQL_GLOBA_PAIR })?;
418 let mut result = statement.query([pattern])?;
419 while let Some(key_value) = result.next()? {
420 let (key, value): (K, V) = (key_value.get(0)?, key_value.get(1)?);
421 callback(key, value);
422 }
423 Ok(())
424 }
425
426 #[inline]
428 pub fn len(&self) -> Result<Size, Error> {
429 let mut statement = self.connection.prepare_cached(SQL_COUNT_KEYS)?;
430 let count: i64 = statement.query_one([], |row| row.get(0))?;
431 Ok(Size::from_i64(count))
432 }
433
434 #[inline]
436 pub fn is_empty(&self) -> Result<bool, Error> {
437 let mut statement = self.connection.prepare_cached(SQL_EXIST_KEYS)?;
438 let any_elements: bool = statement.query_one([], |row| row.get(0))?;
439 Ok(!any_elements)
440 }
441
442 #[inline]
444 pub fn clear(&mut self) -> Result<(), Error> {
445 let mut statement = self.connection.prepare_cached(SQL_DELETE_ALL)?;
446 statement.execute([])?;
447 Ok(())
448 }
449}
450
451pub struct SQLiteMapTransaction<'a, K, V>
461where
462 K: Type,
463 V: Type,
464{
465 _types: (PhantomData<K>, PhantomData<V>),
466 transaction: Transaction<'a>,
467}
468
469impl<'a, K, V> SQLiteMapTransaction<'a, K, V>
470where
471 K: Type,
472 V: Type,
473{
474 #[inline]
475 fn from(connection: &'a mut Connection) -> Result<Self, Error> {
476 let mut transaction = connection.transaction()?;
477 transaction.set_drop_behavior(rusqlite::DropBehavior::Commit);
478 Ok(Self { _types: (PhantomData, PhantomData), transaction })
479 }
480
481 #[inline]
483 pub fn commit(self) {}
484
485 #[inline]
487 pub fn insert<Q, R>(&mut self, key: &Q, value: &R) -> Result<bool, Error>
488 where
489 K: Borrow<Q>,
490 Q: ?Sized + ToSql,
491 V: Borrow<R>,
492 R: ?Sized + ToSql,
493 {
494 let mut statement = self.transaction.prepare_cached(SQL_INSERT_KEY)?;
495 match statement.execute(params![key, value]) {
496 Ok(_) => Ok(true),
497 Err(error) => check_constraint_violation(error),
498 }
499 }
500
501 #[inline]
503 pub fn update<Q, R>(&mut self, key: &Q, value: &R) -> Result<(), Error>
504 where
505 K: Borrow<Q>,
506 Q: ?Sized + ToSql,
507 V: Borrow<R>,
508 R: ?Sized + ToSql,
509 {
510 let mut statement = self.transaction.prepare_cached(SQL_UPSERT_KEY)?;
511 statement.execute(params![key, value])?;
512 Ok(())
513 }
514
515 #[inline]
517 pub fn contains_key<Q>(&self, key: &Q) -> Result<bool, Error>
518 where
519 K: Borrow<Q>,
520 Q: ?Sized + ToSql,
521 {
522 let mut statement = self.transaction.prepare_cached(SQL_EXISTS_KEY)?;
523 Ok(statement.exists([key])?)
524 }
525
526 #[inline]
528 pub fn contains_key_nocase<Q>(&self, key: &Q) -> Result<bool, Error>
529 where
530 K: Borrow<Q> + CharType,
531 Q: ?Sized + ToSql,
532 {
533 let mut statement = self.transaction.prepare_cached(SQL_EXISTS_NOC)?;
534 Ok(statement.exists([key])?)
535 }
536
537 #[inline]
539 pub fn get<Q>(&self, key: &Q) -> Result<Option<V>, Error>
540 where
541 K: Borrow<Q>,
542 Q: ?Sized + ToSql,
543 {
544 let mut statement = self.transaction.prepare_cached(SQL_LOOKUP_KEY)?;
545 Ok(statement.query_one([key], |row| row.get(0)).optional()?)
546 }
547
548 #[inline]
550 pub fn get_nocase<Q>(&self, key: &Q) -> Result<Option<V>, Error>
551 where
552 K: Borrow<Q> + CharType,
553 Q: ?Sized + ToSql,
554 {
555 let mut statement = self.transaction.prepare_cached(SQL_LOOKUP_NOC)?;
556 Ok(statement.query_one([key], |row| row.get(0)).optional()?)
557 }
558
559 #[inline]
561 pub fn remove<Q>(&mut self, key: &Q) -> Result<bool, Error>
562 where
563 K: Borrow<Q>,
564 Q: ?Sized + ToSql,
565 {
566 let mut statement = self.transaction.prepare_cached(SQL_DELETE_KEY)?;
567 Ok(statement.execute([key])? != 0)
568 }
569
570 #[inline]
572 pub fn remove_nocase<Q>(&mut self, key: &Q) -> Result<bool, Error>
573 where
574 K: Borrow<Q> + CharType,
575 Q: ?Sized + ToSql,
576 {
577 let mut statement = self.transaction.prepare_cached(SQL_DELETE_NOC)?;
578 Ok(statement.execute([key])? != 0)
579 }
580
581 #[inline]
583 pub fn for_each_key<F>(&self, mut callback: F) -> Result<(), Error>
584 where
585 F: FnMut(K),
586 {
587 let mut statement = self.transaction.prepare_cached(SQL_QUERY_KEYS)?;
588 for key in statement.query_map([], |row| row.get(0))? {
589 callback(key?);
590 }
591 Ok(())
592 }
593
594 #[inline]
596 pub fn for_each_entry<F>(&self, mut callback: F) -> Result<(), Error>
597 where
598 F: FnMut(K, V),
599 {
600 let mut statement = self.transaction.prepare_cached(SQL_QUERY_PAIR)?;
601 let mut result = statement.query([])?;
602 while let Some(key_value) = result.next()? {
603 let (key, value): (K, V) = (key_value.get(0)?, key_value.get(1)?);
604 callback(key, value);
605 }
606 Ok(())
607 }
608
609 #[inline]
611 pub fn find_key<P>(&self, predicate: P) -> Result<Option<K>, Error>
612 where
613 P: Fn(&K) -> bool,
614 {
615 let mut statement = self.transaction.prepare_cached(SQL_QUERY_KEYS)?;
616 for key in statement.query_map([], |row| row.get(0))? {
617 let key: K = key?;
618 if predicate(key.borrow()) {
619 return Ok(Some(key));
620 }
621 }
622 Ok(None)
623 }
624
625 #[inline]
627 pub fn find_entry<P>(&self, predicate: P) -> Result<Option<(K, V)>, Error>
628 where
629 P: Fn(&K, &V) -> bool,
630 {
631 let mut statement = self.transaction.prepare_cached(SQL_QUERY_PAIR)?;
632 let mut result = statement.query([])?;
633 while let Some(key_value) = result.next()? {
634 let (key, value): (K, V) = (key_value.get(0)?, key_value.get(1)?);
635 if predicate(&key, &value) {
636 return Ok(Some((key, value)));
637 }
638 }
639 Ok(None)
640 }
641
642 #[inline]
644 pub fn glob_keys<F, Q>(&self, invert: bool, pattern: &Q, mut callback: F) -> Result<(), Error>
645 where
646 F: FnMut(K),
647 K: Borrow<Q> + CharType,
648 Q: ?Sized + ToSql,
649 {
650 let mut statement = self.transaction.prepare_cached(if invert { SQL_GLOBN_KEYS } else { SQL_GLOBA_KEYS })?;
651 for key in statement.query_map([pattern], |row| row.get(0))? {
652 callback(key?);
653 }
654 Ok(())
655 }
656
657 #[inline]
659 pub fn glob_entries<F, Q>(&self, invert: bool, pattern: &Q, mut callback: F) -> Result<(), Error>
660 where
661 F: FnMut(K, V),
662 K: Borrow<Q> + CharType,
663 Q: ?Sized + ToSql,
664 {
665 let mut statement = self.transaction.prepare_cached(if invert { SQL_GLOBN_PAIR } else { SQL_GLOBA_PAIR })?;
666 let mut result = statement.query([pattern])?;
667 while let Some(key_value) = result.next()? {
668 let (key, value): (K, V) = (key_value.get(0)?, key_value.get(1)?);
669 callback(key, value);
670 }
671 Ok(())
672 }
673
674 #[inline]
676 pub fn len(&self) -> Result<Size, Error> {
677 let mut statement = self.transaction.prepare_cached(SQL_COUNT_KEYS)?;
678 let count: i64 = statement.query_one([], |row| row.get(0))?;
679 Ok(Size::from_i64(count))
680 }
681
682 #[inline]
684 pub fn is_empty(&self) -> Result<bool, Error> {
685 let mut statement = self.transaction.prepare_cached(SQL_EXIST_KEYS)?;
686 let any_elements: bool = statement.query_one([], |row| row.get(0))?;
687 Ok(!any_elements)
688 }
689
690 #[inline]
692 pub fn clear(&mut self) -> Result<(), Error> {
693 let mut statement = self.transaction.prepare_cached(SQL_DELETE_ALL)?;
694 statement.execute([])?;
695 Ok(())
696 }
697}