mirror of
https://github.com/block/buzz.git
synced 2026-11-01 23:11:58 +00:00
chore(db): delete unused user search
buzz_db::user::search_users, UserSearchProfile, and escape_like had no callers anywhere and no relay-facing surface; relay user search now goes through buzz-search contains mode. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1833,16 +1833,6 @@ impl Db {
|
||||
user::get_user_by_nip05(&self.pool, community_id, local_part, domain).await
|
||||
}
|
||||
|
||||
/// Search users by display name, NIP-05 handle, or pubkey prefix.
|
||||
pub async fn search_users(
|
||||
&self,
|
||||
community_id: CommunityId,
|
||||
query: &str,
|
||||
limit: u32,
|
||||
) -> Result<Vec<user::UserSearchProfile>> {
|
||||
user::search_users(&self.pool, community_id, query, limit).await
|
||||
}
|
||||
|
||||
/// Atomically set agent owner — only if no owner is currently assigned.
|
||||
/// Returns Ok(true) if set, Ok(false) if an owner already exists.
|
||||
pub async fn set_agent_owner(
|
||||
|
||||
@@ -20,19 +20,6 @@ pub struct UserProfile {
|
||||
pub nip05_handle: Option<String>,
|
||||
}
|
||||
|
||||
/// Lightweight user record returned from search.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct UserSearchProfile {
|
||||
/// Raw 32-byte compressed public key.
|
||||
pub pubkey: Vec<u8>,
|
||||
/// Human-readable display name chosen by the user.
|
||||
pub display_name: Option<String>,
|
||||
/// URL of the user's avatar image.
|
||||
pub avatar_url: Option<String>,
|
||||
/// NIP-05 identifier (user@domain).
|
||||
pub nip05_handle: Option<String>,
|
||||
}
|
||||
|
||||
/// Ensure a user record exists for the given pubkey (upsert).
|
||||
/// Creates with minimal fields if not present; no-op if already exists.
|
||||
///
|
||||
@@ -206,80 +193,6 @@ pub async fn get_user_by_nip05(
|
||||
))
|
||||
}
|
||||
|
||||
/// Escape SQL LIKE metacharacters (`%`, `_`, `\`) so user input is treated
|
||||
/// as literal text. Used with `ESCAPE '\'` in the query.
|
||||
///
|
||||
/// Without this, a search query of `"%"` would match every row (full table
|
||||
/// scan) and `"_"` would act as a single-character wildcard.
|
||||
fn escape_like(input: &str) -> String {
|
||||
input
|
||||
.replace('\\', "\\\\")
|
||||
.replace('%', "\\%")
|
||||
.replace('_', "\\_")
|
||||
}
|
||||
|
||||
/// Search users by display name, NIP-05 handle, or pubkey prefix.
|
||||
///
|
||||
/// Empty queries return an empty vec and do not hit the database.
|
||||
pub async fn search_users(
|
||||
pool: &PgPool,
|
||||
community_id: CommunityId,
|
||||
query: &str,
|
||||
limit: u32,
|
||||
) -> Result<Vec<UserSearchProfile>> {
|
||||
let normalized = query.trim().to_lowercase();
|
||||
if normalized.is_empty() {
|
||||
return Ok(Vec::new());
|
||||
}
|
||||
|
||||
let escaped = escape_like(&normalized);
|
||||
let contains_pattern = format!("%{escaped}%");
|
||||
let prefix_pattern = format!("{escaped}%");
|
||||
let limit = limit.clamp(1, 500) as i64;
|
||||
|
||||
let rows = sqlx::query_as::<_, (Vec<u8>, Option<String>, Option<String>, Option<String>)>(
|
||||
r#"
|
||||
SELECT pubkey, display_name, avatar_url, nip05_handle
|
||||
FROM users
|
||||
WHERE community_id = $1
|
||||
AND (LOWER(COALESCE(display_name, '')) LIKE $2 ESCAPE '\'
|
||||
OR LOWER(COALESCE(nip05_handle, '')) LIKE $2 ESCAPE '\'
|
||||
OR LOWER(encode(pubkey, 'hex')) LIKE $2 ESCAPE '\')
|
||||
ORDER BY
|
||||
CASE
|
||||
WHEN LOWER(COALESCE(display_name, '')) = $3 THEN 0
|
||||
WHEN LOWER(COALESCE(nip05_handle, '')) = $3 THEN 1
|
||||
WHEN LOWER(encode(pubkey, 'hex')) = $3 THEN 2
|
||||
WHEN LOWER(COALESCE(display_name, '')) LIKE $4 ESCAPE '\' THEN 3
|
||||
WHEN LOWER(COALESCE(nip05_handle, '')) LIKE $4 ESCAPE '\' THEN 4
|
||||
WHEN LOWER(encode(pubkey, 'hex')) LIKE $4 ESCAPE '\' THEN 5
|
||||
ELSE 6
|
||||
END,
|
||||
COALESCE(NULLIF(display_name, ''), NULLIF(nip05_handle, ''), LOWER(encode(pubkey, 'hex')))
|
||||
LIMIT $5
|
||||
"#,
|
||||
)
|
||||
.bind(community_id.as_uuid())
|
||||
.bind(&contains_pattern)
|
||||
.bind(&normalized)
|
||||
.bind(&prefix_pattern)
|
||||
.bind(limit)
|
||||
.fetch_all(pool)
|
||||
.await?;
|
||||
|
||||
Ok(rows
|
||||
.into_iter()
|
||||
.map(
|
||||
|(pubkey, display_name, avatar_url, nip05_handle)| UserSearchProfile {
|
||||
pubkey,
|
||||
display_name,
|
||||
avatar_url,
|
||||
nip05_handle,
|
||||
},
|
||||
)
|
||||
.collect())
|
||||
}
|
||||
|
||||
/// Set the owner pubkey for an agent user.
|
||||
/// The owner pubkey must already exist in the users table (FK constraint).
|
||||
/// Returns an error if the agent pubkey is not found (rows_affected == 0).
|
||||
@@ -612,40 +525,6 @@ mod tests {
|
||||
assert!(result.is_err(), "should reject invalid policy value");
|
||||
}
|
||||
|
||||
// Use the production `escape_like` function directly — no local mirror.
|
||||
use super::escape_like;
|
||||
|
||||
#[test]
|
||||
fn like_escape_percent() {
|
||||
assert_eq!(escape_like("%"), "\\%");
|
||||
assert_eq!(escape_like("100%match"), "100\\%match");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn like_escape_underscore() {
|
||||
assert_eq!(escape_like("_"), "\\_");
|
||||
assert_eq!(escape_like("a_b"), "a\\_b");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn like_escape_backslash() {
|
||||
assert_eq!(escape_like("\\"), "\\\\");
|
||||
assert_eq!(escape_like("a\\b"), "a\\\\b");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn like_escape_combined() {
|
||||
// All three metacharacters in one string
|
||||
assert_eq!(escape_like("%_\\"), "\\%\\_\\\\");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn like_escape_normal_input_unchanged() {
|
||||
assert_eq!(escape_like("alice"), "alice");
|
||||
assert_eq!(escape_like("bob@example.com"), "bob@example.com");
|
||||
assert_eq!(escape_like(""), "");
|
||||
}
|
||||
|
||||
/// A user with "owner_only" policy but no agent_owner_pubkey set should
|
||||
/// return Some(("owner_only", None)).
|
||||
#[tokio::test]
|
||||
|
||||
Reference in New Issue
Block a user