sql/parsers/create_parser/
json.rs

1// Copyright 2023 Greptime Team
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use 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;
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_FORMAT,
50        JSON_OPT_UNSTRUCTURED_KEYS,
51    };
52    use crate::statements::statement::Statement;
53
54    #[test]
55    fn test_parse_json_datatype_options() {
56        fn parse(sql: &str) -> Option<OptionMap> {
57            let Statement::CreateTable(mut create_table) = ParserContext::create_with_dialect(
58                sql,
59                &GreptimeDbDialect {},
60                ParseOptions::default(),
61            )
62            .unwrap()
63            .remove(0) else {
64                unreachable!()
65            };
66
67            let Column {
68                column_def,
69                extensions,
70            } = create_table.columns.remove(0);
71            assert_eq!(column_def.name.to_string(), "my_json");
72            assert_eq!(column_def.data_type, DataType::JSON);
73            assert!(column_def.options.is_empty());
74
75            extensions.json_datatype_options
76        }
77
78        let sql = r#"
79CREATE TABLE json_data (
80    my_json JSON(format = "partial", unstructured_keys = ["k", "foo.bar", "a.b.c"]),
81    ts TIMESTAMP TIME INDEX,
82)"#;
83        let options = parse(sql).unwrap();
84        assert_eq!(options.len(), 2);
85        assert_eq!(
86            options.value(JSON_OPT_FORMAT).and_then(|x| x.as_string()),
87            Some(JSON_FORMAT_PARTIAL)
88        );
89        let expected = vec!["k", "foo.bar", "a.b.c"];
90        assert_eq!(
91            options
92                .value(JSON_OPT_UNSTRUCTURED_KEYS)
93                .and_then(|x| x.as_list()),
94            Some(expected)
95        );
96
97        let sql = r#"
98CREATE TABLE json_data (
99    my_json JSON(format = "structured"),
100    ts TIMESTAMP TIME INDEX,
101)"#;
102        let options = parse(sql).unwrap();
103        assert_eq!(options.len(), 1);
104        assert_eq!(
105            options.value(JSON_OPT_FORMAT).and_then(|x| x.as_string()),
106            Some(JSON_FORMAT_FULL_STRUCTURED)
107        );
108
109        let sql = r#"
110CREATE TABLE json_data (
111    my_json JSON(format = "raw"),
112    ts TIMESTAMP TIME INDEX,
113)"#;
114        let options = parse(sql).unwrap();
115        assert_eq!(options.len(), 1);
116        assert_eq!(
117            options.value(JSON_OPT_FORMAT).and_then(|x| x.as_string()),
118            Some(JSON_FORMAT_RAW)
119        );
120
121        let sql = r#"
122CREATE TABLE json_data (
123    my_json JSON(),
124    ts TIMESTAMP TIME INDEX,
125)"#;
126        let options = parse(sql).unwrap();
127        assert!(options.is_empty());
128
129        let sql = r#"
130CREATE TABLE json_data (
131    my_json JSON,
132    ts TIMESTAMP TIME INDEX,
133)"#;
134        let options = parse(sql);
135        assert!(options.is_none());
136    }
137}