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