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}