1use std::str::FromStr;
16use std::sync::LazyLock;
17
18use base64::Engine;
19use itertools::Itertools;
20use num_bigint::BigInt;
21use risingwave_common::array::{Finite32, ListValue, StructValue};
22use risingwave_common::cast::{i64_to_timestamp, i64_to_timestamptz, str_to_bytea};
23use risingwave_common::log::LogSuppressor;
24use risingwave_common::types::{
25 DEBEZIUM_UNAVAILABLE_VALUE, DataType, Date, Decimal, Int256, Interval, JsonbVal, ScalarImpl,
26 Time, Timestamp, Timestamptz, ToOwnedDatum, VectorVal, debezium_unavailable_vector,
27};
28use risingwave_connector_codec::decoder::utils::scaled_bigint_to_rust_decimal;
29use simd_json::base::ValueAsObject;
30use simd_json::prelude::{
31 TypedValue, ValueAsArray, ValueAsScalar, ValueObjectAccess, ValueTryAsScalar,
32};
33use simd_json::{BorrowedValue, ValueType};
34use thiserror_ext::AsReport;
35
36use super::{Access, AccessError, AccessResult};
37use crate::parser::DatumCow;
38use crate::schema::{InvalidOptionError, bail_invalid_option_error};
39
40fn try_parse_debezium_geometry_as_bytea(
58 value: &BorrowedValue<'_>,
59 create_error: impl Fn() -> AccessError,
60) -> AccessResult<Option<Box<[u8]>>> {
61 let obj = match value.as_object() {
62 Some(obj) => obj,
63 None => return Ok(None),
64 };
65
66 let srid = obj.get("srid").and_then(|v| v.as_i64());
69 let wkb = obj.get("wkb").and_then(|v| v.as_str());
70
71 let (Some(_srid), Some(wkb)) = (srid, wkb) else {
72 return Ok(None);
73 };
74
75 let bytes = base64::engine::general_purpose::STANDARD
76 .decode(wkb)
77 .map_err(|_| create_error())?
78 .into_boxed_slice();
79
80 Ok(Some(bytes))
81}
82
83#[derive(Clone, Debug)]
84pub enum ByteaHandling {
85 Standard,
86 Base64,
88}
89#[derive(Clone, Debug)]
90pub enum TimeHandling {
91 Milli,
92 Micro,
93}
94
95#[derive(Clone, Copy, Debug)]
96pub enum BigintUnsignedHandlingMode {
97 Long,
99 Precise,
101}
102
103#[derive(Clone, Debug)]
104pub enum TimestamptzHandling {
105 UtcString,
107 UtcWithoutSuffix,
109 Milli,
111 Micro,
113 GuessNumberUnit,
119}
120
121impl TimestamptzHandling {
122 pub const OPTION_KEY: &'static str = "timestamptz.handling.mode";
123
124 pub fn from_options(value: &str) -> Result<Self, InvalidOptionError> {
125 let mode = match value {
126 "utc_string" => Self::UtcString,
127 "utc_without_suffix" => Self::UtcWithoutSuffix,
128 "micro" => Self::Micro,
129 "milli" => Self::Milli,
130 "guess_number_unit" => Self::GuessNumberUnit,
131 v => bail_invalid_option_error!("unrecognized {} value {}", Self::OPTION_KEY, v),
132 };
133 Ok(mode)
134 }
135}
136
137#[derive(Clone, Debug)]
138pub enum TimestampHandling {
139 Milli,
140 Micro,
141 GuessNumberUnit,
142}
143
144#[derive(Clone, Debug)]
145pub enum JsonValueHandling {
146 AsValue,
147 AsString,
148}
149#[derive(Clone, Debug)]
150pub enum NumericHandling {
151 Strict,
152 Relax {
154 string_parsing: bool,
156 },
157}
158#[derive(Clone, Debug)]
159pub enum BooleanHandling {
160 Strict,
161 Relax {
163 string_parsing: bool,
165 string_integer_parsing: bool,
167 },
168}
169
170#[derive(Clone, Debug)]
171pub enum VarcharHandling {
172 Strict,
174 OnlyPrimaryTypes,
176 AllTypes,
178}
179
180#[derive(Clone, Debug)]
181pub enum StructHandling {
182 Strict,
184 AllowJsonString,
187}
188
189#[derive(Clone, Debug)]
190pub struct JsonParseOptions {
191 pub bytea_handling: ByteaHandling,
192 pub time_handling: TimeHandling,
193 pub timestamp_handling: TimestampHandling,
194 pub timestamptz_handling: TimestamptzHandling,
195 pub json_value_handling: JsonValueHandling,
196 pub numeric_handling: NumericHandling,
197 pub boolean_handling: BooleanHandling,
198 pub varchar_handling: VarcharHandling,
199 pub struct_handling: StructHandling,
200 pub bigint_unsigned_handling: BigintUnsignedHandlingMode,
201 pub ignoring_keycase: bool,
202 pub handle_toast_columns: bool,
203}
204
205impl Default for JsonParseOptions {
206 fn default() -> Self {
207 Self::DEFAULT.clone()
208 }
209}
210
211impl JsonParseOptions {
212 pub const CANAL: JsonParseOptions = JsonParseOptions {
213 bytea_handling: ByteaHandling::Standard,
214 time_handling: TimeHandling::Micro,
215 timestamp_handling: TimestampHandling::GuessNumberUnit, timestamptz_handling: TimestamptzHandling::GuessNumberUnit, json_value_handling: JsonValueHandling::AsValue,
218 numeric_handling: NumericHandling::Relax {
219 string_parsing: true,
220 },
221 boolean_handling: BooleanHandling::Relax {
222 string_parsing: true,
223 string_integer_parsing: true,
224 },
225 varchar_handling: VarcharHandling::Strict,
226 struct_handling: StructHandling::Strict,
227 bigint_unsigned_handling: BigintUnsignedHandlingMode::Long, ignoring_keycase: true,
229 handle_toast_columns: false,
230 };
231 pub const DEFAULT: JsonParseOptions = JsonParseOptions {
232 bytea_handling: ByteaHandling::Standard,
233 time_handling: TimeHandling::Micro,
234 timestamp_handling: TimestampHandling::GuessNumberUnit, timestamptz_handling: TimestamptzHandling::GuessNumberUnit, json_value_handling: JsonValueHandling::AsValue,
237 numeric_handling: NumericHandling::Relax {
238 string_parsing: true,
239 },
240 boolean_handling: BooleanHandling::Strict,
241 varchar_handling: VarcharHandling::OnlyPrimaryTypes,
242 struct_handling: StructHandling::AllowJsonString,
243 bigint_unsigned_handling: BigintUnsignedHandlingMode::Long, ignoring_keycase: true,
245 handle_toast_columns: false,
246 };
247
248 pub fn new_for_debezium(
249 timestamptz_handling: TimestamptzHandling,
250 timestamp_handling: TimestampHandling,
251 time_handling: TimeHandling,
252 bigint_unsigned_handling: BigintUnsignedHandlingMode,
253 handle_toast_columns: bool,
254 ) -> Self {
255 Self {
256 bytea_handling: ByteaHandling::Base64,
257 time_handling,
258 timestamp_handling,
259 timestamptz_handling,
260 json_value_handling: JsonValueHandling::AsString,
261 numeric_handling: NumericHandling::Relax {
262 string_parsing: false,
263 },
264 boolean_handling: BooleanHandling::Relax {
265 string_parsing: false,
266 string_integer_parsing: false,
267 },
268 varchar_handling: VarcharHandling::Strict,
269 struct_handling: StructHandling::Strict,
270 bigint_unsigned_handling,
271 ignoring_keycase: true,
272 handle_toast_columns,
273 }
274 }
275
276 pub fn parse<'a>(
277 &self,
278 value: &'a BorrowedValue<'a>,
279 type_expected: &DataType,
280 ) -> AccessResult<DatumCow<'a>> {
281 let create_error = || AccessError::TypeError {
282 expected: format!("{:?}", type_expected),
283 got: value.value_type().to_string(),
284 value: value.to_string(),
285 };
286 let v: ScalarImpl = match (type_expected, value.value_type()) {
287 (_, ValueType::Null) => return Ok(DatumCow::NULL),
288 (DataType::Boolean, ValueType::Bool) => value.as_bool().unwrap().into(),
290
291 (
292 DataType::Boolean,
293 ValueType::I64 | ValueType::I128 | ValueType::U64 | ValueType::U128,
294 ) if matches!(self.boolean_handling, BooleanHandling::Relax { .. })
295 && matches!(value.as_i64(), Some(0i64) | Some(1i64)) =>
296 {
297 (value.as_i64() == Some(1i64)).into()
298 }
299
300 (DataType::Boolean, ValueType::String)
301 if matches!(
302 self.boolean_handling,
303 BooleanHandling::Relax {
304 string_parsing: true,
305 ..
306 }
307 ) =>
308 {
309 match value.as_str().unwrap().to_lowercase().as_str() {
310 "true" => true.into(),
311 "false" => false.into(),
312 c @ ("1" | "0")
313 if matches!(
314 self.boolean_handling,
315 BooleanHandling::Relax {
316 string_parsing: true,
317 string_integer_parsing: true
318 }
319 ) =>
320 {
321 if c == "1" {
322 true.into()
323 } else {
324 false.into()
325 }
326 }
327 _ => Err(create_error())?,
328 }
329 }
330 (
332 DataType::Int16,
333 ValueType::I64 | ValueType::I128 | ValueType::U64 | ValueType::U128,
334 ) => value.try_as_i16().map_err(|_| create_error())?.into(),
335
336 (DataType::Int16, ValueType::String)
337 if matches!(
338 self.numeric_handling,
339 NumericHandling::Relax {
340 string_parsing: true
341 }
342 ) =>
343 {
344 value
345 .as_str()
346 .unwrap()
347 .parse::<i16>()
348 .map_err(|_| create_error())?
349 .into()
350 }
351 (
353 DataType::Int32,
354 ValueType::I64 | ValueType::I128 | ValueType::U64 | ValueType::U128,
355 ) => value.try_as_i32().map_err(|_| create_error())?.into(),
356
357 (DataType::Int32, ValueType::String)
358 if matches!(
359 self.numeric_handling,
360 NumericHandling::Relax {
361 string_parsing: true
362 }
363 ) =>
364 {
365 value
366 .as_str()
367 .unwrap()
368 .parse::<i32>()
369 .map_err(|_| create_error())?
370 .into()
371 }
372 (
374 DataType::Int64,
375 ValueType::I64 | ValueType::I128 | ValueType::U64 | ValueType::U128,
376 ) => value.try_as_i64().map_err(|_| create_error())?.into(),
377
378 (DataType::Int64, ValueType::String)
379 if matches!(
380 self.numeric_handling,
381 NumericHandling::Relax {
382 string_parsing: true
383 }
384 ) =>
385 {
386 value
387 .as_str()
388 .unwrap()
389 .parse::<i64>()
390 .map_err(|_| create_error())?
391 .into()
392 }
393 (
395 DataType::Float32,
396 ValueType::I64 | ValueType::I128 | ValueType::U64 | ValueType::U128,
397 ) if matches!(self.numeric_handling, NumericHandling::Relax { .. }) => {
398 (value.try_as_i64().map_err(|_| create_error())? as f32).into()
399 }
400 (DataType::Float32, ValueType::String)
401 if matches!(
402 self.numeric_handling,
403 NumericHandling::Relax {
404 string_parsing: true
405 }
406 ) =>
407 {
408 value
409 .as_str()
410 .unwrap()
411 .parse::<f32>()
412 .map_err(|_| create_error())?
413 .into()
414 }
415 (DataType::Float32, ValueType::F64) => {
416 value.try_as_f32().map_err(|_| create_error())?.into()
417 }
418 (
420 DataType::Float64,
421 ValueType::I64 | ValueType::I128 | ValueType::U64 | ValueType::U128,
422 ) if matches!(self.numeric_handling, NumericHandling::Relax { .. }) => {
423 (value.try_as_i64().map_err(|_| create_error())? as f64).into()
424 }
425 (DataType::Float64, ValueType::String)
426 if matches!(
427 self.numeric_handling,
428 NumericHandling::Relax {
429 string_parsing: true
430 }
431 ) =>
432 {
433 value
434 .as_str()
435 .unwrap()
436 .parse::<f64>()
437 .map_err(|_| create_error())?
438 .into()
439 }
440 (DataType::Float64, ValueType::F64) => {
441 value.try_as_f64().map_err(|_| create_error())?.into()
442 }
443 (DataType::Decimal, ValueType::I128 | ValueType::U128) => {
445 Decimal::from_str(&value.try_as_i128().map_err(|_| create_error())?.to_string())
446 .map_err(|_| create_error())?
447 .into()
448 }
449 (DataType::Decimal, ValueType::I64 | ValueType::U64) => {
450 let i64_val = value.try_as_i64().map_err(|_| create_error())?;
451 Decimal::from(i64_val).into()
452 }
453 (DataType::Decimal, ValueType::String) => {
454 let str_val = value.as_str().unwrap();
455 match str_val {
457 "NAN" => return Ok(DatumCow::Owned(Some(ScalarImpl::Decimal(Decimal::NaN)))),
458 "POSITIVE_INFINITY" => {
459 return Ok(DatumCow::Owned(Some(ScalarImpl::Decimal(
460 Decimal::PositiveInf,
461 ))));
462 }
463 "NEGATIVE_INFINITY" => {
464 return Ok(DatumCow::Owned(Some(ScalarImpl::Decimal(
465 Decimal::NegativeInf,
466 ))));
467 }
468 _ => {}
469 }
470
471 Decimal::from_str(str_val)
472 .or_else(|_err| {
473 try_base64_decode_decimal(
474 str_val,
475 self.bigint_unsigned_handling,
476 create_error,
477 )
478 })?
479 .into()
480 }
481
482 (DataType::Decimal, ValueType::F64) => {
483 Decimal::try_from(value.try_as_f64().map_err(|_| create_error())?)
484 .map_err(|_| create_error())?
485 .into()
486 }
487 (DataType::Decimal, ValueType::Object) => {
488 let scale = value
491 .get("scale")
492 .ok_or_else(create_error)?
493 .as_i32()
494 .unwrap();
495 let value = value
496 .get("value")
497 .ok_or_else(create_error)?
498 .as_str()
499 .unwrap()
500 .as_bytes();
501 let unscaled = BigInt::from_signed_bytes_be(value);
502 let decimal = scaled_bigint_to_rust_decimal(unscaled, scale as _)?;
503 ScalarImpl::Decimal(Decimal::Normalized(decimal))
504 }
505 (
507 DataType::Date,
508 ValueType::I64 | ValueType::I128 | ValueType::U64 | ValueType::U128,
509 ) => Date::with_days_since_unix_epoch(value.try_as_i32().map_err(|_| create_error())?)
510 .map_err(|_| create_error())?
511 .into(),
512 (DataType::Date, ValueType::String) => value
513 .as_str()
514 .unwrap()
515 .parse::<Date>()
516 .map_err(|_| create_error())?
517 .into(),
518 (DataType::Varchar, ValueType::String) => {
520 return Ok(DatumCow::Borrowed(Some(value.as_str().unwrap().into())));
521 }
522 (
523 DataType::Varchar,
524 ValueType::Bool
525 | ValueType::I64
526 | ValueType::I128
527 | ValueType::U64
528 | ValueType::U128
529 | ValueType::F64,
530 ) if matches!(self.varchar_handling, VarcharHandling::OnlyPrimaryTypes) => {
531 value.to_string().into()
532 }
533 (
534 DataType::Varchar,
535 ValueType::Bool
536 | ValueType::I64
537 | ValueType::I128
538 | ValueType::U64
539 | ValueType::U128
540 | ValueType::F64
541 | ValueType::Array
542 | ValueType::Object,
543 ) if matches!(self.varchar_handling, VarcharHandling::AllTypes) => {
544 value.to_string().into()
545 }
546 (DataType::Time, ValueType::String) => value
548 .as_str()
549 .unwrap()
550 .parse::<Time>()
551 .map_err(|_| create_error())?
552 .into(),
553 (
554 DataType::Time,
555 ValueType::I64 | ValueType::I128 | ValueType::U64 | ValueType::U128,
556 ) => value
557 .as_i64()
558 .map(|i| match self.time_handling {
559 TimeHandling::Milli => Time::with_milli(i as u32),
560 TimeHandling::Micro => Time::with_micro(i as u64),
561 })
562 .unwrap()
563 .map_err(|_| create_error())?
564 .into(),
565 (DataType::Timestamp, ValueType::String) => value
567 .as_str()
568 .unwrap()
569 .parse::<Timestamp>()
570 .map_err(|_| create_error())?
571 .into(),
572 (
573 DataType::Timestamp,
574 ValueType::I64 | ValueType::I128 | ValueType::U64 | ValueType::U128,
575 ) => value
576 .as_i64()
577 .map(|num| match self.timestamp_handling {
578 TimestampHandling::Milli => {
581 Timestamp::with_millis(num).map_err(|_| create_error())
582 }
583 TimestampHandling::Micro => {
584 Timestamp::with_micros(num).map_err(|_| create_error())
585 }
586 TimestampHandling::GuessNumberUnit => {
587 i64_to_timestamp(num).map_err(|_| create_error())
588 }
589 })
590 .ok_or_else(create_error)??
591 .into(),
592 (DataType::Timestamptz, ValueType::String) => match self.timestamptz_handling {
594 TimestamptzHandling::UtcWithoutSuffix => value
595 .as_str()
596 .unwrap()
597 .parse::<Timestamp>()
598 .map(|naive_utc| {
599 Timestamptz::from_micros(naive_utc.0.and_utc().timestamp_micros())
600 })
601 .map_err(|_| create_error())?
602 .into(),
603 _ => value
605 .as_str()
606 .unwrap()
607 .parse::<Timestamptz>()
608 .map_err(|_| create_error())?
609 .into(),
610 },
611 (
612 DataType::Timestamptz,
613 ValueType::I64 | ValueType::I128 | ValueType::U64 | ValueType::U128,
614 ) => value
615 .as_i64()
616 .and_then(|num| match self.timestamptz_handling {
617 TimestamptzHandling::GuessNumberUnit => i64_to_timestamptz(num).ok(),
618 TimestamptzHandling::Micro => Some(Timestamptz::from_micros(num)),
619 TimestamptzHandling::Milli => Timestamptz::from_millis(num),
620 TimestamptzHandling::UtcString | TimestamptzHandling::UtcWithoutSuffix => None,
622 })
623 .ok_or_else(create_error)?
624 .into(),
625 (DataType::Interval, ValueType::String) => value
627 .as_str()
628 .unwrap()
629 .parse::<Interval>()
630 .map_err(|_| create_error())?
631 .into(),
632 (DataType::Struct(struct_type_info), ValueType::Object) => {
634 let mut fields = Vec::with_capacity(struct_type_info.len());
637 for (field_name, field_type) in struct_type_info.iter() {
638 let field_value = json_object_get_case_insensitive(value, field_name)
639 .unwrap_or_else(|| {
640 let error = AccessError::Undefined {
641 name: field_name.to_owned(),
642 path: struct_type_info.to_string(), };
644 static LOG_SUPPRESSOR: LazyLock<LogSuppressor> = LazyLock::new(LogSuppressor::default);
646 if let Ok(suppressed_count) = LOG_SUPPRESSOR.check() {
647 tracing::warn!(error = %error.as_report(), suppressed_count, "undefined nested field, padding with `NULL`");
648 }
649 &BorrowedValue::Static(simd_json::StaticNode::Null)
650 });
651 fields.push(
652 self.parse(field_value, field_type)
653 .map(|d| d.to_owned_datum())?,
654 );
655 }
656 StructValue::new(fields).into()
657 }
658
659 (DataType::Struct(_), ValueType::String)
662 if matches!(self.struct_handling, StructHandling::AllowJsonString) =>
663 {
664 let mut value = value.as_str().unwrap().as_bytes().to_vec();
666 let value =
667 simd_json::to_borrowed_value(&mut value[..]).map_err(|_| create_error())?;
668 return self
669 .parse(&value, type_expected)
670 .map(|d| d.to_owned_datum().into());
671 }
672
673 (DataType::List(list_type), ValueType::Array) => ListValue::new({
675 let item_type = list_type.elem();
676 let array = value.as_array().unwrap();
677 let mut builder = item_type.create_array_builder(array.len());
678 for v in array {
679 let value = self.parse(v, item_type)?;
680 builder.append(value);
681 }
682 builder.finish()
683 })
684 .into(),
685 (DataType::Vector(size), ValueType::Array) => {
687 let array = value.as_array().unwrap();
688 if array.len() != *size {
689 Err(create_error())?
690 }
691 let mut elems = Vec::with_capacity(array.len());
692 for v in array {
693 let value = match v.value_type() {
694 ValueType::I64 | ValueType::I128 => {
695 let i128_value = v.try_as_i128().map_err(|_| create_error())?;
696 i128_value
697 .to_string()
698 .parse::<f32>()
699 .map_err(|_| create_error())?
700 }
701 ValueType::U64 | ValueType::U128 => {
702 let u128_value = v.try_as_u128().map_err(|_| create_error())?;
703 u128_value
704 .to_string()
705 .parse::<f32>()
706 .map_err(|_| create_error())?
707 }
708 ValueType::F64 => {
709 let f64_value = v.try_as_f64().map_err(|_| create_error())?;
710 if !f64_value.is_finite() {
711 Err(create_error())?
712 }
713 f64_value
714 .to_string()
715 .parse::<f32>()
716 .map_err(|_| create_error())?
717 }
718 _ => Err(create_error())?,
719 };
720 let finite = Finite32::try_from(value).map_err(|_| create_error())?;
721 elems.push(finite);
722 }
723 VectorVal::from(elems).into()
724 }
725 (DataType::Vector(size), ValueType::String) => {
732 let s = value.as_str().unwrap();
733 if self.handle_toast_columns
734 && s.len() == DEBEZIUM_UNAVAILABLE_VALUE.len()
735 && s == DEBEZIUM_UNAVAILABLE_VALUE
736 {
737 debezium_unavailable_vector(*size).into()
742 } else {
743 VectorVal::from_text(s, *size)
744 .map_err(|_| create_error())?
745 .into()
746 }
747 }
748
749 (DataType::Bytea, ValueType::String) => {
751 let value_str = value.as_str().unwrap();
752
753 match self.bytea_handling {
754 ByteaHandling::Standard => {
755 let mut buf = Vec::new();
756 str_to_bytea(value_str, &mut buf).map_err(|_| create_error())?;
757 buf.into()
758 }
759 ByteaHandling::Base64 => base64::engine::general_purpose::STANDARD
760 .decode(value_str)
761 .map_err(|_| create_error())?
762 .into_boxed_slice()
763 .into(),
764 }
765 }
766 (DataType::Bytea, ValueType::Object) => {
769 match try_parse_debezium_geometry_as_bytea(value, create_error)? {
770 Some(bytes) => bytes.into(),
771 None => Err(create_error())?,
772 }
773 }
774 (DataType::Jsonb, ValueType::String)
776 if matches!(self.json_value_handling, JsonValueHandling::AsString) =>
777 {
778 match self.handle_toast_columns {
782 true => JsonbVal::from_debezium_unavailable_value(value.as_str().unwrap())
783 .map_err(|_| create_error())?
784 .into(),
785 false => JsonbVal::from_str(value.as_str().unwrap())
786 .map_err(|_| create_error())?
787 .into(),
788 }
789 }
790 (DataType::Jsonb, _)
791 if matches!(self.json_value_handling, JsonValueHandling::AsValue) =>
792 {
793 let value: serde_json::Value =
794 value.clone().try_into().map_err(|_| create_error())?;
795 JsonbVal::from(value).into()
796 }
797 (
799 DataType::Int256,
800 ValueType::I64 | ValueType::I128 | ValueType::U64 | ValueType::U128,
801 ) => Int256::from(value.try_as_i64().map_err(|_| create_error())?).into(),
802
803 (DataType::Int256, ValueType::String) => Int256::from_str(value.as_str().unwrap())
804 .map_err(|_| create_error())?
805 .into(),
806
807 (_expected, _got) => Err(create_error())?,
808 };
809 Ok(DatumCow::Owned(Some(v)))
810 }
811}
812
813fn try_base64_decode_decimal(
821 str_val: &str,
822 bigint_unsigned_handling: BigintUnsignedHandlingMode,
823 create_error: impl Fn() -> AccessError,
824) -> Result<Decimal, AccessError> {
825 match bigint_unsigned_handling {
826 BigintUnsignedHandlingMode::Precise => {
827 let value = base64::engine::general_purpose::STANDARD
832 .decode(str_val)
833 .map_err(|_| create_error())?;
834 let unscaled = num_bigint::BigInt::from_signed_bytes_be(&value);
835 Decimal::from_str(&unscaled.to_string()).map_err(|_| create_error())
836 }
837 BigintUnsignedHandlingMode::Long => {
838 Err(create_error())
840 }
841 }
842}
843
844pub struct JsonAccess<'a> {
845 value: BorrowedValue<'a>,
846 options: &'a JsonParseOptions,
847}
848
849impl<'a> JsonAccess<'a> {
850 pub fn new_with_options(value: BorrowedValue<'a>, options: &'a JsonParseOptions) -> Self {
851 Self { value, options }
852 }
853
854 pub fn new(value: BorrowedValue<'a>) -> Self {
855 Self::new_with_options(value, &JsonParseOptions::DEFAULT)
856 }
857}
858
859impl Access for JsonAccess<'_> {
860 fn access<'a>(&'a self, path: &[&str], type_expected: &DataType) -> AccessResult<DatumCow<'a>> {
861 let mut value = &self.value;
862
863 for (idx, &key) in path.iter().enumerate() {
864 if let Some(sub_value) = if self.options.ignoring_keycase {
865 json_object_get_case_insensitive(value, key)
866 } else {
867 value.get(key)
868 } {
869 value = sub_value;
870 } else {
871 Err(AccessError::Undefined {
872 name: key.to_owned(),
873 path: path.iter().take(idx).join("."),
874 })?;
875 }
876 }
877
878 self.options.parse(value, type_expected)
879 }
880}
881
882fn json_object_get_case_insensitive<'b>(
886 v: &'b simd_json::BorrowedValue<'b>,
887 key: &str,
888) -> Option<&'b simd_json::BorrowedValue<'b>> {
889 let obj = v.as_object()?;
890 let value = obj.get(key);
891 if value.is_some() {
892 return value; }
894 for (k, v) in obj {
895 if k.eq_ignore_ascii_case(key) {
896 return Some(v);
897 }
898 }
899 None
900}