leetcode_api/leetcode/question/
qs_detail.rs

1use std::fmt::Display;
2
3use sea_orm::sea_query::{self, OnConflict};
4use serde::{Deserialize, Serialize};
5
6use self::question::*;
7use crate::{dao::InsertToDB, entities::detail};
8
9#[derive(Clone)]
10#[derive(Debug)]
11#[derive(Default)]
12#[derive(PartialEq, Eq)]
13#[derive(Serialize, Deserialize)]
14pub struct QuestionData {
15    #[serde(default)]
16    pub data: Detail,
17}
18#[derive(Clone)]
19#[derive(Debug)]
20#[derive(Default)]
21#[derive(PartialEq, Eq)]
22#[derive(Serialize, Deserialize)]
23pub struct Detail {
24    #[serde(default)]
25    pub question: Question,
26}
27
28/// this field all from
29/// `String`(json from leetcode website) ->
30/// `Struct`(`Question` field) ->
31/// `String`(database store for correct deserialize to `Question` field)
32macro_rules! my_serde {
33    ($($struct_name:ident),*) => {
34        paste::paste! {
35            $(
36                mod [<$struct_name:snake:lower _serde>] {
37                    use serde::{Deserialize, Deserializer, Serializer};
38
39                    use super::question::$struct_name;
40
41                    pub fn deserialize<'de, D>(deserializer: D) -> Result<$struct_name, D::Error>
42                    where
43                        D: Deserializer<'de>,
44                    {
45                        let s = String::deserialize(deserializer)?;
46
47                        Ok(serde_json::from_str(&s).unwrap_or_default())
48                    }
49
50                    pub fn serialize<S>(v: &$struct_name, serializer: S) -> Result<S::Ok, S::Error>
51                    where
52                        S: Serializer,
53                    {
54                        let a = serde_json::to_string(v).unwrap_or_default();
55
56                        serializer.serialize_str(&a)
57                    }
58                }
59            )*
60        }
61    };
62}
63my_serde!(MetaData, Stats, EnvInfo);
64
65/// a question's detail
66#[derive(Clone)]
67#[derive(Debug)]
68#[derive(Default)]
69#[derive(PartialEq, Eq)]
70#[derive(Serialize, Deserialize)]
71pub struct Question {
72    #[serde(default)]
73    pub qs_slug: Option<String>,
74    #[serde(default)]
75    pub content: Option<String>,
76    #[serde(default, with = "stats_serde")]
77    pub stats: Stats,
78    #[serde(default, alias = "sampleTestCase")]
79    pub sample_test_case: String,
80    #[serde(default, alias = "exampleTestcases")]
81    pub example_testcases: String,
82    #[serde(default, alias = "metaData", with = "meta_data_serde")]
83    pub meta_data: MetaData,
84    #[serde(default, alias = "translatedTitle")]
85    pub translated_title: Option<String>,
86    #[serde(default, alias = "translatedContent")]
87    pub translated_content: Option<String>,
88    #[serde(default)]
89    pub hints: Vec<String>,
90    #[serde(default, alias = "mysqlSchemas")]
91    pub mysql_schemas: Vec<String>,
92    #[serde(default, alias = "dataSchemas")]
93    pub data_schemas: Vec<String>,
94    #[serde(default, alias = "questionId")]
95    pub question_id: String,
96    #[serde(default, alias = "questionTitle")]
97    pub question_title: Option<String>,
98    #[serde(default, alias = "isPaidOnly")]
99    pub is_paid_only: bool,
100    #[serde(default, alias = "codeSnippets")]
101    pub code_snippets: Option<Vec<CodeSnippet>>,
102    #[serde(default)]
103    pub title: String,
104    #[serde(default)]
105    pub difficulty: String,
106    #[serde(default, alias = "topicTags")]
107    pub topic_tags: Vec<TopicTags>,
108    #[serde(default, alias = "enableRunCode")]
109    pub enable_run_code: bool,
110    #[serde(default, alias = "envInfo", with = "env_info_serde")]
111    pub env_info: EnvInfo,
112}
113
114impl Question {
115    pub fn new_with_info<D: Display>(content: D) -> Self {
116        Self {
117            content: Some(content.to_string()),
118            ..Default::default()
119        }
120    }
121}
122
123impl InsertToDB for Question {
124    type Value = u32;
125    type Entity = detail::Entity;
126    type Model = detail::Model;
127    type ActiveModel = detail::ActiveModel;
128
129    fn to_model(&self, question_id: Self::Value) -> Self::Model {
130        Self::Model {
131            id: question_id,
132            content: serde_json::to_string(self).unwrap_or_default(),
133        }
134    }
135    fn on_conflict() -> OnConflict {
136        sea_query::OnConflict::column(detail::Column::Id)
137            .update_columns([detail::Column::Id, detail::Column::Content])
138            .to_owned()
139    }
140}
141
142pub mod question {
143    use std::fmt::Display;
144
145    use serde::{Deserialize, Serialize};
146
147    macro_rules! env_info_macro {
148        ($($lang_name:ident),*) => {
149            #[derive(Clone)]
150            #[derive(Debug)]
151            #[derive(Default)]
152            #[derive(PartialEq, Eq)]
153            #[derive(Serialize, Deserialize)]
154            pub struct EnvInfo {
155                $(
156                    #[serde(default)]
157                    $lang_name : Vec<String>,
158                )*
159            }
160            impl Display for EnvInfo {
161                fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
162                    let mut res = String::new();
163                    $(
164                        if !self.$lang_name.is_empty() {
165                            let pat = format!("\n### {}", format_args!("{}\n", self.$lang_name.join("\n")));
166                            res.push_str(&pat);
167                        }
168                    )*
169                    res.fmt(f)
170                }
171            }
172        };
173    }
174    env_info_macro!(
175        bash, c, cpp, csharp, dart, elixir, erlang, golang, java, javascript, kotlin, mssql, mysql,
176        oraclesql, postgresql, php, python, python3, pythondata, pythonml, racket, react, ruby,
177        rust, scala, swift, typescript
178    );
179
180    #[derive(Clone)]
181    #[derive(Debug)]
182    #[derive(Default)]
183    #[derive(PartialEq, Eq)]
184    #[derive(Serialize, Deserialize)]
185    pub struct Stats {
186        #[serde(alias = "totalAccepted")]
187        pub total_accepted: String,
188        #[serde(alias = "totalSubmission")]
189        pub total_submission: String,
190        #[serde(alias = "totalAcceptedRaw")]
191        pub total_accepted_raw: usize,
192        #[serde(alias = "totalSubmissionRaw")]
193        pub total_submission_raw: usize,
194        #[serde(alias = "acRate")]
195        pub ac_rate: String,
196    }
197    /// metadata
198    #[derive(Clone)]
199    #[derive(Debug)]
200    #[derive(Default)]
201    #[derive(PartialEq, Eq)]
202    #[derive(Serialize, Deserialize)]
203    pub struct MetaData {
204        #[serde(default)]
205        pub name: String,
206        #[serde(default)]
207        pub params: Vec<Param>,
208        #[serde(default)]
209        pub r#return: Return,
210    }
211
212    /// nest field
213    #[derive(Clone)]
214    #[derive(Debug)]
215    #[derive(Default)]
216    #[derive(PartialEq, Eq)]
217    #[derive(Serialize, Deserialize)]
218    pub struct Param {
219        #[serde(default)]
220        pub name: String,
221        #[serde(default)]
222        pub r#type: String,
223        // pub dealloc: bool,
224    }
225
226    /// nest field
227    #[derive(Clone)]
228    #[derive(Debug)]
229    #[derive(Default)]
230    #[derive(PartialEq, Eq)]
231    #[derive(Serialize, Deserialize)]
232    pub struct Return {
233        #[serde(default)]
234        pub r#type: String,
235        // pub dealloc: bool,
236    }
237
238    #[derive(Clone)]
239    #[derive(Debug)]
240    #[derive(Default)]
241    #[derive(PartialEq, Eq)]
242    #[derive(Serialize, Deserialize)]
243    /// language and it's snippet
244    pub struct CodeSnippet {
245        #[serde(default)]
246        pub lang: String,
247        #[serde(default, alias = "langSlug")]
248        pub lang_slug: String,
249        #[serde(default)]
250        pub code: String,
251    }
252
253    #[derive(Clone)]
254    #[derive(Debug)]
255    #[derive(Default)]
256    #[derive(PartialEq, Eq)]
257    #[derive(Serialize, Deserialize)]
258    pub struct TopicTags {
259        #[serde(default)]
260        pub name: String,
261        #[serde(default)]
262        pub slug: String,
263        #[serde(default, alias = "translatedName")]
264        pub translated_name: Option<String>,
265    }
266}