Skip to main content

datatypes/
json.rs

1// Copyright 2023 Greptime Team
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Data conversion between greptime's StructType and Json
16//!
17//! The idea of this module is to provide utilities to convert serde_json::Value to greptime's StructType and vice versa.
18//!
19//! The struct will carry all the fields of the Json object. We will not flatten any json object in this implementation.
20//!
21
22pub mod value;
23
24use std::collections::BTreeMap;
25use std::collections::btree_map::Entry;
26use std::sync::Arc;
27
28use serde::{Deserialize, Serialize};
29use serde_json::{Map, Value as Json};
30use snafu::ResultExt;
31
32use crate::data_type::ConcreteDataType;
33use crate::error::{self, InvalidJson2SettingsSnafu, Result, UnsupportedJsonTypeSnafu};
34use crate::json::value::{JsonValue, JsonVariant, encode_serde_json_as_jsonb};
35use crate::prelude::DataType as _;
36use crate::types::json_type::{JsonNativeType, JsonObjectType};
37use crate::value::{ListValue, StructValue, Value};
38
39/// Maximum number of JSON container levels represented as nested Arrow types.
40pub const JSON2_MAX_STRUCTURED_DEPTH: usize = 50;
41/// Reserved physical field containing unexpanded JSON2 paths.
42pub const JSON2_REMAINDER_FIELD_NAME: &str = "!__remainder__!";
43/// Default maximum number of unhinted JSON leaf paths expanded into Arrow fields.
44pub const JSON2_DEFAULT_MAX_AUTO_EXPANDED_PATHS: u32 = 100;
45
46/// JSON2 settings stored in column schema metadata and represented through
47/// Arrow extension metadata.
48#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize)]
49pub struct JsonSettings {
50    #[serde(default)]
51    type_hints: Vec<JsonTypeHint>,
52    /// Maximum number of unhinted JSON paths expanded into Arrow fields.
53    ///
54    /// `None` preserves the legacy unlimited layout.
55    #[serde(default, skip_serializing_if = "Option::is_none")]
56    max_auto_expanded_paths: Option<u32>,
57}
58
59#[derive(Deserialize)]
60struct JsonSettingsSerde {
61    #[serde(default)]
62    type_hints: Vec<JsonTypeHint>,
63    #[serde(default)]
64    max_auto_expanded_paths: Option<u32>,
65}
66
67impl<'de> Deserialize<'de> for JsonSettings {
68    fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
69    where
70        D: serde::Deserializer<'de>,
71    {
72        let settings = JsonSettingsSerde::deserialize(deserializer)?;
73        Self::try_new(settings.type_hints, settings.max_auto_expanded_paths)
74            .map_err(serde::de::Error::custom)
75    }
76}
77
78/// Declares selected JSON2 subpaths as typed fields.
79///
80/// These hints let JSON2 encode frequently used subpaths in a typed layout, so
81/// queries over those subpaths can get behavior and performance closer to
82/// ordinary columns.
83#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
84pub struct JsonTypeHint {
85    /// JSON2 subpath for a typed field.
86    ///
87    /// Each item is one JSON object key. For example, `["user", "age"]`
88    /// represents `user.age`.
89    ///
90    /// Array traversal is not currently supported. For example, a hint cannot
91    /// describe `events[0].name` or fields shared by all items in `events[*]`.
92    pub path: Vec<String>,
93    #[serde(rename = "type")]
94    pub data_type: ConcreteDataType,
95    pub inverted_index: bool,
96    /// Optional Bloom Filter configuration for this path.
97    #[serde(default, skip_serializing_if = "Option::is_none")]
98    pub skipping_index: Option<crate::schema::SkippingIndexOptions>,
99}
100
101/// Specifies how encoding handles a value that does not match its JSON2 type hint.
102#[derive(Debug, Clone, Copy, PartialEq, Eq)]
103pub enum TypeHintMismatchPolicy {
104    /// Returns an error for a type hint mismatch.
105    Reject,
106    /// Coerces to the hint type, encoding unconvertible values as null.
107    CoerceOrNull,
108}
109
110/// Context for JSON encoding/decoding that tracks the current key path.
111#[derive(Clone, Debug)]
112pub struct JsonContext<'a> {
113    /// Current key path from the JSON2 root.
114    pub path: Vec<String>,
115    /// Settings for JSON encoding/decoding.
116    pub settings: &'a JsonSettings,
117}
118
119impl JsonSettings {
120    /// Creates default v2 settings for newly created JSON2 columns.
121    pub fn new_v2() -> Self {
122        Self {
123            type_hints: vec![],
124            max_auto_expanded_paths: Some(JSON2_DEFAULT_MAX_AUTO_EXPANDED_PATHS),
125        }
126    }
127
128    /// Creates and validates JSON2 settings.
129    pub fn try_new(
130        type_hints: Vec<JsonTypeHint>,
131        max_auto_expanded_paths: Option<u32>,
132    ) -> Result<Self> {
133        validate_type_hints(&type_hints)?;
134        Ok(Self {
135            type_hints,
136            max_auto_expanded_paths,
137        })
138    }
139
140    pub fn type_hints(&self) -> &[JsonTypeHint] {
141        &self.type_hints
142    }
143
144    pub fn max_auto_expanded_paths(&self) -> Option<u32> {
145        self.max_auto_expanded_paths
146    }
147
148    pub fn into_parts(self) -> (Vec<JsonTypeHint>, Option<u32>) {
149        (self.type_hints, self.max_auto_expanded_paths)
150    }
151
152    /// Returns whether the settings are equivalent, ignoring type hint order.
153    pub fn equivalent(&self, other: &Self) -> bool {
154        let Self {
155            type_hints,
156            max_auto_expanded_paths,
157        } = self;
158        let Self {
159            type_hints: other_hints,
160            max_auto_expanded_paths: other_max_auto_expanded_paths,
161        } = other;
162
163        if max_auto_expanded_paths != other_max_auto_expanded_paths
164            || type_hints.len() != other_hints.len()
165        {
166            return false;
167        }
168
169        let mut hints = type_hints.iter().collect::<Vec<_>>();
170        let mut other_hints = other_hints.iter().collect::<Vec<_>>();
171        hints.sort_unstable_by(|a, b| a.path.cmp(&b.path));
172        other_hints.sort_unstable_by(|a, b| a.path.cmp(&b.path));
173        hints == other_hints
174    }
175
176    /// Decode an encoded StructValue back into a serde_json::Value.
177    pub fn decode(&self, value: Value) -> Result<Json> {
178        let mut context = JsonContext {
179            path: Vec::new(),
180            settings: self,
181        };
182        decode_value_with_context(value, &mut context)
183    }
184
185    /// Encode a serde_json::Value into a Value::Json using current settings.
186    pub fn encode(&self, json: Json) -> Result<Value> {
187        self.encode_with_type_hint_mismatch_policy(json, TypeHintMismatchPolicy::Reject)
188    }
189
190    /// Encodes a serde_json::Value using the given type hint mismatch policy.
191    pub fn encode_with_type_hint_mismatch_policy(
192        &self,
193        json: Json,
194        policy: TypeHintMismatchPolicy,
195    ) -> Result<Value> {
196        if let Json::Object(object) = &json
197            && object.contains_key(JSON2_REMAINDER_FIELD_NAME)
198        {
199            return error::InvalidJsonSnafu {
200                value: format!(
201                    "root object cannot contain reserved field '{JSON2_REMAINDER_FIELD_NAME}'"
202                ),
203            }
204            .fail();
205        }
206        let mut context = JsonContext {
207            path: Vec::new(),
208            settings: self,
209        };
210        encode_json_with_context(json, &mut context, policy).map(|v| Value::Json(Box::new(v)))
211    }
212}
213
214fn validate_type_hints(type_hints: &[JsonTypeHint]) -> Result<()> {
215    if type_hints.is_empty() {
216        return Ok(());
217    }
218
219    let mut object = JsonObjectType::new();
220    for hint in type_hints {
221        if let Some(options) = &hint.skipping_index {
222            crate::schema::SkippingIndexOptions::new(
223                options.granularity,
224                options.false_positive_rate(),
225                options.index_type.clone(),
226            )?;
227        }
228        if hint.path.len() > JSON2_MAX_STRUCTURED_DEPTH {
229            return InvalidJson2SettingsSnafu {
230                reason: format!(
231                    "JSON2 type hint path cannot exceed {JSON2_MAX_STRUCTURED_DEPTH} segments"
232                ),
233            }
234            .fail();
235        }
236        for part in &hint.path {
237            if part.is_empty() {
238                return InvalidJson2SettingsSnafu {
239                    reason: "JSON2 type hint path segments must not be empty",
240                }
241                .fail();
242            }
243            if part == JSON2_REMAINDER_FIELD_NAME {
244                return InvalidJson2SettingsSnafu {
245                    reason: format!(
246                        "JSON2 type hint path cannot contain reserved field '{JSON2_REMAINDER_FIELD_NAME}'"
247                    ),
248                }
249                .fail();
250            }
251        }
252        let data_type = match &hint.data_type {
253            ConcreteDataType::Boolean(_)
254            | ConcreteDataType::UInt64(_)
255            | ConcreteDataType::Int64(_)
256            | ConcreteDataType::Float64(_)
257            | ConcreteDataType::String(_) => (&hint.data_type).into(),
258            data_type => {
259                return InvalidJson2SettingsSnafu {
260                    reason: format!("unsupported JSON2 type hint data type: {data_type}"),
261                }
262                .fail();
263            }
264        };
265        validate_type_hint(&mut object, &hint.path, data_type)?;
266    }
267    Ok(())
268}
269
270fn validate_type_hint(
271    object: &mut JsonObjectType,
272    path: &[String],
273    data_type: JsonNativeType,
274) -> Result<()> {
275    let Some((name, path)) = path.split_first() else {
276        return InvalidJson2SettingsSnafu {
277            reason: "JSON2 type hint path must not be empty".to_string(),
278        }
279        .fail();
280    };
281    if path.is_empty() {
282        if object.insert(name.clone(), data_type).is_some() {
283            return InvalidJson2SettingsSnafu {
284                reason: format!("duplicate JSON2 type hint path '{name}'"),
285            }
286            .fail();
287        }
288        return Ok(());
289    }
290
291    let child = object
292        .entry(name.clone())
293        .or_insert_with(|| JsonNativeType::Object(JsonObjectType::new()));
294    let JsonNativeType::Object(child) = child else {
295        return InvalidJson2SettingsSnafu {
296            reason: format!("conflicting JSON2 type hint path at '{name}'"),
297        }
298        .fail();
299    };
300    validate_type_hint(child, path, data_type)
301}
302
303impl<'a> JsonContext<'a> {
304    fn type_hint(&self) -> Option<&'a JsonTypeHint> {
305        self.settings
306            .type_hints
307            .iter()
308            .find(|hint| hint.path == self.path)
309    }
310}
311
312fn with_key_context<T>(
313    context: &mut JsonContext,
314    key: &str,
315    f: impl FnOnce(&mut JsonContext) -> Result<T>,
316) -> Result<T> {
317    context.path.push(key.to_string());
318    let result = f(context);
319    context.path.pop();
320    result
321}
322
323/// Main encoding function with key path tracking
324fn encode_json_with_context(
325    json: Json,
326    context: &mut JsonContext,
327    policy: TypeHintMismatchPolicy,
328) -> Result<JsonValue> {
329    if context.path.is_empty() && !matches!(json, Json::Object(_)) {
330        return UnsupportedJsonTypeSnafu.fail();
331    }
332
333    match json {
334        Json::Object(json_object) => encode_json_object_with_context(json_object, context, policy),
335        Json::Array(json_array) => encode_json_array_with_context(json_array, context, policy),
336        _ => encode_json_value_with_context(json, context, policy),
337    }
338}
339
340fn encode_json_object_with_context<'a>(
341    json_object: Map<String, Json>,
342    context: &mut JsonContext<'a>,
343    policy: TypeHintMismatchPolicy,
344) -> Result<JsonValue> {
345    let mut object = BTreeMap::new();
346    for (key, value) in json_object {
347        let value = with_key_context(context, &key, |context| {
348            if let Some(hint) = context.type_hint() {
349                encode_json_value_with_hint(value, hint, context, policy)
350            } else {
351                encode_json_value_with_context(value, context, policy)
352            }
353        })?;
354
355        object.insert(key, value.into_variant());
356    }
357
358    fill_missing_type_hints(&mut object, context, policy)?;
359
360    Ok(JsonValue::new(JsonVariant::Object(object)))
361}
362
363fn fill_missing_type_hints(
364    object: &mut BTreeMap<String, JsonVariant>,
365    context: &mut JsonContext,
366    policy: TypeHintMismatchPolicy,
367) -> Result<()> {
368    for hint in &context.settings.type_hints {
369        if hint.path.len() > context.path.len() && hint.path.starts_with(&context.path) {
370            let depth = context.path.len();
371            let key = &hint.path[depth];
372            with_key_context(context, key, |context| {
373                insert_missing_type_hint(object, context, hint, depth, policy)
374            })?;
375        }
376    }
377    Ok(())
378}
379
380fn insert_missing_type_hint(
381    object: &mut BTreeMap<String, JsonVariant>,
382    field_context: &mut JsonContext,
383    hint: &JsonTypeHint,
384    depth: usize,
385    policy: TypeHintMismatchPolicy,
386) -> Result<()> {
387    let key = &hint.path[depth];
388    let is_leaf = depth + 1 == hint.path.len();
389
390    if is_leaf {
391        if !object.contains_key(key) {
392            object.insert(key.clone(), JsonValue::null().into_variant());
393        }
394        return Ok(());
395    }
396
397    match object.entry(key.clone()) {
398        Entry::Occupied(mut entry) => match entry.get_mut() {
399            JsonVariant::Object(child) => {
400                insert_missing_type_hint(child, field_context, hint, depth + 1, policy)
401            }
402            _ if policy == TypeHintMismatchPolicy::CoerceOrNull => {
403                entry.insert(JsonValue::null().into_variant());
404                Ok(())
405            }
406            _ => error::InvalidJsonSnafu {
407                value: format!(
408                    "JSON2 type hint path {} expects object at {}",
409                    hint.path.join("."),
410                    field_context.path.join(".")
411                ),
412            }
413            .fail(),
414        },
415        Entry::Vacant(entry) => {
416            let mut child = BTreeMap::new();
417            insert_missing_type_hint(&mut child, field_context, hint, depth + 1, policy)?;
418            entry.insert(JsonVariant::Object(child));
419            Ok(())
420        }
421    }
422}
423
424fn encode_json_value_with_hint(
425    json: Json,
426    hint: &JsonTypeHint,
427    context: &mut JsonContext,
428    policy: TypeHintMismatchPolicy,
429) -> Result<JsonValue> {
430    if json.is_null() {
431        return Ok(JsonValue::null());
432    }
433
434    let json = match (&hint.data_type, json) {
435        (ConcreteDataType::String(_), Json::String(value)) => {
436            return Ok(value.into());
437        }
438        (
439            ConcreteDataType::Int8(_)
440            | ConcreteDataType::Int16(_)
441            | ConcreteDataType::Int32(_)
442            | ConcreteDataType::Int64(_),
443            Json::Number(value),
444        ) => {
445            if let Some(value) = value.as_i64() {
446                return Ok(value.into());
447            }
448            Json::Number(value)
449        }
450        (
451            ConcreteDataType::UInt8(_)
452            | ConcreteDataType::UInt16(_)
453            | ConcreteDataType::UInt32(_)
454            | ConcreteDataType::UInt64(_),
455            Json::Number(value),
456        ) => {
457            if let Some(value) = value.as_u64() {
458                return Ok(value.into());
459            }
460            Json::Number(value)
461        }
462        (ConcreteDataType::Float32(_) | ConcreteDataType::Float64(_), Json::Number(value)) => {
463            if let Some(value) = value.as_f64() {
464                return Ok(value.into());
465            }
466            Json::Number(value)
467        }
468        (ConcreteDataType::Boolean(_), Json::Bool(value)) => {
469            return Ok(value.into());
470        }
471        (_, json) => json,
472    };
473
474    match policy {
475        TypeHintMismatchPolicy::Reject => error::InvalidJsonSnafu {
476            value: format!(
477                "JSON value at {} does not match JSON2 type hint {}",
478                context.path.join("."),
479                hint.data_type
480            ),
481        }
482        .fail(),
483        TypeHintMismatchPolicy::CoerceOrNull => {
484            let value = coerce_json_value_to_type(json, &hint.data_type);
485            let value = Json::try_from(value).map_err(|error| {
486                error::InvalidJsonSnafu {
487                    value: error.to_string(),
488                }
489                .build()
490            })?;
491            Ok(JsonValue::new(value.into()))
492        }
493    }
494}
495
496/// Coerces a JSON value using the same semantics as JSON2 query projection.
497/// Values that cannot be converted become null.
498pub(crate) fn coerce_json_value_to_type(value: Json, to_type: &ConcreteDataType) -> Value {
499    if value.is_null() {
500        return Value::Null;
501    }
502
503    if to_type.is_string() {
504        let value = match value {
505            Json::String(value) => value,
506            value => value.to_string(),
507        };
508        return Value::String(value.into());
509    }
510
511    if matches!(to_type, ConcreteDataType::Binary(_)) {
512        return Value::Binary(encode_serde_json_as_jsonb(value).into());
513    }
514
515    if let Some(struct_type) = to_type.as_struct() {
516        let Json::Object(mut object) = value else {
517            return Value::Null;
518        };
519        let values = struct_type
520            .fields()
521            .iter()
522            .map(|field| {
523                object
524                    .remove(field.name())
525                    .map(|value| coerce_json_value_to_type(value, field.data_type()))
526                    .unwrap_or(Value::Null)
527            })
528            .collect::<Vec<_>>();
529        return Value::Struct(StructValue::new(values, struct_type.clone()));
530    }
531
532    if let Some(list_type) = to_type.as_list() {
533        let Json::Array(values) = value else {
534            return Value::Null;
535        };
536        let item_type = list_type.item_type().clone();
537        let values = values
538            .into_iter()
539            .map(|value| coerce_json_value_to_type(value, &item_type))
540            .collect::<Vec<_>>();
541        return Value::List(ListValue::new(values, Arc::new(item_type)));
542    }
543
544    let value = match value {
545        Json::Bool(value) => Value::Boolean(value),
546        Json::Number(value) => {
547            if let Some(value) = value.as_i64() {
548                Value::Int64(value)
549            } else if let Some(value) = value.as_u64() {
550                Value::UInt64(value)
551            } else if let Some(value) = value.as_f64() {
552                Value::Float64(value.into())
553            } else {
554                Value::Null
555            }
556        }
557        Json::String(value) => Value::String(value.into()),
558        Json::Array(_) | Json::Object(_) | Json::Null => Value::Null,
559    };
560    to_type.try_cast(value).unwrap_or(Value::Null)
561}
562
563fn encode_json_array_with_context<'a>(
564    json_array: Vec<Json>,
565    context: &mut JsonContext<'a>,
566    policy: TypeHintMismatchPolicy,
567) -> Result<JsonValue> {
568    let json_array_len = json_array.len();
569    let mut items = Vec::with_capacity(json_array_len);
570
571    for (index, value) in json_array.into_iter().enumerate() {
572        let item_value = with_key_context(context, &index.to_string(), |context| {
573            encode_json_value_with_context(value, context, policy)
574        })?;
575        items.push(item_value);
576    }
577
578    // In specification, it's valid for a JSON array to have different types of items, for example,
579    // ["a string", 1]. However, in implementation, the `JsonValue` will be converted to Arrow list
580    // array, which requires all items have exactly the same type. So we merge out the maybe
581    // different item types to a unified type, and align all the item values to it.
582
583    let merged_item_type = if let Some((first, rests)) = items.split_first() {
584        let mut merged = first.json_type().clone();
585        for rest in rests.iter().map(|x| x.json_type()) {
586            if matches!(merged, JsonNativeType::Variant) {
587                break;
588            }
589            merged.merge(rest);
590        }
591        Some(merged)
592    } else {
593        None
594    };
595    if let Some(unified_item_type) = merged_item_type {
596        for item in &mut items {
597            item.try_align(&unified_item_type)?;
598        }
599    }
600    let items = items
601        .into_iter()
602        .map(|x| x.into_variant())
603        .collect::<Vec<_>>();
604    Ok(JsonValue::new(JsonVariant::Array(items)))
605}
606
607/// Helper function to encode a JSON value to a Value and determine its ConcreteDataType with context
608fn encode_json_value_with_context(
609    json: Json,
610    context: &mut JsonContext,
611    policy: TypeHintMismatchPolicy,
612) -> Result<JsonValue> {
613    if context.path.len() >= JSON2_MAX_STRUCTURED_DEPTH
614        && matches!(&json, Json::Object(_) | Json::Array(_))
615    {
616        return Ok(JsonValue::new(JsonVariant::Variant(
617            encode_serde_json_as_jsonb(json),
618        )));
619    }
620
621    match json {
622        Json::Null => Ok(JsonValue::null()),
623        Json::Bool(b) => Ok(b.into()),
624        Json::Number(n) => {
625            if let Some(i) = n.as_i64() {
626                Ok(i.into())
627            } else if let Some(u) = n.as_u64() {
628                if u <= i64::MAX as u64 {
629                    Ok((u as i64).into())
630                } else {
631                    Ok(u.into())
632                }
633            } else if let Some(f) = n.as_f64() {
634                Ok(f.into())
635            } else {
636                // Fallback to string representation
637                Ok(n.to_string().into())
638            }
639        }
640        Json::String(s) => Ok(s.into()),
641        Json::Array(arr) => encode_json_array_with_context(arr, context, policy),
642        Json::Object(obj) => encode_json_object_with_context(obj, context, policy),
643    }
644}
645
646/// Main decoding function with key path tracking
647fn decode_value_with_context(value: Value, context: &mut JsonContext) -> Result<Json> {
648    match value {
649        Value::Struct(struct_value) => decode_struct_with_context(struct_value, context),
650        Value::List(list_value) => decode_list_with_context(list_value, context),
651        _ => decode_primitive_value(value),
652    }
653}
654
655/// Decode a structured value to JSON object
656fn decode_struct_with_context<'a>(
657    struct_value: StructValue,
658    context: &mut JsonContext<'a>,
659) -> Result<Json> {
660    let mut json_object = Map::with_capacity(struct_value.len());
661
662    let (items, fields) = struct_value.into_parts();
663
664    for (field, field_value) in fields.fields().iter().zip(items) {
665        let json_value = with_key_context(context, field.name(), |context| {
666            decode_value_with_context(field_value, context)
667        })?;
668        json_object.insert(field.name().to_string(), json_value);
669    }
670
671    Ok(Json::Object(json_object))
672}
673
674/// Decode a list value to JSON array
675fn decode_list_with_context(list_value: ListValue, context: &mut JsonContext) -> Result<Json> {
676    let mut json_array = Vec::with_capacity(list_value.len());
677
678    let data_items = list_value.take_items();
679
680    for (index, item) in data_items.into_iter().enumerate() {
681        let json_value = with_key_context(context, &index.to_string(), |context| {
682            decode_value_with_context(item, context)
683        })?;
684        json_array.push(json_value);
685    }
686
687    Ok(Json::Array(json_array))
688}
689
690/// Decode primitive value to JSON
691fn decode_primitive_value(value: Value) -> Result<Json> {
692    match value {
693        Value::Null => Ok(Json::Null),
694        Value::Boolean(b) => Ok(Json::Bool(b)),
695        Value::UInt8(v) => Ok(Json::from(v)),
696        Value::UInt16(v) => Ok(Json::from(v)),
697        Value::UInt32(v) => Ok(Json::from(v)),
698        Value::UInt64(v) => Ok(Json::from(v)),
699        Value::Int8(v) => Ok(Json::from(v)),
700        Value::Int16(v) => Ok(Json::from(v)),
701        Value::Int32(v) => Ok(Json::from(v)),
702        Value::Int64(v) => Ok(Json::from(v)),
703        Value::Float32(v) => Ok(Json::from(v.0)),
704        Value::Float64(v) => Ok(Json::from(v.0)),
705        Value::String(s) => Ok(Json::String(s.as_utf8().to_string())),
706        Value::Binary(b) => serde_json::to_value(b).context(error::SerializeSnafu),
707        Value::Date(v) => Ok(Json::from(v.val())),
708        Value::Timestamp(v) => serde_json::to_value(v.value()).context(error::SerializeSnafu),
709        Value::Time(v) => serde_json::to_value(v.value()).context(error::SerializeSnafu),
710        Value::IntervalYearMonth(v) => {
711            serde_json::to_value(v.to_i32()).context(error::SerializeSnafu)
712        }
713        Value::IntervalDayTime(v) => {
714            serde_json::to_value(v.to_i64()).context(error::SerializeSnafu)
715        }
716        Value::IntervalMonthDayNano(v) => {
717            serde_json::to_value(v.to_i128()).context(error::SerializeSnafu)
718        }
719        Value::Duration(v) => serde_json::to_value(v.value()).context(error::SerializeSnafu),
720        Value::Decimal128(v) => serde_json::to_value(v.to_string()).context(error::SerializeSnafu),
721        Value::Struct(_) | Value::List(_) | Value::Json(_) => {
722            // These should be handled by the context-aware functions
723            Err(error::InvalidJsonSnafu {
724                value: "Structured values should be handled by context-aware decoding".to_string(),
725            }
726            .build())
727        }
728    }
729}
730
731#[cfg(test)]
732mod tests {
733    use std::sync::Arc;
734
735    use serde_json::json;
736
737    use super::*;
738    use crate::data_type::ConcreteDataType;
739    use crate::types::{ListType, StructField, StructType};
740
741    fn struct_field_value<'a>(struct_value: &'a StructValue, field_name: &str) -> &'a Value {
742        let index = struct_value
743            .struct_type()
744            .fields()
745            .iter()
746            .position(|field| field.name() == field_name)
747            .expect("field exists");
748        &struct_value.items()[index]
749    }
750
751    #[test]
752    fn test_skipping_index_settings_roundtrip() {
753        let old = r#"{"type_hints":[{"path":["service","name"],"type":{"String":{}},"inverted_index":true}]}"#;
754        let legacy: JsonSettings = serde_json::from_str(old).unwrap();
755        assert!(legacy.type_hints()[0].skipping_index.is_none());
756        let mut hints = legacy.type_hints().to_vec();
757        hints[0].skipping_index = Some(crate::schema::SkippingIndexOptions::default());
758        let settings = JsonSettings::try_new(hints.clone(), Some(0)).unwrap();
759        let json = serde_json::to_string(&settings).unwrap();
760        assert_eq!(
761            settings,
762            serde_json::from_str::<JsonSettings>(&json).unwrap()
763        );
764        assert!(!settings.equivalent(&legacy));
765        hints[0].skipping_index.as_mut().unwrap().granularity = 0;
766        assert!(JsonSettings::try_new(hints, Some(0)).is_err());
767    }
768
769    #[test]
770    fn test_json_settings_equivalent() -> Result<()> {
771        let hints = vec![
772            JsonTypeHint {
773                path: vec!["user".to_string(), "name".to_string()],
774                data_type: ConcreteDataType::string_datatype(),
775                inverted_index: false,
776                skipping_index: None,
777            },
778            JsonTypeHint {
779                path: vec!["count".to_string()],
780                data_type: ConcreteDataType::int64_datatype(),
781                inverted_index: false,
782                skipping_index: None,
783            },
784        ];
785        let settings = JsonSettings::try_new(hints.clone(), Some(10))?;
786        let mut reversed = hints.clone();
787        reversed.reverse();
788        let reordered = JsonSettings::try_new(reversed, Some(10))?;
789        assert_ne!(settings, reordered);
790        assert!(settings.equivalent(&reordered));
791        assert!(reordered.equivalent(&settings));
792        assert!(settings.equivalent(&settings));
793        assert_eq!(hints, settings.type_hints());
794        assert!(JsonSettings::default().equivalent(&JsonSettings::default()));
795
796        for limit in [None, Some(0), Some(11)] {
797            assert!(!settings.equivalent(&JsonSettings::try_new(hints.clone(), limit)?));
798        }
799        assert!(!settings.equivalent(&JsonSettings::try_new(vec![hints[0].clone()], Some(10))?));
800
801        let mut changed = hints.clone();
802        changed[0].path = vec!["user".to_string(), "id".to_string()];
803        assert!(!settings.equivalent(&JsonSettings::try_new(changed, Some(10))?));
804
805        let mut changed = hints.clone();
806        changed[0].data_type = ConcreteDataType::int64_datatype();
807        assert!(!settings.equivalent(&JsonSettings::try_new(changed, Some(10))?));
808
809        let mut changed = hints;
810        changed[0].inverted_index = true;
811        assert!(!settings.equivalent(&JsonSettings::try_new(changed, Some(10))?));
812        Ok(())
813    }
814
815    #[test]
816    fn test_json_settings_deserializes_legacy_type_hint_constraints()
817    -> std::result::Result<(), Box<dyn std::error::Error>> {
818        let json_str = r#"{
819            "type_hints": [
820                {
821                    "path": ["user", "age"],
822                    "type": {
823                        "Int64": {}
824                    },
825                    "nullable": false,
826                    "default_constraint": {
827                        "Value": {
828                            "Int64": 18
829                        }
830                    },
831                    "inverted_index": true
832                },
833                {
834                    "path": ["user", "name"],
835                    "type": {
836                        "String": {
837                            "size_type": "Utf8"
838                        }
839                    },
840                    "nullable": true,
841                    "inverted_index": false
842                }
843            ]
844        }"#;
845
846        let deserialized = serde_json::from_str::<JsonSettings>(json_str)?;
847
848        let expected = JsonSettings::try_new(
849            vec![
850                JsonTypeHint {
851                    path: vec!["user".to_string(), "age".to_string()],
852                    data_type: ConcreteDataType::int64_datatype(),
853                    inverted_index: true,
854                    skipping_index: None,
855                },
856                JsonTypeHint {
857                    path: vec!["user".to_string(), "name".to_string()],
858                    data_type: ConcreteDataType::string_datatype(),
859                    inverted_index: false,
860                    skipping_index: None,
861                },
862            ],
863            None,
864        )?;
865        assert_eq!(deserialized, expected);
866        Ok(())
867    }
868
869    #[test]
870    fn test_json_settings_ser_de() -> std::result::Result<(), Box<dyn std::error::Error>> {
871        let type_hints = vec![
872            JsonTypeHint {
873                path: vec!["user".to_string(), "age".to_string()],
874                data_type: ConcreteDataType::int64_datatype(),
875                inverted_index: true,
876                skipping_index: None,
877            },
878            JsonTypeHint {
879                path: vec!["user".to_string(), "name".to_string()],
880                data_type: ConcreteDataType::string_datatype(),
881                inverted_index: false,
882                skipping_index: None,
883            },
884        ];
885
886        for settings in [
887            JsonSettings {
888                type_hints: type_hints.clone(),
889                max_auto_expanded_paths: None,
890            },
891            JsonSettings {
892                type_hints,
893                max_auto_expanded_paths: Some(1),
894            },
895        ] {
896            let serialized = serde_json::to_string(&settings)?;
897            let deserialized = serde_json::from_str::<JsonSettings>(&serialized)?;
898            assert_eq!(settings, deserialized);
899        }
900        Ok(())
901    }
902
903    #[test]
904    fn test_json_settings_path_validation() {
905        for (path, expected_valid) in [
906            (vec![""], false),
907            (vec!["", "nested"], false),
908            (vec!["nested", ""], false),
909            (vec!["nested", "", "leaf"], false),
910            (vec!["nested", JSON2_REMAINDER_FIELD_NAME], false),
911            (vec!["nested", JSON2_REMAINDER_FIELD_NAME, "leaf"], false),
912            (vec!["nested", "leaf"], true),
913            (vec![], false),
914            (vec![JSON2_REMAINDER_FIELD_NAME], false),
915            (vec![JSON2_REMAINDER_FIELD_NAME, "leaf"], false),
916        ] {
917            for inverted_index in [false, true] {
918                let hint = JsonTypeHint {
919                    path: path.iter().map(|part| (*part).to_string()).collect(),
920                    data_type: ConcreteDataType::string_datatype(),
921                    inverted_index,
922                    skipping_index: None,
923                };
924                let serialized = json!({"type_hints": [hint.clone()]});
925                assert_eq!(
926                    JsonSettings::try_new(vec![hint], None).is_ok(),
927                    expected_valid,
928                    "path: {path:?}, inverted_index: {inverted_index}"
929                );
930                assert_eq!(
931                    serde_json::from_value::<JsonSettings>(serialized).is_ok(),
932                    expected_valid,
933                    "path: {path:?}, inverted_index: {inverted_index}"
934                );
935            }
936        }
937    }
938
939    #[test]
940    fn test_json_settings_reject_invalid_type_hints() {
941        for type_hints in [
942            json!([{"path": [], "type": {"Int64": {}}, "nullable": true, "inverted_index": false}]),
943            json!([
944                {"path": ["a"], "type": {"Int64": {}}, "nullable": true, "inverted_index": false},
945                {"path": ["a", "b"], "type": {"Int64": {}}, "nullable": true, "inverted_index": false}
946            ]),
947            json!([{"path": [JSON2_REMAINDER_FIELD_NAME], "type": {"Int64": {}}, "nullable": true, "inverted_index": false}]),
948        ] {
949            let settings = json!({"type_hints": type_hints});
950            assert!(serde_json::from_value::<JsonSettings>(settings).is_err());
951        }
952
953        let hint = |path, data_type| JsonTypeHint {
954            path,
955            data_type,
956            inverted_index: false,
957            skipping_index: None,
958        };
959        assert!(
960            JsonSettings::try_new(
961                vec![hint(
962                    vec!["nested".to_string(), JSON2_REMAINDER_FIELD_NAME.to_string()],
963                    ConcreteDataType::string_datatype(),
964                )],
965                None,
966            )
967            .is_err()
968        );
969        assert!(
970            JsonSettings::try_new(
971                vec![hint(
972                    vec!["nested".to_string(); JSON2_MAX_STRUCTURED_DEPTH + 1],
973                    ConcreteDataType::string_datatype(),
974                )],
975                None,
976            )
977            .is_err()
978        );
979        assert!(
980            JsonSettings::try_new(
981                vec![hint(
982                    vec!["date".to_string()],
983                    ConcreteDataType::date_datatype(),
984                )],
985                None,
986            )
987            .is_err()
988        );
989    }
990
991    #[test]
992    fn test_encode_root_non_object_json() {
993        let settings = JsonSettings::default();
994        let cases = [
995            ("null", Json::Null),
996            ("boolean", Json::Bool(true)),
997            ("integer", Json::from(42)),
998            ("float", Json::from(3.15)),
999            ("string", Json::String("hello".to_string())),
1000            ("array", json!([1, 2, 3])),
1001            ("mixed array", json!([1, "hello", true, 3.15])),
1002            ("empty array", json!([])),
1003        ];
1004
1005        for (name, json) in cases {
1006            let err = settings.encode(json).unwrap_err();
1007            assert!(
1008                matches!(err, crate::error::Error::UnsupportedJsonType { .. }),
1009                "{name}: {err:?}"
1010            );
1011        }
1012    }
1013
1014    #[test]
1015    fn test_coerce_or_null_on_type_hint_mismatch() -> Result<()> {
1016        let settings = JsonSettings::try_new(
1017            vec![JsonTypeHint {
1018                path: vec!["kind".to_string()],
1019                data_type: ConcreteDataType::int64_datatype(),
1020                inverted_index: false,
1021                skipping_index: None,
1022            }],
1023            None,
1024        )?;
1025
1026        let result = settings
1027            .encode_with_type_hint_mismatch_policy(
1028                json!({"kind": "invalid", "message": "kept"}),
1029                TypeHintMismatchPolicy::CoerceOrNull,
1030            )?
1031            .into_json_inner()
1032            .unwrap();
1033        let Value::Struct(root) = result else {
1034            panic!("Expected Struct value");
1035        };
1036        assert_eq!(struct_field_value(&root, "kind"), &Value::Null);
1037        assert_eq!(
1038            struct_field_value(&root, "message"),
1039            &Value::String("kept".into())
1040        );
1041        Ok(())
1042    }
1043
1044    #[test]
1045    fn test_coerce_or_null_converts_type_hint_values() -> Result<()> {
1046        let settings = JsonSettings::try_new(
1047            vec![
1048                JsonTypeHint {
1049                    path: vec!["to_string".to_string()],
1050                    data_type: ConcreteDataType::string_datatype(),
1051                    inverted_index: false,
1052                    skipping_index: None,
1053                },
1054                JsonTypeHint {
1055                    path: vec!["to_int".to_string()],
1056                    data_type: ConcreteDataType::int64_datatype(),
1057                    inverted_index: false,
1058                    skipping_index: None,
1059                },
1060            ],
1061            None,
1062        )?;
1063
1064        let result = settings
1065            .encode_with_type_hint_mismatch_policy(
1066                json!({"to_string": 123, "to_int": "456", "invalid": "value"}),
1067                TypeHintMismatchPolicy::CoerceOrNull,
1068            )?
1069            .into_json_inner()
1070            .unwrap();
1071        let Value::Struct(root) = result else {
1072            panic!("Expected Struct value");
1073        };
1074        assert_eq!(
1075            struct_field_value(&root, "to_string"),
1076            &Value::String("123".into())
1077        );
1078        assert_eq!(struct_field_value(&root, "to_int"), &Value::Int64(456));
1079        assert_eq!(
1080            struct_field_value(&root, "invalid"),
1081            &Value::String("value".into())
1082        );
1083        Ok(())
1084    }
1085
1086    #[test]
1087    fn test_coerce_or_null_on_nested_type_hint_structure_mismatch() -> Result<()> {
1088        let settings = JsonSettings::try_new(
1089            vec![JsonTypeHint {
1090                path: vec!["user".to_string(), "age".to_string()],
1091                data_type: ConcreteDataType::int64_datatype(),
1092                inverted_index: false,
1093                skipping_index: None,
1094            }],
1095            None,
1096        )?;
1097
1098        let result = settings
1099            .encode_with_type_hint_mismatch_policy(
1100                json!({"user": "invalid", "message": "kept"}),
1101                TypeHintMismatchPolicy::CoerceOrNull,
1102            )?
1103            .into_json_inner()
1104            .unwrap();
1105        let Value::Struct(root) = result else {
1106            panic!("Expected Struct value");
1107        };
1108        assert_eq!(struct_field_value(&root, "user"), &Value::Null);
1109        assert_eq!(
1110            struct_field_value(&root, "message"),
1111            &Value::String("kept".into())
1112        );
1113        Ok(())
1114    }
1115
1116    #[test]
1117    fn test_encode_rejects_reserved_remainder_field() -> Result<()> {
1118        let settings = JsonSettings::default();
1119        let err = settings
1120            .encode(json!({"!__remainder__!": "user-value"}))
1121            .unwrap_err();
1122        assert!(
1123            err.to_string()
1124                .contains("root object cannot contain reserved field")
1125        );
1126
1127        settings.encode(json!({"nested": {"!__remainder__!": "user-value"}}))?;
1128        Ok(())
1129    }
1130
1131    #[test]
1132    fn test_encode_json_object() {
1133        let json = json!({
1134            "name": "John",
1135            "age": 30,
1136            "active": true
1137        });
1138
1139        let settings = JsonSettings::default();
1140        let result = settings.encode(json).unwrap().into_json_inner().unwrap();
1141        let Value::Struct(result) = result else {
1142            panic!("Expected Struct value");
1143        };
1144        assert_eq!(result.items().len(), 3);
1145
1146        let items = result.items();
1147        let struct_type = result.struct_type();
1148
1149        // Check that we have the expected fields
1150        let fields = struct_type.fields();
1151        let field_names: Vec<&str> = fields.iter().map(|f| f.name()).collect();
1152        assert!(field_names.contains(&"name"));
1153        assert!(field_names.contains(&"age"));
1154        assert!(field_names.contains(&"active"));
1155
1156        // Find and check each field
1157        for (i, field) in struct_type.fields().iter().enumerate() {
1158            match field.name() {
1159                "name" => {
1160                    assert_eq!(items[i], Value::String("John".into()));
1161                    assert_eq!(field.data_type(), &ConcreteDataType::string_datatype());
1162                }
1163                "age" => {
1164                    assert_eq!(items[i], Value::Int64(30));
1165                    assert_eq!(field.data_type(), &ConcreteDataType::int64_datatype());
1166                }
1167                "active" => {
1168                    assert_eq!(items[i], Value::Boolean(true));
1169                    assert_eq!(field.data_type(), &ConcreteDataType::boolean_datatype());
1170                }
1171                _ => panic!("Unexpected field: {}", field.name()),
1172            }
1173        }
1174    }
1175
1176    #[test]
1177    fn test_encode_json_nested_object() {
1178        let json = json!({
1179            "person": {
1180                "name": "Alice",
1181                "age": 25
1182            },
1183            "scores": [95, 87, 92]
1184        });
1185
1186        let settings = JsonSettings::default();
1187        let result = settings.encode(json).unwrap().into_json_inner().unwrap();
1188        let Value::Struct(result) = result else {
1189            panic!("Expected Struct value");
1190        };
1191        assert_eq!(result.items().len(), 2);
1192
1193        let items = result.items();
1194        let struct_type = result.struct_type();
1195
1196        // Check person field (nested struct)
1197        let person_index = struct_type
1198            .fields()
1199            .iter()
1200            .position(|f| f.name() == "person")
1201            .unwrap();
1202        if let Value::Struct(person_struct) = &items[person_index] {
1203            assert_eq!(person_struct.items().len(), 2);
1204            let fields = person_struct.struct_type().fields();
1205            let person_fields: Vec<&str> = fields.iter().map(|f| f.name()).collect();
1206            assert!(person_fields.contains(&"name"));
1207            assert!(person_fields.contains(&"age"));
1208        } else {
1209            panic!("Expected Struct value for person field");
1210        }
1211
1212        // Check scores field (list)
1213        let scores_index = struct_type
1214            .fields()
1215            .iter()
1216            .position(|f| f.name() == "scores")
1217            .unwrap();
1218        if let Value::List(scores_list) = &items[scores_index] {
1219            assert_eq!(scores_list.items().len(), 3);
1220            assert_eq!(scores_list.items()[0], Value::Int64(95));
1221            assert_eq!(scores_list.items()[1], Value::Int64(87));
1222            assert_eq!(scores_list.items()[2], Value::Int64(92));
1223        } else {
1224            panic!("Expected List value for scores field");
1225        }
1226    }
1227
1228    #[test]
1229    fn test_encode_json_structured() {
1230        let json = json!({
1231            "name": "Bob",
1232            "age": 35
1233        });
1234
1235        let settings = JsonSettings::default();
1236        let result = settings.encode(json).unwrap().into_json_inner().unwrap();
1237
1238        if let Value::Struct(struct_value) = result {
1239            assert_eq!(struct_value.items().len(), 2);
1240            let fields = struct_value.struct_type().fields();
1241            let field_names: Vec<&str> = fields.iter().map(|f| f.name()).collect();
1242            assert!(field_names.contains(&"name"));
1243            assert!(field_names.contains(&"age"));
1244        } else {
1245            panic!("Expected Struct value");
1246        }
1247    }
1248
1249    #[test]
1250    fn test_encode_json_respects_type_hint() -> Result<()> {
1251        let type_hints = vec![JsonTypeHint {
1252            path: vec!["age".to_string()],
1253            data_type: ConcreteDataType::int64_datatype(),
1254            inverted_index: false,
1255            skipping_index: None,
1256        }];
1257        let settings = JsonSettings::try_new(type_hints, None)?;
1258
1259        let result = settings
1260            .encode(json!({
1261                "name": "Alice",
1262                "age": 42
1263            }))
1264            .unwrap()
1265            .into_json_inner()
1266            .unwrap();
1267
1268        let Value::Struct(struct_value) = result else {
1269            panic!("Expected Struct value");
1270        };
1271        assert_eq!(struct_field_value(&struct_value, "age"), &Value::Int64(42));
1272
1273        let err = settings
1274            .encode(json!({
1275                "age": "42"
1276            }))
1277            .unwrap_err();
1278        assert!(err.to_string().contains("does not match JSON2 type hint"));
1279        Ok(())
1280    }
1281
1282    #[test]
1283    fn test_encode_json_respects_unsigned_type_hint() -> Result<()> {
1284        let type_hints = vec![JsonTypeHint {
1285            path: vec!["count".to_string()],
1286            data_type: ConcreteDataType::uint64_datatype(),
1287            inverted_index: false,
1288            skipping_index: None,
1289        }];
1290        let settings = JsonSettings::try_new(type_hints, None)?;
1291
1292        let result = settings
1293            .encode(json!({
1294                "count": u64::MAX
1295            }))
1296            .unwrap()
1297            .into_json_inner()
1298            .unwrap();
1299
1300        let Value::Struct(struct_value) = result else {
1301            panic!("Expected Struct value");
1302        };
1303        assert_eq!(
1304            struct_field_value(&struct_value, "count"),
1305            &Value::UInt64(u64::MAX)
1306        );
1307
1308        let err = settings
1309            .encode(json!({
1310                "count": -1
1311            }))
1312            .unwrap_err();
1313        assert!(err.to_string().contains("does not match JSON2 type hint"));
1314        Ok(())
1315    }
1316
1317    #[test]
1318    fn test_encode_json_fills_missing_type_hint_with_null() -> Result<()> {
1319        let type_hints = vec![JsonTypeHint {
1320            path: vec!["user".to_string(), "age".to_string()],
1321            data_type: ConcreteDataType::int64_datatype(),
1322            inverted_index: false,
1323            skipping_index: None,
1324        }];
1325        let settings = JsonSettings::try_new(type_hints, None)?;
1326
1327        let result = settings
1328            .encode(json!({}))
1329            .unwrap()
1330            .into_json_inner()
1331            .unwrap();
1332
1333        let Value::Struct(root) = result else {
1334            panic!("Expected Struct value");
1335        };
1336        let Value::Struct(user) = struct_field_value(&root, "user") else {
1337            panic!("Expected user Struct value");
1338        };
1339        assert_eq!(struct_field_value(user, "age"), &Value::Null);
1340        Ok(())
1341    }
1342
1343    #[test]
1344    fn test_encode_json_fills_missing_nullable_type_hint_with_null() -> Result<()> {
1345        let type_hints = vec![JsonTypeHint {
1346            path: vec!["user".to_string(), "name".to_string()],
1347            data_type: ConcreteDataType::string_datatype(),
1348            inverted_index: false,
1349            skipping_index: None,
1350        }];
1351        let settings = JsonSettings::try_new(type_hints, None)?;
1352
1353        let result = settings
1354            .encode(json!({ "user": {} }))
1355            .unwrap()
1356            .into_json_inner()
1357            .unwrap();
1358
1359        let Value::Struct(root) = result else {
1360            panic!("Expected Struct value");
1361        };
1362        let Value::Struct(user) = struct_field_value(&root, "user") else {
1363            panic!("Expected user Struct value");
1364        };
1365        assert_eq!(struct_field_value(user, "name"), &Value::Null);
1366        Ok(())
1367    }
1368
1369    #[test]
1370    fn test_encode_json_allows_missing_type_hint() -> Result<()> {
1371        let type_hints = vec![JsonTypeHint {
1372            path: vec!["user".to_string(), "age".to_string()],
1373            data_type: ConcreteDataType::int64_datatype(),
1374            inverted_index: false,
1375            skipping_index: None,
1376        }];
1377        let settings = JsonSettings::try_new(type_hints, None)?;
1378
1379        settings.encode(json!({}))?;
1380        Ok(())
1381    }
1382
1383    #[test]
1384    fn test_encode_json_merges_missing_type_hint_prefix() -> Result<()> {
1385        let type_hints = vec![
1386            JsonTypeHint {
1387                path: vec!["user".to_string(), "age".to_string()],
1388                data_type: ConcreteDataType::int64_datatype(),
1389                inverted_index: false,
1390                skipping_index: None,
1391            },
1392            JsonTypeHint {
1393                path: vec!["user".to_string(), "name".to_string()],
1394                data_type: ConcreteDataType::string_datatype(),
1395                inverted_index: false,
1396                skipping_index: None,
1397            },
1398        ];
1399        let settings = JsonSettings::try_new(type_hints, None)?;
1400
1401        let result = settings.encode(json!({}))?.into_json_inner().unwrap();
1402
1403        let Value::Struct(root) = result else {
1404            panic!("Expected Struct value");
1405        };
1406        let Value::Struct(user) = struct_field_value(&root, "user") else {
1407            panic!("Expected user Struct value");
1408        };
1409        assert_eq!(struct_field_value(user, "age"), &Value::Null);
1410        assert_eq!(struct_field_value(user, "name"), &Value::Null);
1411        Ok(())
1412    }
1413
1414    #[test]
1415    fn test_json_settings_structured() {
1416        let json = json!({
1417            "name": "Eve",
1418            "score": 95
1419        });
1420
1421        let settings = JsonSettings::default();
1422        let result = settings.encode(json).unwrap().into_json_inner().unwrap();
1423
1424        if let Value::Struct(struct_value) = result {
1425            assert_eq!(struct_value.items().len(), 2);
1426        } else {
1427            panic!("Expected Struct value");
1428        }
1429    }
1430
1431    #[cfg(test)]
1432    mod decode_tests {
1433        use ordered_float::OrderedFloat;
1434        use serde_json::json;
1435
1436        use super::*;
1437
1438        #[test]
1439        fn test_decode_primitive_values() {
1440            let settings = JsonSettings::default();
1441
1442            // Test null
1443            let result = settings.decode(Value::Null).unwrap();
1444            assert_eq!(result, Json::Null);
1445
1446            // Test boolean
1447            let result = settings.decode(Value::Boolean(true)).unwrap();
1448            assert_eq!(result, Json::Bool(true));
1449
1450            // Test integer
1451            let result = settings.decode(Value::Int64(42)).unwrap();
1452            assert_eq!(result, Json::from(42));
1453
1454            // Test float
1455            let result = settings.decode(Value::Float64(OrderedFloat(3.16))).unwrap();
1456            assert_eq!(result, Json::from(3.16));
1457
1458            // Test string
1459            let result = settings.decode(Value::String("hello".into())).unwrap();
1460            assert_eq!(result, Json::String("hello".to_string()));
1461        }
1462
1463        #[test]
1464        fn test_decode_struct() {
1465            let settings = JsonSettings::default();
1466
1467            let struct_value = StructValue::new(
1468                vec![
1469                    Value::String("Alice".into()),
1470                    Value::Int64(25),
1471                    Value::Boolean(true),
1472                ],
1473                StructType::new(Arc::new(vec![
1474                    StructField::new(
1475                        "name".to_string(),
1476                        ConcreteDataType::string_datatype(),
1477                        true,
1478                    ),
1479                    StructField::new("age".to_string(), ConcreteDataType::int64_datatype(), true),
1480                    StructField::new(
1481                        "active".to_string(),
1482                        ConcreteDataType::boolean_datatype(),
1483                        true,
1484                    ),
1485                ])),
1486            );
1487
1488            let result = settings.decode(Value::Struct(struct_value)).unwrap();
1489            let expected = json!({
1490                "name": "Alice",
1491                "age": 25,
1492                "active": true
1493            });
1494            assert_eq!(result, expected);
1495        }
1496
1497        #[test]
1498        fn test_decode_list() {
1499            let settings = JsonSettings::default();
1500
1501            let list_value = ListValue::new(
1502                vec![Value::Int64(1), Value::Int64(2), Value::Int64(3)],
1503                Arc::new(ConcreteDataType::int64_datatype()),
1504            );
1505
1506            let result = settings.decode(Value::List(list_value)).unwrap();
1507            let expected = json!([1, 2, 3]);
1508            assert_eq!(result, expected);
1509        }
1510
1511        #[test]
1512        fn test_decode_nested_structure() {
1513            let settings = JsonSettings::default();
1514
1515            let inner_struct = StructValue::new(
1516                vec![Value::String("Alice".into()), Value::Int64(25)],
1517                StructType::new(Arc::new(vec![
1518                    StructField::new(
1519                        "name".to_string(),
1520                        ConcreteDataType::string_datatype(),
1521                        true,
1522                    ),
1523                    StructField::new("age".to_string(), ConcreteDataType::int64_datatype(), true),
1524                ])),
1525            );
1526
1527            let score_list_item_type = Arc::new(ConcreteDataType::int64_datatype());
1528            let outer_struct = StructValue::new(
1529                vec![
1530                    Value::Struct(inner_struct),
1531                    Value::List(ListValue::new(
1532                        vec![Value::Int64(95), Value::Int64(87)],
1533                        score_list_item_type.clone(),
1534                    )),
1535                ],
1536                StructType::new(Arc::new(vec![
1537                    StructField::new(
1538                        "user".to_string(),
1539                        ConcreteDataType::Struct(StructType::new(Arc::new(vec![
1540                            StructField::new(
1541                                "name".to_string(),
1542                                ConcreteDataType::string_datatype(),
1543                                true,
1544                            ),
1545                            StructField::new(
1546                                "age".to_string(),
1547                                ConcreteDataType::int64_datatype(),
1548                                true,
1549                            ),
1550                        ]))),
1551                        true,
1552                    ),
1553                    StructField::new(
1554                        "scores".to_string(),
1555                        ConcreteDataType::List(ListType::new(score_list_item_type.clone())),
1556                        true,
1557                    ),
1558                ])),
1559            );
1560
1561            let result = settings.decode(Value::Struct(outer_struct)).unwrap();
1562            let expected = json!({
1563                "user": {
1564                    "name": "Alice",
1565                    "age": 25
1566                },
1567                "scores": [95, 87]
1568            });
1569            assert_eq!(result, expected);
1570        }
1571
1572        #[test]
1573        fn test_decode_missing_fields() {
1574            let settings = JsonSettings::default();
1575
1576            // Struct with missing field (null value)
1577            let struct_value = StructValue::new(
1578                vec![
1579                    Value::String("Bob".into()),
1580                    Value::Null, // missing age field
1581                ],
1582                StructType::new(Arc::new(vec![
1583                    StructField::new(
1584                        "name".to_string(),
1585                        ConcreteDataType::string_datatype(),
1586                        true,
1587                    ),
1588                    StructField::new("age".to_string(), ConcreteDataType::int64_datatype(), true),
1589                ])),
1590            );
1591
1592            let result = settings.decode(Value::Struct(struct_value)).unwrap();
1593            let expected = json!({
1594                "name": "Bob",
1595                "age": null
1596            });
1597            assert_eq!(result, expected);
1598        }
1599    }
1600}