systemprompt_analytics/repository/traffic/
mod.rs1mod audience;
13mod pages;
14
15use crate::Result;
16use chrono::{DateTime, Utc};
17use sqlx::PgPool;
18use std::sync::Arc;
19use systemprompt_database::DbPool;
20
21use crate::models::reporting::TrafficSourceRow;
22
23#[derive(Debug, Clone, Copy)]
24pub struct PageQuery<'a> {
25 pub start: DateTime<Utc>,
26 pub end: DateTime<Utc>,
27 pub limit: i64,
28 pub engaged_only: bool,
29 pub referrer: Option<&'a str>,
30 pub path_prefix: Option<&'a str>,
31}
32
33#[derive(Debug, Clone, Copy)]
34pub struct NavigationQuery<'a> {
35 pub start: DateTime<Utc>,
36 pub end: DateTime<Utc>,
37 pub limit: i64,
38 pub path_prefix: Option<&'a str>,
39 pub internal_only: bool,
40}
41
42#[derive(Debug)]
43pub struct TrafficAnalyticsRepository {
44 pool: Arc<PgPool>,
45}
46
47impl TrafficAnalyticsRepository {
48 pub fn new(db: &DbPool) -> Result<Self> {
49 let pool = db.pool_arc()?;
50 Ok(Self { pool })
51 }
52
53 pub async fn get_sources(
54 &self,
55 start: DateTime<Utc>,
56 end: DateTime<Utc>,
57 limit: i64,
58 engaged_only: bool,
59 ) -> Result<Vec<TrafficSourceRow>> {
60 if engaged_only {
61 sqlx::query_as!(
62 TrafficSourceRow,
63 r#"
64 SELECT
65 COALESCE(referrer_source, 'direct') as "source",
66 COUNT(*)::bigint as "count!"
67 FROM v_engaged_traffic
68 WHERE started_at >= $1 AND started_at < $2
69 GROUP BY referrer_source
70 ORDER BY COUNT(*) DESC
71 LIMIT $3
72 "#,
73 start,
74 end,
75 limit
76 )
77 .fetch_all(&*self.pool)
78 .await
79 .map_err(Into::into)
80 } else {
81 sqlx::query_as!(
82 TrafficSourceRow,
83 r#"
84 SELECT
85 COALESCE(referrer_source, 'direct') as "source",
86 COUNT(*)::bigint as "count!"
87 FROM v_clean_traffic
88 WHERE started_at >= $1 AND started_at < $2
89 GROUP BY referrer_source
90 ORDER BY COUNT(*) DESC
91 LIMIT $3
92 "#,
93 start,
94 end,
95 limit
96 )
97 .fetch_all(&*self.pool)
98 .await
99 .map_err(Into::into)
100 }
101 }
102}