datatypes/schema/
raw.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 serde::{Deserialize, Serialize};
16
17use crate::error::{Error, Result};
18use crate::schema::{ColumnSchema, Schema, SchemaBuilder};
19
20/// Struct used to serialize and deserialize [`Schema`](crate::schema::Schema).
21///
22/// This struct only contains necessary data to recover the Schema.
23#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
24pub struct RawSchema {
25    /// Schema of columns.
26    pub column_schemas: Vec<ColumnSchema>,
27    /// Index of the timestamp column.
28    pub timestamp_index: Option<usize>,
29    /// Schema version.
30    pub version: u32,
31}
32
33impl RawSchema {
34    /// Creates a new [RawSchema] from specific `column_schemas`.
35    ///
36    /// Sets [RawSchema::timestamp_index] to the first index of the timestamp
37    /// column. It doesn't check whether time index column is duplicate.
38    pub fn new(column_schemas: Vec<ColumnSchema>) -> RawSchema {
39        let timestamp_index = column_schemas
40            .iter()
41            .position(|column_schema| column_schema.is_time_index());
42
43        RawSchema {
44            column_schemas,
45            timestamp_index,
46            version: 0,
47        }
48    }
49}
50
51impl TryFrom<RawSchema> for Schema {
52    type Error = Error;
53
54    fn try_from(raw: RawSchema) -> Result<Schema> {
55        // While building Schema, we don't trust the fields, such as timestamp_index,
56        // in RawSchema. We use SchemaBuilder to perform the validation.
57        SchemaBuilder::try_from(raw.column_schemas)?
58            .version(raw.version)
59            .build()
60    }
61}
62
63impl From<&Schema> for RawSchema {
64    fn from(schema: &Schema) -> RawSchema {
65        RawSchema {
66            column_schemas: schema.column_schemas.clone(),
67            timestamp_index: schema.timestamp_index,
68            version: schema.version,
69        }
70    }
71}
72
73#[cfg(test)]
74mod tests {
75    use super::*;
76    use crate::data_type::ConcreteDataType;
77
78    #[test]
79    fn test_raw_convert() {
80        let column_schemas = vec![
81            ColumnSchema::new("col1", ConcreteDataType::int32_datatype(), true),
82            ColumnSchema::new(
83                "ts",
84                ConcreteDataType::timestamp_millisecond_datatype(),
85                false,
86            )
87            .with_time_index(true),
88        ];
89        let schema = SchemaBuilder::try_from(column_schemas)
90            .unwrap()
91            .version(123)
92            .build()
93            .unwrap();
94
95        let raw = RawSchema::from(&schema);
96        let schema_new = Schema::try_from(raw).unwrap();
97
98        assert_eq!(schema, schema_new);
99    }
100
101    #[test]
102    fn test_new_raw_schema_with_time_index() {
103        let column_schemas = vec![
104            ColumnSchema::new("col1", ConcreteDataType::int32_datatype(), true),
105            ColumnSchema::new(
106                "ts",
107                ConcreteDataType::timestamp_millisecond_datatype(),
108                false,
109            )
110            .with_time_index(true),
111        ];
112        let schema = RawSchema::new(column_schemas);
113        assert_eq!(1, schema.timestamp_index.unwrap());
114    }
115
116    #[test]
117    fn test_new_raw_schema_without_time_index() {
118        let column_schemas = vec![
119            ColumnSchema::new("col1", ConcreteDataType::int32_datatype(), true),
120            ColumnSchema::new(
121                "ts",
122                ConcreteDataType::timestamp_millisecond_datatype(),
123                false,
124            ),
125        ];
126        let schema = RawSchema::new(column_schemas);
127        assert!(schema.timestamp_index.is_none());
128    }
129}