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

Does not work with *int ? #250

Closed
StephanSchmidt opened this issue Dec 12, 2023 · 3 comments
Closed

Does not work with *int ? #250

StephanSchmidt opened this issue Dec 12, 2023 · 3 comments
Assignees
Labels
enhancement New feature or request

Comments

@StephanSchmidt
Copy link

With github.com/gookit/validate v1.5.1

I use

type Salary struct {
       MinSalary   *int `json:"MinSalary" validate:"int|min:10000" message:"The minimum salary is 10.000 EUR"`
	OkSalary    *int `json:"OkSalary" validate:"int|min:10000" message:"The ok salary is larger than 10.000 EUR"`
	HappySalary *int `json:"HappySalary" validate:"int|min:10000" message:"The happy salary is larger than 10.000 EUR"`
}

With the data

(params.Salary) {
 MinSalary: (*int)(<nil>),
 OkSalary: (*int)(0xc0002503c8)(121211212),
 HappySalary: (*int)(<nil>)
}

and get on validation this error:

(validate.Errors) (len=1) (PANIC=runtime error: invalid memory address or nil pointer dereference){
 (string) (len=8) "OkSalary": (validate.MS) (len=1) (PANIC=runtime error: invalid memory address or nil pointer dereference){
  (string) (len=3) "int": (string) (len=39) "The ok salary is larger than 10.000 EUR"
 }

Does *int not work as a field? How would I encode optional ints?

@StephanSchmidt
Copy link
Author

StephanSchmidt commented Dec 13, 2023

[Edit] Sorry, should have known, private fields are not validated.

Narrowed it down to visibility of fields:

package main

import (
	"fmt"
	"github.com/davecgh/go-spew/spew"
	"github.com/gookit/validate"
)

// Works
type A struct {
	a *int `validate:"min:1"`
}

// Doesn't work
type B struct {
	B *int `validate:"min:1"`
}

func main() {
	i := 3

	// Works
	pa := A{a: &i}
	va := validate.Struct(pa)
	spew.Dump(va)
	if va.Validate() {
		fmt.Println("Ok!")
	} else {
		fmt.Println("Not ok!")
		spew.Dump(va.Errors)
	}

	// Doesn't work
	p := B{B: &i}
	v := validate.Struct(p)
	spew.Dump(p)
	if v.Validate() {
		fmt.Println("Ok!")
	} else {
		fmt.Println("Not ok!")
		spew.Dump(v.Errors)
	}
}

go.mod

module a

go 1.21

require (
	github.com/davecgh/go-spew v1.1.1 // indirect
	github.com/gookit/filter v1.2.0 // indirect
	github.com/gookit/goutil v0.6.12 // indirect
	github.com/gookit/validate v1.5.1 // indirect
	golang.org/x/text v0.11.0 // indirect
)

@StephanSchmidt
Copy link
Author

StephanSchmidt commented Dec 16, 2023

Wasn't clear in my last comment. How would I model optional numbers?

*int does not work.
it seems 0 works, so

A1 int `validate:"int|min:200"`"

validates to ok with 0 but fails with 100. Couldn't find that in the documentation. Is this how to model optional ints?

package main

import (
	"fmt"
	"github.com/davecgh/go-spew/spew"
	"github.com/gookit/validate"
)

type A struct {
	A1 *int `validate:"int|min:200"`
	A2 *int `validate:"int|min:200"`
}

func main() {
	i := 3

	// Works
	pa := A{A1: &i, A2: nil}
	va := validate.Struct(pa)
	spew.Dump(pa)
	if va.Validate() {
		fmt.Println("Ok!")
	} else {
		fmt.Println("Not ok!")
		fmt.Println(va.Errors.One())
		spew.Dump(va.Errors)
	}
}

results in


(main.A) {
 A1: (*int)(0xc0001befa8)(3),
 A2: (*int)(<nil>)
}
Not ok!
A1 value must be an integer
(validate.Errors) (len=1) (PANIC=runtime error: invalid memory address or nil pointer dereference){
 (string) (len=2) "A1": (validate.MS) (len=1) (PANIC=runtime error: invalid memory address or nil pointer dereference){
  (string) (len=3) "int": (string) (len=27) "A1 value must be an integer"
 }
}

@inhere inhere added enhancement New feature or request and removed unconfirmed labels Jan 6, 2024
inhere added a commit that referenced this issue Jan 13, 2024
@inhere
Copy link
Member

inhere commented Jan 13, 2024

@StephanSchmidt please see test:

validate/issues_test.go

Lines 1602 to 1651 in ab0111b

func TestIssues_250(t *testing.T) {
type Salary struct {
MinSalary *int `json:"MinSalary" validate:"int|min:10000" message:"The minimum salary is 10.000 EUR"`
OkSalary *int `json:"OkSalary" validate:"int|min:10000" message:"The ok salary is larger than 10.000 EUR"`
HappySalary *int `json:"HappySalary" validate:"int|min:10000" message:"The happy salary is larger than 10.000 EUR"`
}
// works: optional
st := &Salary{}
v := validate.Struct(st)
assert.True(t, v.Validate())
// works
iv := 3
st = &Salary{
MinSalary: &iv,
}
v = validate.Struct(st)
assert.False(t, v.Validate())
assert.ErrMsg(t, v.Errors, "MinSalary: The minimum salary is 10.000 EUR")
// works: use zero value
iv2 := 0
st = &Salary{
MinSalary: &iv2,
}
v = validate.Struct(st)
assert.False(t, v.Validate())
assert.ErrMsg(t, v.Errors, "MinSalary: The minimum salary is 10.000 EUR")
// case 2
type A struct {
A1 *int `validate:"int|min:200"`
A2 *int `validate:"int|min:200"`
}
// works
i := 3
pa := A{A1: &i, A2: nil}
v = validate.Struct(pa)
assert.False(t, v.Validate())
assert.StrContains(t, v.Errors.String(), "A1 min value is 200")
// works
i2 := 0
pa = A{A1: &i2, A2: nil}
v = validate.Struct(pa)
assert.False(t, v.Validate())
assert.StrContains(t, v.Errors.String(), "A1 min value is 200")
}

It's OK?

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

No branches or pull requests

2 participants