commit e0ed122951b6203246fa4499e55ffb31019e667e
parent e1ad2e231f790ba4779c41e069a7540f94a40250
Author: kernelkind <kernelkind@gmail.com>
Date: Mon, 8 Sep 2025 16:04:12 -0400
use `NdbQueryPackage` to call ndb::query multiple times
necessary to ensure we can retrieve reposts from ndb
Signed-off-by: kernelkind <kernelkind@gmail.com>
Diffstat:
6 files changed, 97 insertions(+), 40 deletions(-)
diff --git a/crates/notedeck/src/contacts.rs b/crates/notedeck/src/contacts.rs
@@ -1,5 +1,5 @@
use crate::{
- filter::{self, HybridFilter},
+ filter::{self, HybridFilter, ValidKind},
Error,
};
use nostrdb::{Filter, Note};
@@ -15,8 +15,14 @@ pub fn hybrid_contacts_filter(
add_pk: Option<&[u8; 32]>,
with_hashtags: bool,
) -> Result<HybridFilter, Error> {
- let local = filter::filter_from_tags(note, add_pk, with_hashtags)?
- .into_filter(vec![1], filter::default_limit());
+ let local = vec![
+ filter::filter_from_tags(note, add_pk, with_hashtags)?
+ .into_query_package(ValidKind::One, filter::default_limit()),
+ filter::filter_from_tags(note, add_pk, with_hashtags)?
+ .into_query_package(ValidKind::Six, filter::default_limit()),
+ filter::filter_from_tags(note, add_pk, with_hashtags)?
+ .into_query_package(ValidKind::Zero, filter::default_limit()),
+ ];
let remote = filter::filter_from_tags(note, add_pk, with_hashtags)?
.into_filter(vec![1, 0], filter::default_remote_limit());
diff --git a/crates/notedeck/src/filter.rs b/crates/notedeck/src/filter.rs
@@ -213,7 +213,7 @@ pub struct FilteredTags {
/// The local and remote filter are related but slightly different
#[derive(Debug, Clone)]
pub struct SplitFilter {
- pub local: Vec<Filter>,
+ pub local: Vec<NdbQueryPackage>,
pub remote: Vec<Filter>,
}
@@ -230,16 +230,23 @@ impl HybridFilter {
HybridFilter::Unsplit(filter)
}
- pub fn split(local: Vec<Filter>, remote: Vec<Filter>) -> Self {
+ pub fn split(local: Vec<NdbQueryPackage>, remote: Vec<Filter>) -> Self {
HybridFilter::Split(SplitFilter { local, remote })
}
- pub fn local(&self) -> &[Filter] {
+ pub fn local(&self) -> NdbQueryPackages {
match self {
- Self::Split(split) => &split.local,
+ Self::Split(split) => NdbQueryPackages {
+ packages: split.local.iter().map(NdbQueryPackage::borrow).collect(),
+ },
// local as the same as remote in unsplit
- Self::Unsplit(local) => local,
+ Self::Unsplit(local) => NdbQueryPackages {
+ packages: vec![NdbQueryPackageUnowned {
+ filters: local,
+ kind: None,
+ }],
+ },
}
}
diff --git a/crates/notedeck_columns/src/multi_subscriber.rs b/crates/notedeck_columns/src/multi_subscriber.rs
@@ -311,7 +311,7 @@ impl TimelineSub {
let before = self.state.clone();
match &mut self.state {
SubState::NoSub { dependers } => {
- let Some(sub) = ndb_sub(ndb, filter.local(), "") else {
+ let Some(sub) = ndb_sub(ndb, &filter.local().combined(), "") else {
return;
};
@@ -326,7 +326,7 @@ impl TimelineSub {
dependers: _,
} => {}
SubState::RemoteOnly { remote, dependers } => {
- let Some(local) = ndb_sub(ndb, filter.local(), "") else {
+ let Some(local) = ndb_sub(ndb, &filter.local().combined(), "") else {
return;
};
self.state = SubState::Unified {
diff --git a/crates/notedeck_columns/src/timeline/cache.rs b/crates/notedeck_columns/src/timeline/cache.rs
@@ -134,15 +134,22 @@ impl TimelineCache {
}
let notes = if let FilterState::Ready(filters) = id.filters(txn, ndb) {
- if let Ok(results) = ndb.query(txn, filters.local(), 1000) {
- results
- .into_iter()
- .map(NoteRef::from_query_result)
- .collect()
- } else {
- debug!("got no results from TimelineCache lookup for {:?}", id);
- vec![]
+ let mut notes = Vec::new();
+
+ for package in filters.local().packages {
+ if let Ok(results) = ndb.query(txn, package.filters, 1000) {
+ let cur_notes: Vec<NoteRef> = results
+ .into_iter()
+ .map(NoteRef::from_query_result)
+ .collect();
+
+ notes.extend(cur_notes);
+ } else {
+ debug!("got no results from TimelineCache lookup for {:?}", id);
+ }
}
+
+ notes
} else {
// filter is not ready yet
vec![]
@@ -178,12 +185,20 @@ impl TimelineCache {
let (mut open_result, timeline) = match notes_resp.vitality {
Vitality::Stale(timeline) => {
// The timeline cache is stale, let's update it
- let notes = find_new_notes(
- timeline.all_or_any_entries().latest(),
- timeline.subscription.get_filter()?.local(),
- txn,
- ndb,
- );
+ let notes = {
+ let mut notes = Vec::new();
+ for package in timeline.subscription.get_filter()?.local().packages {
+ let cur_notes = find_new_notes(
+ timeline.all_or_any_entries().latest(),
+ package.filters,
+ txn,
+ ndb,
+ );
+ notes.extend(cur_notes);
+ }
+ notes
+ };
+
let open_result = if notes.is_empty() {
None
} else {
diff --git a/crates/notedeck_columns/src/timeline/kind.rs b/crates/notedeck_columns/src/timeline/kind.rs
@@ -3,6 +3,7 @@ use crate::search::SearchQuery;
use crate::timeline::{Timeline, TimelineTab};
use enostr::{Filter, NoteId, Pubkey};
use nostrdb::{Ndb, Transaction};
+use notedeck::filter::{NdbQueryPackage, ValidKind};
use notedeck::{
contacts::{contacts_filter, hybrid_contacts_filter},
filter::{self, default_limit, default_remote_limit, HybridFilter},
@@ -728,15 +729,29 @@ fn last_per_pubkey_filter_state(ndb: &Ndb, pk: &Pubkey) -> FilterState {
}
fn profile_filter(pk: &[u8; 32]) -> HybridFilter {
+ let local = vec![
+ NdbQueryPackage {
+ filters: vec![Filter::new()
+ .authors([pk])
+ .kinds([1])
+ .limit(default_limit())
+ .build()],
+ kind: ValidKind::One,
+ },
+ NdbQueryPackage {
+ filters: vec![Filter::new()
+ .authors([pk])
+ .kinds([6])
+ .limit(default_limit())
+ .build()],
+ kind: ValidKind::Six,
+ },
+ ];
HybridFilter::split(
+ local,
vec![Filter::new()
.authors([pk])
- .kinds([1])
- .limit(default_limit())
- .build()],
- vec![Filter::new()
- .authors([pk])
- .kinds([1, 0])
+ .kinds([1, 6, 0])
.limit(default_remote_limit())
.build()],
)
diff --git a/crates/notedeck_columns/src/timeline/mod.rs b/crates/notedeck_columns/src/timeline/mod.rs
@@ -676,18 +676,32 @@ fn setup_initial_timeline(
timeline.subscription, timeline.filter
);
- let mut lim = 0i32;
- for filter in filters.local() {
- lim += filter.limit().unwrap_or(1) as i32;
- }
+ let notes = {
+ let mut notes = Vec::new();
+
+ for package in filters.local().packages {
+ let mut lim = 0i32;
+ for filter in package.filters {
+ lim += filter.limit().unwrap_or(1) as i32;
+ }
- debug!("setup_initial_timeline: limit for local filter is {}", lim);
+ debug!("setup_initial_timeline: limit for local filter is {}", lim);
+
+ let cur_notes: Vec<NoteRef> = ndb
+ .query(txn, package.filters, lim)?
+ .into_iter()
+ .map(NoteRef::from_query_result)
+ .collect();
+ tracing::debug!(
+ "Found {} notes for kind: {:?}",
+ cur_notes.len(),
+ package.kind
+ );
+ notes.extend(&cur_notes);
+ }
- let notes: Vec<NoteRef> = ndb
- .query(txn, filters.local(), lim)?
- .into_iter()
- .map(NoteRef::from_query_result)
- .collect();
+ notes
+ };
if let Some(pks) = timeline.insert_new(txn, ndb, note_cache, ¬es) {
pks.process(ndb, txn, unknown_ids);