Can I set default max length for string fields in struct?
Asked Answered
N

5

6

I have multiple structs in my application using golang. Some fields in a struct have maxsize tags, some does not have. for e.g:

type structone struct {
  fieldone string `valid:MaxSize(2)`
  fieldtwo string 
}

type structtwo struct {
  fieldone string `valid:MaxSize(2)`
  fieldtwo string 
}

So I want to set default maxsize for all fields, if does not contain any valid max size tags in run time. Is it possible? Can somebody help.

Novosibirsk answered 22/11, 2019 at 7:30 Comment(0)
B
5

Can I set default max length for string fields in struct?

No.

Brout answered 22/11, 2019 at 7:35 Comment(0)
C
2

The string predeclared type does not allow you to limit the length of the string value it may hold.

What you may do is use an unexported field so it cannot be accessed (set) outside of your package, and provide a setter method in which you check the length, and refuse to set it if it does not meet your requirements (or cap the value to the allowed max).

For example:

func (s *structone) SetFieldone(v string) error {
    if len(v) > 2 {
        return errors.New("too long")
    }
    s.fieldone = v
    return nil
}
Chaddie answered 22/11, 2019 at 7:41 Comment(2)
The problem is I have hundreds of struct like this in my application and I will have to define for each of them. :(Novosibirsk
he is looking to statically load his program, programmatically add tag, then save the updated to program. ast etc..Jennefer
B
0

The other answers seem to assume you are using vanilla strings in Go and asking if you could limit their max size. That could be achieved with some of the suggestions made.

However, from the code snippet you have provided, I infer that you are asking whether the validate go package can specify a default max size of all fields in a struct using tags.

Unfortunately, that library does not currently support specifying a default validation tag for all fields. You have to explicitly define the validation tag for all fields of a struct.

What you are trying to achieve is possible, however, but the library needs to be extended.

One suggestion is extending it to support syntax such as:

type MyStruct struct {
    valid.Default `valid:MaxSize(5)`

    field1 string
    field2 string
}
Bernoulli answered 22/11, 2019 at 7:49 Comment(3)
Yes you are right and I am not depending on library. I wanted to achieve it using my own code during runtime and then provide that struct to library so it can validate properly.Novosibirsk
I like your suggestion. could you provide an example for this?Novosibirsk
I will attempt to write some code to achieve that. Best case scenario, I will come up with a fork for the library that supports what you need. I will set aside some time to tinker with this today.Bernoulli
J
0

this program read itself, add the tag valid:MaxSize(2) to the property structone.fieldone, then prints the updated program to os.Stdout.

package main

import (
    "go/ast"
    "go/printer"
    "go/token"
    "log"
    "os"
    "strings"

    "golang.org/x/tools/go/ast/astutil"
    "golang.org/x/tools/go/loader"
)

type structone struct {
    fieldone string
    fieldtwo string
}

func main() {
    var conf loader.Config
    _, err := conf.FromArgs([]string{"."}, false)
    if err != nil {
        log.Fatal(err)
    }
    prog, err := conf.Load()
    if err != nil {
        log.Fatal(err)
    }
    astutil.Apply(prog.InitialPackages()[0].Files[0], addTag("structone.fieldone", "`valid:MaxSize(2)`"), nil)

    printer.Fprint(os.Stdout, prog.Fset, prog.InitialPackages()[0].Files[0])
}

func addTag(p string, tag string) func(*astutil.Cursor) bool {
    pp := strings.Split(p, ".")
    sName := pp[0]
    pName := pp[1]
    return func(cursor *astutil.Cursor) bool {
        n := cursor.Node()
        if x, ok := n.(*ast.TypeSpec); ok {
            return x.Name.Name == sName
        } else if x, ok := n.(*ast.Field); ok {
            for _, v := range x.Names {
                if v.Name == pName {
                    x.Tag = &ast.BasicLit{
                        Value: tag,
                        Kind:  token.STRING,
                    }
                }
            }
        } else if _, ok := n.(*ast.File); ok {
            return true
        } else if _, ok := n.(*ast.GenDecl); ok {
            return true
        } else if _, ok := n.(*ast.TypeSpec); ok {
            return true
        } else if _, ok := n.(*ast.StructType); ok {
            return true
        } else if _, ok := n.(*ast.FieldList); ok {
            return true
        }
        return false
    }
}
Jennefer answered 22/11, 2019 at 9:57 Comment(0)
Q
-1

The question is a bit old, but I believe it is worth the effort to help others in the same situation. As indicated in one of the previous answers, you will need the 'validator' package and some adjustments to your struct to achieve this.

package main

import (
    "fmt"

    "github.com/go-playground/validator/v10"
)

type Structone struct {
    Fieldone string `validate:"required,lt=10"`
    Fieldtwo string `validate:"required,gte=8"`
}

var validate *validator.Validate

func main() {
    s1 := &Structone{
        Fieldone: "ok string",
        Fieldtwo: "Error!",
    }
    validate = validator.New()
    err := validate.Struct(s1)
    if err != nil {
        // get all error at once
        errs := err.(validator.ValidationErrors)
        fmt.Println(errs)
    }
}
Quadriceps answered 5/7, 2024 at 0:1 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.