laminar_connectors/serde/
mod.rs1pub mod csv;
5pub mod debezium;
6pub mod json;
7pub mod raw;
8#[cfg(any(
9 test,
10 feature = "kafka",
11 feature = "nats",
12 feature = "rabbitmq",
13 feature = "ibmmq",
14 feature = "websocket",
15 feature = "files"
16))]
17pub(crate) mod schema_contract;
18
19use arrow_array::RecordBatch;
20use arrow_schema::SchemaRef;
21
22use crate::error::SerdeError;
23
24#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
26pub enum Format {
27 Json,
29
30 Csv,
32
33 Raw,
35
36 Debezium,
38
39 Avro,
41
42 Fpml,
45}
46
47impl Format {
48 #[must_use]
50 pub fn as_str(&self) -> &'static str {
51 match self {
52 Format::Json => "json",
53 Format::Csv => "csv",
54 Format::Raw => "raw",
55 Format::Debezium => "debezium",
56 Format::Avro => "avro",
57 Format::Fpml => "fpml",
58 }
59 }
60
61 #[cfg(any(feature = "rabbitmq", feature = "ibmmq"))]
63 pub(crate) fn source_option_keys(self) -> &'static [&'static str] {
64 match self {
65 #[cfg(feature = "fpml")]
66 Format::Fpml => crate::fpml::message::OPTION_KEYS,
67 _ => &[],
68 }
69 }
70
71 pub fn parse(s: &str) -> Result<Self, SerdeError> {
77 s.parse()
78 }
79}
80
81impl std::str::FromStr for Format {
82 type Err = SerdeError;
83
84 fn from_str(s: &str) -> Result<Self, Self::Err> {
85 match s.to_lowercase().as_str() {
86 "json" => Ok(Format::Json),
87 "csv" => Ok(Format::Csv),
88 "raw" | "bytes" => Ok(Format::Raw),
89 "debezium" | "debezium-json" => Ok(Format::Debezium),
90 "avro" | "confluent-avro" => Ok(Format::Avro),
91 "fpml" => Ok(Format::Fpml),
92 other => Err(SerdeError::UnsupportedFormat(other.to_string())),
93 }
94 }
95}
96
97impl std::fmt::Display for Format {
98 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
99 write!(f, "{}", self.as_str())
100 }
101}
102
103pub trait RecordDeserializer: Send + Sync {
108 fn deserialize(&self, data: &[u8], schema: &SchemaRef) -> Result<RecordBatch, SerdeError>;
115
116 fn deserialize_batch(
126 &self,
127 records: &[&[u8]],
128 schema: &SchemaRef,
129 ) -> Result<RecordBatch, SerdeError> {
130 if records.is_empty() {
131 return Ok(RecordBatch::new_empty(schema.clone()));
132 }
133
134 let batches: Result<Vec<RecordBatch>, SerdeError> = records
135 .iter()
136 .map(|data| self.deserialize(data, schema))
137 .collect();
138 let batches = batches?;
139
140 arrow_select::concat::concat_batches(schema, &batches)
141 .map_err(|e| SerdeError::MalformedInput(format!("failed to concat batches: {e}")))
142 }
143
144 fn format(&self) -> Format;
146
147 fn as_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
149 None
150 }
151}
152
153pub trait RecordSerializer: Send + Sync {
158 fn serialize(&self, batch: &RecordBatch) -> Result<Vec<Vec<u8>>, SerdeError>;
166
167 fn serialize_batch(&self, batch: &RecordBatch) -> Result<Vec<u8>, SerdeError> {
176 let records = self.serialize(batch)?;
177 let total_len: usize = records.iter().map(Vec::len).sum();
178 let mut buf = Vec::with_capacity(total_len);
179 for record in &records {
180 buf.extend_from_slice(record);
181 }
182 Ok(buf)
183 }
184
185 fn format(&self) -> Format;
187}
188
189pub fn create_deserializer(format: Format) -> Result<Box<dyn RecordDeserializer>, SerdeError> {
195 match format {
196 Format::Json => Ok(Box::new(json::JsonDeserializer::new())),
197 Format::Csv => Ok(Box::new(csv::CsvDeserializer::new())),
198 Format::Raw => Ok(Box::new(raw::RawBytesDeserializer::new())),
199 Format::Debezium => Ok(Box::new(debezium::DebeziumDeserializer::new())),
200 Format::Avro => Err(SerdeError::UnsupportedFormat(
201 "Avro requires a connector-provided deserializer".into(),
202 )),
203 Format::Fpml => Err(SerdeError::UnsupportedFormat(
204 "FpML requires a connector-provided decoder".into(),
205 )),
206 }
207}
208
209pub fn create_serializer(format: Format) -> Result<Box<dyn RecordSerializer>, SerdeError> {
215 match format {
216 Format::Json => Ok(Box::new(json::JsonSerializer::new())),
217 Format::Csv => Ok(Box::new(csv::CsvSerializer::new())),
218 Format::Raw => Ok(Box::new(raw::RawBytesSerializer::new())),
219 Format::Debezium => Err(SerdeError::UnsupportedFormat(
220 "Debezium is a deserialization-only format".into(),
221 )),
222 Format::Avro => Err(SerdeError::UnsupportedFormat(
223 "Avro requires a connector-provided serializer".into(),
224 )),
225 Format::Fpml => Err(SerdeError::UnsupportedFormat(
226 "FpML is a source-only format".into(),
227 )),
228 }
229}
230
231#[cfg(test)]
232mod tests;