Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(decoder-configs): add flag to force decoding nil input in decoder config #42

Merged
merged 27 commits into from
Sep 20, 2024

Conversation

mahadzaryab1
Copy link

@mahadzaryab1 mahadzaryab1 commented Aug 24, 2024

Added a config flag DecodeNil to allow DecodeHook to allow decoding nil inputs. This PR fixes #37.

mapstructure.go Outdated Show resolved Hide resolved
@mahadzaryab1
Copy link
Author

@yurishkuro thanks for the feedback! i addressed your comments - let me know if you have any other feedback!

mapstructure.go Outdated Show resolved Hide resolved
mapstructure_test.go Outdated Show resolved Hide resolved
@mahadzaryab1
Copy link
Author

@yurishkuro Thanks for your great feedback! I tried to address all your comments. Let me know what you think and when we should open this up for maintainer review.

mapstructure.go Outdated Show resolved Hide resolved
mapstructure.go Show resolved Hide resolved
mapstructure_test.go Outdated Show resolved Hide resolved
mapstructure_test.go Outdated Show resolved Hide resolved
mapstructure.go Outdated Show resolved Hide resolved
@mahadzaryab1 mahadzaryab1 changed the title [WIP] feat(decoder-configs): add flag to force decoding in decoder config [WIP] feat(decoder-configs): add flag to force decoding nil input in decoder config Aug 27, 2024
@mahadzaryab1
Copy link
Author

mahadzaryab1 commented Aug 27, 2024

@yurishkuro addressed all your feedback! thank you so much for your comments - should we open it for maintainer review?

mapstructure.go Outdated Show resolved Hide resolved
mapstructure_test.go Outdated Show resolved Hide resolved
Copy link

@yurishkuro yurishkuro left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm. Just a few nits, otherwise I think it's ready for maintainers' review

mapstructure_test.go Outdated Show resolved Hide resolved
mapstructure_test.go Outdated Show resolved Hide resolved
mapstructure_test.go Outdated Show resolved Hide resolved
@mahadzaryab1 mahadzaryab1 changed the title [WIP] feat(decoder-configs): add flag to force decoding nil input in decoder config feat(decoder-configs): add flag to force decoding nil input in decoder config Aug 27, 2024
@mahadzaryab1 mahadzaryab1 marked this pull request as ready for review August 27, 2024 23:39
decodeNil: true,
input: map[string]interface{}{"message": "bar"},
decodeHook: goodbyeHook,
expectedResult: Transformed{Message: "goodbye"},

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this the correct result? It looks like the decode hook has the final say, rather than the actual input.

Copy link
Author

@mahadzaryab1 mahadzaryab1 Sep 7, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The way we have it set up right now is if DecodeNil is true then it will force the hook to run regardless of what the input is. I believe this is what the current behaviour is even without DecodeNil.

decodeNil: false,
input: map[string]interface{}{"message": "bar"},
decodeHook: goodbyeHook,
expectedResult: Transformed{Message: "goodbye"},

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one seems okay to me since decodeNil is false so we just run the hook on the input as usual. Let me know if I'm misunderstanding something though.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it just doesn't match my understanding of the hooks - in OTEL Collector the hooks are used to provide defaults, but then the regular parsing still takes place. Perhaps it's specific to how the OTEL hooks are implemented, but looking at mapstructure.go L493, even after the hook is invoked the execution still continues, so should't the parsing of user input still happen?

Copy link
Author

@mahadzaryab1 mahadzaryab1 Sep 8, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@yurishkuro Correct me if I'm wrong but it looks like the input gets overridden by the return value of the hook and then the processing continues on that instead of the original input?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, I think that's a valid use case to completely replace the input, but based on the documentation the intention of the hook function is to alter the input somehow, not completely replace it. Because if you completely replace it, especially with the actual struct, then the decoding becomes trivial - just assign input to output, whereas the value of this library is in decoding complex structures.

I would suggest adding another test with a new hook where instead of returning a struct, the hook adds another value to the map, e.g.

map[string]any{"message": originalvalue, "when": "see you later"},

this way you can say that yes the hook was run, but it didn't just short-circuit everything, it still proceeded with the normal decoding.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@yurishkuro thanks for the suggestion! i added a few more test cases in. let me know what you think!

Signed-off-by: Mahad Zaryab <[email protected]>
mapstructure_test.go Outdated Show resolved Hide resolved
Copy link

@yurishkuro yurishkuro left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Signed-off-by: Mahad Zaryab <[email protected]>
Copy link
Member

@sagikazarmark sagikazarmark left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @mahadzaryab1 !

@sagikazarmark sagikazarmark merged commit ff5d967 into go-viper:main Sep 20, 2024
8 checks passed
@sagikazarmark sagikazarmark added this to the v2.2.0 milestone Sep 20, 2024
@yurishkuro
Copy link

🎉 🎉 🎉

// If we get here, we have an untyped nil so the type of the input is assumed.
// We do this because all subsequent code requires a valid value for inputVal.
var mapVal map[string]interface{}
inputVal = reflect.MakeMap(reflect.TypeOf(mapVal))

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mahadzaryab1 I was previously concerned with this line since we're setting the input to a map when the destination field could be a primitive field. I noticed a bunch of unit tests in OTEL Collector started failing if I enable DecodeNil=true because of this open-telemetry/opentelemetry-collector#10260

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@yurishkuro I see. The tests that are failing have a different output kind from a map[string]any. One thing that fixes these tests is simply setting outputVal=inputVal which would remove the assumption of what an input should be and assume that it is the type as the output. However, this doesn't work for the new optional config we added since we expect everything going through this hook here to be a map[string]any, so the Unmarshal method never runs. Is there anything we can do in this hook to force the unmarshaller to run? The other option here would be to specify what type the input is when it is nil. Let me know what you think.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I may have a fix, testing it out

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sounds good! let me know if i can help with anything

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#45

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Allow DecodeHook to run for zero values
3 participants