1use std::sync::Arc;
5
6use arrow_array::{
7 ArrayRef, BooleanArray, Float32Array, Float64Array, Int8Array, Int16Array, Int32Array, Int64Array,
8 LargeStringArray, UInt8Array, UInt16Array, UInt32Array, UInt64Array, builder::LargeBinaryBuilder,
9};
10use arrow_buffer::BooleanBuffer;
11use arrow_schema::FieldRef;
12use reifydb_value::{
13 fragment::Fragment,
14 util::hex::decode,
15 value::{
16 Value,
17 blob::Blob,
18 constraint::{precision::Precision, scale::Scale},
19 container::{
20 any_array::any_array_optional,
21 decimal_array::decimal_array,
22 digest_array::push_digest,
23 temporal_array::{date_array, datetime_array, duration_array, time_array},
24 uuid_array::{identity_id_array, uuid4_array, uuid7_array},
25 varlen_array::blob_array,
26 wide_int_array::wide_array,
27 },
28 date::Date,
29 datetime::DateTime,
30 decimal::{Decimal, parse::parse_decimal},
31 diff_type::DiffType,
32 digest::Digest,
33 duration::Duration,
34 enum_variant::EnumVariant,
35 frame::frame::Frame,
36 identity::IdentityId,
37 ordered_f32::OrderedF32,
38 ordered_f64::OrderedF64,
39 temporal::parse::{
40 date::parse_date, datetime::parse_datetime, duration::parse_duration, time::parse_time,
41 },
42 time::Time,
43 uuid::{
44 Uuid4, Uuid7,
45 parse::{parse_uuid4, parse_uuid7},
46 },
47 value_type::ValueType,
48 },
49};
50use serde::de::Error as _;
51use serde_json::{Error, Value as JsonValue, from_str, from_value};
52
53use crate::{
54 error::DecodeError,
55 frame::decode::{decoded_column, frame_batch},
56 json::{excerpt, none_marker_depth, types::ResponseFrame},
57 tag::peel_options,
58 unscaled::decimal_unscaled,
59};
60
61pub fn frames_from_json(json: &str) -> Result<Vec<Frame>, Error> {
62 let response_frames: Vec<ResponseFrame> = from_str(json)?;
63 frames_from_response(response_frames)
64}
65
66pub fn frames_from_envelope(body: JsonValue) -> Result<Vec<Frame>, Error> {
67 let mut envelope = match body {
68 JsonValue::Object(envelope) => envelope,
69 other => {
70 return Err(Error::custom(format!(
71 "frames envelope is not an object: {}",
72 excerpt(&other.to_string())
73 )));
74 }
75 };
76 let frames = envelope.remove("frames").ok_or_else(|| Error::custom("frames envelope has no `frames` key"))?;
77 frames_from_response(from_value(frames)?)
78}
79
80fn frames_from_response(response_frames: Vec<ResponseFrame>) -> Result<Vec<Frame>, Error> {
81 response_frames.into_iter().map(response_frame_to_frame).collect::<Result<_, _>>().map_err(Error::custom)
82}
83
84fn response_frame_to_frame(frame: ResponseFrame) -> Result<Frame, DecodeError> {
85 for (key, present) in [
86 ("row_numbers", !frame.row_numbers.is_empty()),
87 ("created_at", !frame.created_at.is_empty()),
88 ("updated_at", !frame.updated_at.is_empty()),
89 ("time", !frame.time.is_empty()),
90 ] {
91 if present {
92 return Err(DecodeError::InvalidData(format!(
93 "frame key {key} is not supported, system columns travel as # columns"
94 )));
95 }
96 }
97
98 let columns = frame
99 .columns
100 .into_iter()
101 .map(|col| convert_column_to_data(&col.name, col.r#type.value_type, col.payload))
102 .collect::<Result<Vec<_>, DecodeError>>()?;
103 let row_count = columns.first().map_or(0, |(_, array)| array.len());
104
105 let op =
106 frame.op.map(|raw| {
107 DiffType::from_u8(raw)
108 .ok_or_else(|| DecodeError::InvalidData(format!("unknown frame op {raw}")))
109 })
110 .transpose()?;
111
112 Ok(Frame {
113 batch: frame_batch(columns, row_count)?,
114 op,
115 })
116}
117
118fn cell_error(column: &str, row: usize, ty: &ValueType, text: &str) -> DecodeError {
119 column_error(column, row, format!("cannot parse '{}' as {ty}", excerpt(text)))
120}
121
122fn column_error(column: &str, row: usize, reason: String) -> DecodeError {
123 DecodeError::ColumnDecodeFailed {
124 column_name: column.to_string(),
125 row_index: Some(row),
126 source: Box::new(DecodeError::InvalidData(reason)),
127 }
128}
129
130pub fn parse_value(ty: &ValueType, text: &str) -> Result<Value, DecodeError> {
131 let (base, depth) = peel_options(ty);
132 match none_marker_depth(text) {
133 Some(_) if depth == 0 => Err(DecodeError::InvalidData(format!("none marker for non-Option type {ty}"))),
134 Some(wrapped) if wrapped >= depth => Err(DecodeError::InvalidData(format!(
135 "none marker depth {wrapped} exceeds the {depth} Option layers of type {ty}"
136 ))),
137 Some(wrapped) => Ok(Value::None {
138 inner: strip_options(ty, wrapped + 1),
139 }),
140 None => parse_base(base, text)
141 .ok_or_else(|| DecodeError::InvalidData(format!("cannot parse '{text}' as {ty}"))),
142 }
143}
144
145pub fn parse_json_value(ty: &ValueType, json: &JsonValue) -> Result<Value, DecodeError> {
146 let (base, depth) = peel_options(ty);
147 if let Some(wrapped) = json.as_str().and_then(none_marker_depth) {
148 return match wrapped {
149 _ if depth == 0 => {
150 Err(DecodeError::InvalidData(format!("none marker for non-Option type {ty}")))
151 }
152 wrapped if wrapped >= depth => Err(DecodeError::InvalidData(format!(
153 "none marker depth {wrapped} exceeds the {depth} Option layers of type {ty}"
154 ))),
155 wrapped => Ok(Value::None {
156 inner: strip_options(ty, wrapped + 1),
157 }),
158 };
159 }
160 match base {
161 ValueType::List(inner) => {
162 let items = json
163 .as_array()
164 .ok_or_else(|| DecodeError::InvalidData(format!("cannot parse '{json}' as {ty}")))?;
165 let values = items
166 .iter()
167 .map(|item| parse_json_value(inner, item))
168 .collect::<Result<Vec<_>, _>>()?;
169 Ok(Value::List(values))
170 }
171 ValueType::Record(fields) => {
172 let obj = json
173 .as_object()
174 .ok_or_else(|| DecodeError::InvalidData(format!("cannot parse '{json}' as {ty}")))?;
175 let values = fields
176 .iter()
177 .map(|(name, field_ty)| {
178 let item = obj.get(name).ok_or_else(|| {
179 DecodeError::InvalidData(format!(
180 "record is missing field '{name}' for {ty}"
181 ))
182 })?;
183 Ok((name.clone(), parse_json_value(field_ty, item)?))
184 })
185 .collect::<Result<Vec<_>, DecodeError>>()?;
186 Ok(Value::Record(values))
187 }
188 _ => {
189 let text = json.as_str().ok_or_else(|| {
190 DecodeError::InvalidData(format!("expected a JSON string for {ty}, got {json}"))
191 })?;
192 parse_value(ty, text)
193 }
194 }
195}
196
197fn strip_options(ty: &ValueType, layers: u32) -> ValueType {
198 let mut inner = ty;
199 for _ in 0..layers {
200 if let ValueType::Option(next) = inner {
201 inner = next;
202 }
203 }
204 inner.clone()
205}
206
207fn parse_base(base: &ValueType, text: &str) -> Option<Value> {
208 match base {
209 ValueType::Boolean => text.parse().ok().map(Value::Boolean),
210 ValueType::Float4 => parse_float4(text).map(Value::Float4),
211 ValueType::Float8 => parse_float8(text).map(Value::Float8),
212 ValueType::Int1 => text.parse().ok().map(Value::Int1),
213 ValueType::Int2 => text.parse().ok().map(Value::Int2),
214 ValueType::Int4 => text.parse().ok().map(Value::Int4),
215 ValueType::Int8 => text.parse().ok().map(Value::Int8),
216 ValueType::Int16 => text.parse().ok().map(Value::Int16),
217 ValueType::Utf8 => Some(Value::Utf8(text.to_string())),
218 ValueType::Enum(name) => Some(Value::Enum(EnumVariant::new(name.clone(), text))),
219 ValueType::Uint1 => text.parse().ok().map(Value::Uint1),
220 ValueType::Uint2 => text.parse().ok().map(Value::Uint2),
221 ValueType::Uint4 => text.parse().ok().map(Value::Uint4),
222 ValueType::Uint8 => text.parse().ok().map(Value::Uint8),
223 ValueType::Uint16 => text.parse().ok().map(Value::Uint16),
224 ValueType::Date => parse_date_text(text).map(Value::Date),
225 ValueType::DateTime => parse_datetime_text(text).map(Value::DateTime),
226 ValueType::Time => parse_time_text(text).map(Value::Time),
227 ValueType::Duration => parse_duration_text(text).map(Value::Duration),
228 ValueType::Uuid4 => parse_uuid4_text(text).map(Value::Uuid4),
229 ValueType::Uuid7 => parse_uuid7_text(text).map(Value::Uuid7),
230 ValueType::IdentityId => parse_identity_id(text).map(Value::IdentityId),
231 ValueType::Blob => parse_blob(text).map(Value::Blob),
232 ValueType::Decimal {
233 precision,
234 scale,
235 } => parse_decimal_text(text, *precision, *scale).map(Value::Decimal),
236 ValueType::Option(inner) => parse_base(inner, text),
237 ValueType::Digest {
238 inner,
239 accuracy,
240 } => parse_digest_text(inner, *accuracy, text).map(|digest| Value::Digest(Box::new(digest))),
241 ValueType::Any
242 | ValueType::DictionaryId
243 | ValueType::List(_)
244 | ValueType::Record(_)
245 | ValueType::Tuple(_) => Some(Value::Utf8(text.to_string())),
246 }
247}
248
249fn parse_float4(text: &str) -> Option<OrderedF32> {
250 OrderedF32::try_from(text.parse::<f32>().ok()?).ok()
251}
252
253fn parse_float8(text: &str) -> Option<OrderedF64> {
254 OrderedF64::try_from(text.parse::<f64>().ok()?).ok()
255}
256
257fn parse_date_text(text: &str) -> Option<Date> {
258 parse_date(Fragment::internal(text)).ok()
259}
260
261fn parse_datetime_text(text: &str) -> Option<DateTime> {
262 parse_datetime(Fragment::internal(text))
263 .ok()
264 .or_else(|| DateTime::from_epoch_secs(text.parse::<i64>().ok()?).ok())
265}
266
267fn parse_time_text(text: &str) -> Option<Time> {
268 parse_time(Fragment::internal(text)).ok()
269}
270
271fn parse_duration_text(text: &str) -> Option<Duration> {
272 parse_duration(Fragment::internal(text)).ok()
273}
274
275fn parse_uuid4_text(text: &str) -> Option<Uuid4> {
276 parse_uuid4(Fragment::internal(text)).ok()
277}
278
279fn parse_uuid7_text(text: &str) -> Option<Uuid7> {
280 parse_uuid7(Fragment::internal(text)).ok()
281}
282
283fn parse_identity_id(text: &str) -> Option<IdentityId> {
284 parse_uuid7_text(text).map(IdentityId::from)
285}
286
287fn parse_blob(text: &str) -> Option<Blob> {
288 Blob::from_hex(Fragment::internal(text)).ok()
289}
290
291fn parse_digest_text(inner: &ValueType, accuracy: u32, text: &str) -> Option<Digest> {
292 let bytes = decode(text.strip_prefix("0x")?).ok()?;
293 let digest = Digest::decode(&bytes).ok()?;
294 (*digest.inner() == *inner && digest.accuracy() == accuracy).then_some(digest)
295}
296
297fn parse_decimal_text(text: &str, precision: Precision, scale: Scale) -> Option<Decimal> {
298 let value = parse_decimal(Fragment::internal(text)).ok()?;
299 let unscaled = decimal_unscaled(&value, precision, scale)?;
300 Decimal::from_parts(unscaled, scale.value())
301}
302
303fn cells<T: Clone>(
304 name: &str,
305 ty: &ValueType,
306 rows: Vec<Option<String>>,
307 filler: T,
308 parse: impl Fn(&str) -> Option<T>,
309) -> Result<Vec<T>, DecodeError> {
310 rows.into_iter()
311 .enumerate()
312 .map(|(row, cell)| match cell {
313 None => Ok(filler.clone()),
314 Some(text) => parse(&text).ok_or_else(|| cell_error(name, row, ty, &text)),
315 })
316 .collect()
317}
318
319pub fn convert_column_to_data(
320 name: &str,
321 target: ValueType,
322 data: Vec<JsonValue>,
323) -> Result<(FieldRef, ArrayRef), DecodeError> {
324 let (base, depth) = peel_options(&target);
325 if depth > 1 {
326 return Err(DecodeError::ColumnDecodeFailed {
327 column_name: name.to_string(),
328 row_index: None,
329 source: Box::new(DecodeError::InvalidData(format!(
330 "type {target} has {depth} option layers, but a column holds at most one"
331 ))),
332 });
333 }
334 if matches!(base, ValueType::List(_) | ValueType::Record(_)) {
335 return convert_list_or_record_column(name, &target, base, depth, data);
336 }
337 let data: Vec<String> = data
338 .into_iter()
339 .enumerate()
340 .map(|(row, payload)| match payload {
341 JsonValue::String(text) => Ok(text),
342 other => Err(column_error(
343 name,
344 row,
345 format!("expected a JSON string for {target}, got {other}"),
346 )),
347 })
348 .collect::<Result<_, _>>()?;
349 let mut layers = vec![vec![true; data.len()]; depth as usize];
350 let mut rows = Vec::with_capacity(data.len());
351 for (row, payload) in data.into_iter().enumerate() {
352 match none_marker_depth(&payload) {
353 None => rows.push(Some(payload)),
354 Some(wrapped) if wrapped < depth => {
355 for layer in &mut layers[wrapped as usize..] {
356 layer[row] = false;
357 }
358 rows.push(None);
359 }
360 Some(0) if matches!(base, ValueType::Digest { .. }) => rows.push(None),
361 Some(_) if depth == 0 => {
362 return Err(column_error(
363 name,
364 row,
365 format!("none marker for non-Option type {target}"),
366 ));
367 }
368 Some(wrapped) => {
369 return Err(column_error(
370 name,
371 row,
372 format!(
373 "none marker depth {wrapped} exceeds the {depth} Option layers of type {target}"
374 ),
375 ));
376 }
377 }
378 }
379 let (value_type, array) = base_column(name, base, rows)?;
380 column(name, value_type, array, layers)
381}
382
383fn column(
384 name: &str,
385 value_type: ValueType,
386 array: ArrayRef,
387 layers: Vec<Vec<bool>>,
388) -> Result<(FieldRef, ArrayRef), DecodeError> {
389 decoded_column(name, value_type, array, layers.into_iter().next().map(BooleanBuffer::from), None).map_err(
390 |error| DecodeError::ColumnDecodeFailed {
391 column_name: name.to_string(),
392 row_index: None,
393 source: Box::new(error),
394 },
395 )
396}
397
398fn convert_list_or_record_column(
399 name: &str,
400 target: &ValueType,
401 base: &ValueType,
402 depth: u32,
403 data: Vec<JsonValue>,
404) -> Result<(FieldRef, ArrayRef), DecodeError> {
405 let mut layers = vec![vec![true; data.len()]; depth as usize];
406 let mut values = Vec::with_capacity(data.len());
407 for (row, payload) in data.into_iter().enumerate() {
408 match payload.as_str().and_then(none_marker_depth) {
409 None => {
410 let value = parse_json_value(base, &payload)
411 .map_err(|e| column_error(name, row, e.to_string()))?;
412 if let Value::None {
413 ..
414 } = value
415 {
416 return Err(column_error(
417 name,
418 row,
419 format!("none for non-Option type {target}"),
420 ));
421 }
422 values.push(Some(value));
423 }
424 Some(wrapped) if wrapped < depth => {
425 for layer in &mut layers[wrapped as usize..] {
426 layer[row] = false;
427 }
428 values.push(None);
429 }
430 Some(_) if depth == 0 => {
431 return Err(column_error(
432 name,
433 row,
434 format!("none marker for non-Option type {target}"),
435 ));
436 }
437 Some(wrapped) => {
438 return Err(column_error(
439 name,
440 row,
441 format!(
442 "none marker depth {wrapped} exceeds the {depth} Option layers of type {target}"
443 ),
444 ));
445 }
446 }
447 }
448 column(name, base.clone(), Arc::new(any_array_optional(values)), layers)
449}
450
451fn base_column(name: &str, base: &ValueType, rows: Vec<Option<String>>) -> Result<(ValueType, ArrayRef), DecodeError> {
452 let array: ArrayRef = match base {
453 ValueType::Option(inner) => return base_column(name, inner, rows),
454 ValueType::Boolean => Arc::new(BooleanArray::from(cells(name, base, rows, false, |s| s.parse().ok())?)),
455 ValueType::Float4 => Arc::new(Float32Array::from(cells(name, base, rows, 0.0f32, |s| {
456 s.parse().ok().map(OrderedF32::canonical)
457 })?)),
458 ValueType::Float8 => Arc::new(Float64Array::from(cells(name, base, rows, 0.0f64, |s| {
459 s.parse().ok().map(OrderedF64::canonical)
460 })?)),
461 ValueType::Int1 => Arc::new(Int8Array::from(cells(name, base, rows, 0i8, |s| s.parse().ok())?)),
462 ValueType::Int2 => Arc::new(Int16Array::from(cells(name, base, rows, 0i16, |s| s.parse().ok())?)),
463 ValueType::Int4 => Arc::new(Int32Array::from(cells(name, base, rows, 0i32, |s| s.parse().ok())?)),
464 ValueType::Int8 => Arc::new(Int64Array::from(cells(name, base, rows, 0i64, |s| s.parse().ok())?)),
465 ValueType::Int16 => Arc::new(wide_array(cells(name, base, rows, 0i128, |s| s.parse().ok())?)),
466 ValueType::Uint1 => Arc::new(UInt8Array::from(cells(name, base, rows, 0u8, |s| s.parse().ok())?)),
467 ValueType::Uint2 => Arc::new(UInt16Array::from(cells(name, base, rows, 0u16, |s| s.parse().ok())?)),
468 ValueType::Uint4 => Arc::new(UInt32Array::from(cells(name, base, rows, 0u32, |s| s.parse().ok())?)),
469 ValueType::Uint8 => Arc::new(UInt64Array::from(cells(name, base, rows, 0u64, |s| s.parse().ok())?)),
470 ValueType::Uint16 => Arc::new(wide_array(cells(name, base, rows, 0u128, |s| s.parse().ok())?)),
471 ValueType::Date => Arc::new(date_array(cells(
472 name,
473 base,
474 rows,
475 Date::from_ymd(1970, 1, 1).unwrap(),
476 parse_date_text,
477 )?)),
478 ValueType::DateTime => Arc::new(datetime_array(cells(
479 name,
480 base,
481 rows,
482 DateTime::from_epoch_secs(0).unwrap(),
483 parse_datetime_text,
484 )?)),
485 ValueType::Time => Arc::new(time_array(cells(
486 name,
487 base,
488 rows,
489 Time::from_hms(0, 0, 0).unwrap(),
490 parse_time_text,
491 )?)),
492 ValueType::Duration => {
493 Arc::new(duration_array(cells(name, base, rows, Duration::zero(), parse_duration_text)?))
494 }
495 ValueType::Uuid4 => Arc::new(uuid4_array(cells(
496 name,
497 base,
498 rows,
499 parse_uuid4_text("00000000-0000-4000-8000-000000000000").unwrap(),
500 parse_uuid4_text,
501 )?)),
502 ValueType::Uuid7 => Arc::new(uuid7_array(cells(
503 name,
504 base,
505 rows,
506 parse_uuid7_text("00000000-0000-7000-8000-000000000000").unwrap(),
507 parse_uuid7_text,
508 )?)),
509 ValueType::IdentityId => Arc::new(identity_id_array(cells(
510 name,
511 base,
512 rows,
513 parse_identity_id("00000000-0000-7000-8000-000000000000").unwrap(),
514 parse_identity_id,
515 )?)),
516 ValueType::Blob => Arc::new(blob_array(&cells(name, base, rows, Blob::new(vec![]), parse_blob)?)),
517 ValueType::Decimal {
518 precision,
519 scale,
520 } => decimal_array(
521 *precision,
522 *scale,
523 cells(name, base, rows, Decimal::zero(), |text| parse_decimal_text(text, *precision, *scale))?,
524 )
525 .into_array(),
526 ValueType::Digest {
527 inner,
528 accuracy,
529 } => {
530 let mut builder = LargeBinaryBuilder::with_capacity(rows.len(), 0);
531 for (row, cell) in rows.into_iter().enumerate() {
532 match cell {
533 None => builder.append_null(),
534 Some(text) => {
535 let digest = parse_digest_text(inner, *accuracy, &text)
536 .ok_or_else(|| cell_error(name, row, base, &text))?;
537 push_digest(&mut builder, &digest);
538 }
539 }
540 }
541 Arc::new(builder.finish())
542 }
543 ValueType::Utf8
544 | ValueType::Any
545 | ValueType::DictionaryId
546 | ValueType::List(_)
547 | ValueType::Record(_)
548 | ValueType::Tuple(_) => {
549 let strings = cells(name, base, rows, String::new(), |s| Some(s.to_string()))?;
550 return Ok((ValueType::Utf8, Arc::new(LargeStringArray::from(strings))));
551 }
552 ValueType::Enum(_) => {
553 let strings = cells(name, base, rows, String::new(), |s| Some(s.to_string()))?;
554 Arc::new(LargeStringArray::from(strings))
555 }
556 };
557 Ok((base.clone(), array))
558}