diff --git a/zomes/trust_atom/src/lib.rs b/zomes/trust_atom/src/lib.rs index d1895e5..d894196 100644 --- a/zomes/trust_atom/src/lib.rs +++ b/zomes/trust_atom/src/lib.rs @@ -86,6 +86,7 @@ pub fn query(input: QueryInput) -> ExternResult> { input.target, input.content_full, input.content_starts_with, + input.content_not_starts_with, input.value_starts_with, ) } @@ -96,6 +97,7 @@ pub fn query_mine(input: QueryMineInput) -> ExternResult> { input.target, input.content_full, input.content_starts_with, + input.content_not_starts_with, input.value_starts_with, ) } diff --git a/zomes/trust_atom/src/trust_atom.rs b/zomes/trust_atom/src/trust_atom.rs index e2c1624..05822b1 100644 --- a/zomes/trust_atom/src/trust_atom.rs +++ b/zomes/trust_atom/src/trust_atom.rs @@ -180,6 +180,7 @@ pub fn query_mine( target: Option, content_full: Option, content_starts_with: Option, + content_not_starts_with: Option, value_starts_with: Option, ) -> ExternResult> { let agent_address = AnyLinkableHash::from(agent_info()?.agent_initial_pubkey); @@ -189,6 +190,7 @@ pub fn query_mine( target, content_full, content_starts_with, + content_not_starts_with, value_starts_with, )?; @@ -204,6 +206,7 @@ pub fn query( target: Option, content_full: Option, content_starts_with: Option, + content_not_starts_with: Option, value_starts_with: Option, ) -> ExternResult> { let (link_direction, link_base) = match (source, target) { @@ -217,27 +220,56 @@ pub fn query( } }; + if let Some(content_not_starts_with_string) = content_not_starts_with { + if content_full.is_some() || content_starts_with.is_some() || value_starts_with.is_some() { + return Err(wasm_error!( + "Passing content_not_starts_with means content_full, content_starts_with, and value_starts_with must all be None" + )); + } + let links = get_links(link_base.clone(), LinkTypes::TrustAtom, None)?; + let trust_atoms = convert_links_to_trust_atoms(links, &link_direction, link_base)?; + let filtered_trust_atoms = trust_atoms + .into_iter() + .filter(|trust_atom| { + let content_option = trust_atom.content.clone(); + if let Some(content) = content_option { + if content.starts_with(content_not_starts_with_string.as_str()) { + return false; + } + } + true + }) + .collect(); + return Ok(filtered_trust_atoms); + } + let link_tag = match (content_full, content_starts_with, value_starts_with) { (Some(_content_full), Some(_content_starts_with), _) => { - return Err(wasm_error!("Only one of `content_full` or `content_starts_with` can be used")) - }, + return Err(wasm_error!( + "Only one of `content_full` or `content_starts_with` can be used" + )) + } (_, Some(_content_starts_with), Some(_value_starts_with)) => { return Err(wasm_error!( "Cannot use `value_starts_with` and `content_starts_with` arguments together; maybe try `content_full` instead?", - )) - }, + )); + } (Some(content_full), None, Some(value_starts_with)) => Some(create_link_tag( &link_direction, &[Some(content_full), Some(value_starts_with)], )), - (Some(content_full), None, None) => { - Some(create_link_tag_metal(&link_direction, vec![content_full, UNICODE_NUL_STR.to_string()])) - }, + (Some(content_full), None, None) => Some(create_link_tag_metal( + &link_direction, + vec![content_full, UNICODE_NUL_STR.to_string()], + )), (None, Some(content_starts_with), None) => Some(create_link_tag( &link_direction, &[Some(content_starts_with)], )), - (None, None, Some(value_starts_with)) => Some(create_link_tag(&link_direction, &[Some(value_starts_with)])), + (None, None, Some(value_starts_with)) => Some(create_link_tag( + &link_direction, + &[None, Some(value_starts_with)], + )), (None, None, None) => None, }; let links = get_links(link_base.clone(), LinkTypes::TrustAtom, link_tag)?; diff --git a/zomes/trust_atom/tests/trust_atom_tests.rs b/zomes/trust_atom/tests/trust_atom_tests.rs index 1c285e9..48b2033 100644 --- a/zomes/trust_atom/tests/trust_atom_tests.rs +++ b/zomes/trust_atom/tests/trust_atom_tests.rs @@ -302,6 +302,7 @@ pub async fn test_delete_trust_atom() { target: Some(target.clone()), content_full: None, content_starts_with: None, + content_not_starts_with: None, value_starts_with: None, }, ) @@ -320,6 +321,7 @@ pub async fn test_delete_trust_atom() { target: None, content_full: None, content_starts_with: None, + content_not_starts_with: None, value_starts_with: None, }, ) @@ -352,6 +354,7 @@ pub async fn test_delete_trust_atom() { target: Some(target.clone()), content_full: None, content_starts_with: None, + content_not_starts_with: None, value_starts_with: None, }, ) @@ -370,6 +373,7 @@ pub async fn test_delete_trust_atom() { target: None, content_full: None, content_starts_with: None, + content_not_starts_with: None, value_starts_with: None, }, ) @@ -420,6 +424,7 @@ pub async fn test_query_mine() { trust_atom_types::QueryMineInput { target: None, content_starts_with: None, + content_not_starts_with: None, content_full: None, value_starts_with: None, }, @@ -486,6 +491,7 @@ pub async fn test_query_mine_with_content_starts_with() { target: None, content_full: None, content_starts_with: Some("sushi".into()), + content_not_starts_with: None, value_starts_with: None, // value_starts_with: Some("0.0".into()), }, @@ -506,6 +512,82 @@ pub async fn test_query_mine_with_content_starts_with() { ); } +#[tokio::test(flavor = "multi_thread")] +pub async fn test_query_mine_with_content_not_starts_with() { + let (conductor, _agent, cell1) = setup_1_conductor().await; + + // CREATE TARGET ENTRY + + let target_hash: EntryHash = conductor + .call( + &cell1.zome("trust_atom"), + "create_string_target", + "Sushi Ran", + ) + .await; + + // CREATE TRUST ATOMS + + let contents = vec![ + "sushi", + "sushi __not joint", + "sush not__", + "__not_example", // should be matched + "__ starts", // should be matched + "reg_example", + ]; + + for content in contents { + let _result: trust_atom_types::TrustAtom = conductor + .call( + &cell1.zome("trust_atom"), + "create_trust_atom", + trust_atom_types::TrustAtomInput { + target: AnyLinkableHash::from(target_hash.clone()), + content: Some(content.into()), + value: Some("0.8".into()), + extra: Some(BTreeMap::new()), + }, + ) + .await; + } + // QUERY MY TRUST ATOMS + + let trust_atoms_from_query: Vec = conductor + .call( + &cell1.zome("trust_atom"), + "query_mine", + trust_atom_types::QueryMineInput { + target: None, + content_full: None, + content_starts_with: None, + content_not_starts_with: Some("__".into()), + value_starts_with: None, + }, + ) + .await; + + assert_eq!(trust_atoms_from_query.len(), 4); + + let mut actual = [ + trust_atoms_from_query[0].clone().content, + trust_atoms_from_query[1].clone().content, + trust_atoms_from_query[2].clone().content, + trust_atoms_from_query[3].clone().content, + ]; + actual.sort(); + + assert_eq!( + actual, + [ + Some("reg_example".to_string()), + Some("sush not__".to_string()), + Some("sushi".to_string()), + Some("sushi __not joint".to_string()), + ] + ); +} + #[tokio::test(flavor = "multi_thread")] pub async fn test_query_mine_with_content_full() { let (conductor, _agent, cell1): (SweetConductor, AgentPubKey, SweetCell) = @@ -539,6 +621,7 @@ pub async fn test_query_mine_with_content_full() { ) .await; } + // QUERY MY TRUST ATOMS let trust_atoms_from_query: Vec = conductor @@ -549,6 +632,7 @@ pub async fn test_query_mine_with_content_full() { target: None, content_full: Some("sushi".into()), content_starts_with: None, + content_not_starts_with: None, value_starts_with: None, // value_starts_with: Some("0.0".into()), }, @@ -563,6 +647,194 @@ pub async fn test_query_mine_with_content_full() { ); } +#[tokio::test(flavor = "multi_thread")] +pub async fn test_query_mine_with_content_full_and_value_starts_with() { + let (conductor, _agent, cell1) = setup_1_conductor().await; + + // CREATE TARGET ENTRY + + let target_hash: EntryHash = conductor + .call( + &cell1.zome("trust_atom"), + "create_string_target", + "Sushi Ran", + ) + .await; + + // CREATE TRUST ATOMS + + let _trust_atom_1: trust_atom_types::TrustAtom = conductor + .call( + &cell1.zome("trust_atom"), + "create_trust_atom", + trust_atom_types::TrustAtomInput { + target: AnyLinkableHash::from(target_hash.clone()), + content: None, + value: Some("0.88".into()), + extra: Some(BTreeMap::new()), + }, + ) + .await; + + let _trust_atom_2: trust_atom_types::TrustAtom = conductor + .call( + &cell1.zome("trust_atom"), + "create_trust_atom", + trust_atom_types::TrustAtomInput { + target: AnyLinkableHash::from(target_hash.clone()), + content: Some("sushi".into()), + value: Some("0.71".into()), + extra: Some(BTreeMap::new()), + }, + ) + .await; + + let _trust_atom_3: trust_atom_types::TrustAtom = conductor + .call( + &cell1.zome("trust_atom"), + "create_trust_atom", + trust_atom_types::TrustAtomInput { + target: AnyLinkableHash::from(target_hash.clone()), + content: Some("sushi".into()), + value: Some("0.7".into()), + extra: Some(BTreeMap::new()), + }, + ) + .await; + + // QUERY MY TRUST ATOMS + + let trust_atoms_from_query: Vec = conductor + .call( + &cell1.zome("trust_atom"), + "query_mine", + trust_atom_types::QueryMineInput { + target: None, + content_full: Some("sushi".into()), + content_starts_with: None, + content_not_starts_with: None, + value_starts_with: Some(".7".into()), + }, + ) + .await; + + assert_eq!(trust_atoms_from_query.len(), 2); + + let mut actual = [ + trust_atoms_from_query[0].clone().value, + trust_atoms_from_query[1].clone().value, + ]; + actual.sort(); + + assert_eq!( + actual, + [ + Some(".700000000".to_string()), + Some(".710000000".to_string()), + ] + ); +} + +#[tokio::test(flavor = "multi_thread")] +pub async fn test_query_mine_with_value_starts_with() { + let (conductor, _agent, cell1) = setup_1_conductor().await; + + // CREATE TARGET ENTRY + + let target_hash: EntryHash = conductor + .call( + &cell1.zome("trust_atom"), + "create_string_target", + "Sushi Ran", + ) + .await; + + // CREATE TRUST ATOMS + + let _trust_atom_1: trust_atom_types::TrustAtom = conductor + .call( + &cell1.zome("trust_atom"), + "create_trust_atom", + trust_atom_types::TrustAtomInput { + target: AnyLinkableHash::from(target_hash.clone()), + content: None, + value: Some("0.88".into()), + extra: Some(BTreeMap::new()), + }, + ) + .await; + + let _trust_atom_2: trust_atom_types::TrustAtom = conductor + .call( + &cell1.zome("trust_atom"), + "create_trust_atom", + trust_atom_types::TrustAtomInput { + target: AnyLinkableHash::from(target_hash.clone()), + content: None, + value: Some("0.81".into()), + extra: Some(BTreeMap::new()), + }, + ) + .await; + + let _trust_atom_3: trust_atom_types::TrustAtom = conductor + .call( + &cell1.zome("trust_atom"), + "create_trust_atom", + trust_atom_types::TrustAtomInput { + target: AnyLinkableHash::from(target_hash.clone()), + content: None, + value: Some("0.7".into()), + extra: Some(BTreeMap::new()), + }, + ) + .await; + + // let _links: Vec = conductor + // .call( + // &cell1.zome("trust_atom"), + // "test_helper_list_links_for_base", + // target_hash, + // ) + // .await; + + // for link in links { + // println!("{:#?}", String::from_utf8(link.tag.into_inner())); + // } + + // QUERY MY TRUST ATOMS + + let trust_atoms_from_query: Vec = conductor + .call( + &cell1.zome("trust_atom"), + "query_mine", + trust_atom_types::QueryMineInput { + target: None, + content_full: None, + content_starts_with: None, + content_not_starts_with: None, + value_starts_with: Some(".8".into()), + }, + ) + .await; + + assert_eq!(trust_atoms_from_query.len(), 2); + + let mut actual = [ + trust_atoms_from_query[0].clone().value, + trust_atoms_from_query[1].clone().value, + ]; + actual.sort(); + + assert_eq!( + actual, + [ + Some(".810000000".to_string()), + Some(".880000000".to_string()) + ] + ); +} + #[tokio::test(flavor = "multi_thread")] pub async fn test_get_extra() { let (conductor, _agent, cell1): (SweetConductor, AgentPubKey, SweetCell) = diff --git a/zomes/trust_atom_types/src/lib.rs b/zomes/trust_atom_types/src/lib.rs index 3858ea8..e1fdfbe 100644 --- a/zomes/trust_atom_types/src/lib.rs +++ b/zomes/trust_atom_types/src/lib.rs @@ -27,6 +27,7 @@ pub struct QueryInput { pub target: Option, pub content_full: Option, pub content_starts_with: Option, + pub content_not_starts_with: Option, pub value_starts_with: Option, } @@ -35,6 +36,7 @@ pub struct QueryMineInput { pub target: Option, pub content_full: Option, pub content_starts_with: Option, + pub content_not_starts_with: Option, pub value_starts_with: Option, }