mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-11-01 15:44:14 +00:00
Support Map literal syntax for DuckDB and Generic (#1344)
This commit is contained in:
parent
71dc966586
commit
48ea5640a2
7 changed files with 219 additions and 0 deletions
|
|
@ -329,6 +329,37 @@ impl fmt::Display for DictionaryField {
|
|||
}
|
||||
}
|
||||
|
||||
/// Represents a Map expression.
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
|
||||
pub struct Map {
|
||||
pub entries: Vec<MapEntry>,
|
||||
}
|
||||
|
||||
impl Display for Map {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "MAP {{{}}}", display_comma_separated(&self.entries))
|
||||
}
|
||||
}
|
||||
|
||||
/// A map field within a map.
|
||||
///
|
||||
/// [duckdb]: https://duckdb.org/docs/sql/data_types/map.html#creating-maps
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
|
||||
pub struct MapEntry {
|
||||
pub key: Box<Expr>,
|
||||
pub value: Box<Expr>,
|
||||
}
|
||||
|
||||
impl fmt::Display for MapEntry {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}: {}", self.key, self.value)
|
||||
}
|
||||
}
|
||||
|
||||
/// Options for `CAST` / `TRY_CAST`
|
||||
/// BigQuery: <https://cloud.google.com/bigquery/docs/reference/standard-sql/format-elements#formatting_syntax>
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
|
|
@ -764,6 +795,14 @@ pub enum Expr {
|
|||
/// ```
|
||||
/// [1]: https://duckdb.org/docs/sql/data_types/struct#creating-structs
|
||||
Dictionary(Vec<DictionaryField>),
|
||||
/// `DuckDB` specific `Map` literal expression [1]
|
||||
///
|
||||
/// Syntax:
|
||||
/// ```sql
|
||||
/// syntax: Map {key1: value1[, ... ]}
|
||||
/// ```
|
||||
/// [1]: https://duckdb.org/docs/sql/data_types/map#creating-maps
|
||||
Map(Map),
|
||||
/// An access of nested data using subscript syntax, for example `array[2]`.
|
||||
Subscript {
|
||||
expr: Box<Expr>,
|
||||
|
|
@ -1331,6 +1370,9 @@ impl fmt::Display for Expr {
|
|||
Expr::Dictionary(fields) => {
|
||||
write!(f, "{{{}}}", display_comma_separated(fields))
|
||||
}
|
||||
Expr::Map(map) => {
|
||||
write!(f, "{map}")
|
||||
}
|
||||
Expr::Subscript {
|
||||
expr,
|
||||
subscript: key,
|
||||
|
|
|
|||
|
|
@ -48,4 +48,11 @@ impl Dialect for DuckDbDialect {
|
|||
fn supports_dictionary_syntax(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
// DuckDB uses this syntax for `MAP`s.
|
||||
//
|
||||
// https://duckdb.org/docs/sql/data_types/map.html#creating-maps
|
||||
fn support_map_literal_syntax(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -70,4 +70,8 @@ impl Dialect for GenericDialect {
|
|||
fn supports_select_wildcard_except(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn support_map_literal_syntax(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -215,6 +215,11 @@ pub trait Dialect: Debug + Any {
|
|||
fn supports_dictionary_syntax(&self) -> bool {
|
||||
false
|
||||
}
|
||||
/// Returns true if the dialect supports defining object using the
|
||||
/// syntax like `Map {1: 10, 2: 20}`.
|
||||
fn support_map_literal_syntax(&self) -> bool {
|
||||
false
|
||||
}
|
||||
/// Returns true if the dialect supports lambda functions, for example:
|
||||
///
|
||||
/// ```sql
|
||||
|
|
|
|||
|
|
@ -1078,6 +1078,9 @@ impl<'a> Parser<'a> {
|
|||
let expr = self.parse_subexpr(Self::PLUS_MINUS_PREC)?;
|
||||
Ok(Expr::Prior(Box::new(expr)))
|
||||
}
|
||||
Keyword::MAP if self.peek_token() == Token::LBrace && self.dialect.support_map_literal_syntax() => {
|
||||
self.parse_duckdb_map_literal()
|
||||
}
|
||||
// Here `w` is a word, check if it's a part of a multipart
|
||||
// identifier, a function call, or a simple identifier:
|
||||
_ => match self.peek_token().token {
|
||||
|
|
@ -2322,6 +2325,47 @@ impl<'a> Parser<'a> {
|
|||
})
|
||||
}
|
||||
|
||||
/// DuckDB specific: Parse a duckdb [map]
|
||||
///
|
||||
/// Syntax:
|
||||
///
|
||||
/// ```sql
|
||||
/// Map {key1: value1[, ... ]}
|
||||
/// ```
|
||||
///
|
||||
/// [map]: https://duckdb.org/docs/sql/data_types/map.html#creating-maps
|
||||
fn parse_duckdb_map_literal(&mut self) -> Result<Expr, ParserError> {
|
||||
self.expect_token(&Token::LBrace)?;
|
||||
|
||||
let fields = self.parse_comma_separated(Self::parse_duckdb_map_field)?;
|
||||
|
||||
self.expect_token(&Token::RBrace)?;
|
||||
|
||||
Ok(Expr::Map(Map { entries: fields }))
|
||||
}
|
||||
|
||||
/// Parse a field for a duckdb [map]
|
||||
///
|
||||
/// Syntax
|
||||
///
|
||||
/// ```sql
|
||||
/// key: value
|
||||
/// ```
|
||||
///
|
||||
/// [map]: https://duckdb.org/docs/sql/data_types/map.html#creating-maps
|
||||
fn parse_duckdb_map_field(&mut self) -> Result<MapEntry, ParserError> {
|
||||
let key = self.parse_expr()?;
|
||||
|
||||
self.expect_token(&Token::Colon)?;
|
||||
|
||||
let value = self.parse_expr()?;
|
||||
|
||||
Ok(MapEntry {
|
||||
key: Box::new(key),
|
||||
value: Box::new(value),
|
||||
})
|
||||
}
|
||||
|
||||
/// Parse clickhouse [map]
|
||||
///
|
||||
/// Syntax
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue