diff --git a/src/pickledb.rs b/src/pickledb.rs index 68f4a47..2c203b4 100644 --- a/src/pickledb.rs +++ b/src/pickledb.rs @@ -10,6 +10,7 @@ use crate::iterators::{PickleDbIterator, PickleDbListIterator}; use crate::serialization::SerializationMethod; use crate::serialization::Serializer; +#[derive(Copy, Clone)] /// An enum that determines the policy of dumping PickleDb changes into the file pub enum PickleDbDumpPolicy { /// Never dump any change, file will always remain read-only @@ -71,6 +72,34 @@ impl PickleDb { } } + /// Attempts to load a DB from a file, and if it fails to load, constructs a new `PickleDb` instance. + /// + /// # Arguments + /// + /// * `db_path` - a path where the DB will be stored + /// * `dump_policy` - an enum value that determines the policy of dumping DB changes into the file. Please see + /// [PickleDb::load()](#method.load) to understand the different policy options + /// * `serialization_method` - the serialization method to use for storing the data to memory and file + /// + /// # Examples + /// + /// ```no_run + /// use pickledb::{PickleDb, PickleDbDumpPolicy, SerializationMethod}; + /// + /// let mut db = PickleDb::load_or_new("example.db", PickleDbDumpPolicy::AutoDump, SerializationMethod::Json); + /// ``` + /// + pub fn load_or_new>( + db_path: P, + dump_policy: PickleDbDumpPolicy, + serialization_method: SerializationMethod, + ) -> Result { + match db_path.as_ref().exists() { + true => PickleDb::load(db_path, dump_policy, serialization_method), + false => Ok(PickleDb::new(db_path, dump_policy, serialization_method)), + } + } + /// Constructs a new `PickleDb` instance that uses [JSON serialization](https://crates.io/crates/serde_json) for storing the data. /// /// # Arguments @@ -550,14 +579,8 @@ impl PickleDb { /// pub fn get_all(&self) -> Vec { [ - self.map - .iter() - .map(|(key, _)| key.clone()) - .collect::>(), - self.list_map - .iter() - .map(|(key, _)| key.clone()) - .collect::>(), + self.map.keys().cloned().collect::>(), + self.list_map.keys().cloned().collect::>(), ] .concat() } diff --git a/src/serialization.rs b/src/serialization.rs index 4ce0194..eb11b61 100644 --- a/src/serialization.rs +++ b/src/serialization.rs @@ -7,7 +7,7 @@ type DbListMap = HashMap>>; /// An enum for specifying the serialization method to use when creating a new PickleDB database /// or loading one from a file -#[derive(Debug)] +#[derive(Debug, Clone, Copy)] pub enum SerializationMethod { /// [JSON serialization](https://crates.io/crates/serde_json) Json, diff --git a/tests/pickledb_key_value_tests.rs b/tests/pickledb_key_value_tests.rs index 8d979b1..6bbeb70 100644 --- a/tests/pickledb_key_value_tests.rs +++ b/tests/pickledb_key_value_tests.rs @@ -414,3 +414,123 @@ fn iter_test(ser_method_int: i32) { // verify all 5 keys were seen assert_eq!(keys_seen.iter().filter(|&t| *t).count(), 5); } + +#[rstest_parametrize(ser_method_int, case(0), case(1), case(2), case(3))] +fn basic_set_get_load_or_new(ser_method_int: i32) { + test_setup!("basic_set_get_load_or_new", ser_method_int, db_name); + + let mut db = PickleDb::load_or_new( + &db_name, + PickleDbDumpPolicy::AutoDump, + ser_method!(ser_method_int), + ); + + // set a number + let num = 100; + db.set("num", &num).unwrap(); + + // set a floating point number + let float_num = 1.224; + db.set("float", &float_num).unwrap(); + + // set a String + let mystr = String::from("my string"); + db.set("string", &mystr).unwrap(); + + // set a Vec + let myvec = vec![1, 2, 3]; + db.set("vec", &myvec).unwrap(); + + // set a struct + #[derive(Serialize, Deserialize, Debug)] + struct Coor { + x: i32, + y: i32, + } + let mycoor = Coor { x: 1, y: 2 }; + db.set("struct", &mycoor).unwrap(); + + // read a num + assert_eq!(db.get::("num").unwrap(), num); + // read a floating point number + assert_eq!(db.get::("float").unwrap(), float_num); + // read a String + assert_eq!(db.get::("string").unwrap(), mystr); + // read a Vec + assert_eq!(db.get::>("vec").unwrap(), myvec); + // read a struct + assert_eq!(db.get::("struct").unwrap().x, mycoor.x); + assert_eq!(db.get::("struct").unwrap().y, mycoor.y); +} + +#[rstest_parametrize(ser_method_int, case(0), case(1), case(2), case(3))] +fn load_or_new(ser_method_int: i32) { + test_setup!("load_or_new", ser_method_int, db_name); + + let mut db = PickleDb::new( + &db_name, + PickleDbDumpPolicy::AutoDump, + ser_method!(ser_method_int), + ); + + // set a number + let num = 100; + db.set("num", &num).unwrap(); + + // set a floating point number + let float_num = 1.224; + db.set("float", &float_num).unwrap(); + + // set a String + let mystr = String::from("my string"); + db.set("string", &mystr).unwrap(); + + // set a Vec + let myvec = vec![1, 2, 3]; + db.set("vec", &myvec).unwrap(); + + // set a struct + #[derive(Serialize, Deserialize, Debug)] + struct Coor { + x: i32, + y: i32, + } + let mycoor = Coor { x: 1, y: 2 }; + db.set("struct", &mycoor).unwrap(); + + // read a num + assert_eq!(db.get::("num").unwrap(), num); + // read a floating point number + assert_eq!(db.get::("float").unwrap(), float_num); + // read a String + assert_eq!(db.get::("string").unwrap(), mystr); + // read a Vec + assert_eq!(db.get::>("vec").unwrap(), myvec); + // read a struct + assert_eq!(db.get::("struct").unwrap().x, mycoor.x); + assert_eq!(db.get::("struct").unwrap().y, mycoor.y); + + // drop database + drop(db); + + // create new database that should load from existing database + let db = PickleDb::load_or_new( + &db_name, + PickleDbDumpPolicy::AutoDump, + ser_method!(ser_method_int), + ); + + // assert data is identical to existing database + + // read a num + assert_eq!(db.get::("num").unwrap(), num); + // read a floating point number + assert_eq!(db.get::("float").unwrap(), float_num); + // read a String + assert_eq!(db.get::("string").unwrap(), mystr); + // read a Vec + assert_eq!(db.get::>("vec").unwrap(), myvec); + // read a struct + assert_eq!(db.get::("struct").unwrap().x, mycoor.x); + assert_eq!(db.get::("struct").unwrap().y, mycoor.y); +}