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().ok_or_else(|| {
263 ArrowError::ParseError(
264 "Field 'id' attribute is not an integer".to_string(),
265 )
266 })?,
267 _ => {
268 return Err(ArrowError::ParseError(
269 "Field missing 'id' attribute".to_string(),
270 ));
271 }
272 };
273 dict_is_ordered = match dictionary.get("isOrdered") {
274 Some(&Value::Bool(n)) => n,
275 _ => {
276 return Err(ArrowError::ParseError(
277 "Field missing 'isOrdered' attribute".to_string(),
278 ));
279 }
280 };
281 DataType::Dictionary(Box::new(index_type), Box::new(data_type))
282 }
283 _ => data_type,
284 };
285
286 #[expect(deprecated)]
287 let mut field = Field::new_dict(name, data_type, nullable, dict_id, dict_is_ordered);
288 field.set_metadata(metadata);
289 Ok(field)
290 }
291 _ => Err(ArrowError::ParseError(
292 "Invalid json value type for field".to_string(),
293 )),
294 }
295}
296
297pub fn field_to_json(field: &Field) -> serde_json::Value {
299 let children: Vec<serde_json::Value> = match field.data_type() {
300 DataType::Struct(fields) => fields.iter().map(|x| field_to_json(x.as_ref())).collect(),
301 DataType::List(field)
302 | DataType::LargeList(field)
303 | DataType::ListView(field)
304 | DataType::LargeListView(field)
305 | DataType::FixedSizeList(field, _)
306 | DataType::Map(field, _) => vec![field_to_json(field)],
307 DataType::RunEndEncoded(run_ends, values) => {
308 vec![field_to_json(run_ends), field_to_json(values)]
309 }
310 _ => vec![],
311 };
312
313 let mut json = match field.data_type() {
314 DataType::Dictionary(index_type, value_type) => {
315 #[expect(deprecated)]
316 let dict_id = field.dict_id().unwrap();
317 serde_json::json!({
318 "name": field.name(),
319 "nullable": field.is_nullable(),
320 "type": data_type_to_json(value_type),
321 "children": children,
322 "dictionary": {
323 "id": dict_id,
324 "indexType": data_type_to_json(index_type),
325 "isOrdered": field.dict_is_ordered().unwrap(),
326 }
327 })
328 }
329 _ => serde_json::json!({
330 "name": field.name(),
331 "nullable": field.is_nullable(),
332 "type": data_type_to_json(field.data_type()),
333 "children": children
334 }),
335 };
336
337 if !field.metadata().is_empty() {
338 json["metadata"] = field
339 .metadata()
340 .iter()
341 .map(|(key, value)| (key.clone(), value.clone()))
342 .collect();
343 }
344
345 json
346}
347
348#[cfg(test)]
349mod tests {
350 use super::*;
351 use arrow::datatypes::UnionMode;
352 use serde_json::Value;
353
354 #[test]
355 fn struct_field_to_json() {
356 let f = Field::new_struct(
357 "address",
358 vec![
359 Field::new("street", DataType::Utf8, false),
360 Field::new("zip", DataType::UInt16, false),
361 ],
362 false,
363 );
364 let value: Value = serde_json::from_str(
365 r#"{
366 "name": "address",
367 "nullable": false,
368 "type": {
369 "name": "struct"
370 },
371 "children": [
372 {
373 "name": "street",
374 "nullable": false,
375 "type": {
376 "name": "utf8"
377 },
378 "children": []
379 },
380 {
381 "name": "zip",
382 "nullable": false,
383 "type": {
384 "name": "int",
385 "bitWidth": 16,
386 "isSigned": false
387 },
388 "children": []
389 }
390 ]
391 }"#,
392 )
393 .unwrap();
394 assert_eq!(value, field_to_json(&f));
395 }
396
397 #[test]
398 fn map_field_to_json() {
399 let f = Field::new_map(
400 "my_map",
401 "my_entries",
402 Field::new("my_keys", DataType::Utf8, false),
403 Field::new("my_values", DataType::UInt16, true),
404 true,
405 false,
406 );
407 let value: Value = serde_json::from_str(
408 r#"{
409 "name": "my_map",
410 "nullable": false,
411 "type": {
412 "name": "map",
413 "keysSorted": true
414 },
415 "children": [
416 {
417 "name": "my_entries",
418 "nullable": false,
419 "type": {
420 "name": "struct"
421 },
422 "children": [
423 {
424 "name": "my_keys",
425 "nullable": false,
426 "type": {
427 "name": "utf8"
428 },
429 "children": []
430 },
431 {
432 "name": "my_values",
433 "nullable": true,
434 "type": {
435 "name": "int",
436 "bitWidth": 16,
437 "isSigned": false
438 },
439 "children": []
440 }
441 ]
442 }
443 ]
444 }"#,
445 )
446 .unwrap();
447 assert_eq!(value, field_to_json(&f));
448 }
449
450 #[test]
451 fn primitive_field_to_json() {
452 let f = Field::new("first_name", DataType::Utf8, false);
453 let value: Value = serde_json::from_str(
454 r#"{
455 "name": "first_name",
456 "nullable": false,
457 "type": {
458 "name": "utf8"
459 },
460 "children": []
461 }"#,
462 )
463 .unwrap();
464 assert_eq!(value, field_to_json(&f));
465 }
466 #[test]
467 fn parse_struct_from_json() {
468 let json = r#"
469 {
470 "name": "address",
471 "type": {
472 "name": "struct"
473 },
474 "nullable": false,
475 "children": [
476 {
477 "name": "street",
478 "type": {
479 "name": "utf8"
480 },
481 "nullable": false,
482 "children": []
483 },
484 {
485 "name": "zip",
486 "type": {
487 "name": "int",
488 "isSigned": false,
489 "bitWidth": 16
490 },
491 "nullable": false,
492 "children": []
493 }
494 ]
495 }
496 "#;
497 let value: Value = serde_json::from_str(json).unwrap();
498 let dt = field_from_json(&value).unwrap();
499
500 let expected = Field::new_struct(
501 "address",
502 vec![
503 Field::new("street", DataType::Utf8, false),
504 Field::new("zip", DataType::UInt16, false),
505 ],
506 false,
507 );
508
509 assert_eq!(expected, dt);
510 }
511
512 #[test]
513 fn parse_map_from_json() {
514 let json = r#"
515 {
516 "name": "my_map",
517 "nullable": false,
518 "type": {
519 "name": "map",
520 "keysSorted": true
521 },
522 "children": [
523 {
524 "name": "my_entries",
525 "nullable": false,
526 "type": {
527 "name": "struct"
528 },
529 "children": [
530 {
531 "name": "my_keys",
532 "nullable": false,
533 "type": {
534 "name": "utf8"
535 },
536 "children": []
537 },
538 {
539 "name": "my_values",
540 "nullable": true,
541 "type": {
542 "name": "int",
543 "bitWidth": 16,
544 "isSigned": false
545 },
546 "children": []
547 }
548 ]
549 }
550 ]
551 }
552 "#;
553 let value: Value = serde_json::from_str(json).unwrap();
554 let dt = field_from_json(&value).unwrap();
555
556 let expected = Field::new_map(
557 "my_map",
558 "my_entries",
559 Field::new("my_keys", DataType::Utf8, false),
560 Field::new("my_values", DataType::UInt16, true),
561 true,
562 false,
563 );
564
565 assert_eq!(expected, dt);
566 }
567
568 #[test]
569 fn parse_union_from_json() {
570 let json = r#"
571 {
572 "name": "my_union",
573 "nullable": false,
574 "type": {
575 "name": "union",
576 "mode": "SPARSE",
577 "typeIds": [
578 5,
579 7
580 ]
581 },
582 "children": [
583 {
584 "name": "f1",
585 "type": {
586 "name": "int",
587 "isSigned": true,
588 "bitWidth": 32
589 },
590 "nullable": true,
591 "children": []
592 },
593 {
594 "name": "f2",
595 "type": {
596 "name": "utf8"
597 },
598 "nullable": true,
599 "children": []
600 }
601 ]
602 }
603 "#;
604 let value: Value = serde_json::from_str(json).unwrap();
605 let dt = field_from_json(&value).unwrap();
606
607 let expected = Field::new_union(
608 "my_union",
609 vec![5, 7],
610 vec![
611 Field::new("f1", DataType::Int32, true),
612 Field::new("f2", DataType::Utf8, true),
613 ],
614 UnionMode::Sparse,
615 );
616
617 assert_eq!(expected, dt);
618 }
619}