sql/parsers/create_parser/
json.rs1use snafu::ResultExt;
16use sqlparser::parser::Parser;
17use sqlparser::tokenizer::Token;
18
19use crate::error::{Result, SyntaxSnafu};
20use crate::statements::OptionMap;
21use crate::util;
22
23pub(super) fn parse_json_datatype_options(parser: &mut Parser<'_>) -> Result<Option<OptionMap>> {
24 if parser.consume_token(&Token::LParen) {
25 let result = parser
26 .parse_comma_separated0(Parser::parse_sql_option, Token::RParen)
27 .context(SyntaxSnafu)
28 .and_then(|options| {
29 options
30 .into_iter()
31 .map(util::parse_option_string)
32 .collect::<Result<Vec<_>>>()
33 })?;
34 parser.expect_token(&Token::RParen).context(SyntaxSnafu)?;
35 Ok(Some(OptionMap::new(result)))
36 } else {
37 Ok(None)
38 }
39}
40
41#[cfg(test)]
42mod tests {
43 use sqlparser::ast::{DataType, Expr, Ident, StructField};
44
45 use crate::dialect::GreptimeDbDialect;
46 use crate::parser::{ParseOptions, ParserContext};
47 use crate::statements::OptionMap;
48 use crate::statements::create::{
49 Column, JSON_FORMAT_FULL_STRUCTURED, JSON_FORMAT_PARTIAL, JSON_FORMAT_RAW, JSON_OPT_FIELDS,
50 JSON_OPT_FORMAT, JSON_OPT_UNSTRUCTURED_KEYS,
51 };
52 use crate::statements::statement::Statement;
53 use crate::util::OptionValue;
54
55 #[test]
56 fn test_parse_json_datatype_options() {
57 fn parse(sql: &str) -> Option<OptionMap> {
58 let Statement::CreateTable(mut create_table) = ParserContext::create_with_dialect(
59 sql,
60 &GreptimeDbDialect {},
61 ParseOptions::default(),
62 )
63 .unwrap()
64 .remove(0) else {
65 unreachable!()
66 };
67
68 let Column {
69 column_def,
70 extensions,
71 } = create_table.columns.remove(0);
72 assert_eq!(column_def.name.to_string(), "my_json");
73 assert_eq!(column_def.data_type, DataType::JSON);
74 assert!(column_def.options.is_empty());
75
76 extensions.json_datatype_options
77 }
78
79 let sql = r#"
80CREATE TABLE json_data (
81 my_json JSON(format = "partial", fields = Struct<i Int, "o.a" String, "o.b" String, `x.y.z` Float64>),
82 ts TIMESTAMP TIME INDEX,
83)"#;
84 let options = parse(sql).unwrap();
85 assert_eq!(options.len(), 2);
86 let option = options.value(JSON_OPT_FIELDS);
87 let expected = OptionValue::try_new(Expr::Struct {
88 values: vec![],
89 fields: vec![
90 StructField {
91 field_name: Some(Ident::new("i")),
92 field_type: DataType::Int(None),
93 options: None,
94 },
95 StructField {
96 field_name: Some(Ident::with_quote('"', "o.a")),
97 field_type: DataType::String(None),
98 options: None,
99 },
100 StructField {
101 field_name: Some(Ident::with_quote('"', "o.b")),
102 field_type: DataType::String(None),
103 options: None,
104 },
105 StructField {
106 field_name: Some(Ident::with_quote('`', "x.y.z")),
107 field_type: DataType::Float64,
108 options: None,
109 },
110 ],
111 })
112 .ok();
113 assert_eq!(option, expected.as_ref());
114
115 let sql = r#"
116CREATE TABLE json_data (
117 my_json JSON(format = "partial", unstructured_keys = ["k", "foo.bar", "a.b.c"]),
118 ts TIMESTAMP TIME INDEX,
119)"#;
120 let options = parse(sql).unwrap();
121 assert_eq!(options.len(), 2);
122 assert_eq!(
123 options.value(JSON_OPT_FORMAT).and_then(|x| x.as_string()),
124 Some(JSON_FORMAT_PARTIAL)
125 );
126 let expected = vec!["k", "foo.bar", "a.b.c"];
127 assert_eq!(
128 options
129 .value(JSON_OPT_UNSTRUCTURED_KEYS)
130 .and_then(|x| x.as_list()),
131 Some(expected)
132 );
133
134 let sql = r#"
135CREATE TABLE json_data (
136 my_json JSON(format = "structured"),
137 ts TIMESTAMP TIME INDEX,
138)"#;
139 let options = parse(sql).unwrap();
140 assert_eq!(options.len(), 1);
141 assert_eq!(
142 options.value(JSON_OPT_FORMAT).and_then(|x| x.as_string()),
143 Some(JSON_FORMAT_FULL_STRUCTURED)
144 );
145
146 let sql = r#"
147CREATE TABLE json_data (
148 my_json JSON(format = "raw"),
149 ts TIMESTAMP TIME INDEX,
150)"#;
151 let options = parse(sql).unwrap();
152 assert_eq!(options.len(), 1);
153 assert_eq!(
154 options.value(JSON_OPT_FORMAT).and_then(|x| x.as_string()),
155 Some(JSON_FORMAT_RAW)
156 );
157
158 let sql = r#"
159CREATE TABLE json_data (
160 my_json JSON(),
161 ts TIMESTAMP TIME INDEX,
162)"#;
163 let options = parse(sql).unwrap();
164 assert!(options.is_empty());
165
166 let sql = r#"
167CREATE TABLE json_data (
168 my_json JSON,
169 ts TIMESTAMP TIME INDEX,
170)"#;
171 let options = parse(sql);
172 assert!(options.is_none());
173 }
174}