@@ -266,9 +266,9 @@ pub(super) mod _serde {
266266 use serde:: { Deserialize , Serialize } ;
267267
268268 use super :: { Operation , Snapshot , Summary } ;
269- use crate :: Error ;
270269 use crate :: spec:: SchemaId ;
271270 use crate :: spec:: snapshot:: SnapshotRowRange ;
271+ use crate :: { Error , ErrorKind } ;
272272
273273 #[ derive( Debug , Serialize , Deserialize , PartialEq , Eq ) ]
274274 #[ serde( rename_all = "kebab-case" ) ]
@@ -408,9 +408,19 @@ pub(super) mod _serde {
408408 timestamp_ms : v1. timestamp_ms ,
409409 manifest_list : match ( v1. manifest_list , v1. manifests ) {
410410 ( Some ( file) , None ) => file,
411- ( Some ( _) , Some ( _) ) => "Invalid v1 snapshot, when manifest list provided, manifest files should be omitted" . to_string ( ) ,
412- ( None , _) => "Unsupported v1 snapshot, only manifest list is supported" . to_string ( )
413- } ,
411+ ( Some ( _) , Some ( _) ) => {
412+ return Err ( Error :: new (
413+ ErrorKind :: Unexpected ,
414+ "v1 snapshot invariant violated: manifest_list and manifests are both set" ,
415+ ) ) ;
416+ }
417+ ( None , _) => {
418+ return Err ( Error :: new (
419+ ErrorKind :: FeatureUnsupported ,
420+ "v1 snapshot invariant violated: manifest_list is missing" ,
421+ ) ) ;
422+ }
423+ } ,
414424 summary : v1. summary . unwrap_or ( Summary {
415425 operation : Operation :: default ( ) ,
416426 additional_properties : HashMap :: new ( ) ,
@@ -517,6 +527,7 @@ mod tests {
517527
518528 use chrono:: { TimeZone , Utc } ;
519529
530+ use crate :: spec:: TableMetadata ;
520531 use crate :: spec:: snapshot:: _serde:: SnapshotV1 ;
521532 use crate :: spec:: snapshot:: { Operation , Snapshot , Summary } ;
522533
@@ -604,6 +615,73 @@ mod tests {
604615 ) ;
605616 }
606617
618+ #[ test]
619+ fn test_v1_snapshot_with_manifest_list_and_manifests ( ) {
620+ {
621+ let metadata = r#"
622+ {
623+ "format-version": 1,
624+ "table-uuid": "d20125c8-7284-442c-9aea-15fee620737c",
625+ "location": "s3://bucket/test/location",
626+ "last-updated-ms": 1700000000000,
627+ "last-column-id": 1,
628+ "schema": {
629+ "type": "struct",
630+ "fields": [
631+ {"id": 1, "name": "x", "required": true, "type": "long"}
632+ ]
633+ },
634+ "partition-spec": [],
635+ "properties": {},
636+ "current-snapshot-id": 111111111,
637+ "snapshots": [
638+ {
639+ "snapshot-id": 111111111,
640+ "timestamp-ms": 1600000000000,
641+ "summary": {"operation": "append"},
642+ "manifest-list": "s3://bucket/metadata/snap-123.avro",
643+ "manifests": ["s3://bucket/metadata/manifest-1.avro"]
644+ }
645+ ]
646+ }
647+ "# ;
648+
649+ let result = serde_json:: from_str :: < TableMetadata > ( metadata) ;
650+ assert ! ( result. is_err( ) ) ;
651+ }
652+
653+ {
654+ let metadata = r#"
655+ {
656+ "format-version": 1,
657+ "table-uuid": "d20125c8-7284-442c-9aea-15fee620737c",
658+ "location": "s3://bucket/test/location",
659+ "last-updated-ms": 1700000000000,
660+ "last-column-id": 1,
661+ "schema": {
662+ "type": "struct",
663+ "fields": [
664+ {"id": 1, "name": "x", "required": true, "type": "long"}
665+ ]
666+ },
667+ "partition-spec": [],
668+ "properties": {},
669+ "current-snapshot-id": 111111111,
670+ "snapshots": [
671+ {
672+ "snapshot-id": 111111111,
673+ "timestamp-ms": 1600000000000,
674+ "summary": {"operation": "append"},
675+ "manifests": ["s3://bucket/metadata/manifest-1.avro"]
676+ }
677+ ]
678+ }
679+ "# ;
680+ let result = serde_json:: from_str :: < TableMetadata > ( metadata) ;
681+ assert ! ( result. is_err( ) ) ;
682+ }
683+ }
684+
607685 #[ test]
608686 fn test_snapshot_v1_to_v2_with_missing_summary ( ) {
609687 use crate :: spec:: snapshot:: _serde:: SnapshotV1 ;
0 commit comments