1use nom::branch::alt;
2use nom::bytes::complete::{tag, tag_no_case, take_until};
3use nom::character::complete;
4use nom::character::complete::{multispace0, multispace1};
5use nom::combinator::{map, opt};
6use nom::multi::many1;
7use nom::sequence::{delimited, preceded, tuple};
8use nom::IResult;
9use std::fmt::{Display, Formatter};
10
11use base::error::ParseSQLError;
12use base::index_type::IndexType;
13use base::visible_type::VisibleType;
14use base::CommonParser;
15
16#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
26pub enum IndexOption {
27 KeyBlockSize(u64),
28 IndexType(IndexType),
29 WithParser(String),
30 Comment(String),
31 VisibleType(VisibleType),
32 EngineAttribute(String), SecondaryEngineAttribute(String), }
35
36impl Display for IndexOption {
37 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
38 match *self {
39 IndexOption::KeyBlockSize(ref val) => write!(f, "KEY_BLOCK_SIZE {}", val),
40 IndexOption::IndexType(ref val) => write!(f, "{}", val),
41 IndexOption::WithParser(ref val) => write!(f, "WITH PARSER {}", val),
42 IndexOption::Comment(ref val) => write!(f, "COMMENT '{}'", val),
43 IndexOption::VisibleType(ref val) => match *val {
44 VisibleType::Visible => write!(f, "VISIBLE"),
45 VisibleType::Invisible => write!(f, "INVISIBLE"),
46 },
47 IndexOption::EngineAttribute(ref val) => write!(f, "ENGINE_ATTRIBUTE {}", val),
48 IndexOption::SecondaryEngineAttribute(ref val) => {
49 write!(f, "SECONDARY_ENGINE_ATTRIBUTE {}", val)
50 }
51 }
52 }
53}
54
55impl IndexOption {
56 pub fn parse(i: &str) -> IResult<&str, IndexOption, ParseSQLError<&str>> {
57 alt((
58 map(Self::key_block_size, IndexOption::KeyBlockSize),
59 map(IndexType::parse, IndexOption::IndexType),
60 map(Self::with_parser, IndexOption::WithParser),
61 map(CommonParser::parse_comment, IndexOption::Comment),
62 map(VisibleType::parse, IndexOption::VisibleType),
63 map(Self::engine_attribute, IndexOption::EngineAttribute),
64 map(
65 Self::secondary_engine_attribute,
66 IndexOption::SecondaryEngineAttribute,
67 ),
68 ))(i)
69 }
70
71 pub fn format_list(list: &[IndexOption]) -> String {
72 list.iter()
73 .map(|x| x.to_string())
74 .collect::<Vec<String>>()
75 .join(" ")
76 }
77
78 pub fn opt_index_option(
89 i: &str,
90 ) -> IResult<&str, Option<Vec<IndexOption>>, ParseSQLError<&str>> {
91 opt(many1(map(preceded(multispace0, IndexOption::parse), |x| x)))(i)
92 }
93
94 fn key_block_size(i: &str) -> IResult<&str, u64, ParseSQLError<&str>> {
96 map(
97 tuple((
98 multispace0,
99 tag_no_case("KEY_BLOCK_SIZE"),
100 multispace0,
101 opt(tag("=")),
102 multispace0,
103 complete::u64,
104 )),
105 |(_, _, _, _, _, size)| size,
106 )(i)
107 }
108
109 fn with_parser(i: &str) -> IResult<&str, String, ParseSQLError<&str>> {
111 map(
112 tuple((
113 multispace0,
114 tag_no_case("WITH"),
115 multispace1,
116 tag_no_case("PARSER"),
117 multispace1,
118 CommonParser::sql_identifier,
119 multispace0,
120 )),
121 |(_, _, _, _, _, parser_name, _)| String::from(parser_name),
122 )(i)
123 }
124
125 fn engine_attribute(i: &str) -> IResult<&str, String, ParseSQLError<&str>> {
127 map(
128 tuple((
129 tag_no_case("ENGINE_ATTRIBUTE"),
130 multispace0,
131 opt(tag("=")),
132 map(delimited(tag("'"), take_until("'"), tag("'")), |x| {
133 String::from(x)
134 }),
135 multispace0,
136 )),
137 |(_, _, _, engine, _)| engine,
138 )(i)
139 }
140
141 fn secondary_engine_attribute(i: &str) -> IResult<&str, String, ParseSQLError<&str>> {
143 CommonParser::parse_string_value_with_key(i, "SECONDARY_ENGINE_ATTRIBUTE".to_string())
144 }
145}
146
147#[cfg(test)]
148mod tests {
149 use base::index_option::IndexOption;
150 use base::visible_type::VisibleType;
151 use base::visible_type::VisibleType::Invisible;
152
153 #[test]
154 fn parse_index_option_item() {
155 let parts = [
156 "KEY_BLOCK_SIZE=1024",
157 "COMMENT 'This is an index comment'",
158 "INVISIBLE",
159 "WITH PARSER ngram",
160 ];
161 let exps = [
162 IndexOption::KeyBlockSize(1024),
163 IndexOption::Comment("This is an index comment".to_string()),
164 IndexOption::VisibleType(VisibleType::Invisible),
165 IndexOption::WithParser("ngram".to_string()),
166 ];
167 for i in 0..parts.len() {
168 let res = IndexOption::parse(parts[i]);
169 assert!(res.is_ok());
170 assert_eq!(res.unwrap().1, exps[i]);
171 }
172 }
173
174 #[test]
175 fn parse_index_option() {
176 let parts = ["INVISIBLE KEY_BLOCK_SIZE 333"];
177 let exps = [vec![
178 IndexOption::VisibleType(Invisible),
179 IndexOption::KeyBlockSize(333),
180 ]];
181 for i in 0..parts.len() {
182 let res = IndexOption::opt_index_option(parts[i]);
183 assert!(res.is_ok());
184 assert_eq!(res.unwrap().1.unwrap(), exps[i]);
185 }
186 }
187}