Skip to main content

headless_lms_credit_registration/use_cases/
ledger_snapshot.rs

1//! The `ledger-snapshot` phase: the day's queue depth for every ledger state, every timeline step
2//! and the Needs attention count.
3
4use chrono::{DateTime, Duration, NaiveTime, Utc};
5use headless_lms_models::credit_registration_daily_snapshots::{
6    count_states_for_day, write_attention_snapshot_for_date, write_snapshot_for_date,
7    write_step_snapshot_for_date,
8};
9use headless_lms_models::credit_registrations::{
10    count_by_step_and_engagement, count_needing_attention,
11};
12use sqlx::PgPool;
13
14use crate::attention::attention_rules;
15use crate::error::CreditRegistrationResult;
16use crate::workflow::Counts;
17
18/// Its own phase rather than folded into `config-validation`'s per-module check: a scoped run must
19/// never write a snapshot that claims to cover every course, and `ScopeSupport::NONE` only enforces
20/// that if the write has no other job sharing its dispatch.
21pub(crate) async fn run(
22    pool: &PgPool,
23    account_linking_since: Option<DateTime<Utc>>,
24) -> CreditRegistrationResult<Counts> {
25    let mut conn = pool.acquire().await?;
26    let today = Utc::now().date_naive();
27    let day_start = today.and_time(NaiveTime::MIN).and_utc();
28    let counts = count_states_for_day(&mut conn, day_start, day_start + Duration::days(1)).await?;
29    write_snapshot_for_date(&mut conn, today, &counts).await?;
30    let step_counts = count_by_step_and_engagement(&mut conn, account_linking_since).await?;
31    write_step_snapshot_for_date(&mut conn, today, &step_counts).await?;
32    let rules = attention_rules(&mut conn, account_linking_since).await?;
33    let needs_attention_count = count_needing_attention(&mut conn, &rules).await?;
34    write_attention_snapshot_for_date(&mut conn, today, needs_attention_count).await?;
35    Ok(Counts::processed(counts.len() as i64))
36}