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