algohub_server/utils/
contest.rs

1use anyhow::Result;
2use surrealdb::{engine::remote::ws::Client, sql::Thing, Surreal};
3
4use crate::models::contest::{Contest, ContestData, ContestProblem};
5
6pub async fn create(
7    db: &Surreal<Client>,
8    creator_id: &str,
9    contest: ContestData,
10) -> Result<Option<Contest>> {
11    Ok(db
12        .create("contest")
13        .content(Contest {
14            id: None,
15            name: contest.name.to_string(),
16            mode: contest.mode,
17            visibility: contest.visibility,
18            description: contest.description,
19            announcement: None,
20            start_time: contest.start_time,
21            end_time: contest.end_time,
22            owner: contest.owner.clone().into(),
23            creator: ("account", creator_id).into(),
24            updaters: vec![("account", creator_id).into()],
25            participants: vec![],
26            created_at: chrono::Utc::now().naive_utc(),
27            updated_at: chrono::Utc::now().naive_utc(),
28        })
29        .await?)
30}
31
32pub async fn get(db: &Surreal<Client>, id: &str) -> Result<Option<Contest>> {
33    Ok(db.select(("contest", id)).await?)
34}
35
36pub async fn list_all(db: &Surreal<Client>) -> Result<Vec<Contest>> {
37    Ok(db.query("SELECT * FROM contest").await?.take(0)?)
38}
39
40pub async fn list_by_owner(db: &Surreal<Client>, id: &str) -> Result<Vec<Contest>> {
41    Ok(db
42        .query("SELECT * FROM contest WHERE record::id(owner) = $id")
43        .bind(("id", id.to_string()))
44        .await?
45        .take(0)?)
46}
47
48const ADD_PROBLEM: &str = r#"
49UPDATE type::thing("contest", $id)
50SET problems = array::union(problems, $problems);
51"#;
52pub async fn add_problems(
53    db: &Surreal<Client>,
54    id: String,
55    problems: Vec<Thing>,
56) -> Result<Option<Contest>> {
57    Ok(db
58        .query(ADD_PROBLEM)
59        .bind(("id", id))
60        .bind(("problems", problems))
61        .await?
62        .take(0)?)
63}
64
65const LIST_PROBLEMS: &str = r#"
66SELECT title, record::id(id) AS id, count(
67    SELECT VALUE true
68    FROM submission WHERE record::id(creator) == $account_id AND problem == $parent.id
69    AND judge_result.status.type == "accepted"
70) > 0 AS solved,
71count(
72    SELECT record::id(creator) FROM submission WHERE problem == $parent.id
73) AS submittedCount,
74count(
75    SELECT record::id(creator)
76    FROM submission WHERE problem == $parent.id
77    AND judge_result.status.type == "accepted"
78) AS acceptedCount
79FROM type::thing("contest", $id).problems;
80"#;
81pub async fn list_problems(
82    db: &Surreal<Client>,
83    id: &str,
84    account_id: &str,
85) -> Result<Vec<ContestProblem>> {
86    Ok(db
87        .query(LIST_PROBLEMS)
88        .bind(("id", id.to_string()))
89        .bind(("account_id", account_id.to_string()))
90        .await?
91        .take(0)?)
92}
93
94const REMOVE_PROBLEM: &str =
95    "UPDATE contest SET problems -= type::thing(\"problem\", $problem) WHERE record::id(id) = $id";
96pub async fn remove_problem(
97    db: &Surreal<Client>,
98    id: String,
99    problem: Thing,
100) -> Result<Option<Contest>> {
101    Ok(db
102        .query(REMOVE_PROBLEM)
103        .bind(("id", id))
104        .bind(("problem", problem))
105        .await?
106        .take(0)?)
107}