@@ -662,6 +662,11 @@ func (v *Validator) validateMapElement(root string, elem common.MapStr, doc comm
662662 errs = append (errs , err ... )
663663 }
664664 default :
665+ if skipLeafOfObject (root , name , v .specVersion , v .Schema ) {
666+ // Till some versions we skip some validations on leaf of objects, check if it is the case.
667+ break
668+ }
669+
665670 err := v .validateScalarElement (key , val , doc )
666671 if err != nil {
667672 errs = append (errs , err )
@@ -820,6 +825,36 @@ func skipValidationForField(key string) bool {
820825 isFieldFamilyMatching ("event.module" , key ) // field is deprecated
821826}
822827
828+ // skipLeafOfObject checks if the element is a child of an object that was skipped in some previous
829+ // version of the spec. This is relevant in documents that store fields without subobjects.
830+ func skipLeafOfObject (root , name string , specVersion semver.Version , schema []FieldDefinition ) bool {
831+ if specVersion .LessThan (semver3_0_1 ) {
832+ // Check if this is a subobject of an object we didn't traverse.
833+ if ! strings .Contains (name , "." ) {
834+ return false
835+ }
836+ key := name
837+ if root != "" {
838+ key = root + "." + name
839+ }
840+ _ , ancestor := findAncestorElementDefinition (key , schema , func (key string , def * FieldDefinition ) bool {
841+ // Don't look for ancestors beyond root, these objects have been already traversed.
842+ if len (key ) < len (root ) {
843+ return false
844+ }
845+ if ! slices .Contains ([]string {"group" , "object" , "nested" , "flattened" }, def .Type ) {
846+ return false
847+ }
848+ return true
849+ })
850+ if ancestor != nil {
851+ return true
852+ }
853+ }
854+
855+ return false
856+ }
857+
823858func isFieldFamilyMatching (family , key string ) bool {
824859 return key == family || strings .HasPrefix (key , family + "." )
825860}
@@ -858,19 +893,11 @@ func isArrayOfObjects(val any) bool {
858893}
859894
860895func isFlattenedSubfield (key string , schema []FieldDefinition ) bool {
861- for strings .Contains (key , "." ) {
862- i := strings .LastIndex (key , "." )
863- key = key [:i ]
864- ancestor := FindElementDefinition (key , schema )
865- if ancestor == nil {
866- continue
867- }
868- if ancestor .Type == "flattened" {
869- return true
870- }
871- }
896+ _ , ancestor := findAncestorElementDefinition (key , schema , func (_ string , def * FieldDefinition ) bool {
897+ return def .Type == "flattened"
898+ })
872899
873- return false
900+ return ancestor != nil
874901}
875902
876903func findElementDefinitionForRoot (root , searchedKey string , fieldDefinitions []FieldDefinition ) * FieldDefinition {
@@ -921,6 +948,22 @@ func findParentElementDefinition(key string, fieldDefinitions []FieldDefinition)
921948 return FindElementDefinition (parentKey , fieldDefinitions )
922949}
923950
951+ func findAncestorElementDefinition (key string , fieldDefinitions []FieldDefinition , cond func (string , * FieldDefinition ) bool ) (string , * FieldDefinition ) {
952+ for strings .Contains (key , "." ) {
953+ i := strings .LastIndex (key , "." )
954+ key = key [:i ]
955+ ancestor := FindElementDefinition (key , fieldDefinitions )
956+ if ancestor == nil {
957+ continue
958+ }
959+ if cond (key , ancestor ) {
960+ return key , ancestor
961+ }
962+ }
963+
964+ return "" , nil
965+ }
966+
924967// compareKeys checks if `searchedKey` matches with the given `key`. `key` can contain
925968// wildcards (`*`), that match any sequence of characters in `searchedKey` different to dots.
926969func compareKeys (key string , def FieldDefinition , searchedKey string ) bool {
0 commit comments