prisma_rust_schema/
annotation.rs

1use std::str::FromStr;
2
3use proc_macro2::TokenStream;
4use quote::ToTokens;
5
6#[derive(Debug, Default)]
7pub struct FieldAnnotation {
8    /// What to rename the field to
9    pub rename: Option<String>,
10    /// Whether to skip this field
11    pub skip: bool,
12    /// The Rust type of the field to overwrite to
13    pub type_: Option<String>,
14    /// The visibility of the field
15    pub visibility: Visibility,
16}
17
18#[derive(Debug, Default)]
19pub struct ModelAnnotation {
20    pub derive: Option<Vec<String>>,
21    pub rename: Option<String>,
22    pub skip: bool,
23    pub visibility: Visibility,
24}
25
26#[derive(Debug, Default)]
27pub struct EnumAnnotation {
28    pub derive: Option<Vec<String>>,
29    pub rename: Option<String>,
30    pub skip: bool,
31    pub visibility: Visibility,
32}
33
34#[derive(Debug, Default)]
35pub struct EnumValueAnnotation {
36    pub rename: Option<String>,
37    pub skip: bool,
38}
39
40#[derive(Debug, Default)]
41pub struct TypeAnnotation {
42    pub derive: Option<Vec<String>>,
43    pub rename: Option<String>,
44    pub skip: bool,
45    /// The Rust type of the field to overwrite to
46    pub type_: Option<String>,
47    pub visibility: Visibility,
48}
49
50#[derive(Debug, Clone, Copy)]
51pub enum Visibility {
52    /// Visible to all
53    /// i.e. `pub`
54    Public,
55    /// Not visible
56    Private,
57    /// Visible to the current module and its descendants
58    /// (i.e. `pub(crate)`)
59    Protected,
60}
61
62impl Default for Visibility {
63    fn default() -> Self {
64        Visibility::Public
65    }
66}
67
68impl ToTokens for Visibility {
69    fn to_tokens(&self, tokens: &mut TokenStream) {
70        match self {
71            Visibility::Public => quote::quote! { pub }.to_tokens(tokens),
72            Visibility::Private => quote::quote! {}.to_tokens(tokens),
73            Visibility::Protected => quote::quote! { pub(crate) }.to_tokens(tokens),
74        }
75    }
76}
77
78impl FromStr for FieldAnnotation {
79    type Err = String;
80
81    fn from_str(s: &str) -> Result<Self, Self::Err> {
82        let mut skip = false;
83        let mut rename = None;
84        let mut visibility = Visibility::default();
85        let mut type_ = None;
86
87        for line in s.lines() {
88            if line.trim().starts_with("@prs.") {
89                let func = line.trim_start_matches("@prs.");
90                let (op, val) = func.split_once('=').unwrap_or((func, "true"));
91
92                match op.trim() {
93                    "skip" => {
94                        skip = val.trim() != "false";
95                    }
96                    "type" => {
97                        type_ = Some(val.trim().to_string());
98                    }
99                    "rename" => {
100                        rename = Some(val.trim().to_string());
101                    }
102                    "visibility" => {
103                        visibility = match val.trim() {
104                            "private" => Visibility::Private,
105                            "protected" => Visibility::Protected,
106                            "public" => Visibility::Public,
107                            _ => {
108                                return Err(format!(
109                                    "Unknown visibility: {}
110Available options: private, protected (pub(crate)), public (pub)",
111                                    val
112                                ));
113                            }
114                        };
115                    }
116                    _ => {
117                        return Err(format!("Unknown field annotation: {}", func));
118                    }
119                }
120            }
121        }
122
123        Ok(FieldAnnotation {
124            rename,
125            skip,
126            type_,
127            visibility,
128        })
129    }
130}
131
132impl From<String> for FieldAnnotation {
133    fn from(s: String) -> Self {
134        FieldAnnotation::from_str(&s).unwrap_or_default()
135    }
136}
137impl From<&String> for FieldAnnotation {
138    fn from(s: &String) -> Self {
139        FieldAnnotation::from_str(s).unwrap_or_default()
140    }
141}
142
143impl FromStr for ModelAnnotation {
144    type Err = String;
145
146    fn from_str(s: &str) -> Result<Self, Self::Err> {
147        let mut skip = false;
148        let mut rename = None;
149        let mut visibility = Visibility::default();
150        let mut derive = None;
151
152        for line in s.lines() {
153            if line.trim().starts_with("@prs.") {
154                let func = line.trim_start_matches("@prs.");
155                let (op, val) = func.split_once('=').unwrap_or((func, "true"));
156
157                match op.trim() {
158                    "skip" => {
159                        skip = val.trim() != "false";
160                    }
161                    "rename" => {
162                        rename = Some(val.trim().to_string());
163                    }
164                    "visibility" => {
165                        visibility = match val.trim() {
166                            "private" => Visibility::Private,
167                            "protected" => Visibility::Protected,
168                            "public" => Visibility::Public,
169                            _ => {
170                                return Err(format!(
171                                    "Unknown visibility: {}
172Available options: private, protected (pub(crate)), public (pub)",
173                                    val
174                                ));
175                            }
176                        };
177                    }
178                    "derive" => {
179                        let derive_str = val.trim();
180                        if derive_str.is_empty() {
181                            return Err("Derive cannot be empty".to_string());
182                        }
183                        derive = Some(
184                            derive_str
185                                .split(',')
186                                .map(|s| s.trim().to_string())
187                                .collect(),
188                        );
189                    }
190                    _ => {
191                        return Err(format!("Unknown field annotation: {}", func));
192                    }
193                }
194            }
195        }
196
197        Ok(ModelAnnotation {
198            skip,
199            rename,
200            visibility,
201            derive,
202        })
203    }
204}
205
206impl From<String> for ModelAnnotation {
207    fn from(s: String) -> Self {
208        ModelAnnotation::from_str(&s).unwrap_or_default()
209    }
210}
211impl From<&String> for ModelAnnotation {
212    fn from(s: &String) -> Self {
213        ModelAnnotation::from_str(s).unwrap_or_default()
214    }
215}
216
217impl FromStr for EnumAnnotation {
218    type Err = String;
219
220    fn from_str(s: &str) -> Result<Self, Self::Err> {
221        let mut skip = false;
222        let mut rename = None;
223        let mut visibility = Visibility::default();
224        let mut derive = None;
225
226        for line in s.lines() {
227            if line.trim().starts_with("@prs.") {
228                let func = line.trim_start_matches("@prs.");
229                let (op, val) = func.split_once('=').unwrap_or((func, "true"));
230
231                match op.trim() {
232                    "skip" => {
233                        skip = val.trim() != "false";
234                    }
235                    "rename" => {
236                        rename = Some(val.trim().to_string());
237                    }
238                    "visibility" => {
239                        visibility = match val.trim() {
240                            "private" => Visibility::Private,
241                            "protected" => Visibility::Protected,
242                            "public" => Visibility::Public,
243                            _ => {
244                                return Err(format!(
245                                    "Unknown visibility: {}
246Available options: private, protected (pub(crate)), public (pub)",
247                                    val
248                                ));
249                            }
250                        };
251                    }
252                    "derive" => {
253                        let derive_str = val.trim();
254                        if derive_str.is_empty() {
255                            return Err("Derive cannot be empty".to_string());
256                        }
257                        derive = Some(
258                            derive_str
259                                .split(',')
260                                .map(|s| s.trim().to_string())
261                                .collect(),
262                        );
263                    }
264                    _ => {
265                        return Err(format!("Unknown field annotation: {}", func));
266                    }
267                }
268            }
269        }
270
271        Ok(EnumAnnotation {
272            skip,
273            rename,
274            visibility,
275            derive,
276        })
277    }
278}
279
280impl From<String> for EnumAnnotation {
281    fn from(s: String) -> Self {
282        EnumAnnotation::from_str(&s).unwrap_or_default()
283    }
284}
285impl From<&String> for EnumAnnotation {
286    fn from(s: &String) -> Self {
287        EnumAnnotation::from_str(s).unwrap_or_default()
288    }
289}
290
291impl FromStr for TypeAnnotation {
292    type Err = String;
293
294    fn from_str(s: &str) -> Result<Self, Self::Err> {
295        let mut skip = false;
296        let mut rename = None;
297        let mut visibility = Visibility::default();
298        let mut derive = None;
299        let mut type_ = None;
300
301        for line in s.lines() {
302            if line.trim().starts_with("@prs.") {
303                let func = line.trim_start_matches("@prs.");
304                let (op, val) = func.split_once('=').unwrap_or((func, "true"));
305
306                match op.trim() {
307                    "skip" => {
308                        skip = val.trim() != "false";
309                    }
310                    "type" => {
311                        type_ = Some(val.trim().to_string());
312                    }
313                    "rename" => {
314                        rename = Some(val.trim().to_string());
315                    }
316                    "visibility" => {
317                        visibility = match val.trim() {
318                            "private" => Visibility::Private,
319                            "protected" => Visibility::Protected,
320                            "public" => Visibility::Public,
321                            _ => {
322                                return Err(format!(
323                                    "Unknown visibility: {}
324Available options: private, protected (pub(crate)), public (pub)",
325                                    val
326                                ));
327                            }
328                        };
329                    }
330                    "derive" => {
331                        let derive_str = val.trim();
332                        if derive_str.is_empty() {
333                            return Err("Derive cannot be empty".to_string());
334                        }
335                        derive = Some(
336                            derive_str
337                                .split(',')
338                                .map(|s| s.trim().to_string())
339                                .collect(),
340                        );
341                    }
342                    _ => {
343                        return Err(format!("Unknown field annotation: {}", func));
344                    }
345                }
346            }
347        }
348
349        Ok(TypeAnnotation {
350            derive,
351            rename,
352            skip,
353            type_,
354            visibility,
355        })
356    }
357}
358
359impl From<String> for TypeAnnotation {
360    fn from(s: String) -> Self {
361        TypeAnnotation::from_str(&s).unwrap_or_default()
362    }
363}
364impl From<&String> for TypeAnnotation {
365    fn from(s: &String) -> Self {
366        TypeAnnotation::from_str(s).unwrap_or_default()
367    }
368}
369
370impl FromStr for EnumValueAnnotation {
371    type Err = String;
372
373    fn from_str(s: &str) -> Result<Self, Self::Err> {
374        let mut skip = false;
375        let mut rename = None;
376
377        for line in s.lines() {
378            if line.trim().starts_with("@prs.") {
379                let func = line.trim_start_matches("@prs.");
380                let (op, val) = func.split_once('=').unwrap_or((func, "true"));
381
382                match op.trim() {
383                    "skip" => {
384                        skip = val.trim() != "false";
385                    }
386                    "rename" => {
387                        rename = Some(val.trim().to_string());
388                    }
389                    _ => {
390                        return Err(format!("Unknown field annotation: {}", func));
391                    }
392                }
393            }
394        }
395
396        Ok(EnumValueAnnotation { skip, rename })
397    }
398}
399
400impl From<String> for EnumValueAnnotation {
401    fn from(s: String) -> Self {
402        EnumValueAnnotation::from_str(&s).unwrap_or_default()
403    }
404}
405impl From<&String> for EnumValueAnnotation {
406    fn from(s: &String) -> Self {
407        EnumValueAnnotation::from_str(s).unwrap_or_default()
408    }
409}