Skip to content

Commit 2dc00b3

Browse files
feat: add util function to get type of field
1 parent 755f96f commit 2dc00b3

File tree

2 files changed

+128
-7
lines changed

2 files changed

+128
-7
lines changed

rql/parser.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,20 @@ func getDataTypeOfField(tagString string) string {
188188
return res
189189
}
190190

191+
func GetDataTypeOfField(fieldName string, checkStruct interface{}) (string, error) {
192+
val := reflect.ValueOf(checkStruct)
193+
filterIdx := searchKeyInsideStruct(fieldName, val)
194+
if filterIdx < 0 {
195+
return "", fmt.Errorf("'%s' is not a valid field", fieldName)
196+
}
197+
structKeyTag := val.Type().Field(filterIdx).Tag.Get(TAG)
198+
dataType := getDataTypeOfField(structKeyTag)
199+
if !slices.Contains([]string{DATATYPE_STRING, DATATYPE_BOOL, DATATYPE_NUMBER, DATATYPE_DATETIME}, dataType) {
200+
return "", fmt.Errorf("invalid datatype '%s' is for field %s", dataType, fieldName)
201+
}
202+
return dataType, nil
203+
}
204+
191205
func isValidOperator(filterItem Filter) bool {
192206
switch filterItem.dataType {
193207
case DATATYPE_NUMBER:

rql/parser_test.go

Lines changed: 114 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,19 @@
11
package rql
22

33
import (
4+
"strings"
45
"testing"
56
"time"
67
)
78

8-
type TestStruct struct {
9-
ID int32 `rql:"name=id,type=number"`
10-
Name string `rql:"name=name,type=string"`
11-
IsActive bool `rql:"name=is_active,type=bool"`
12-
CreatedAt time.Time `rql:"name=created_at,type=datetime"`
13-
}
14-
159
func TestValidateQuery(t *testing.T) {
10+
type TestStruct struct {
11+
ID int32 `rql:"name=id,type=number"`
12+
Name string `rql:"name=name,type=string"`
13+
IsActive bool `rql:"name=is_active,type=bool"`
14+
CreatedAt time.Time `rql:"name=created_at,type=datetime"`
15+
}
16+
1617
tests := []struct {
1718
name string
1819
query Query
@@ -86,3 +87,109 @@ func TestValidateQuery(t *testing.T) {
8687
})
8788
}
8889
}
90+
91+
func TestGetDataTypeOfField(t *testing.T) {
92+
type TestStruct struct {
93+
StringField string `rql:"name=string_field,type=string"`
94+
NumberField int `rql:"name=number_field,type=number"`
95+
BoolField bool `rql:"name=bool_field,type=bool"`
96+
DateTimeField time.Time `rql:"name=datetime_field,type=datetime"`
97+
InvalidField string `rql:"name=invalid_field,type=invalid"`
98+
NoTypeField string `rql:"name=no_type_field"` // No type specified
99+
NoTagField string // No tag at all
100+
}
101+
102+
tests := []struct {
103+
name string
104+
fieldName string
105+
expectedType string
106+
expectedError bool
107+
errorContains string
108+
}{
109+
{
110+
name: "String field by struct name",
111+
fieldName: "StringField",
112+
expectedType: "string",
113+
expectedError: false,
114+
},
115+
{
116+
name: "String field by tag name",
117+
fieldName: "string_field",
118+
expectedType: "string",
119+
expectedError: false,
120+
},
121+
{
122+
name: "Number field by struct name",
123+
fieldName: "NumberField",
124+
expectedType: "number",
125+
expectedError: false,
126+
},
127+
{
128+
name: "Number field by tag name",
129+
fieldName: "number_field",
130+
expectedType: "number",
131+
expectedError: false,
132+
},
133+
{
134+
name: "Bool field by struct name",
135+
fieldName: "BoolField",
136+
expectedType: "bool",
137+
expectedError: false,
138+
},
139+
{
140+
name: "DateTime field by struct name",
141+
fieldName: "DateTimeField",
142+
expectedType: "datetime",
143+
expectedError: false,
144+
},
145+
{
146+
name: "Invalid field name",
147+
fieldName: "NonExistentField",
148+
expectedType: "",
149+
expectedError: true,
150+
errorContains: "is not a valid field",
151+
},
152+
{
153+
name: "No type specified in tag",
154+
fieldName: "NoTypeField",
155+
expectedType: "string", // Should default to string
156+
expectedError: false,
157+
},
158+
{
159+
name: "No tag field",
160+
fieldName: "NoTagField",
161+
expectedType: "string", // Should default to string
162+
expectedError: false,
163+
},
164+
}
165+
166+
testStruct := TestStruct{}
167+
168+
for _, tt := range tests {
169+
t.Run(tt.name, func(t *testing.T) {
170+
dataType, err := GetDataTypeOfField(tt.fieldName, testStruct)
171+
172+
// Check error cases
173+
if tt.expectedError {
174+
if err == nil {
175+
t.Errorf("Expected error but got none")
176+
return
177+
}
178+
if !strings.Contains(err.Error(), tt.errorContains) {
179+
t.Errorf("Expected error containing '%s', got '%s'", tt.errorContains, err.Error())
180+
}
181+
return
182+
}
183+
184+
// Check success cases
185+
if err != nil {
186+
t.Errorf("Unexpected error: %v", err)
187+
return
188+
}
189+
190+
if dataType != tt.expectedType {
191+
t.Errorf("Expected type '%s', got '%s'", tt.expectedType, dataType)
192+
}
193+
})
194+
}
195+
}

0 commit comments

Comments
 (0)