Parse special TRIM function with ISO GQL FROM clause syntax TRIM "(" [("LEADING" | "TRAILING" | "BOTH") [ ] "FROM"] ")"
(tokens: &[Token])
| 2190 | /// Parse special TRIM function with ISO GQL FROM clause syntax |
| 2191 | /// TRIM "(" [("LEADING" | "TRAILING" | "BOTH") [<string-expr>] "FROM"] <string-expr> ")" |
| 2192 | fn trim_function_call(tokens: &[Token]) -> IResult<&[Token], FunctionCall> { |
| 2193 | // Check if this is a TRIM function call |
| 2194 | if !matches!(tokens.first(), Some(Token::Identifier(name)) if name.eq_ignore_ascii_case("TRIM")) |
| 2195 | { |
| 2196 | return Err(nom::Err::Error(nom::error::Error::new( |
| 2197 | tokens, |
| 2198 | nom::error::ErrorKind::Tag, |
| 2199 | ))); |
| 2200 | } |
| 2201 | |
| 2202 | let (tokens, _name) = identifier(tokens)?; // Consume TRIM |
| 2203 | let (tokens, _) = expect_token(Token::LeftParen)(tokens)?; // Consume ( |
| 2204 | |
| 2205 | let mut arguments = Vec::new(); |
| 2206 | let mut remaining = tokens; |
| 2207 | |
| 2208 | // Check for trim mode keywords: LEADING, TRAILING, BOTH |
| 2209 | let trim_mode = match remaining.first() { |
| 2210 | Some(Token::Leading) => { |
| 2211 | remaining = &remaining[1..]; |
| 2212 | Some("LEADING") |
| 2213 | } |
| 2214 | Some(Token::Trailing) => { |
| 2215 | remaining = &remaining[1..]; |
| 2216 | Some("TRAILING") |
| 2217 | } |
| 2218 | Some(Token::Both) => { |
| 2219 | remaining = &remaining[1..]; |
| 2220 | Some("BOTH") |
| 2221 | } |
| 2222 | _ => None, |
| 2223 | }; |
| 2224 | |
| 2225 | // If we have a trim mode, check for optional trim character and FROM keyword |
| 2226 | if let Some(mode) = trim_mode { |
| 2227 | // Add mode as first argument |
| 2228 | arguments.push(Expression::Literal(Literal::String(mode.to_string()))); |
| 2229 | |
| 2230 | // Check if next token is FROM (no trim character specified) or an expression (trim character) |
| 2231 | if matches!(remaining.first(), Some(Token::From)) { |
| 2232 | // TRIM(MODE FROM string) - no trim character, use default whitespace |
| 2233 | remaining = &remaining[1..]; // consume FROM |
| 2234 | arguments.push(Expression::Literal(Literal::String(" ".to_string()))); |
| 2235 | // default trim char |
| 2236 | } else { |
| 2237 | // TRIM(MODE char_expr FROM string) - parse trim character |
| 2238 | let (new_remaining, trim_char_expr) = expression(remaining)?; |
| 2239 | remaining = new_remaining; |
| 2240 | arguments.push(trim_char_expr); // trim character |
| 2241 | |
| 2242 | // Expect FROM keyword |
| 2243 | let (new_remaining, _) = expect_token(Token::From)(remaining)?; |
| 2244 | remaining = new_remaining; |
| 2245 | } |
| 2246 | |
| 2247 | // Parse the string expression to trim |
| 2248 | let (new_remaining, string_expr) = expression(remaining)?; |
| 2249 | remaining = new_remaining; |
nothing calls this directly
no test coverage detected