laminar_connectors/schema/json/encoder/
mod.rs1use std::io::Write as _;
4use std::sync::Arc;
5
6use arrow_array::cast::AsArray;
7use arrow_array::{Array, RecordBatch};
8use arrow_json::writer::{
9 Encoder, EncoderFactory, EncoderOptions, LineDelimited, NullableEncoder, WriterBuilder,
10};
11use arrow_schema::{ArrowError, DataType, FieldRef, SchemaRef};
12
13use crate::schema::error::{SchemaError, SchemaResult};
14use crate::schema::traits::FormatEncoder;
15
16#[derive(Debug)]
20pub struct JsonEncoder {
21 schema: SchemaRef,
22}
23
24impl JsonEncoder {
25 pub fn validate_schema(schema: &SchemaRef) -> SchemaResult<()> {
30 laminar_core::schema_binding::SchemaBinding::logical(
31 "json",
32 laminar_core::schema_binding::SchemaDirection::Sink,
33 laminar_core::schema_binding::SchemaOrigin::Query,
34 schema.as_ref().clone(),
35 )
36 .map_err(|error| SchemaError::Incompatible(error.to_string()))?;
37 let options =
38 EncoderOptions::default().with_encoder_factory(Arc::new(JsonbPassthroughFactory));
39 for field in schema.fields() {
40 let array = arrow_array::new_empty_array(field.data_type());
41 arrow_json::writer::make_encoder(field, array.as_ref(), &options).map_err(|error| {
42 SchemaError::Incompatible(format!(
43 "JSON writer field '{}' cannot encode {}: {error}",
44 field.name(),
45 field.data_type()
46 ))
47 })?;
48 }
49 Ok(())
50 }
51
52 #[must_use]
54 pub fn new(schema: SchemaRef) -> Self {
55 Self { schema }
56 }
57}
58
59impl FormatEncoder for JsonEncoder {
60 fn input_schema(&self) -> SchemaRef {
61 self.schema.clone()
62 }
63
64 fn encode_batch(&self, batch: &RecordBatch) -> SchemaResult<Vec<Vec<u8>>> {
65 if batch.num_rows() == 0 {
66 return Ok(Vec::new());
67 }
68
69 let mut buf = Vec::new();
70 {
71 let mut writer = WriterBuilder::new()
72 .with_explicit_nulls(true)
73 .with_encoder_factory(Arc::new(JsonbPassthroughFactory))
74 .build::<_, LineDelimited>(&mut buf);
75 writer
76 .write(batch)
77 .map_err(|e| SchemaError::DecodeError(format!("JSON encode error: {e}")))?;
78 writer
79 .finish()
80 .map_err(|e| SchemaError::DecodeError(format!("JSON finish error: {e}")))?;
81 }
82
83 let output: Vec<Vec<u8>> = buf
84 .split(|&b| b == b'\n')
85 .filter(|line| !line.is_empty())
86 .map(<[u8]>::to_vec)
87 .collect();
88
89 Ok(output)
90 }
91
92 fn format_name(&self) -> &'static str {
93 "json"
94 }
95}
96
97#[derive(Debug)]
99struct JsonbPassthroughFactory;
100
101impl EncoderFactory for JsonbPassthroughFactory {
102 fn make_default_encoder<'a>(
103 &self,
104 _field: &'a FieldRef,
105 array: &'a dyn Array,
106 _options: &'a EncoderOptions,
107 ) -> Result<Option<NullableEncoder<'a>>, ArrowError> {
108 if *array.data_type() != DataType::LargeBinary {
109 return Ok(None);
110 }
111 let binary_array = array.as_binary::<i64>();
112 let nulls = binary_array.nulls().cloned();
113 let encoder = LargeBinaryJsonbEncoder {
114 array: binary_array,
115 };
116 Ok(Some(NullableEncoder::new(Box::new(encoder), nulls)))
117 }
118}
119
120struct LargeBinaryJsonbEncoder<'a> {
121 array: &'a arrow_array::LargeBinaryArray,
122}
123
124impl Encoder for LargeBinaryJsonbEncoder<'_> {
125 fn encode(&mut self, idx: usize, out: &mut Vec<u8>) {
126 let bytes = self.array.value(idx);
127 if serde_json::from_slice::<serde_json::Value>(bytes).is_ok() {
128 out.extend_from_slice(bytes);
129 } else {
130 write!(out, "\"<binary:{} bytes>\"", bytes.len()).unwrap();
131 }
132 }
133}
134
135#[cfg(test)]
136mod tests;