sql_cli/sql/parser/
file_cte_parser.rs1use super::ast::FileCTESpec;
20use super::lexer::Token;
21
22pub struct FileCteParser;
23
24impl FileCteParser {
25 pub fn parse(parser: &mut crate::sql::recursive_parser::Parser) -> Result<FileCTESpec, String> {
30 if let Token::Identifier(id) = &parser.current_token {
32 if id.to_uppercase() != "PATH" {
33 return Err(format!("Expected PATH keyword in FILE CTE, found '{}'", id));
34 }
35 } else {
36 return Err("Expected PATH keyword in FILE CTE".to_string());
37 }
38 parser.advance();
39
40 let path = match &parser.current_token {
42 Token::StringLiteral(p) => p.clone(),
43 _ => return Err("Expected string literal after PATH keyword".to_string()),
44 };
45 parser.advance();
46
47 let mut recursive = false;
49 let mut glob: Option<String> = None;
50 let mut max_depth: Option<usize> = None;
51 let mut max_files: Option<usize> = None;
52 let mut follow_links = false;
53 let mut include_hidden = false;
54
55 while !matches!(parser.current_token, Token::RightParen)
57 && !matches!(parser.current_token, Token::Eof)
58 {
59 if let Token::Identifier(id) = &parser.current_token {
60 match id.to_uppercase().as_str() {
61 "RECURSIVE" => {
62 parser.advance();
63 recursive = true;
64 }
65 "GLOB" => {
66 parser.advance();
67 glob = Some(Self::parse_string(parser, "GLOB")?);
68 }
69 "MAX_DEPTH" => {
70 parser.advance();
71 max_depth = Some(Self::parse_usize(parser, "MAX_DEPTH")?);
72 }
73 "MAX_FILES" => {
74 parser.advance();
75 max_files = Some(Self::parse_usize(parser, "MAX_FILES")?);
76 }
77 "FOLLOW_LINKS" => {
78 parser.advance();
79 follow_links = true;
80 }
81 "INCLUDE_HIDDEN" => {
82 parser.advance();
83 include_hidden = true;
84 }
85 _ => {
86 return Err(format!(
87 "Unexpected keyword '{}' in FILE CTE specification",
88 id
89 ));
90 }
91 }
92 } else {
93 break;
94 }
95 }
96
97 Ok(FileCTESpec {
98 path,
99 recursive,
100 glob,
101 max_depth,
102 max_files,
103 follow_links,
104 include_hidden,
105 })
106 }
107
108 fn parse_string(
109 parser: &mut crate::sql::recursive_parser::Parser,
110 clause: &str,
111 ) -> Result<String, String> {
112 match &parser.current_token {
113 Token::StringLiteral(s) => {
114 let s = s.clone();
115 parser.advance();
116 Ok(s)
117 }
118 _ => Err(format!("Expected string literal after {} clause", clause)),
119 }
120 }
121
122 fn parse_usize(
123 parser: &mut crate::sql::recursive_parser::Parser,
124 clause: &str,
125 ) -> Result<usize, String> {
126 match &parser.current_token {
127 Token::NumberLiteral(n) => {
128 let val = n
129 .parse::<usize>()
130 .map_err(|_| format!("Invalid {} value: {}", clause, n))?;
131 parser.advance();
132 Ok(val)
133 }
134 _ => Err(format!("Expected integer after {} clause", clause)),
135 }
136 }
137}