arrow_schema/extension/canonical/
json.rs1use serde_core::de::{self, MapAccess, Visitor};
23use serde_core::ser::SerializeStruct;
24use serde_core::{Deserialize, Deserializer, Serialize, Serializer};
25use std::fmt;
26
27use crate::{ArrowError, DataType, extension::ExtensionType};
28
29#[derive(Debug, Clone, Default, PartialEq)]
45pub struct Json(JsonMetadata);
46
47#[derive(Debug, Clone, Copy, PartialEq)]
49struct Empty {}
50
51impl Serialize for Empty {
52 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
53 where
54 S: Serializer,
55 {
56 let state = serializer.serialize_struct("Empty", 0)?;
57 state.end()
58 }
59}
60
61struct EmptyVisitor;
62
63impl<'de> Visitor<'de> for EmptyVisitor {
64 type Value = Empty;
65
66 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
67 formatter.write_str("struct Empty")
68 }
69
70 fn visit_seq<A>(self, mut _seq: A) -> Result<Self::Value, A::Error>
71 where
72 A: de::SeqAccess<'de>,
73 {
74 Ok(Empty {})
75 }
76
77 fn visit_map<V>(self, mut map: V) -> Result<Empty, V::Error>
78 where
79 V: MapAccess<'de>,
80 {
81 if let Some(key) = map.next_key::<String>()? {
82 return Err(de::Error::unknown_field(&key, EMPTY_FIELDS));
83 }
84 Ok(Empty {})
85 }
86
87 fn visit_u64<E>(self, _v: u64) -> Result<Self::Value, E>
88 where
89 E: de::Error,
90 {
91 Err(de::Error::unknown_field("", EMPTY_FIELDS))
92 }
93
94 fn visit_str<E>(self, _v: &str) -> Result<Self::Value, E>
95 where
96 E: de::Error,
97 {
98 Err(de::Error::unknown_field("", EMPTY_FIELDS))
99 }
100
101 fn visit_bytes<E>(self, _v: &[u8]) -> Result<Self::Value, E>
102 where
103 E: de::Error,
104 {
105 Err(de::Error::unknown_field("", EMPTY_FIELDS))
106 }
107}
108
109static EMPTY_FIELDS: &[&str] = &[];
110
111impl<'de> Deserialize<'de> for Empty {
112 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
113 where
114 D: Deserializer<'de>,
115 {
116 deserializer.deserialize_struct("Empty", EMPTY_FIELDS, EmptyVisitor)
117 }
118}
119
120#[derive(Debug, Default, Clone, PartialEq)]
122pub struct JsonMetadata(Option<Empty>);
123
124impl ExtensionType for Json {
125 const NAME: &'static str = "arrow.json";
126
127 type Metadata = JsonMetadata;
128
129 fn metadata(&self) -> &Self::Metadata {
130 &self.0
131 }
132
133 fn serialize_metadata(&self) -> Option<String> {
134 Some(
135 self.metadata()
136 .0
137 .as_ref()
138 .map(serde_json::to_string)
139 .map(Result::unwrap)
140 .unwrap_or_else(|| "".to_owned()),
141 )
142 }
143
144 fn deserialize_metadata(metadata: Option<&str>) -> Result<Self::Metadata, ArrowError> {
145 const ERR: &str = "Json extension type metadata is either an empty string or a JSON string with an empty object";
146 metadata
147 .map_or_else(
148 || Err(ArrowError::InvalidArgumentError(ERR.to_owned())),
149 |metadata| {
150 match metadata {
151 "" => Ok(None),
153 value => serde_json::from_str::<Empty>(value)
154 .map(Option::Some)
155 .map_err(|_| ArrowError::InvalidArgumentError(ERR.to_owned())),
156 }
157 },
158 )
159 .map(JsonMetadata)
160 }
161
162 fn supports_data_type(&self, data_type: &DataType) -> Result<(), ArrowError> {
163 match data_type {
164 DataType::Utf8 | DataType::LargeUtf8 | DataType::Utf8View => Ok(()),
165 data_type => Err(ArrowError::InvalidArgumentError(format!(
166 "Json data type mismatch, expected one of Utf8, LargeUtf8, Utf8View, found {data_type}"
167 ))),
168 }
169 }
170
171 fn try_new(data_type: &DataType, metadata: Self::Metadata) -> Result<Self, ArrowError> {
172 let json = Self(metadata);
173 json.supports_data_type(data_type)?;
174 Ok(json)
175 }
176
177 fn validate(data_type: &DataType, _metadata: Self::Metadata) -> Result<(), ArrowError> {
178 Self::default().supports_data_type(data_type)
179 }
180}
181
182#[cfg(test)]
183mod tests {
184 #[cfg(feature = "canonical_extension_types")]
185 use crate::extension::CanonicalExtensionType;
186 use crate::{
187 Field,
188 extension::{EXTENSION_TYPE_METADATA_KEY, EXTENSION_TYPE_NAME_KEY},
189 };
190
191 use super::*;
192
193 #[test]
194 fn valid() -> Result<(), ArrowError> {
195 let mut field = Field::new("", DataType::Utf8, false);
196 field.try_with_extension_type(Json::default())?;
197 assert_eq!(
198 field.metadata().get(EXTENSION_TYPE_METADATA_KEY),
199 Some(&"".to_owned())
200 );
201 assert_eq!(
202 field.try_extension_type::<Json>()?,
203 Json(JsonMetadata(None))
204 );
205
206 let mut field = Field::new("", DataType::LargeUtf8, false);
207 field.try_with_extension_type(Json(JsonMetadata(Some(Empty {}))))?;
208 assert_eq!(
209 field.metadata().get(EXTENSION_TYPE_METADATA_KEY),
210 Some(&"{}".to_owned())
211 );
212 assert_eq!(
213 field.try_extension_type::<Json>()?,
214 Json(JsonMetadata(Some(Empty {})))
215 );
216
217 let mut field = Field::new("", DataType::Utf8View, false);
218 field.try_with_extension_type(Json::default())?;
219 field.try_extension_type::<Json>()?;
220 #[cfg(feature = "canonical_extension_types")]
221 assert_eq!(
222 field.try_canonical_extension_type()?,
223 CanonicalExtensionType::Json(Json::default())
224 );
225 Ok(())
226 }
227
228 #[test]
229 #[should_panic(expected = "Extension type name missing")]
230 fn missing_name() {
231 let field = Field::new("", DataType::Int8, false).with_metadata(
232 [(EXTENSION_TYPE_METADATA_KEY.to_owned(), "{}".to_owned())]
233 .into_iter()
234 .collect(),
235 );
236 field.extension_type::<Json>();
237 }
238
239 #[test]
240 #[should_panic(expected = "expected one of Utf8, LargeUtf8, Utf8View, found Null")]
241 fn invalid_type() {
242 Field::new("", DataType::Null, false).with_extension_type(Json::default());
243 }
244
245 #[test]
246 #[should_panic(
247 expected = "Json extension type metadata is either an empty string or a JSON string with an empty object"
248 )]
249 fn invalid_metadata() {
250 let field = Field::new("", DataType::Utf8, false).with_metadata(
251 [
252 (EXTENSION_TYPE_NAME_KEY.to_owned(), Json::NAME.to_owned()),
253 (EXTENSION_TYPE_METADATA_KEY.to_owned(), "1234".to_owned()),
254 ]
255 .into_iter()
256 .collect(),
257 );
258 field.extension_type::<Json>();
259 }
260
261 #[test]
262 #[should_panic(
263 expected = "Json extension type metadata is either an empty string or a JSON string with an empty object"
264 )]
265 fn missing_metadata() {
266 let field = Field::new("", DataType::LargeUtf8, false).with_metadata(
267 [(EXTENSION_TYPE_NAME_KEY.to_owned(), Json::NAME.to_owned())]
268 .into_iter()
269 .collect(),
270 );
271 field.extension_type::<Json>();
272 }
273}