use native_db::*; use native_model::{native_model, Model}; use serde::{Deserialize, Serialize}; use shortcut_assert_fs::TmpFs; #[derive(Serialize, Deserialize, Eq, PartialEq, Clone, Debug)] #[native_model(id = 1, version = 1)] #[native_db( primary_key(pk -> String), secondary_key(gk_1 -> String, unique) )] struct Item { id: u32, name: String, } impl Item { pub fn pk(&self) -> String { format!("{}", self.id) } pub fn gk_1(&self) -> String { format!("{}-{}", self.name, self.id) } } #[test] fn upsert_get_read_write_transaction() { let tf = TmpFs::new().unwrap(); let item = Item { id: 1, name: "test".to_string(), }; let mut models = Models::new(); models.define::().unwrap(); let db = Builder::new() .create(&models, tf.path("test").as_std_path()) .unwrap(); let rw = db.rw_transaction().unwrap(); rw.upsert(item.clone()).unwrap(); rw.commit().unwrap(); let rw = db.rw_transaction().unwrap(); let result_item = rw .get() .secondary(ItemKey::gk_1, "test-1") .unwrap() .unwrap(); assert_eq!(item, result_item); rw.commit().unwrap(); } #[test] fn upsert_get_read_transaction() { let tf = TmpFs::new().unwrap(); let item = Item { id: 1, name: "test".to_string(), }; let mut models = Models::new(); models.define::().unwrap(); let db = Builder::new() .create(&models, tf.path("test").as_std_path()) .unwrap(); let rw = db.rw_transaction().unwrap(); rw.upsert(item.clone()).unwrap(); rw.commit().unwrap(); let r = db.r_transaction().unwrap(); let result_item = r.get().secondary(ItemKey::gk_1, "test-1").unwrap().unwrap(); assert_eq!(item, result_item); } #[derive(Serialize, Deserialize, Eq, PartialEq, Clone, Debug)] #[native_model(id = 1, version = 1)] #[native_db] struct ItemDuplicate { #[primary_key] id: u32, #[secondary_key(unique)] name: String, } #[test] fn test_upsert_duplicate_key() { let tf = TmpFs::new().unwrap(); let item_1 = ItemDuplicate { id: 1, name: "test".to_string(), }; let item_2 = ItemDuplicate { id: 2, name: "test".to_string(), }; let mut models = Models::new(); models.define::().unwrap(); let db = Builder::new() .create(&models, tf.path("test").as_std_path()) .unwrap(); let rw = db.rw_transaction().unwrap(); rw.upsert(item_1).unwrap(); let result = rw.upsert(item_2); assert!(result.is_err()); assert!(matches!( result.unwrap_err(), db_type::Error::DuplicateKey { .. } )); } #[test] fn upsert_get_update_secondary_key() { let item_1 = ItemDuplicate { id: 1, name: "test".to_string(), }; let mut models = Models::new(); models.define::().unwrap(); let db = Builder::new().create_in_memory(&models).unwrap(); let rw = db.rw_transaction().unwrap(); let _ = rw.upsert(item_1.clone()).unwrap(); rw.commit().unwrap(); // Stats let stats = db.redb_stats().unwrap(); assert_eq!(stats.primary_tables.len(), 1); assert_eq!(stats.primary_tables[0].name, "1_1_id"); assert_eq!(stats.primary_tables[0].n_entries, Some(1)); assert_eq!(stats.secondary_tables.len(), 1); assert_eq!(stats.secondary_tables[0].name, "1_1_name"); assert_eq!(stats.secondary_tables[0].n_entries, Some(1)); // Update the secondary key let rw = db.rw_transaction().unwrap(); let mut item: ItemDuplicate = rw.get().primary(1u32).unwrap().unwrap(); item.name = "test2".to_string(); rw.upsert(item).unwrap(); rw.commit().unwrap(); // Stats let stats = db.redb_stats().unwrap(); assert_eq!(stats.primary_tables.len(), 1); assert_eq!(stats.primary_tables[0].name, "1_1_id"); assert_eq!(stats.primary_tables[0].n_entries, Some(1)); assert_eq!(stats.secondary_tables.len(), 1); assert_eq!(stats.secondary_tables[0].name, "1_1_name"); assert_eq!(stats.secondary_tables[0].n_entries, Some(1)); } #[derive(Serialize, Deserialize, Eq, PartialEq, Clone, Debug)] #[native_model(id = 1, version = 1)] #[native_db] struct ItemOptional { #[primary_key] id: u32, #[secondary_key(unique, optional)] name: Option, } #[test] fn test_upsert_optional() { let tf = TmpFs::new().unwrap(); let item_1 = ItemOptional { id: 1, name: Some("test".to_string()), }; let item_2 = ItemOptional { id: 2, name: None }; let mut models = Models::new(); models.define::().unwrap(); let db = Builder::new() .create(&models, tf.path("test").as_std_path()) .unwrap(); let rw = db.rw_transaction().unwrap(); rw.upsert(item_1.clone()).unwrap(); rw.upsert(item_2.clone()).unwrap(); rw.commit().unwrap(); let stats = db.redb_stats().unwrap(); assert_eq!(stats.primary_tables.len(), 1); assert_eq!(stats.primary_tables[0].name, "1_1_id"); assert_eq!(stats.primary_tables[0].n_entries, Some(2)); assert_eq!(stats.secondary_tables.len(), 1); assert_eq!(stats.secondary_tables[0].name, "1_1_name"); assert_eq!(stats.secondary_tables[0].n_entries, Some(1)); let r = db.r_transaction().unwrap(); let result_item = r .get() .secondary(ItemOptionalKey::name, Some("test")) .unwrap() .unwrap(); assert_eq!(item_1, result_item); }