diff --git a/partiql-parser/src/lexer.rs b/partiql-parser/src/lexer.rs index 8785f755..c3367a50 100644 --- a/partiql-parser/src/lexer.rs +++ b/partiql-parser/src/lexer.rs @@ -1126,6 +1126,43 @@ mod tests { Ok(()) } + /// In the future, the following identifiers may be converted into reserved keywords. In that case, + /// the following test will need to be modified. + #[test] + fn select_non_reserved_keywords() -> Result<(), ParseError<'static, BytePosition>> { + let query = + "SELECT acyclic, BoTh, DOMAIN, SiMpLe, Trail, leading, TRailing, USER\nfrom @\"foo\""; + let mut offset_tracker = LineOffsetTracker::default(); + let lexer = PartiqlLexer::new(query, &mut offset_tracker); + let toks: Vec<_> = lexer.collect::>()?; + + assert_eq!( + vec![ + Token::Select, + Token::UnquotedIdent("acyclic"), + Token::Comma, + Token::UnquotedIdent("BoTh"), + Token::Comma, + Token::UnquotedIdent("DOMAIN"), + Token::Comma, + Token::UnquotedIdent("SiMpLe"), + Token::Comma, + Token::UnquotedIdent("Trail"), + Token::Comma, + Token::UnquotedIdent("leading"), + Token::Comma, + Token::UnquotedIdent("TRailing"), + Token::Comma, + Token::UnquotedIdent("USER"), + Token::From, + Token::QuotedAtIdentifier("foo"), + ], + toks.into_iter().map(|(_s, t, _e)| t).collect::>() + ); + assert_eq!(offset_tracker.num_lines(), 2); + Ok(()) + } + #[test] fn err_invalid_input() { let query = "SELECT # FROM data GROUP BY a"; diff --git a/partiql-parser/src/parse/mod.rs b/partiql-parser/src/parse/mod.rs index d34f4ddf..0e430217 100644 --- a/partiql-parser/src/parse/mod.rs +++ b/partiql-parser/src/parse/mod.rs @@ -679,6 +679,48 @@ mod tests { } } + /// In the future, the following identifiers may be converted into reserved keywords. In that case, + /// the following tests will need to be modified. + mod non_reserved_keywords { + use super::*; + + #[test] + fn projection_list_trim_spec() { + parse!(r#"SELECT leading FROM t"#); + parse!(r#"SELECT leading, a FROM t"#); + parse!(r#"SELECT leading + trailing, b FROM t"#); + parse!(r#"SELECT both + leading + trailing, a, b, c FROM t"#); + } + + #[test] + fn from_source_trim_spec() { + parse!(r#"SELECT leading, trailing, both FROM leading, trailing, both"#); + } + + #[test] + fn complex_trim() { + parse!( + r#"SELECT leading + trim(leading leading FROM ' hello world'), both FROM leading, trailing, both"# + ); + } + + #[test] + fn graph_pattern_matching() { + parse!(r#"SELECT acyclic, trail, simple FROM t"#); + parse!(r#"AcYcLiC"#); + parse!(r#"TrAiL"#); + parse!(r#"SiMpLe"#); + } + + #[test] + fn user_public_domain() { + parse!(r#"SELECT user, puBlIC, DOMAIN FROM USER, pUbLIc, domain"#); + parse!(r#"USER"#); + parse!(r#"pUbLIC"#); + parse!(r#"domain"#); + } + } + mod errors { use super::*; use crate::error::{LexError, UnexpectedToken, UnexpectedTokenData}; diff --git a/partiql-parser/src/preprocessor.rs b/partiql-parser/src/preprocessor.rs index 9e31ba3a..ffe8a1cc 100644 --- a/partiql-parser/src/preprocessor.rs +++ b/partiql-parser/src/preprocessor.rs @@ -706,10 +706,45 @@ mod tests { preprocess(r#"trim(LEADING 'Foo' from 'FooBar')"#)?, lex(r#"trim(LEADING : 'Foo', "from" : 'FooBar')"#)? ); + + // Trim Specification in all 3 spots + assert_eq!( + preprocess(r#"trim(BOTH TrAiLiNg from TRAILING)"#)?, + lex(r#"trim(BOTH : TrAiLiNg, "from" : TRAILING)"#)? + ); + + // Trim specification in 1st and 2nd spot + assert_eq!( + preprocess(r#"trim(LEADING LEADING from 'FooBar')"#)?, + lex(r#"trim(LEADING : LEADING, "from" : 'FooBar')"#)? + ); + assert_eq!( + preprocess(r#"trim(LEADING TrAiLiNg from 'FooBar')"#)?, + lex(r#"trim(LEADING : TrAiLiNg, "from" : 'FooBar')"#)? + ); + assert_eq!( + preprocess(r#"trim(tRaIlInG TrAiLiNg from 'FooBar')"#)?, + lex(r#"trim(tRaIlInG : TrAiLiNg, "from" : 'FooBar')"#)? + ); + + // Trim specification in 1st and 3rd spot assert_eq!( preprocess(r#"trim(LEADING 'Foo' from leaDing)"#)?, lex(r#"trim(LEADING : 'Foo', "from" : leaDing)"#)? ); + + // Trim Specification (quoted) in 2nd and 3rd spot + assert_eq!( + preprocess(r#"trim('LEADING' from leaDing)"#)?, + lex(r#"trim('LEADING', "from" : leaDing)"#)? + ); + + // Trim Specification in 3rd spot only + assert_eq!( + preprocess(r#"trim('a' from leaDing)"#)?, + lex(r#"trim('a', "from" : leaDing)"#)? + ); + assert_eq!( preprocess(r#"trim(leading from ' Bar')"#)?, lex(r#"trim(leading : ' ', "from" : ' Bar')"#)?