algohub_server/utils/
problem.rs1use 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}