common_catalog/
lib.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 consts::DEFAULT_CATALOG_NAME;
16
17pub mod consts;
18
19#[inline]
20pub fn format_schema_name(catalog: &str, schema: &str) -> String {
21    format!("{catalog}.{schema}")
22}
23
24/// Formats table fully-qualified name
25#[inline]
26pub fn format_full_table_name(catalog: &str, schema: &str, table: &str) -> String {
27    format!("{catalog}.{schema}.{table}")
28}
29
30/// Formats flow fully-qualified name
31#[inline]
32pub fn format_full_flow_name(catalog: &str, flow: &str) -> String {
33    format!("{catalog}.{flow}")
34}
35
36/// Build db name from catalog and schema string
37pub fn build_db_string(catalog: &str, schema: &str) -> String {
38    if catalog == DEFAULT_CATALOG_NAME {
39        schema.to_string()
40    } else {
41        format!("{catalog}-{schema}")
42    }
43}
44
45/// Attempt to parse catalog and schema from given database name
46///
47/// The database name may come from different sources:
48///
49/// - MySQL `schema` name in MySQL protocol login request: it's optional and user
50///   and switch database using `USE` command
51/// - Postgres `database` parameter in Postgres wire protocol, required
52/// - HTTP RESTful API: the database parameter, optional
53/// - gRPC: the dbname field in header, optional but has a higher priority than
54///   original catalog/schema
55///
56/// When database name is provided, we attempt to parse catalog and schema from
57/// it. We assume the format `[<catalog>-]<schema>`:
58///
59/// - If `[<catalog>-]` part is not provided, we use whole database name as
60///   schema name
61/// - if `[<catalog>-]` is provided, we split database name with `-` and use
62///   `<catalog>` and `<schema>`.
63pub fn parse_catalog_and_schema_from_db_string(db: &str) -> (String, String) {
64    match parse_optional_catalog_and_schema_from_db_string(db) {
65        (Some(catalog), schema) => (catalog, schema),
66        (None, schema) => (DEFAULT_CATALOG_NAME.to_string(), schema),
67    }
68}
69
70/// Attempt to parse catalog and schema from given database name
71///
72/// Similar to [`parse_catalog_and_schema_from_db_string`] but returns an optional
73/// catalog if it's not provided in the database name.
74pub fn parse_optional_catalog_and_schema_from_db_string(db: &str) -> (Option<String>, String) {
75    let parts = db.splitn(2, '-').collect::<Vec<&str>>();
76    if parts.len() == 2 {
77        (Some(parts[0].to_lowercase()), parts[1].to_lowercase())
78    } else {
79        (None, db.to_lowercase())
80    }
81}
82
83#[cfg(test)]
84mod tests {
85    use super::*;
86
87    #[test]
88    fn test_db_string() {
89        assert_eq!("test", build_db_string(DEFAULT_CATALOG_NAME, "test"));
90        assert_eq!("a0b1c2d3-test", build_db_string("a0b1c2d3", "test"));
91    }
92
93    #[test]
94    fn test_parse_catalog_and_schema() {
95        assert_eq!(
96            (DEFAULT_CATALOG_NAME.to_string(), "fullschema".to_string()),
97            parse_catalog_and_schema_from_db_string("fullschema")
98        );
99
100        assert_eq!(
101            ("catalog".to_string(), "schema".to_string()),
102            parse_catalog_and_schema_from_db_string("catalog-schema")
103        );
104
105        assert_eq!(
106            ("catalog".to_string(), "schema1-schema2".to_string()),
107            parse_catalog_and_schema_from_db_string("catalog-schema1-schema2")
108        );
109
110        assert_eq!(
111            (None, "fullschema".to_string()),
112            parse_optional_catalog_and_schema_from_db_string("fullschema")
113        );
114
115        assert_eq!(
116            (Some("catalog".to_string()), "schema".to_string()),
117            parse_optional_catalog_and_schema_from_db_string("catalog-schema")
118        );
119
120        assert_eq!(
121            (Some("catalog".to_string()), "schema".to_string()),
122            parse_optional_catalog_and_schema_from_db_string("CATALOG-SCHEMA")
123        );
124
125        assert_eq!(
126            (Some("catalog".to_string()), "schema1-schema2".to_string()),
127            parse_optional_catalog_and_schema_from_db_string("catalog-schema1-schema2")
128        );
129    }
130}