aimdb_core/remote/
metadata.rs1use core::any::TypeId;
4use serde::{Deserialize, Serialize};
5use std::string::String;
6
7use crate::record_id::{RecordId, RecordKey};
8
9#[derive(Debug, Clone, Serialize, Deserialize)]
17pub struct RecordMetadata {
18 pub record_id: u32,
20
21 pub record_key: String,
23
24 pub name: String,
26
27 pub type_id: String,
29
30 pub buffer_type: String,
32
33 #[serde(skip_serializing_if = "Option::is_none")]
35 pub buffer_capacity: Option<usize>,
36
37 pub producer_count: usize,
39
40 pub consumer_count: usize,
42
43 pub writable: bool,
45
46 pub created_at: String,
48
49 #[serde(skip_serializing_if = "Option::is_none")]
51 pub last_update: Option<String>,
52
53 pub outbound_connector_count: usize,
55
56 #[cfg(feature = "metrics")]
59 #[serde(skip_serializing_if = "Option::is_none")]
60 pub produced_count: Option<u64>,
61
62 #[cfg(feature = "metrics")]
64 #[serde(skip_serializing_if = "Option::is_none")]
65 pub consumed_count: Option<u64>,
66
67 #[cfg(feature = "metrics")]
69 #[serde(skip_serializing_if = "Option::is_none")]
70 pub dropped_count: Option<u64>,
71
72 #[cfg(feature = "metrics")]
74 #[serde(skip_serializing_if = "Option::is_none")]
75 pub occupancy: Option<(usize, usize)>,
76}
77
78impl RecordMetadata {
79 #[allow(clippy::too_many_arguments)]
94 pub fn new<K: RecordKey>(
95 record_id: RecordId,
96 record_key: K,
97 type_id: TypeId,
98 name: String,
99 buffer_type: String,
100 buffer_capacity: Option<usize>,
101 producer_count: usize,
102 consumer_count: usize,
103 writable: bool,
104 created_at: String,
105 outbound_connector_count: usize,
106 ) -> Self {
107 Self {
108 record_id: record_id.raw(),
109 record_key: record_key.as_str().to_string(),
110 name,
111 type_id: format!("{:?}", type_id),
112 buffer_type,
113 buffer_capacity,
114 producer_count,
115 consumer_count,
116 writable,
117 created_at,
118 last_update: None,
119 outbound_connector_count,
120 #[cfg(feature = "metrics")]
121 produced_count: None,
122 #[cfg(feature = "metrics")]
123 consumed_count: None,
124 #[cfg(feature = "metrics")]
125 dropped_count: None,
126 #[cfg(feature = "metrics")]
127 occupancy: None,
128 }
129 }
130
131 pub fn with_last_update(mut self, timestamp: String) -> Self {
133 self.last_update = Some(timestamp);
134 self
135 }
136
137 pub fn with_last_update_opt(mut self, timestamp: Option<String>) -> Self {
139 self.last_update = timestamp;
140 self
141 }
142
143 #[cfg(feature = "metrics")]
148 pub fn with_buffer_metrics(mut self, snapshot: crate::buffer::BufferMetricsSnapshot) -> Self {
149 self.produced_count = Some(snapshot.produced_count);
150 self.consumed_count = Some(snapshot.consumed_count);
151 self.dropped_count = Some(snapshot.dropped_count);
152 if snapshot.occupancy.1 > 0 {
154 self.occupancy = Some(snapshot.occupancy);
155 }
156 self
157 }
158}
159
160#[cfg(test)]
161mod tests {
162 use super::*;
163 use crate::record_id::StringKey;
164
165 #[test]
166 fn test_record_metadata_creation() {
167 let type_id = TypeId::of::<i32>();
168 let metadata = RecordMetadata::new(
169 RecordId::new(0),
170 StringKey::new("test.record"),
171 type_id,
172 "i32".to_string(),
173 "spmc_ring".to_string(),
174 Some(100),
175 1,
176 2,
177 false,
178 "2025-10-31T10:00:00.000Z".to_string(),
179 0,
180 );
181
182 assert_eq!(metadata.record_id, 0);
183 assert_eq!(metadata.record_key, "test.record");
184 assert_eq!(metadata.name, "i32");
185 assert_eq!(metadata.buffer_type, "spmc_ring");
186 assert_eq!(metadata.buffer_capacity, Some(100));
187 assert_eq!(metadata.producer_count, 1);
188 assert_eq!(metadata.consumer_count, 2);
189 assert_eq!(metadata.outbound_connector_count, 0);
190 assert!(!metadata.writable);
191 }
192
193 #[test]
194 fn test_record_metadata_serialization() {
195 let type_id = TypeId::of::<String>();
196 let metadata = RecordMetadata::new(
197 RecordId::new(1),
198 StringKey::new("app.config"),
199 type_id,
200 "String".to_string(),
201 "single_latest".to_string(),
202 None,
203 1,
204 1,
205 true,
206 "2025-10-31T10:00:00.000Z".to_string(),
207 2,
208 )
209 .with_last_update("2025-10-31T12:00:00.000Z".to_string());
210
211 let json = serde_json::to_string(&metadata).unwrap();
212 assert!(json.contains("\"record_id\":1"));
213 assert!(json.contains("\"record_key\":\"app.config\""));
214 assert!(json.contains("\"name\":\"String\""));
215 assert!(json.contains("\"buffer_type\":\"single_latest\""));
216 assert!(json.contains("\"writable\":true"));
217 assert!(json.contains("\"outbound_connector_count\":2"));
218 }
219}