use NdbQueryPackage to call ndb::query multiple times

necessary to ensure we can retrieve reposts from ndb

Signed-off-by: kernelkind <kernelkind@gmail.com>
This commit is contained in:
kernelkind
2025-09-08 16:04:12 -04:00
parent e1ad2e231f
commit e0ed122951
6 changed files with 97 additions and 40 deletions

View File

@@ -1,5 +1,5 @@
use crate::{ use crate::{
filter::{self, HybridFilter}, filter::{self, HybridFilter, ValidKind},
Error, Error,
}; };
use nostrdb::{Filter, Note}; use nostrdb::{Filter, Note};
@@ -15,8 +15,14 @@ pub fn hybrid_contacts_filter(
add_pk: Option<&[u8; 32]>, add_pk: Option<&[u8; 32]>,
with_hashtags: bool, with_hashtags: bool,
) -> Result<HybridFilter, Error> { ) -> Result<HybridFilter, Error> {
let local = filter::filter_from_tags(note, add_pk, with_hashtags)? let local = vec![
.into_filter(vec![1], filter::default_limit()); 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)? let remote = filter::filter_from_tags(note, add_pk, with_hashtags)?
.into_filter(vec![1, 0], filter::default_remote_limit()); .into_filter(vec![1, 0], filter::default_remote_limit());

View File

@@ -213,7 +213,7 @@ pub struct FilteredTags {
/// The local and remote filter are related but slightly different /// The local and remote filter are related but slightly different
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct SplitFilter { pub struct SplitFilter {
pub local: Vec<Filter>, pub local: Vec<NdbQueryPackage>,
pub remote: Vec<Filter>, pub remote: Vec<Filter>,
} }
@@ -230,16 +230,23 @@ impl HybridFilter {
HybridFilter::Unsplit(filter) 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 }) HybridFilter::Split(SplitFilter { local, remote })
} }
pub fn local(&self) -> &[Filter] { pub fn local(&self) -> NdbQueryPackages {
match self { 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 // local as the same as remote in unsplit
Self::Unsplit(local) => local, Self::Unsplit(local) => NdbQueryPackages {
packages: vec![NdbQueryPackageUnowned {
filters: local,
kind: None,
}],
},
} }
} }

View File

@@ -311,7 +311,7 @@ impl TimelineSub {
let before = self.state.clone(); let before = self.state.clone();
match &mut self.state { match &mut self.state {
SubState::NoSub { dependers } => { SubState::NoSub { dependers } => {
let Some(sub) = ndb_sub(ndb, filter.local(), "") else { let Some(sub) = ndb_sub(ndb, &filter.local().combined(), "") else {
return; return;
}; };
@@ -326,7 +326,7 @@ impl TimelineSub {
dependers: _, dependers: _,
} => {} } => {}
SubState::RemoteOnly { remote, 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; return;
}; };
self.state = SubState::Unified { self.state = SubState::Unified {

View File

@@ -134,15 +134,22 @@ impl TimelineCache {
} }
let notes = if let FilterState::Ready(filters) = id.filters(txn, ndb) { let notes = if let FilterState::Ready(filters) = id.filters(txn, ndb) {
if let Ok(results) = ndb.query(txn, filters.local(), 1000) { let mut notes = Vec::new();
results
.into_iter() for package in filters.local().packages {
.map(NoteRef::from_query_result) if let Ok(results) = ndb.query(txn, package.filters, 1000) {
.collect() let cur_notes: Vec<NoteRef> = results
} else { .into_iter()
debug!("got no results from TimelineCache lookup for {:?}", id); .map(NoteRef::from_query_result)
vec![] .collect();
notes.extend(cur_notes);
} else {
debug!("got no results from TimelineCache lookup for {:?}", id);
}
} }
notes
} else { } else {
// filter is not ready yet // filter is not ready yet
vec![] vec![]
@@ -178,12 +185,20 @@ impl TimelineCache {
let (mut open_result, timeline) = match notes_resp.vitality { let (mut open_result, timeline) = match notes_resp.vitality {
Vitality::Stale(timeline) => { Vitality::Stale(timeline) => {
// The timeline cache is stale, let's update it // The timeline cache is stale, let's update it
let notes = find_new_notes( let notes = {
timeline.all_or_any_entries().latest(), let mut notes = Vec::new();
timeline.subscription.get_filter()?.local(), for package in timeline.subscription.get_filter()?.local().packages {
txn, let cur_notes = find_new_notes(
ndb, timeline.all_or_any_entries().latest(),
); package.filters,
txn,
ndb,
);
notes.extend(cur_notes);
}
notes
};
let open_result = if notes.is_empty() { let open_result = if notes.is_empty() {
None None
} else { } else {

View File

@@ -3,6 +3,7 @@ use crate::search::SearchQuery;
use crate::timeline::{Timeline, TimelineTab}; use crate::timeline::{Timeline, TimelineTab};
use enostr::{Filter, NoteId, Pubkey}; use enostr::{Filter, NoteId, Pubkey};
use nostrdb::{Ndb, Transaction}; use nostrdb::{Ndb, Transaction};
use notedeck::filter::{NdbQueryPackage, ValidKind};
use notedeck::{ use notedeck::{
contacts::{contacts_filter, hybrid_contacts_filter}, contacts::{contacts_filter, hybrid_contacts_filter},
filter::{self, default_limit, default_remote_limit, HybridFilter}, 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 { 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( HybridFilter::split(
local,
vec![Filter::new() vec![Filter::new()
.authors([pk]) .authors([pk])
.kinds([1]) .kinds([1, 6, 0])
.limit(default_limit())
.build()],
vec![Filter::new()
.authors([pk])
.kinds([1, 0])
.limit(default_remote_limit()) .limit(default_remote_limit())
.build()], .build()],
) )

View File

@@ -676,18 +676,32 @@ fn setup_initial_timeline(
timeline.subscription, timeline.filter timeline.subscription, timeline.filter
); );
let mut lim = 0i32; let notes = {
for filter in filters.local() { let mut notes = Vec::new();
lim += filter.limit().unwrap_or(1) as i32;
}
debug!("setup_initial_timeline: limit for local filter is {}", lim); for package in filters.local().packages {
let mut lim = 0i32;
for filter in package.filters {
lim += filter.limit().unwrap_or(1) as i32;
}
let notes: Vec<NoteRef> = ndb debug!("setup_initial_timeline: limit for local filter is {}", lim);
.query(txn, filters.local(), lim)?
.into_iter() let cur_notes: Vec<NoteRef> = ndb
.map(NoteRef::from_query_result) .query(txn, package.filters, lim)?
.collect(); .into_iter()
.map(NoteRef::from_query_result)
.collect();
tracing::debug!(
"Found {} notes for kind: {:?}",
cur_notes.len(),
package.kind
);
notes.extend(&cur_notes);
}
notes
};
if let Some(pks) = timeline.insert_new(txn, ndb, note_cache, &notes) { if let Some(pks) = timeline.insert_new(txn, ndb, note_cache, &notes) {
pks.process(ndb, txn, unknown_ids); pks.process(ndb, txn, unknown_ids);