fix: value_hex tag query

Signed-off-by: Greg Heartsfield <scsibug@imap.cc>
This commit is contained in:
Kieran 2023-10-17 16:07:56 +01:00 committed by Greg Heartsfield
parent 9d0a98f8bf
commit 24b1705a08

View File

@ -60,7 +60,8 @@ async fn cleanup_expired(conn: PostgresPool, frequency: Duration) -> Result<()>
} }
} }
} }
}; }
;
} }
}); });
Ok(()) Ok(())
@ -880,17 +881,32 @@ fn query_from_filter(f: &ReqFilter) -> Option<QueryBuilder<Postgres>> {
for (key, val) in map.iter() { for (key, val) in map.iter() {
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 (t.\"name\" = ") 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 (t.\"name\" = ")
.push_bind(key.to_string()) .push_bind(key.to_string())
.push(" AND (value in ("); .push(" AND (");
let has_plain_values = val.iter().any(|v| !is_lower_hex(v));
let has_hex_values = val.iter().any(|v| v.len() % 2 == 0 && is_lower_hex(v));
if has_plain_values {
query.push("value in (");
// plain value match first // plain value match first
let mut tag_query = query.separated(", "); let mut tag_query = query.separated(", ");
for v in val.iter() { for v in val.iter()
if (v.len() % 2 != 0) && !is_lower_hex(v) { .filter(|v| !is_lower_hex(v)) {
tag_query.push_bind(v.as_bytes()); tag_query.push_bind(v.as_bytes());
} else { }
}
if has_plain_values && has_hex_values {
query.push(") OR ");
}
if has_hex_values {
query.push("value_hex in (");
// plain value match first
let mut tag_query = query.separated(", ");
for v in val.iter()
.filter(|v| v.len() % 2 == 0 && is_lower_hex(v)) {
tag_query.push_bind(hex::decode(v).ok()); tag_query.push_bind(hex::decode(v).ok());
} }
} }
query.push("))))"); query.push("))))");
} }
} }
@ -925,10 +941,7 @@ fn query_from_filter(f: &ReqFilter) -> Option<QueryBuilder<Postgres>> {
query.push("e.hidden != 1::bit(1)"); query.push("e.hidden != 1::bit(1)");
} }
// never display expired events // never display expired events
query query.push(" AND (e.expires_at IS NULL OR e.expires_at > now())");
.push(" AND (e.expires_at IS NULL OR e.expires_at > ")
.push_bind(Utc.timestamp_opt(utils::unix_time() as i64, 0).unwrap())
.push(")");
// Apply per-filter limit to this query. // Apply per-filter limit to this query.
// The use of a LIMIT implies a DESC order, to capture only the most recent events. // The use of a LIMIT implies a DESC order, to capture only the most recent events.
@ -963,3 +976,67 @@ impl FromRow<'_, PgRow> for VerificationRecord {
}) })
} }
} }
#[cfg(test)]
mod tests {
use std::collections::{HashMap, HashSet};
use super::*;
#[test]
fn test_query_gen_tag_value_hex() {
let filter = ReqFilter {
ids: None,
kinds: Some(vec![1000]),
since: None,
until: None,
authors: Some(vec!["84de35e2584d2b144aae823c9ed0b0f3deda09648530b93d1a2a146d1dea9864".to_owned()]),
limit: None,
tags: Some(HashMap::from([
('p', HashSet::from(["63fe6318dc58583cfe16810f86dd09e18bfd76aabc24a0081ce2856f330504ed".to_owned()]))
])),
force_no_match: false,
};
let q = query_from_filter(&filter).unwrap();
assert_eq!(q.sql(), "SELECT e.\"content\", e.created_at FROM \"event\" e WHERE (e.pub_key in ($1) OR e.delegated_by in ($2)) AND e.kind in ($3) 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\" = $4 AND (value_hex 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_gen_tag_value() {
let filter = ReqFilter {
ids: None,
kinds: Some(vec![1000]),
since: None,
until: None,
authors: Some(vec!["84de35e2584d2b144aae823c9ed0b0f3deda09648530b93d1a2a146d1dea9864".to_owned()]),
limit: None,
tags: Some(HashMap::from([
('d', HashSet::from(["test".to_owned()]))
])),
force_no_match: false,
};
let q = query_from_filter(&filter).unwrap();
assert_eq!(q.sql(), "SELECT e.\"content\", e.created_at FROM \"event\" e WHERE (e.pub_key in ($1) OR e.delegated_by in ($2)) AND e.kind in ($3) 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\" = $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_gen_tag_value_and_value_hex() {
let filter = ReqFilter {
ids: None,
kinds: Some(vec![1000]),
since: None,
until: None,
authors: Some(vec!["84de35e2584d2b144aae823c9ed0b0f3deda09648530b93d1a2a146d1dea9864".to_owned()]),
limit: None,
tags: Some(HashMap::from([
('d', HashSet::from(["test".to_owned(), "63fe6318dc58583cfe16810f86dd09e18bfd76aabc24a0081ce2856f330504ed".to_owned()]))
])),
force_no_match: false,
};
let q = query_from_filter(&filter).unwrap();
assert_eq!(q.sql(), "SELECT e.\"content\", e.created_at FROM \"event\" e WHERE (e.pub_key in ($1) OR e.delegated_by in ($2)) AND e.kind in ($3) 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\" = $4 AND (value in ($5) OR value_hex in ($6)))) 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")
}
}