From 7afe3b7d7c6fd8ba904eb34810780a04f72420e5 Mon Sep 17 00:00:00 2001 From: William Casarin Date: Thu, 26 Dec 2024 09:38:56 -0800 Subject: [PATCH] algos: introduce last_n_per_pubkey_from_tags This function creates filters for the base our first algo in Damus: Called "last N note per pubkey". I don't have a better name for it. This function generates a query in the form: [ {"authors": ["author_a"], "limit": 1, "kinds": [1] , {"authors": ["author_b"], "limit": 1, "kinds": [1] , {"authors": ["author_c"], "limit": 1, "kinds": [1] , {"authors": ["author_c"], "limit": 1, "kinds": [1] ... ] Due to an unfortunate restriction currently in nostrdb and strfry, we can only do about 16 to 20 of these at any given time. I have made this limit configurable in strfry[1]. I just need to do the same in nostrdb now. [1] https://github.com/hoytech/strfry/pull/133 Changelog-Added: Add last_n_per_pubkey_from_tags algo function --- crates/notedeck/src/filter.rs | 54 +++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/crates/notedeck/src/filter.rs b/crates/notedeck/src/filter.rs index 81f1299e..387beb4e 100644 --- a/crates/notedeck/src/filter.rs +++ b/crates/notedeck/src/filter.rs @@ -190,6 +190,60 @@ impl FilteredTags { } } +/// Create a "last N notes per pubkey" query. +pub fn last_n_per_pubkey_from_tags( + note: &Note, + kind: u64, + notes_per_pubkey: u64, +) -> Result> { + let mut filters: Vec = vec![]; + + for tag in note.tags() { + // TODO: fix arbitrary MAX_FILTER limit in nostrdb + if filters.len() == 15 { + break; + } + + if tag.count() < 2 { + continue; + } + + let t = if let Some(t) = tag.get_unchecked(0).variant().str() { + t + } else { + continue; + }; + + if t == "p" { + let author = if let Some(author) = tag.get_unchecked(1).variant().id() { + author + } else { + continue; + }; + + let mut filter = Filter::new(); + filter.start_authors_field()?; + filter.add_id_element(author)?; + filter.end_field(); + filters.push(filter.kinds([kind]).limit(notes_per_pubkey).build()); + } else if t == "t" { + let hashtag = if let Some(hashtag) = tag.get_unchecked(1).variant().str() { + hashtag + } else { + continue; + }; + + let mut filter = Filter::new(); + filter.start_tags_field('t')?; + filter.add_str_element(hashtag)?; + filter.end_field(); + filters.push(filter.kinds([kind]).limit(notes_per_pubkey).build()); + } + } + + Ok(filters) +} + /// Create a filter from tags. This can be used to create a filter /// from a contact list pub fn filter_from_tags(