@@ -21,6 +21,7 @@ use std::str::Chars;
2121
2222use super :: dialect:: keywords:: { Keyword , ALL_KEYWORDS , ALL_KEYWORDS_INDEX } ;
2323use super :: dialect:: Dialect ;
24+ use super :: dialect:: PostgreSqlDialect ;
2425use super :: dialect:: SnowflakeDialect ;
2526#[ cfg( feature = "serde" ) ]
2627use serde:: { Deserialize , Serialize } ;
@@ -104,6 +105,31 @@ pub enum Token {
104105 RBrace ,
105106 /// Right Arrow `=>`
106107 RArrow ,
108+ /// https://www.postgresql.org/docs/9.5/functions-json.html
109+ /// various PostgreSQL JSON index operators:
110+ /// `->`
111+ PgJsonGetIndex ,
112+ /// `->>`
113+ PgJsonGetIndexText ,
114+ /// `#>` Get JSON object at specified path
115+ PgJsonGetPath ,
116+ /// `#>>` Get JSON object at specified path as text
117+ PgJsonGetPathText ,
118+ /// `@>` Does the left JSON value contain the right JSON path/value entries
119+ /// at the top level?
120+ PgJsonGt ,
121+ /// <@` Are the left JSON path/value entries contained at the top level
122+ /// within the right JSON value?
123+ PgJsonLt ,
124+ /// `?` Does the string exist as a top-level key within the JSON value?
125+ PgJsonKeyExists ,
126+ /// `?|` Do any of these array strings exist as top-level keys?
127+ PgJsonAnyKeyExists ,
128+ /// `?&` Do all of these array strings exist as top-level keys?
129+ PgJsonAllKeysExist ,
130+ /// `#-` Delete the field or element with specified path (for JSON arrays,
131+ /// negative integers count from the end)
132+ PgJsonMinus ,
107133 /// Sharp `#` used for PostgreSQL Bitwise XOR operator
108134 Sharp ,
109135 /// Tilde `~` used for PostgreSQL Bitwise NOT operator
@@ -163,6 +189,16 @@ impl fmt::Display for Token {
163189 Token :: LBrace => f. write_str ( "{" ) ,
164190 Token :: RBrace => f. write_str ( "}" ) ,
165191 Token :: RArrow => f. write_str ( "=>" ) ,
192+ Token :: PgJsonGetIndex => f. write_str ( "->" ) ,
193+ Token :: PgJsonGetIndexText => f. write_str ( "->>" ) ,
194+ Token :: PgJsonGetPath => f. write_str ( "#>" ) ,
195+ Token :: PgJsonGetPathText => f. write_str ( "#>>" ) ,
196+ Token :: PgJsonGt => f. write_str ( "@>" ) ,
197+ Token :: PgJsonLt => f. write_str ( "@<" ) ,
198+ Token :: PgJsonKeyExists => f. write_str ( "?" ) ,
199+ Token :: PgJsonAnyKeyExists => f. write_str ( "?|" ) ,
200+ Token :: PgJsonAllKeysExist => f. write_str ( "?&" ) ,
201+ Token :: PgJsonMinus => f. write_str ( "#-" ) ,
166202 Token :: Sharp => f. write_str ( "#" ) ,
167203 Token :: ExclamationMark => f. write_str ( "!" ) ,
168204 Token :: DoubleExclamationMark => f. write_str ( "!!" ) ,
@@ -409,6 +445,15 @@ impl<'a> Tokenizer<'a> {
409445 comment,
410446 } ) ) )
411447 }
448+ Some ( '>' ) if dialect_of ! ( self is PostgreSqlDialect ) => {
449+ chars. next ( ) ; // consume >
450+ if let Some ( '>' ) = chars. peek ( ) {
451+ chars. next ( ) ; // consume >
452+ Ok ( Some ( Token :: PgJsonGetIndexText ) )
453+ } else {
454+ Ok ( Some ( Token :: PgJsonGetIndex ) )
455+ }
456+ }
412457 // a regular '-' operator
413458 _ => Ok ( Some ( Token :: Minus ) ) ,
414459 }
@@ -505,9 +550,66 @@ impl<'a> Tokenizer<'a> {
505550 comment,
506551 } ) ) )
507552 }
553+ '#' => {
554+ chars. next ( ) ; // consume #
555+ if dialect_of ! ( self is PostgreSqlDialect ) {
556+ match chars. peek ( ) {
557+ Some ( '>' ) => {
558+ chars. next ( ) ; // consume >
559+ if let Some ( '>' ) = chars. peek ( ) {
560+ chars. next ( ) ; // consume >
561+ Ok ( Some ( Token :: PgJsonGetPathText ) )
562+ } else {
563+ Ok ( Some ( Token :: PgJsonGetPath ) )
564+ }
565+ }
566+ Some ( '-' ) => {
567+ chars. next ( ) ; // consume -
568+ Ok ( Some ( Token :: PgJsonMinus ) )
569+ }
570+ _ => Ok ( Some ( Token :: Sharp ) ) ,
571+ }
572+ } else {
573+ Ok ( Some ( Token :: Sharp ) )
574+ }
575+ }
508576 '~' => self . consume_and_return ( chars, Token :: Tilde ) ,
509- '#' => self . consume_and_return ( chars, Token :: Sharp ) ,
510- '@' => self . consume_and_return ( chars, Token :: AtSign ) ,
577+ '@' => {
578+ chars. next ( ) ; // consume @
579+ if dialect_of ! ( self is PostgreSqlDialect ) {
580+ match chars. peek ( ) {
581+ Some ( '>' ) => {
582+ chars. next ( ) ; // consume >
583+ Ok ( Some ( Token :: PgJsonGt ) )
584+ }
585+ Some ( '<' ) => {
586+ chars. next ( ) ; // consume <
587+ Ok ( Some ( Token :: PgJsonLt ) )
588+ }
589+ _ => Ok ( Some ( Token :: AtSign ) ) ,
590+ }
591+ } else {
592+ Ok ( Some ( Token :: AtSign ) )
593+ }
594+ }
595+ '?' => {
596+ chars. next ( ) ; // consume ?
597+ if dialect_of ! ( self is PostgreSqlDialect ) {
598+ match chars. peek ( ) {
599+ Some ( '|' ) => {
600+ chars. next ( ) ; // consume |
601+ Ok ( Some ( Token :: PgJsonAnyKeyExists ) )
602+ }
603+ Some ( '&' ) => {
604+ chars. next ( ) ; // consume &
605+ Ok ( Some ( Token :: PgJsonAllKeysExist ) )
606+ }
607+ _ => Ok ( Some ( Token :: PgJsonKeyExists ) ) ,
608+ }
609+ } else {
610+ Ok ( Some ( Token :: Char ( '?' ) ) )
611+ }
612+ }
511613 other => self . consume_and_return ( chars, Token :: Char ( other) ) ,
512614 } ,
513615 None => Ok ( None ) ,
0 commit comments