mirror of
https://github.com/scsibug/nostr-rs-relay.git
synced 2024-11-21 16:59:06 -05:00
fix: abort query builder for empty arrays
Signed-off-by: Greg Heartsfield <scsibug@imap.cc>
This commit is contained in:
parent
b4471a6698
commit
ab736f5f98
|
@ -726,7 +726,6 @@ fn query_from_filter(f: &ReqFilter) -> Option<QueryBuilder<Postgres>> {
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut query = QueryBuilder::new("SELECT e.\"content\", e.created_at FROM \"event\" e WHERE ");
|
let mut query = QueryBuilder::new("SELECT e.\"content\", e.created_at FROM \"event\" e WHERE ");
|
||||||
|
|
||||||
// This tracks whether we need to push a prefix AND before adding another clause
|
// This tracks whether we need to push a prefix AND before adding another clause
|
||||||
let mut push_and = false;
|
let mut push_and = false;
|
||||||
// Query for "authors", allowing prefix matches
|
// Query for "authors", allowing prefix matches
|
||||||
|
@ -734,140 +733,142 @@ fn query_from_filter(f: &ReqFilter) -> Option<QueryBuilder<Postgres>> {
|
||||||
// filter out non-hex values
|
// filter out non-hex values
|
||||||
let auth_vec: Vec<&String> = auth_vec.iter().filter(|a| is_hex(a)).collect();
|
let auth_vec: Vec<&String> = auth_vec.iter().filter(|a| is_hex(a)).collect();
|
||||||
|
|
||||||
if !auth_vec.is_empty() {
|
if auth_vec.is_empty() {
|
||||||
query.push("(");
|
return None;
|
||||||
|
}
|
||||||
|
query.push("(");
|
||||||
|
|
||||||
// shortcut authors into "IN" query
|
// shortcut authors into "IN" query
|
||||||
let any_is_range = auth_vec.iter().any(|pk| pk.len() != 64);
|
let any_is_range = auth_vec.iter().any(|pk| pk.len() != 64);
|
||||||
if !any_is_range {
|
if !any_is_range {
|
||||||
query.push("e.pub_key in (");
|
query.push("e.pub_key in (");
|
||||||
let mut pk_sep = query.separated(", ");
|
let mut pk_sep = query.separated(", ");
|
||||||
for pk in auth_vec.iter() {
|
for pk in auth_vec.iter() {
|
||||||
pk_sep.push_bind(hex::decode(pk).ok());
|
pk_sep.push_bind(hex::decode(pk).ok());
|
||||||
}
|
}
|
||||||
query.push(") OR e.delegated_by in (");
|
query.push(") OR e.delegated_by in (");
|
||||||
let mut pk_delegated_sep = query.separated(", ");
|
let mut pk_delegated_sep = query.separated(", ");
|
||||||
for pk in auth_vec.iter() {
|
for pk in auth_vec.iter() {
|
||||||
pk_delegated_sep.push_bind(hex::decode(pk).ok());
|
pk_delegated_sep.push_bind(hex::decode(pk).ok());
|
||||||
}
|
|
||||||
query.push(")");
|
|
||||||
push_and = true;
|
|
||||||
} else {
|
|
||||||
let mut range_authors = query.separated(" OR ");
|
|
||||||
for auth in auth_vec {
|
|
||||||
match hex_range(auth) {
|
|
||||||
Some(HexSearch::Exact(ex)) => {
|
|
||||||
range_authors
|
|
||||||
.push("(e.pub_key = ")
|
|
||||||
.push_bind_unseparated(ex.clone())
|
|
||||||
.push_unseparated(" OR e.delegated_by = ")
|
|
||||||
.push_bind_unseparated(ex)
|
|
||||||
.push_unseparated(")");
|
|
||||||
}
|
|
||||||
Some(HexSearch::Range(lower, upper)) => {
|
|
||||||
range_authors
|
|
||||||
.push("((e.pub_key > ")
|
|
||||||
.push_bind_unseparated(lower.clone())
|
|
||||||
.push_unseparated(" AND e.pub_key < ")
|
|
||||||
.push_bind_unseparated(upper.clone())
|
|
||||||
.push_unseparated(") OR (e.delegated_by > ")
|
|
||||||
.push_bind_unseparated(lower)
|
|
||||||
.push_unseparated(" AND e.delegated_by < ")
|
|
||||||
.push_bind_unseparated(upper)
|
|
||||||
.push_unseparated("))");
|
|
||||||
}
|
|
||||||
Some(HexSearch::LowerOnly(lower)) => {
|
|
||||||
range_authors
|
|
||||||
.push("(e.pub_key > ")
|
|
||||||
.push_bind_unseparated(lower.clone())
|
|
||||||
.push_unseparated(" OR e.delegated_by > ")
|
|
||||||
.push_bind_unseparated(lower)
|
|
||||||
.push_unseparated(")");
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
info!("Could not parse hex range from author {:?}", auth);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
push_and = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
query.push(")");
|
query.push(")");
|
||||||
|
push_and = true;
|
||||||
|
} else {
|
||||||
|
let mut range_authors = query.separated(" OR ");
|
||||||
|
for auth in auth_vec {
|
||||||
|
match hex_range(auth) {
|
||||||
|
Some(HexSearch::Exact(ex)) => {
|
||||||
|
range_authors
|
||||||
|
.push("(e.pub_key = ")
|
||||||
|
.push_bind_unseparated(ex.clone())
|
||||||
|
.push_unseparated(" OR e.delegated_by = ")
|
||||||
|
.push_bind_unseparated(ex)
|
||||||
|
.push_unseparated(")");
|
||||||
|
}
|
||||||
|
Some(HexSearch::Range(lower, upper)) => {
|
||||||
|
range_authors
|
||||||
|
.push("((e.pub_key > ")
|
||||||
|
.push_bind_unseparated(lower.clone())
|
||||||
|
.push_unseparated(" AND e.pub_key < ")
|
||||||
|
.push_bind_unseparated(upper.clone())
|
||||||
|
.push_unseparated(") OR (e.delegated_by > ")
|
||||||
|
.push_bind_unseparated(lower)
|
||||||
|
.push_unseparated(" AND e.delegated_by < ")
|
||||||
|
.push_bind_unseparated(upper)
|
||||||
|
.push_unseparated("))");
|
||||||
|
}
|
||||||
|
Some(HexSearch::LowerOnly(lower)) => {
|
||||||
|
range_authors
|
||||||
|
.push("(e.pub_key > ")
|
||||||
|
.push_bind_unseparated(lower.clone())
|
||||||
|
.push_unseparated(" OR e.delegated_by > ")
|
||||||
|
.push_bind_unseparated(lower)
|
||||||
|
.push_unseparated(")");
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
info!("Could not parse hex range from author {:?}", auth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
push_and = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
query.push(")");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Query for Kind
|
// Query for Kind
|
||||||
if let Some(ks) = &f.kinds {
|
if let Some(ks) = &f.kinds {
|
||||||
if !ks.is_empty() {
|
if ks.is_empty() {
|
||||||
if push_and {
|
return None;
|
||||||
query.push(" AND ");
|
|
||||||
}
|
|
||||||
push_and = true;
|
|
||||||
|
|
||||||
query.push("e.kind in (");
|
|
||||||
let mut list_query = query.separated(", ");
|
|
||||||
for k in ks.iter() {
|
|
||||||
list_query.push_bind(*k as i64);
|
|
||||||
}
|
|
||||||
query.push(")");
|
|
||||||
}
|
}
|
||||||
|
if push_and {
|
||||||
|
query.push(" AND ");
|
||||||
|
}
|
||||||
|
push_and = true;
|
||||||
|
|
||||||
|
query.push("e.kind in (");
|
||||||
|
let mut list_query = query.separated(", ");
|
||||||
|
for k in ks.iter() {
|
||||||
|
list_query.push_bind(*k as i64);
|
||||||
|
}
|
||||||
|
query.push(")");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Query for event, allowing prefix matches
|
// Query for event, allowing prefix matches
|
||||||
if let Some(id_vec) = &f.ids {
|
if let Some(id_vec) = &f.ids {
|
||||||
// filter out non-hex values
|
// filter out non-hex values
|
||||||
let id_vec: Vec<&String> = id_vec.iter().filter(|a| is_hex(a)).collect();
|
let id_vec: Vec<&String> = id_vec.iter().filter(|a| is_hex(a)).collect();
|
||||||
|
if id_vec.is_empty() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
if push_and {
|
||||||
|
query.push(" AND (");
|
||||||
|
} else {
|
||||||
|
query.push("(");
|
||||||
|
}
|
||||||
|
push_and = true;
|
||||||
|
|
||||||
if !id_vec.is_empty() {
|
// shortcut ids into "IN" query
|
||||||
if push_and {
|
let any_is_range = id_vec.iter().any(|pk| pk.len() != 64);
|
||||||
query.push(" AND (");
|
if !any_is_range {
|
||||||
} else {
|
query.push("id in (");
|
||||||
query.push("(");
|
let mut sep = query.separated(", ");
|
||||||
|
for id in id_vec.iter() {
|
||||||
|
sep.push_bind(hex::decode(id).ok());
|
||||||
}
|
}
|
||||||
push_and = true;
|
query.push(")");
|
||||||
|
} else {
|
||||||
// shortcut ids into "IN" query
|
// take each author and convert to a hex search
|
||||||
let any_is_range = id_vec.iter().any(|pk| pk.len() != 64);
|
let mut id_query = query.separated(" OR ");
|
||||||
if !any_is_range {
|
for id in id_vec {
|
||||||
query.push("id in (");
|
match hex_range(id) {
|
||||||
let mut sep = query.separated(", ");
|
Some(HexSearch::Exact(ex)) => {
|
||||||
for id in id_vec.iter() {
|
id_query
|
||||||
sep.push_bind(hex::decode(id).ok());
|
.push("(id = ")
|
||||||
}
|
.push_bind_unseparated(ex)
|
||||||
query.push(")");
|
.push_unseparated(")");
|
||||||
} else {
|
}
|
||||||
// take each author and convert to a hex search
|
Some(HexSearch::Range(lower, upper)) => {
|
||||||
let mut id_query = query.separated(" OR ");
|
id_query
|
||||||
for id in id_vec {
|
.push("(id > ")
|
||||||
match hex_range(id) {
|
.push_bind_unseparated(lower)
|
||||||
Some(HexSearch::Exact(ex)) => {
|
.push_unseparated(" AND id < ")
|
||||||
id_query
|
.push_bind_unseparated(upper)
|
||||||
.push("(id = ")
|
.push_unseparated(")");
|
||||||
.push_bind_unseparated(ex)
|
}
|
||||||
.push_unseparated(")");
|
Some(HexSearch::LowerOnly(lower)) => {
|
||||||
}
|
id_query
|
||||||
Some(HexSearch::Range(lower, upper)) => {
|
.push("(id > ")
|
||||||
id_query
|
.push_bind_unseparated(lower)
|
||||||
.push("(id > ")
|
.push_unseparated(")");
|
||||||
.push_bind_unseparated(lower)
|
}
|
||||||
.push_unseparated(" AND id < ")
|
None => {
|
||||||
.push_bind_unseparated(upper)
|
info!("Could not parse hex range from id {:?}", id);
|
||||||
.push_unseparated(")");
|
|
||||||
}
|
|
||||||
Some(HexSearch::LowerOnly(lower)) => {
|
|
||||||
id_query
|
|
||||||
.push("(id > ")
|
|
||||||
.push_bind_unseparated(lower)
|
|
||||||
.push_unseparated(")");
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
info!("Could not parse hex range from id {:?}", id);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
query.push(")");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
query.push(")");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Query for tags
|
// Query for tags
|
||||||
|
@ -881,6 +882,9 @@ fn query_from_filter(f: &ReqFilter) -> Option<QueryBuilder<Postgres>> {
|
||||||
let mut push_or = false;
|
let mut push_or = false;
|
||||||
query.push("e.id IN (SELECT ee.id FROM \"event\" ee LEFT JOIN tag t on ee.id = t.event_id WHERE ee.hidden != 1::bit(1) and ");
|
query.push("e.id IN (SELECT ee.id FROM \"event\" ee LEFT JOIN tag t on ee.id = t.event_id WHERE ee.hidden != 1::bit(1) and ");
|
||||||
for (key, val) in map.iter() {
|
for (key, val) in map.iter() {
|
||||||
|
if val.is_empty() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
if push_or {
|
if push_or {
|
||||||
query.push(" OR ");
|
query.push(" OR ");
|
||||||
}
|
}
|
||||||
|
@ -1065,4 +1069,21 @@ mod tests {
|
||||||
let q = query_from_filter(&filter).unwrap();
|
let q = query_from_filter(&filter).unwrap();
|
||||||
assert_eq!(q.sql(), "SELECT e.\"content\", e.created_at FROM \"event\" e WHERE e.kind in ($1) AND e.id IN (SELECT ee.id FROM \"event\" ee LEFT JOIN tag t on ee.id = t.event_id WHERE ee.hidden != 1::bit(1) and (t.\"name\" = $2 AND (value in ($3))) OR (t.\"name\" = $4 AND (value in ($5)))) AND e.hidden != 1::bit(1) AND (e.expires_at IS NULL OR e.expires_at > now()) ORDER BY e.created_at ASC LIMIT 1000")
|
assert_eq!(q.sql(), "SELECT e.\"content\", e.created_at FROM \"event\" e WHERE e.kind in ($1) AND e.id IN (SELECT ee.id FROM \"event\" ee LEFT JOIN tag t on ee.id = t.event_id WHERE ee.hidden != 1::bit(1) and (t.\"name\" = $2 AND (value in ($3))) OR (t.\"name\" = $4 AND (value in ($5)))) AND e.hidden != 1::bit(1) AND (e.expires_at IS NULL OR e.expires_at > now()) ORDER BY e.created_at ASC LIMIT 1000")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_query_empty_tags() {
|
||||||
|
let filter = ReqFilter {
|
||||||
|
ids: None,
|
||||||
|
kinds: Some(vec![1, 6, 16, 30023, 1063, 6969]),
|
||||||
|
since: Some(1700697846),
|
||||||
|
until: None,
|
||||||
|
authors: None,
|
||||||
|
limit: None,
|
||||||
|
tags: Some(HashMap::from([
|
||||||
|
('a', HashSet::new())
|
||||||
|
])),
|
||||||
|
force_no_match: false,
|
||||||
|
};
|
||||||
|
assert!(query_from_filter(&filter).is_none());
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user