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