1use pest::iterators::Pair;
3use crate::ast::*;
4use crate::{Rule, SchemaParser};
5use pest::Parser;
6
7pub fn parse_schema(src: &str) -> Result<Schema, String> {
8 SchemaParser::parse(Rule::schema, src)
9 .map_err(|e| format!("Parse error: {}", e))
10 .and_then(|mut pairs| {
11 let schema_pair = pairs.next().ok_or("Empty schema")?;
12 Ok(build_ast(schema_pair))
13 })
14}
15
16pub(crate) fn build_ast(pair: Pair<Rule>) -> Schema {
17 let mut models = Vec::new();
18 for inner in pair.into_inner() {
19 match inner.as_rule() {
20 Rule::model_decl => models.push(parse_model(inner)),
21 _ => (),
22 }
23 }
24 Schema { models }
25}
26
27fn parse_model(pair: Pair<Rule>) -> Model {
28 let mut pairs = pair.into_inner();
29 let name = pairs.next().unwrap().as_str().to_string();
30 let mut fields = Vec::new();
31 for pair in pairs {
32 if matches!(pair.as_rule(), Rule::field_decl) {
33 fields.push(parse_field(pair));
34 }
35 }
36 Model { name, fields }
37}
38
39fn parse_field(pair: Pair<Rule>) -> Field {
40 let mut pairs = pair.into_inner();
41 let name = pairs.next().unwrap().as_str().to_string();
42 let mut raw_type_name = pairs.next().unwrap().as_str().to_string();
43
44 let mut modifiers = Vec::new();
45 let mut attributes = Vec::new();
46
47 let mut is_nullable = false;
48 if raw_type_name.ends_with('?') {
49 is_nullable = true;
50 raw_type_name = raw_type_name.trim_end_matches('?').to_string();
51 }
52
53 for pair in pairs {
54 match pair.as_rule() {
55 Rule::modifier => {
56 if let Ok(m) = parse_modifier(pair) {
57 modifiers.push(m);
58 }
59 }
60 Rule::attr => attributes.push(parse_attribute(pair)),
61 _ => (),
62 }
63 }
64
65 if is_nullable {
66 modifiers.push(Modifier::Nullable);
67 } else if !modifiers.iter().any(|m| matches!(m, Modifier::NotNull | Modifier::PrimaryKey)) {
68 modifiers.push(Modifier::NotNull);
69 }
70
71 Field {
72 name,
73 type_name: raw_type_name,
74 modifiers,
75 attributes,
76 }
77}
78
79fn parse_modifier(pair: Pair<Rule>) -> Result<Modifier, String> {
80 let mut inner = pair.into_inner();
81 let mod_name = inner.next().unwrap().as_str();
82 let args = inner.next().map(|p| {
83 p.into_inner()
84 .next()
85 .map(|ac| ac.as_str().trim().to_string())
86 .unwrap_or_default()
87 });
88
89 match mod_name {
90 "PrimaryKey" => Ok(Modifier::PrimaryKey),
91 "NotNull" => Ok(Modifier::NotNull),
92 "Nullable" => Ok(Modifier::Nullable),
93 "Unique" => Ok(Modifier::Unique),
94 "ForeignKey" => parse_foreign_key(args),
95 _ => Err(format!("Unknown modifier: {}", mod_name)),
96 }
97}
98
99fn parse_foreign_key(args: Option<String>) -> Result<Modifier, String> {
100 let arg_str = args.ok_or("ForeignKey requires arguments")?;
101
102 if let Some(dot_pos) = arg_str.find('.') {
103 let model = arg_str[..dot_pos].trim().to_string();
104 let field = arg_str[dot_pos + 1..].trim().to_string();
105 return Ok(Modifier::ForeignKey {
106 model,
107 field: Some(field),
108 });
109 }
110
111 if let Some(paren_pos) = arg_str.find('(') {
112 let model = arg_str[..paren_pos].trim().to_string();
113 if let Some(close_pos) = arg_str.find(')') {
114 let field = arg_str[paren_pos + 1..close_pos].trim().to_string();
115 return Ok(Modifier::ForeignKey {
116 model,
117 field: Some(field),
118 });
119 }
120 }
121
122 Ok(Modifier::ForeignKey {
123 model: arg_str,
124 field: None,
125 })
126}
127
128fn parse_attribute(pair: Pair<Rule>) -> Attribute {
129 let mut inner = pair.into_inner();
130 let name = inner.next().unwrap().as_str().to_string();
131 let args = inner.next().map(|p| {
132 p.as_str().to_string()
133 });
134 Attribute { name, args }
135}
136