Skip to content

Commit

Permalink
refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
hariso committed Nov 7, 2024
1 parent 7ffa105 commit ceeae03
Showing 1 changed file with 57 additions and 31 deletions.
88 changes: 57 additions & 31 deletions schema/avro/union.go
Original file line number Diff line number Diff line change
Expand Up @@ -224,47 +224,73 @@ func (r unionResolver) afterUnmarshalNullUnionSubstitutions(val any, substitutio
return nil, err
}

// nullUnionField is the actual field, i.e. the last leg in the path.
// nullUnionField is nil if the field is actually a key in a map.
// In that case, all the values in the map need to be checked and substituted.
// nullUnionField is not nil if it's a field within a record schema.
// In that case, we only substitute that field.
// nullUnionField is the fields that needs to be substitured.
// It's the last leg in the path.
nullUnionField := nullUnionPath[len(nullUnionPath)-1].field

// Loop through collected parent maps and collect all substitutions.
for i, parentMap := range parentMaps {
for fieldName, avroVal := range parentMap {
if nullUnionField != nil && fieldName != nullUnionField.Name() {
continue
}
if avroVal == nil {
// don't change nil values
continue
}
vmap, ok := avroVal.(map[string]any)
if !ok {
// if the value is not a map, it's not a nil value
continue
}
if len(vmap) != 1 {
return nil, fmt.Errorf("expected single value encoded as a map, got %d elements: %w", len(vmap), ErrSchemaValueMismatch)
}

// this is a map with a single value, store the substitution
for _, actualVal := range vmap {
substitutions = append(substitutions, mapSubstitution{
m: parentMaps[i],
key: fieldName,
val: actualVal,
})
break
for _, parentMap := range parentMaps {
// nullUnionField is nil if the field represents a key in a map.
// In that case, all the values in the map need to be checked and substituted.
if nullUnionField == nil {
for key, _ := range parentMap {
sub, err := r.substitute(parentMap, key)
if err != nil {
return nil, err
}
// substitution not needed for this key, skip to next
if sub == nil {
continue
}
substitutions = append(substitutions, sub)
}
continue
}
// nullUnionField is not nil if it's a field within a record schema.
// In that case, we only substitute that field.
sub, err := r.substitute(parentMap, nullUnionField.Name())
if err != nil {
return nil, err
}
// substitution not needed for this key, skip to next
if sub == nil {
continue
}
substitutions = append(substitutions, sub)
}
}
return substitutions, nil
}

func (r unionResolver) substitute(parentMap map[string]any, name string) (substitution, error) {
avroVal := parentMap[name]
if avroVal == nil {
// don't change nil values
return nil, nil

Check failure on line 269 in schema/avro/union.go

View workflow job for this annotation

GitHub Actions / golangci-lint

return both the `nil` error and invalid value: use a sentinel error instead (nilnil)
}
vmap, ok := avroVal.(map[string]any)
if !ok {
// if the value is not a map, it's not a nil value
return nil, nil

Check failure on line 274 in schema/avro/union.go

View workflow job for this annotation

GitHub Actions / golangci-lint

return both the `nil` error and invalid value: use a sentinel error instead (nilnil)
}
if len(vmap) != 1 {
return nil, fmt.Errorf("expected single value for %s encoded as a map, got %d elements: %w", name, len(vmap), ErrSchemaValueMismatch)
}

// this is a map with a single value, store the substitution
for _, actualVal := range vmap {
return mapSubstitution{
m: parentMap,
key: name,
val: actualVal,
}, nil
}

// we can reach this line only if we didn't return
// the substitution from the loop above
panic("substitution not returned (this is a bug in the code)")
}

// BeforeMarshal traverses the value using the schema and finds all values that
// have the Avro type Union. Those values need to be changed to a map with a
// single key that contains the name of the type. This function takes that value
Expand Down

0 comments on commit ceeae03

Please sign in to comment.