Skip to main content

sqlitemap/
lib.rs

1#[cfg(test)]
2extern crate serde;
3#[cfg(test)]
4extern crate flate2;
5#[cfg(test)]
6extern crate serde_json;
7#[cfg(test)]
8#[macro_use]
9extern crate serde_derive;
10extern crate rusqlite;
11
12mod map;
13pub use map::SqliteMap;
14
15#[cfg(test)]
16mod tests {
17    use super::*;
18    use rusqlite;
19    use rusqlite::Connection;
20    use rusqlite::Error;
21    use rusqlite::types::{ToSql, FromSql, ValueRef, FromSqlError, FromSqlResult, ToSqlOutput};
22
23    #[test]
24    fn it_works() {
25        let connection = Connection::open_in_memory().unwrap();
26        let mut book_reviews = SqliteMap::new(&connection, "map", "TEXT", "TEXT").unwrap();
27
28        assert!(book_reviews.is_empty().unwrap());
29
30        // review some books.
31        assert_eq!(book_reviews.insert::<String>(&"Adventures of Huckleberry Finn",    &"My favorite book.").unwrap(), None);
32        assert_eq!(book_reviews.insert::<String>(&"Grimms' Fairy Tales",               &"Masterpiece.").unwrap(), None);
33        assert_eq!(book_reviews.insert::<String>(&"The Adventures of Sherlock Holmes", &"Eye lyked it alot.").unwrap(), None);
34        assert_eq!(book_reviews.get(&"The Adventures of Sherlock Holmes").unwrap(), Some(String::from("Eye lyked it alot.")));
35        assert_eq!(book_reviews.get::<String>(&"The Adventures of Somebody Else").unwrap(), None);
36
37        // Test replacement
38        assert_eq!(book_reviews.insert::<String>(&"Pride and Prejudice", &"Very enjoyable.").unwrap(), None);
39        assert_eq!(book_reviews.insert(&"Pride and Prejudice", &"Just terrible.").unwrap(), Some(String::from("Very enjoyable.")));
40        assert_eq!(book_reviews.get(&"Pride and Prejudice").unwrap(), Some(String::from("Just terrible.")));
41
42        assert!(!book_reviews.is_empty().unwrap());
43
44        assert_eq!(book_reviews.len().unwrap(), 4);
45
46        // check for a specific one.
47        assert!(!book_reviews.contains_key(&"Les Misérables").unwrap());
48
49        // oops, this review has a lot of spelling mistakes, let's delete it.
50        assert_eq!(book_reviews.remove(&"The Adventures of Sherlock Holmes").unwrap(), Some(String::from("Eye lyked it alot.")));
51        assert_eq!(book_reviews.remove::<String>(&"The Adventures of Sherlock Holmes").unwrap(), None);
52
53        let x: Result<Vec<String>, Error> = book_reviews.keys().unwrap().collect();
54        assert_eq!(x.unwrap(), ["Adventures of Huckleberry Finn", "Grimms' Fairy Tales", "Pride and Prejudice"]);
55
56        let x: Result<Vec<String>, Error> = book_reviews.values().unwrap().collect();
57        assert_eq!(x.unwrap(), ["My favorite book.", "Masterpiece.", "Just terrible."]);
58
59        let x: Result<Vec<(String, String)>, Error> = book_reviews.iter().unwrap().collect();
60        assert_eq!(x.unwrap(), [
61           (String::from("Adventures of Huckleberry Finn"), String::from("My favorite book.")),
62           (String::from("Grimms' Fairy Tales"), String::from("Masterpiece.")),
63           (String::from("Pride and Prejudice"), String::from("Just terrible."))]);
64
65        assert_eq!(book_reviews.len().unwrap(), 3);
66    }
67
68    #[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
69    struct Foo {
70        x: i32,
71        y: String,
72    }
73
74    impl ToSql for Foo {
75        fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
76            let string = serde_json::to_string(self).map_err(|err| rusqlite::Error::ToSqlConversionFailure(Box::new(err)))?;
77            Ok(ToSqlOutput::from(string))
78        }
79    }
80
81    impl FromSql for Foo {
82        fn column_result(value: ValueRef) -> FromSqlResult<Self> {
83            match value {
84                ValueRef::Text(s) => serde_json::from_str(s),
85                ValueRef::Blob(b) => serde_json::from_slice(b),
86                _ => return Err(FromSqlError::InvalidType),
87            }.map_err(|err| FromSqlError::Other(Box::new(err)))
88        }
89    }
90
91
92    #[test]
93    fn json_output() {
94        let connection = Connection::open_in_memory().unwrap();
95        let mut book_reviews = SqliteMap::new(&connection, "map", "TEXT", "TEXT").unwrap();
96        let foo = Foo{
97            x: 8,
98            y: String::from("This is a test string"),
99        };
100
101        assert_eq!(book_reviews.insert::<Foo>(&"foo", &foo).unwrap(), None);
102        assert_eq!(book_reviews.insert(&"foo", &foo).unwrap(), Some(foo));
103    }
104
105    use std::io::prelude::*;
106    use flate2::Compression;
107    use flate2::write::ZlibEncoder;
108    use flate2::read::ZlibDecoder;
109
110    #[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
111    struct ZipFoo(Foo);
112
113    impl ToSql for ZipFoo {
114        fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
115            let mut e = ZlibEncoder::new(Vec::new(), Compression::default());
116            let string = serde_json::to_vec(self).map_err(|err| rusqlite::Error::ToSqlConversionFailure(Box::new(err)))?;
117            e.write_all(&string).map_err(|err| rusqlite::Error::ToSqlConversionFailure(Box::new(err)))?;
118            Ok(ToSqlOutput::from(e.finish().map_err(|err| rusqlite::Error::ToSqlConversionFailure(Box::new(err)))?))
119        }
120    }
121
122    impl FromSql for ZipFoo {
123        fn column_result(value: ValueRef) -> FromSqlResult<Self> {
124            let mut s = String::new();
125            match value {
126                ValueRef::Blob(b) => {
127                    let mut z = ZlibDecoder::new(b);
128                    z.read_to_string(&mut s).map_err(|err| FromSqlError::Other(Box::new(err)))?;
129                    serde_json::from_str(&s)
130                },
131                _ => return Err(FromSqlError::InvalidType),
132            }.map_err(|err| FromSqlError::Other(Box::new(err)))
133        }
134    }
135
136    #[test]
137    fn zip_json_output() {
138        let connection = Connection::open_in_memory().unwrap();
139        let mut book_reviews = SqliteMap::new(&connection, "map", "BLOB", "BLOB").unwrap();
140        let foo = ZipFoo(Foo{
141            x: 8,
142            y: String::from("This is a test string"),
143        });
144
145        assert_eq!(book_reviews.insert::<Foo>(&"foo", &foo).unwrap(), None);
146        assert_eq!(book_reviews.insert(&"foo", &foo).unwrap(), Some(foo));
147    }
148}