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<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(OptionMap::new(result))
36    } else {
37        Ok(OptionMap::default())
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) -> 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            assert!(extensions.json_datatype_options.is_some());
76            extensions.json_datatype_options.unwrap()
77        }
78
79        let sql = r#"
80CREATE TABLE json_data (
81    my_json JSON(format = "partial", unstructured_keys = ["k", "foo.bar", "a.b.c"]),
82    ts TIMESTAMP TIME INDEX,
83)"#;
84        let options = parse(sql);
85        assert_eq!(options.len(), 2);
86        assert_eq!(
87            options.value(JSON_OPT_FORMAT).and_then(|x| x.as_string()),
88            Some(JSON_FORMAT_PARTIAL)
89        );
90        let expected = vec!["k", "foo.bar", "a.b.c"];
91        assert_eq!(
92            options
93                .value(JSON_OPT_UNSTRUCTURED_KEYS)
94                .and_then(|x| x.as_list()),
95            Some(expected)
96        );
97
98        let sql = r#"
99CREATE TABLE json_data (
100    my_json JSON(format = "structured"),
101    ts TIMESTAMP TIME INDEX,
102)"#;
103        let options = parse(sql);
104        assert_eq!(options.len(), 1);
105        assert_eq!(
106            options.value(JSON_OPT_FORMAT).and_then(|x| x.as_string()),
107            Some(JSON_FORMAT_FULL_STRUCTURED)
108        );
109
110        let sql = r#"
111CREATE TABLE json_data (
112    my_json JSON(format = "raw"),
113    ts TIMESTAMP TIME INDEX,
114)"#;
115        let options = parse(sql);
116        assert_eq!(options.len(), 1);
117        assert_eq!(
118            options.value(JSON_OPT_FORMAT).and_then(|x| x.as_string()),
119            Some(JSON_FORMAT_RAW)
120        );
121
122        let sql = r#"
123CREATE TABLE json_data (
124    my_json JSON(),
125    ts TIMESTAMP TIME INDEX,
126)"#;
127        let options = parse(sql);
128        assert!(options.is_empty());
129
130        let sql = r#"
131CREATE TABLE json_data (
132    my_json JSON,
133    ts TIMESTAMP TIME INDEX,
134)"#;
135        let options = parse(sql);
136        assert!(options.is_empty());
137    }
138}