1use crate::schema::{InnerDecimalSchema, NamespaceRef, UuidSchema};
20use crate::{
21 AvroResult, Error,
22 bigdecimal::{deserialize_big_decimal, serialize_big_decimal},
23 decimal::Decimal,
24 duration::Duration,
25 error::Details,
26 schema::{
27 DecimalSchema, EnumSchema, FixedSchema, Name, Precision, RecordField, RecordSchema,
28 ResolvedSchema, Scale, Schema, SchemaKind, UnionSchema,
29 },
30};
31use bigdecimal::BigDecimal;
32use log::{debug, error};
33use serde_json::{Number, Value as JsonValue};
34use std::{
35 borrow::Borrow,
36 collections::{BTreeMap, HashMap},
37 fmt::Debug,
38 hash::BuildHasher,
39 str::FromStr,
40};
41use uuid::Uuid;
42
43fn max_prec_for_len(len: usize) -> Result<usize, Error> {
45 let len = i32::try_from(len).map_err(|e| Details::ConvertLengthToI32(e, len))?;
46 Ok((2.0_f64.powi(8 * len - 1) - 1.0).log10().floor() as usize)
47}
48
49#[derive(Clone, Debug, PartialEq, strum::EnumDiscriminants)]
54#[strum_discriminants(name(ValueKind))]
55pub enum Value {
56 Null,
58 Boolean(bool),
60 Int(i32),
62 Long(i64),
64 Float(f32),
66 Double(f64),
68 Bytes(Vec<u8>),
70 String(String),
72 Fixed(usize, Vec<u8>),
75 Enum(u32, String),
82 Union(u32, Box<Value>),
89 Array(Vec<Value>),
91 Map(HashMap<String, Value>),
93 Record(Vec<(String, Value)>),
100 Date(i32),
105 Decimal(Decimal),
107 BigDecimal(BigDecimal),
109 TimeMillis(i32),
111 TimeMicros(i64),
113 TimestampMillis(i64),
115 TimestampMicros(i64),
117 TimestampNanos(i64),
119 LocalTimestampMillis(i64),
121 LocalTimestampMicros(i64),
123 LocalTimestampNanos(i64),
125 Duration(Duration),
127 Uuid(Uuid),
129}
130
131macro_rules! to_value(
132 ($type:ty, $variant_constructor:expr) => (
133 impl From<$type> for Value {
134 fn from(value: $type) -> Self {
135 $variant_constructor(value)
136 }
137 }
138 );
139);
140
141to_value!(bool, Value::Boolean);
142to_value!(i32, Value::Int);
143to_value!(i64, Value::Long);
144to_value!(f32, Value::Float);
145to_value!(f64, Value::Double);
146to_value!(String, Value::String);
147to_value!(Vec<u8>, Value::Bytes);
148to_value!(Uuid, Value::Uuid);
149to_value!(Decimal, Value::Decimal);
150to_value!(BigDecimal, Value::BigDecimal);
151to_value!(Duration, Value::Duration);
152
153impl From<()> for Value {
154 fn from(_: ()) -> Self {
155 Self::Null
156 }
157}
158
159impl TryFrom<usize> for Value {
160 type Error = Error;
161
162 fn try_from(value: usize) -> Result<Self, Self::Error> {
163 Ok(i64::try_from(value)
164 .map_err(|e| Details::ConvertUsizeToI64(e, value))?
165 .into())
166 }
167}
168
169impl From<&str> for Value {
170 fn from(value: &str) -> Self {
171 Self::String(value.to_owned())
172 }
173}
174
175impl From<&[u8]> for Value {
176 fn from(value: &[u8]) -> Self {
177 Self::Bytes(value.to_owned())
178 }
179}
180
181impl<T> From<Option<T>> for Value
182where
183 T: Into<Self>,
184{
185 fn from(value: Option<T>) -> Self {
186 Self::Union(
188 value.is_some() as u32,
189 Box::new(value.map_or_else(|| Self::Null, Into::into)),
190 )
191 }
192}
193
194impl<K, V, S> From<HashMap<K, V, S>> for Value
195where
196 K: Into<String>,
197 V: Into<Self>,
198 S: BuildHasher,
199{
200 fn from(value: HashMap<K, V, S>) -> Self {
201 Self::Map(
202 value
203 .into_iter()
204 .map(|(key, value)| (key.into(), value.into()))
205 .collect(),
206 )
207 }
208}
209
210#[derive(Debug, Clone)]
212pub struct Record<'a> {
213 pub fields: Vec<(String, Value)>,
217 schema_lookup: &'a BTreeMap<String, usize>,
218}
219
220impl Record<'_> {
221 pub fn new(schema: &Schema) -> Option<Record<'_>> {
225 match *schema {
226 Schema::Record(RecordSchema {
227 fields: ref schema_fields,
228 lookup: ref schema_lookup,
229 ..
230 }) => {
231 let mut fields = Vec::with_capacity(schema_fields.len());
232 for schema_field in schema_fields.iter() {
233 fields.push((schema_field.name.clone(), Value::Null));
234 }
235
236 Some(Record {
237 fields,
238 schema_lookup,
239 })
240 }
241 _ => None,
242 }
243 }
244
245 pub fn put<V>(&mut self, field: &str, value: V)
250 where
251 V: Into<Value>,
252 {
253 if let Some(&position) = self.schema_lookup.get(field) {
254 self.fields[position].1 = value.into();
255 }
256 }
257
258 pub fn get(&self, field: &str) -> Option<&Value> {
262 self.schema_lookup
263 .get(field)
264 .map(|&position| &self.fields[position].1)
265 }
266}
267
268impl<'a> From<Record<'a>> for Value {
269 fn from(value: Record<'a>) -> Self {
270 Self::Record(value.fields)
271 }
272}
273
274impl TryFrom<JsonValue> for Value {
275 type Error = Error;
276
277 fn try_from(value: JsonValue) -> Result<Self, Self::Error> {
278 match value {
279 JsonValue::Null => Ok(Self::Null),
280 JsonValue::Bool(b) => Ok(b.into()),
281 JsonValue::Number(ref n) if n.is_i64() => {
282 let n = n.as_i64().unwrap();
283 if n >= i32::MIN as i64 && n <= i32::MAX as i64 {
284 Ok(Value::Int(n as i32))
285 } else {
286 Ok(Value::Long(n))
287 }
288 }
289 JsonValue::Number(ref n) if n.is_f64() => Ok(Value::Double(n.as_f64().unwrap())),
290 JsonValue::Number(n) => Err(Details::JsonNumberTooLarge(n).into()),
291 JsonValue::String(s) => Ok(s.into()),
292 JsonValue::Array(items) => {
293 let items = items
294 .into_iter()
295 .map(Value::try_from)
296 .collect::<Result<Vec<_>, _>>()?;
297 Ok(Value::Array(items))
298 }
299 JsonValue::Object(items) => {
300 let items = items
301 .into_iter()
302 .map(|(key, value)| Value::try_from(value).map(|v| (key, v)))
303 .collect::<Result<HashMap<_, _>, _>>()?;
304 Ok(Value::Map(items))
305 }
306 }
307 }
308}
309
310impl TryFrom<Value> for JsonValue {
312 type Error = crate::error::Error;
313 fn try_from(value: Value) -> AvroResult<Self> {
314 match value {
315 Value::Null => Ok(Self::Null),
316 Value::Boolean(b) => Ok(Self::Bool(b)),
317 Value::Int(i) => Ok(Self::Number(i.into())),
318 Value::Long(l) => Ok(Self::Number(l.into())),
319 Value::Float(f) => Number::from_f64(f.into())
320 .map(Self::Number)
321 .ok_or_else(|| Details::ConvertF64ToJson(f.into()).into()),
322 Value::Double(d) => Number::from_f64(d)
323 .map(Self::Number)
324 .ok_or_else(|| Details::ConvertF64ToJson(d).into()),
325 Value::Bytes(bytes) => Ok(Self::Array(bytes.into_iter().map(|b| b.into()).collect())),
326 Value::String(s) => Ok(Self::String(s)),
327 Value::Fixed(_size, items) => {
328 Ok(Self::Array(items.into_iter().map(|v| v.into()).collect()))
329 }
330 Value::Enum(_i, s) => Ok(Self::String(s)),
331 Value::Union(_i, b) => Self::try_from(*b),
332 Value::Array(items) => items
333 .into_iter()
334 .map(Self::try_from)
335 .collect::<Result<Vec<_>, _>>()
336 .map(Self::Array),
337 Value::Map(items) => items
338 .into_iter()
339 .map(|(key, value)| Self::try_from(value).map(|v| (key, v)))
340 .collect::<Result<Vec<_>, _>>()
341 .map(|v| Self::Object(v.into_iter().collect())),
342 Value::Record(items) => items
343 .into_iter()
344 .map(|(key, value)| Self::try_from(value).map(|v| (key, v)))
345 .collect::<Result<Vec<_>, _>>()
346 .map(|v| Self::Object(v.into_iter().collect())),
347 Value::Date(d) => Ok(Self::Number(d.into())),
348 Value::Decimal(ref d) => <Vec<u8>>::try_from(d)
349 .map(|vec| Self::Array(vec.into_iter().map(|v| v.into()).collect())),
350 Value::BigDecimal(ref bg) => {
351 let vec1: Vec<u8> = serialize_big_decimal(bg)?;
352 Ok(Self::Array(vec1.into_iter().map(|b| b.into()).collect()))
353 }
354 Value::TimeMillis(t) => Ok(Self::Number(t.into())),
355 Value::TimeMicros(t) => Ok(Self::Number(t.into())),
356 Value::TimestampMillis(t) => Ok(Self::Number(t.into())),
357 Value::TimestampMicros(t) => Ok(Self::Number(t.into())),
358 Value::TimestampNanos(t) => Ok(Self::Number(t.into())),
359 Value::LocalTimestampMillis(t) => Ok(Self::Number(t.into())),
360 Value::LocalTimestampMicros(t) => Ok(Self::Number(t.into())),
361 Value::LocalTimestampNanos(t) => Ok(Self::Number(t.into())),
362 Value::Duration(d) => Ok(Self::Array(
363 <[u8; 12]>::from(d).iter().map(|&v| v.into()).collect(),
364 )),
365 Value::Uuid(uuid) => Ok(Self::String(uuid.as_hyphenated().to_string())),
366 }
367 }
368}
369
370impl Value {
371 pub fn validate(&self, schema: &Schema) -> bool {
379 self.validate_schemata(&[schema])
380 }
381
382 pub fn validate_schemata(&self, schemata: &[&Schema]) -> bool {
387 let rs = ResolvedSchema::try_from(schemata.to_vec())
388 .expect("Schemata didn't successfully resolve");
389 let schemata_len = schemata.len();
390 schemata.iter().any(
391 |schema| match self.validate_internal(schema, rs.get_names(), None) {
392 Some(reason) => {
393 let log_message =
394 format!("Invalid value: {self:?} for schema: {schema:?}. Reason: {reason}");
395 if schemata_len == 1 {
396 error!("{log_message}");
397 } else {
398 debug!("{log_message}");
399 };
400 false
401 }
402 None => true,
403 },
404 )
405 }
406
407 fn accumulate(accumulator: Option<String>, other: Option<String>) -> Option<String> {
408 match (accumulator, other) {
409 (None, None) => None,
410 (None, s @ Some(_)) => s,
411 (s @ Some(_), None) => s,
412 (Some(reason1), Some(reason2)) => Some(format!("{reason1}\n{reason2}")),
413 }
414 }
415
416 pub(crate) fn validate_internal<S: Borrow<Schema> + Debug>(
418 &self,
419 schema: &Schema,
420 names: &HashMap<Name, S>,
421 enclosing_namespace: NamespaceRef,
422 ) -> Option<String> {
423 match (self, schema) {
424 (_, Schema::Ref { name }) => {
425 let name = name.fully_qualified_name(enclosing_namespace);
426 names.get(&name).map_or_else(
427 || {
428 Some(format!(
429 "Unresolved schema reference: '{:?}'. Parsed names: {:?}",
430 name,
431 names.keys()
432 ))
433 },
434 |s| self.validate_internal(s.borrow(), names, name.namespace()),
435 )
436 }
437 (&Value::Null, &Schema::Null) => None,
438 (&Value::Boolean(_), &Schema::Boolean) => None,
439 (&Value::Int(_), &Schema::Int) => None,
440 (&Value::Int(_), &Schema::Date) => None,
441 (&Value::Int(_), &Schema::TimeMillis) => None,
442 (&Value::Int(_), &Schema::Long) => None,
443 (&Value::Long(_), &Schema::Long) => None,
444 (&Value::Long(_), &Schema::TimeMicros) => None,
445 (&Value::Long(_), &Schema::TimestampMillis) => None,
446 (&Value::Long(_), &Schema::TimestampMicros) => None,
447 (&Value::Long(_), &Schema::LocalTimestampMillis) => None,
448 (&Value::Long(_), &Schema::LocalTimestampMicros) => None,
449 (&Value::TimestampMicros(_), &Schema::TimestampMicros) => None,
450 (&Value::TimestampMillis(_), &Schema::TimestampMillis) => None,
451 (&Value::TimestampNanos(_), &Schema::TimestampNanos) => None,
452 (&Value::LocalTimestampMicros(_), &Schema::LocalTimestampMicros) => None,
453 (&Value::LocalTimestampMillis(_), &Schema::LocalTimestampMillis) => None,
454 (&Value::LocalTimestampNanos(_), &Schema::LocalTimestampNanos) => None,
455 (&Value::TimeMicros(_), &Schema::TimeMicros) => None,
456 (&Value::TimeMillis(_), &Schema::TimeMillis) => None,
457 (&Value::Date(_), &Schema::Date) => None,
458 (&Value::Decimal(_), &Schema::Decimal { .. }) => None,
459 (&Value::BigDecimal(_), &Schema::BigDecimal) => None,
460 (&Value::Duration(_), &Schema::Duration(_)) => None,
461 (&Value::Uuid(_), &Schema::Uuid(_)) => None,
462 (&Value::Float(_), &Schema::Float) => None,
463 (&Value::Float(_), &Schema::Double) => None,
464 (&Value::Double(_), &Schema::Double) => None,
465 (&Value::Bytes(_), &Schema::Bytes) => None,
466 (&Value::Bytes(_), &Schema::Decimal { .. }) => None,
467 (Value::Bytes(bytes), &Schema::Uuid(UuidSchema::Bytes)) => {
468 if bytes.len() != 16 {
469 Some(format!(
470 "The value's size ({}) is not the right length for a bytes UUID (16)",
471 bytes.len()
472 ))
473 } else {
474 None
475 }
476 }
477 (&Value::String(_), &Schema::String) => None,
478 (Value::String(string), &Schema::Uuid(UuidSchema::String)) => {
479 if string.len() < 32 {
481 Some(format!(
482 "The value's size ({}) is not the right length for a string UUID (>=32)",
483 string.len()
484 ))
485 } else {
486 None
487 }
488 }
489 (&Value::Fixed(n, _), &Schema::Fixed(FixedSchema { size, .. })) => {
490 if n != size {
491 Some(format!(
492 "The value's size ({n}) is different than the schema's size ({size})"
493 ))
494 } else {
495 None
496 }
497 }
498 (Value::Bytes(b), &Schema::Fixed(FixedSchema { size, .. })) => {
499 if b.len() != size {
500 Some(format!(
501 "The bytes' length ({}) is different than the schema's size ({})",
502 b.len(),
503 size
504 ))
505 } else {
506 None
507 }
508 }
509 (&Value::Fixed(n, _), &Schema::Duration(_)) => {
510 if n != 12 {
511 Some(format!(
512 "The value's size ('{n}') must be exactly 12 to be a Duration"
513 ))
514 } else {
515 None
516 }
517 }
518 (&Value::Fixed(n, _), Schema::Uuid(UuidSchema::Fixed(size, ..))) => {
519 if size.size != 16 {
520 Some(format!(
521 "The schema's size ('{}') must be exactly 16 to be a Uuid",
522 size.size
523 ))
524 } else if n != 16 {
525 Some(format!(
526 "The value's size ('{n}') must be exactly 16 to be a Uuid"
527 ))
528 } else {
529 None
530 }
531 }
532 (&Value::Fixed(_n, _), &Schema::Decimal { .. }) => None,
534 (Value::String(s), Schema::Enum(EnumSchema { symbols, .. })) => {
535 if !symbols.contains(s) {
536 Some(format!("'{s}' is not a member of the possible symbols"))
537 } else {
538 None
539 }
540 }
541 (
542 &Value::Enum(i, ref s),
543 Schema::Enum(EnumSchema {
544 symbols, default, ..
545 }),
546 ) => symbols
547 .get(i as usize)
548 .map(|ref symbol| {
549 if symbol != &s {
550 Some(format!("Symbol '{s}' is not at position '{i}'"))
551 } else {
552 None
553 }
554 })
555 .unwrap_or_else(|| match default {
556 Some(_) => None,
557 None => Some(format!("No symbol at position '{i}'")),
558 }),
559 (&Value::Union(i, ref value), Schema::Union(inner)) => inner
561 .variants()
562 .get(i as usize)
563 .map(|schema| value.validate_internal(schema, names, enclosing_namespace))
564 .unwrap_or_else(|| Some(format!("No schema in the union at position '{i}'"))),
565 (v, Schema::Union(inner)) => {
566 match inner.find_schema_with_known_schemata(v, Some(names), enclosing_namespace) {
567 Some(_) => None,
568 None => Some("Could not find matching type in union".to_string()),
569 }
570 }
571 (Value::Array(items), Schema::Array(inner)) => items.iter().fold(None, |acc, item| {
572 Value::accumulate(
573 acc,
574 item.validate_internal(&inner.items, names, enclosing_namespace),
575 )
576 }),
577 (Value::Map(items), Schema::Map(inner)) => {
578 items.iter().fold(None, |acc, (_, value)| {
579 Value::accumulate(
580 acc,
581 value.validate_internal(&inner.types, names, enclosing_namespace),
582 )
583 })
584 }
585 (
586 Value::Record(record_fields),
587 Schema::Record(RecordSchema {
588 fields,
589 lookup,
590 name,
591 ..
592 }),
593 ) => {
594 let non_nullable_fields_count =
595 fields.iter().filter(|&rf| !rf.is_nullable()).count();
596
597 if record_fields.len() < non_nullable_fields_count {
599 return Some(format!(
600 "The value's records length ({}) doesn't match the schema ({} non-nullable fields)",
601 record_fields.len(),
602 non_nullable_fields_count
603 ));
604 } else if record_fields.len() > fields.len() {
605 return Some(format!(
606 "The value's records length ({}) is greater than the schema's ({} fields)",
607 record_fields.len(),
608 fields.len(),
609 ));
610 }
611
612 record_fields
613 .iter()
614 .fold(None, |acc, (field_name, record_field)| {
615 let record_namespace = name.namespace().or(enclosing_namespace);
616 match lookup.get(field_name) {
617 Some(idx) => {
618 let field = &fields[*idx];
619 Value::accumulate(
620 acc,
621 record_field.validate_internal(
622 &field.schema,
623 names,
624 record_namespace,
625 ),
626 )
627 }
628 None => Value::accumulate(
629 acc,
630 Some(format!("There is no schema field for field '{field_name}'")),
631 ),
632 }
633 })
634 }
635 (Value::Map(items), Schema::Record(RecordSchema { fields, .. })) => {
636 fields.iter().fold(None, |acc, field| {
637 if let Some(item) = items.get(&field.name) {
638 let res = item.validate_internal(&field.schema, names, enclosing_namespace);
639 Value::accumulate(acc, res)
640 } else if !field.is_nullable() {
641 Value::accumulate(
642 acc,
643 Some(format!(
644 "Field with name '{:?}' is not a member of the map items",
645 field.name
646 )),
647 )
648 } else {
649 acc
650 }
651 })
652 }
653 (v, s) => Some(format!(
654 "Unsupported value-schema combination! Value: {v:?}, schema: {s:?}"
655 )),
656 }
657 }
658
659 pub fn resolve(self, schema: &Schema) -> AvroResult<Self> {
666 self.resolve_schemata(schema, Vec::with_capacity(0))
667 }
668
669 pub fn resolve_schemata(self, schema: &Schema, schemata: Vec<&Schema>) -> AvroResult<Self> {
676 let enclosing_namespace = schema.namespace();
677 let rs = if schemata.is_empty() {
678 ResolvedSchema::try_from(schema)?
679 } else {
680 ResolvedSchema::try_from(schemata)?
681 };
682 self.resolve_internal(schema, rs.get_names(), enclosing_namespace, &None)
683 }
684
685 pub(crate) fn resolve_internal<S: Borrow<Schema> + Debug>(
686 mut self,
687 schema: &Schema,
688 names: &HashMap<Name, S>,
689 enclosing_namespace: NamespaceRef,
690 field_default: &Option<JsonValue>,
691 ) -> AvroResult<Self> {
692 if SchemaKind::from(&self) == SchemaKind::Union
694 && SchemaKind::from(schema) != SchemaKind::Union
695 {
696 let v = match self {
698 Value::Union(_i, b) => *b,
699 _ => unreachable!(),
700 };
701 self = v;
702 }
703 match schema {
704 Schema::Ref { name } => {
705 let name = name.fully_qualified_name(enclosing_namespace);
706
707 if let Some(resolved) = names.get(&name) {
708 debug!("Resolved {name:?}");
709 self.resolve_internal(resolved.borrow(), names, name.namespace(), field_default)
710 } else {
711 error!("Failed to resolve schema {name:?}");
712 Err(Details::SchemaResolutionError(name.into_owned()).into())
713 }
714 }
715 Schema::Null => self.resolve_null(),
716 Schema::Boolean => self.resolve_boolean(),
717 Schema::Int => self.resolve_int(),
718 Schema::Long => self.resolve_long(),
719 Schema::Float => self.resolve_float(),
720 Schema::Double => self.resolve_double(),
721 Schema::Bytes => self.resolve_bytes(),
722 Schema::String => self.resolve_string(),
723 Schema::Fixed(FixedSchema { size, .. }) => self.resolve_fixed(*size),
724 Schema::Union(inner) => {
725 self.resolve_union(inner, names, enclosing_namespace, field_default)
726 }
727 Schema::Enum(EnumSchema {
728 symbols, default, ..
729 }) => self.resolve_enum(symbols, default, field_default),
730 Schema::Array(inner) => self.resolve_array(&inner.items, names, enclosing_namespace),
731 Schema::Map(inner) => self.resolve_map(&inner.types, names, enclosing_namespace),
732 Schema::Record(RecordSchema { fields, .. }) => {
733 self.resolve_record(fields, names, enclosing_namespace)
734 }
735 Schema::Decimal(DecimalSchema {
736 scale,
737 precision,
738 inner,
739 }) => self.resolve_decimal(*precision, *scale, inner),
740 Schema::BigDecimal => self.resolve_bigdecimal(),
741 Schema::Date => self.resolve_date(),
742 Schema::TimeMillis => self.resolve_time_millis(),
743 Schema::TimeMicros => self.resolve_time_micros(),
744 Schema::TimestampMillis => self.resolve_timestamp_millis(),
745 Schema::TimestampMicros => self.resolve_timestamp_micros(),
746 Schema::TimestampNanos => self.resolve_timestamp_nanos(),
747 Schema::LocalTimestampMillis => self.resolve_local_timestamp_millis(),
748 Schema::LocalTimestampMicros => self.resolve_local_timestamp_micros(),
749 Schema::LocalTimestampNanos => self.resolve_local_timestamp_nanos(),
750 Schema::Duration(_) => self.resolve_duration(),
751 Schema::Uuid(inner) => self.resolve_uuid(inner),
752 }
753 }
754
755 fn resolve_uuid(self, inner: &UuidSchema) -> Result<Self, Error> {
756 let value = match (self, inner) {
757 (uuid @ Value::Uuid(_), _) => uuid,
758 (Value::String(ref string), UuidSchema::String) => {
759 Value::Uuid(Uuid::from_str(string).map_err(Details::ConvertStrToUuid)?)
760 }
761 (Value::Bytes(ref bytes), UuidSchema::Bytes) => {
762 Value::Uuid(Uuid::from_slice(bytes).map_err(Details::ConvertSliceToUuid)?)
763 }
764 (Value::Fixed(n, ref bytes), UuidSchema::Fixed(_)) => {
765 if n != 16 {
766 return Err(Details::ConvertFixedToUuid(n).into());
767 }
768 Value::Uuid(Uuid::from_slice(bytes).map_err(Details::ConvertSliceToUuid)?)
769 }
770 (Value::String(ref string), UuidSchema::Fixed(_)) => {
771 let bytes = string.as_bytes();
772 if bytes.len() != 16 {
773 return Err(Details::ConvertFixedToUuid(bytes.len()).into());
774 }
775 Value::Uuid(Uuid::from_slice(bytes).map_err(Details::ConvertSliceToUuid)?)
776 }
777 (other, _) => return Err(Details::GetUuid(other).into()),
778 };
779 Ok(value)
780 }
781
782 fn resolve_bigdecimal(self) -> Result<Self, Error> {
783 Ok(match self {
784 bg @ Value::BigDecimal(_) => bg,
785 Value::Bytes(b) => Value::BigDecimal(deserialize_big_decimal(&b)?),
786 other => return Err(Details::GetBigDecimal(other).into()),
787 })
788 }
789
790 fn resolve_duration(self) -> Result<Self, Error> {
791 Ok(match self {
792 duration @ Value::Duration { .. } => duration,
793 Value::Fixed(size, bytes) => {
794 if size != 12 {
795 return Err(Details::GetDurationFixedBytes(size).into());
796 }
797 Value::Duration(Duration::from([
798 bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7],
799 bytes[8], bytes[9], bytes[10], bytes[11],
800 ]))
801 }
802 other => return Err(Details::ResolveDuration(other).into()),
803 })
804 }
805
806 fn resolve_decimal(
807 self,
808 precision: Precision,
809 scale: Scale,
810 inner: &InnerDecimalSchema,
811 ) -> Result<Self, Error> {
812 if scale > precision {
813 return Err(Details::GetScaleAndPrecision { scale, precision }.into());
814 }
815 match inner {
816 &InnerDecimalSchema::Fixed(FixedSchema { size, .. }) => {
817 if max_prec_for_len(size)? < precision {
818 return Err(Details::GetScaleWithFixedSize { size, precision }.into());
819 }
820 }
821 InnerDecimalSchema::Bytes => (),
822 };
823 match self {
824 Value::Decimal(num) => {
825 let num_bytes = num.len();
826 if max_prec_for_len(num_bytes)? < precision {
827 Err(Details::ComparePrecisionAndSize {
828 precision,
829 num_bytes,
830 }
831 .into())
832 } else {
833 Ok(Value::Decimal(num))
834 }
835 }
837 Value::Fixed(_, bytes) | Value::Bytes(bytes) => {
838 if max_prec_for_len(bytes.len())? < precision {
839 Err(Details::ComparePrecisionAndSize {
840 precision,
841 num_bytes: bytes.len(),
842 }
843 .into())
844 } else {
845 Ok(Value::Decimal(Decimal::from(bytes)))
847 }
848 }
849 other => Err(Details::ResolveDecimal(other).into()),
850 }
851 }
852
853 fn resolve_date(self) -> Result<Self, Error> {
854 match self {
855 Value::Date(d) | Value::Int(d) => Ok(Value::Date(d)),
856 other => Err(Details::GetDate(other).into()),
857 }
858 }
859
860 fn resolve_time_millis(self) -> Result<Self, Error> {
861 match self {
862 Value::TimeMillis(t) | Value::Int(t) => Ok(Value::TimeMillis(t)),
863 other => Err(Details::GetTimeMillis(other).into()),
864 }
865 }
866
867 fn resolve_time_micros(self) -> Result<Self, Error> {
868 match self {
869 Value::TimeMicros(t) | Value::Long(t) => Ok(Value::TimeMicros(t)),
870 Value::Int(t) => Ok(Value::TimeMicros(i64::from(t))),
871 other => Err(Details::GetTimeMicros(other).into()),
872 }
873 }
874
875 fn resolve_timestamp_millis(self) -> Result<Self, Error> {
876 match self {
877 Value::TimestampMillis(ts) | Value::Long(ts) => Ok(Value::TimestampMillis(ts)),
878 Value::Int(ts) => Ok(Value::TimestampMillis(i64::from(ts))),
879 other => Err(Details::GetTimestampMillis(other).into()),
880 }
881 }
882
883 fn resolve_timestamp_micros(self) -> Result<Self, Error> {
884 match self {
885 Value::TimestampMicros(ts) | Value::Long(ts) => Ok(Value::TimestampMicros(ts)),
886 Value::Int(ts) => Ok(Value::TimestampMicros(i64::from(ts))),
887 other => Err(Details::GetTimestampMicros(other).into()),
888 }
889 }
890
891 fn resolve_timestamp_nanos(self) -> Result<Self, Error> {
892 match self {
893 Value::TimestampNanos(ts) | Value::Long(ts) => Ok(Value::TimestampNanos(ts)),
894 Value::Int(ts) => Ok(Value::TimestampNanos(i64::from(ts))),
895 other => Err(Details::GetTimestampNanos(other).into()),
896 }
897 }
898
899 fn resolve_local_timestamp_millis(self) -> Result<Self, Error> {
900 match self {
901 Value::LocalTimestampMillis(ts) | Value::Long(ts) => {
902 Ok(Value::LocalTimestampMillis(ts))
903 }
904 Value::Int(ts) => Ok(Value::LocalTimestampMillis(i64::from(ts))),
905 other => Err(Details::GetLocalTimestampMillis(other).into()),
906 }
907 }
908
909 fn resolve_local_timestamp_micros(self) -> Result<Self, Error> {
910 match self {
911 Value::LocalTimestampMicros(ts) | Value::Long(ts) => {
912 Ok(Value::LocalTimestampMicros(ts))
913 }
914 Value::Int(ts) => Ok(Value::LocalTimestampMicros(i64::from(ts))),
915 other => Err(Details::GetLocalTimestampMicros(other).into()),
916 }
917 }
918
919 fn resolve_local_timestamp_nanos(self) -> Result<Self, Error> {
920 match self {
921 Value::LocalTimestampNanos(ts) | Value::Long(ts) => Ok(Value::LocalTimestampNanos(ts)),
922 Value::Int(ts) => Ok(Value::LocalTimestampNanos(i64::from(ts))),
923 other => Err(Details::GetLocalTimestampNanos(other).into()),
924 }
925 }
926
927 fn resolve_null(self) -> Result<Self, Error> {
928 match self {
929 Value::Null => Ok(Value::Null),
930 other => Err(Details::GetNull(other).into()),
931 }
932 }
933
934 fn resolve_boolean(self) -> Result<Self, Error> {
935 match self {
936 Value::Boolean(b) => Ok(Value::Boolean(b)),
937 other => Err(Details::GetBoolean(other).into()),
938 }
939 }
940
941 fn resolve_int(self) -> Result<Self, Error> {
942 match self {
943 Value::Int(n) => Ok(Value::Int(n)),
944 Value::Long(n) => {
945 let n = i32::try_from(n).map_err(|e| Details::ZagI32(e, n))?;
946 Ok(Value::Int(n))
947 }
948 other => Err(Details::GetInt(other).into()),
949 }
950 }
951
952 fn resolve_long(self) -> Result<Self, Error> {
953 match self {
954 Value::Int(n) => Ok(Value::Long(i64::from(n))),
955 Value::Long(n) => Ok(Value::Long(n)),
956 other => Err(Details::GetLong(other).into()),
957 }
958 }
959
960 fn resolve_float(self) -> Result<Self, Error> {
961 match self {
962 Value::Int(n) => Ok(Value::Float(n as f32)),
963 Value::Long(n) => Ok(Value::Float(n as f32)),
964 Value::Float(x) => Ok(Value::Float(x)),
965 Value::Double(x) => Ok(Value::Float(x as f32)),
966 Value::String(ref x) => match Self::parse_special_float(x) {
967 Some(f) => Ok(Value::Float(f)),
968 None => Err(Details::GetFloat(self).into()),
969 },
970 other => Err(Details::GetFloat(other).into()),
971 }
972 }
973
974 fn resolve_double(self) -> Result<Self, Error> {
975 match self {
976 Value::Int(n) => Ok(Value::Double(f64::from(n))),
977 Value::Long(n) => Ok(Value::Double(n as f64)),
978 Value::Float(x) => Ok(Value::Double(f64::from(x))),
979 Value::Double(x) => Ok(Value::Double(x)),
980 Value::String(ref x) => match Self::parse_special_float(x) {
981 Some(f) => Ok(Value::Double(f64::from(f))),
982 None => Err(Details::GetDouble(self).into()),
983 },
984 other => Err(Details::GetDouble(other).into()),
985 }
986 }
987
988 fn parse_special_float(value: &str) -> Option<f32> {
991 match value {
992 "NaN" => Some(f32::NAN),
993 "INF" | "Infinity" => Some(f32::INFINITY),
994 "-INF" | "-Infinity" => Some(f32::NEG_INFINITY),
995 _ => None,
996 }
997 }
998
999 fn resolve_bytes(self) -> Result<Self, Error> {
1000 match self {
1001 Value::Bytes(bytes) => Ok(Value::Bytes(bytes)),
1002 Value::String(s) => Ok(Value::Bytes(s.into_bytes())),
1003 Value::Array(items) => Ok(Value::Bytes(
1004 items
1005 .into_iter()
1006 .map(Value::try_u8)
1007 .collect::<Result<Vec<_>, _>>()?,
1008 )),
1009 other => Err(Details::GetBytes(other).into()),
1010 }
1011 }
1012
1013 fn resolve_string(self) -> Result<Self, Error> {
1014 match self {
1015 Value::String(s) => Ok(Value::String(s)),
1016 Value::Bytes(bytes) | Value::Fixed(_, bytes) => Ok(Value::String(
1017 String::from_utf8(bytes).map_err(Details::ConvertToUtf8)?,
1018 )),
1019 other => Err(Details::GetString(other).into()),
1020 }
1021 }
1022
1023 fn resolve_fixed(self, size: usize) -> Result<Self, Error> {
1024 match self {
1025 Value::Fixed(n, bytes) => {
1026 if n == size {
1027 Ok(Value::Fixed(n, bytes))
1028 } else {
1029 Err(Details::CompareFixedSizes { size, n }.into())
1030 }
1031 }
1032 Value::String(s) => Ok(Value::Fixed(s.len(), s.into_bytes())),
1033 Value::Bytes(s) => {
1034 if s.len() == size {
1035 Ok(Value::Fixed(size, s))
1036 } else {
1037 Err(Details::CompareFixedSizes { size, n: s.len() }.into())
1038 }
1039 }
1040 other => Err(Details::GetStringForFixed(other).into()),
1041 }
1042 }
1043
1044 pub(crate) fn resolve_enum(
1045 self,
1046 symbols: &[String],
1047 enum_default: &Option<String>,
1048 _field_default: &Option<JsonValue>,
1049 ) -> Result<Self, Error> {
1050 let validate_symbol = |symbol: String, symbols: &[String]| {
1051 if let Some(index) = symbols.iter().position(|item| item == &symbol) {
1052 Ok(Value::Enum(index as u32, symbol))
1053 } else {
1054 match enum_default {
1055 Some(default) => {
1056 if let Some(index) = symbols.iter().position(|item| item == default) {
1057 Ok(Value::Enum(index as u32, default.clone()))
1058 } else {
1059 Err(Details::GetEnumDefault {
1060 symbol,
1061 symbols: symbols.into(),
1062 }
1063 .into())
1064 }
1065 }
1066 _ => Err(Details::GetEnumDefault {
1067 symbol,
1068 symbols: symbols.into(),
1069 }
1070 .into()),
1071 }
1072 }
1073 };
1074
1075 match self {
1076 Value::Enum(_raw_index, s) => validate_symbol(s, symbols),
1077 Value::String(s) => validate_symbol(s, symbols),
1078 other => Err(Details::GetEnum(other).into()),
1079 }
1080 }
1081
1082 fn resolve_union<S: Borrow<Schema> + Debug>(
1083 self,
1084 schema: &UnionSchema,
1085 names: &HashMap<Name, S>,
1086 enclosing_namespace: NamespaceRef,
1087 field_default: &Option<JsonValue>,
1088 ) -> Result<Self, Error> {
1089 let v = match self {
1090 Value::Union(_i, v) => *v,
1092 v => v,
1094 };
1095 let (i, inner) = schema
1096 .find_schema_with_known_schemata(&v, Some(names), enclosing_namespace)
1097 .ok_or_else(|| Details::FindUnionVariant {
1098 schema: schema.clone(),
1099 value: v.clone(),
1100 })?;
1101
1102 Ok(Value::Union(
1103 i as u32,
1104 Box::new(v.resolve_internal(inner, names, enclosing_namespace, field_default)?),
1105 ))
1106 }
1107
1108 fn resolve_array<S: Borrow<Schema> + Debug>(
1109 self,
1110 schema: &Schema,
1111 names: &HashMap<Name, S>,
1112 enclosing_namespace: NamespaceRef,
1113 ) -> Result<Self, Error> {
1114 match self {
1115 Value::Array(items) => Ok(Value::Array(
1116 items
1117 .into_iter()
1118 .map(|item| item.resolve_internal(schema, names, enclosing_namespace, &None))
1119 .collect::<Result<_, _>>()?,
1120 )),
1121 other => Err(Details::GetArray {
1122 expected: schema.into(),
1123 other,
1124 }
1125 .into()),
1126 }
1127 }
1128
1129 fn resolve_map<S: Borrow<Schema> + Debug>(
1130 self,
1131 schema: &Schema,
1132 names: &HashMap<Name, S>,
1133 enclosing_namespace: NamespaceRef,
1134 ) -> Result<Self, Error> {
1135 match self {
1136 Value::Map(items) => Ok(Value::Map(
1137 items
1138 .into_iter()
1139 .map(|(key, value)| {
1140 value
1141 .resolve_internal(schema, names, enclosing_namespace, &None)
1142 .map(|value| (key, value))
1143 })
1144 .collect::<Result<_, _>>()?,
1145 )),
1146 other => Err(Details::GetMap {
1147 expected: schema.into(),
1148 other,
1149 }
1150 .into()),
1151 }
1152 }
1153
1154 fn resolve_record<S: Borrow<Schema> + Debug>(
1155 self,
1156 fields: &[RecordField],
1157 names: &HashMap<Name, S>,
1158 enclosing_namespace: NamespaceRef,
1159 ) -> Result<Self, Error> {
1160 let mut items = match self {
1161 Value::Map(items) => Ok(items),
1162 Value::Record(fields) => Ok(fields.into_iter().collect::<HashMap<_, _>>()),
1163 other => Err(Error::new(Details::GetRecord {
1164 expected: fields
1165 .iter()
1166 .map(|field| (field.name.clone(), field.schema.clone().into()))
1167 .collect(),
1168 other,
1169 })),
1170 }?;
1171
1172 let new_fields = fields
1173 .iter()
1174 .map(|field| {
1175 let value = match items.remove(&field.name) {
1176 Some(value) => value,
1177 None => match field.default {
1178 Some(ref value) => match field.schema {
1179 Schema::Enum(EnumSchema {
1180 ref symbols,
1181 ref default,
1182 ..
1183 }) => Value::try_from(value.clone())?.resolve_enum(
1184 symbols,
1185 default,
1186 &field.default.clone(),
1187 )?,
1188 Schema::Union(ref union_schema) => {
1189 let first = &union_schema.variants()[0];
1190 match first {
1193 Schema::Null => Value::Union(0, Box::new(Value::Null)),
1194 _ => Value::Union(
1195 0,
1196 Box::new(
1197 Value::try_from(value.clone())?.resolve_internal(
1198 first,
1199 names,
1200 enclosing_namespace,
1201 &field.default,
1202 )?,
1203 ),
1204 ),
1205 }
1206 }
1207 _ => Value::try_from(value.clone())?,
1208 },
1209 None => {
1210 return Err(Details::GetField(field.name.clone()).into());
1211 }
1212 },
1213 };
1214 value
1215 .resolve_internal(&field.schema, names, enclosing_namespace, &field.default)
1216 .map(|value| (field.name.clone(), value))
1217 })
1218 .collect::<Result<Vec<_>, _>>()?;
1219
1220 Ok(Value::Record(new_fields))
1221 }
1222
1223 fn try_u8(self) -> AvroResult<u8> {
1224 let int = self.resolve(&Schema::Int)?;
1225 if let Value::Int(n) = int
1226 && n >= 0
1227 && n <= i32::from(u8::MAX)
1228 {
1229 return Ok(n as u8);
1230 }
1231
1232 Err(Details::GetU8(int).into())
1233 }
1234}
1235
1236#[cfg(test)]
1237mod tests {
1238 use super::*;
1239 use crate::{
1240 duration::{Days, Millis, Months},
1241 error::Details,
1242 to_value,
1243 };
1244 use apache_avro_test_helper::{
1245 TestResult,
1246 logger::{assert_logged, assert_not_logged},
1247 };
1248 use num_bigint::BigInt;
1249 use pretty_assertions::assert_eq;
1250 use serde_json::json;
1251
1252 #[test]
1253 fn avro_3809_validate_nested_records_with_implicit_namespace() -> TestResult {
1254 let schema = Schema::parse_str(
1255 r#"{
1256 "name": "record_name",
1257 "namespace": "space",
1258 "type": "record",
1259 "fields": [
1260 {
1261 "name": "outer_field_1",
1262 "type": {
1263 "type": "record",
1264 "name": "middle_record_name",
1265 "namespace": "middle_namespace",
1266 "fields": [
1267 {
1268 "name": "middle_field_1",
1269 "type": {
1270 "type": "record",
1271 "name": "inner_record_name",
1272 "fields": [
1273 { "name": "inner_field_1", "type": "double" }
1274 ]
1275 }
1276 },
1277 { "name": "middle_field_2", "type": "inner_record_name" }
1278 ]
1279 }
1280 }
1281 ]
1282 }"#,
1283 )?;
1284 let value = Value::Record(vec![(
1285 "outer_field_1".into(),
1286 Value::Record(vec![
1287 (
1288 "middle_field_1".into(),
1289 Value::Record(vec![("inner_field_1".into(), Value::Double(1.2f64))]),
1290 ),
1291 (
1292 "middle_field_2".into(),
1293 Value::Record(vec![("inner_field_1".into(), Value::Double(1.6f64))]),
1294 ),
1295 ]),
1296 )]);
1297
1298 assert!(value.validate(&schema));
1299 Ok(())
1300 }
1301
1302 #[test]
1303 fn validate() -> TestResult {
1304 let value_schema_valid = vec![
1305 (Value::Int(42), Schema::Int, true, ""),
1306 (Value::Int(43), Schema::Long, true, ""),
1307 (Value::Float(43.2), Schema::Float, true, ""),
1308 (Value::Float(45.9), Schema::Double, true, ""),
1309 (
1310 Value::Int(42),
1311 Schema::Boolean,
1312 false,
1313 "Invalid value: Int(42) for schema: Boolean. Reason: Unsupported value-schema combination! Value: Int(42), schema: Boolean",
1314 ),
1315 (
1316 Value::Union(0, Box::new(Value::Null)),
1317 Schema::Union(UnionSchema::new(vec![Schema::Null, Schema::Int])?),
1318 true,
1319 "",
1320 ),
1321 (
1322 Value::Union(1, Box::new(Value::Int(42))),
1323 Schema::Union(UnionSchema::new(vec![Schema::Null, Schema::Int])?),
1324 true,
1325 "",
1326 ),
1327 (
1328 Value::Union(0, Box::new(Value::Null)),
1329 Schema::Union(UnionSchema::new(vec![Schema::Double, Schema::Int])?),
1330 false,
1331 "Invalid value: Union(0, Null) for schema: Union(UnionSchema { schemas: [Double, Int] }). Reason: Unsupported value-schema combination! Value: Null, schema: Double",
1332 ),
1333 (
1334 Value::Union(3, Box::new(Value::Int(42))),
1335 Schema::Union(UnionSchema::new(vec![
1336 Schema::Null,
1337 Schema::Double,
1338 Schema::String,
1339 Schema::Int,
1340 ])?),
1341 true,
1342 "",
1343 ),
1344 (
1345 Value::Union(1, Box::new(Value::Long(42i64))),
1346 Schema::Union(UnionSchema::new(vec![
1347 Schema::Null,
1348 Schema::TimestampMillis,
1349 ])?),
1350 true,
1351 "",
1352 ),
1353 (
1354 Value::Union(2, Box::new(Value::Long(1_i64))),
1355 Schema::Union(UnionSchema::new(vec![Schema::Null, Schema::Int])?),
1356 false,
1357 "Invalid value: Union(2, Long(1)) for schema: Union(UnionSchema { schemas: [Null, Int] }). Reason: No schema in the union at position '2'",
1358 ),
1359 (
1360 Value::Array(vec![Value::Long(42i64)]),
1361 Schema::array(Schema::Long).build(),
1362 true,
1363 "",
1364 ),
1365 (
1366 Value::Array(vec![Value::Boolean(true)]),
1367 Schema::array(Schema::Long).build(),
1368 false,
1369 "Invalid value: Array([Boolean(true)]) for schema: Array(ArraySchema { items: Long, .. }). Reason: Unsupported value-schema combination! Value: Boolean(true), schema: Long",
1370 ),
1371 (
1372 Value::Record(vec![]),
1373 Schema::Null,
1374 false,
1375 "Invalid value: Record([]) for schema: Null. Reason: Unsupported value-schema combination! Value: Record([]), schema: Null",
1376 ),
1377 (
1378 Value::Fixed(12, vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]),
1379 Schema::Duration(FixedSchema {
1380 name: Name::try_from("TestName")?,
1381 aliases: None,
1382 doc: None,
1383 size: 12,
1384 attributes: BTreeMap::new(),
1385 }),
1386 true,
1387 "",
1388 ),
1389 (
1390 Value::Fixed(11, vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]),
1391 Schema::Duration(FixedSchema {
1392 name: Name::try_from("TestName")?,
1393 aliases: None,
1394 doc: None,
1395 size: 12,
1396 attributes: BTreeMap::new(),
1397 }),
1398 false,
1399 r#"Invalid value: Fixed(11, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) for schema: Duration(FixedSchema { name: Name { name: "TestName", .. }, size: 12, .. }). Reason: The value's size ('11') must be exactly 12 to be a Duration"#,
1400 ),
1401 (
1402 Value::Record(vec![("unknown_field_name".to_string(), Value::Null)]),
1403 Schema::Record(RecordSchema {
1404 name: Name::new("record_name")?,
1405 aliases: None,
1406 doc: None,
1407 fields: vec![
1408 RecordField::builder()
1409 .name("field_name".to_string())
1410 .schema(Schema::Int)
1411 .build(),
1412 ],
1413 lookup: Default::default(),
1414 attributes: Default::default(),
1415 }),
1416 false,
1417 r#"Invalid value: Record([("unknown_field_name", Null)]) for schema: Record(RecordSchema { name: Name { name: "record_name", .. }, fields: [RecordField { name: "field_name", schema: Int, .. }], .. }). Reason: There is no schema field for field 'unknown_field_name'"#,
1418 ),
1419 (
1420 Value::Record(vec![("field_name".to_string(), Value::Null)]),
1421 Schema::Record(RecordSchema {
1422 name: Name::new("record_name")?,
1423 aliases: None,
1424 doc: None,
1425 fields: vec![
1426 RecordField::builder()
1427 .name("field_name".to_string())
1428 .schema(Schema::Ref {
1429 name: Name::new("missing")?,
1430 })
1431 .build(),
1432 ],
1433 lookup: [("field_name".to_string(), 0)].iter().cloned().collect(),
1434 attributes: Default::default(),
1435 }),
1436 false,
1437 r#"Invalid value: Record([("field_name", Null)]) for schema: Record(RecordSchema { name: Name { name: "record_name", .. }, fields: [RecordField { name: "field_name", schema: Ref { name: Name { name: "missing", .. } }, .. }], .. }). Reason: Unresolved schema reference: 'Name { name: "missing", .. }'. Parsed names: []"#,
1438 ),
1439 ];
1440
1441 for (value, schema, valid, expected_err_message) in value_schema_valid.into_iter() {
1442 let err_message = value.validate_internal::<Schema>(&schema, &HashMap::default(), None);
1443 assert_eq!(valid, err_message.is_none());
1444 if !valid {
1445 let full_err_message = format!(
1446 "Invalid value: {:?} for schema: {:?}. Reason: {}",
1447 value,
1448 schema,
1449 err_message.unwrap()
1450 );
1451 assert_eq!(expected_err_message, full_err_message);
1452 }
1453 }
1454
1455 Ok(())
1456 }
1457
1458 #[test]
1459 fn validate_fixed() -> TestResult {
1460 let schema = Schema::Fixed(FixedSchema {
1461 size: 4,
1462 name: Name::new("some_fixed")?,
1463 aliases: None,
1464 doc: None,
1465 attributes: Default::default(),
1466 });
1467
1468 assert!(Value::Fixed(4, vec![0, 0, 0, 0]).validate(&schema));
1469 let value = Value::Fixed(5, vec![0, 0, 0, 0, 0]);
1470 assert!(!value.validate(&schema));
1471 assert_logged(
1472 format!(
1473 "Invalid value: {:?} for schema: {:?}. Reason: {}",
1474 value, schema, "The value's size (5) is different than the schema's size (4)"
1475 )
1476 .as_str(),
1477 );
1478
1479 assert!(Value::Bytes(vec![0, 0, 0, 0]).validate(&schema));
1480 let value = Value::Bytes(vec![0, 0, 0, 0, 0]);
1481 assert!(!value.validate(&schema));
1482 assert_logged(
1483 format!(
1484 "Invalid value: {:?} for schema: {:?}. Reason: {}",
1485 value, schema, "The bytes' length (5) is different than the schema's size (4)"
1486 )
1487 .as_str(),
1488 );
1489
1490 Ok(())
1491 }
1492
1493 #[test]
1494 fn validate_enum() -> TestResult {
1495 let schema = Schema::Enum(EnumSchema {
1496 name: Name::new("some_enum")?,
1497 aliases: None,
1498 doc: None,
1499 symbols: vec![
1500 "spades".to_string(),
1501 "hearts".to_string(),
1502 "diamonds".to_string(),
1503 "clubs".to_string(),
1504 ],
1505 default: None,
1506 attributes: Default::default(),
1507 });
1508
1509 assert!(Value::Enum(0, "spades".to_string()).validate(&schema));
1510 assert!(Value::String("spades".to_string()).validate(&schema));
1511
1512 let value = Value::Enum(1, "spades".to_string());
1513 assert!(!value.validate(&schema));
1514 assert_logged(
1515 format!(
1516 "Invalid value: {:?} for schema: {:?}. Reason: {}",
1517 value, schema, "Symbol 'spades' is not at position '1'"
1518 )
1519 .as_str(),
1520 );
1521
1522 let value = Value::Enum(1000, "spades".to_string());
1523 assert!(!value.validate(&schema));
1524 assert_logged(
1525 format!(
1526 "Invalid value: {:?} for schema: {:?}. Reason: {}",
1527 value, schema, "No symbol at position '1000'"
1528 )
1529 .as_str(),
1530 );
1531
1532 let value = Value::String("lorem".to_string());
1533 assert!(!value.validate(&schema));
1534 assert_logged(
1535 format!(
1536 "Invalid value: {:?} for schema: {:?}. Reason: {}",
1537 value, schema, "'lorem' is not a member of the possible symbols"
1538 )
1539 .as_str(),
1540 );
1541
1542 let other_schema = Schema::Enum(EnumSchema {
1543 name: Name::new("some_other_enum")?,
1544 aliases: None,
1545 doc: None,
1546 symbols: vec![
1547 "hearts".to_string(),
1548 "diamonds".to_string(),
1549 "clubs".to_string(),
1550 "spades".to_string(),
1551 ],
1552 default: None,
1553 attributes: Default::default(),
1554 });
1555
1556 let value = Value::Enum(0, "spades".to_string());
1557 assert!(!value.validate(&other_schema));
1558 assert_logged(
1559 format!(
1560 "Invalid value: {:?} for schema: {:?}. Reason: {}",
1561 value, other_schema, "Symbol 'spades' is not at position '0'"
1562 )
1563 .as_str(),
1564 );
1565
1566 Ok(())
1567 }
1568
1569 #[test]
1570 fn validate_record() -> TestResult {
1571 let schema = Schema::Record(RecordSchema {
1584 name: Name::new("some_record")?,
1585 aliases: None,
1586 doc: None,
1587 fields: vec![
1588 RecordField::builder()
1589 .name("a".to_string())
1590 .schema(Schema::Long)
1591 .build(),
1592 RecordField::builder()
1593 .name("b".to_string())
1594 .schema(Schema::String)
1595 .build(),
1596 RecordField::builder()
1597 .name("c".to_string())
1598 .default(JsonValue::Null)
1599 .schema(Schema::Union(UnionSchema::new(vec![
1600 Schema::Null,
1601 Schema::Int,
1602 ])?))
1603 .build(),
1604 ],
1605 lookup: [
1606 ("a".to_string(), 0),
1607 ("b".to_string(), 1),
1608 ("c".to_string(), 2),
1609 ]
1610 .iter()
1611 .cloned()
1612 .collect(),
1613 attributes: Default::default(),
1614 });
1615
1616 assert!(
1617 Value::Record(vec![
1618 ("a".to_string(), Value::Long(42i64)),
1619 ("b".to_string(), Value::String("foo".to_string())),
1620 ])
1621 .validate(&schema)
1622 );
1623
1624 let value = Value::Record(vec![
1625 ("b".to_string(), Value::String("foo".to_string())),
1626 ("a".to_string(), Value::Long(42i64)),
1627 ]);
1628 assert!(value.validate(&schema));
1629
1630 let value = Value::Record(vec![
1631 ("a".to_string(), Value::Boolean(false)),
1632 ("b".to_string(), Value::String("foo".to_string())),
1633 ]);
1634 assert!(!value.validate(&schema));
1635 assert_logged(
1636 r#"Invalid value: Record([("a", Boolean(false)), ("b", String("foo"))]) for schema: Record(RecordSchema { name: Name { name: "some_record", .. }, fields: [RecordField { name: "a", schema: Long, .. }, RecordField { name: "b", schema: String, .. }, RecordField { name: "c", default: Null, schema: Union(UnionSchema { schemas: [Null, Int] }), .. }], .. }). Reason: Unsupported value-schema combination! Value: Boolean(false), schema: Long"#,
1637 );
1638
1639 let value = Value::Record(vec![
1640 ("a".to_string(), Value::Long(42i64)),
1641 ("c".to_string(), Value::String("foo".to_string())),
1642 ]);
1643 assert!(!value.validate(&schema));
1644 assert_logged(
1645 r#"Invalid value: Record([("a", Long(42)), ("c", String("foo"))]) for schema: Record(RecordSchema { name: Name { name: "some_record", .. }, fields: [RecordField { name: "a", schema: Long, .. }, RecordField { name: "b", schema: String, .. }, RecordField { name: "c", default: Null, schema: Union(UnionSchema { schemas: [Null, Int] }), .. }], .. }). Reason: Could not find matching type in union"#,
1646 );
1647 assert_not_logged(
1648 r#"Invalid value: String("foo") for schema: Int. Reason: Unsupported value-schema combination"#,
1649 );
1650
1651 let value = Value::Record(vec![
1652 ("a".to_string(), Value::Long(42i64)),
1653 ("d".to_string(), Value::String("foo".to_string())),
1654 ]);
1655 assert!(!value.validate(&schema));
1656 assert_logged(
1657 r#"Invalid value: Record([("a", Long(42)), ("d", String("foo"))]) for schema: Record(RecordSchema { name: Name { name: "some_record", .. }, fields: [RecordField { name: "a", schema: Long, .. }, RecordField { name: "b", schema: String, .. }, RecordField { name: "c", default: Null, schema: Union(UnionSchema { schemas: [Null, Int] }), .. }], .. }). Reason: There is no schema field for field 'd'"#,
1658 );
1659
1660 let value = Value::Record(vec![
1661 ("a".to_string(), Value::Long(42i64)),
1662 ("b".to_string(), Value::String("foo".to_string())),
1663 ("c".to_string(), Value::Null),
1664 ("d".to_string(), Value::Null),
1665 ]);
1666 assert!(!value.validate(&schema));
1667 assert_logged(
1668 r#"Invalid value: Record([("a", Long(42)), ("b", String("foo")), ("c", Null), ("d", Null)]) for schema: Record(RecordSchema { name: Name { name: "some_record", .. }, fields: [RecordField { name: "a", schema: Long, .. }, RecordField { name: "b", schema: String, .. }, RecordField { name: "c", default: Null, schema: Union(UnionSchema { schemas: [Null, Int] }), .. }], .. }). Reason: The value's records length (4) is greater than the schema's (3 fields)"#,
1669 );
1670
1671 assert!(
1672 Value::Map(
1673 vec![
1674 ("a".to_string(), Value::Long(42i64)),
1675 ("b".to_string(), Value::String("foo".to_string())),
1676 ]
1677 .into_iter()
1678 .collect()
1679 )
1680 .validate(&schema)
1681 );
1682
1683 assert!(
1684 !Value::Map(
1685 vec![("d".to_string(), Value::Long(123_i64)),]
1686 .into_iter()
1687 .collect()
1688 )
1689 .validate(&schema)
1690 );
1691 assert_logged(
1692 r#"Invalid value: Map({"d": Long(123)}) for schema: Record(RecordSchema { name: Name { name: "some_record", .. }, fields: [RecordField { name: "a", schema: Long, .. }, RecordField { name: "b", schema: String, .. }, RecordField { name: "c", default: Null, schema: Union(UnionSchema { schemas: [Null, Int] }), .. }], .. }). Reason: Field with name '"a"' is not a member of the map items
1693Field with name '"b"' is not a member of the map items"#,
1694 );
1695
1696 let union_schema = Schema::Union(UnionSchema::new(vec![Schema::Null, schema])?);
1697
1698 assert!(
1699 Value::Union(
1700 1,
1701 Box::new(Value::Record(vec![
1702 ("a".to_string(), Value::Long(42i64)),
1703 ("b".to_string(), Value::String("foo".to_string())),
1704 ]))
1705 )
1706 .validate(&union_schema)
1707 );
1708
1709 assert!(
1710 Value::Union(
1711 1,
1712 Box::new(Value::Map(
1713 vec![
1714 ("a".to_string(), Value::Long(42i64)),
1715 ("b".to_string(), Value::String("foo".to_string())),
1716 ]
1717 .into_iter()
1718 .collect()
1719 ))
1720 )
1721 .validate(&union_schema)
1722 );
1723
1724 Ok(())
1725 }
1726
1727 #[test]
1728 fn resolve_bytes_ok() -> TestResult {
1729 let value = Value::Array(vec![Value::Int(0), Value::Int(42)]);
1730 assert_eq!(
1731 value.resolve(&Schema::Bytes)?,
1732 Value::Bytes(vec![0u8, 42u8])
1733 );
1734
1735 Ok(())
1736 }
1737
1738 #[test]
1739 fn resolve_string_from_bytes() -> TestResult {
1740 let value = Value::Bytes(vec![97, 98, 99]);
1741 assert_eq!(
1742 value.resolve(&Schema::String)?,
1743 Value::String("abc".to_string())
1744 );
1745
1746 Ok(())
1747 }
1748
1749 #[test]
1750 fn resolve_string_from_fixed() -> TestResult {
1751 let value = Value::Fixed(3, vec![97, 98, 99]);
1752 assert_eq!(
1753 value.resolve(&Schema::String)?,
1754 Value::String("abc".to_string())
1755 );
1756
1757 Ok(())
1758 }
1759
1760 #[test]
1761 fn resolve_bytes_failure() {
1762 let value = Value::Array(vec![Value::Int(2000), Value::Int(-42)]);
1763 assert!(value.resolve(&Schema::Bytes).is_err());
1764 }
1765
1766 #[test]
1767 fn resolve_decimal_bytes() -> TestResult {
1768 let value = Value::Decimal(Decimal::from(vec![1, 2, 3, 4, 5]));
1769 value.clone().resolve(&Schema::Decimal(DecimalSchema {
1770 precision: 10,
1771 scale: 4,
1772 inner: InnerDecimalSchema::Bytes,
1773 }))?;
1774 assert!(value.resolve(&Schema::String).is_err());
1775
1776 Ok(())
1777 }
1778
1779 #[test]
1780 fn resolve_decimal_invalid_scale() {
1781 let value = Value::Decimal(Decimal::from(vec![1, 2]));
1782 assert!(
1783 value
1784 .resolve(&Schema::Decimal(DecimalSchema {
1785 precision: 2,
1786 scale: 3,
1787 inner: InnerDecimalSchema::Bytes,
1788 }))
1789 .is_err()
1790 );
1791 }
1792
1793 #[test]
1794 fn resolve_decimal_invalid_precision_for_length() {
1795 let value = Value::Decimal(Decimal::from((1u8..=8u8).rev().collect::<Vec<_>>()));
1796 assert!(
1797 value
1798 .resolve(&Schema::Decimal(DecimalSchema {
1799 precision: 1,
1800 scale: 0,
1801 inner: InnerDecimalSchema::Bytes,
1802 }))
1803 .is_ok()
1804 );
1805 }
1806
1807 #[test]
1808 fn resolve_decimal_fixed() {
1809 let value = Value::Decimal(Decimal::from(vec![1, 2, 3, 4, 5]));
1810 assert!(
1811 value
1812 .clone()
1813 .resolve(&Schema::Decimal(DecimalSchema {
1814 precision: 10,
1815 scale: 1,
1816 inner: InnerDecimalSchema::Fixed(FixedSchema {
1817 name: Name::new("decimal").unwrap(),
1818 aliases: None,
1819 size: 20,
1820 doc: None,
1821 attributes: Default::default(),
1822 })
1823 }))
1824 .is_ok()
1825 );
1826 assert!(value.resolve(&Schema::String).is_err());
1827 }
1828
1829 #[test]
1830 fn resolve_date() {
1831 let value = Value::Date(2345);
1832 assert!(value.clone().resolve(&Schema::Date).is_ok());
1833 assert!(value.resolve(&Schema::String).is_err());
1834 }
1835
1836 #[test]
1837 fn resolve_time_millis() {
1838 let value = Value::TimeMillis(10);
1839 assert!(value.clone().resolve(&Schema::TimeMillis).is_ok());
1840 assert!(value.resolve(&Schema::TimeMicros).is_err());
1841 }
1842
1843 #[test]
1844 fn resolve_time_micros() {
1845 let value = Value::TimeMicros(10);
1846 assert!(value.clone().resolve(&Schema::TimeMicros).is_ok());
1847 assert!(value.resolve(&Schema::TimeMillis).is_err());
1848 }
1849
1850 #[test]
1851 fn resolve_timestamp_millis() {
1852 let value = Value::TimestampMillis(10);
1853 assert!(value.clone().resolve(&Schema::TimestampMillis).is_ok());
1854 assert!(value.resolve(&Schema::Float).is_err());
1855
1856 let value = Value::Float(10.0f32);
1857 assert!(value.resolve(&Schema::TimestampMillis).is_err());
1858 }
1859
1860 #[test]
1861 fn resolve_timestamp_micros() {
1862 let value = Value::TimestampMicros(10);
1863 assert!(value.clone().resolve(&Schema::TimestampMicros).is_ok());
1864 assert!(value.resolve(&Schema::Int).is_err());
1865
1866 let value = Value::Double(10.0);
1867 assert!(value.resolve(&Schema::TimestampMicros).is_err());
1868 }
1869
1870 #[test]
1871 fn test_avro_3914_resolve_timestamp_nanos() {
1872 let value = Value::TimestampNanos(10);
1873 assert!(value.clone().resolve(&Schema::TimestampNanos).is_ok());
1874 assert!(value.resolve(&Schema::Int).is_err());
1875
1876 let value = Value::Double(10.0);
1877 assert!(value.resolve(&Schema::TimestampNanos).is_err());
1878 }
1879
1880 #[test]
1881 fn test_avro_3853_resolve_timestamp_millis() {
1882 let value = Value::LocalTimestampMillis(10);
1883 assert!(value.clone().resolve(&Schema::LocalTimestampMillis).is_ok());
1884 assert!(value.resolve(&Schema::Float).is_err());
1885
1886 let value = Value::Float(10.0f32);
1887 assert!(value.resolve(&Schema::LocalTimestampMillis).is_err());
1888 }
1889
1890 #[test]
1891 fn test_avro_3853_resolve_timestamp_micros() {
1892 let value = Value::LocalTimestampMicros(10);
1893 assert!(value.clone().resolve(&Schema::LocalTimestampMicros).is_ok());
1894 assert!(value.resolve(&Schema::Int).is_err());
1895
1896 let value = Value::Double(10.0);
1897 assert!(value.resolve(&Schema::LocalTimestampMicros).is_err());
1898 }
1899
1900 #[test]
1901 fn test_avro_3916_resolve_timestamp_nanos() {
1902 let value = Value::LocalTimestampNanos(10);
1903 assert!(value.clone().resolve(&Schema::LocalTimestampNanos).is_ok());
1904 assert!(value.resolve(&Schema::Int).is_err());
1905
1906 let value = Value::Double(10.0);
1907 assert!(value.resolve(&Schema::LocalTimestampNanos).is_err());
1908 }
1909
1910 #[test]
1911 fn resolve_duration() {
1912 let value = Value::Duration(Duration::new(
1913 Months::new(10),
1914 Days::new(5),
1915 Millis::new(3000),
1916 ));
1917 assert!(
1918 value
1919 .clone()
1920 .resolve(&Schema::Duration(FixedSchema {
1921 name: Name::try_from("TestName").expect("Name is valid"),
1922 aliases: None,
1923 doc: None,
1924 size: 12,
1925 attributes: BTreeMap::new()
1926 }))
1927 .is_ok()
1928 );
1929 assert!(value.resolve(&Schema::TimestampMicros).is_err());
1930 assert!(
1931 Value::Long(1i64)
1932 .resolve(&Schema::Duration(FixedSchema {
1933 name: Name::try_from("TestName").expect("Name is valid"),
1934 aliases: None,
1935 doc: None,
1936 size: 12,
1937 attributes: BTreeMap::new()
1938 }))
1939 .is_err()
1940 );
1941 }
1942
1943 #[test]
1944 fn resolve_uuid() -> TestResult {
1945 let value = Value::Uuid(Uuid::parse_str("1481531d-ccc9-46d9-a56f-5b67459c0537")?);
1946 assert!(
1947 value
1948 .clone()
1949 .resolve(&Schema::Uuid(UuidSchema::String))
1950 .is_ok()
1951 );
1952 assert!(
1953 value
1954 .clone()
1955 .resolve(&Schema::Uuid(UuidSchema::Bytes))
1956 .is_ok()
1957 );
1958 assert!(
1959 value
1960 .clone()
1961 .resolve(&Schema::Uuid(UuidSchema::Fixed(FixedSchema {
1962 name: Name::new("some_name")?,
1963 aliases: None,
1964 doc: None,
1965 size: 16,
1966 attributes: Default::default(),
1967 })))
1968 .is_ok()
1969 );
1970 assert!(value.resolve(&Schema::TimestampMicros).is_err());
1971
1972 Ok(())
1973 }
1974
1975 #[test]
1976 fn avro_3678_resolve_float_to_double() {
1977 let value = Value::Float(2345.1);
1978 assert!(value.resolve(&Schema::Double).is_ok());
1979 }
1980
1981 #[test]
1982 fn test_avro_3621_resolve_to_nullable_union() -> TestResult {
1983 let schema = Schema::parse_str(
1984 r#"{
1985 "type": "record",
1986 "name": "root",
1987 "fields": [
1988 {
1989 "name": "event",
1990 "type": [
1991 "null",
1992 {
1993 "type": "record",
1994 "name": "event",
1995 "fields": [
1996 {
1997 "name": "amount",
1998 "type": "int"
1999 },
2000 {
2001 "name": "size",
2002 "type": [
2003 "null",
2004 "int"
2005 ],
2006 "default": null
2007 }
2008 ]
2009 }
2010 ],
2011 "default": null
2012 }
2013 ]
2014 }"#,
2015 )?;
2016
2017 let value = Value::Record(vec![(
2018 "event".to_string(),
2019 Value::Record(vec![("amount".to_string(), Value::Int(200))]),
2020 )]);
2021 assert!(value.resolve(&schema).is_ok());
2022
2023 let value = Value::Record(vec![(
2024 "event".to_string(),
2025 Value::Record(vec![("size".to_string(), Value::Int(1))]),
2026 )]);
2027 assert!(value.resolve(&schema).is_err());
2028
2029 Ok(())
2030 }
2031
2032 #[test]
2033 fn json_from_avro() -> TestResult {
2034 assert_eq!(JsonValue::try_from(Value::Null)?, JsonValue::Null);
2035 assert_eq!(
2036 JsonValue::try_from(Value::Boolean(true))?,
2037 JsonValue::Bool(true)
2038 );
2039 assert_eq!(
2040 JsonValue::try_from(Value::Int(1))?,
2041 JsonValue::Number(1.into())
2042 );
2043 assert_eq!(
2044 JsonValue::try_from(Value::Long(1))?,
2045 JsonValue::Number(1.into())
2046 );
2047 assert_eq!(
2048 JsonValue::try_from(Value::Float(1.0))?,
2049 JsonValue::Number(Number::from_f64(1.0).unwrap())
2050 );
2051 assert_eq!(
2052 JsonValue::try_from(Value::Double(1.0))?,
2053 JsonValue::Number(Number::from_f64(1.0).unwrap())
2054 );
2055 assert_eq!(
2056 JsonValue::try_from(Value::Bytes(vec![1, 2, 3]))?,
2057 JsonValue::Array(vec![
2058 JsonValue::Number(1.into()),
2059 JsonValue::Number(2.into()),
2060 JsonValue::Number(3.into())
2061 ])
2062 );
2063 assert_eq!(
2064 JsonValue::try_from(Value::String("test".into()))?,
2065 JsonValue::String("test".into())
2066 );
2067 assert_eq!(
2068 JsonValue::try_from(Value::Fixed(3, vec![1, 2, 3]))?,
2069 JsonValue::Array(vec![
2070 JsonValue::Number(1.into()),
2071 JsonValue::Number(2.into()),
2072 JsonValue::Number(3.into())
2073 ])
2074 );
2075 assert_eq!(
2076 JsonValue::try_from(Value::Enum(1, "test_enum".into()))?,
2077 JsonValue::String("test_enum".into())
2078 );
2079 assert_eq!(
2080 JsonValue::try_from(Value::Union(1, Box::new(Value::String("test_enum".into()))))?,
2081 JsonValue::String("test_enum".into())
2082 );
2083 assert_eq!(
2084 JsonValue::try_from(Value::Array(vec![
2085 Value::Int(1),
2086 Value::Int(2),
2087 Value::Int(3)
2088 ]))?,
2089 JsonValue::Array(vec![
2090 JsonValue::Number(1.into()),
2091 JsonValue::Number(2.into()),
2092 JsonValue::Number(3.into())
2093 ])
2094 );
2095 assert_eq!(
2096 JsonValue::try_from(Value::Map(
2097 vec![
2098 ("v1".to_string(), Value::Int(1)),
2099 ("v2".to_string(), Value::Int(2)),
2100 ("v3".to_string(), Value::Int(3))
2101 ]
2102 .into_iter()
2103 .collect()
2104 ))?,
2105 JsonValue::Object(
2106 vec![
2107 ("v1".to_string(), JsonValue::Number(1.into())),
2108 ("v2".to_string(), JsonValue::Number(2.into())),
2109 ("v3".to_string(), JsonValue::Number(3.into()))
2110 ]
2111 .into_iter()
2112 .collect()
2113 )
2114 );
2115 assert_eq!(
2116 JsonValue::try_from(Value::Record(vec![
2117 ("v1".to_string(), Value::Int(1)),
2118 ("v2".to_string(), Value::Int(2)),
2119 ("v3".to_string(), Value::Int(3))
2120 ]))?,
2121 JsonValue::Object(
2122 vec![
2123 ("v1".to_string(), JsonValue::Number(1.into())),
2124 ("v2".to_string(), JsonValue::Number(2.into())),
2125 ("v3".to_string(), JsonValue::Number(3.into()))
2126 ]
2127 .into_iter()
2128 .collect()
2129 )
2130 );
2131 assert_eq!(
2132 JsonValue::try_from(Value::Date(1))?,
2133 JsonValue::Number(1.into())
2134 );
2135 assert_eq!(
2136 JsonValue::try_from(Value::Decimal(vec![1, 2, 3].into()))?,
2137 JsonValue::Array(vec![
2138 JsonValue::Number(1.into()),
2139 JsonValue::Number(2.into()),
2140 JsonValue::Number(3.into())
2141 ])
2142 );
2143 assert_eq!(
2144 JsonValue::try_from(Value::TimeMillis(1))?,
2145 JsonValue::Number(1.into())
2146 );
2147 assert_eq!(
2148 JsonValue::try_from(Value::TimeMicros(1))?,
2149 JsonValue::Number(1.into())
2150 );
2151 assert_eq!(
2152 JsonValue::try_from(Value::TimestampMillis(1))?,
2153 JsonValue::Number(1.into())
2154 );
2155 assert_eq!(
2156 JsonValue::try_from(Value::TimestampMicros(1))?,
2157 JsonValue::Number(1.into())
2158 );
2159 assert_eq!(
2160 JsonValue::try_from(Value::TimestampNanos(1))?,
2161 JsonValue::Number(1.into())
2162 );
2163 assert_eq!(
2164 JsonValue::try_from(Value::LocalTimestampMillis(1))?,
2165 JsonValue::Number(1.into())
2166 );
2167 assert_eq!(
2168 JsonValue::try_from(Value::LocalTimestampMicros(1))?,
2169 JsonValue::Number(1.into())
2170 );
2171 assert_eq!(
2172 JsonValue::try_from(Value::LocalTimestampNanos(1))?,
2173 JsonValue::Number(1.into())
2174 );
2175 assert_eq!(
2176 JsonValue::try_from(Value::Duration(
2177 [
2178 1u8, 2u8, 3u8, 4u8, 5u8, 6u8, 7u8, 8u8, 9u8, 10u8, 11u8, 12u8
2179 ]
2180 .into()
2181 ))?,
2182 JsonValue::Array(vec![
2183 JsonValue::Number(1.into()),
2184 JsonValue::Number(2.into()),
2185 JsonValue::Number(3.into()),
2186 JsonValue::Number(4.into()),
2187 JsonValue::Number(5.into()),
2188 JsonValue::Number(6.into()),
2189 JsonValue::Number(7.into()),
2190 JsonValue::Number(8.into()),
2191 JsonValue::Number(9.into()),
2192 JsonValue::Number(10.into()),
2193 JsonValue::Number(11.into()),
2194 JsonValue::Number(12.into()),
2195 ])
2196 );
2197 assert_eq!(
2198 JsonValue::try_from(Value::Uuid(Uuid::parse_str(
2199 "936DA01F-9ABD-4D9D-80C7-02AF85C822A8"
2200 )?))?,
2201 JsonValue::String("936da01f-9abd-4d9d-80c7-02af85c822a8".into())
2202 );
2203
2204 Ok(())
2205 }
2206
2207 #[test]
2208 fn test_avro_3433_recursive_resolves_record() -> TestResult {
2209 let schema = Schema::parse_str(
2210 r#"
2211 {
2212 "type":"record",
2213 "name":"TestStruct",
2214 "fields": [
2215 {
2216 "name":"a",
2217 "type":{
2218 "type":"record",
2219 "name": "Inner",
2220 "fields": [ {
2221 "name":"z",
2222 "type":"int"
2223 }]
2224 }
2225 },
2226 {
2227 "name":"b",
2228 "type":"Inner"
2229 }
2230 ]
2231 }"#,
2232 )?;
2233
2234 let inner_value1 = Value::Record(vec![("z".into(), Value::Int(3))]);
2235 let inner_value2 = Value::Record(vec![("z".into(), Value::Int(6))]);
2236 let outer = Value::Record(vec![("a".into(), inner_value1), ("b".into(), inner_value2)]);
2237 outer
2238 .resolve(&schema)
2239 .expect("Record definition defined in one field must be available in other field");
2240
2241 Ok(())
2242 }
2243
2244 #[test]
2245 fn test_avro_3433_recursive_resolves_array() -> TestResult {
2246 let schema = Schema::parse_str(
2247 r#"
2248 {
2249 "type":"record",
2250 "name":"TestStruct",
2251 "fields": [
2252 {
2253 "name":"a",
2254 "type":{
2255 "type":"array",
2256 "items": {
2257 "type":"record",
2258 "name": "Inner",
2259 "fields": [ {
2260 "name":"z",
2261 "type":"int"
2262 }]
2263 }
2264 }
2265 },
2266 {
2267 "name":"b",
2268 "type": {
2269 "type":"map",
2270 "values":"Inner"
2271 }
2272 }
2273 ]
2274 }"#,
2275 )?;
2276
2277 let inner_value1 = Value::Record(vec![("z".into(), Value::Int(3))]);
2278 let inner_value2 = Value::Record(vec![("z".into(), Value::Int(6))]);
2279 let outer_value = Value::Record(vec![
2280 ("a".into(), Value::Array(vec![inner_value1])),
2281 (
2282 "b".into(),
2283 Value::Map(vec![("akey".into(), inner_value2)].into_iter().collect()),
2284 ),
2285 ]);
2286 outer_value
2287 .resolve(&schema)
2288 .expect("Record defined in array definition must be resolvable from map");
2289
2290 Ok(())
2291 }
2292
2293 #[test]
2294 fn test_avro_3433_recursive_resolves_map() -> TestResult {
2295 let schema = Schema::parse_str(
2296 r#"
2297 {
2298 "type":"record",
2299 "name":"TestStruct",
2300 "fields": [
2301 {
2302 "name":"a",
2303 "type":{
2304 "type":"record",
2305 "name": "Inner",
2306 "fields": [ {
2307 "name":"z",
2308 "type":"int"
2309 }]
2310 }
2311 },
2312 {
2313 "name":"b",
2314 "type": {
2315 "type":"map",
2316 "values":"Inner"
2317 }
2318 }
2319 ]
2320 }"#,
2321 )?;
2322
2323 let inner_value1 = Value::Record(vec![("z".into(), Value::Int(3))]);
2324 let inner_value2 = Value::Record(vec![("z".into(), Value::Int(6))]);
2325 let outer_value = Value::Record(vec![
2326 ("a".into(), inner_value1),
2327 (
2328 "b".into(),
2329 Value::Map(vec![("akey".into(), inner_value2)].into_iter().collect()),
2330 ),
2331 ]);
2332 outer_value
2333 .resolve(&schema)
2334 .expect("Record defined in record field must be resolvable from map field");
2335
2336 Ok(())
2337 }
2338
2339 #[test]
2340 fn test_avro_3433_recursive_resolves_record_wrapper() -> TestResult {
2341 let schema = Schema::parse_str(
2342 r#"
2343 {
2344 "type":"record",
2345 "name":"TestStruct",
2346 "fields": [
2347 {
2348 "name":"a",
2349 "type":{
2350 "type":"record",
2351 "name": "Inner",
2352 "fields": [ {
2353 "name":"z",
2354 "type":"int"
2355 }]
2356 }
2357 },
2358 {
2359 "name":"b",
2360 "type": {
2361 "type":"record",
2362 "name": "InnerWrapper",
2363 "fields": [ {
2364 "name":"j",
2365 "type":"Inner"
2366 }]
2367 }
2368 }
2369 ]
2370 }"#,
2371 )?;
2372
2373 let inner_value1 = Value::Record(vec![("z".into(), Value::Int(3))]);
2374 let inner_value2 = Value::Record(vec![(
2375 "j".into(),
2376 Value::Record(vec![("z".into(), Value::Int(6))]),
2377 )]);
2378 let outer_value =
2379 Value::Record(vec![("a".into(), inner_value1), ("b".into(), inner_value2)]);
2380 outer_value.resolve(&schema).expect("Record schema defined in field must be resolvable in Record schema defined in other field");
2381
2382 Ok(())
2383 }
2384
2385 #[test]
2386 fn test_avro_3433_recursive_resolves_map_and_array() -> TestResult {
2387 let schema = Schema::parse_str(
2388 r#"
2389 {
2390 "type":"record",
2391 "name":"TestStruct",
2392 "fields": [
2393 {
2394 "name":"a",
2395 "type":{
2396 "type":"map",
2397 "values": {
2398 "type":"record",
2399 "name": "Inner",
2400 "fields": [ {
2401 "name":"z",
2402 "type":"int"
2403 }]
2404 }
2405 }
2406 },
2407 {
2408 "name":"b",
2409 "type": {
2410 "type":"array",
2411 "items":"Inner"
2412 }
2413 }
2414 ]
2415 }"#,
2416 )?;
2417
2418 let inner_value1 = Value::Record(vec![("z".into(), Value::Int(3))]);
2419 let inner_value2 = Value::Record(vec![("z".into(), Value::Int(6))]);
2420 let outer_value = Value::Record(vec![
2421 (
2422 "a".into(),
2423 Value::Map(vec![("akey".into(), inner_value2)].into_iter().collect()),
2424 ),
2425 ("b".into(), Value::Array(vec![inner_value1])),
2426 ]);
2427 outer_value
2428 .resolve(&schema)
2429 .expect("Record defined in map definition must be resolvable from array");
2430
2431 Ok(())
2432 }
2433
2434 #[test]
2435 fn test_avro_3433_recursive_resolves_union() -> TestResult {
2436 let schema = Schema::parse_str(
2437 r#"
2438 {
2439 "type":"record",
2440 "name":"TestStruct",
2441 "fields": [
2442 {
2443 "name":"a",
2444 "type":["null", {
2445 "type":"record",
2446 "name": "Inner",
2447 "fields": [ {
2448 "name":"z",
2449 "type":"int"
2450 }]
2451 }]
2452 },
2453 {
2454 "name":"b",
2455 "type":"Inner"
2456 }
2457 ]
2458 }"#,
2459 )?;
2460
2461 let inner_value1 = Value::Record(vec![("z".into(), Value::Int(3))]);
2462 let inner_value2 = Value::Record(vec![("z".into(), Value::Int(6))]);
2463 let outer1 = Value::Record(vec![
2464 ("a".into(), inner_value1),
2465 ("b".into(), inner_value2.clone()),
2466 ]);
2467 outer1
2468 .resolve(&schema)
2469 .expect("Record definition defined in union must be resolved in other field");
2470 let outer2 = Value::Record(vec![("a".into(), Value::Null), ("b".into(), inner_value2)]);
2471 outer2
2472 .resolve(&schema)
2473 .expect("Record definition defined in union must be resolved in other field");
2474
2475 Ok(())
2476 }
2477
2478 #[test]
2479 fn test_avro_3461_test_multi_level_resolve_outer_namespace() -> TestResult {
2480 let schema = r#"
2481 {
2482 "name": "record_name",
2483 "namespace": "space",
2484 "type": "record",
2485 "fields": [
2486 {
2487 "name": "outer_field_1",
2488 "type": [
2489 "null",
2490 {
2491 "type": "record",
2492 "name": "middle_record_name",
2493 "fields":[
2494 {
2495 "name":"middle_field_1",
2496 "type":[
2497 "null",
2498 {
2499 "type":"record",
2500 "name":"inner_record_name",
2501 "fields":[
2502 {
2503 "name":"inner_field_1",
2504 "type":"double"
2505 }
2506 ]
2507 }
2508 ]
2509 }
2510 ]
2511 }
2512 ]
2513 },
2514 {
2515 "name": "outer_field_2",
2516 "type" : "space.inner_record_name"
2517 }
2518 ]
2519 }
2520 "#;
2521 let schema = Schema::parse_str(schema)?;
2522 let inner_record = Value::Record(vec![("inner_field_1".into(), Value::Double(5.4))]);
2523 let middle_record_variation_1 = Value::Record(vec![(
2524 "middle_field_1".into(),
2525 Value::Union(0, Box::new(Value::Null)),
2526 )]);
2527 let middle_record_variation_2 = Value::Record(vec![(
2528 "middle_field_1".into(),
2529 Value::Union(1, Box::new(inner_record.clone())),
2530 )]);
2531 let outer_record_variation_1 = Value::Record(vec![
2532 (
2533 "outer_field_1".into(),
2534 Value::Union(0, Box::new(Value::Null)),
2535 ),
2536 ("outer_field_2".into(), inner_record.clone()),
2537 ]);
2538 let outer_record_variation_2 = Value::Record(vec![
2539 (
2540 "outer_field_1".into(),
2541 Value::Union(1, Box::new(middle_record_variation_1)),
2542 ),
2543 ("outer_field_2".into(), inner_record.clone()),
2544 ]);
2545 let outer_record_variation_3 = Value::Record(vec![
2546 (
2547 "outer_field_1".into(),
2548 Value::Union(1, Box::new(middle_record_variation_2)),
2549 ),
2550 ("outer_field_2".into(), inner_record),
2551 ]);
2552
2553 outer_record_variation_1
2554 .resolve(&schema)
2555 .expect("Should be able to resolve value to the schema that is it's definition");
2556 outer_record_variation_2
2557 .resolve(&schema)
2558 .expect("Should be able to resolve value to the schema that is it's definition");
2559 outer_record_variation_3
2560 .resolve(&schema)
2561 .expect("Should be able to resolve value to the schema that is it's definition");
2562
2563 Ok(())
2564 }
2565
2566 #[test]
2567 fn test_avro_3461_test_multi_level_resolve_middle_namespace() -> TestResult {
2568 let schema = r#"
2569 {
2570 "name": "record_name",
2571 "namespace": "space",
2572 "type": "record",
2573 "fields": [
2574 {
2575 "name": "outer_field_1",
2576 "type": [
2577 "null",
2578 {
2579 "type": "record",
2580 "name": "middle_record_name",
2581 "namespace":"middle_namespace",
2582 "fields":[
2583 {
2584 "name":"middle_field_1",
2585 "type":[
2586 "null",
2587 {
2588 "type":"record",
2589 "name":"inner_record_name",
2590 "fields":[
2591 {
2592 "name":"inner_field_1",
2593 "type":"double"
2594 }
2595 ]
2596 }
2597 ]
2598 }
2599 ]
2600 }
2601 ]
2602 },
2603 {
2604 "name": "outer_field_2",
2605 "type" : "middle_namespace.inner_record_name"
2606 }
2607 ]
2608 }
2609 "#;
2610 let schema = Schema::parse_str(schema)?;
2611 let inner_record = Value::Record(vec![("inner_field_1".into(), Value::Double(5.4))]);
2612 let middle_record_variation_1 = Value::Record(vec![(
2613 "middle_field_1".into(),
2614 Value::Union(0, Box::new(Value::Null)),
2615 )]);
2616 let middle_record_variation_2 = Value::Record(vec![(
2617 "middle_field_1".into(),
2618 Value::Union(1, Box::new(inner_record.clone())),
2619 )]);
2620 let outer_record_variation_1 = Value::Record(vec![
2621 (
2622 "outer_field_1".into(),
2623 Value::Union(0, Box::new(Value::Null)),
2624 ),
2625 ("outer_field_2".into(), inner_record.clone()),
2626 ]);
2627 let outer_record_variation_2 = Value::Record(vec![
2628 (
2629 "outer_field_1".into(),
2630 Value::Union(1, Box::new(middle_record_variation_1)),
2631 ),
2632 ("outer_field_2".into(), inner_record.clone()),
2633 ]);
2634 let outer_record_variation_3 = Value::Record(vec![
2635 (
2636 "outer_field_1".into(),
2637 Value::Union(1, Box::new(middle_record_variation_2)),
2638 ),
2639 ("outer_field_2".into(), inner_record),
2640 ]);
2641
2642 outer_record_variation_1
2643 .resolve(&schema)
2644 .expect("Should be able to resolve value to the schema that is it's definition");
2645 outer_record_variation_2
2646 .resolve(&schema)
2647 .expect("Should be able to resolve value to the schema that is it's definition");
2648 outer_record_variation_3
2649 .resolve(&schema)
2650 .expect("Should be able to resolve value to the schema that is it's definition");
2651
2652 Ok(())
2653 }
2654
2655 #[test]
2656 fn test_avro_3461_test_multi_level_resolve_inner_namespace() -> TestResult {
2657 let schema = r#"
2658 {
2659 "name": "record_name",
2660 "namespace": "space",
2661 "type": "record",
2662 "fields": [
2663 {
2664 "name": "outer_field_1",
2665 "type": [
2666 "null",
2667 {
2668 "type": "record",
2669 "name": "middle_record_name",
2670 "namespace":"middle_namespace",
2671 "fields":[
2672 {
2673 "name":"middle_field_1",
2674 "type":[
2675 "null",
2676 {
2677 "type":"record",
2678 "name":"inner_record_name",
2679 "namespace":"inner_namespace",
2680 "fields":[
2681 {
2682 "name":"inner_field_1",
2683 "type":"double"
2684 }
2685 ]
2686 }
2687 ]
2688 }
2689 ]
2690 }
2691 ]
2692 },
2693 {
2694 "name": "outer_field_2",
2695 "type" : "inner_namespace.inner_record_name"
2696 }
2697 ]
2698 }
2699 "#;
2700 let schema = Schema::parse_str(schema)?;
2701
2702 let inner_record = Value::Record(vec![("inner_field_1".into(), Value::Double(5.4))]);
2703 let middle_record_variation_1 = Value::Record(vec![(
2704 "middle_field_1".into(),
2705 Value::Union(0, Box::new(Value::Null)),
2706 )]);
2707 let middle_record_variation_2 = Value::Record(vec![(
2708 "middle_field_1".into(),
2709 Value::Union(1, Box::new(inner_record.clone())),
2710 )]);
2711 let outer_record_variation_1 = Value::Record(vec![
2712 (
2713 "outer_field_1".into(),
2714 Value::Union(0, Box::new(Value::Null)),
2715 ),
2716 ("outer_field_2".into(), inner_record.clone()),
2717 ]);
2718 let outer_record_variation_2 = Value::Record(vec![
2719 (
2720 "outer_field_1".into(),
2721 Value::Union(1, Box::new(middle_record_variation_1)),
2722 ),
2723 ("outer_field_2".into(), inner_record.clone()),
2724 ]);
2725 let outer_record_variation_3 = Value::Record(vec![
2726 (
2727 "outer_field_1".into(),
2728 Value::Union(1, Box::new(middle_record_variation_2)),
2729 ),
2730 ("outer_field_2".into(), inner_record),
2731 ]);
2732
2733 outer_record_variation_1
2734 .resolve(&schema)
2735 .expect("Should be able to resolve value to the schema that is it's definition");
2736 outer_record_variation_2
2737 .resolve(&schema)
2738 .expect("Should be able to resolve value to the schema that is it's definition");
2739 outer_record_variation_3
2740 .resolve(&schema)
2741 .expect("Should be able to resolve value to the schema that is it's definition");
2742
2743 Ok(())
2744 }
2745
2746 #[test]
2747 fn test_avro_3460_validation_with_refs() -> TestResult {
2748 let schema = Schema::parse_str(
2749 r#"
2750 {
2751 "type":"record",
2752 "name":"TestStruct",
2753 "fields": [
2754 {
2755 "name":"a",
2756 "type":{
2757 "type":"record",
2758 "name": "Inner",
2759 "fields": [ {
2760 "name":"z",
2761 "type":"int"
2762 }]
2763 }
2764 },
2765 {
2766 "name":"b",
2767 "type":"Inner"
2768 }
2769 ]
2770 }"#,
2771 )?;
2772
2773 let inner_value_right = Value::Record(vec![("z".into(), Value::Int(3))]);
2774 let inner_value_wrong1 = Value::Record(vec![("z".into(), Value::Null)]);
2775 let inner_value_wrong2 = Value::Record(vec![("a".into(), Value::String("testing".into()))]);
2776 let outer1 = Value::Record(vec![
2777 ("a".into(), inner_value_right.clone()),
2778 ("b".into(), inner_value_wrong1),
2779 ]);
2780
2781 let outer2 = Value::Record(vec![
2782 ("a".into(), inner_value_right),
2783 ("b".into(), inner_value_wrong2),
2784 ]);
2785
2786 assert!(
2787 !outer1.validate(&schema),
2788 "field b record is invalid against the schema"
2789 ); assert!(
2791 !outer2.validate(&schema),
2792 "field b record is invalid against the schema"
2793 ); Ok(())
2796 }
2797
2798 #[test]
2799 fn test_avro_3460_validation_with_refs_real_struct() -> TestResult {
2800 use serde::Serialize;
2801
2802 #[derive(Serialize, Clone)]
2803 struct TestInner {
2804 z: i32,
2805 }
2806
2807 #[derive(Serialize)]
2808 struct TestRefSchemaStruct1 {
2809 a: TestInner,
2810 b: String, }
2812
2813 #[derive(Serialize)]
2814 struct TestRefSchemaStruct2 {
2815 a: TestInner,
2816 b: i32, }
2818
2819 #[derive(Serialize)]
2820 struct TestRefSchemaStruct3 {
2821 a: TestInner,
2822 b: Option<TestInner>, }
2824
2825 let schema = Schema::parse_str(
2826 r#"
2827 {
2828 "type":"record",
2829 "name":"TestStruct",
2830 "fields": [
2831 {
2832 "name":"a",
2833 "type":{
2834 "type":"record",
2835 "name": "Inner",
2836 "fields": [ {
2837 "name":"z",
2838 "type":"int"
2839 }]
2840 }
2841 },
2842 {
2843 "name":"b",
2844 "type":"Inner"
2845 }
2846 ]
2847 }"#,
2848 )?;
2849
2850 let test_inner = TestInner { z: 3 };
2851 let test_outer1 = TestRefSchemaStruct1 {
2852 a: test_inner.clone(),
2853 b: "testing".into(),
2854 };
2855 let test_outer2 = TestRefSchemaStruct2 {
2856 a: test_inner.clone(),
2857 b: 24,
2858 };
2859 let test_outer3 = TestRefSchemaStruct3 {
2860 a: test_inner,
2861 b: None,
2862 };
2863
2864 let test_outer1: Value = to_value(test_outer1)?;
2865 let test_outer2: Value = to_value(test_outer2)?;
2866 let test_outer3: Value = to_value(test_outer3)?;
2867
2868 assert!(
2869 !test_outer1.validate(&schema),
2870 "field b record is invalid against the schema"
2871 );
2872 assert!(
2873 !test_outer2.validate(&schema),
2874 "field b record is invalid against the schema"
2875 );
2876 assert!(
2877 !test_outer3.validate(&schema),
2878 "field b record is invalid against the schema"
2879 );
2880
2881 Ok(())
2882 }
2883
2884 fn avro_3674_with_or_without_namespace(with_namespace: bool) -> TestResult {
2885 use serde::Serialize;
2886
2887 let schema_str = r#"
2888 {
2889 "type": "record",
2890 "name": "NamespacedMessage",
2891 [NAMESPACE]
2892 "fields": [
2893 {
2894 "name": "field_a",
2895 "type": {
2896 "type": "record",
2897 "name": "NestedMessage",
2898 "fields": [
2899 {
2900 "name": "enum_a",
2901 "type": {
2902 "type": "enum",
2903 "name": "EnumType",
2904 "symbols": ["SYMBOL_1", "SYMBOL_2"],
2905 "default": "SYMBOL_1"
2906 }
2907 },
2908 {
2909 "name": "enum_b",
2910 "type": "EnumType"
2911 }
2912 ]
2913 }
2914 }
2915 ]
2916 }
2917 "#;
2918 let schema_str = schema_str.replace(
2919 "[NAMESPACE]",
2920 if with_namespace {
2921 r#""namespace": "com.domain","#
2922 } else {
2923 ""
2924 },
2925 );
2926
2927 let schema = Schema::parse_str(&schema_str)?;
2928
2929 #[derive(Serialize)]
2930 enum EnumType {
2931 #[serde(rename = "SYMBOL_1")]
2932 Symbol1,
2933 #[serde(rename = "SYMBOL_2")]
2934 Symbol2,
2935 }
2936
2937 #[derive(Serialize)]
2938 struct FieldA {
2939 enum_a: EnumType,
2940 enum_b: EnumType,
2941 }
2942
2943 #[derive(Serialize)]
2944 struct NamespacedMessage {
2945 field_a: FieldA,
2946 }
2947
2948 let msg = NamespacedMessage {
2949 field_a: FieldA {
2950 enum_a: EnumType::Symbol2,
2951 enum_b: EnumType::Symbol1,
2952 },
2953 };
2954
2955 let test_value: Value = to_value(msg)?;
2956 assert!(test_value.validate(&schema), "test_value should validate");
2957 assert!(
2958 test_value.resolve(&schema).is_ok(),
2959 "test_value should resolve"
2960 );
2961
2962 Ok(())
2963 }
2964
2965 #[test]
2966 fn test_avro_3674_validate_no_namespace_resolution() -> TestResult {
2967 avro_3674_with_or_without_namespace(false)
2968 }
2969
2970 #[test]
2971 fn test_avro_3674_validate_with_namespace_resolution() -> TestResult {
2972 avro_3674_with_or_without_namespace(true)
2973 }
2974
2975 fn avro_3688_schema_resolution_panic(set_field_b: bool) -> TestResult {
2976 use serde::{Deserialize, Serialize};
2977
2978 let schema_str = r#"{
2979 "type": "record",
2980 "name": "Message",
2981 "fields": [
2982 {
2983 "name": "field_a",
2984 "type": [
2985 "null",
2986 {
2987 "name": "Inner",
2988 "type": "record",
2989 "fields": [
2990 {
2991 "name": "inner_a",
2992 "type": "string"
2993 }
2994 ]
2995 }
2996 ],
2997 "default": null
2998 },
2999 {
3000 "name": "field_b",
3001 "type": [
3002 "null",
3003 "Inner"
3004 ],
3005 "default": null
3006 }
3007 ]
3008 }"#;
3009
3010 #[derive(Serialize, Deserialize)]
3011 struct Inner {
3012 inner_a: String,
3013 }
3014
3015 #[derive(Serialize, Deserialize)]
3016 struct Message {
3017 field_a: Option<Inner>,
3018 field_b: Option<Inner>,
3019 }
3020
3021 let schema = Schema::parse_str(schema_str)?;
3022
3023 let msg = Message {
3024 field_a: Some(Inner {
3025 inner_a: "foo".to_string(),
3026 }),
3027 field_b: if set_field_b {
3028 Some(Inner {
3029 inner_a: "bar".to_string(),
3030 })
3031 } else {
3032 None
3033 },
3034 };
3035
3036 let test_value: Value = to_value(msg)?;
3037 assert!(test_value.validate(&schema), "test_value should validate");
3038 assert!(
3039 test_value.resolve(&schema).is_ok(),
3040 "test_value should resolve"
3041 );
3042
3043 Ok(())
3044 }
3045
3046 #[test]
3047 fn test_avro_3688_field_b_not_set() -> TestResult {
3048 avro_3688_schema_resolution_panic(false)
3049 }
3050
3051 #[test]
3052 fn test_avro_3688_field_b_set() -> TestResult {
3053 avro_3688_schema_resolution_panic(true)
3054 }
3055
3056 #[test]
3057 fn test_avro_3764_use_resolve_schemata() -> TestResult {
3058 let referenced_schema =
3059 r#"{"name": "enumForReference", "type": "enum", "symbols": ["A", "B"]}"#;
3060 let main_schema = r#"{"name": "recordWithReference", "type": "record", "fields": [{"name": "reference", "type": "enumForReference"}]}"#;
3061
3062 let value: serde_json::Value = serde_json::from_str(
3063 r#"
3064 {
3065 "reference": "A"
3066 }
3067 "#,
3068 )?;
3069
3070 let avro_value = Value::try_from(value)?;
3071
3072 let schemas = Schema::parse_list([main_schema, referenced_schema])?;
3073
3074 let main_schema = schemas.first().unwrap();
3075 let schemata: Vec<_> = schemas.iter().skip(1).collect();
3076
3077 let resolve_result = avro_value.clone().resolve_schemata(main_schema, schemata);
3078
3079 assert!(
3080 resolve_result.is_ok(),
3081 "result of resolving with schemata should be ok, got: {resolve_result:?}"
3082 );
3083
3084 let resolve_result = avro_value.resolve(main_schema);
3085 assert!(
3086 resolve_result.is_err(),
3087 "result of resolving without schemata should be err, got: {resolve_result:?}"
3088 );
3089
3090 Ok(())
3091 }
3092
3093 #[test]
3094 fn test_avro_3767_union_resolve_complex_refs() -> TestResult {
3095 let referenced_enum =
3096 r#"{"name": "enumForReference", "type": "enum", "symbols": ["A", "B"]}"#;
3097 let referenced_record = r#"{"name": "recordForReference", "type": "record", "fields": [{"name": "refInRecord", "type": "enumForReference"}]}"#;
3098 let main_schema = r#"{"name": "recordWithReference", "type": "record", "fields": [{"name": "reference", "type": ["null", "recordForReference"]}]}"#;
3099
3100 let value: serde_json::Value = serde_json::from_str(
3101 r#"
3102 {
3103 "reference": {
3104 "refInRecord": "A"
3105 }
3106 }
3107 "#,
3108 )?;
3109
3110 let avro_value = Value::try_from(value)?;
3111
3112 let schemata = Schema::parse_list([referenced_enum, referenced_record, main_schema])?;
3113
3114 let main_schema = schemata.last().unwrap();
3115 let other_schemata: Vec<&Schema> = schemata.iter().take(2).collect();
3116
3117 let resolve_result = avro_value.resolve_schemata(main_schema, other_schemata)?;
3118
3119 let schemata_ref = schemata.iter().collect::<Vec<_>>();
3120 assert!(
3121 resolve_result.validate_schemata(&schemata_ref),
3122 "result of validation with schemata should be true"
3123 );
3124
3125 Ok(())
3126 }
3127
3128 #[test]
3129 fn test_avro_3782_incorrect_decimal_resolving() -> TestResult {
3130 let schema = r#"{"name": "decimalSchema", "logicalType": "decimal", "type": "fixed", "precision": 8, "scale": 0, "size": 8}"#;
3131
3132 let avro_value = Value::Decimal(Decimal::from(
3133 BigInt::from(12345678u32).to_signed_bytes_be(),
3134 ));
3135 let schema = Schema::parse_str(schema)?;
3136 let resolve_result = avro_value.resolve(&schema);
3137 assert!(
3138 resolve_result.is_ok(),
3139 "resolve result must be ok, got: {resolve_result:?}"
3140 );
3141
3142 Ok(())
3143 }
3144
3145 #[test]
3146 fn test_avro_3779_bigdecimal_resolving() -> TestResult {
3147 let schema =
3148 r#"{"name": "bigDecimalSchema", "logicalType": "big-decimal", "type": "bytes" }"#;
3149
3150 let avro_value = Value::BigDecimal(BigDecimal::from(12345678u32));
3151 let schema = Schema::parse_str(schema)?;
3152 let resolve_result: AvroResult<Value> = avro_value.resolve(&schema);
3153 assert!(
3154 resolve_result.is_ok(),
3155 "resolve result must be ok, got: {resolve_result:?}"
3156 );
3157
3158 Ok(())
3159 }
3160
3161 #[test]
3162 fn test_avro_3892_resolve_fixed_from_bytes() -> TestResult {
3163 let value = Value::Bytes(vec![97, 98, 99]);
3164 assert_eq!(
3165 value.resolve(&Schema::Fixed(FixedSchema {
3166 name: "test".try_into()?,
3167 aliases: None,
3168 doc: None,
3169 size: 3,
3170 attributes: Default::default()
3171 }))?,
3172 Value::Fixed(3, vec![97, 98, 99])
3173 );
3174
3175 let value = Value::Bytes(vec![97, 99]);
3176 assert!(
3177 value
3178 .resolve(&Schema::Fixed(FixedSchema {
3179 name: "test".try_into()?,
3180 aliases: None,
3181 doc: None,
3182 size: 3,
3183 attributes: Default::default()
3184 }))
3185 .is_err(),
3186 );
3187
3188 let value = Value::Bytes(vec![97, 98, 99, 100]);
3189 assert!(
3190 value
3191 .resolve(&Schema::Fixed(FixedSchema {
3192 name: "test".try_into()?,
3193 aliases: None,
3194 doc: None,
3195 size: 3,
3196 attributes: Default::default()
3197 }))
3198 .is_err(),
3199 );
3200
3201 Ok(())
3202 }
3203
3204 #[test]
3205 fn avro_3928_from_serde_value_to_types_value() -> TestResult {
3206 assert_eq!(Value::try_from(serde_json::Value::Null)?, Value::Null);
3207 assert_eq!(Value::try_from(json!(true))?, Value::Boolean(true));
3208 assert_eq!(Value::try_from(json!(false))?, Value::Boolean(false));
3209 assert_eq!(Value::try_from(json!(0))?, Value::Int(0));
3210 assert_eq!(Value::try_from(json!(i32::MIN))?, Value::Int(i32::MIN));
3211 assert_eq!(Value::try_from(json!(i32::MAX))?, Value::Int(i32::MAX));
3212 assert_eq!(
3213 Value::try_from(json!(i32::MIN as i64 - 1))?,
3214 Value::Long(i32::MIN as i64 - 1)
3215 );
3216 assert_eq!(
3217 Value::try_from(json!(i32::MAX as i64 + 1))?,
3218 Value::Long(i32::MAX as i64 + 1)
3219 );
3220 assert_eq!(Value::try_from(json!(1.23))?, Value::Double(1.23));
3221 assert_eq!(Value::try_from(json!(-1.23))?, Value::Double(-1.23));
3222 assert_eq!(
3223 Value::try_from(json!(u64::MIN))?,
3224 Value::Int(u64::MIN as i32)
3225 );
3226 assert_eq!(
3227 Value::try_from(json!("some text"))?,
3228 Value::String("some text".into())
3229 );
3230 assert_eq!(
3231 Value::try_from(json!(["text1", "text2", "text3"]))?,
3232 Value::Array(vec![
3233 Value::String("text1".into()),
3234 Value::String("text2".into()),
3235 Value::String("text3".into())
3236 ])
3237 );
3238 assert_eq!(
3239 Value::try_from(json!({"key1": "value1", "key2": "value2"}))?,
3240 Value::Map(
3241 vec![
3242 ("key1".into(), Value::String("value1".into())),
3243 ("key2".into(), Value::String("value2".into()))
3244 ]
3245 .into_iter()
3246 .collect()
3247 )
3248 );
3249 Ok(())
3250 }
3251
3252 #[test]
3253 fn avro_4024_resolve_double_from_unknown_string_err() -> TestResult {
3254 let schema = Schema::parse_str(r#"{"type": "double"}"#)?;
3255 let value = Value::String("unknown".to_owned());
3256 match value.resolve(&schema).map_err(Error::into_details) {
3257 Err(err @ Details::GetDouble(_)) => {
3258 assert_eq!(
3259 format!("{err:?}"),
3260 r#"Expected Value::Double, Value::Float, Value::Int, Value::Long or Value::String ("NaN", "INF", "Infinity", "-INF" or "-Infinity"), got: String("unknown")"#
3261 );
3262 }
3263 other => {
3264 panic!("Expected Details::GetDouble, got {other:?}");
3265 }
3266 }
3267 Ok(())
3268 }
3269
3270 #[test]
3271 fn avro_4024_resolve_float_from_unknown_string_err() -> TestResult {
3272 let schema = Schema::parse_str(r#"{"type": "float"}"#)?;
3273 let value = Value::String("unknown".to_owned());
3274 match value.resolve(&schema).map_err(Error::into_details) {
3275 Err(err @ Details::GetFloat(_)) => {
3276 assert_eq!(
3277 format!("{err:?}"),
3278 r#"Expected Value::Float, Value::Double, Value::Int, Value::Long or Value::String ("NaN", "INF", "Infinity", "-INF" or "-Infinity"), got: String("unknown")"#
3279 );
3280 }
3281 other => {
3282 panic!("Expected Details::GetFloat, got {other:?}");
3283 }
3284 }
3285 Ok(())
3286 }
3287
3288 #[test]
3289 fn avro_4029_resolve_from_unsupported_err() -> TestResult {
3290 let data: Vec<(&str, Value, &str)> = vec![
3291 (
3292 r#"{ "name": "NAME", "type": "int" }"#,
3293 Value::Float(123_f32),
3294 "Expected Value::Int, got: Float(123.0)",
3295 ),
3296 (
3297 r#"{ "name": "NAME", "type": "fixed", "size": 3 }"#,
3298 Value::Float(123_f32),
3299 "String expected for fixed, got: Float(123.0)",
3300 ),
3301 (
3302 r#"{ "name": "NAME", "type": "bytes" }"#,
3303 Value::Float(123_f32),
3304 "Expected Value::Bytes, got: Float(123.0)",
3305 ),
3306 (
3307 r#"{ "name": "NAME", "type": "string", "logicalType": "uuid" }"#,
3308 Value::String("abc-1234".into()),
3309 "Failed to convert &str to UUID: invalid group count: expected 5, found 2",
3310 ),
3311 (
3312 r#"{ "name": "NAME", "type": "string", "logicalType": "uuid" }"#,
3313 Value::Float(123_f32),
3314 "Expected Value::Uuid, got: Float(123.0)",
3315 ),
3316 (
3317 r#"{ "name": "NAME", "type": "bytes", "logicalType": "big-decimal" }"#,
3318 Value::Float(123_f32),
3319 "Expected Value::BigDecimal, got: Float(123.0)",
3320 ),
3321 (
3322 r#"{ "name": "NAME", "type": "fixed", "size": 12, "logicalType": "duration" }"#,
3323 Value::Float(123_f32),
3324 "Expected Value::Duration or Value::Fixed(12), got: Float(123.0)",
3325 ),
3326 (
3327 r#"{ "name": "NAME", "type": "bytes", "logicalType": "decimal", "precision": 4, "scale": 3 }"#,
3328 Value::Float(123_f32),
3329 "Expected Value::Decimal, Value::Bytes or Value::Fixed, got: Float(123.0)",
3330 ),
3331 (
3332 r#"{ "name": "NAME", "type": "bytes" }"#,
3333 Value::Array(vec![Value::Long(256_i64)]),
3334 "Unable to convert to u8, got Int(256)",
3335 ),
3336 (
3337 r#"{ "name": "NAME", "type": "int", "logicalType": "date" }"#,
3338 Value::Float(123_f32),
3339 "Expected Value::Date or Value::Int, got: Float(123.0)",
3340 ),
3341 (
3342 r#"{ "name": "NAME", "type": "int", "logicalType": "time-millis" }"#,
3343 Value::Float(123_f32),
3344 "Expected Value::TimeMillis or Value::Int, got: Float(123.0)",
3345 ),
3346 (
3347 r#"{ "name": "NAME", "type": "long", "logicalType": "time-micros" }"#,
3348 Value::Float(123_f32),
3349 "Expected Value::TimeMicros, Value::Long or Value::Int, got: Float(123.0)",
3350 ),
3351 (
3352 r#"{ "name": "NAME", "type": "long", "logicalType": "timestamp-millis" }"#,
3353 Value::Float(123_f32),
3354 "Expected Value::TimestampMillis, Value::Long or Value::Int, got: Float(123.0)",
3355 ),
3356 (
3357 r#"{ "name": "NAME", "type": "long", "logicalType": "timestamp-micros" }"#,
3358 Value::Float(123_f32),
3359 "Expected Value::TimestampMicros, Value::Long or Value::Int, got: Float(123.0)",
3360 ),
3361 (
3362 r#"{ "name": "NAME", "type": "long", "logicalType": "timestamp-nanos" }"#,
3363 Value::Float(123_f32),
3364 "Expected Value::TimestampNanos, Value::Long or Value::Int, got: Float(123.0)",
3365 ),
3366 (
3367 r#"{ "name": "NAME", "type": "long", "logicalType": "local-timestamp-millis" }"#,
3368 Value::Float(123_f32),
3369 "Expected Value::LocalTimestampMillis, Value::Long or Value::Int, got: Float(123.0)",
3370 ),
3371 (
3372 r#"{ "name": "NAME", "type": "long", "logicalType": "local-timestamp-micros" }"#,
3373 Value::Float(123_f32),
3374 "Expected Value::LocalTimestampMicros, Value::Long or Value::Int, got: Float(123.0)",
3375 ),
3376 (
3377 r#"{ "name": "NAME", "type": "long", "logicalType": "local-timestamp-nanos" }"#,
3378 Value::Float(123_f32),
3379 "Expected Value::LocalTimestampNanos, Value::Long or Value::Int, got: Float(123.0)",
3380 ),
3381 (
3382 r#"{ "name": "NAME", "type": "null" }"#,
3383 Value::Float(123_f32),
3384 "Expected Value::Null, got: Float(123.0)",
3385 ),
3386 (
3387 r#"{ "name": "NAME", "type": "boolean" }"#,
3388 Value::Float(123_f32),
3389 "Expected Value::Boolean, got: Float(123.0)",
3390 ),
3391 (
3392 r#"{ "name": "NAME", "type": "int" }"#,
3393 Value::Float(123_f32),
3394 "Expected Value::Int, got: Float(123.0)",
3395 ),
3396 (
3397 r#"{ "name": "NAME", "type": "long" }"#,
3398 Value::Float(123_f32),
3399 "Expected Value::Long or Value::Int, got: Float(123.0)",
3400 ),
3401 (
3402 r#"{ "name": "NAME", "type": "float" }"#,
3403 Value::Boolean(false),
3404 r#"Expected Value::Float, Value::Double, Value::Int, Value::Long or Value::String ("NaN", "INF", "Infinity", "-INF" or "-Infinity"), got: Boolean(false)"#,
3405 ),
3406 (
3407 r#"{ "name": "NAME", "type": "double" }"#,
3408 Value::Boolean(false),
3409 r#"Expected Value::Double, Value::Float, Value::Int, Value::Long or Value::String ("NaN", "INF", "Infinity", "-INF" or "-Infinity"), got: Boolean(false)"#,
3410 ),
3411 (
3412 r#"{ "name": "NAME", "type": "string" }"#,
3413 Value::Boolean(false),
3414 "Expected Value::String, Value::Bytes or Value::Fixed, got: Boolean(false)",
3415 ),
3416 (
3417 r#"{ "name": "NAME", "type": "enum", "symbols": ["one", "two"] }"#,
3418 Value::Boolean(false),
3419 "Expected Value::Enum, got: Boolean(false)",
3420 ),
3421 ];
3422
3423 for (schema_str, value, expected_error) in data {
3424 let schema = Schema::parse_str(schema_str)?;
3425 match value.resolve(&schema) {
3426 Err(error) => {
3427 assert_eq!(format!("{error}"), expected_error);
3428 }
3429 other => {
3430 panic!("Expected '{expected_error}', got {other:?}");
3431 }
3432 }
3433 }
3434 Ok(())
3435 }
3436
3437 #[test]
3438 fn avro_rs_130_get_from_record() -> TestResult {
3439 let schema = r#"
3440 {
3441 "type": "record",
3442 "name": "NamespacedMessage",
3443 "namespace": "space",
3444 "fields": [
3445 {
3446 "name": "foo",
3447 "type": "string"
3448 },
3449 {
3450 "name": "bar",
3451 "type": "long"
3452 }
3453 ]
3454 }
3455 "#;
3456
3457 let schema = Schema::parse_str(schema)?;
3458 let mut record = Record::new(&schema).unwrap();
3459 record.put("foo", "hello");
3460 record.put("bar", 123_i64);
3461
3462 assert_eq!(
3463 record.get("foo").unwrap(),
3464 &Value::String("hello".to_string())
3465 );
3466 assert_eq!(record.get("bar").unwrap(), &Value::Long(123));
3467
3468 assert_eq!(record.get("baz"), None);
3470
3471 Ok(())
3472 }
3473
3474 #[test]
3475 fn avro_rs_392_resolve_long_to_int() {
3476 let value = Value::Long(0);
3478 value.resolve(&Schema::Int).unwrap();
3479 let value = Value::Long(i64::MAX);
3481 assert!(matches!(
3482 value.resolve(&Schema::Int).unwrap_err().details(),
3483 Details::ZagI32(_, _)
3484 ));
3485 }
3486
3487 #[test]
3488 fn avro_rs_450_serde_json_number_u64_max() {
3489 assert_eq!(
3490 Value::try_from(json!(u64::MAX))
3491 .unwrap_err()
3492 .into_details()
3493 .to_string(),
3494 "JSON number 18446744073709551615 could not be converted into an Avro value as it's too large"
3495 );
3496 }
3497}