1use crate::{data_type_from_json, data_type_to_json};
19use arrow::datatypes::{DataType, Field};
20use arrow::error::{ArrowError, Result};
21use std::collections::HashMap;
22use std::sync::Arc;
23
24pub fn field_from_json(json: &serde_json::Value) -> Result<Field> {
26 use serde_json::Value;
27 match *json {
28 Value::Object(ref map) => {
29 let name = match map.get("name") {
30 Some(Value::String(name)) => name.clone(),
31 _ => {
32 return Err(ArrowError::ParseError(
33 "Field missing 'name' attribute".to_string(),
34 ));
35 }
36 };
37 let Some(&Value::Bool(nullable)) = map.get("nullable") else {
38 return Err(ArrowError::ParseError(
39 "Field missing 'nullable' attribute".to_string(),
40 ));
41 };
42 let data_type = match map.get("type") {
43 Some(t) => data_type_from_json(t)?,
44 _ => {
45 return Err(ArrowError::ParseError(
46 "Field missing 'type' attribute".to_string(),
47 ));
48 }
49 };
50
51 let metadata = match map.get("metadata") {
53 Some(Value::Array(values)) => {
54 let mut res: HashMap<String, String> = HashMap::default();
55 for value in values {
56 match value.as_object() {
57 Some(map) => {
58 if map.len() != 2 {
59 return Err(ArrowError::ParseError(
60 "Field 'metadata' must have exact two entries for each key-value map".to_string(),
61 ));
62 }
63 if let (Some(k), Some(v)) = (map.get("key"), map.get("value")) {
64 if let (Some(k_str), Some(v_str)) = (k.as_str(), v.as_str()) {
65 res.insert(
66 k_str.to_string().clone(),
67 v_str.to_string().clone(),
68 );
69 } else {
70 return Err(ArrowError::ParseError(
71 "Field 'metadata' must have map value of string type"
72 .to_string(),
73 ));
74 }
75 } else {
76 return Err(ArrowError::ParseError("Field 'metadata' lacks map keys named \"key\" or \"value\"".to_string()));
77 }
78 }
79 _ => {
80 return Err(ArrowError::ParseError(
81 "Field 'metadata' contains non-object key-value pair"
82 .to_string(),
83 ));
84 }
85 }
86 }
87 res
88 }
89 Some(Value::Object(values)) => {
92 let mut res: HashMap<String, String> = HashMap::default();
93 for (k, v) in values {
94 if let Some(str_value) = v.as_str() {
95 res.insert(k.clone(), str_value.to_string().clone());
96 } else {
97 return Err(ArrowError::ParseError(format!(
98 "Field 'metadata' contains non-string value for key {k}"
99 )));
100 }
101 }
102 res
103 }
104 Some(_) => {
105 return Err(ArrowError::ParseError(
106 "Field `metadata` is not json array".to_string(),
107 ));
108 }
109 _ => HashMap::default(),
110 };
111
112 let data_type = match data_type {
114 DataType::List(_)
115 | DataType::LargeList(_)
116 | DataType::ListView(_)
117 | DataType::LargeListView(_)
118 | DataType::FixedSizeList(_, _) => match map.get("children") {
119 Some(Value::Array(values)) => {
120 if values.len() != 1 {
121 return Err(ArrowError::ParseError(
122 "Field 'children' must have one element for a list data type"
123 .to_string(),
124 ));
125 }
126 match data_type {
127 DataType::List(_) => {
128 DataType::List(Arc::new(field_from_json(&values[0])?))
129 }
130 DataType::LargeList(_) => {
131 DataType::LargeList(Arc::new(field_from_json(&values[0])?))
132 }
133 DataType::ListView(_) => {
134 DataType::ListView(Arc::new(field_from_json(&values[0])?))
135 }
136 DataType::LargeListView(_) => {
137 DataType::LargeListView(Arc::new(field_from_json(&values[0])?))
138 }
139 DataType::FixedSizeList(_, int) => {
140 DataType::FixedSizeList(Arc::new(field_from_json(&values[0])?), int)
141 }
142 _ => unreachable!(
143 "Data type should be a list, largelist, listview, largelistview or fixedsizelist"
144 ),
145 }
146 }
147 Some(_) => {
148 return Err(ArrowError::ParseError(
149 "Field 'children' must be an array".to_string(),
150 ));
151 }
152 None => {
153 return Err(ArrowError::ParseError(
154 "Field missing 'children' attribute".to_string(),
155 ));
156 }
157 },
158 DataType::Struct(_) => match map.get("children") {
159 Some(Value::Array(values)) => {
160 DataType::Struct(values.iter().map(field_from_json).collect::<Result<_>>()?)
161 }
162 Some(_) => {
163 return Err(ArrowError::ParseError(
164 "Field 'children' must be an array".to_string(),
165 ));
166 }
167 None => {
168 return Err(ArrowError::ParseError(
169 "Field missing 'children' attribute".to_string(),
170 ));
171 }
172 },
173 DataType::Map(_, keys_sorted) => {
174 match map.get("children") {
175 Some(Value::Array(values)) if values.len() == 1 => {
176 let child = field_from_json(&values[0])?;
177 match child.data_type() {
179 DataType::Struct(map_fields) if map_fields.len() == 2 => {
180 DataType::Map(Arc::new(child), keys_sorted)
181 }
182 t => {
183 return Err(ArrowError::ParseError(format!(
184 "Map children should be a struct with 2 fields, found {t:?}"
185 )));
186 }
187 }
188 }
189 Some(_) => {
190 return Err(ArrowError::ParseError(
191 "Field 'children' must be an array with 1 element".to_string(),
192 ));
193 }
194 None => {
195 return Err(ArrowError::ParseError(
196 "Field missing 'children' attribute".to_string(),
197 ));
198 }
199 }
200 }
201 DataType::Union(fields, mode) => match map.get("children") {
202 Some(Value::Array(values)) => {
203 let fields = fields
204 .iter()
205 .zip(values)
206 .map(|((id, _), value)| Ok((id, Arc::new(field_from_json(value)?))))
207 .collect::<Result<_>>()?;
208
209 DataType::Union(fields, mode)
210 }
211 Some(_) => {
212 return Err(ArrowError::ParseError(
213 "Field 'children' must be an array".to_string(),
214 ));
215 }
216 None => {
217 return Err(ArrowError::ParseError(
218 "Field missing 'children' attribute".to_string(),
219 ));
220 }
221 },
222 DataType::RunEndEncoded(_, _) => match map.get("children") {
223 Some(Value::Array(values)) => {
224 if values.len() != 2 {
225 return Err(ArrowError::ParseError(
226 "Field 'children' must have exactly 2 elements for RunEndEncoded"
227 .to_string(),
228 ));
229 }
230 let run_ends = Arc::new(field_from_json(&values[0])?);
231 let values_field = Arc::new(field_from_json(&values[1])?);
232 DataType::RunEndEncoded(run_ends, values_field)
233 }
234 Some(_) => {
235 return Err(ArrowError::ParseError(
236 "Field 'children' must be an array".to_string(),
237 ));
238 }
239 None => {
240 return Err(ArrowError::ParseError(
241 "Field missing 'children' attribute".to_string(),
242 ));
243 }
244 },
245 _ => data_type,
246 };
247
248 let mut dict_id = 0;
249 let mut dict_is_ordered = false;
250
251 let data_type = match map.get("dictionary") {
252 Some(dictionary) => {
253 let index_type = match dictionary.get("indexType") {
254 Some(t) => data_type_from_json(t)?,
255 _ => {
256 return Err(ArrowError::ParseError(
257 "Field missing 'indexType' attribute".to_string(),
258 ));
259 }
260 };
261 dict_id = match dictionary.get("id") {
262 Some(Value::Number(n)) => n.as_i64().unwrap(),
263 _ => {
264 return Err(ArrowError::ParseError(
265 "Field missing 'id' attribute".to_string(),
266 ));
267 }
268 };
269 dict_is_ordered = match dictionary.get("isOrdered") {
270 Some(&Value::Bool(n)) => n,
271 _ => {
272 return Err(ArrowError::ParseError(
273 "Field missing 'isOrdered' attribute".to_string(),
274 ));
275 }
276 };
277 DataType::Dictionary(Box::new(index_type), Box::new(data_type))
278 }
279 _ => data_type,
280 };
281
282 #[expect(deprecated)]
283 let mut field = Field::new_dict(name, data_type, nullable, dict_id, dict_is_ordered);
284 field.set_metadata(metadata);
285 Ok(field)
286 }
287 _ => Err(ArrowError::ParseError(
288 "Invalid json value type for field".to_string(),
289 )),
290 }
291}
292
293pub fn field_to_json(field: &Field) -> serde_json::Value {
295 let children: Vec<serde_json::Value> = match field.data_type() {
296 DataType::Struct(fields) => fields.iter().map(|x| field_to_json(x.as_ref())).collect(),
297 DataType::List(field)
298 | DataType::LargeList(field)
299 | DataType::ListView(field)
300 | DataType::LargeListView(field)
301 | DataType::FixedSizeList(field, _)
302 | DataType::Map(field, _) => vec![field_to_json(field)],
303 DataType::RunEndEncoded(run_ends, values) => {
304 vec![field_to_json(run_ends), field_to_json(values)]
305 }
306 _ => vec![],
307 };
308
309 match field.data_type() {
310 DataType::Dictionary(index_type, value_type) => {
311 #[expect(deprecated)]
312 let dict_id = field.dict_id().unwrap();
313 serde_json::json!({
314 "name": field.name(),
315 "nullable": field.is_nullable(),
316 "type": data_type_to_json(value_type),
317 "children": children,
318 "dictionary": {
319 "id": dict_id,
320 "indexType": data_type_to_json(index_type),
321 "isOrdered": field.dict_is_ordered().unwrap(),
322 }
323 })
324 }
325 _ => serde_json::json!({
326 "name": field.name(),
327 "nullable": field.is_nullable(),
328 "type": data_type_to_json(field.data_type()),
329 "children": children
330 }),
331 }
332}
333
334#[cfg(test)]
335mod tests {
336 use super::*;
337 use arrow::datatypes::UnionMode;
338 use serde_json::Value;
339
340 #[test]
341 fn struct_field_to_json() {
342 let f = Field::new_struct(
343 "address",
344 vec![
345 Field::new("street", DataType::Utf8, false),
346 Field::new("zip", DataType::UInt16, false),
347 ],
348 false,
349 );
350 let value: Value = serde_json::from_str(
351 r#"{
352 "name": "address",
353 "nullable": false,
354 "type": {
355 "name": "struct"
356 },
357 "children": [
358 {
359 "name": "street",
360 "nullable": false,
361 "type": {
362 "name": "utf8"
363 },
364 "children": []
365 },
366 {
367 "name": "zip",
368 "nullable": false,
369 "type": {
370 "name": "int",
371 "bitWidth": 16,
372 "isSigned": false
373 },
374 "children": []
375 }
376 ]
377 }"#,
378 )
379 .unwrap();
380 assert_eq!(value, field_to_json(&f));
381 }
382
383 #[test]
384 fn map_field_to_json() {
385 let f = Field::new_map(
386 "my_map",
387 "my_entries",
388 Field::new("my_keys", DataType::Utf8, false),
389 Field::new("my_values", DataType::UInt16, true),
390 true,
391 false,
392 );
393 let value: Value = serde_json::from_str(
394 r#"{
395 "name": "my_map",
396 "nullable": false,
397 "type": {
398 "name": "map",
399 "keysSorted": true
400 },
401 "children": [
402 {
403 "name": "my_entries",
404 "nullable": false,
405 "type": {
406 "name": "struct"
407 },
408 "children": [
409 {
410 "name": "my_keys",
411 "nullable": false,
412 "type": {
413 "name": "utf8"
414 },
415 "children": []
416 },
417 {
418 "name": "my_values",
419 "nullable": true,
420 "type": {
421 "name": "int",
422 "bitWidth": 16,
423 "isSigned": false
424 },
425 "children": []
426 }
427 ]
428 }
429 ]
430 }"#,
431 )
432 .unwrap();
433 assert_eq!(value, field_to_json(&f));
434 }
435
436 #[test]
437 fn primitive_field_to_json() {
438 let f = Field::new("first_name", DataType::Utf8, false);
439 let value: Value = serde_json::from_str(
440 r#"{
441 "name": "first_name",
442 "nullable": false,
443 "type": {
444 "name": "utf8"
445 },
446 "children": []
447 }"#,
448 )
449 .unwrap();
450 assert_eq!(value, field_to_json(&f));
451 }
452 #[test]
453 fn parse_struct_from_json() {
454 let json = r#"
455 {
456 "name": "address",
457 "type": {
458 "name": "struct"
459 },
460 "nullable": false,
461 "children": [
462 {
463 "name": "street",
464 "type": {
465 "name": "utf8"
466 },
467 "nullable": false,
468 "children": []
469 },
470 {
471 "name": "zip",
472 "type": {
473 "name": "int",
474 "isSigned": false,
475 "bitWidth": 16
476 },
477 "nullable": false,
478 "children": []
479 }
480 ]
481 }
482 "#;
483 let value: Value = serde_json::from_str(json).unwrap();
484 let dt = field_from_json(&value).unwrap();
485
486 let expected = Field::new_struct(
487 "address",
488 vec![
489 Field::new("street", DataType::Utf8, false),
490 Field::new("zip", DataType::UInt16, false),
491 ],
492 false,
493 );
494
495 assert_eq!(expected, dt);
496 }
497
498 #[test]
499 fn parse_map_from_json() {
500 let json = r#"
501 {
502 "name": "my_map",
503 "nullable": false,
504 "type": {
505 "name": "map",
506 "keysSorted": true
507 },
508 "children": [
509 {
510 "name": "my_entries",
511 "nullable": false,
512 "type": {
513 "name": "struct"
514 },
515 "children": [
516 {
517 "name": "my_keys",
518 "nullable": false,
519 "type": {
520 "name": "utf8"
521 },
522 "children": []
523 },
524 {
525 "name": "my_values",
526 "nullable": true,
527 "type": {
528 "name": "int",
529 "bitWidth": 16,
530 "isSigned": false
531 },
532 "children": []
533 }
534 ]
535 }
536 ]
537 }
538 "#;
539 let value: Value = serde_json::from_str(json).unwrap();
540 let dt = field_from_json(&value).unwrap();
541
542 let expected = Field::new_map(
543 "my_map",
544 "my_entries",
545 Field::new("my_keys", DataType::Utf8, false),
546 Field::new("my_values", DataType::UInt16, true),
547 true,
548 false,
549 );
550
551 assert_eq!(expected, dt);
552 }
553
554 #[test]
555 fn parse_union_from_json() {
556 let json = r#"
557 {
558 "name": "my_union",
559 "nullable": false,
560 "type": {
561 "name": "union",
562 "mode": "SPARSE",
563 "typeIds": [
564 5,
565 7
566 ]
567 },
568 "children": [
569 {
570 "name": "f1",
571 "type": {
572 "name": "int",
573 "isSigned": true,
574 "bitWidth": 32
575 },
576 "nullable": true,
577 "children": []
578 },
579 {
580 "name": "f2",
581 "type": {
582 "name": "utf8"
583 },
584 "nullable": true,
585 "children": []
586 }
587 ]
588 }
589 "#;
590 let value: Value = serde_json::from_str(json).unwrap();
591 let dt = field_from_json(&value).unwrap();
592
593 let expected = Field::new_union(
594 "my_union",
595 vec![5, 7],
596 vec![
597 Field::new("f1", DataType::Int32, true),
598 Field::new("f2", DataType::Utf8, true),
599 ],
600 UnionMode::Sparse,
601 );
602
603 assert_eq!(expected, dt);
604 }
605}