algohub_server/utils/
problem.rs

1use anyhow::Result;
2use serde::Deserialize;
3use surrealdb::{engine::remote::ws::Client, sql::Thing, Surreal};
4
5use crate::models::problem::{CreateProblem, Problem, ServerTestCase};
6
7pub async fn create(db: &Surreal<Client>, problem: CreateProblem<'_>) -> Result<Option<Problem>> {
8    Ok(db
9        .create("problem")
10        .content(Into::<Problem>::into(problem))
11        .await?)
12}
13
14pub async fn update(
15    db: &Surreal<Client>,
16    id: &str,
17    problem: CreateProblem<'_>,
18) -> Result<Option<Problem>> {
19    Ok(db
20        .update(("problem", id))
21        .content(Into::<Problem>::into(problem))
22        .await?)
23}
24
25const DELETE_ALL_ASSETS_QUERY: &str = r#"
26IF $problem.exists() {
27    FOR $asset IN (SELECT VALUE test_cases FROM $problem) {
28        DELETE $asset.input, $asset.output;
29    };
30    (DELETE ONLY $problem RETURN BEFORE)
31}
32"#;
33pub async fn delete(db: &Surreal<Client>, id: &str) -> Result<Option<Problem>> {
34    Ok(db
35        .query(DELETE_ALL_ASSETS_QUERY)
36        .bind(("problem", Thing::from(("problem", id))))
37        .await?
38        .take(0)?)
39}
40
41pub async fn get<M>(db: &Surreal<Client>, id: &str) -> Result<Option<M>>
42where
43    for<'de> M: Deserialize<'de>,
44{
45    Ok(db.select(("problem", id)).await?)
46}
47
48const LIST_QUERY: &str = r#"
49IF $authed THEN
50    IF $limit THEN
51        SELECT * FROM problem WHERE owner = type::thing("account", $id) LIMIT $limit
52    ELSE
53        SELECT * FROM problem WHERE owner = type::thing("account", $id)
54    END;
55ELSE
56    IF $limit THEN
57        SELECT * FROM problem WHERE owner = type::thing("account", $id) AND private = false LIMIT $limit
58    ELSE
59        SELECT * FROM problem WHERE owner = type::thing("account", $id) AND private = false
60    END;
61END;"#;
62
63pub async fn list_for_account<M>(
64    db: &Surreal<Client>,
65    account_id: Option<String>,
66    authed_id: Option<String>,
67    limit: Option<u32>,
68) -> Result<Vec<M>>
69where
70    for<'de> M: Deserialize<'de>,
71{
72    let mut response = db
73        .query(LIST_QUERY)
74        .bind((
75            "authed",
76            authed_id.is_some() && account_id.is_some() && authed_id == account_id,
77        ))
78        .bind(("id", account_id))
79        .bind(("limit", limit))
80        .await?;
81
82    Ok(response.take(0)?)
83}
84
85const SELECT_TEST_CASES_QUERY: &str = r#"
86IF $problem.exists() THEN
87    SELECT input.path AS input, output.path AS output FROM $problem.test_cases
88ELSE
89    []
90END;
91"#;
92pub async fn get_test_cases_by_id(db: &Surreal<Client>, id: &str) -> Result<Vec<ServerTestCase>> {
93    Ok(db
94        .query(SELECT_TEST_CASES_QUERY)
95        .bind(("problem", Thing::from(("problem", id))))
96        .await?
97        .take(0)?)
98}