kalamdb_commons/models/schemas/
schema_field.rs1#[cfg(feature = "schema-metadata")]
4use arrow_schema::Field;
5use serde::{Deserialize, Serialize};
6
7#[cfg(feature = "schema-metadata")]
8use crate::conversions::read_kalam_column_flags_metadata;
9use crate::{
10 models::datatypes::KalamDataType,
11 schemas::{ColumnDefinition, FieldFlag, FieldFlags},
12};
13
14#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
40pub struct SchemaField {
41 pub name: String,
43
44 pub data_type: KalamDataType,
46
47 pub index: usize,
49
50 #[serde(default, skip_serializing_if = "Option::is_none")]
54 pub flags: Option<FieldFlags>,
55}
56
57impl SchemaField {
58 pub fn new(name: impl Into<String>, data_type: KalamDataType, index: usize) -> Self {
60 Self {
61 name: name.into(),
62 data_type,
63 index,
64 flags: None,
65 }
66 }
67
68 pub fn from_column_definition(column: &ColumnDefinition, index: usize) -> Self {
69 Self {
70 name: column.column_name.clone(),
71 data_type: column.data_type.clone(),
72 index,
73 flags: Self::flags_for_column(column.is_primary_key, column.is_nullable),
74 }
75 }
76
77 #[cfg(feature = "schema-metadata")]
78 pub fn from_arrow_field(field: &Field, data_type: KalamDataType, index: usize) -> Self {
79 let flags = read_kalam_column_flags_metadata(field);
80
81 Self {
82 name: field.name().clone(),
83 data_type,
84 index,
85 flags,
86 }
87 }
88
89 pub fn with_flags(mut self, flags: FieldFlags) -> Self {
90 if !flags.is_empty() {
91 self.flags = Some(flags);
92 }
93 self
94 }
95
96 pub fn flags_for_column(is_primary_key: bool, is_nullable: bool) -> Option<FieldFlags> {
97 let mut flags = FieldFlags::new();
98 if is_primary_key {
99 flags.insert(FieldFlag::PrimaryKey);
100 flags.insert(FieldFlag::Unique);
101 }
102 if !is_nullable {
103 flags.insert(FieldFlag::NonNull);
104 }
105
106 if flags.is_empty() {
107 None
108 } else {
109 Some(flags)
110 }
111 }
112}
113
114#[cfg(test)]
115mod tests {
116 use serde_json;
117
118 use super::*;
119
120 #[test]
121 fn test_schema_field_serialization() {
122 let field = SchemaField::new("user_id", KalamDataType::BigInt, 0);
123 let json = serde_json::to_string(&field).unwrap();
124 assert!(json.contains("\"name\":\"user_id\""));
125 assert!(json.contains("\"data_type\":\"BigInt\""));
126 assert!(json.contains("\"index\":0"));
127 assert!(!json.contains("\"flags\":"));
128 }
129
130 #[test]
131 fn test_schema_field_deserialization() {
132 let json = r#"{"name":"email","data_type":"Text","index":1}"#;
133 let field: SchemaField = serde_json::from_str(json).unwrap();
134 assert_eq!(field.name, "email");
135 assert_eq!(field.data_type, KalamDataType::Text);
136 assert_eq!(field.index, 1);
137 assert_eq!(field.flags, None);
138 }
139
140 #[test]
141 fn test_schema_field_with_flags() {
142 let mut flags = FieldFlags::new();
143 flags.insert(FieldFlag::PrimaryKey);
144 flags.insert(FieldFlag::NonNull);
145 flags.insert(FieldFlag::Unique);
146 let field = SchemaField::new("id", KalamDataType::Uuid, 0).with_flags(flags);
147 let json = serde_json::to_string(&field).unwrap();
148 assert!(json.contains("\"flags\":["));
149 assert!(json.contains("\"pk\""));
150 assert!(json.contains("\"nn\""));
151 assert!(json.contains("\"uq\""));
152 }
153
154 #[test]
155 fn test_schema_field_deserializes_flags_array() {
156 let json = r#"{"name":"id","data_type":"Uuid","index":0,"flags":["pk","nn","uq"]}"#;
157 let field: SchemaField = serde_json::from_str(json).unwrap();
158 assert!(matches!(
159 field.flags,
160 Some(flags)
161 if flags.contains(&FieldFlag::PrimaryKey)
162 && flags.contains(&FieldFlag::NonNull)
163 && flags.contains(&FieldFlag::Unique)
164 ));
165 }
166
167 #[test]
168 fn test_schema_field_with_embedding() {
169 let field = SchemaField::new("vector", KalamDataType::Embedding(384), 5);
170 let json = serde_json::to_string(&field).unwrap();
171 assert!(json.contains("\"Embedding\":384"));
172 }
173
174 #[test]
175 fn test_schema_field_with_decimal() {
176 let field = SchemaField::new(
177 "price",
178 KalamDataType::Decimal {
179 precision: 10,
180 scale: 2,
181 },
182 2,
183 );
184 let json = serde_json::to_string(&field).unwrap();
185 assert!(json.contains("\"Decimal\""));
186 }
187}