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

Handling non present field in struct #8

Closed
zekth opened this issue Dec 15, 2023 · 2 comments · Fixed by #9
Closed

Handling non present field in struct #8

zekth opened this issue Dec 15, 2023 · 2 comments · Fixed by #9
Labels
bug Something isn't working enhancement New feature or request

Comments

@zekth
Copy link
Contributor

zekth commented Dec 15, 2023

This is an annoying JSON x Golang edge case but found a solution for this

Let's assume we have a struct like so:

type testStruct struct {
	Foo gonull.Nullable[*string] `json:"foo"`
}

we want to be able to handle those cases:

  • {"foo":"f"}
  • {}
  • {"foo": null}

In the current api we cannot check if the field is present. As {} and {"foo":null} will result with Valid: false and nil value. However we can do this:

diff --git a/gonull.go b/gonull.go
index b20a29e..deab37d 100644
--- a/gonull.go
+++ b/gonull.go
@@ -19,8 +19,9 @@ var (
 // It keeps track of the value (Val) and a flag (Valid) indicating whether the value has been set.
 // This allows for better handling of nullable values, ensuring proper value management and serialization.
 type Nullable[T any] struct {
-       Val   T
-       Valid bool
+       Val     T
+       Valid   bool
+       Present bool
 }
 
 // NewNullable creates a new Nullable with the given value and sets Valid to true.
@@ -59,6 +60,7 @@ func (n Nullable[T]) Value() (driver.Value, error) {
 // UnmarshalJSON implements the json.Unmarshaler interface for Nullable, allowing it to be used as a nullable field in JSON operations.
 // This method ensures proper unmarshalling of JSON data into the Nullable value, correctly setting the Valid flag based on the JSON data.
 func (n *Nullable[T]) UnmarshalJSON(data []byte) error {
+       n.Present = true
        if string(data) == "null" {
                n.Valid = false
                return nil

Then we have this successful test:

func TestPresent(t *testing.T) {
	var nullable1 testStruct
	var nullable2 testStruct
	var nullable3 testStruct

	err := json.Unmarshal([]byte(`{"foo":"f"}`), &nullable1)
	assert.NoError(t, err)
	assert.Equal(t, true, nullable1.Foo.Valid)
	assert.Equal(t, true, nullable1.Foo.Present)

	err = json.Unmarshal([]byte(`{}`), &nullable2)
	assert.NoError(t, err)
	assert.Equal(t, false, nullable2.Foo.Valid)
	assert.Equal(t, false, nullable3.Foo.Present)
	assert.Nil(t, nullable2.Foo.Val)

	err = json.Unmarshal([]byte(`{"foo": null}`), &nullable3)
	assert.NoError(t, err)
	assert.Equal(t, false, nullable3.Foo.Valid)
	assert.Equal(t, true, nullable3.Foo.Present)
	assert.Nil(t, nullable3.Foo.Val)
}

Happy to raise a PR if the implementation is ok.

@LukaGiorgadze
Copy link
Owner

Hey @zekth, thanks for pointing out this issue. It's a good topic to discuss. frankly, I'm not sure when you'd need to use Foo gonull.Nullable[*string] 'json:"foo"', but as you said, it might be a rare but useful case. Freel free to open PR, I'll gladly check and approve it!
Thank you!

@LukaGiorgadze LukaGiorgadze added bug Something isn't working enhancement New feature or request labels Dec 20, 2023
@zekth zekth mentioned this issue Dec 20, 2023
@LukaGiorgadze
Copy link
Owner

https://github.com/LukaGiorgadze/gonull/releases/tag/v1.0.0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working enhancement New feature or request
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants