Conversation
lmdb: match literals partially with simple contains(phrase)
|
|
||
|
|
||
| /// Match a query against an event | ||
| #[cfg(test)] |
| #[cfg(test)] | ||
| mod tests { | ||
| use nostr::{Event, EventBuilder, Keys, Tag}; | ||
|
|
||
| use super::*; | ||
|
|
||
| fn create_test_event(content: &str) -> Event { | ||
| let keys = Keys::generate(); | ||
| EventBuilder::text_note(content) | ||
| .sign_with_keys(&keys) | ||
| .unwrap() | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_search_match_in_content() { | ||
| let event = create_test_event("Hello World"); | ||
| let event: EventBorrow = (&event).into(); | ||
|
|
||
| let mut filter = DatabaseFilter::from(Filter::new()); | ||
|
|
||
| // Case insensitive match | ||
| filter.search = Some("hello".to_string()); | ||
| assert!(filter.match_event(&event)); | ||
|
|
||
| filter.search = Some("world".to_string()); | ||
| assert!(filter.match_event(&event)); | ||
|
|
||
| // No match | ||
| filter.search = Some("rust".to_string()); | ||
| assert!(!filter.match_event(&event)); | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_search_match_in_tags() { | ||
| let keys = Keys::generate(); | ||
| let event = EventBuilder::text_note("content") | ||
| .tag(Tag::parse(["title", "Search userfacing tags"]).unwrap()) | ||
| .sign_with_keys(&keys) | ||
| .unwrap(); | ||
| let event: EventBorrow = (&event).into(); | ||
|
|
||
| let mut filter = DatabaseFilter::from(Filter::new()); | ||
|
|
||
| filter.search = Some("userfacing".to_string()); | ||
| assert!(filter.match_event(&event)); | ||
|
|
||
| filter.search = Some("bitcoin".to_string()); | ||
| assert!(!filter.match_event(&event)); | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_search_empty_query() { | ||
| let event = create_test_event("test"); | ||
| let event: EventBorrow = (&event).into(); | ||
| let mut filter = DatabaseFilter::from(Filter::new()); | ||
|
|
||
| filter.search = Some("".to_string()); | ||
| assert!(!filter.match_event(&event)); | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_search_no_query() { | ||
| let event = create_test_event("test"); | ||
| let event: EventBorrow = (&event).into(); | ||
| let filter = DatabaseFilter::from(Filter::new()); | ||
|
|
||
| assert!(filter.match_event(&event)); | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_search_partial_match() { | ||
| let event = create_test_event("nostr protocol"); | ||
| let event: EventBorrow = (&event).into(); | ||
| let mut filter = DatabaseFilter::from(Filter::new()); | ||
|
|
||
| filter.search = Some("proto".to_string()); | ||
| assert!(filter.match_event(&event)); | ||
| } | ||
| } |
There was a problem hiding this comment.
You shouldn't remove old tests
| // Match specific tag by field name | ||
| assert!(match_query("title:introduction", &event)); | ||
|
|
||
| // Match 't' tag | ||
| assert!(match_query("t:bitcoin", &event)); | ||
|
|
||
| // Field name is case-insensitive | ||
| assert!(match_query("TITLE:nostr", &event)); | ||
|
|
||
| // Non-matching field | ||
| assert!(!match_query("title:ethereum", &event)); | ||
|
|
||
| // Field that doesn't exist | ||
| assert!(!match_query("author:someone", &event)); | ||
|
|
||
| // Match summary tag (not in allowed tags, but accessible via field syntax) | ||
| assert!(match_query("summary:guide", &event)); |
There was a problem hiding this comment.
This is not a thing in NIP-50.
A query string may contain key:value pairs (two words separated by colon), these are extensions, relays SHOULD ignore extensions they don't support.
key:value should be an extension, not a tag search
| // Must have bitcoin, must not have ethereum | ||
| assert!(match_query("+bitcoin -ethereum", &event)); | ||
|
|
||
| // Must not have bitcoin - should not match | ||
| assert!(!match_query("-bitcoin", &event)); | ||
|
|
||
| // Must have bitcoin, must not have decentralized - should not match | ||
| assert!(!match_query("+bitcoin -decentralized", &event)); |
There was a problem hiding this comment.
searchfield is a string describing a query in a human-readable form, i.e. "best nostr apps". Relays SHOULD interpret the query to the best of their ability and return events that match it.
- and + is not a human-readable form, right? Also they are not in the NIP-50
There was a problem hiding this comment.
I think the - and + are defined in the tantivy_query_grammar package as a way of including and excluding results for a search term. However, for anybody who will use the API to perform a search, this is not obvious to them and should not be.
But since the NIP does state:
Clients may include kinds, ids and other filter field to restrict the search results to particular event kinds.
is it viable to add the keys: Include, exclude to DatabaseFilter where clients can pass their preferences. This would then need to be translated to - and +
Description
Details
Adds a proper query parser for the search filter field in nostr-lmdb, replacing the previous simple substring matching with a full query language:
Query Syntax:
Matching Behavior:
contains(phrase)Implementation:
Checklist