common_meta/ddl/
create_table_template.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 std::collections::HashMap;
16
17use api::v1::region::{CreateRequest, RegionColumnDef};
18use api::v1::{ColumnDef, CreateTableExpr, SemanticType};
19use snafu::OptionExt;
20use store_api::metric_engine_consts::LOGICAL_TABLE_METADATA_KEY;
21use store_api::storage::{RegionId, RegionNumber};
22use table::metadata::TableId;
23
24use crate::error;
25use crate::error::Result;
26use crate::wal_options_allocator::prepare_wal_options;
27
28pub(crate) fn build_template(create_table_expr: &CreateTableExpr) -> Result<CreateRequest> {
29    let column_defs = create_table_expr
30        .column_defs
31        .iter()
32        .enumerate()
33        .map(|(i, c)| {
34            let semantic_type = if create_table_expr.time_index == c.name {
35                SemanticType::Timestamp
36            } else if create_table_expr.primary_keys.contains(&c.name) {
37                SemanticType::Tag
38            } else {
39                SemanticType::Field
40            };
41
42            RegionColumnDef {
43                column_def: Some(ColumnDef {
44                    name: c.name.clone(),
45                    data_type: c.data_type,
46                    is_nullable: c.is_nullable,
47                    default_constraint: c.default_constraint.clone(),
48                    semantic_type: semantic_type as i32,
49                    comment: String::new(),
50                    datatype_extension: c.datatype_extension,
51                    options: c.options.clone(),
52                }),
53                column_id: i as u32,
54            }
55        })
56        .collect::<Vec<_>>();
57
58    let primary_key = create_table_expr
59        .primary_keys
60        .iter()
61        .map(|key| {
62            column_defs
63                .iter()
64                .find_map(|c| {
65                    c.column_def.as_ref().and_then(|x| {
66                        if &x.name == key {
67                            Some(c.column_id)
68                        } else {
69                            None
70                        }
71                    })
72                })
73                .context(error::PrimaryKeyNotFoundSnafu { key })
74        })
75        .collect::<Result<_>>()?;
76
77    let template = CreateRequest {
78        region_id: 0,
79        engine: create_table_expr.engine.to_string(),
80        column_defs,
81        primary_key,
82        path: String::new(),
83        options: create_table_expr.table_options.clone(),
84    };
85
86    Ok(template)
87}
88
89/// Builder for [PbCreateRegionRequest].
90pub struct CreateRequestBuilder {
91    template: CreateRequest,
92    /// Optional. Only for metric engine.
93    physical_table_id: Option<TableId>,
94}
95
96impl CreateRequestBuilder {
97    pub(crate) fn new(template: CreateRequest, physical_table_id: Option<TableId>) -> Self {
98        Self {
99            template,
100            physical_table_id,
101        }
102    }
103
104    pub fn template(&self) -> &CreateRequest {
105        &self.template
106    }
107
108    pub(crate) fn build_one(
109        &self,
110        region_id: RegionId,
111        storage_path: String,
112        region_wal_options: &HashMap<RegionNumber, String>,
113    ) -> Result<CreateRequest> {
114        let mut request = self.template.clone();
115
116        request.region_id = region_id.as_u64();
117        request.path = storage_path;
118        // Stores the encoded wal options into the request options.
119        prepare_wal_options(&mut request.options, region_id, region_wal_options);
120
121        if let Some(physical_table_id) = self.physical_table_id {
122            // Logical table has the same region numbers with physical table, and they have a one-to-one mapping.
123            // For example, region 0 of logical table must resides with region 0 of physical table. So here we can
124            // simply concat the physical table id and the logical region number to get the physical region id.
125            let physical_region_id = RegionId::new(physical_table_id, region_id.region_number());
126
127            request.options.insert(
128                LOGICAL_TABLE_METADATA_KEY.to_string(),
129                physical_region_id.as_u64().to_string(),
130            );
131        }
132
133        Ok(request)
134    }
135}