Skip to main content

systemprompt_analytics/repository/fingerprint/
queries.rs

1//! Fingerprint-reputation read queries for `FingerprintRepository`.
2//!
3//! Counts and finds reusable active sessions, and lists recent fingerprints
4//! for the abuse-analysis job. All reads go to the read pool.
5//!
6//! Copyright (c) systemprompt.io — Business Source License 1.1.
7//! See <https://systemprompt.io> for licensing details.
8
9use crate::Result;
10
11use super::FingerprintRepository;
12use crate::models::FingerprintReputation;
13use systemprompt_identifiers::{SessionId, UserId};
14
15impl FingerprintRepository {
16    pub async fn count_active_sessions(&self, fingerprint_hash: &str) -> Result<i32> {
17        self.sessions
18            .count_active_fingerprint_sessions(fingerprint_hash)
19            .await
20            .map_err(crate::AnalyticsError::from)
21    }
22
23    pub async fn find_reusable_session(&self, fingerprint_hash: &str) -> Result<Option<SessionId>> {
24        self.sessions
25            .find_reusable_fingerprint_session(fingerprint_hash)
26            .await
27            .map_err(crate::AnalyticsError::from)
28    }
29
30    pub async fn get_fingerprints_for_analysis(&self) -> Result<Vec<FingerprintReputation>> {
31        let rows = sqlx::query_as!(
32            FingerprintReputation,
33            r#"
34            SELECT
35                fingerprint_hash,
36                first_seen_at,
37                last_seen_at,
38                total_session_count,
39                active_session_count,
40                total_request_count,
41                requests_last_hour,
42                peak_requests_per_minute,
43                sustained_high_velocity_minutes,
44                is_flagged,
45                flag_reason,
46                flagged_at,
47                reputation_score,
48                abuse_incidents,
49                last_abuse_at,
50                last_ip_address,
51                last_user_agent,
52                associated_user_ids as "associated_user_ids: Vec<UserId>",
53                updated_at
54            FROM fingerprint_reputation
55            WHERE last_seen_at > CURRENT_TIMESTAMP - INTERVAL '1 hour'
56            ORDER BY total_request_count DESC
57            LIMIT 1000
58            "#,
59        )
60        .fetch_all(&*self.pool)
61        .await?;
62
63        Ok(rows)
64    }
65}