From 80f03a57fe9febaa4eb8a96e2fdda4eab6a6f1ab Mon Sep 17 00:00:00 2001 From: Mike Dilger Date: Sun, 19 Feb 2023 10:13:15 +1300 Subject: [PATCH] Events::get_local_events_by_filter() --- src/events.rs | 123 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 121 insertions(+), 2 deletions(-) diff --git a/src/events.rs b/src/events.rs index 0059f5e5..14e33020 100644 --- a/src/events.rs +++ b/src/events.rs @@ -2,7 +2,8 @@ use crate::error::Error; use crate::globals::GLOBALS; use async_recursion::async_recursion; use dashmap::DashMap; -use nostr_types::{Event, Id}; +use nostr_types::{Event, Filter, Id}; +use std::fmt::Display; use tokio::task; pub struct Events { @@ -30,7 +31,7 @@ impl Events { self.events.get(id).map(|e| e.value().to_owned()) } - /// Get the event from memory, and also try the database + /// Get the event from memory, and also try the database, by Id pub async fn get_local(&self, id: Id) -> Result, Error> { if let Some(e) = self.get(&id) { return Ok(Some(e)); @@ -61,6 +62,92 @@ impl Events { } } + /// Get event from database, by Filter + #[allow(dead_code)] + pub async fn get_local_events_by_filter(&self, filter: Filter) -> Result, Error> { + let mut conditions: Vec = Vec::new(); + if !filter.ids.is_empty() { + conditions.push(build_prefix_condition("id", &filter.ids)); + } + if !filter.authors.is_empty() { + conditions.push(build_prefix_condition("pubkey", &filter.authors)); + } + if !filter.kinds.is_empty() { + let mut c = "kind in (".to_owned(); + let mut virgin = true; + for kind in filter.kinds.iter() { + if !virgin { + c.push(','); + } + virgin = false; + let k: u64 = (*kind).into(); + c.push_str(&format!("{}", k)); + } + c.push(')'); + conditions.push(c); + } + if !filter.a.is_empty() { + conditions.push(build_tag_condition("a", &filter.a)); + } + if !filter.d.is_empty() { + conditions.push(build_tag_condition("d", &filter.d)); + } + if !filter.e.is_empty() { + conditions.push(build_tag_condition("e", &filter.e)); + } + if !filter.g.is_empty() { + conditions.push(build_tag_condition("g", &filter.g)); + } + if !filter.p.is_empty() { + conditions.push(build_tag_condition("p", &filter.p)); + } + if !filter.r.is_empty() { + conditions.push(build_tag_condition("r", &filter.r)); + } + if !filter.t.is_empty() { + conditions.push(build_tag_condition("t", &filter.t)); + } + if let Some(since) = filter.since { + conditions.push(format!("created_at >= {}", since.0)); + } + if let Some(until) = filter.until { + conditions.push(format!("created_at <= {}", until.0)); + } + + let mut sql = format!("SELECT raw FROM event WHERE {}", conditions.join(" AND ")); + + if let Some(limit) = filter.limit { + sql.push_str(&(format!(" LIMIT {}", limit))); + } + + tracing::trace!("get_local_events_by_filter SQL={}", &sql); + + let events_result = task::spawn_blocking(move || -> Result, Error> { + let maybe_db = GLOBALS.db.blocking_lock(); + let db = maybe_db.as_ref().unwrap(); + let mut stmt = db.prepare(&sql)?; + let mut rows = stmt.raw_query(); + let mut events: Vec = Vec::new(); + while let Some(row) = rows.next()? { + let s: String = row.get(0)?; + events.push(serde_json::from_str(&s)?); + } + Ok(events) + }) + .await?; + let events = events_result?; + + for event in events.iter() { + // Process that event + crate::process::process_new_event(event, false, None, None).await?; + + // Add to memory + self.insert(event.clone()); + } + + Ok(events) + } + #[async_recursion] pub async fn get_highest_local_parent(&self, id: &Id) -> Result, Error> { if let Some(event) = self.get_local(*id).await? { @@ -81,3 +168,35 @@ impl Events { self.events.iter() } } + +fn build_prefix_condition(field: &str, values: &[T]) -> String { + let mut c = "(".to_owned(); + let mut virgin = true; + for val in values.iter() { + if !virgin { + c.push_str(" OR "); + } + virgin = false; + c.push_str(&format!("{} LIKE '{}%'", field, val)); + } + c.push(')'); + c +} + +fn build_tag_condition(tag: &str, values: &[T]) -> String { + // "id in (SELECT event FROM event_tag WHERE label='e' AND field0={})"; + let mut c = format!( + "id in (SELECT event FROM event_tag WHERE label='{}' AND field0 IN (", + tag + ); + let mut virgin = true; + for val in values.iter() { + if !virgin { + c.push(','); + } + virgin = false; + c.push_str(&format!("'{}'", val)); + } + c.push_str("))"); + c +}