headless_lms_models/
page_visit_datum_summary_by_courses.rs1use chrono::NaiveDate;
2
3use crate::prelude::*;
4
5#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
6#[cfg_attr(feature = "ts_rs", derive(TS))]
7pub struct PageVisitDatumSummaryByCourse {
8 pub id: Uuid,
9 pub created_at: DateTime<Utc>,
10 pub updated_at: DateTime<Utc>,
11 pub deleted_at: Option<DateTime<Utc>>,
12 pub course_id: Option<Uuid>,
13 pub exam_id: Option<Uuid>,
14 pub referrer: Option<String>,
15 pub utm_source: Option<String>,
16 pub utm_medium: Option<String>,
17 pub utm_campaign: Option<String>,
18 pub utm_term: Option<String>,
19 pub utm_content: Option<String>,
20 pub num_visitors: i32,
21 pub visit_date: NaiveDate,
22}
23
24pub async fn calculate_and_update_for_date(
26 conn: &mut PgConnection,
27 date: NaiveDate,
28) -> ModelResult<Vec<PageVisitDatumSummaryByCourse>> {
29 let res = sqlx::query_as!(
30 PageVisitDatumSummaryByCourse,
31 r#"
32INSERT INTO page_visit_datum_summary_by_courses (
33 course_id,
34 exam_id,
35 referrer,
36 utm_source,
37 utm_medium,
38 utm_campaign,
39 utm_term,
40 utm_content,
41 num_visitors,
42 visit_date
43 )
44SELECT
45 course_id,
46 exam_id,
47 referrer,
48 utm_source,
49 utm_medium,
50 utm_campaign,
51 utm_term,
52 utm_content,
53 COUNT(DISTINCT anonymous_identifier) AS num_visitors,
54 $1 AS visit_date
55FROM page_visit_datum
56WHERE deleted_at IS NULL
57 AND created_at::date = $1
58 AND is_bot = FALSE
59GROUP BY course_id,
60 exam_id,
61 referrer,
62 utm_source,
63 utm_medium,
64 utm_campaign,
65 utm_term,
66 utm_content
67 ON CONFLICT (
68 course_id,
69 exam_id,
70 referrer,
71 visit_date,
72 utm_source,
73 utm_medium,
74 utm_campaign,
75 utm_term,
76 utm_content,
77 deleted_at
78 ) DO
79UPDATE
80SET num_visitors = EXCLUDED.num_visitors
81RETURNING *
82"#,
83 date
84 )
85 .fetch_all(conn)
86 .await?;
87
88 Ok(res)
89}
90
91pub async fn get_latest_date(conn: &mut PgConnection) -> ModelResult<Option<NaiveDate>> {
93 let res = sqlx::query!(
94 r#"
95SELECT MAX(visit_date) AS latest_date
96FROM page_visit_datum_summary_by_courses
97WHERE deleted_at IS NULL
98"#,
99 )
100 .fetch_optional(conn)
101 .await?;
102
103 Ok(res.and_then(|r| r.latest_date))
104}
105
106pub async fn get_all_for_course(
107 conn: &mut PgConnection,
108 course_id: Uuid,
109) -> ModelResult<Vec<PageVisitDatumSummaryByCourse>> {
110 let res = sqlx::query_as!(
111 PageVisitDatumSummaryByCourse,
112 r#"
113SELECT *
114FROM page_visit_datum_summary_by_courses
115WHERE course_id = $1
116AND deleted_at IS NULL
117"#,
118 course_id
119 )
120 .fetch_all(conn)
121 .await?;
122
123 Ok(res)
124}