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