1pub mod value;
23
24use std::collections::BTreeMap;
25use std::collections::btree_map::Entry;
26
27use serde::{Deserialize, Serialize};
28use serde_json::{Map, Value as Json};
29use snafu::ResultExt;
30
31use crate::data_type::ConcreteDataType;
32use crate::error::{self, Result, UnsupportedJsonTypeSnafu};
33use crate::json::value::{JsonValue, JsonVariant};
34use crate::schema::ColumnDefaultConstraint;
35use crate::types::json_type::JsonNativeType;
36use crate::value::{ListValue, StructValue, Value};
37
38#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
41pub struct JsonSettings {
42 #[serde(default)]
43 pub type_hints: Vec<JsonTypeHint>,
44}
45
46#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
52pub struct JsonTypeHint {
53 pub path: Vec<String>,
61 #[serde(rename = "type")]
62 pub data_type: ConcreteDataType,
63 pub nullable: bool,
64 #[serde(skip_serializing_if = "Option::is_none")]
65 pub default_constraint: Option<ColumnDefaultConstraint>,
66 pub inverted_index: bool,
67}
68
69#[derive(Clone, Debug)]
71pub struct JsonContext<'a> {
72 pub path: Vec<String>,
74 pub settings: &'a JsonSettings,
76}
77
78impl JsonSettings {
79 pub fn new(type_hints: Vec<JsonTypeHint>) -> Self {
80 Self { type_hints }
81 }
82
83 pub fn decode(&self, value: Value) -> Result<Json> {
85 let mut context = JsonContext {
86 path: Vec::new(),
87 settings: self,
88 };
89 decode_value_with_context(value, &mut context)
90 }
91
92 pub fn encode(&self, json: Json) -> Result<Value> {
94 let mut context = JsonContext {
95 path: Vec::new(),
96 settings: self,
97 };
98 encode_json_with_context(json, &mut context).map(|v| Value::Json(Box::new(v)))
99 }
100}
101
102impl<'a> JsonContext<'a> {
103 fn type_hint(&self) -> Option<&'a JsonTypeHint> {
104 self.settings
105 .type_hints
106 .iter()
107 .find(|hint| hint.path == self.path)
108 }
109}
110
111fn with_key_context<T>(
112 context: &mut JsonContext,
113 key: &str,
114 f: impl FnOnce(&mut JsonContext) -> Result<T>,
115) -> Result<T> {
116 context.path.push(key.to_string());
117 let result = f(context);
118 context.path.pop();
119 result
120}
121
122fn encode_json_with_context(json: Json, context: &mut JsonContext) -> Result<JsonValue> {
124 if context.path.is_empty() && !matches!(json, Json::Object(_)) {
125 return UnsupportedJsonTypeSnafu.fail();
126 }
127
128 match json {
129 Json::Object(json_object) => encode_json_object_with_context(json_object, context),
130 Json::Array(json_array) => encode_json_array_with_context(json_array, context),
131 _ => encode_json_value_with_context(json, context),
132 }
133}
134
135fn encode_json_object_with_context<'a>(
136 json_object: Map<String, Json>,
137 context: &mut JsonContext<'a>,
138) -> Result<JsonValue> {
139 let mut object = BTreeMap::new();
140 for (key, value) in json_object {
141 let value = with_key_context(context, &key, |context| {
142 if let Some(hint) = context.type_hint() {
143 encode_json_value_with_hint(value, hint, context)
144 } else {
145 encode_json_value_with_context(value, context)
146 }
147 })?;
148
149 object.insert(key, value.into_variant());
150 }
151
152 apply_missing_type_hints(&mut object, context)?;
153
154 Ok(JsonValue::new(JsonVariant::Object(object)))
155}
156
157fn apply_missing_type_hints(
158 object: &mut BTreeMap<String, JsonVariant>,
159 context: &mut JsonContext,
160) -> Result<()> {
161 for hint in &context.settings.type_hints {
162 if hint.path.len() > context.path.len() && hint.path.starts_with(&context.path) {
163 let depth = context.path.len();
164 let key = &hint.path[depth];
165 with_key_context(context, key, |context| {
166 insert_missing_type_hint(object, context, hint, depth)
167 })?;
168 }
169 }
170 Ok(())
171}
172
173fn insert_missing_type_hint(
174 object: &mut BTreeMap<String, JsonVariant>,
175 field_context: &mut JsonContext,
176 hint: &JsonTypeHint,
177 depth: usize,
178) -> Result<()> {
179 let key = &hint.path[depth];
180 let is_leaf = depth + 1 == hint.path.len();
181
182 if is_leaf {
183 if !object.contains_key(key) {
184 let value = encode_missing_type_hint_value(hint, field_context)?;
185 object.insert(key.clone(), value.into_variant());
186 }
187 return Ok(());
188 }
189
190 match object.entry(key.clone()) {
191 Entry::Occupied(mut entry) => match entry.get_mut() {
192 JsonVariant::Object(child) => {
193 insert_missing_type_hint(child, field_context, hint, depth + 1)
194 }
195 _ => error::InvalidJsonSnafu {
196 value: format!(
197 "JSON2 type hint path {} expects object at {}",
198 hint.path.join("."),
199 field_context.path.join(".")
200 ),
201 }
202 .fail(),
203 },
204 Entry::Vacant(entry) => {
205 let mut child = BTreeMap::new();
206 insert_missing_type_hint(&mut child, field_context, hint, depth + 1)?;
207 entry.insert(JsonVariant::Object(child));
208 Ok(())
209 }
210 }
211}
212
213fn encode_missing_type_hint_value(
214 hint: &JsonTypeHint,
215 context: &mut JsonContext,
216) -> Result<JsonValue> {
217 if let Some(default_constraint) = &hint.default_constraint {
218 let value = default_constraint.create_default(&hint.data_type, hint.nullable)?;
219 let json = decode_primitive_value(value)?;
220 return encode_json_value_with_hint(json, hint, context);
221 }
222
223 if hint.nullable {
224 Ok(JsonValue::null())
225 } else {
226 error::InvalidJsonSnafu {
227 value: format!(
228 "missing non-null JSON2 type hint path {}",
229 hint.path.join(".")
230 ),
231 }
232 .fail()
233 }
234}
235
236fn encode_json_value_with_hint(
237 json: Json,
238 hint: &JsonTypeHint,
239 context: &mut JsonContext,
240) -> Result<JsonValue> {
241 if json.is_null() {
242 return if hint.nullable {
243 Ok(JsonValue::null())
244 } else {
245 error::InvalidJsonSnafu {
246 value: format!(
247 "JSON2 type hint path {} is not nullable",
248 context.path.join(".")
249 ),
250 }
251 .fail()
252 };
253 }
254
255 let invalid_type = || {
256 error::InvalidJsonSnafu {
257 value: format!(
258 "JSON value at {} does not match JSON2 type hint {}",
259 context.path.join("."),
260 hint.data_type
261 ),
262 }
263 .fail()
264 };
265
266 match (&hint.data_type, json) {
267 (ConcreteDataType::String(_), Json::String(v)) => Ok(v.into()),
268 (
269 ConcreteDataType::Int8(_)
270 | ConcreteDataType::Int16(_)
271 | ConcreteDataType::Int32(_)
272 | ConcreteDataType::Int64(_),
273 Json::Number(v),
274 ) => match v.as_i64() {
275 Some(v) => Ok(v.into()),
276 None => invalid_type(),
277 },
278 (
279 ConcreteDataType::UInt8(_)
280 | ConcreteDataType::UInt16(_)
281 | ConcreteDataType::UInt32(_)
282 | ConcreteDataType::UInt64(_),
283 Json::Number(v),
284 ) => match v.as_u64() {
285 Some(v) => Ok(v.into()),
286 None => invalid_type(),
287 },
288 (ConcreteDataType::Float32(_) | ConcreteDataType::Float64(_), Json::Number(v)) => {
289 match v.as_f64() {
290 Some(v) => Ok(v.into()),
291 None => invalid_type(),
292 }
293 }
294 (ConcreteDataType::Boolean(_), Json::Bool(v)) => Ok(v.into()),
295 _ => invalid_type(),
296 }
297}
298
299fn encode_json_array_with_context<'a>(
300 json_array: Vec<Json>,
301 context: &mut JsonContext<'a>,
302) -> Result<JsonValue> {
303 let json_array_len = json_array.len();
304 let mut items = Vec::with_capacity(json_array_len);
305
306 for (index, value) in json_array.into_iter().enumerate() {
307 let item_value = with_key_context(context, &index.to_string(), |context| {
308 encode_json_value_with_context(value, context)
309 })?;
310 items.push(item_value);
311 }
312
313 let merged_item_type = if let Some((first, rests)) = items.split_first() {
319 let mut merged = first.json_type().clone();
320 for rest in rests.iter().map(|x| x.json_type()) {
321 if matches!(merged, JsonNativeType::Variant) {
322 break;
323 }
324 merged.merge(rest);
325 }
326 Some(merged)
327 } else {
328 None
329 };
330 if let Some(unified_item_type) = merged_item_type {
331 for item in &mut items {
332 item.try_align(&unified_item_type)?;
333 }
334 }
335 let items = items
336 .into_iter()
337 .map(|x| x.into_variant())
338 .collect::<Vec<_>>();
339 Ok(JsonValue::new(JsonVariant::Array(items)))
340}
341
342fn encode_json_value_with_context(json: Json, context: &mut JsonContext) -> Result<JsonValue> {
344 match json {
345 Json::Null => Ok(JsonValue::null()),
346 Json::Bool(b) => Ok(b.into()),
347 Json::Number(n) => {
348 if let Some(i) = n.as_i64() {
349 Ok(i.into())
350 } else if let Some(u) = n.as_u64() {
351 if u <= i64::MAX as u64 {
352 Ok((u as i64).into())
353 } else {
354 Ok(u.into())
355 }
356 } else if let Some(f) = n.as_f64() {
357 Ok(f.into())
358 } else {
359 Ok(n.to_string().into())
361 }
362 }
363 Json::String(s) => Ok(s.into()),
364 Json::Array(arr) => encode_json_array_with_context(arr, context),
365 Json::Object(obj) => encode_json_object_with_context(obj, context),
366 }
367}
368
369fn decode_value_with_context(value: Value, context: &mut JsonContext) -> Result<Json> {
371 match value {
372 Value::Struct(struct_value) => decode_struct_with_context(struct_value, context),
373 Value::List(list_value) => decode_list_with_context(list_value, context),
374 _ => decode_primitive_value(value),
375 }
376}
377
378fn decode_struct_with_context<'a>(
380 struct_value: StructValue,
381 context: &mut JsonContext<'a>,
382) -> Result<Json> {
383 let mut json_object = Map::with_capacity(struct_value.len());
384
385 let (items, fields) = struct_value.into_parts();
386
387 for (field, field_value) in fields.fields().iter().zip(items) {
388 let json_value = with_key_context(context, field.name(), |context| {
389 decode_value_with_context(field_value, context)
390 })?;
391 json_object.insert(field.name().to_string(), json_value);
392 }
393
394 Ok(Json::Object(json_object))
395}
396
397fn decode_list_with_context(list_value: ListValue, context: &mut JsonContext) -> Result<Json> {
399 let mut json_array = Vec::with_capacity(list_value.len());
400
401 let data_items = list_value.take_items();
402
403 for (index, item) in data_items.into_iter().enumerate() {
404 let json_value = with_key_context(context, &index.to_string(), |context| {
405 decode_value_with_context(item, context)
406 })?;
407 json_array.push(json_value);
408 }
409
410 Ok(Json::Array(json_array))
411}
412
413fn decode_primitive_value(value: Value) -> Result<Json> {
415 match value {
416 Value::Null => Ok(Json::Null),
417 Value::Boolean(b) => Ok(Json::Bool(b)),
418 Value::UInt8(v) => Ok(Json::from(v)),
419 Value::UInt16(v) => Ok(Json::from(v)),
420 Value::UInt32(v) => Ok(Json::from(v)),
421 Value::UInt64(v) => Ok(Json::from(v)),
422 Value::Int8(v) => Ok(Json::from(v)),
423 Value::Int16(v) => Ok(Json::from(v)),
424 Value::Int32(v) => Ok(Json::from(v)),
425 Value::Int64(v) => Ok(Json::from(v)),
426 Value::Float32(v) => Ok(Json::from(v.0)),
427 Value::Float64(v) => Ok(Json::from(v.0)),
428 Value::String(s) => Ok(Json::String(s.as_utf8().to_string())),
429 Value::Binary(b) => serde_json::to_value(b.as_ref()).context(error::SerializeSnafu),
430 Value::Date(v) => Ok(Json::from(v.val())),
431 Value::Timestamp(v) => serde_json::to_value(v.value()).context(error::SerializeSnafu),
432 Value::Time(v) => serde_json::to_value(v.value()).context(error::SerializeSnafu),
433 Value::IntervalYearMonth(v) => {
434 serde_json::to_value(v.to_i32()).context(error::SerializeSnafu)
435 }
436 Value::IntervalDayTime(v) => {
437 serde_json::to_value(v.to_i64()).context(error::SerializeSnafu)
438 }
439 Value::IntervalMonthDayNano(v) => {
440 serde_json::to_value(v.to_i128()).context(error::SerializeSnafu)
441 }
442 Value::Duration(v) => serde_json::to_value(v.value()).context(error::SerializeSnafu),
443 Value::Decimal128(v) => serde_json::to_value(v.to_string()).context(error::SerializeSnafu),
444 Value::Struct(_) | Value::List(_) | Value::Json(_) => {
445 Err(error::InvalidJsonSnafu {
447 value: "Structured values should be handled by context-aware decoding".to_string(),
448 }
449 .build())
450 }
451 }
452}
453
454#[cfg(test)]
455mod tests {
456 use std::sync::Arc;
457
458 use serde_json::json;
459
460 use super::*;
461 use crate::data_type::ConcreteDataType;
462 use crate::types::{ListType, StructField, StructType};
463
464 fn struct_field_value<'a>(struct_value: &'a StructValue, field_name: &str) -> &'a Value {
465 let index = struct_value
466 .struct_type()
467 .fields()
468 .iter()
469 .position(|field| field.name() == field_name)
470 .expect("field exists");
471 &struct_value.items()[index]
472 }
473
474 #[test]
475 fn test_json_settings_forward_compatibility() {
476 let json_str = r#"{
477 "type_hints": [
478 {
479 "path": ["user", "age"],
480 "type": {
481 "Int64": {}
482 },
483 "nullable": false,
484 "default_constraint": {
485 "Value": {
486 "Int64": 18
487 }
488 },
489 "inverted_index": true
490 },
491 {
492 "path": ["user", "name"],
493 "type": {
494 "String": {
495 "size_type": "Utf8"
496 }
497 },
498 "nullable": true,
499 "inverted_index": false
500 }
501 ]
502 }"#;
503
504 let deserialized = serde_json::from_str::<JsonSettings>(json_str).unwrap();
505
506 assert_eq!(
507 deserialized,
508 JsonSettings::new(vec![
509 JsonTypeHint {
510 path: vec!["user".to_string(), "age".to_string()],
511 data_type: ConcreteDataType::int64_datatype(),
512 nullable: false,
513 default_constraint: Some(ColumnDefaultConstraint::Value(Value::Int64(18))),
514 inverted_index: true,
515 },
516 JsonTypeHint {
517 path: vec!["user".to_string(), "name".to_string()],
518 data_type: ConcreteDataType::string_datatype(),
519 nullable: true,
520 default_constraint: None,
521 inverted_index: false,
522 },
523 ])
524 );
525 }
526
527 #[test]
528 fn test_json_settings_ser_de() {
529 let settings = JsonSettings::new(vec![
530 JsonTypeHint {
531 path: vec!["user".to_string(), "age".to_string()],
532 data_type: ConcreteDataType::int64_datatype(),
533 nullable: false,
534 default_constraint: Some(ColumnDefaultConstraint::Value(Value::Int64(18))),
535 inverted_index: true,
536 },
537 JsonTypeHint {
538 path: vec!["user".to_string(), "name".to_string()],
539 data_type: ConcreteDataType::string_datatype(),
540 nullable: true,
541 default_constraint: None,
542 inverted_index: false,
543 },
544 ]);
545
546 let serialized = serde_json::to_string(&settings).unwrap();
547 let deserialized = serde_json::from_str::<JsonSettings>(&serialized).unwrap();
548
549 assert_eq!(settings, deserialized);
550 }
551
552 #[test]
553 fn test_encode_root_non_object_json() {
554 let settings = JsonSettings::default();
555 let cases = [
556 ("null", Json::Null),
557 ("boolean", Json::Bool(true)),
558 ("integer", Json::from(42)),
559 ("float", Json::from(3.15)),
560 ("string", Json::String("hello".to_string())),
561 ("array", json!([1, 2, 3])),
562 ("mixed array", json!([1, "hello", true, 3.15])),
563 ("empty array", json!([])),
564 ];
565
566 for (name, json) in cases {
567 let err = settings.encode(json).unwrap_err();
568 assert!(
569 matches!(err, crate::error::Error::UnsupportedJsonType { .. }),
570 "{name}: {err:?}"
571 );
572 }
573 }
574
575 #[test]
576 fn test_encode_json_object() {
577 let json = json!({
578 "name": "John",
579 "age": 30,
580 "active": true
581 });
582
583 let settings = JsonSettings::default();
584 let result = settings.encode(json).unwrap().into_json_inner().unwrap();
585 let Value::Struct(result) = result else {
586 panic!("Expected Struct value");
587 };
588 assert_eq!(result.items().len(), 3);
589
590 let items = result.items();
591 let struct_type = result.struct_type();
592
593 let fields = struct_type.fields();
595 let field_names: Vec<&str> = fields.iter().map(|f| f.name()).collect();
596 assert!(field_names.contains(&"name"));
597 assert!(field_names.contains(&"age"));
598 assert!(field_names.contains(&"active"));
599
600 for (i, field) in struct_type.fields().iter().enumerate() {
602 match field.name() {
603 "name" => {
604 assert_eq!(items[i], Value::String("John".into()));
605 assert_eq!(field.data_type(), &ConcreteDataType::string_datatype());
606 }
607 "age" => {
608 assert_eq!(items[i], Value::Int64(30));
609 assert_eq!(field.data_type(), &ConcreteDataType::int64_datatype());
610 }
611 "active" => {
612 assert_eq!(items[i], Value::Boolean(true));
613 assert_eq!(field.data_type(), &ConcreteDataType::boolean_datatype());
614 }
615 _ => panic!("Unexpected field: {}", field.name()),
616 }
617 }
618 }
619
620 #[test]
621 fn test_encode_json_nested_object() {
622 let json = json!({
623 "person": {
624 "name": "Alice",
625 "age": 25
626 },
627 "scores": [95, 87, 92]
628 });
629
630 let settings = JsonSettings::default();
631 let result = settings.encode(json).unwrap().into_json_inner().unwrap();
632 let Value::Struct(result) = result else {
633 panic!("Expected Struct value");
634 };
635 assert_eq!(result.items().len(), 2);
636
637 let items = result.items();
638 let struct_type = result.struct_type();
639
640 let person_index = struct_type
642 .fields()
643 .iter()
644 .position(|f| f.name() == "person")
645 .unwrap();
646 if let Value::Struct(person_struct) = &items[person_index] {
647 assert_eq!(person_struct.items().len(), 2);
648 let fields = person_struct.struct_type().fields();
649 let person_fields: Vec<&str> = fields.iter().map(|f| f.name()).collect();
650 assert!(person_fields.contains(&"name"));
651 assert!(person_fields.contains(&"age"));
652 } else {
653 panic!("Expected Struct value for person field");
654 }
655
656 let scores_index = struct_type
658 .fields()
659 .iter()
660 .position(|f| f.name() == "scores")
661 .unwrap();
662 if let Value::List(scores_list) = &items[scores_index] {
663 assert_eq!(scores_list.items().len(), 3);
664 assert_eq!(scores_list.items()[0], Value::Int64(95));
665 assert_eq!(scores_list.items()[1], Value::Int64(87));
666 assert_eq!(scores_list.items()[2], Value::Int64(92));
667 } else {
668 panic!("Expected List value for scores field");
669 }
670 }
671
672 #[test]
673 fn test_encode_json_structured() {
674 let json = json!({
675 "name": "Bob",
676 "age": 35
677 });
678
679 let settings = JsonSettings::default();
680 let result = settings.encode(json).unwrap().into_json_inner().unwrap();
681
682 if let Value::Struct(struct_value) = result {
683 assert_eq!(struct_value.items().len(), 2);
684 let fields = struct_value.struct_type().fields();
685 let field_names: Vec<&str> = fields.iter().map(|f| f.name()).collect();
686 assert!(field_names.contains(&"name"));
687 assert!(field_names.contains(&"age"));
688 } else {
689 panic!("Expected Struct value");
690 }
691 }
692
693 #[test]
694 fn test_encode_json_respects_type_hint() {
695 let settings = JsonSettings::new(vec![JsonTypeHint {
696 path: vec!["age".to_string()],
697 data_type: ConcreteDataType::int64_datatype(),
698 nullable: false,
699 default_constraint: None,
700 inverted_index: false,
701 }]);
702
703 let result = settings
704 .encode(json!({
705 "name": "Alice",
706 "age": 42
707 }))
708 .unwrap()
709 .into_json_inner()
710 .unwrap();
711
712 let Value::Struct(struct_value) = result else {
713 panic!("Expected Struct value");
714 };
715 assert_eq!(struct_field_value(&struct_value, "age"), &Value::Int64(42));
716
717 let err = settings
718 .encode(json!({
719 "age": "42"
720 }))
721 .unwrap_err();
722 assert!(err.to_string().contains("does not match JSON2 type hint"));
723 }
724
725 #[test]
726 fn test_encode_json_respects_unsigned_type_hint() {
727 let settings = JsonSettings::new(vec![JsonTypeHint {
728 path: vec!["count".to_string()],
729 data_type: ConcreteDataType::uint64_datatype(),
730 nullable: false,
731 default_constraint: None,
732 inverted_index: false,
733 }]);
734
735 let result = settings
736 .encode(json!({
737 "count": u64::MAX
738 }))
739 .unwrap()
740 .into_json_inner()
741 .unwrap();
742
743 let Value::Struct(struct_value) = result else {
744 panic!("Expected Struct value");
745 };
746 assert_eq!(
747 struct_field_value(&struct_value, "count"),
748 &Value::UInt64(u64::MAX)
749 );
750
751 let err = settings
752 .encode(json!({
753 "count": -1
754 }))
755 .unwrap_err();
756 assert!(err.to_string().contains("does not match JSON2 type hint"));
757 }
758
759 #[test]
760 fn test_encode_json_fills_missing_type_hint_with_default() {
761 let settings = JsonSettings::new(vec![JsonTypeHint {
762 path: vec!["user".to_string(), "age".to_string()],
763 data_type: ConcreteDataType::int64_datatype(),
764 nullable: false,
765 default_constraint: Some(ColumnDefaultConstraint::Value(Value::Int64(7))),
766 inverted_index: false,
767 }]);
768
769 let result = settings
770 .encode(json!({}))
771 .unwrap()
772 .into_json_inner()
773 .unwrap();
774
775 let Value::Struct(root) = result else {
776 panic!("Expected Struct value");
777 };
778 let Value::Struct(user) = struct_field_value(&root, "user") else {
779 panic!("Expected user Struct value");
780 };
781 assert_eq!(struct_field_value(user, "age"), &Value::Int64(7));
782 }
783
784 #[test]
785 fn test_encode_json_fills_missing_nullable_type_hint_with_null() {
786 let settings = JsonSettings::new(vec![JsonTypeHint {
787 path: vec!["user".to_string(), "name".to_string()],
788 data_type: ConcreteDataType::string_datatype(),
789 nullable: true,
790 default_constraint: None,
791 inverted_index: false,
792 }]);
793
794 let result = settings
795 .encode(json!({ "user": {} }))
796 .unwrap()
797 .into_json_inner()
798 .unwrap();
799
800 let Value::Struct(root) = result else {
801 panic!("Expected Struct value");
802 };
803 let Value::Struct(user) = struct_field_value(&root, "user") else {
804 panic!("Expected user Struct value");
805 };
806 assert_eq!(struct_field_value(user, "name"), &Value::Null);
807 }
808
809 #[test]
810 fn test_encode_json_rejects_missing_non_null_type_hint() {
811 let settings = JsonSettings::new(vec![JsonTypeHint {
812 path: vec!["user".to_string(), "age".to_string()],
813 data_type: ConcreteDataType::int64_datatype(),
814 nullable: false,
815 default_constraint: None,
816 inverted_index: false,
817 }]);
818
819 let err = settings.encode(json!({})).unwrap_err();
820 assert!(
821 err.to_string()
822 .contains("missing non-null JSON2 type hint path user.age")
823 );
824 }
825
826 #[test]
827 fn test_encode_json_merges_missing_type_hint_prefix() {
828 let settings = JsonSettings::new(vec![
829 JsonTypeHint {
830 path: vec!["user".to_string(), "age".to_string()],
831 data_type: ConcreteDataType::int64_datatype(),
832 nullable: false,
833 default_constraint: Some(ColumnDefaultConstraint::Value(Value::Int64(7))),
834 inverted_index: false,
835 },
836 JsonTypeHint {
837 path: vec!["user".to_string(), "name".to_string()],
838 data_type: ConcreteDataType::string_datatype(),
839 nullable: false,
840 default_constraint: Some(ColumnDefaultConstraint::Value(Value::String(
841 "unknown".into(),
842 ))),
843 inverted_index: false,
844 },
845 ]);
846
847 let result = settings
848 .encode(json!({}))
849 .unwrap()
850 .into_json_inner()
851 .unwrap();
852
853 let Value::Struct(root) = result else {
854 panic!("Expected Struct value");
855 };
856 let Value::Struct(user) = struct_field_value(&root, "user") else {
857 panic!("Expected user Struct value");
858 };
859 assert_eq!(struct_field_value(user, "age"), &Value::Int64(7));
860 assert_eq!(
861 struct_field_value(user, "name"),
862 &Value::String("unknown".into())
863 );
864 }
865
866 #[test]
867 fn test_json_settings_structured() {
868 let json = json!({
869 "name": "Eve",
870 "score": 95
871 });
872
873 let settings = JsonSettings::default();
874 let result = settings.encode(json).unwrap().into_json_inner().unwrap();
875
876 if let Value::Struct(struct_value) = result {
877 assert_eq!(struct_value.items().len(), 2);
878 } else {
879 panic!("Expected Struct value");
880 }
881 }
882
883 #[cfg(test)]
884 mod decode_tests {
885 use ordered_float::OrderedFloat;
886 use serde_json::json;
887
888 use super::*;
889
890 #[test]
891 fn test_decode_primitive_values() {
892 let settings = JsonSettings::default();
893
894 let result = settings.decode(Value::Null).unwrap();
896 assert_eq!(result, Json::Null);
897
898 let result = settings.decode(Value::Boolean(true)).unwrap();
900 assert_eq!(result, Json::Bool(true));
901
902 let result = settings.decode(Value::Int64(42)).unwrap();
904 assert_eq!(result, Json::from(42));
905
906 let result = settings.decode(Value::Float64(OrderedFloat(3.16))).unwrap();
908 assert_eq!(result, Json::from(3.16));
909
910 let result = settings.decode(Value::String("hello".into())).unwrap();
912 assert_eq!(result, Json::String("hello".to_string()));
913 }
914
915 #[test]
916 fn test_decode_struct() {
917 let settings = JsonSettings::default();
918
919 let struct_value = StructValue::new(
920 vec![
921 Value::String("Alice".into()),
922 Value::Int64(25),
923 Value::Boolean(true),
924 ],
925 StructType::new(Arc::new(vec![
926 StructField::new(
927 "name".to_string(),
928 ConcreteDataType::string_datatype(),
929 true,
930 ),
931 StructField::new("age".to_string(), ConcreteDataType::int64_datatype(), true),
932 StructField::new(
933 "active".to_string(),
934 ConcreteDataType::boolean_datatype(),
935 true,
936 ),
937 ])),
938 );
939
940 let result = settings.decode(Value::Struct(struct_value)).unwrap();
941 let expected = json!({
942 "name": "Alice",
943 "age": 25,
944 "active": true
945 });
946 assert_eq!(result, expected);
947 }
948
949 #[test]
950 fn test_decode_list() {
951 let settings = JsonSettings::default();
952
953 let list_value = ListValue::new(
954 vec![Value::Int64(1), Value::Int64(2), Value::Int64(3)],
955 Arc::new(ConcreteDataType::int64_datatype()),
956 );
957
958 let result = settings.decode(Value::List(list_value)).unwrap();
959 let expected = json!([1, 2, 3]);
960 assert_eq!(result, expected);
961 }
962
963 #[test]
964 fn test_decode_nested_structure() {
965 let settings = JsonSettings::default();
966
967 let inner_struct = StructValue::new(
968 vec![Value::String("Alice".into()), Value::Int64(25)],
969 StructType::new(Arc::new(vec![
970 StructField::new(
971 "name".to_string(),
972 ConcreteDataType::string_datatype(),
973 true,
974 ),
975 StructField::new("age".to_string(), ConcreteDataType::int64_datatype(), true),
976 ])),
977 );
978
979 let score_list_item_type = Arc::new(ConcreteDataType::int64_datatype());
980 let outer_struct = StructValue::new(
981 vec![
982 Value::Struct(inner_struct),
983 Value::List(ListValue::new(
984 vec![Value::Int64(95), Value::Int64(87)],
985 score_list_item_type.clone(),
986 )),
987 ],
988 StructType::new(Arc::new(vec![
989 StructField::new(
990 "user".to_string(),
991 ConcreteDataType::Struct(StructType::new(Arc::new(vec![
992 StructField::new(
993 "name".to_string(),
994 ConcreteDataType::string_datatype(),
995 true,
996 ),
997 StructField::new(
998 "age".to_string(),
999 ConcreteDataType::int64_datatype(),
1000 true,
1001 ),
1002 ]))),
1003 true,
1004 ),
1005 StructField::new(
1006 "scores".to_string(),
1007 ConcreteDataType::List(ListType::new(score_list_item_type.clone())),
1008 true,
1009 ),
1010 ])),
1011 );
1012
1013 let result = settings.decode(Value::Struct(outer_struct)).unwrap();
1014 let expected = json!({
1015 "user": {
1016 "name": "Alice",
1017 "age": 25
1018 },
1019 "scores": [95, 87]
1020 });
1021 assert_eq!(result, expected);
1022 }
1023
1024 #[test]
1025 fn test_decode_missing_fields() {
1026 let settings = JsonSettings::default();
1027
1028 let struct_value = StructValue::new(
1030 vec![
1031 Value::String("Bob".into()),
1032 Value::Null, ],
1034 StructType::new(Arc::new(vec![
1035 StructField::new(
1036 "name".to_string(),
1037 ConcreteDataType::string_datatype(),
1038 true,
1039 ),
1040 StructField::new("age".to_string(), ConcreteDataType::int64_datatype(), true),
1041 ])),
1042 );
1043
1044 let result = settings.decode(Value::Struct(struct_value)).unwrap();
1045 let expected = json!({
1046 "name": "Bob",
1047 "age": null
1048 });
1049 assert_eq!(result, expected);
1050 }
1051 }
1052}