use crate::ast::{
Expr, IsJsonExpr, JsonAggregateBody, JsonAggregateExpr, JsonArrayBody, JsonArrayExpr,
JsonBehavior, JsonBehaviorKind, JsonConstructorExpr, JsonConstructorKind, JsonEncoding,
JsonFormat, JsonFuncExpr, JsonFuncKind, JsonItemType, JsonKeyValue, JsonKeyValueSpelling,
JsonNullClause, JsonObjectExpr, JsonPassingArg, JsonQuotesBehavior, JsonReturning,
JsonValueExpr, JsonWrapperBehavior, Keyword, Span, Spanned,
};
use crate::error::ParseResult;
use crate::parser::Dialect;
use crate::parser::engine::Parser;
use crate::tokenizer::{Punctuation, Token};
use thin_vec::ThinVec;
impl<'a, D: Dialect> Parser<'a, D> {
pub(super) fn parse_sqljson_expr(&mut self, token: Token) -> ParseResult<Expr<D::Ext>> {
let crate::tokenizer::TokenKind::Keyword(keyword) = token.kind else {
unreachable!("parse_sqljson_expr is reached only with a keyword token");
};
match keyword {
Keyword::JsonValue => self.parse_json_query_func(token, JsonFuncKind::Value),
Keyword::JsonQuery => self.parse_json_query_func(token, JsonFuncKind::Query),
Keyword::JsonExists => self.parse_json_query_func(token, JsonFuncKind::Exists),
Keyword::JsonObject => self.parse_json_object(token),
Keyword::JsonArray => self.parse_json_array(token),
Keyword::JsonObjectagg => self.parse_json_object_agg(token),
Keyword::JsonArrayagg => self.parse_json_array_agg(token),
Keyword::Json => self.parse_json_constructor(token, JsonConstructorKind::Json),
Keyword::JsonScalar => self.parse_json_constructor(token, JsonConstructorKind::Scalar),
Keyword::JsonSerialize => {
self.parse_json_constructor(token, JsonConstructorKind::Serialize)
}
_ => unreachable!("parse_sqljson_expr dispatched a non-SQL/JSON keyword"),
}
}
fn parse_json_query_func(
&mut self,
token: Token,
kind: JsonFuncKind,
) -> ParseResult<Expr<D::Ext>> {
self.advance()?; self.expect_punct(Punctuation::LParen, "`(` after the SQL/JSON function name")?;
let context = self.parse_json_value_expr()?;
self.expect_punct(
Punctuation::Comma,
"`,` before the SQL/JSON path expression",
)?;
let path = self.parse_expr()?;
let passing = self.parse_json_passing_opt()?;
let returning = if matches!(kind, JsonFuncKind::Value | JsonFuncKind::Query) {
self.parse_json_returning_opt()?
} else {
None
};
let (wrapper, quotes) = if matches!(kind, JsonFuncKind::Query) {
(self.parse_json_wrapper()?, self.parse_json_quotes()?)
} else {
(
JsonWrapperBehavior::Unspecified,
JsonQuotesBehavior::Unspecified,
)
};
let on_empty = if matches!(kind, JsonFuncKind::Value | JsonFuncKind::Query) {
self.parse_json_on_behavior(Keyword::Empty)?
} else {
None
};
let on_error = self.parse_json_on_behavior(Keyword::Error)?;
self.expect_punct(Punctuation::RParen, "`)` to close the SQL/JSON function")?;
let span = token.span.union(self.preceding_span());
let meta = self.make_meta(span);
Ok(Expr::JsonFunc {
json_func: Box::new(JsonFuncExpr {
kind,
context,
path: Box::new(path),
passing,
returning,
wrapper,
quotes,
on_empty,
on_error,
meta,
}),
meta,
})
}
fn parse_json_object(&mut self, token: Token) -> ParseResult<Expr<D::Ext>> {
let start = self.checkpoint();
self.advance()?; self.expect_punct(Punctuation::LParen, "`(` after `JSON_OBJECT`")?;
let mut entries = ThinVec::new();
let mut null_clause = None;
let mut unique_keys = None;
let mut returning = None;
if self.peek_is_punct(Punctuation::RParen)? {
self.advance()?; } else if self.peek_is_keyword(Keyword::Returning)? {
returning = self.parse_json_returning_opt()?;
self.expect_punct(Punctuation::RParen, "`)` to close `JSON_OBJECT`")?;
} else {
let Some(first) = self.try_parse_json_member()? else {
self.rewind(start);
return self.parse_word_prefix(token);
};
entries.push(first);
while self.eat_punct(Punctuation::Comma)? {
entries.push(self.parse_json_member_required()?);
}
null_clause = self.parse_json_null_clause()?;
unique_keys = self.parse_json_unique()?;
returning = self.parse_json_returning_opt()?;
self.expect_punct(Punctuation::RParen, "`)` to close `JSON_OBJECT`")?;
}
let span = token.span.union(self.preceding_span());
let meta = self.make_meta(span);
Ok(Expr::JsonObject {
json_object: Box::new(JsonObjectExpr {
entries,
null_clause,
unique_keys,
returning,
meta,
}),
meta,
})
}
fn parse_json_array(&mut self, token: Token) -> ParseResult<Expr<D::Ext>> {
self.advance()?; self.expect_punct(Punctuation::LParen, "`(` after `JSON_ARRAY`")?;
let body_start = self.current_span()?;
let body = if self.peek_is_punct(Punctuation::RParen)?
|| self.peek_is_keyword(Keyword::Returning)?
{
let meta = self.make_meta(body_start);
JsonArrayBody::Values {
items: ThinVec::new(),
null_clause: None,
meta,
}
} else if self.peek_starts_query()? {
let query = self.parse_query()?;
let format = self.parse_json_format()?;
let meta = self.make_meta(body_start.union(self.preceding_span()));
JsonArrayBody::Query {
query: Box::new(query),
format,
meta,
}
} else {
let items = self.parse_comma_separated(Self::parse_json_value_expr)?;
let null_clause = self.parse_json_null_clause()?;
let meta = self.make_meta(body_start.union(self.preceding_span()));
JsonArrayBody::Values {
items,
null_clause,
meta,
}
};
let returning = self.parse_json_returning_opt()?;
self.expect_punct(Punctuation::RParen, "`)` to close `JSON_ARRAY`")?;
let span = token.span.union(self.preceding_span());
let meta = self.make_meta(span);
Ok(Expr::JsonArray {
json_array: Box::new(JsonArrayExpr {
body,
returning,
meta,
}),
meta,
})
}
fn parse_json_object_agg(&mut self, token: Token) -> ParseResult<Expr<D::Ext>> {
self.advance()?; self.expect_punct(Punctuation::LParen, "`(` after `JSON_OBJECTAGG`")?;
let body_start = self.current_span()?;
let entry = self.parse_json_member_required()?;
let null_clause = self.parse_json_null_clause()?;
let unique_keys = self.parse_json_unique()?;
let returning = self.parse_json_returning_opt()?;
self.expect_punct(Punctuation::RParen, "`)` to close `JSON_OBJECTAGG`")?;
let meta = self.make_meta(body_start.union(self.preceding_span()));
let body = JsonAggregateBody::Object {
entry,
unique_keys,
meta,
};
self.finish_json_aggregate(token, body, null_clause, returning)
}
fn parse_json_array_agg(&mut self, token: Token) -> ParseResult<Expr<D::Ext>> {
self.advance()?; self.expect_punct(Punctuation::LParen, "`(` after `JSON_ARRAYAGG`")?;
let body_start = self.current_span()?;
let value = self.parse_json_value_expr()?;
let order_by = self.parse_aggregate_order_by()?;
let null_clause = self.parse_json_null_clause()?;
let returning = self.parse_json_returning_opt()?;
self.expect_punct(Punctuation::RParen, "`)` to close `JSON_ARRAYAGG`")?;
let meta = self.make_meta(body_start.union(self.preceding_span()));
let body = JsonAggregateBody::Array {
value,
order_by,
meta,
};
self.finish_json_aggregate(token, body, null_clause, returning)
}
fn finish_json_aggregate(
&mut self,
token: Token,
body: JsonAggregateBody<D::Ext>,
null_clause: Option<JsonNullClause>,
returning: Option<JsonReturning<D::Ext>>,
) -> ParseResult<Expr<D::Ext>> {
let (filter, _filter_where) = self.parse_aggregate_filter()?;
let over = self.parse_over_clause()?.map(Box::new);
let span = token.span.union(self.preceding_span());
let meta = self.make_meta(span);
Ok(Expr::JsonAggregate {
json_aggregate: Box::new(JsonAggregateExpr {
body,
null_clause,
returning,
filter,
over,
meta,
}),
meta,
})
}
fn parse_json_constructor(
&mut self,
token: Token,
kind: JsonConstructorKind,
) -> ParseResult<Expr<D::Ext>> {
let start = self.checkpoint();
self.advance()?; self.expect_punct(Punctuation::LParen, "`(` after the SQL/JSON constructor")?;
if self.peek_is_punct(Punctuation::RParen)?
&& !self
.features()
.call_syntax
.sqljson_constructors_require_argument
{
self.rewind(start);
return self.parse_word_prefix(token);
}
let value = if matches!(kind, JsonConstructorKind::Scalar) {
let expr = self.parse_expr()?;
let span = expr.span();
let meta = self.make_meta(span);
JsonValueExpr {
expr: Box::new(expr),
format: None,
meta,
}
} else {
self.parse_json_value_expr()?
};
let unique_keys = if matches!(kind, JsonConstructorKind::Json) {
self.parse_json_unique()?
} else {
None
};
let returning = if matches!(kind, JsonConstructorKind::Serialize) {
self.parse_json_returning_opt()?
} else {
None
};
self.expect_punct(Punctuation::RParen, "`)` to close the SQL/JSON constructor")?;
let span = token.span.union(self.preceding_span());
let meta = self.make_meta(span);
Ok(Expr::JsonConstructor {
json_constructor: Box::new(JsonConstructorExpr {
kind,
value,
unique_keys,
returning,
meta,
}),
meta,
})
}
pub(super) fn parse_is_json_predicate(
&mut self,
expr: Expr<D::Ext>,
negated: bool,
) -> ParseResult<Expr<D::Ext>> {
self.expect_keyword(Keyword::Json)?;
let item_type = if self.eat_keyword(Keyword::Value)? {
JsonItemType::Value
} else if self.eat_keyword(Keyword::Array)? {
JsonItemType::Array
} else if self.eat_keyword(Keyword::Object)? {
JsonItemType::Object
} else if self.eat_keyword(Keyword::Scalar)? {
JsonItemType::Scalar
} else {
JsonItemType::Any
};
let unique_keys = self.parse_json_unique()?.unwrap_or_default();
let span = expr.span().union(self.preceding_span());
let meta = self.make_meta(span);
Ok(Expr::IsJson {
is_json: Box::new(IsJsonExpr {
expr: Box::new(expr),
negated,
item_type,
unique_keys,
meta,
}),
meta,
})
}
pub(crate) fn parse_json_value_expr(&mut self) -> ParseResult<JsonValueExpr<D::Ext>> {
let expr = self.parse_expr()?;
let format = self.parse_json_format()?;
let span = expr.span().union(self.preceding_span());
let meta = self.make_meta(span);
Ok(JsonValueExpr {
expr: Box::new(expr),
format,
meta,
})
}
pub(crate) fn parse_json_format(&mut self) -> ParseResult<Option<JsonFormat>> {
if !self.eat_keyword(Keyword::Format)? {
return Ok(None);
}
self.expect_keyword(Keyword::Json)?;
let encoding = if self.eat_keyword(Keyword::Encoding)? {
Some(self.parse_json_encoding()?)
} else {
None
};
Ok(Some(JsonFormat { encoding }))
}
fn parse_json_encoding(&mut self) -> ParseResult<JsonEncoding> {
let Some(token) = self.peek()? else {
return Err(self.unexpected("a JSON encoding (UTF8, UTF16, or UTF32)"));
};
let text = self.span_text(token.span).to_owned();
let encoding = if text.eq_ignore_ascii_case("UTF8") {
JsonEncoding::Utf8
} else if text.eq_ignore_ascii_case("UTF16") {
JsonEncoding::Utf16
} else if text.eq_ignore_ascii_case("UTF32") {
JsonEncoding::Utf32
} else {
return Err(self.error_at(token.span, "a JSON encoding (UTF8, UTF16, or UTF32)", text));
};
self.advance()?;
Ok(encoding)
}
fn parse_json_returning_opt(&mut self) -> ParseResult<Option<JsonReturning<D::Ext>>> {
let start = self.current_span()?;
if !self.eat_keyword(Keyword::Returning)? {
return Ok(None);
}
let data_type = self.parse_data_type()?;
let format = self.parse_json_format()?;
let span = start.union(self.preceding_span());
let meta = self.make_meta(span);
Ok(Some(JsonReturning {
data_type: Box::new(data_type),
format,
meta,
}))
}
pub(crate) fn parse_json_passing_opt(
&mut self,
) -> ParseResult<ThinVec<JsonPassingArg<D::Ext>>> {
if !self.eat_keyword(Keyword::Passing)? {
return Ok(ThinVec::new());
}
self.parse_comma_separated(Self::parse_json_passing_arg)
}
fn parse_json_passing_arg(&mut self) -> ParseResult<JsonPassingArg<D::Ext>> {
let start = self.current_span()?;
let value = self.parse_json_value_expr()?;
self.expect_keyword(Keyword::As)?;
let name = self.parse_as_alias_ident()?;
let span = start.union(self.preceding_span());
let meta = self.make_meta(span);
Ok(JsonPassingArg { value, name, meta })
}
pub(crate) fn parse_json_on_behavior(
&mut self,
slot: Keyword,
) -> ParseResult<Option<JsonBehavior<D::Ext>>> {
let start = self.checkpoint();
let Some(behavior) = self.try_parse_json_behavior()? else {
return Ok(None);
};
if self.eat_keyword(Keyword::On)? && self.eat_keyword(slot)? {
Ok(Some(behavior))
} else {
self.rewind(start);
Ok(None)
}
}
fn try_parse_json_behavior(&mut self) -> ParseResult<Option<JsonBehavior<D::Ext>>> {
let start = self.current_span()?;
let (kind, default_expr) = if self.eat_keyword(Keyword::Error)? {
(JsonBehaviorKind::Error, None)
} else if self.eat_keyword(Keyword::Null)? {
(JsonBehaviorKind::Null, None)
} else if self.eat_keyword(Keyword::True)? {
(JsonBehaviorKind::True, None)
} else if self.eat_keyword(Keyword::False)? {
(JsonBehaviorKind::False, None)
} else if self.eat_keyword(Keyword::Unknown)? {
(JsonBehaviorKind::Unknown, None)
} else if self.eat_keyword(Keyword::Empty)? {
if self.eat_keyword(Keyword::Array)? {
(JsonBehaviorKind::EmptyArray, None)
} else if self.eat_keyword(Keyword::Object)? {
(JsonBehaviorKind::EmptyObject, None)
} else {
(JsonBehaviorKind::Empty, None)
}
} else if self.eat_keyword(Keyword::Default)? {
let expr = self.parse_expr()?;
(JsonBehaviorKind::Default, Some(Box::new(expr)))
} else {
return Ok(None);
};
let span = start.union(self.preceding_span());
let meta = self.make_meta(span);
Ok(Some(JsonBehavior {
kind,
default_expr,
meta,
}))
}
pub(crate) fn parse_json_wrapper(&mut self) -> ParseResult<JsonWrapperBehavior> {
if self.eat_keyword(Keyword::Without)? {
let _ = self.eat_keyword(Keyword::Array)?;
self.expect_keyword(Keyword::Wrapper)?;
Ok(JsonWrapperBehavior::Without)
} else if self.eat_keyword(Keyword::With)? {
let conditional = if self.eat_keyword(Keyword::Conditional)? {
true
} else {
let _ = self.eat_keyword(Keyword::Unconditional)?;
false
};
let _ = self.eat_keyword(Keyword::Array)?;
self.expect_keyword(Keyword::Wrapper)?;
Ok(if conditional {
JsonWrapperBehavior::Conditional
} else {
JsonWrapperBehavior::Unconditional
})
} else {
Ok(JsonWrapperBehavior::Unspecified)
}
}
pub(crate) fn parse_json_quotes(&mut self) -> ParseResult<JsonQuotesBehavior> {
let keep = if self.eat_keyword(Keyword::Keep)? {
true
} else if self.eat_keyword(Keyword::Omit)? {
false
} else {
return Ok(JsonQuotesBehavior::Unspecified);
};
self.expect_keyword(Keyword::Quotes)?;
if self.eat_keyword(Keyword::On)? {
self.expect_keyword(Keyword::Scalar)?;
self.expect_keyword(Keyword::String)?;
}
Ok(if keep {
JsonQuotesBehavior::Keep
} else {
JsonQuotesBehavior::Omit
})
}
fn parse_json_null_clause(&mut self) -> ParseResult<Option<JsonNullClause>> {
if self.peek_is_keyword(Keyword::Absent)? {
self.advance()?; self.expect_keyword(Keyword::On)?;
self.expect_keyword(Keyword::Null)?;
Ok(Some(JsonNullClause::AbsentOnNull))
} else if self.peek_is_keyword(Keyword::Null)?
&& self.peek_nth_is_keyword(1, Keyword::On)?
{
self.advance()?; self.advance()?; self.expect_keyword(Keyword::Null)?;
Ok(Some(JsonNullClause::NullOnNull))
} else {
Ok(None)
}
}
fn parse_json_unique(&mut self) -> ParseResult<Option<bool>> {
let with = if self.peek_is_keyword(Keyword::With)?
&& self.peek_nth_is_keyword(1, Keyword::Unique)?
{
true
} else if self.peek_is_keyword(Keyword::Without)?
&& self.peek_nth_is_keyword(1, Keyword::Unique)?
{
false
} else {
return Ok(None);
};
self.advance()?; self.advance()?; let _ = self.eat_keyword(Keyword::Keys)?;
Ok(Some(with))
}
fn parse_json_member_required(&mut self) -> ParseResult<JsonKeyValue<D::Ext>> {
match self.try_parse_json_member()? {
Some(member) => Ok(member),
None => {
Err(self
.unexpected("a SQL/JSON object member (`key : value` or `key VALUE value`)"))
}
}
}
fn try_parse_json_member(&mut self) -> ParseResult<Option<JsonKeyValue<D::Ext>>> {
let start = self.current_span()?;
let has_key_prefix = self.peek_is_keyword(Keyword::Key)?
&& !self.peek_nth_is_punct(1, Punctuation::Comma)?
&& !self.peek_nth_is_punct(1, Punctuation::RParen)?;
if has_key_prefix {
self.advance()?; }
let checkpoint = self.checkpoint();
let key_primary = self.parse_prefix()?.expr;
if self.peek_is_keyword(Keyword::Value)? {
self.advance()?; return self.finish_json_member(start, key_primary, JsonKeyValueSpelling::Value);
}
if self.peek_is_punct(Punctuation::Colon)? {
self.advance()?; return self.finish_json_member(start, key_primary, JsonKeyValueSpelling::Colon);
}
self.rewind(checkpoint);
let key_expr = self.parse_expr()?;
if self.peek_is_punct(Punctuation::Colon)? {
self.advance()?; return self.finish_json_member(start, key_expr, JsonKeyValueSpelling::Colon);
}
Ok(None)
}
fn finish_json_member(
&mut self,
start: Span,
key: Expr<D::Ext>,
spelling: JsonKeyValueSpelling,
) -> ParseResult<Option<JsonKeyValue<D::Ext>>> {
let value = self.parse_json_value_expr()?;
let span = start.union(self.preceding_span());
let meta = self.make_meta(span);
Ok(Some(JsonKeyValue {
key: Box::new(key),
value,
spelling,
meta,
}))
}
}