risingwave_common/types/
fields.rs

1// Copyright 2023 RisingWave Labs
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 super::DataType;
16use crate::row::OwnedRow;
17use crate::util::chunk_coalesce::DataChunkBuilder;
18
19/// A struct can implements `Fields` when if can be represented as a relational Row.
20///
21/// # Derivable
22///
23/// This trait can be automatically derived with [`#[derive(Fields)]`](derive@super::Fields).
24/// Type of the fields must implement [`WithDataType`](super::WithDataType) and [`ToOwnedDatum`](super::ToOwnedDatum).
25///
26/// ```
27/// # use risingwave_common::types::Fields;
28///
29/// #[derive(Fields)]
30/// struct Data {
31///     v1: i16,
32///     v2: i32,
33/// }
34/// ```
35///
36/// You can add `#[primary_key]` attribute to one of the fields to specify the primary key of the table.
37///
38/// ```
39/// # use risingwave_common::types::Fields;
40///
41/// #[derive(Fields)]
42/// struct Data {
43///     #[primary_key]
44///     v1: i16,
45///     v2: i32,
46/// }
47/// ```
48///
49/// If the primary key is composite, you can add `#[primary_key(...)]` attribute to the struct to specify the order of the fields.
50///
51/// ```
52/// # use risingwave_common::types::Fields;
53///
54/// #[derive(Fields)]
55/// #[primary_key(v2, v1)]
56/// struct Data {
57///     v1: i16,
58///     v2: i32,
59/// }
60/// ```
61pub trait Fields {
62    /// The primary key of the table.
63    ///
64    /// - `None` if the primary key is not applicable.
65    /// - `Some(&[])` if the primary key is empty, i.e., there'll be at most one row in the table.
66    const PRIMARY_KEY: Option<&'static [usize]>;
67
68    /// Return the schema of the struct.
69    fn fields() -> Vec<(&'static str, DataType)>;
70
71    /// Convert the struct to an `OwnedRow`.
72    fn into_owned_row(self) -> OwnedRow;
73
74    /// Create a [`DataChunkBuilder`](crate::util::chunk_coalesce::DataChunkBuilder) with the schema of the struct.
75    fn data_chunk_builder(capacity: usize) -> DataChunkBuilder {
76        DataChunkBuilder::new(
77            Self::fields().into_iter().map(|(_, ty)| ty).collect(),
78            capacity,
79        )
80    }
81}
82
83#[cfg(test)]
84mod tests {
85    use bytes::Bytes;
86
87    use super::*;
88    use crate::types::{F32, Fields, StructType, Timestamp, Timestamptz};
89
90    #[test]
91    #[allow(dead_code)]
92    fn test_macro() {
93        #[derive(Fields)]
94        struct Sub {
95            v12: Timestamptz,
96            v13: Bytes,
97        }
98
99        #[derive(Fields)]
100        struct Data {
101            v1: i16,
102            v2: std::primitive::i32,
103            v3: bool,
104            v4: f32,
105            v5: F32,
106            v6: Option<f64>,
107            v7: Vec<u8>,
108            v8: std::vec::Vec<i16>,
109            v9: Option<Vec<i64>>,
110            v10: std::option::Option<Vec<Option<F32>>>,
111            v11: Timestamp,
112            v14: Sub,
113        }
114
115        assert_eq!(
116            Data::fields(),
117            vec![
118                ("v1", DataType::Int16),
119                ("v2", DataType::Int32),
120                ("v3", DataType::Boolean),
121                ("v4", DataType::Float32),
122                ("v5", DataType::Float32),
123                ("v6", DataType::Float64),
124                ("v7", DataType::Bytea),
125                ("v8", DataType::Int16.list()),
126                ("v9", DataType::Int64.list()),
127                ("v10", DataType::Float32.list()),
128                ("v11", DataType::Timestamp),
129                (
130                    "v14",
131                    DataType::Struct(StructType::new(vec![
132                        ("v12", DataType::Timestamptz),
133                        ("v13", DataType::Bytea)
134                    ]))
135                )
136            ]
137        )
138    }
139}