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 type_name = pairs.next().unwrap().as_str().to_string();
43
44 let mut modifiers = Vec::new();
45 let mut attributes = Vec::new();
46
47 for pair in pairs {
48 match pair.as_rule() {
49 Rule::modifier => {
50 if let Ok(m) = parse_modifier(pair) {
51 modifiers.push(m);
52 }
53 }
54 Rule::attr => attributes.push(parse_attribute(pair)),
55 _ => (),
56 }
57 }
58
59 Field { name, type_name, modifiers, attributes }
60}
61
62fn parse_modifier(pair: Pair<Rule>) -> Result<Modifier, String> {
63 let mut inner = pair.into_inner();
64 let mod_name = inner.next().unwrap().as_str();
65 let args = inner.next().map(|p| {
66 p.into_inner()
67 .next()
68 .map(|ac| ac.as_str().trim().to_string())
69 .unwrap_or_default()
70 });
71
72 match mod_name {
73 "PrimaryKey" => Ok(Modifier::PrimaryKey),
74 "NotNull" => Ok(Modifier::NotNull),
75 "Nullable" => Ok(Modifier::Nullable),
76 "Unique" => Ok(Modifier::Unique),
77 "ForeignKey" => parse_foreign_key(args),
78 _ => Err(format!("Unknown modifier: {}", mod_name)),
79 }
80}
81
82fn parse_foreign_key(args: Option<String>) -> Result<Modifier, String> {
83 let arg_str = args.ok_or("ForeignKey requires arguments")?;
84
85 if let Some(dot_pos) = arg_str.find('.') {
87 let model = arg_str[..dot_pos].trim().to_string();
88 let field = arg_str[dot_pos + 1..].trim().to_string();
89 return Ok(Modifier::ForeignKey {
90 model,
91 field: Some(field),
92 });
93 }
94
95 if let Some(paren_pos) = arg_str.find('(') {
96 let model = arg_str[..paren_pos].trim().to_string();
97 if let Some(close_pos) = arg_str.find(')') {
98 let field = arg_str[paren_pos + 1..close_pos].trim().to_string();
99 return Ok(Modifier::ForeignKey {
100 model,
101 field: Some(field),
102 });
103 }
104 }
105
106 Ok(Modifier::ForeignKey {
107 model: arg_str,
108 field: None,
109 })
110}
111
112fn parse_attribute(pair: Pair<Rule>) -> Attribute {
113 let mut inner = pair.into_inner();
114 let name = inner.next().unwrap().as_str().to_string();
115 let args = inner.next().map(|p| {
116 p.as_str().to_string()
117 });
118 Attribute { name, args }
119}
120