1use super::base::parse_identifier;
2use crate::ast::*;
3use nom::{
4 IResult, Parser,
5 branch::alt,
6 bytes::complete::{tag_no_case, take_while1},
7 character::complete::{char, multispace0, multispace1},
8 combinator::{map, opt, recognize, value},
9 multi::{many0, separated_list1},
10 sequence::{delimited, preceded},
11};
12
13pub fn parse_create_table<'a>(input: &'a str, table: &str) -> IResult<&'a str, Qail> {
15 let (input, columns) = separated_list1(
16 (multispace0, char(','), multispace0),
17 parse_column_definition,
18 )
19 .parse(input)?;
20
21 let (input, _) = multispace0(input)?;
22 let (input, table_constraints) = many0(parse_table_constraint).parse(input)?;
23
24 Ok((
25 input,
26 Qail {
27 action: Action::Make,
28 table: table.to_string(),
29 columns,
30 joins: vec![],
31 cages: vec![],
32 distinct: false,
33 distinct_on: vec![],
34 index_def: None,
35 table_constraints,
36 set_ops: vec![],
37 having: vec![],
38 group_by_mode: GroupByMode::default(),
39 ctes: vec![],
40 returning: None,
41 on_conflict: None,
42 source_query: None,
43 channel: None,
44 payload: None,
45 savepoint_name: None,
46 from_tables: vec![],
47 using_tables: vec![],
48 lock_mode: None,
49 fetch: None,
50 default_values: false,
51 overriding: None,
52 sample: None,
53 only_table: false,
54 vector: None,
55 score_threshold: None,
56 vector_name: None,
57 with_vector: false,
58 vector_size: None,
59 distance: None,
60 on_disk: None,
61 function_def: None,
62 trigger_def: None,
63 raw_value: None,
64 redis_ttl: None,
65 redis_set_condition: None,
66 },
67 ))
68}
69
70pub fn parse_table_constraint(input: &str) -> IResult<&str, TableConstraint> {
72 let (input, _) = multispace0(input)?;
73
74 alt((
75 map(
77 (
78 tag_no_case("primary"),
79 multispace1,
80 tag_no_case("key"),
81 multispace0,
82 delimited(
83 char('('),
84 separated_list1((multispace0, char(','), multispace0), parse_identifier),
85 char(')'),
86 ),
87 ),
88 |(_, _, _, _, cols): (_, _, _, _, Vec<&str>)| {
89 TableConstraint::PrimaryKey(cols.iter().map(|s| s.to_string()).collect())
90 },
91 ),
92 map(
94 (
95 tag_no_case("unique"),
96 multispace0,
97 delimited(
98 char('('),
99 separated_list1((multispace0, char(','), multispace0), parse_identifier),
100 char(')'),
101 ),
102 ),
103 |(_, _, cols): (_, _, Vec<&str>)| {
104 TableConstraint::Unique(cols.iter().map(|s| s.to_string()).collect())
105 },
106 ),
107 ))
108 .parse(input)
109}
110
111pub fn parse_column_definition(input: &str) -> IResult<&str, Expr> {
113 let (input, name) = take_while1(|c: char| c.is_alphanumeric() || c == '_').parse(input)?;
114 let (input, _) = char(':').parse(input)?;
115
116 let (input, data_type) = take_while1(|c: char| c.is_alphanumeric() || c == '_').parse(input)?;
117
118 let (input, constraints) = many0(preceded(char(':'), parse_constraint)).parse(input)?;
119
120 Ok((
121 input,
122 Expr::Def {
123 name: name.to_string(),
124 data_type: data_type.to_string(),
125 constraints,
126 },
127 ))
128}
129
130pub fn parse_constraint(input: &str) -> IResult<&str, Constraint> {
132 alt((
133 value(Constraint::PrimaryKey, tag_no_case("pk")),
135 value(Constraint::PrimaryKey, tag_no_case("primarykey")),
136 value(Constraint::Unique, tag_no_case("unique")),
138 value(Constraint::Unique, tag_no_case("uniq")),
139 value(Constraint::Nullable, tag_no_case("notnull")),
141 value(Constraint::Nullable, tag_no_case("nn")),
142 map(
144 preceded(
145 alt((tag_no_case("default="), tag_no_case("def="))),
146 recognize(take_while1(|c: char| c != ',' && c != ':' && c != ' ')),
147 ),
148 |val: &str| Constraint::Default(val.to_string()),
149 ),
150 map(
151 preceded(
152 tag_no_case("check="),
153 recognize(take_while1(|c: char| c != ',' && c != ':' && c != ' ')),
154 ),
155 |expr: &str| Constraint::Check(vec![expr.to_string()]),
156 ),
157 ))
158 .parse(input)
159}
160
161pub fn parse_create_index(input: &str) -> IResult<&str, Qail> {
163 let (input, _) = tag_no_case("index").parse(input)?;
164 let (input, _) = multispace1(input)?;
165
166 let (input, index_name) = parse_identifier(input)?;
167 let (input, _) = multispace1(input)?;
168
169 let (input, _) = tag_no_case("on").parse(input)?;
170 let (input, _) = multispace1(input)?;
171
172 let (input, table_name) = parse_identifier(input)?;
173 let (input, _) = multispace1(input)?;
174
175 let (input, columns) =
176 separated_list1((multispace0, char(','), multispace0), parse_identifier).parse(input)?;
177 let (input, _) = multispace0(input)?;
178
179 let (input, unique) = opt(tag_no_case("unique")).parse(input)?;
180
181 Ok((
182 input,
183 Qail {
184 action: Action::Index,
185 table: String::new(),
186 columns: vec![],
187 joins: vec![],
188 cages: vec![],
189 distinct: false,
190 distinct_on: vec![],
191 index_def: Some(IndexDef {
192 name: index_name.to_string(),
193 table: table_name.to_string(),
194 columns: columns.iter().map(|s| s.to_string()).collect(),
195 unique: unique.is_some(),
196 index_type: None,
197 }),
198 table_constraints: vec![],
199 set_ops: vec![],
200 having: vec![],
201 group_by_mode: GroupByMode::default(),
202 ctes: vec![],
203 returning: None,
204 on_conflict: None,
205 source_query: None,
206 channel: None,
207 payload: None,
208 savepoint_name: None,
209 from_tables: vec![],
210 using_tables: vec![],
211 lock_mode: None,
212 fetch: None,
213 default_values: false,
214 overriding: None,
215 sample: None,
216 only_table: false,
217 vector: None,
218 score_threshold: None,
219 vector_name: None,
220 with_vector: false,
221 vector_size: None,
222 distance: None,
223 on_disk: None,
224 function_def: None,
225 trigger_def: None,
226 raw_value: None,
227 redis_ttl: None,
228 redis_set_condition: None,
229 },
230 ))
231}