Skip to main content

datatypes/vectors/json/
array.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
15use std::cmp::Ordering;
16use std::sync::Arc;
17
18use arrow::compute::{can_cast_types, cast};
19use arrow_array::cast::AsArray;
20use arrow_array::types::{
21    Float32Type, Float64Type, Int8Type, Int16Type, Int32Type, Int64Type, UInt8Type, UInt16Type,
22    UInt32Type, UInt64Type,
23};
24use arrow_array::{Array, ArrayRef, GenericListArray, ListArray, StructArray, new_null_array};
25use arrow_schema::{DataType, Field, FieldRef};
26use common_telemetry::trace;
27use serde_json::Value;
28use snafu::{OptionExt, ResultExt};
29
30use crate::arrow_array::{MutableBinaryArray, binary_array_value, string_array_value};
31use crate::data_type::ConcreteDataType;
32use crate::error::{
33    AlignJsonArraySnafu, ArrowComputeSnafu, InvalidJsonSnafu, InvalidJsonbSnafu, Result,
34};
35use crate::extension::json::{JSON2_REMAINDER_FIELD_NAME, json2_remainder_field};
36use crate::json::JsonSettings;
37use crate::json::value::{decode_json_variant, encode_serde_json_as_jsonb};
38use crate::prelude::{DataType as _, Value as GreptimeValue};
39use crate::value::{ListValue, StructValue};
40use crate::vectors::MutableVector;
41use crate::vectors::json::builder::{JsonVectorBuilder, json2_physical_data_type};
42use crate::vectors::json::variant::variant_to_json_values;
43
44pub struct JsonArray<'a> {
45    inner: &'a ArrayRef,
46}
47
48impl JsonArray<'_> {
49    /// Try to get the value (as a [Value]) at the index `i`.
50    pub fn try_get_value(&self, i: usize) -> Result<Value> {
51        let array = self.inner;
52        if array.is_null(i) {
53            return Ok(Value::Null);
54        }
55
56        let value = match array.data_type() {
57            DataType::Null => Value::Null,
58            DataType::Boolean => Value::Bool(array.as_boolean().value(i)),
59            DataType::Int8 => Value::from(array.as_primitive::<Int8Type>().value(i)),
60            DataType::Int16 => Value::from(array.as_primitive::<Int16Type>().value(i)),
61            DataType::Int32 => Value::from(array.as_primitive::<Int32Type>().value(i)),
62            DataType::Int64 => Value::from(array.as_primitive::<Int64Type>().value(i)),
63            DataType::UInt8 => Value::from(array.as_primitive::<UInt8Type>().value(i)),
64            DataType::UInt16 => Value::from(array.as_primitive::<UInt16Type>().value(i)),
65            DataType::UInt32 => Value::from(array.as_primitive::<UInt32Type>().value(i)),
66            DataType::UInt64 => Value::from(array.as_primitive::<UInt64Type>().value(i)),
67            DataType::Float32 => Value::from(array.as_primitive::<Float32Type>().value(i)),
68            DataType::Float64 => Value::from(array.as_primitive::<Float64Type>().value(i)),
69            DataType::Utf8 | DataType::LargeUtf8 | DataType::Utf8View => {
70                Value::String(string_array_value(array, i).to_string())
71            }
72            DataType::Binary | DataType::LargeBinary | DataType::BinaryView => {
73                let bytes = binary_array_value(array, i);
74                decode_json_variant(bytes).map_err(|error| InvalidJsonbSnafu { error }.build())?
75            }
76            DataType::Struct(_) => {
77                let structs = array.as_struct();
78                let object = structs
79                    .fields()
80                    .iter()
81                    .zip(structs.columns())
82                    .map(|(field, column)| {
83                        JsonArray::from(column)
84                            .try_get_value(i)
85                            .map(|v| (field.name().clone(), v))
86                    })
87                    .collect::<Result<_>>()?;
88                Value::Object(object)
89            }
90            DataType::List(_) => {
91                let lists = array.as_list::<i32>();
92                let list = lists.value(i);
93                let list = JsonArray::from(&list);
94                let mut values = Vec::with_capacity(list.inner.len());
95                for i in 0..list.inner.len() {
96                    values.push(list.try_get_value(i)?);
97                }
98                Value::Array(values)
99            }
100            t => {
101                return InvalidJsonSnafu {
102                    value: format!("unknown JSON type {t}"),
103                }
104                .fail();
105            }
106        };
107        Ok(value)
108    }
109
110    /// Projects a physical JSON2 array to a logical query type.
111    ///
112    /// TODO(LFC) Supersede `project_to_v2` to `project_to`.
113    pub fn project_to_v2(&self, field: &Field, target: &DataType) -> Result<ArrayRef> {
114        if json2_remainder_field(field)?.is_some() {
115            project_json_values(self.json2_values()?, target)
116        } else {
117            self.project_to(target)
118        }
119    }
120
121    /// Rewrites a JSON2 array from the current physical layout into the specified
122    /// v2 physical layout.
123    pub fn rewrite_to_v2(
124        &self,
125        field: &Field,
126        logical_settings: &JsonSettings,
127        target_layout: &JsonSettings,
128    ) -> Result<ArrayRef> {
129        let is_v2 = json2_remainder_field(field)?.is_some();
130        if is_v2 && self.inner.data_type() == &json2_physical_data_type(target_layout) {
131            return Ok(self.inner.clone());
132        }
133
134        let values = if is_v2 {
135            self.json2_values()?
136        } else {
137            (0..self.inner.len())
138                .map(|i| self.try_get_value(i))
139                .collect::<Result<Vec<_>>>()?
140        };
141        let mut builder = JsonVectorBuilder::with_settings(target_layout, values.len());
142        for value in values {
143            if value.is_null() {
144                builder.push_null();
145            } else {
146                let value = logical_settings.encode(value)?;
147                builder.try_push_value_ref(&value.as_value_ref())?;
148            }
149        }
150        Ok(builder.to_vector().to_arrow_array())
151    }
152
153    fn json2_values(&self) -> Result<Vec<Value>> {
154        let structs = self.inner.as_struct_opt().context(AlignJsonArraySnafu {
155            reason: "JSON2 layout v2 root array must be a struct",
156        })?;
157        let remainder = structs.column_by_name(JSON2_REMAINDER_FIELD_NAME);
158        let mut remainders = if let Some(remainder) = remainder {
159            variant_to_json_values(remainder)?
160        } else {
161            vec![None; structs.len()]
162        };
163        let mut values = Vec::with_capacity(structs.len());
164        let mut path = Vec::new();
165
166        for (i, remainder) in remainders.iter_mut().enumerate() {
167            if structs.is_null(i) {
168                values.push(Value::Null);
169                continue;
170            }
171
172            let mut object = match remainder.take() {
173                None => serde_json::Map::new(),
174                Some(Value::Object(object)) => object,
175                Some(value) => {
176                    return InvalidJsonSnafu {
177                        value: format!("JSON2 layout v2 remainder must be an object, got {value}"),
178                    }
179                    .fail();
180                }
181            };
182
183            for (child, column) in structs.fields().iter().zip(structs.columns()) {
184                if child.name() == JSON2_REMAINDER_FIELD_NAME {
185                    continue;
186                }
187                let mut value = JsonArray::from(column).try_get_value(i)?;
188                // Arrow child nulls cannot distinguish a missing path from an explicit JSON
189                // null. Builders preserve explicit null presence in the remainder, so nulls
190                // from the explicit branch must be discarded before merging both branches.
191                remove_null_object_fields(&mut value);
192                if value.is_null() {
193                    continue;
194                }
195                merge_explicit_value(&mut object, child.name().clone(), value, &mut path)?;
196            }
197            values.push(Value::Object(object));
198        }
199
200        Ok(values)
201    }
202
203    /// Normalizes a JSON2 array to the wider `expect` data type without losing
204    /// information.
205    ///
206    /// This is mainly used for write/flush-time JSON2 schema alignment:
207    /// - fields missing from the source are filled with typed null arrays;
208    /// - fields present in the source must also exist in `expect`;
209    /// - fields present in both are widened recursively when their types differ.
210    ///
211    /// Narrowing conversions and any other conversions that may lose information
212    /// are rejected.
213    pub fn widen_to(&self, expect: &DataType) -> Result<ArrayRef> {
214        let data_type = self.inner.data_type();
215
216        if data_type == expect {
217            return Ok(self.inner.clone());
218        }
219
220        trace!(
221            "Try aligning JSON array {} to data type {}",
222            data_type, expect
223        );
224
225        let struct_array = self.inner.as_struct_opt().context(AlignJsonArraySnafu {
226            reason: "expect struct array",
227        })?;
228        let array_fields = struct_array.fields();
229        let array_columns = struct_array.columns();
230        let DataType::Struct(expect_fields) = expect else {
231            return AlignJsonArraySnafu {
232                reason: "expect struct datatype",
233            }
234            .fail();
235        };
236        let mut aligned = Vec::with_capacity(expect_fields.len());
237
238        // Compare the fields in the JSON array and the to-be-aligned schema, amending with null
239        // arrays on the way. It's very important to note that fields in the JSON array and those
240        // in the JSON type are both **SORTED**, which can be guaranteed because the fields in the
241        // JSON type implementation are sorted.
242        debug_assert!(expect_fields.iter().map(|f| f.name()).is_sorted());
243        debug_assert!(array_fields.iter().map(|f| f.name()).is_sorted());
244
245        let mut i = 0; // point to the expect fields
246        let mut j = 0; // point to the array fields
247        while i < expect_fields.len() && j < array_fields.len() {
248            let expect_field = &expect_fields[i];
249            let array_field = &array_fields[j];
250            match expect_field.name().cmp(array_field.name()) {
251                Ordering::Equal => {
252                    if expect_field.data_type() == array_field.data_type() {
253                        aligned.push(array_columns[j].clone());
254                    } else {
255                        let expect_type = expect_field.data_type();
256                        let array_type = array_field.data_type();
257                        let array = match (expect_type, array_type) {
258                            (DataType::Struct(_), DataType::Struct(_)) => {
259                                JsonArray::from(&array_columns[j]).widen_to(expect_type)?
260                            }
261                            (DataType::List(expect_item), DataType::List(array_item)) => {
262                                let list_array = array_columns[j].as_list::<i32>();
263                                widen_list(list_array, array_item, expect_item)?
264                            }
265                            _ => JsonArray::from(&array_columns[j]).widen_scalar_to(expect_type)?,
266                        };
267                        aligned.push(array);
268                    }
269                    i += 1;
270                    j += 1;
271                }
272                Ordering::Less => {
273                    aligned.push(new_null_array(expect_field.data_type(), struct_array.len()));
274                    i += 1;
275                }
276                Ordering::Greater => {
277                    return AlignJsonArraySnafu {
278                        reason: format!(
279                            "source field {} does not exist in target schema",
280                            array_field.name()
281                        ),
282                    }
283                    .fail();
284                }
285            }
286        }
287        if j < array_fields.len() {
288            return AlignJsonArraySnafu {
289                reason: format!(
290                    "source field {} does not exist in target schema",
291                    array_fields[j].name()
292                ),
293            }
294            .fail();
295        }
296        if i < expect_fields.len() {
297            for field in &expect_fields[i..] {
298                aligned.push(new_null_array(field.data_type(), struct_array.len()));
299            }
300        }
301
302        let json_array = StructArray::try_new_with_length(
303            expect_fields.clone(),
304            aligned,
305            struct_array.nulls().cloned(),
306            struct_array.len(),
307        )
308        .map_err(|e| {
309            AlignJsonArraySnafu {
310                reason: e.to_string(),
311            }
312            .build()
313        })?;
314        Ok(Arc::new(json_array))
315    }
316
317    /// Widens an array to the merged JSON2 physical type without losing information.
318    ///
319    /// Supported conversions:
320    /// - identical types are returned unchanged;
321    /// - null arrays become typed null arrays;
322    /// - concrete JSON values are encoded as JSONB when the target type is binary.
323    ///
324    /// All other conversions are rejected.
325    fn widen_scalar_to(&self, to_type: &DataType) -> Result<ArrayRef> {
326        let from_type = self.inner.data_type();
327        if from_type == to_type {
328            return Ok(self.inner.clone());
329        }
330
331        if from_type == &DataType::Null {
332            return Ok(new_null_array(to_type, self.inner.len()));
333        }
334
335        if !from_type.is_binary() && to_type.is_binary() {
336            return self.encode_variant();
337        }
338
339        AlignJsonArraySnafu {
340            reason: format!("unable to widen {from_type} to {to_type}"),
341        }
342        .fail()
343    }
344
345    fn encode_variant(&self) -> Result<ArrayRef> {
346        let len = self.inner.len();
347        let mut encoded = Vec::with_capacity(len);
348        let mut total_bytes = 0;
349
350        for i in 0..len {
351            let value = self.try_get_value(i)?;
352            if value.is_null() {
353                encoded.push(None);
354            } else {
355                let bytes = encode_serde_json_as_jsonb(value);
356                total_bytes += bytes.len();
357                encoded.push(Some(bytes));
358            }
359        }
360
361        let mut builder = MutableBinaryArray::with_capacity(len, total_bytes);
362        for value in encoded {
363            builder.append_option(value);
364        }
365        Ok(Arc::new(builder.finish()))
366    }
367
368    /// Projects this JSON array to `target` for query evaluation.
369    ///
370    /// Unlike [`Self::widen_to`], projection tolerates lossy conversions:
371    /// - source fields not present in `target` are discarded;
372    /// - fields missing from the source are filled with typed null arrays;
373    /// - values incompatible with the target type become NULL.
374    ///
375    /// Projection is applied recursively to structs and lists. Input nulls
376    /// remain NULL. Errors unrelated to type incompatibility, such as invalid
377    /// JSONB, are returned.
378    pub fn project_to(&self, target: &DataType) -> Result<ArrayRef> {
379        if self.inner.data_type() == target {
380            return Ok(self.inner.clone());
381        }
382
383        match (self.inner.data_type(), target) {
384            (DataType::Struct(_), DataType::Struct(target_fields)) => {
385                let struct_array = self.inner.as_struct();
386                let mut columns = Vec::with_capacity(target_fields.len());
387                for target_field in target_fields {
388                    let column = struct_array
389                        .column_by_name(target_field.name())
390                        .map(|column| JsonArray::from(column).project_to(target_field.data_type()))
391                        .transpose()?
392                        .unwrap_or_else(|| {
393                            new_null_array(target_field.data_type(), self.inner.len())
394                        });
395                    columns.push(column);
396                }
397                let projected = StructArray::try_new_with_length(
398                    target_fields.clone(),
399                    columns,
400                    struct_array.nulls().cloned(),
401                    struct_array.len(),
402                )
403                .context(ArrowComputeSnafu)?;
404                Ok(Arc::new(projected))
405            }
406            (DataType::List(_), DataType::List(target_item)) => {
407                let list_array = self.inner.as_list::<i32>();
408                let item_projected =
409                    JsonArray::from(list_array.values()).project_to(target_item.data_type())?;
410                Ok(Arc::new(
411                    GenericListArray::<i32>::try_new(
412                        target_item.clone(),
413                        list_array.offsets().clone(),
414                        item_projected,
415                        list_array.nulls().cloned(),
416                    )
417                    .context(ArrowComputeSnafu)?,
418                ))
419            }
420            _ => self.project_values_to(target),
421        }
422    }
423
424    fn project_values_to(&self, to_type: &DataType) -> Result<ArrayRef> {
425        let from_type = self.inner.data_type();
426        if can_fast_cast_types(from_type, to_type) {
427            return cast(self.inner.as_ref(), to_type).context(ArrowComputeSnafu);
428        }
429
430        let values = (0..self.inner.len())
431            .map(|i| self.try_get_value(i))
432            .collect::<Result<Vec<_>>>()?;
433        project_json_values(values, to_type)
434    }
435}
436
437fn merge_explicit_value(
438    remainder: &mut serde_json::Map<String, Value>,
439    key: String,
440    explicit: Value,
441    path: &mut Vec<String>,
442) -> Result<()> {
443    let Some(existing) = remainder.get_mut(&key) else {
444        remainder.insert(key, explicit);
445        return Ok(());
446    };
447    path.push(key);
448
449    let (Value::Object(remainder), Value::Object(explicit)) = (existing, explicit) else {
450        return InvalidJsonSnafu {
451            value: format!(
452                "cannot merge '{}' in explicit fields and remainder: not both objects",
453                path.join("."),
454            ),
455        }
456        .fail();
457    };
458    for (key, value) in explicit {
459        merge_explicit_value(remainder, key, value, path)?;
460    }
461    path.pop();
462    Ok(())
463}
464
465fn remove_null_object_fields(value: &mut Value) {
466    let Value::Object(object) = value else {
467        return;
468    };
469    object.retain(|_, value| {
470        remove_null_object_fields(value);
471        !value.is_null()
472    });
473}
474
475/// Returns whether Arrow can cast between the types without JSON-aware projection.
476/// Binary and nested types require JSONB decoding or recursive projection.
477fn can_fast_cast_types(from_type: &DataType, to_type: &DataType) -> bool {
478    let is_scalar = |data_type: &DataType| {
479        data_type.is_numeric() || data_type.is_string() || data_type == &DataType::Boolean
480    };
481
482    is_scalar(from_type) && is_scalar(to_type) && can_cast_types(from_type, to_type)
483}
484
485fn project_json_values(values: Vec<Value>, to_type: &DataType) -> Result<ArrayRef> {
486    let concrete_type = ConcreteDataType::from_arrow_type(to_type);
487    let mut builder = concrete_type.create_mutable_vector(values.len());
488    for value in values {
489        let value = project_json_value_to_type(value, &concrete_type)?;
490        builder.try_push_value_ref(&value.as_value_ref())?;
491    }
492    Ok(builder.to_vector().to_arrow_array())
493}
494
495fn project_json_value_to_type(value: Value, to_type: &ConcreteDataType) -> Result<GreptimeValue> {
496    if value.is_null() {
497        return Ok(GreptimeValue::Null);
498    }
499
500    if to_type.is_string() {
501        let value = match value {
502            Value::String(value) => value,
503            value => value.to_string(),
504        };
505        return Ok(GreptimeValue::String(value.into()));
506    }
507
508    if matches!(to_type, ConcreteDataType::Binary(_)) {
509        return Ok(GreptimeValue::Binary(
510            encode_serde_json_as_jsonb(value).into(),
511        ));
512    }
513
514    if let Some(struct_type) = to_type.as_struct() {
515        let Value::Object(mut object) = value else {
516            return Ok(GreptimeValue::Null);
517        };
518        let values = struct_type
519            .fields()
520            .iter()
521            .map(|field| {
522                object
523                    .remove(field.name())
524                    .map(|value| project_json_value_to_type(value, field.data_type()))
525                    .transpose()
526                    .map(|value| value.unwrap_or(GreptimeValue::Null))
527            })
528            .collect::<Result<Vec<_>>>()?;
529        return Ok(GreptimeValue::Struct(StructValue::new(
530            values,
531            struct_type.clone(),
532        )));
533    }
534
535    if let Some(list_type) = to_type.as_list() {
536        let Value::Array(values) = value else {
537            return Ok(GreptimeValue::Null);
538        };
539        let item_type = list_type.item_type().clone();
540        let values = values
541            .into_iter()
542            .map(|value| project_json_value_to_type(value, &item_type))
543            .collect::<Result<Vec<_>>>()?;
544        return Ok(GreptimeValue::List(ListValue::new(
545            values,
546            Arc::new(item_type),
547        )));
548    }
549
550    let value = match value {
551        Value::Bool(value) => GreptimeValue::Boolean(value),
552        Value::Number(value) => {
553            if let Some(value) = value.as_i64() {
554                GreptimeValue::Int64(value)
555            } else if let Some(value) = value.as_u64() {
556                GreptimeValue::UInt64(value)
557            } else if let Some(value) = value.as_f64() {
558                GreptimeValue::Float64(value.into())
559            } else {
560                GreptimeValue::Null
561            }
562        }
563        Value::String(value) => GreptimeValue::String(value.into()),
564        Value::Array(_) | Value::Object(_) => GreptimeValue::Null,
565        Value::Null => GreptimeValue::Null,
566    };
567    Ok(to_type.try_cast(value).unwrap_or(GreptimeValue::Null))
568}
569
570fn widen_list(list_array: &ListArray, actual: &FieldRef, expected: &FieldRef) -> Result<ArrayRef> {
571    let item_aligned = match (actual.data_type(), expected.data_type()) {
572        (DataType::Struct(_), DataType::Struct(_)) => {
573            JsonArray::from(list_array.values()).widen_to(expected.data_type())?
574        }
575        (DataType::List(actual), DataType::List(expected)) => {
576            let list_array = list_array.values().as_list::<i32>();
577            widen_list(list_array, actual, expected)?
578        }
579        _ => JsonArray::from(list_array.values()).widen_scalar_to(expected.data_type())?,
580    };
581    Ok(Arc::new(
582        GenericListArray::<i32>::try_new(
583            expected.clone(),
584            list_array.offsets().clone(),
585            item_aligned,
586            list_array.nulls().cloned(),
587        )
588        .context(ArrowComputeSnafu)?,
589    ))
590}
591
592impl<'a> From<&'a ArrayRef> for JsonArray<'a> {
593    fn from(inner: &'a ArrayRef) -> Self {
594        Self { inner }
595    }
596}
597
598#[cfg(test)]
599mod test {
600    use std::sync::Arc;
601
602    use arrow_array::types::Int64Type;
603    use arrow_array::{
604        BinaryArray, BooleanArray, Float32Array, Float64Array, Int8Array, Int16Array, Int32Array,
605        Int64Array, ListArray, StringArray, UInt8Array, UInt16Array, UInt32Array, UInt64Array,
606    };
607    use arrow_schema::{Field, Fields};
608    use serde_json::json;
609
610    use super::*;
611    use crate::extension::json::{Json2ExtensionType, JsonMetadata};
612    use crate::json::{JsonSettings, JsonTypeHint};
613    use crate::vectors::json::variant::{json_values_to_variant, variant_field};
614
615    #[test]
616    fn test_try_get_value() -> Result<()> {
617        let nulls = new_null_array(&DataType::Null, 2);
618        assert_eq!(JsonArray::from(&nulls).try_get_value(0)?, Value::Null);
619
620        let bools: ArrayRef = Arc::new(BooleanArray::from(vec![Some(true), None]));
621        assert_eq!(JsonArray::from(&bools).try_get_value(0)?, json!(true));
622        assert_eq!(JsonArray::from(&bools).try_get_value(1)?, Value::Null);
623
624        let ints: ArrayRef = Arc::new(Int64Array::from(vec![Some(-7), None]));
625        assert_eq!(JsonArray::from(&ints).try_get_value(0)?, json!(-7));
626        assert_eq!(JsonArray::from(&ints).try_get_value(1)?, Value::Null);
627
628        macro_rules! assert_number {
629            ($array:expr, $expected:expr) => {{
630                let array: ArrayRef = Arc::new($array);
631                assert_eq!(JsonArray::from(&array).try_get_value(0)?, json!($expected));
632            }};
633        }
634        assert_number!(Int8Array::from(vec![-8]), -8);
635        assert_number!(Int16Array::from(vec![-16]), -16);
636        assert_number!(Int32Array::from(vec![-32]), -32);
637        assert_number!(UInt8Array::from(vec![8]), 8);
638        assert_number!(UInt16Array::from(vec![16]), 16);
639        assert_number!(UInt32Array::from(vec![32]), 32);
640        assert_number!(Float32Array::from(vec![1.25]), 1.25);
641
642        let floats: ArrayRef = Arc::new(Float64Array::from(vec![Some(1.5)]));
643        assert_eq!(JsonArray::from(&floats).try_get_value(0)?, json!(1.5));
644
645        let strings: ArrayRef = Arc::new(StringArray::from(vec![Some("hello"), None]));
646        assert_eq!(JsonArray::from(&strings).try_get_value(0)?, json!("hello"));
647        assert_eq!(JsonArray::from(&strings).try_get_value(1)?, Value::Null);
648
649        let nested = jsonb::parse_value(br#"{"nested":[1,null,"x"]}"#)
650            .unwrap()
651            .to_vec();
652        let null = jsonb::parse_value(b"null").unwrap().to_vec();
653        let binaries: ArrayRef =
654            Arc::new(BinaryArray::from(vec![nested.as_slice(), null.as_slice()]));
655        assert_eq!(
656            JsonArray::from(&binaries).try_get_value(0)?,
657            json!({"nested": [1, null, "x"]})
658        );
659        assert_eq!(JsonArray::from(&binaries).try_get_value(1)?, Value::Null);
660
661        let lists: ArrayRef = Arc::new(ListArray::from_iter_primitive::<Int64Type, _, _>(vec![
662            Some(vec![Some(1), None, Some(3)]),
663            None,
664        ]));
665        assert_eq!(
666            JsonArray::from(&lists).try_get_value(0)?,
667            json!([1, null, 3])
668        );
669        assert_eq!(JsonArray::from(&lists).try_get_value(1)?, Value::Null);
670
671        let structs: ArrayRef = Arc::new(StructArray::from(vec![
672            (
673                Arc::new(Field::new("flag", DataType::Boolean, true)),
674                Arc::new(BooleanArray::from(vec![Some(true), None])) as ArrayRef,
675            ),
676            (
677                Arc::new(Field::new_list(
678                    "items",
679                    Field::new_list_field(DataType::Int64, true),
680                    true,
681                )),
682                Arc::new(ListArray::from_iter_primitive::<Int64Type, _, _>(vec![
683                    Some(vec![Some(1), None]),
684                    Some(vec![Some(2)]),
685                ])) as ArrayRef,
686            ),
687        ]));
688        assert_eq!(
689            JsonArray::from(&structs).try_get_value(0)?,
690            json!({"flag": true, "items": [1, null]})
691        );
692        assert_eq!(
693            JsonArray::from(&structs).try_get_value(1)?,
694            json!({"flag": null, "items": [2]})
695        );
696
697        Ok(())
698    }
699
700    #[test]
701    fn test_cast_variant_to_utf8_view_preserves_json_null() -> Result<()> {
702        let encode = |json: &[u8]| jsonb::parse_value(json).unwrap().to_vec();
703        let json_null = encode(b"null");
704        let object = encode(br#"{"value":1}"#);
705        let string = encode(br#""text""#);
706        let variants: ArrayRef = Arc::new(BinaryArray::from(vec![
707            Some(json_null.as_slice()),
708            Some(object.as_slice()),
709            Some(string.as_slice()),
710            None,
711        ]));
712
713        let casted = JsonArray::from(&variants).project_to(&DataType::Utf8View)?;
714        let casted = casted.as_string_view();
715        assert!(casted.is_null(0));
716        assert_eq!(casted.value(1), r#"{"value":1}"#);
717        assert_eq!(casted.value(2), "text");
718        assert!(casted.is_null(3));
719
720        Ok(())
721    }
722
723    #[test]
724    fn test_project_plain_scalars() -> Result<()> {
725        let integers: ArrayRef = Arc::new(Int64Array::from(vec![Some(42), Some(i64::MAX), None]));
726        let projected = JsonArray::from(&integers).project_to(&DataType::Int32)?;
727        let expected: ArrayRef = Arc::new(Int32Array::from(vec![Some(42), None, None]));
728        assert_eq!(&expected, &projected);
729
730        let booleans: ArrayRef = Arc::new(BooleanArray::from(vec![Some(true), Some(false), None]));
731        let projected = JsonArray::from(&booleans).project_to(&DataType::Float64)?;
732        let expected: ArrayRef = Arc::new(Float64Array::from(vec![Some(1.0), Some(0.0), None]));
733        assert_eq!(&expected, &projected);
734
735        let strings: ArrayRef = Arc::new(StringArray::from(vec![Some("42"), Some("bad"), None]));
736        let projected = JsonArray::from(&strings).project_to(&DataType::UInt64)?;
737        let expected: ArrayRef = Arc::new(UInt64Array::from(vec![Some(42), None, None]));
738        assert_eq!(&expected, &projected);
739
740        Ok(())
741    }
742
743    #[test]
744    fn test_widen_null_to_any_type() -> Result<()> {
745        let nulls = new_null_array(&DataType::Null, 2);
746        let target_types = [
747            DataType::Boolean,
748            DataType::UInt64,
749            DataType::Utf8View,
750            DataType::Binary,
751            DataType::List(Arc::new(Field::new_list_field(DataType::Int64, true))),
752            DataType::Struct(Fields::from(vec![Field::new(
753                "value",
754                DataType::Int64,
755                true,
756            )])),
757        ];
758
759        for target_type in target_types {
760            let widened = JsonArray::from(&nulls).widen_scalar_to(&target_type)?;
761            assert_eq!(&target_type, widened.data_type());
762            assert_eq!(2, widened.len());
763            assert_eq!(2, widened.null_count());
764        }
765
766        Ok(())
767    }
768
769    #[test]
770    fn test_widen_non_null_to_utf8_view_fails() {
771        let bools: ArrayRef = Arc::new(BooleanArray::from(vec![true]));
772        let err = JsonArray::from(&bools)
773            .widen_scalar_to(&DataType::Utf8View)
774            .unwrap_err();
775
776        assert_eq!(
777            "Failed to align JSON array, reason: unable to widen Boolean to Utf8View",
778            err.to_string()
779        );
780    }
781
782    #[test]
783    fn test_widen_variant_to_non_binary_fails() {
784        let value = jsonb::parse_value(b"true").unwrap().to_vec();
785        let variants: ArrayRef = Arc::new(BinaryArray::from(vec![value.as_slice()]));
786        let err = JsonArray::from(&variants)
787            .widen_scalar_to(&DataType::Boolean)
788            .unwrap_err();
789
790        assert_eq!(
791            "Failed to align JSON array, reason: unable to widen Binary to Boolean",
792            err.to_string()
793        );
794    }
795
796    #[test]
797    fn test_widen_between_number_types_fails() {
798        let values: ArrayRef = Arc::new(UInt64Array::from(vec![1]));
799        let err = JsonArray::from(&values)
800            .widen_scalar_to(&DataType::Int64)
801            .unwrap_err();
802
803        assert_eq!(
804            "Failed to align JSON array, reason: unable to widen UInt64 to Int64",
805            err.to_string()
806        );
807    }
808
809    #[test]
810    fn test_widen_numbers_to_variant_preserves_values() -> Result<()> {
811        let cases: [(ArrayRef, Value); 3] = [
812            (Arc::new(UInt64Array::from(vec![u64::MAX])), json!(u64::MAX)),
813            (Arc::new(Int64Array::from(vec![i64::MIN])), json!(i64::MIN)),
814            (Arc::new(Float64Array::from(vec![1.25])), json!(1.25)),
815        ];
816
817        for (values, expected) in cases {
818            let widened = JsonArray::from(&values).widen_scalar_to(&DataType::Binary)?;
819            assert_eq!(&DataType::Binary, widened.data_type());
820            assert_eq!(expected, JsonArray::from(&widened).try_get_value(0)?);
821        }
822
823        Ok(())
824    }
825
826    #[test]
827    fn test_align_json_array() -> Result<()> {
828        struct TestCase {
829            json_array: ArrayRef,
830            schema_type: DataType,
831            expected: std::result::Result<ArrayRef, String>,
832        }
833
834        impl TestCase {
835            fn new(
836                json_array: StructArray,
837                schema_type: Fields,
838                expected: std::result::Result<Vec<ArrayRef>, String>,
839            ) -> Self {
840                Self {
841                    json_array: Arc::new(json_array),
842                    schema_type: DataType::Struct(schema_type.clone()),
843                    expected: expected
844                        .map(|x| Arc::new(StructArray::new(schema_type, x, None)) as ArrayRef),
845                }
846            }
847
848            fn test(self) -> Result<()> {
849                let result = JsonArray::from(&self.json_array).widen_to(&self.schema_type);
850                match (result, self.expected) {
851                    (Ok(json_array), Ok(expected)) => assert_eq!(&json_array, &expected),
852                    (Ok(json_array), Err(e)) => {
853                        panic!("expecting error {e} but actually get: {json_array:?}")
854                    }
855                    (Err(e), Err(expected)) => assert_eq!(e.to_string(), expected),
856                    (Err(e), Ok(_)) => return Err(e),
857                }
858                Ok(())
859            }
860        }
861
862        // Test empty json array can be aligned with a complex json type.
863        TestCase::new(
864            StructArray::new_empty_fields(2, None),
865            Fields::from(vec![
866                Field::new("int", DataType::Int64, true),
867                Field::new_struct(
868                    "nested",
869                    vec![Field::new("bool", DataType::Boolean, true)],
870                    true,
871                ),
872                Field::new("string", DataType::Utf8, true),
873            ]),
874            Ok(vec![
875                Arc::new(Int64Array::new_null(2)) as ArrayRef,
876                Arc::new(StructArray::new_null(
877                    Fields::from(vec![Arc::new(Field::new("bool", DataType::Boolean, true))]),
878                    2,
879                )),
880                Arc::new(StringArray::new_null(2)),
881            ]),
882        )
883        .test()?;
884
885        // Test simple json array alignment.
886        TestCase::new(
887            StructArray::from(vec![(
888                Arc::new(Field::new("float", DataType::Float64, true)),
889                Arc::new(Float64Array::from(vec![1.0, 2.0, 3.0])) as ArrayRef,
890            )]),
891            Fields::from(vec![
892                Field::new("float", DataType::Float64, true),
893                Field::new("string", DataType::Utf8, true),
894            ]),
895            Ok(vec![
896                Arc::new(Float64Array::from(vec![1.0, 2.0, 3.0])) as ArrayRef,
897                Arc::new(StringArray::new_null(3)),
898            ]),
899        )
900        .test()?;
901
902        // Test complex json array alignment.
903        TestCase::new(
904            StructArray::from(vec![
905                (
906                    Arc::new(Field::new_list(
907                        "list",
908                        Field::new_list_field(DataType::Int64, true),
909                        true,
910                    )),
911                    Arc::new(ListArray::from_iter_primitive::<Int64Type, _, _>(vec![
912                        Some(vec![Some(1)]),
913                        None,
914                        Some(vec![Some(2), Some(3)]),
915                    ])) as ArrayRef,
916                ),
917                (
918                    Arc::new(Field::new_struct(
919                        "nested",
920                        vec![Field::new("int", DataType::Int64, true)],
921                        true,
922                    )),
923                    Arc::new(StructArray::from(vec![(
924                        Arc::new(Field::new("int", DataType::Int64, true)),
925                        Arc::new(Int64Array::from(vec![-1, -2, -3])) as ArrayRef,
926                    )])),
927                ),
928                (
929                    Arc::new(Field::new("string", DataType::Utf8, true)),
930                    Arc::new(StringArray::from(vec!["a", "b", "c"])),
931                ),
932            ]),
933            Fields::from(vec![
934                Field::new("bool", DataType::Boolean, true),
935                Field::new_list("list", Field::new_list_field(DataType::Int64, true), true),
936                Field::new_struct(
937                    "nested",
938                    vec![
939                        Field::new("float", DataType::Float64, true),
940                        Field::new("int", DataType::Int64, true),
941                    ],
942                    true,
943                ),
944                Field::new("string", DataType::Utf8, true),
945            ]),
946            Ok(vec![
947                Arc::new(BooleanArray::new_null(3)) as ArrayRef,
948                Arc::new(ListArray::from_iter_primitive::<Int64Type, _, _>(vec![
949                    Some(vec![Some(1)]),
950                    None,
951                    Some(vec![Some(2), Some(3)]),
952                ])),
953                Arc::new(StructArray::from(vec![
954                    (
955                        Arc::new(Field::new("float", DataType::Float64, true)),
956                        Arc::new(Float64Array::new_null(3)) as ArrayRef,
957                    ),
958                    (
959                        Arc::new(Field::new("int", DataType::Int64, true)),
960                        Arc::new(Int64Array::from(vec![-1, -2, -3])),
961                    ),
962                ])),
963                Arc::new(StringArray::from(vec!["a", "b", "c"])),
964            ]),
965        )
966        .test()?;
967
968        // Source fields that do not exist in the target schema must not be discarded.
969        TestCase::new(
970            StructArray::from(vec![(
971                Arc::new(Field::new("a", DataType::Boolean, true)),
972                Arc::new(BooleanArray::from(vec![true])) as ArrayRef,
973            )]),
974            Fields::from(vec![Field::new("b", DataType::Boolean, true)]),
975            Err(
976                "Failed to align JSON array, reason: source field a does not exist in target schema"
977                    .to_string(),
978            ),
979        )
980        .test()?;
981
982        // Trailing source fields must also be rejected after all target fields are processed.
983        TestCase::new(
984            StructArray::from(vec![(
985                Arc::new(Field::new("b", DataType::Boolean, true)),
986                Arc::new(BooleanArray::from(vec![true])) as ArrayRef,
987            )]),
988            Fields::from(vec![Field::new("a", DataType::Boolean, true)]),
989            Err(
990                "Failed to align JSON array, reason: source field b does not exist in target schema"
991                    .to_string(),
992            ),
993        )
994        .test()?;
995
996        Ok(())
997    }
998
999    #[test]
1000    fn test_align_variant_to_struct() -> Result<()> {
1001        let encode = |json: &[u8]| jsonb::parse_value(json).unwrap().to_vec();
1002        let object =
1003            encode(br#"{"nested":{"flag":true,"items":[1,2],"raw":{"x":1},"text":42,"value":42}}"#);
1004        let scalar = encode(b"1");
1005        let variants: ArrayRef = Arc::new(BinaryArray::from(vec![
1006            Some(object.as_slice()),
1007            None,
1008            Some(scalar.as_slice()),
1009        ]));
1010        let expected_type = DataType::Struct(Fields::from(vec![Field::new_struct(
1011            "nested",
1012            vec![
1013                Field::new("flag", DataType::Boolean, true),
1014                Field::new_list("items", Field::new_list_field(DataType::UInt64, true), true),
1015                Field::new("raw", DataType::Binary, true),
1016                Field::new("text", DataType::Utf8View, true),
1017                Field::new("value", DataType::UInt64, true),
1018            ],
1019            true,
1020        )]));
1021
1022        let aligned = JsonArray::from(&variants).project_to(&expected_type)?;
1023        assert_eq!(&expected_type, aligned.data_type());
1024        assert_eq!(
1025            json!({
1026                "nested": {
1027                    "flag": true,
1028                    "items": [1, 2],
1029                    "raw": {"x": 1},
1030                    "text": "42",
1031                    "value": 42
1032                }
1033            }),
1034            JsonArray::from(&aligned).try_get_value(0)?
1035        );
1036        assert!(aligned.is_null(1));
1037        assert!(aligned.is_null(2));
1038
1039        Ok(())
1040    }
1041
1042    #[test]
1043    fn test_align_nested_variant_to_struct() -> Result<()> {
1044        let object = jsonb::parse_value(br#"{"flag":true,"value":42}"#)
1045            .unwrap()
1046            .to_vec();
1047        let variants: ArrayRef = Arc::new(BinaryArray::from(vec![Some(object.as_slice()), None]));
1048        let input: ArrayRef = Arc::new(StructArray::from(vec![(
1049            Arc::new(Field::new("nested", DataType::Binary, true)),
1050            variants,
1051        )]));
1052        let expected_type = DataType::Struct(Fields::from(vec![Field::new_struct(
1053            "nested",
1054            vec![
1055                Field::new("flag", DataType::Boolean, true),
1056                Field::new("value", DataType::UInt64, true),
1057            ],
1058            true,
1059        )]));
1060
1061        let aligned = JsonArray::from(&input).project_to(&expected_type)?;
1062        assert_eq!(&expected_type, aligned.data_type());
1063        assert_eq!(
1064            json!({"nested": {"flag": true, "value": 42}}),
1065            JsonArray::from(&aligned).try_get_value(0)?
1066        );
1067        assert_eq!(
1068            json!({"nested": null}),
1069            JsonArray::from(&aligned).try_get_value(1)?
1070        );
1071
1072        Ok(())
1073    }
1074
1075    #[test]
1076    fn test_reconstruct_json2_v2_value() -> Result<()> {
1077        let remainders = json_values_to_variant(&[
1078            Some(json!({"cold": 1, "nested": {"right": true}})),
1079            Some(json!({"!__remainder__!": "user value"})),
1080        ])?;
1081        let remainder = Arc::new(variant_field(JSON2_REMAINDER_FIELD_NAME, true));
1082        let nested = Arc::new(Field::new_struct(
1083            "nested",
1084            [Arc::new(Field::new("left", DataType::Utf8, true))],
1085            true,
1086        ));
1087        let nested_values: ArrayRef = Arc::new(StructArray::from(vec![(
1088            Arc::new(Field::new("left", DataType::Utf8, true)),
1089            Arc::new(StringArray::from(vec![Some("value"), None])) as ArrayRef,
1090        )]));
1091        let fields = Fields::from(vec![
1092            remainder,
1093            Arc::new(Field::new("count", DataType::Int64, true)),
1094            nested,
1095        ]);
1096        let array: ArrayRef = Arc::new(StructArray::new(
1097            fields.clone(),
1098            vec![
1099                remainders,
1100                Arc::new(Int64Array::from(vec![Some(42), None])),
1101                nested_values,
1102            ],
1103            None,
1104        ));
1105        let field = Field::new("data", DataType::Struct(fields), true).with_extension_type(
1106            Json2ExtensionType::new(Arc::new(JsonMetadata::new(JsonSettings::default()))),
1107        );
1108
1109        assert_eq!(
1110            json!({
1111                "cold": 1,
1112                "count": 42,
1113                "nested": {"left": "value", "right": true}
1114            }),
1115            JsonArray::from(&array).json2_values()?[0]
1116        );
1117        assert_eq!(
1118            json!({
1119                "!__remainder__!": "user value",
1120                "nested": {}
1121            }),
1122            JsonArray::from(&array).json2_values()?[1]
1123        );
1124        let target = DataType::Struct(
1125            vec![
1126                Arc::new(Field::new("cold", DataType::UInt64, true)),
1127                Arc::new(Field::new("count", DataType::Int64, true)),
1128            ]
1129            .into(),
1130        );
1131        let projected = JsonArray::from(&array).project_to_v2(&field, &target)?;
1132        assert_eq!(
1133            json!({"cold": 1, "count": 42}),
1134            JsonArray::from(&projected).try_get_value(0)?
1135        );
1136        assert_eq!(
1137            json!({"cold": null, "count": null}),
1138            JsonArray::from(&projected).try_get_value(1)?
1139        );
1140        Ok(())
1141    }
1142
1143    #[test]
1144    fn test_rewrite_to_v2_reuses_matching_layout() -> Result<()> {
1145        let settings = JsonSettings::try_new(
1146            vec![JsonTypeHint {
1147                path: vec!["kind".to_string()],
1148                data_type: ConcreteDataType::string_datatype(),
1149                nullable: true,
1150                default_constraint: None,
1151                inverted_index: false,
1152            }],
1153            Some(0),
1154        )?;
1155        let value = settings.encode(json!({"kind": "access", "cold": 1}))?;
1156        let mut builder = JsonVectorBuilder::with_settings(&settings, 1);
1157        builder.try_push_value_ref(&value.as_value_ref())?;
1158        let array = builder.to_vector().to_arrow_array();
1159        let structs = array.as_struct();
1160        assert!(structs.column_by_name("kind").is_some());
1161        assert_eq!(
1162            vec![Some(json!({"cold": 1}))],
1163            variant_to_json_values(structs.column_by_name(JSON2_REMAINDER_FIELD_NAME).unwrap())?
1164        );
1165        let field = Field::new("data", array.data_type().clone(), true).with_extension_type(
1166            Json2ExtensionType::new(Arc::new(JsonMetadata::new(settings.clone()))),
1167        );
1168
1169        let rewritten = JsonArray::from(&array).rewrite_to_v2(&field, &settings, &settings)?;
1170
1171        assert!(Arc::ptr_eq(&array, &rewritten));
1172        Ok(())
1173    }
1174
1175    #[test]
1176    fn test_project_partial_json2_v2_without_remainder() -> Result<()> {
1177        let fields = Fields::from(vec![Arc::new(Field::new("hot", DataType::Int64, true))]);
1178        let array: ArrayRef = Arc::new(StructArray::new(
1179            fields.clone(),
1180            vec![Arc::new(Int64Array::from(vec![1, 2]))],
1181            None,
1182        ));
1183        let field = Field::new("data", DataType::Struct(fields), true).with_extension_type(
1184            Json2ExtensionType::new(Arc::new(JsonMetadata::new(JsonSettings::default()))),
1185        );
1186
1187        let projected = JsonArray::from(&array).project_to_v2(&field, field.data_type())?;
1188        assert!(Arc::ptr_eq(&array, &projected));
1189        Ok(())
1190    }
1191
1192    #[test]
1193    fn test_reject_conflict_json2_v2_path() -> Result<()> {
1194        let remainders = json_values_to_variant(&[Some(json!({"count": 1}))])?;
1195        let fields = Fields::from(vec![
1196            Arc::new(variant_field(JSON2_REMAINDER_FIELD_NAME, true)),
1197            Arc::new(Field::new("count", DataType::Int64, true)),
1198        ]);
1199        let array: ArrayRef = Arc::new(StructArray::new(
1200            fields,
1201            vec![remainders, Arc::new(Int64Array::from(vec![2]))],
1202            None,
1203        ));
1204        let error = JsonArray::from(&array).json2_values().unwrap_err();
1205        assert!(
1206            error.to_string().contains(
1207                "cannot merge 'count' in explicit fields and remainder: not both objects"
1208            )
1209        );
1210
1211        let Value::Object(mut remainder) = json!({"count": 1}) else {
1212            unreachable!();
1213        };
1214        let error = merge_explicit_value(
1215            &mut remainder,
1216            "count".to_string(),
1217            json!(1),
1218            &mut Vec::new(),
1219        )
1220        .unwrap_err();
1221        assert!(error.to_string().contains("cannot merge 'count'"));
1222
1223        let Value::Object(mut remainder) = json!({"nested": {"count": 1}}) else {
1224            unreachable!();
1225        };
1226        let error = merge_explicit_value(
1227            &mut remainder,
1228            "nested".to_string(),
1229            json!({"count": 2}),
1230            &mut Vec::new(),
1231        )
1232        .unwrap_err();
1233        assert!(error.to_string().contains("cannot merge 'nested.count'"));
1234        Ok(())
1235    }
1236}