Co-authored-by: marbar3778 <marbar3778@yahoo.com> Co-authored-by: Marko <marko@baricevic.me>
98 lines
3.2 KiB
Go
98 lines
3.2 KiB
Go
package schema
|
|
|
|
import (
|
|
"fmt"
|
|
)
|
|
|
|
// Field represents a field in an object type.
|
|
type Field struct {
|
|
// Name is the name of the field. It must conform to the NameFormat regular expression.
|
|
Name string `json:"name"`
|
|
|
|
// Kind is the basic type of the field.
|
|
Kind Kind `json:"kind"`
|
|
|
|
// Nullable indicates whether null values are accepted for the field. Key fields CANNOT be nullable.
|
|
Nullable bool `json:"nullable,omitempty"`
|
|
|
|
// ReferencedType is the referenced type name when Kind is EnumKind, StructKind or OneOfKind.
|
|
ReferencedType string `json:"referenced_type,omitempty"`
|
|
|
|
// ElementKind is the element type when Kind is ListKind.
|
|
// Support for this is currently UNIMPLEMENTED, this notice will be removed when it is added.
|
|
ElementKind Kind `json:"element_kind,omitempty"`
|
|
|
|
// Size specifies the size or max-size of a field.
|
|
// Support for this is currently UNIMPLEMENTED, this notice will be removed when it is added.
|
|
// Its specific meaning may vary depending on the field kind.
|
|
// For IntNKind and UintNKind fields, it specifies the bit width of the field.
|
|
// For StringKind, BytesKind, AddressKind, and JSONKind, fields it specifies the maximum length rather than a fixed length.
|
|
// If it is 0, such fields have no maximum length.
|
|
// It is invalid to have a non-zero Size for other kinds.
|
|
Size uint32 `json:"size,omitempty"`
|
|
}
|
|
|
|
// Validate validates the field.
|
|
func (c Field) Validate(typeSet TypeSet) error {
|
|
// valid name
|
|
if !ValidateName(c.Name) {
|
|
return fmt.Errorf("invalid field name %q", c.Name)
|
|
}
|
|
|
|
// valid kind
|
|
if err := c.Kind.Validate(); err != nil {
|
|
return fmt.Errorf("invalid field kind for %q: %v", c.Name, err) //nolint:errorlint // false positive due to using go1.12
|
|
}
|
|
|
|
// enum definition only valid with EnumKind
|
|
switch c.Kind {
|
|
case EnumKind:
|
|
if c.ReferencedType == "" {
|
|
return fmt.Errorf("enum field %q must have a referenced type", c.Name)
|
|
}
|
|
|
|
_, ok := typeSet.LookupEnumType(c.ReferencedType)
|
|
if !ok {
|
|
return fmt.Errorf("can't find enum type %q referenced by field %q", c.ReferencedType, c.Name)
|
|
}
|
|
|
|
default:
|
|
if c.ReferencedType != "" {
|
|
return fmt.Errorf("field %q with kind %q cannot have a referenced type", c.Name, c.Kind)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// ValidateValue validates that the value conforms to the field's kind and nullability.
|
|
// Unlike Kind.ValidateValue, it also checks that the value conforms to the EnumType
|
|
// if the field is an EnumKind.
|
|
func (c Field) ValidateValue(value interface{}, typeSet TypeSet) error {
|
|
if value == nil {
|
|
if !c.Nullable {
|
|
return fmt.Errorf("field %q cannot be null", c.Name)
|
|
}
|
|
return nil
|
|
}
|
|
err := c.Kind.ValidateValueType(value)
|
|
if err != nil {
|
|
return fmt.Errorf("invalid value for field %q: %v", c.Name, err) //nolint:errorlint // false positive due to using go1.12
|
|
}
|
|
|
|
switch c.Kind {
|
|
case EnumKind:
|
|
enumType, ok := typeSet.LookupEnumType(c.ReferencedType)
|
|
if !ok {
|
|
return fmt.Errorf("enum field %q references unknown type %q", c.Name, c.ReferencedType)
|
|
}
|
|
err := enumType.ValidateValue(value.(string))
|
|
if err != nil {
|
|
return fmt.Errorf("invalid value for enum field %q: %v", c.Name, err) //nolint:errorlint // false positive due to using go1.12
|
|
}
|
|
default:
|
|
}
|
|
|
|
return nil
|
|
}
|