Events::get_local_events_by_filter()

This commit is contained in:
Mike Dilger 2023-02-19 10:13:15 +13:00
parent e8ac8d4d5f
commit 80f03a57fe
1 changed files with 121 additions and 2 deletions

View File

@ -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<Option<Event>, 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<Vec<Event>, Error> {
let mut conditions: Vec<String> = 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<Vec<Event>, 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<Event> = 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<Option<Id>, Error> {
if let Some(event) = self.get_local(*id).await? {
@ -81,3 +168,35 @@ impl Events {
self.events.iter()
}
}
fn build_prefix_condition<T: Display>(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<T: Display>(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
}