Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions decoder/decoder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,8 @@ func Test_Decode(t *testing.T) {
options: decoder.DecoderOptions{Rules: []decoder.SchemaValidationRule{decoder.INVALID_TYPE, decoder.REQUIRED_ATTRIBUTE}},
},
want: map[string][]string{
"id": {"decoder.REQUIRED_ATTRIBUTE_MISSING"},
"name": {"decoder.REQUIRED_ATTRIBUTE_MISSING"},
"id": {"REQUIRED_ATTRIBUTE_MISSING"},
"name": {"REQUIRED_ATTRIBUTE_MISSING"},
},
},
{
Expand All @@ -125,8 +125,8 @@ func Test_Decode(t *testing.T) {
options: decoder.DecoderOptions{Rules: []decoder.SchemaValidationRule{decoder.INVALID_TYPE, decoder.REQUIRED_ATTRIBUTE}},
},
want: map[string][]string{
"id": {"decoder.REQUIRED_ATTRIBUTE_MISSING"},
"name": {"decoder.REQUIRED_ATTRIBUTE_MISSING"},
"id": {"REQUIRED_ATTRIBUTE_MISSING"},
"name": {"REQUIRED_ATTRIBUTE_MISSING"},
},
},
{
Expand Down
10 changes: 5 additions & 5 deletions decoder/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -304,12 +304,12 @@ func getAttributes(rv reflect.Value, parents []StructAttribute, filterTags, igno
// Struct field definition
rsf := rv.Type().Field(position)

sa := StructAttribute{
sa := *NewStructAttribute(NewStructAttributeFields{
Value: value,
Field: rsf,
Parents: parents,
ListPosition: currentIndex,
}
})

// Do not include an anonymous field at the top level.
// Only include its inner fields.
Expand Down Expand Up @@ -356,12 +356,12 @@ func getAttributes(rv reflect.Value, parents []StructAttribute, filterTags, igno
el := value.Index(l)

if isListOfPrimitives {
child := StructAttribute{
child := *NewStructAttribute(NewStructAttributeFields{
Value: el,
Parents: newParents,
ListPosition: l,
isPrimitive: true,
}
IsPrimitive: true,
})

// Copy information from parent StructField
child.Field = reflect.StructField{
Expand Down
18 changes: 9 additions & 9 deletions decoder/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,7 @@ func Test_GetAllAttributes(t *testing.T) {
}
}

func TestGetAttributes_WithSpecificTags(t *testing.T) {
func Test_GetAttributes_WithSpecificTags(t *testing.T) {
type Expectation struct {
Name string
Model any
Expand Down Expand Up @@ -387,7 +387,7 @@ func TestGetAttributes_WithSpecificTags(t *testing.T) {
}
}

func TestGetTagValues(t *testing.T) {
func Test_GetTagValues(t *testing.T) {
var field reflect.StructField = reflect.StructField{
Tag: `json:"id,omitempty" db:"_id"`,
}
Expand All @@ -410,7 +410,7 @@ func TestGetTagValues(t *testing.T) {
}
}

func TestGetTag(t *testing.T) {
func Test_GetTag(t *testing.T) {
var field reflect.StructField = reflect.StructField{
Tag: `json:"id,omitempty" db:"_id" validate:"min=1,max=255,required"`,
}
Expand All @@ -432,7 +432,7 @@ func TestGetTag(t *testing.T) {
}
}

func TestGetTags(t *testing.T) {
func Test_GetTags(t *testing.T) {
var field reflect.StructField = reflect.StructField{
Tag: `json:"id,omitempty" db:"_id"`,
}
Expand All @@ -448,7 +448,7 @@ func TestGetTags(t *testing.T) {
}
}

func TestTagContainsValues(t *testing.T) {
func Test_TagContainsValues(t *testing.T) {
type Expectation struct {
Name string
Field reflect.StructField
Expand Down Expand Up @@ -527,7 +527,7 @@ func TestTagContainsValues(t *testing.T) {
}
}

func TestMatchingFields(t *testing.T) {
func Test_MatchingFields(t *testing.T) {
type Expectation struct {
Name string
Model any
Expand Down Expand Up @@ -619,7 +619,7 @@ func TestMatchingFields(t *testing.T) {
}
}

func TestSetValuesFromMap(t *testing.T) {
func Test_SetValuesFromMap(t *testing.T) {
type args struct {
model any
values map[string]any
Expand Down Expand Up @@ -667,7 +667,7 @@ func TestSetValuesFromMap(t *testing.T) {
}
}

func TestSetValuesFromBytes(t *testing.T) {
func Test_SetValuesFromBytes(t *testing.T) {
type args struct {
model any
values []byte
Expand Down Expand Up @@ -715,7 +715,7 @@ func TestSetValuesFromBytes(t *testing.T) {
}
}

func TestRemoveValuesFromTag(t *testing.T) {
func Test_RemoveValuesFromTag(t *testing.T) {
type args struct {
tag string
removeList []string
Expand Down
36 changes: 24 additions & 12 deletions decoder/struct.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,19 @@ import (
"fmt"
"reflect"
"strings"

"github.com/oleoneto/go-toolkit/helpers"
)

// This type abstracts both `reflect.Value` and `reflect.StructField` types.
type StructAttribute struct {
Value reflect.Value
Field reflect.StructField
Parents []StructAttribute
Children []StructAttribute
ListPosition int
isPrimitive bool

name *string
}

type NewStructAttributeFields struct {
Expand All @@ -26,7 +29,7 @@ type NewStructAttributeFields struct {

type StructAttributes []StructAttribute

// Returns the name of the field properly scoped under its parents.
// Sets and returns the name of the field properly scoped under its parents.
//
// Usage:
//
Expand All @@ -40,29 +43,35 @@ type StructAttributes []StructAttribute
// }
// }
//
// sa.FullName() // -> "parentA.listB[i].attribute_name"
func (sa *StructAttribute) FullName() (name string) {
if len(sa.Parents) == 0 {
return GetJSONTagValue(sa.Field)
// sa.assignName(parents...) // -> "parentA.listB[i].attribute_name"
func (sa *StructAttribute) assignName(parents ...StructAttribute) string {
if len(parents) < 1 {
sa.name = helpers.PointerTo(GetJSONTagValue(sa.Field))
return *sa.name
}

scope := sa.Parents[len(sa.Parents)-1].FullName()
scope := parents[len(parents)-1].FullName()

// Adds the array notation to the slice/array field
if sa.ListPosition >= 0 {
scope = strings.Join([]string{scope, fmt.Sprint("[", sa.ListPosition, "]")}, "")
}

if sa.isPrimitive {
return scope
sa.name = helpers.PointerTo(scope)
return *sa.name
}

fullName := strings.Join([]string{scope, GetJSONTagValue(sa.Field)}, ".")

// Ensures field name is never prefixed by a dot (.)
return strings.TrimSuffix(strings.TrimPrefix(fullName, "."), ".")
// Ensures field name is never prefixed or suffixed by a dot (.)
sa.name = helpers.PointerTo(strings.TrimSuffix(strings.TrimPrefix(fullName, "."), "."))

return *sa.name
}

func (sa *StructAttribute) FullName() string { return *sa.name }

func (sa *StructAttribute) SkipsPastLastChild() int {
if len(sa.Children) == 0 {
return 0
Expand All @@ -77,12 +86,15 @@ func (sa *StructAttribute) SkipsPastLastChild() int {
}

func NewStructAttribute(args NewStructAttributeFields) *StructAttribute {
return &StructAttribute{
sa := &StructAttribute{
Value: args.Value,
Field: args.Field,
Parents: args.Parents,
Children: args.Children,
ListPosition: args.ListPosition,
isPrimitive: args.IsPrimitive,
}

sa.assignName(args.Parents...)

return sa
}
26 changes: 13 additions & 13 deletions decoder/struct_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ import (
"github.com/oleoneto/go-toolkit/decoder"
)

func TestStructAttribute_SkipsPastLastChild(t *testing.T) {
func Test_StructAttribute_SkipsPastLastChild(t *testing.T) {
type fields struct {
Value reflect.Value
Field reflect.StructField
Parents []decoder.StructAttribute
Children []decoder.StructAttribute
ListPosition int
value reflect.Value
field reflect.StructField
parents []decoder.StructAttribute
children []decoder.StructAttribute
listPosition int
isPrimitive bool
}
tests := []struct {
Expand All @@ -24,26 +24,26 @@ func TestStructAttribute_SkipsPastLastChild(t *testing.T) {
{
name: "test - 1",
fields: fields{
Children: []decoder.StructAttribute{},
children: []decoder.StructAttribute{},
},
want: 0,
},
{
name: "test - 2",
fields: fields{
Children: []decoder.StructAttribute{{}},
children: []decoder.StructAttribute{{}},
},
want: 3,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
sa := decoder.NewStructAttribute(decoder.NewStructAttributeFields{
Value: tt.fields.Value,
Field: tt.fields.Field,
Parents: tt.fields.Parents,
Children: tt.fields.Children,
ListPosition: tt.fields.ListPosition,
Value: tt.fields.value,
Field: tt.fields.field,
Parents: tt.fields.parents,
Children: tt.fields.children,
ListPosition: tt.fields.listPosition,
IsPrimitive: tt.fields.isPrimitive,
})

Expand Down
38 changes: 19 additions & 19 deletions validator/validator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -539,61 +539,61 @@ func Test_PassesRegex(t *testing.T) {
str string
}
tests := []struct {
name string
args args
want bool
name string
args args
passes bool
}{
{
name: "numeric - 0",
want: false,
name: "numeric - 0",
passes: false,
args: args{
pattern: `\d+`,
str: "leonardo",
},
},
{
name: "numeric - 1",
want: true,
name: "numeric - 1",
passes: true,
args: args{
pattern: `\d+`,
str: "299",
},
},
{
name: "numeric - 2",
want: true,
name: "numeric - 2",
passes: true,
args: args{
pattern: `\d{3}$`,
str: "299",
},
},
{
name: "numeric - 3",
want: false,
name: "numeric - 3",
passes: false,
args: args{
pattern: `^\d{2}$`,
str: "299",
},
},
{
name: "US phone number - 1",
want: false,
name: "US phone number - 1",
passes: false,
args: args{
pattern: `^\d{3}-\d{3}-\d{4}$`,
str: "55-5-5555-5555",
},
},
{
name: "US phone number - 2",
want: true,
name: "US phone number - 2",
passes: true,
args: args{
pattern: `^\d{3}-\d{3}-\d{4}$`,
str: "555-555-5555",
},
},
{
name: "invalid - 1",
want: false,
name: "invalid - 1",
passes: false,
args: args{
pattern: `/\`,
str: "#FBA",
Expand All @@ -603,8 +603,8 @@ func Test_PassesRegex(t *testing.T) {

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := validator.PassesRegex(tt.args.pattern, tt.args.str); got != tt.want {
t.Errorf("PassesRegex() = %v, want %v", got, tt.want)
if got := validator.PassesRegex(tt.args.pattern, tt.args.str); got != tt.passes {
t.Errorf("PassesRegex() = %v, want %v", got, tt.passes)
}
})
}
Expand Down
Loading