1use serde::de::DeserializeOwned;
2use serde_json::Value;
3use std::collections::HashMap;
4use tracing::{debug, instrument, warn};
5
6use crate::TableField;
7
8pub trait FieldMapper: Clone {
14 fn map_fields(&mut self, fields: Vec<TableField>);
19
20 fn get_field_id(&self, name: &str) -> Option<u64>;
28
29 fn get_field_name(&self, id: u64) -> Option<String>;
37
38 fn get_fields(&self) -> Vec<TableField>;
43}
44
45#[derive(Clone, Default)]
50pub struct TableMapper {
51 fields: Vec<TableField>,
52 ids_to_names: HashMap<u64, String>,
53 names_to_ids: HashMap<String, u64>,
54}
55
56impl TableMapper {
57 pub fn new() -> Self {
59 Self::default()
60 }
61
62 #[instrument(skip(self, row), fields(row_keys = ?row.keys().collect::<Vec<_>>()), err)]
73 pub fn deserialize_row<T>(&self, row: HashMap<String, Value>) -> Result<T, serde_json::Error>
74 where
75 T: DeserializeOwned,
76 {
77 let converted = self.convert_to_field_names(row);
79 serde_json::from_value(serde_json::to_value(converted)?)
81 }
82
83 #[instrument(skip(self, row), fields(row_keys = ?row.keys().collect::<Vec<_>>()))]
91 pub fn convert_to_field_names(&self, row: HashMap<String, Value>) -> HashMap<String, Value> {
92 let mut converted = HashMap::new();
93 for (key, value) in row {
94 if let Ok(field_id) = key.parse::<u64>() {
96 if let Some(name) = self.get_field_name(field_id) {
97 debug!(field_id = field_id, field_name = ?name, "Converted raw field ID to name");
98 converted.insert(name, value);
99 continue;
100 }
101 }
102 if let Some(field_id) = key
104 .strip_prefix("field_")
105 .and_then(|id| id.parse::<u64>().ok())
106 {
107 if let Some(name) = self.get_field_name(field_id) {
108 debug!(field_id = field_id, field_name = ?name, "Converted prefixed field ID to name");
109 converted.insert(name, value);
110 continue;
111 }
112 warn!(field_id = field_id, "No name mapping found for field ID");
113 }
114 debug!(key = ?key, "Keeping original key");
115 converted.insert(key, value);
116 }
117 debug!(
118 field_count = converted.len(),
119 "Completed field name conversion"
120 );
121 converted
122 }
123
124 #[instrument(skip(self, row), fields(row_keys = ?row.keys().collect::<Vec<_>>()))]
132 pub fn convert_to_field_ids(&self, row: HashMap<String, Value>) -> HashMap<String, Value> {
133 let mut converted = HashMap::new();
134 for (key, value) in row {
135 if let Some(id) = self.get_field_id(&key) {
136 let field_key = format!("field_{}", id);
137 debug!(field_name = ?key, field_id = id, "Converted field name to ID");
138 converted.insert(field_key, value);
139 continue;
140 }
141 debug!(key = ?key, "Keeping original key");
142 converted.insert(key, value);
143 }
144 debug!(
145 field_count = converted.len(),
146 "Completed field ID conversion"
147 );
148 converted
149 }
150}
151
152impl FieldMapper for TableMapper {
153 #[instrument(skip(self, fields), fields(field_count = fields.len()))]
154 fn map_fields(&mut self, fields: Vec<TableField>) {
155 self.ids_to_names.clear();
157 self.names_to_ids.clear();
158
159 fields.iter().for_each(|field| {
161 debug!(field_id = field.id, field_name = ?field.name, "Mapping field");
162 self.ids_to_names.insert(field.id, field.name.clone());
163 self.names_to_ids.insert(field.name.clone(), field.id);
164 });
165
166 self.fields = fields;
167 }
168
169 #[instrument(skip(self))]
170 fn get_field_id(&self, name: &str) -> Option<u64> {
171 let id = self.names_to_ids.get(name).copied();
172 if id.is_none() {
173 warn!(field_name = ?name, "Field name not found in mapping");
174 }
175 id
176 }
177
178 #[instrument(skip(self))]
179 fn get_field_name(&self, id: u64) -> Option<String> {
180 let name = self.ids_to_names.get(&id).cloned();
181 if name.is_none() {
182 warn!(field_id = id, "Field ID not found in mapping");
183 }
184 name
185 }
186
187 fn get_fields(&self) -> Vec<TableField> {
188 self.fields.clone()
189 }
190}
191
192#[cfg(test)]
193mod tests {
194 use super::*;
195
196 fn create_test_field(id: u64, name: &str) -> TableField {
197 TableField {
198 id,
199 table_id: 1,
200 name: name.to_string(),
201 order: 0,
202 r#type: "text".to_string(),
203 primary: false,
204 read_only: false,
205 description: None,
206 }
207 }
208
209 #[test]
210 fn test_mapping_fields() {
211 let mut mapper = TableMapper::new();
212 let fields = vec![
213 create_test_field(1, "Name"),
214 create_test_field(2, "Email"),
215 create_test_field(3, "Age"),
216 ];
217
218 mapper.map_fields(fields.clone());
219
220 assert_eq!(mapper.get_fields().len(), 3);
222
223 assert_eq!(mapper.get_field_name(1), Some("Name".to_string()));
225 assert_eq!(mapper.get_field_name(2), Some("Email".to_string()));
226 assert_eq!(mapper.get_field_name(3), Some("Age".to_string()));
227 assert_eq!(mapper.get_field_name(4), None);
228
229 assert_eq!(mapper.get_field_id("Name"), Some(1));
231 assert_eq!(mapper.get_field_id("Email"), Some(2));
232 assert_eq!(mapper.get_field_id("Age"), Some(3));
233 assert_eq!(mapper.get_field_id("Unknown"), None);
234 }
235
236 #[test]
237 fn test_remapping_fields() {
238 let mut mapper = TableMapper::new();
239
240 let initial_fields = vec![create_test_field(1, "Name"), create_test_field(2, "Email")];
242 mapper.map_fields(initial_fields);
243
244 let updated_fields = vec![
246 create_test_field(1, "FullName"), create_test_field(2, "Email"),
248 create_test_field(3, "Phone"), ];
250 mapper.map_fields(updated_fields);
251
252 assert_eq!(mapper.get_field_name(1), Some("FullName".to_string()));
254 assert_eq!(mapper.get_field_id("FullName"), Some(1));
255 assert_eq!(mapper.get_field_name(3), Some("Phone".to_string()));
256 assert_eq!(mapper.get_field_id("Phone"), Some(3));
257
258 assert_eq!(mapper.get_field_id("Name"), None);
260 }
261}