1use std::borrow::Borrow;
5
6use arrow_array::{
7 Array, LargeBinaryArray,
8 builder::{ArrayBuilder, LargeBinaryBuilder},
9};
10use postcard::{from_bytes, to_allocvec};
11
12use crate::{
13 Result,
14 util::{bitmap, kernel},
15 value::{Value, container::varlen_array, value_type::ValueType},
16};
17
18fn encode(value: &Value, row: usize) -> Vec<u8> {
19 if let Value::None {
20 ..
21 } = value
22 {
23 panic!("an Any cell can not hold a none, row {row} must be a null row");
24 }
25 to_allocvec(value).expect("postcard serialization of a Value is total")
26}
27
28fn decode(row: &[u8]) -> Value {
29 if row.is_empty() {
30 panic!("empty Any row");
31 }
32 match from_bytes(row) {
33 Ok(Value::None {
34 ..
35 }) => panic!("corrupt Any row {row:02x?}: an encoded none, a none is a null row"),
36 Ok(value) => value,
37 Err(error) => panic!("corrupt Any row {row:02x?}: {error}"),
38 }
39}
40
41pub fn any_array<B: Borrow<Value>>(values: impl IntoIterator<Item = B>) -> LargeBinaryArray {
42 let mut builder = LargeBinaryBuilder::new();
43 for (row, value) in values.into_iter().enumerate() {
44 builder.append_value(encode(value.borrow(), row));
45 }
46 builder.finish()
47}
48
49pub fn any_array_optional<B: Borrow<Value>>(values: impl IntoIterator<Item = Option<B>>) -> LargeBinaryArray {
50 let mut builder = LargeBinaryBuilder::new();
51 for (row, value) in values.into_iter().enumerate() {
52 match value {
53 Some(value) => builder.append_value(encode(value.borrow(), row)),
54 None => builder.append_null(),
55 }
56 }
57 builder.finish()
58}
59
60pub fn push_any(builder: &mut LargeBinaryBuilder, value: &Value) {
61 let row = builder.len();
62 builder.append_value(encode(value, row));
63}
64
65pub fn get(array: &LargeBinaryArray, index: usize) -> Option<Value> {
66 varlen_array::get(array, index).filter(|_| array.is_valid(index)).map(decode)
67}
68
69pub fn values(array: &LargeBinaryArray) -> Vec<Value> {
70 (0..array.len()).map(|index| get(array, index).unwrap_or_else(Value::none)).collect()
71}
72
73pub fn get_value(array: &LargeBinaryArray, declared_type: Option<&ValueType>, index: usize) -> Value {
74 match (get(array, index), declared_type) {
75 (Some(value), Some(ValueType::List(_)) | Some(ValueType::Record(_))) => value,
76 (Some(value), _) => Value::Any(Box::new(value)),
77 (None, _) => Value::none(),
78 }
79}
80
81pub fn as_string(array: &LargeBinaryArray, index: usize) -> String {
82 match get(array, index) {
83 Some(value) => format!("{}", value),
84 None => "none".to_string(),
85 }
86}
87
88pub fn reorder(array: &LargeBinaryArray, indices: &[usize]) -> Result<LargeBinaryArray> {
89 kernel::rows_in_range(indices, array.len())?;
90 let mut builder = LargeBinaryBuilder::with_capacity(indices.len(), varlen_array::compact_parts(array).0.len());
91 for &index in indices {
92 builder.append_value(array.value(index));
93 }
94 Ok(varlen_array::attach_nulls(builder.finish(), bitmap::reorder_nulls(array.logical_nulls().as_ref(), indices)))
95}
96
97pub fn equals(left: &LargeBinaryArray, right: &LargeBinaryArray) -> bool {
98 left.len() == right.len() && (0..left.len()).all(|index| get(left, index) == get(right, index))
99}
100
101#[cfg(test)]
102mod tests {
103 use ::uuid::Uuid as StdUuid;
104 use arrow_buffer::i256;
105 use postcard::to_allocvec;
106
107 use super::*;
108 use crate::value::{
109 blob::Blob,
110 date::Date,
111 datetime::DateTime,
112 decimal::Decimal,
113 dictionary::DictionaryEntryId,
114 digest::Digest,
115 duration::Duration,
116 identity::IdentityId,
117 ordered_f32::OrderedF32,
118 ordered_f64::OrderedF64,
119 time::Time,
120 uuid::{Uuid4, Uuid7},
121 };
122
123 fn digest() -> Digest {
124 let mut digest = Digest::new(ValueType::Float8, 10_000).unwrap();
125 for value in [1.0, 2.5, -4.0] {
126 digest.add_value(&Value::float8(value)).unwrap();
127 }
128 digest
129 }
130
131 fn every_variant() -> Vec<Value> {
132 vec![
133 Value::Boolean(true),
134 Value::Float4(OrderedF32::try_from(1.5f32).unwrap()),
135 Value::Float8(OrderedF64::try_from(-0.0f64).unwrap()),
136 Value::Int1(-8),
137 Value::Int2(-1_600),
138 Value::Int4(-320_000),
139 Value::Int8(-64_000_000_000),
140 Value::Int16(i128::MIN),
141 Value::Utf8("state".to_string()),
142 Value::Uint1(8),
143 Value::Uint2(1_600),
144 Value::Uint4(320_000),
145 Value::Uint8(64_000_000_000),
146 Value::Uint16(u128::MAX),
147 Value::Date(Date::new(2026, 7, 20).unwrap()),
148 Value::DateTime(DateTime::new(2026, 7, 20, 12, 34, 56, 789).unwrap()),
149 Value::Time(Time::new(23, 59, 59, 1).unwrap()),
150 Value::Duration(Duration::new(1, 2, 3).unwrap()),
151 Value::IdentityId(IdentityId(Uuid7(StdUuid::from_bytes([
152 0x01, 0x8F, 0x2A, 0x3B, 0x4C, 0x5D, 0x70, 0x07, 0x80, 0x07, 0x00, 0x00, 0x00, 0x00,
153 0x00, 0x07,
154 ])))),
155 Value::Uuid4(Uuid4(StdUuid::from_u128(4))),
156 Value::Uuid7(Uuid7(StdUuid::from_u128(77))),
157 Value::Blob(Blob::new(vec![1, 2, 3])),
158 Value::Decimal(Decimal::from_parts(i256::from_i128(150), 2).unwrap()),
159 Value::Any(Box::new(Value::Boolean(false))),
160 Value::DictionaryId(DictionaryEntryId::U16(u128::MAX)),
161 Value::Type(ValueType::Record(vec![("k".to_string(), ValueType::Int4)])),
162 Value::List(vec![Value::Int4(1), Value::none_of(ValueType::Int4)]),
163 Value::Record(vec![("k".to_string(), Value::Int8(9))]),
164 Value::Tuple(vec![Value::Boolean(true), Value::none()]),
165 Value::Digest(Box::new(digest())),
166 ]
167 }
168
169 #[test]
170 fn every_value_variant_comes_back_from_its_row_exactly() {
171 let cells = every_variant();
173 let array = any_array(&cells);
174 assert!(array.logical_nulls().is_none());
175 for (index, value) in cells.iter().enumerate() {
176 let back = get(&array, index).unwrap();
177 assert_eq!(&back, value);
178 assert_eq!(to_allocvec(&back).unwrap(), to_allocvec(value).unwrap(), "row {index}");
179 }
180 }
181
182 #[test]
183 fn get_value_wraps_rows_unless_the_column_is_a_list_or_a_record() {
184 let list = Value::List(vec![Value::Int4(1)]);
186 let array = any_array([list.clone()]);
187 assert_eq!(get_value(&array, None, 0), Value::Any(Box::new(list.clone())));
188 assert_eq!(get_value(&array, Some(&ValueType::Any), 0), Value::Any(Box::new(list.clone())));
189 assert_eq!(get_value(&array, Some(&ValueType::List(Box::new(ValueType::Int4))), 0), list);
190 let record = Value::Record(vec![("a".to_string(), Value::Int4(1))]);
191 let record_type = ValueType::Record(vec![("a".to_string(), ValueType::Int4)]);
192 assert_eq!(get_value(&any_array([record.clone()]), Some(&record_type), 0), record);
193 assert_eq!(get_value(&array, None, 1), Value::none());
194 }
195
196 #[test]
197 fn a_wrapped_row_stays_wrapped() {
198 let wrapped = Value::Any(Box::new(Value::Int4(3)));
200 let array = any_array([wrapped.clone()]);
201 assert_eq!(get(&array, 0), Some(wrapped.clone()));
202 assert_eq!(get_value(&array, None, 0), Value::Any(Box::new(wrapped)));
203 }
204
205 #[test]
206 fn reorder_with_an_out_of_range_row_fails() {
207 let error = reorder(&any_array([Value::Int4(1)]), &[3, 0]).unwrap_err();
209 assert_eq!(error.diagnostic().message, "row index 3 out of range for a column of 1 rows");
210 }
211
212 #[test]
213 fn any_columns_are_equal_by_value_not_by_row_bytes() {
214 let one_and_a_half = |mantissa: i128, scale: u8| {
216 Value::Decimal(Decimal::from_parts(i256::from_i128(mantissa), scale).unwrap())
217 };
218 assert!(equals(&any_array([one_and_a_half(15, 1)]), &any_array([one_and_a_half(150, 2)])));
219 assert!(!equals(&any_array([Value::Int4(1)]), &any_array([Value::Int4(2)])));
220 assert!(!equals(&any_array([Value::Int4(1)]), &any_array([Value::Int4(1), Value::Int4(1)])));
221 }
222
223 #[test]
224 #[should_panic(expected = "empty Any row")]
225 fn an_empty_any_row_panics_naming_the_type() {
226 get(&LargeBinaryArray::from_iter_values([b"".as_slice()]), 0);
229 }
230}