@@ -51,7 +51,8 @@ pub use self::query::{
51
51
Top , TopQuantity , ValueTableMode , Values , WildcardAdditionalOptions , With ,
52
52
} ;
53
53
pub use self :: value:: {
54
- escape_quoted_string, DateTimeField , DollarQuotedString , TrimWhereField , Value ,
54
+ escape_double_quote_string, escape_quoted_string, DateTimeField , DollarQuotedString ,
55
+ TrimWhereField , Value ,
55
56
} ;
56
57
57
58
use crate :: ast:: helpers:: stmt_data_loading:: {
@@ -270,66 +271,6 @@ impl fmt::Display for Interval {
270
271
}
271
272
}
272
273
273
- /// JsonOperator
274
- #[ derive( Debug , Copy , Clone , PartialEq , PartialOrd , Eq , Ord , Hash ) ]
275
- #[ cfg_attr( feature = "serde" , derive( Serialize , Deserialize ) ) ]
276
- #[ cfg_attr( feature = "visitor" , derive( Visit , VisitMut ) ) ]
277
- pub enum JsonOperator {
278
- /// -> keeps the value as json
279
- Arrow ,
280
- /// ->> keeps the value as text or int.
281
- LongArrow ,
282
- /// #> Extracts JSON sub-object at the specified path
283
- HashArrow ,
284
- /// #>> Extracts JSON sub-object at the specified path as text
285
- HashLongArrow ,
286
- /// : Colon is used by Snowflake (Which is similar to LongArrow)
287
- Colon ,
288
- /// jsonb @> jsonb -> boolean: Test whether left json contains the right json
289
- AtArrow ,
290
- /// jsonb <@ jsonb -> boolean: Test whether right json contains the left json
291
- ArrowAt ,
292
- /// jsonb #- text[] -> jsonb: Deletes the field or array element at the specified
293
- /// path, where path elements can be either field keys or array indexes.
294
- HashMinus ,
295
- /// jsonb @? jsonpath -> boolean: Does JSON path return any item for the specified
296
- /// JSON value?
297
- AtQuestion ,
298
- /// jsonb @@ jsonpath → boolean: Returns the result of a JSON path predicate check
299
- /// for the specified JSON value. Only the first item of the result is taken into
300
- /// account. If the result is not Boolean, then NULL is returned.
301
- AtAt ,
302
- }
303
-
304
- impl fmt:: Display for JsonOperator {
305
- fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
306
- match self {
307
- JsonOperator :: Arrow => {
308
- write ! ( f, "->" )
309
- }
310
- JsonOperator :: LongArrow => {
311
- write ! ( f, "->>" )
312
- }
313
- JsonOperator :: HashArrow => {
314
- write ! ( f, "#>" )
315
- }
316
- JsonOperator :: HashLongArrow => {
317
- write ! ( f, "#>>" )
318
- }
319
- JsonOperator :: Colon => {
320
- write ! ( f, ":" )
321
- }
322
- JsonOperator :: AtArrow => {
323
- write ! ( f, "@>" )
324
- }
325
- JsonOperator :: ArrowAt => write ! ( f, "<@" ) ,
326
- JsonOperator :: HashMinus => write ! ( f, "#-" ) ,
327
- JsonOperator :: AtQuestion => write ! ( f, "@?" ) ,
328
- JsonOperator :: AtAt => write ! ( f, "@@" ) ,
329
- }
330
- }
331
- }
332
-
333
274
/// A field definition within a struct.
334
275
///
335
276
/// [bigquery]: https://cloud.google.com/bigquery/docs/reference/standard-sql/data-types#struct_type
@@ -412,6 +353,59 @@ impl fmt::Display for MapAccessKey {
412
353
}
413
354
}
414
355
356
+ /// An element of a JSON path.
357
+ #[ derive( Debug , Clone , PartialEq , PartialOrd , Eq , Ord , Hash ) ]
358
+ #[ cfg_attr( feature = "serde" , derive( Serialize , Deserialize ) ) ]
359
+ #[ cfg_attr( feature = "visitor" , derive( Visit , VisitMut ) ) ]
360
+ pub enum JsonPathElem {
361
+ /// Accesses an object field using dot notation, e.g. `obj:foo.bar.baz`.
362
+ ///
363
+ /// See <https://docs.snowflake.com/en/user-guide/querying-semistructured#dot-notation>.
364
+ Dot { key : String , quoted : bool } ,
365
+ /// Accesses an object field or array element using bracket notation,
366
+ /// e.g. `obj['foo']`.
367
+ ///
368
+ /// See <https://docs.snowflake.com/en/user-guide/querying-semistructured#bracket-notation>.
369
+ Bracket { key : Expr } ,
370
+ }
371
+
372
+ /// A JSON path.
373
+ ///
374
+ /// See <https://docs.snowflake.com/en/user-guide/querying-semistructured>.
375
+ /// See <https://docs.databricks.com/en/sql/language-manual/sql-ref-json-path-expression.html>.
376
+ #[ derive( Debug , Clone , PartialEq , PartialOrd , Eq , Ord , Hash ) ]
377
+ #[ cfg_attr( feature = "serde" , derive( Serialize , Deserialize ) ) ]
378
+ #[ cfg_attr( feature = "visitor" , derive( Visit , VisitMut ) ) ]
379
+ pub struct JsonPath {
380
+ pub path : Vec < JsonPathElem > ,
381
+ }
382
+
383
+ impl fmt:: Display for JsonPath {
384
+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
385
+ for ( i, elem) in self . path . iter ( ) . enumerate ( ) {
386
+ match elem {
387
+ JsonPathElem :: Dot { key, quoted } => {
388
+ if i == 0 {
389
+ write ! ( f, ":" ) ?;
390
+ } else {
391
+ write ! ( f, "." ) ?;
392
+ }
393
+
394
+ if * quoted {
395
+ write ! ( f, "\" {}\" " , escape_double_quote_string( key) ) ?;
396
+ } else {
397
+ write ! ( f, "{key}" ) ?;
398
+ }
399
+ }
400
+ JsonPathElem :: Bracket { key } => {
401
+ write ! ( f, "[{key}]" ) ?;
402
+ }
403
+ }
404
+ }
405
+ Ok ( ( ) )
406
+ }
407
+ }
408
+
415
409
/// The syntax used for in a cast expression.
416
410
#[ derive( Debug , Clone , PartialEq , PartialOrd , Eq , Ord , Hash ) ]
417
411
#[ cfg_attr( feature = "serde" , derive( Serialize , Deserialize ) ) ]
@@ -449,11 +443,16 @@ pub enum Expr {
449
443
Identifier ( Ident ) ,
450
444
/// Multi-part identifier, e.g. `table_alias.column` or `schema.table.col`
451
445
CompoundIdentifier ( Vec < Ident > ) ,
452
- /// JSON access (postgres) eg: data->'tags'
446
+ /// Access data nested in a value containing semi-structured data, such as
447
+ /// the `VARIANT` type on Snowflake. for example `src:customer[0].name`.
448
+ ///
449
+ /// See <https://docs.snowflake.com/en/user-guide/querying-semistructured>.
450
+ /// See <https://docs.databricks.com/en/sql/language-manual/functions/colonsign.html>.
453
451
JsonAccess {
454
- left : Box < Expr > ,
455
- operator : JsonOperator ,
456
- right : Box < Expr > ,
452
+ /// The value being queried.
453
+ value : Box < Expr > ,
454
+ /// The path to the data to extract.
455
+ path : JsonPath ,
457
456
} ,
458
457
/// CompositeAccess (postgres) eg: SELECT (information_schema._pg_expandarray(array['i','i'])).n
459
458
CompositeAccess {
@@ -1224,16 +1223,8 @@ impl fmt::Display for Expr {
1224
1223
Expr :: Array ( set) => {
1225
1224
write ! ( f, "{set}" )
1226
1225
}
1227
- Expr :: JsonAccess {
1228
- left,
1229
- operator,
1230
- right,
1231
- } => {
1232
- if operator == & JsonOperator :: Colon {
1233
- write ! ( f, "{left}{operator}{right}" )
1234
- } else {
1235
- write ! ( f, "{left} {operator} {right}" )
1236
- }
1226
+ Expr :: JsonAccess { value, path } => {
1227
+ write ! ( f, "{value}{path}" )
1237
1228
}
1238
1229
Expr :: CompositeAccess { expr, key } => {
1239
1230
write ! ( f, "{expr}.{key}" )
0 commit comments