use derivative::Derivative; use entity::*; use entity_inmemory::InmemoryDatabase; #[test] fn id_should_return_copy_of_marked_id_field() { #[derive(Clone, Ent)] struct TestEnt { #[ent(id)] id: Id, #[ent(database)] database: WeakDatabaseRc, #[ent(created)] created: u64, #[ent(last_updated)] last_updated: u64, } let ent = TestEnt { id: 999, database: WeakDatabaseRc::new(), created: 0, last_updated: 0, }; assert_eq!(ent.id(), 999); } #[test] fn set_id_should_update_the_marked_id_field() { #[derive(Clone, Ent)] struct TestEnt { #[ent(id)] id: Id, #[ent(database)] database: WeakDatabaseRc, #[ent(created)] created: u64, #[ent(last_updated)] last_updated: u64, } let mut ent = TestEnt { id: 999, database: WeakDatabaseRc::new(), created: 0, last_updated: 0, }; ent.set_id(123); assert_eq!(ent.id, 123); } #[test] fn r#type_should_return_a_generated_type_using_module_path_and_ent_name() { #[derive(Clone, Ent)] struct TestEnt { #[ent(id)] id: Id, #[ent(database)] database: WeakDatabaseRc, #[ent(created)] created: u64, #[ent(last_updated)] last_updated: u64, } let ent = TestEnt { id: 999, database: WeakDatabaseRc::new(), created: 0, last_updated: 0, }; assert_eq!(ent.r#type(), concat!(module_path!(), "::", "TestEnt")); } #[test] fn created_should_return_copy_of_marked_created_field() { #[derive(Clone, Ent)] struct TestEnt { #[ent(id)] id: Id, #[ent(database)] database: WeakDatabaseRc, #[ent(created)] created: u64, #[ent(last_updated)] last_updated: u64, } let ent = TestEnt { id: EPHEMERAL_ID, database: WeakDatabaseRc::new(), created: 999, last_updated: 0, }; assert_eq!(ent.created(), 999); } #[test] fn last_updated_should_return_copy_of_marked_last_updated_field() { #[derive(Clone, Ent)] struct TestEnt { #[ent(id)] id: Id, #[ent(database)] database: WeakDatabaseRc, #[ent(created)] created: u64, #[ent(last_updated)] last_updated: u64, } let ent = TestEnt { id: EPHEMERAL_ID, database: WeakDatabaseRc::new(), created: 0, last_updated: 999, }; assert_eq!(ent.last_updated(), 999); } #[test] fn field_definitions_should_return_list_of_definitions_for_ent_fields() { #[derive(Clone, ValueLike, IntoValue)] struct CustomValue; #[derive(Clone, Ent)] struct TestEnt { #[ent(id)] id: Id, #[ent(database)] database: WeakDatabaseRc, #[ent(created)] created: u64, #[ent(last_updated)] last_updated: u64, #[ent(field)] a: u32, #[ent(field(indexed))] b: String, #[ent(field(mutable))] c: char, #[ent(field(indexed, mutable))] d: bool, #[ent(field)] e: CustomValue, #[ent(field(computed = "123"))] f: Option, } let ent = TestEnt { id: EPHEMERAL_ID, database: WeakDatabaseRc::new(), created: 0, last_updated: 0, a: 123, b: String::from("test"), c: 'z', d: true, e: CustomValue, f: None, }; assert_eq!( ent.field_definitions(), vec![ FieldDefinition::new_with_attributes( "a", NumberType::U32, vec![FieldAttribute::Immutable] ), FieldDefinition::new_with_attributes( "b", ValueType::Text, vec![FieldAttribute::Indexed, FieldAttribute::Immutable] ), FieldDefinition::new_with_attributes("c", PrimitiveType::Char, vec![]), FieldDefinition::new_with_attributes( "d", PrimitiveType::Bool, vec![FieldAttribute::Indexed] ), FieldDefinition::new_with_attributes( "e", ValueType::Custom, vec![FieldAttribute::Immutable] ), FieldDefinition::new_with_attributes( "f", ValueType::Optional(Box::new(ValueType::Primitive(PrimitiveType::Number( NumberType::U32 )))), vec![FieldAttribute::Computed, FieldAttribute::Immutable], ), ] ); } #[test] fn field_should_return_abstract_value_if_exists() { #[derive(Clone, Debug, ValueLike, IntoValue)] struct CustomValue; #[derive(Clone, Ent)] struct TestEnt { #[ent(id)] id: Id, #[ent(database)] database: WeakDatabaseRc, #[ent(created)] created: u64, #[ent(last_updated)] last_updated: u64, #[ent(field)] a: u32, #[ent(field(indexed))] b: String, #[ent(field(mutable))] c: char, #[ent(field(indexed, mutable))] d: bool, #[ent(field)] e: CustomValue, } let ent = TestEnt { id: EPHEMERAL_ID, database: WeakDatabaseRc::new(), created: 0, last_updated: 0, a: 123, b: String::from("test"), c: 'z', d: true, e: CustomValue, }; assert_eq!(ent.field("a"), Some(Value::from(123u32))); assert_eq!(ent.field("b"), Some(Value::from("test"))); assert_eq!(ent.field("c"), Some(Value::from('z'))); assert_eq!(ent.field("d"), Some(Value::from(true))); assert_eq!(ent.field("e"), Some(Value::from(CustomValue))); assert_eq!(ent.field("f"), None); } #[test] fn field_should_return_computed_value_if_field_marked_as_such() { #[derive(Clone, Ent)] struct TestEnt { #[ent(id)] id: Id, #[ent(database)] database: WeakDatabaseRc, #[ent(created)] created: u64, #[ent(last_updated)] last_updated: u64, #[ent(field(computed = "123"))] computed_field: Option, } let ent = TestEnt { id: EPHEMERAL_ID, database: WeakDatabaseRc::new(), created: 0, last_updated: 0, computed_field: None, }; assert_eq!(ent.field("computed_field"), Some(Value::from(123u32))); } #[test] fn update_field_should_change_the_field_with_given_name_if_it_exists_to_value() { #[derive(Clone, Debug, PartialEq, Eq, ValueLike, IntoValue)] struct CustomValue(usize); #[derive(Clone, Ent)] struct TestEnt { #[ent(id)] id: Id, #[ent(database)] database: WeakDatabaseRc, #[ent(created)] created: u64, #[ent(last_updated)] last_updated: u64, #[ent(field(mutable))] a: u32, #[ent(field(mutable))] b: String, #[ent(field(mutable))] c: char, #[ent(field(mutable))] d: bool, #[ent(field(mutable))] e: CustomValue, // Will fail with immutable error #[ent(field)] f: Option, // Will fail with immutable error #[ent(field(indexed))] g: Option, // Will fail with computed error #[ent(field(computed = "'c'"))] h: Option, } let mut ent = TestEnt { id: EPHEMERAL_ID, database: WeakDatabaseRc::new(), created: 0, last_updated: 0, a: 123, b: String::from("test"), c: 'z', d: true, e: CustomValue(123), f: None, g: None, h: None, }; assert_eq!( ent.update_field("a", Value::from(234u32)).unwrap(), Value::from(123u32) ); assert_eq!(ent.a, 234); assert_eq!( ent.update_field("b", Value::from("newtest")).unwrap(), Value::from("test") ); assert_eq!(ent.b, "newtest"); assert_eq!( ent.update_field("c", Value::from('$')).unwrap(), Value::from('z') ); assert_eq!(ent.c, '$'); assert_eq!( ent.update_field("d", Value::from(false)).unwrap(), Value::from(true) ); assert_eq!(ent.d, false); assert_eq!( ent.update_field("e", Value::from(CustomValue(234))) .unwrap(), Value::from(CustomValue(123)) ); assert_eq!(ent.e, CustomValue(234)); assert!(matches!( ent.update_field("id", Value::from(999usize)).unwrap_err(), EntMutationError::NoField { .. } )); assert!(matches!( ent.update_field("a", Value::from("test")).unwrap_err(), EntMutationError::WrongValueType { .. } )); assert!(matches!( ent.update_field("f", Value::from(Some(123u32))) .unwrap_err(), EntMutationError::FieldImmutable { .. } )); assert!(matches!( ent.update_field("g", Value::from(Some(String::from("test")))) .unwrap_err(), EntMutationError::FieldImmutable { .. } )); assert!(matches!( ent.update_field("h", Value::from(Some('c'))).unwrap_err(), EntMutationError::FieldComputed { .. } )); } #[test] fn update_field_should_fail_if_field_not_marked_mutable() { #[derive(Clone, Ent)] struct TestEnt { #[ent(id)] id: Id, #[ent(database)] database: WeakDatabaseRc, #[ent(created)] created: u64, #[ent(last_updated)] last_updated: u64, #[ent(field)] immutable_field: u32, } let mut ent = TestEnt { id: EPHEMERAL_ID, database: WeakDatabaseRc::new(), created: 0, last_updated: 0, immutable_field: 123, }; let result = ent.update_field("immutable_field", Value::from(456u32)); assert!( result.is_err(), "Update of immutable field unexpectedly succeeded" ); assert_eq!(ent.field("immutable_field"), Some(Value::from(123u32))); } #[test] fn update_field_should_fail_if_field_marked_computed() { #[derive(Clone, Ent)] struct TestEnt { #[ent(id)] id: Id, #[ent(database)] database: WeakDatabaseRc, #[ent(created)] created: u64, #[ent(last_updated)] last_updated: u64, #[ent(field(computed = "123"))] computed_field: Option, } let mut ent = TestEnt { id: EPHEMERAL_ID, database: WeakDatabaseRc::new(), created: 0, last_updated: 0, computed_field: None, }; let result = ent.update_field("computed_field", Value::from(456u32)); assert!( result.is_err(), "Update of computed field unexpectedly succeeded" ); assert_eq!(ent.field("computed_field"), Some(Value::from(123u32))); } #[test] fn edge_definitions_should_return_list_of_definitions_for_ent_edges() { #[derive(Clone, Ent)] struct TestEnt { #[ent(id)] id: Id, #[ent(database)] database: WeakDatabaseRc, #[ent(created)] created: u64, #[ent(last_updated)] last_updated: u64, #[ent(edge(type = "TestEnt"))] a: Option, #[ent(edge(policy = "shallow", type = "TestEnt"))] b: Option, #[ent(edge(policy = "deep", type = "TestEnt"))] c: Option, #[ent(edge(policy = "nothing", type = "TestEnt"))] d: Option, #[ent(edge(type = "TestEnt"))] e: Id, #[ent(edge(policy = "shallow", type = "TestEnt"))] f: Id, #[ent(edge(policy = "deep", type = "TestEnt"))] g: Id, #[ent(edge(policy = "nothing", type = "TestEnt"))] h: Id, #[ent(edge(type = "TestEnt"))] i: Vec, #[ent(edge(policy = "shallow", type = "TestEnt"))] j: Vec, #[ent(edge(policy = "deep", type = "TestEnt"))] k: Vec, #[ent(edge(policy = "nothing", type = "TestEnt"))] l: Vec, } let ent = TestEnt { id: EPHEMERAL_ID, database: WeakDatabaseRc::new(), created: 0, last_updated: 0, a: None, b: None, c: None, d: None, e: 0, f: 0, g: 0, h: 0, i: vec![0], j: vec![0], k: vec![0], l: vec![0], }; assert_eq!( ent.edge_definitions(), vec![ EdgeDefinition::new_with_deletion_policy( "a", EdgeValueType::MaybeOne, EdgeDeletionPolicy::Nothing ), EdgeDefinition::new_with_deletion_policy( "b", EdgeValueType::MaybeOne, EdgeDeletionPolicy::ShallowDelete ), EdgeDefinition::new_with_deletion_policy( "c", EdgeValueType::MaybeOne, EdgeDeletionPolicy::DeepDelete ), EdgeDefinition::new_with_deletion_policy( "d", EdgeValueType::MaybeOne, EdgeDeletionPolicy::Nothing ), EdgeDefinition::new_with_deletion_policy( "e", EdgeValueType::One, EdgeDeletionPolicy::Nothing ), EdgeDefinition::new_with_deletion_policy( "f", EdgeValueType::One, EdgeDeletionPolicy::ShallowDelete ), EdgeDefinition::new_with_deletion_policy( "g", EdgeValueType::One, EdgeDeletionPolicy::DeepDelete ), EdgeDefinition::new_with_deletion_policy( "h", EdgeValueType::One, EdgeDeletionPolicy::Nothing ), EdgeDefinition::new_with_deletion_policy( "i", EdgeValueType::Many, EdgeDeletionPolicy::Nothing ), EdgeDefinition::new_with_deletion_policy( "j", EdgeValueType::Many, EdgeDeletionPolicy::ShallowDelete ), EdgeDefinition::new_with_deletion_policy( "k", EdgeValueType::Many, EdgeDeletionPolicy::DeepDelete ), EdgeDefinition::new_with_deletion_policy( "l", EdgeValueType::Many, EdgeDeletionPolicy::Nothing ), ] ); } #[test] fn edge_should_return_abstract_value_if_exists() { #[derive(Clone, Ent)] struct TestEnt { #[ent(id)] id: Id, #[ent(database)] database: WeakDatabaseRc, #[ent(created)] created: u64, #[ent(last_updated)] last_updated: u64, #[ent(edge(type = "TestEnt"))] a: Option, #[ent(edge(type = "TestEnt"))] b: Option, #[ent(edge(type = "TestEnt"))] c: Id, #[ent(edge(type = "TestEnt"))] d: Vec, } let ent = TestEnt { id: EPHEMERAL_ID, database: WeakDatabaseRc::new(), created: 0, last_updated: 0, a: None, b: Some(3), c: 999, d: vec![1, 2, 3], }; assert_eq!(ent.edge("a"), Some(EdgeValue::from(None))); assert_eq!(ent.edge("b"), Some(EdgeValue::from(Some(3)))); assert_eq!(ent.edge("c"), Some(EdgeValue::from(999))); assert_eq!(ent.edge("d"), Some(EdgeValue::from(vec![1, 2, 3]))); assert_eq!(ent.edge("e"), None); } #[test] fn update_edge_should_change_the_edge_with_given_name_if_it_exists_to_value() { #[derive(Clone, Ent)] struct TestEnt { #[ent(id)] id: Id, #[ent(database)] database: WeakDatabaseRc, #[ent(created)] created: u64, #[ent(last_updated)] last_updated: u64, #[ent(edge(type = "TestEnt"))] a: Option, #[ent(edge(type = "TestEnt"))] b: Option, #[ent(edge(type = "TestEnt"))] c: Id, #[ent(edge(type = "TestEnt"))] d: Vec, } let mut ent = TestEnt { id: EPHEMERAL_ID, database: WeakDatabaseRc::new(), created: 0, last_updated: 0, a: None, b: Some(3), c: 999, d: vec![1, 2, 3], }; assert_eq!( ent.update_edge("a", EdgeValue::from(Some(123))).unwrap(), EdgeValue::from(None) ); assert_eq!(ent.a, Some(123)); assert_eq!( ent.update_edge("b", EdgeValue::from(None)).unwrap(), EdgeValue::from(Some(3)) ); assert_eq!(ent.b, None); assert_eq!( ent.update_edge("c", EdgeValue::from(123)).unwrap(), EdgeValue::from(999) ); assert_eq!(ent.c, 123); assert_eq!( ent.update_edge("d", EdgeValue::from(vec![4, 5])).unwrap(), EdgeValue::from(vec![1, 2, 3]) ); assert_eq!(ent.d, vec![4, 5]); assert!(matches!( ent.update_edge("e", EdgeValue::from(123)).unwrap_err(), EntMutationError::NoEdge { .. } )); assert!(matches!( ent.update_edge("a", EdgeValue::from(123)).unwrap_err(), EntMutationError::WrongEdgeValueType { .. } )); } #[test] fn connect_should_replace_database_with_provided_one() { #[derive(Clone, Ent)] struct TestEnt { #[ent(id)] id: Id, #[ent(database)] database: WeakDatabaseRc, #[ent(created)] created: u64, #[ent(last_updated)] last_updated: u64, } let mut ent = TestEnt { id: 999, database: WeakDatabaseRc::new(), created: 0, last_updated: 0, }; let database = DatabaseRc::new(Box::new(InmemoryDatabase::default())); ent.connect(DatabaseRc::downgrade(&database)); assert!(!WeakDatabaseRc::ptr_eq( &ent.database, &WeakDatabaseRc::new() )); } #[test] fn disconnect_should_remove_any_associated_database() { #[derive(Clone, Ent)] struct TestEnt { #[ent(id)] id: Id, #[ent(database)] database: WeakDatabaseRc, #[ent(created)] created: u64, #[ent(last_updated)] last_updated: u64, } let db = DatabaseRc::new(Box::from(InmemoryDatabase::default())); let mut ent = TestEnt { id: 999, database: DatabaseRc::downgrade(&db), created: 0, last_updated: 0, }; ent.disconnect(); assert!(WeakDatabaseRc::ptr_eq( &ent.database, &WeakDatabaseRc::new() )); } #[test] fn is_connected_should_return_true_if_database_is_contained_within_ent() { #[derive(Clone, Ent)] struct TestEnt { #[ent(id)] id: Id, #[ent(database)] database: WeakDatabaseRc, #[ent(created)] created: u64, #[ent(last_updated)] last_updated: u64, } let mut ent = TestEnt { id: 999, database: WeakDatabaseRc::new(), created: 0, last_updated: 0, }; let db = DatabaseRc::new(Box::from(InmemoryDatabase::default())); assert_eq!(ent.is_connected(), false); ent.database = DatabaseRc::downgrade(&db); assert_eq!(ent.is_connected(), true); } #[test] fn load_edge_should_return_new_copy_of_ents_pointed_to_by_ids() { #[derive(Clone, Derivative, Ent)] #[derivative(Debug, PartialEq, Eq)] struct TestEnt { #[ent(id)] id: Id, #[derivative(Debug = "ignore")] #[derivative(PartialEq = "ignore")] #[ent(database)] database: WeakDatabaseRc, #[ent(created)] created: u64, #[derivative(PartialEq = "ignore")] #[ent(last_updated)] last_updated: u64, #[ent(edge(type = "TestEnt"))] parent: Option, #[ent(edge(type = "TestEnt"))] favorite: Id, #[ent(edge(type = "TestEnt"))] children: Vec, #[ent(field)] value: String, } let database = DatabaseRc::new(Box::from(InmemoryDatabase::default())); let mut ent1 = TestEnt { id: 1, database: WeakDatabaseRc::new(), created: 0, last_updated: 0, parent: None, favorite: 2, children: vec![2, 3], value: String::from("ent1"), }; let mut ent2 = TestEnt { id: 2, database: WeakDatabaseRc::new(), created: 0, last_updated: 0, parent: Some(1), favorite: 3, children: vec![], value: String::from("ent2"), }; let mut ent3 = TestEnt { id: 3, database: WeakDatabaseRc::new(), created: 0, last_updated: 0, parent: Some(1), favorite: 1, children: vec![], value: String::from("ent3"), }; assert!(matches!( ent1.load_edge("parent"), Err(DatabaseError::Disconnected) )); assert!(matches!( ent1.load_edge("favorite"), Err(DatabaseError::Disconnected) )); assert!(matches!( ent1.load_edge("children"), Err(DatabaseError::Disconnected) )); assert!(matches!( ent1.load_edge("something"), Err(DatabaseError::Disconnected) )); ent1.connect(DatabaseRc::downgrade(&database)); ent2.connect(DatabaseRc::downgrade(&database)); ent3.connect(DatabaseRc::downgrade(&database)); ent1.commit().expect("Failed to save Ent1"); ent2.commit().expect("Failed to save Ent2"); ent3.commit().expect("Failed to save Ent3"); let children = ent1 .load_edge("children") .expect("Failed to load ent1 children"); assert_eq!( children .iter() .map(|ent| ent.as_ent::().expect("Could not cast to TestEnt")) .collect::>(), vec![&ent2, &ent3], ); let parent = ent2 .load_edge("parent") .expect("Failed to load ent2 parent"); assert_eq!( parent .iter() .map(|ent| ent.as_ent::().expect("Could not cast to TestEnt")) .collect::>(), vec![&ent1], ); let favorite = ent3 .load_edge("favorite") .expect("Failed to load ent3 favorite"); assert_eq!( favorite .iter() .map(|ent| ent.as_ent::().expect("Could not cast to TestEnt")) .collect::>(), vec![&ent1], ); assert!(matches!( ent1.load_edge("something"), Err(DatabaseError::MissingEdge { .. }) )); } #[test] fn clear_cache_should_clear_all_computed_field_caches() { #[derive(Clone, Ent)] struct TestEnt { #[ent(id)] id: Id, #[ent(database)] database: WeakDatabaseRc, #[ent(created)] created: u64, #[ent(last_updated)] last_updated: u64, #[ent(field)] not_cache_field: Option, #[ent(field(computed = "123"))] cached_field1: Option, #[ent(field(computed = "456"))] cached_field2: Option, } let mut ent = TestEnt { id: 999, database: WeakDatabaseRc::new(), created: 0, last_updated: 0, not_cache_field: None, cached_field1: None, cached_field2: None, }; ent.not_cache_field = Some(999); ent.cached_field1 = Some(123); ent.clear_cache(); assert_eq!(ent.not_cache_field, Some(999)); assert_eq!(ent.cached_field1, None); assert_eq!(ent.cached_field2, None); } #[test] fn refresh_should_update_ent_inplace_with_database_value() { #[derive(Clone, Derivative, Ent)] #[derivative(Debug, PartialEq, Eq)] struct TestEnt { #[ent(id)] id: Id, #[derivative(Debug = "ignore")] #[derivative(PartialEq = "ignore")] #[ent(database)] database: WeakDatabaseRc, #[ent(created)] created: u64, #[derivative(PartialEq = "ignore")] #[ent(last_updated)] last_updated: u64, #[ent(field)] value: String, } let database = InmemoryDatabase::default(); let mut ent = TestEnt { id: 999, database: WeakDatabaseRc::new(), created: 0, last_updated: 0, value: String::from("test"), }; assert!(matches!(ent.refresh(), Err(DatabaseError::Disconnected))); // Insert ent with same id that has some different values database .insert(Box::from(TestEnt { id: 999, database: WeakDatabaseRc::new(), created: 3, // NOTE: This will get replaced by the database last_updated: 0, value: String::from("different"), })) .expect("Failed to add ent to database"); let database = DatabaseRc::new(Box::new(database)); ent.connect(DatabaseRc::downgrade(&database)); ent.refresh().expect("Failed to refresh ent"); assert_eq!(ent.id, 999); assert!( !WeakDatabaseRc::ptr_eq(&ent.database, &WeakDatabaseRc::new()), "Non-assigned weak database ref found" ); assert_eq!(ent.created, 3); assert!(ent.last_updated > 0); assert_eq!(ent.value, "different"); } #[test] fn commit_should_save_ent_to_database_and_update_id_if_it_was_changed() { #[derive(Clone, Derivative, Ent)] #[derivative(Debug, PartialEq, Eq)] struct TestEnt { #[ent(id)] id: Id, #[derivative(Debug = "ignore")] #[derivative(PartialEq = "ignore")] #[ent(database)] database: WeakDatabaseRc, #[ent(created)] created: u64, #[derivative(PartialEq = "ignore")] #[ent(last_updated)] last_updated: u64, } let database = InmemoryDatabase::default(); let mut ent = TestEnt { id: EPHEMERAL_ID, database: WeakDatabaseRc::new(), created: 0, last_updated: 0, }; assert!(matches!(ent.commit(), Err(DatabaseError::Disconnected))); let database = DatabaseRc::new(Box::new(database)); ent.connect(DatabaseRc::downgrade(&database)); ent.commit().expect("Failed to commit ent"); assert_ne!(ent.id, EPHEMERAL_ID, "Ephemeral id was not changed in ent"); assert_eq!( database .get(ent.id) .expect("Unexpected database error") .is_some(), true, ); } #[test] fn remove_should_delete_ent_from_database() { #[derive(Clone, Derivative, Ent)] #[derivative(Debug, PartialEq, Eq)] struct TestEnt { #[ent(id)] id: Id, #[derivative(Debug = "ignore")] #[derivative(PartialEq = "ignore")] #[ent(database)] database: WeakDatabaseRc, #[ent(created)] created: u64, #[derivative(PartialEq = "ignore")] #[ent(last_updated)] last_updated: u64, } let database = InmemoryDatabase::default(); let mut ent = TestEnt { id: 999, database: WeakDatabaseRc::new(), created: 0, last_updated: 0, }; assert!(matches!(ent.remove(), Err(DatabaseError::Disconnected))); let database = DatabaseRc::new(Box::new(database)); ent.connect(DatabaseRc::downgrade(&database)); assert_eq!(ent.remove().expect("Failed to remove ent"), false); assert_eq!( database.get(999).expect("Failed to get ent").is_none(), true, "Ent unexpectedly in database", ); ent.commit().expect("Failed to insert ent into database"); assert_eq!( database.get(999).expect("Failed to get ent").is_some(), true, "Ent unexpectedly not in database", ); assert_eq!(ent.remove().expect("Failed to remove ent"), true); assert_eq!( database.get(999).expect("Failed to get ent").is_none(), true, "Ent unexpectedly in database", ); } #[test] fn supports_all_std_collection_list_types_for_edge_ids() { use std::collections::*; #[derive(Clone, Ent)] struct TestEnt { #[ent(id)] id: Id, #[ent(database)] database: WeakDatabaseRc, #[ent(created)] created: u64, #[ent(last_updated)] last_updated: u64, #[ent(edge(type = "TestEnt"))] a: Vec, #[ent(edge(type = "TestEnt"))] b: VecDeque, #[ent(edge(type = "TestEnt"))] c: LinkedList, #[ent(edge(type = "TestEnt"))] d: BinaryHeap, #[ent(edge(type = "TestEnt"))] e: HashSet, #[ent(edge(type = "TestEnt"))] f: BTreeSet, } let ent = TestEnt { id: 999, database: WeakDatabaseRc::new(), created: 123, last_updated: 456, a: Vec::new(), b: VecDeque::new(), c: LinkedList::new(), d: BinaryHeap::new(), e: HashSet::new(), f: BTreeSet::new(), }; assert_eq!(ent.edge_type("a").unwrap(), EdgeValueType::Many); assert_eq!(ent.edge_type("b").unwrap(), EdgeValueType::Many); assert_eq!(ent.edge_type("c").unwrap(), EdgeValueType::Many); assert_eq!(ent.edge_type("d").unwrap(), EdgeValueType::Many); assert_eq!(ent.edge_type("e").unwrap(), EdgeValueType::Many); assert_eq!(ent.edge_type("f").unwrap(), EdgeValueType::Many); } #[test] fn supports_generic_fields() { #![allow(clippy::float_cmp)] #[derive(Clone, Ent)] struct TestEnt where T: ValueLike + Clone + Send + Sync + 'static, { #[ent(id)] id: Id, #[ent(database)] database: WeakDatabaseRc, #[ent(created)] created: u64, #[ent(last_updated)] last_updated: u64, #[ent(field)] generic_field: T, } let ent = TestEnt { id: 999, database: WeakDatabaseRc::new(), created: 123, last_updated: 456, generic_field: 0.5, }; assert_eq!(ent.field_type("generic_field").unwrap(), ValueType::Custom); assert_eq!(ent.generic_field, 0.5); } #[test] fn supports_os_string_field() { use std::ffi::OsString; #[derive(Clone, Ent)] struct TestEnt { #[ent(id)] id: Id, #[ent(database)] database: WeakDatabaseRc, #[ent(created)] created: u64, #[ent(last_updated)] last_updated: u64, #[ent(field)] a: OsString, } let ent = TestEnt { id: 999, database: WeakDatabaseRc::new(), created: 123, last_updated: 456, a: OsString::from("test"), }; assert_eq!(ent.field_type("a").unwrap(), ValueType::Text); assert_eq!(ent.a, "test"); } #[test] fn supports_pathbuf_field() { use std::path::PathBuf; #[derive(Clone, Ent)] struct TestEnt { #[ent(id)] id: Id, #[ent(database)] database: WeakDatabaseRc, #[ent(created)] created: u64, #[ent(last_updated)] last_updated: u64, #[ent(field)] a: PathBuf, } let ent = TestEnt { id: 999, database: WeakDatabaseRc::new(), created: 123, last_updated: 456, a: PathBuf::from("test"), }; assert_eq!(ent.field_type("a").unwrap(), ValueType::Text); assert_eq!(ent.a.as_os_str(), "test"); } #[test] fn supports_all_std_collection_types_for_fields() { use std::collections::*; #[derive(Clone, Ent)] struct TestEnt { #[ent(id)] id: Id, #[ent(database)] database: WeakDatabaseRc, #[ent(created)] created: u64, #[ent(last_updated)] last_updated: u64, #[ent(field)] a: Vec, #[ent(field)] b: VecDeque, #[ent(field)] c: LinkedList, #[ent(field)] d: BinaryHeap, #[ent(field)] e: HashSet, #[ent(field)] f: BTreeSet, #[ent(field)] g: HashMap, #[ent(field)] h: BTreeMap, } let ent = TestEnt { id: 999, database: WeakDatabaseRc::new(), created: 123, last_updated: 456, a: Vec::new(), b: VecDeque::new(), c: LinkedList::new(), d: BinaryHeap::new(), e: HashSet::new(), f: BTreeSet::new(), g: HashMap::new(), h: BTreeMap::new(), }; assert_eq!( ent.field_type("a").unwrap(), ValueType::List(Box::new(ValueType::Text)), ); assert_eq!( ent.field_type("b").unwrap(), ValueType::List(Box::new(ValueType::Text)), ); assert_eq!( ent.field_type("c").unwrap(), ValueType::List(Box::new(ValueType::Text)), ); assert_eq!( ent.field_type("d").unwrap(), ValueType::List(Box::new(ValueType::Text)), ); assert_eq!( ent.field_type("e").unwrap(), ValueType::List(Box::new(ValueType::Text)), ); assert_eq!( ent.field_type("f").unwrap(), ValueType::List(Box::new(ValueType::Text)), ); assert_eq!( ent.field_type("g").unwrap(), ValueType::Map(Box::new(ValueType::Text)), ); assert_eq!( ent.field_type("h").unwrap(), ValueType::Map(Box::new(ValueType::Text)), ); } #[test] fn supports_option_as_field_type() { #[derive(Clone, Ent)] struct TestEnt { #[ent(id)] id: Id, #[ent(database)] database: WeakDatabaseRc, #[ent(created)] created: u64, #[ent(last_updated)] last_updated: u64, #[ent(field)] field: Option, } let ent = TestEnt { id: 999, database: WeakDatabaseRc::new(), created: 123, last_updated: 456, field: Default::default(), }; assert_eq!( ent.field_type("field").unwrap(), ValueType::Optional(Box::new(ValueType::Text)), ); } #[test] fn supports_bool_as_field_type() { #[derive(Clone, Ent)] struct TestEnt { #[ent(id)] id: Id, #[ent(database)] database: WeakDatabaseRc, #[ent(created)] created: u64, #[ent(last_updated)] last_updated: u64, #[ent(field)] field: bool, } let ent = TestEnt { id: 999, database: WeakDatabaseRc::new(), created: 123, last_updated: 456, field: Default::default(), }; assert_eq!( ent.field_type("field").unwrap(), ValueType::Primitive(PrimitiveType::Bool), ); } #[test] fn supports_char_as_field_type() { #[derive(Clone, Ent)] struct TestEnt { #[ent(id)] id: Id, #[ent(database)] database: WeakDatabaseRc, #[ent(created)] created: u64, #[ent(last_updated)] last_updated: u64, #[ent(field)] field: char, } let ent = TestEnt { id: 999, database: WeakDatabaseRc::new(), created: 123, last_updated: 456, field: Default::default(), }; assert_eq!( ent.field_type("field").unwrap(), ValueType::Primitive(PrimitiveType::Char), ); } #[test] fn supports_f32_as_field_type() { #[derive(Clone, Ent)] struct TestEnt { #[ent(id)] id: Id, #[ent(database)] database: WeakDatabaseRc, #[ent(created)] created: u64, #[ent(last_updated)] last_updated: u64, #[ent(field)] field: f32, } let ent = TestEnt { id: 999, database: WeakDatabaseRc::new(), created: 123, last_updated: 456, field: Default::default(), }; assert_eq!( ent.field_type("field").unwrap(), ValueType::Primitive(PrimitiveType::Number(NumberType::F32)), ); } #[test] fn supports_f64_as_field_type() { #[derive(Clone, Ent)] struct TestEnt { #[ent(id)] id: Id, #[ent(database)] database: WeakDatabaseRc, #[ent(created)] created: u64, #[ent(last_updated)] last_updated: u64, #[ent(field)] field: f64, } let ent = TestEnt { id: 999, database: WeakDatabaseRc::new(), created: 123, last_updated: 456, field: Default::default(), }; assert_eq!( ent.field_type("field").unwrap(), ValueType::Primitive(PrimitiveType::Number(NumberType::F64)), ); } #[test] fn supports_i8_as_field_type() { #[derive(Clone, Ent)] struct TestEnt { #[ent(id)] id: Id, #[ent(database)] database: WeakDatabaseRc, #[ent(created)] created: u64, #[ent(last_updated)] last_updated: u64, #[ent(field)] field: i8, } let ent = TestEnt { id: 999, database: WeakDatabaseRc::new(), created: 123, last_updated: 456, field: Default::default(), }; assert_eq!( ent.field_type("field").unwrap(), ValueType::Primitive(PrimitiveType::Number(NumberType::I8)), ); } #[test] fn supports_i16_as_field_type() { #[derive(Clone, Ent)] struct TestEnt { #[ent(id)] id: Id, #[ent(database)] database: WeakDatabaseRc, #[ent(created)] created: u64, #[ent(last_updated)] last_updated: u64, #[ent(field)] field: i16, } let ent = TestEnt { id: 999, database: WeakDatabaseRc::new(), created: 123, last_updated: 456, field: Default::default(), }; assert_eq!( ent.field_type("field").unwrap(), ValueType::Primitive(PrimitiveType::Number(NumberType::I16)), ); } #[test] fn supports_i32_as_field_type() { #[derive(Clone, Ent)] struct TestEnt { #[ent(id)] id: Id, #[ent(database)] database: WeakDatabaseRc, #[ent(created)] created: u64, #[ent(last_updated)] last_updated: u64, #[ent(field)] field: i32, } let ent = TestEnt { id: 999, database: WeakDatabaseRc::new(), created: 123, last_updated: 456, field: Default::default(), }; assert_eq!( ent.field_type("field").unwrap(), ValueType::Primitive(PrimitiveType::Number(NumberType::I32)), ); } #[test] fn supports_i64_as_field_type() { #[derive(Clone, Ent)] struct TestEnt { #[ent(id)] id: Id, #[ent(database)] database: WeakDatabaseRc, #[ent(created)] created: u64, #[ent(last_updated)] last_updated: u64, #[ent(field)] field: i64, } let ent = TestEnt { id: 999, database: WeakDatabaseRc::new(), created: 123, last_updated: 456, field: Default::default(), }; assert_eq!( ent.field_type("field").unwrap(), ValueType::Primitive(PrimitiveType::Number(NumberType::I64)), ); } #[test] fn supports_i128_as_field_type() { #[derive(Clone, Ent)] struct TestEnt { #[ent(id)] id: Id, #[ent(database)] database: WeakDatabaseRc, #[ent(created)] created: u64, #[ent(last_updated)] last_updated: u64, #[ent(field)] field: i128, } let ent = TestEnt { id: 999, database: WeakDatabaseRc::new(), created: 123, last_updated: 456, field: Default::default(), }; assert_eq!( ent.field_type("field").unwrap(), ValueType::Primitive(PrimitiveType::Number(NumberType::I128)), ); } #[test] fn supports_isize_as_field_type() { #[derive(Clone, Ent)] struct TestEnt { #[ent(id)] id: Id, #[ent(database)] database: WeakDatabaseRc, #[ent(created)] created: u64, #[ent(last_updated)] last_updated: u64, #[ent(field)] field: isize, } let ent = TestEnt { id: 999, database: WeakDatabaseRc::new(), created: 123, last_updated: 456, field: Default::default(), }; assert_eq!( ent.field_type("field").unwrap(), ValueType::Primitive(PrimitiveType::Number(NumberType::Isize)), ); } #[test] fn supports_u8_as_field_type() { #[derive(Clone, Ent)] struct TestEnt { #[ent(id)] id: Id, #[ent(database)] database: WeakDatabaseRc, #[ent(created)] created: u64, #[ent(last_updated)] last_updated: u64, #[ent(field)] field: u8, } let ent = TestEnt { id: 999, database: WeakDatabaseRc::new(), created: 123, last_updated: 456, field: Default::default(), }; assert_eq!( ent.field_type("field").unwrap(), ValueType::Primitive(PrimitiveType::Number(NumberType::U8)), ); } #[test] fn supports_u16_as_field_type() { #[derive(Clone, Ent)] struct TestEnt { #[ent(id)] id: Id, #[ent(database)] database: WeakDatabaseRc, #[ent(created)] created: u64, #[ent(last_updated)] last_updated: u64, #[ent(field)] field: u16, } let ent = TestEnt { id: 999, database: WeakDatabaseRc::new(), created: 123, last_updated: 456, field: Default::default(), }; assert_eq!( ent.field_type("field").unwrap(), ValueType::Primitive(PrimitiveType::Number(NumberType::U16)), ); } #[test] fn supports_u32_as_field_type() { #[derive(Clone, Ent)] struct TestEnt { #[ent(id)] id: Id, #[ent(database)] database: WeakDatabaseRc, #[ent(created)] created: u64, #[ent(last_updated)] last_updated: u64, #[ent(field)] field: u32, } let ent = TestEnt { id: 999, database: WeakDatabaseRc::new(), created: 123, last_updated: 456, field: Default::default(), }; assert_eq!( ent.field_type("field").unwrap(), ValueType::Primitive(PrimitiveType::Number(NumberType::U32)), ); } #[test] fn supports_u64_as_field_type() { #[derive(Clone, Ent)] struct TestEnt { #[ent(id)] id: Id, #[ent(database)] database: WeakDatabaseRc, #[ent(created)] created: u64, #[ent(last_updated)] last_updated: u64, #[ent(field)] field: u64, } let ent = TestEnt { id: 999, database: WeakDatabaseRc::new(), created: 123, last_updated: 456, field: Default::default(), }; assert_eq!( ent.field_type("field").unwrap(), ValueType::Primitive(PrimitiveType::Number(NumberType::U64)), ); } #[test] fn supports_u128_as_field_type() { #[derive(Clone, Ent)] struct TestEnt { #[ent(id)] id: Id, #[ent(database)] database: WeakDatabaseRc, #[ent(created)] created: u64, #[ent(last_updated)] last_updated: u64, #[ent(field)] field: u128, } let ent = TestEnt { id: 999, database: WeakDatabaseRc::new(), created: 123, last_updated: 456, field: Default::default(), }; assert_eq!( ent.field_type("field").unwrap(), ValueType::Primitive(PrimitiveType::Number(NumberType::U128)), ); } #[test] fn supports_usize_as_field_type() { #[derive(Clone, Ent)] struct TestEnt { #[ent(id)] id: Id, #[ent(database)] database: WeakDatabaseRc, #[ent(created)] created: u64, #[ent(last_updated)] last_updated: u64, #[ent(field)] field: usize, } let ent = TestEnt { id: 999, database: WeakDatabaseRc::new(), created: 123, last_updated: 456, field: Default::default(), }; assert_eq!( ent.field_type("field").unwrap(), ValueType::Primitive(PrimitiveType::Number(NumberType::Usize)), ); }