systemprompt_analytics/repository/fingerprint/
queries.rs1use 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}