From 4ad483090edc45aaf971217779202976495b4bde Mon Sep 17 00:00:00 2001 From: William Casarin Date: Mon, 9 May 2022 13:39:49 -0700 Subject: [PATCH] feat(NIP-01): Implement limit This was quickly sneaked in by fiatjaf per my request[0], it makes many queries more efficient and allows for paging when combined with until. It is a bit weird to have multiple limits on each filter... for now we just choose any or the last limit seen. [0]: https://github.com/nostr-protocol/nips/commit/a4aea5337fe6b93e55f9dae1974ead962c1997e8 Signed-off-by: William Casarin --- src/db.rs | 12 +++++++++++- src/subscription.rs | 5 +++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/db.rs b/src/db.rs index b831cce..b2a54e1 100644 --- a/src/db.rs +++ b/src/db.rs @@ -385,6 +385,7 @@ fn query_from_sub(sub: &Subscription) -> (String, Vec>) { // (sqli-safe), or a string that is filtered to only contain // hexadecimal characters. Strings that require escaping (tag // names/values) use parameters. + let mut limit: Option = None; let mut query = "SELECT DISTINCT(e.content) FROM event e LEFT JOIN tag t ON e.id=t.event_id ".to_owned(); // parameters @@ -422,6 +423,9 @@ fn query_from_sub(sub: &Subscription) -> (String, Vec>) { let authors_clause = format!("({})", auth_searches.join(" OR ")); filter_components.push(authors_clause); } + if let Some(lim) = f.limit { + limit = Some(lim) + } // Query for Kind if let Some(ks) = &f.kinds { // kind is number, no escaping needed @@ -513,7 +517,13 @@ fn query_from_sub(sub: &Subscription) -> (String, Vec>) { query.push_str(") "); } // add order clause - query.push_str(" ORDER BY created_at ASC"); + query.push_str(&format!( + " ORDER BY created_at {}", + limit.map_or("ASC", |_| "DESC") + )); + if let Some(lim) = limit { + query.push_str(&format!(" LIMIT {}", lim)) + } debug!("query string: {}", query); (query, params) } diff --git a/src/subscription.rs b/src/subscription.rs index 21f0281..c0cc0aa 100644 --- a/src/subscription.rs +++ b/src/subscription.rs @@ -31,6 +31,8 @@ pub struct ReqFilter { pub until: Option, /// List of author public keys pub authors: Option>, + /// Limit number of results + pub limit: Option, /// Set of tags #[serde(skip)] pub tags: Option>>, @@ -54,6 +56,7 @@ impl<'de> Deserialize<'de> for ReqFilter { since: None, until: None, authors: None, + limit: None, tags: None, }; let mut ts = None; @@ -68,6 +71,8 @@ impl<'de> Deserialize<'de> for ReqFilter { rf.since = Deserialize::deserialize(val).ok(); } else if key == "until" { rf.until = Deserialize::deserialize(val).ok(); + } else if key == "limit" { + rf.limit = Deserialize::deserialize(val).ok(); } else if key == "authors" { rf.authors = Deserialize::deserialize(val).ok(); } else if key.starts_with('#') && key.len() > 1 && val.is_array() {