Skip to content

Commit 75941ae

Browse files
authored
refactor: simplify getValueInterface function (#5280)
1 parent c706517 commit 75941ae

File tree

3 files changed

+152
-17
lines changed

3 files changed

+152
-17
lines changed

core/collection/cache.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,10 @@ func (c *Cache) Del(key string) {
8181
delete(c.data, key)
8282
c.lruCache.remove(key)
8383
c.lock.Unlock()
84+
85+
// RemoveTimer is called outside the lock to avoid performance impact from this
86+
// potentially time-consuming operation. Data integrity is maintained by lruCache,
87+
// which will eventually evict any remaining entries when capacity is exceeded.
8488
c.timingWheel.RemoveTimer(key)
8589
}
8690

core/stores/sqlx/orm.go

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -70,25 +70,16 @@ func getTaggedFieldValueMap(v reflect.Value) (map[string]any, error) {
7070
}
7171

7272
func getValueInterface(value reflect.Value) (any, error) {
73-
switch value.Kind() {
74-
case reflect.Ptr:
75-
if !value.CanAddr() || !value.Addr().CanInterface() {
76-
return nil, ErrNotReadableValue
77-
}
78-
79-
if value.IsNil() {
80-
baseValueType := mapping.Deref(value.Type())
81-
value.Set(reflect.New(baseValueType))
82-
}
83-
84-
return value.Addr().Interface(), nil
85-
default:
86-
if !value.CanAddr() || !value.Addr().CanInterface() {
87-
return nil, ErrNotReadableValue
88-
}
73+
if !value.CanAddr() || !value.Addr().CanInterface() {
74+
return nil, ErrNotReadableValue
75+
}
8976

90-
return value.Addr().Interface(), nil
77+
if value.Kind() == reflect.Pointer && value.IsNil() {
78+
baseValueType := mapping.Deref(value.Type())
79+
value.Set(reflect.New(baseValueType))
9180
}
81+
82+
return value.Addr().Interface(), nil
9283
}
9384

9485
func isScanFailed(err error) bool {

core/stores/sqlx/orm_test.go

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"database/sql"
66
"errors"
7+
"reflect"
78
"testing"
89
"time"
910

@@ -2205,6 +2206,145 @@ func TestUnmarshalRowsSqlNullStringEmptyVsNull(t *testing.T) {
22052206
})
22062207
}
22072208

2209+
func TestGetValueInterface(t *testing.T) {
2210+
t.Run("non_pointer_field", func(t *testing.T) {
2211+
type testStruct struct {
2212+
Name string
2213+
Age int
2214+
}
2215+
s := testStruct{}
2216+
v := reflect.ValueOf(&s).Elem()
2217+
2218+
nameField := v.Field(0)
2219+
result, err := getValueInterface(nameField)
2220+
assert.NoError(t, err)
2221+
assert.NotNil(t, result)
2222+
2223+
// Should return pointer to the field
2224+
ptr, ok := result.(*string)
2225+
assert.True(t, ok)
2226+
*ptr = "test"
2227+
assert.Equal(t, "test", s.Name)
2228+
})
2229+
2230+
t.Run("pointer_field_nil", func(t *testing.T) {
2231+
type testStruct struct {
2232+
NamePtr *string
2233+
AgePtr *int64
2234+
}
2235+
s := testStruct{}
2236+
v := reflect.ValueOf(&s).Elem()
2237+
2238+
// Test with nil pointer field
2239+
namePtrField := v.Field(0)
2240+
assert.True(t, namePtrField.IsNil(), "initial pointer should be nil")
2241+
2242+
result, err := getValueInterface(namePtrField)
2243+
assert.NoError(t, err)
2244+
assert.NotNil(t, result)
2245+
2246+
// Should have allocated the pointer
2247+
assert.False(t, namePtrField.IsNil(), "pointer should be allocated after getValueInterface")
2248+
2249+
// Should return pointer to pointer field
2250+
ptrPtr, ok := result.(**string)
2251+
assert.True(t, ok)
2252+
testValue := "initialized"
2253+
*ptrPtr = &testValue
2254+
assert.NotNil(t, s.NamePtr)
2255+
assert.Equal(t, "initialized", *s.NamePtr)
2256+
})
2257+
2258+
t.Run("pointer_field_already_allocated", func(t *testing.T) {
2259+
type testStruct struct {
2260+
NamePtr *string
2261+
}
2262+
initial := "existing"
2263+
s := testStruct{NamePtr: &initial}
2264+
v := reflect.ValueOf(&s).Elem()
2265+
2266+
namePtrField := v.Field(0)
2267+
assert.False(t, namePtrField.IsNil(), "pointer should not be nil initially")
2268+
2269+
result, err := getValueInterface(namePtrField)
2270+
assert.NoError(t, err)
2271+
assert.NotNil(t, result)
2272+
2273+
// Should return pointer to pointer field
2274+
ptrPtr, ok := result.(**string)
2275+
assert.True(t, ok)
2276+
2277+
// Verify it points to the existing value
2278+
assert.Equal(t, "existing", **ptrPtr)
2279+
2280+
// Modify through the returned pointer
2281+
newValue := "modified"
2282+
*ptrPtr = &newValue
2283+
assert.Equal(t, "modified", *s.NamePtr)
2284+
})
2285+
2286+
t.Run("pointer_field_zero_value", func(t *testing.T) {
2287+
type testStruct struct {
2288+
IntPtr *int
2289+
}
2290+
s := testStruct{}
2291+
v := reflect.ValueOf(&s).Elem()
2292+
2293+
intPtrField := v.Field(0)
2294+
result, err := getValueInterface(intPtrField)
2295+
assert.NoError(t, err)
2296+
2297+
// After calling getValueInterface, nil pointer should be allocated
2298+
assert.NotNil(t, s.IntPtr)
2299+
2300+
// Set zero value through returned interface
2301+
ptrPtr, ok := result.(**int)
2302+
assert.True(t, ok)
2303+
zero := 0
2304+
*ptrPtr = &zero
2305+
assert.Equal(t, 0, *s.IntPtr)
2306+
})
2307+
2308+
t.Run("not_addressable_value", func(t *testing.T) {
2309+
type testStruct struct {
2310+
Name string
2311+
}
2312+
s := testStruct{Name: "test"}
2313+
v := reflect.ValueOf(s) // Non-pointer, not addressable
2314+
2315+
nameField := v.Field(0)
2316+
result, err := getValueInterface(nameField)
2317+
assert.Error(t, err)
2318+
assert.Equal(t, ErrNotReadableValue, err)
2319+
assert.Nil(t, result)
2320+
})
2321+
2322+
t.Run("multiple_pointer_types", func(t *testing.T) {
2323+
type testStruct struct {
2324+
StringPtr *string
2325+
IntPtr *int
2326+
Int64Ptr *int64
2327+
FloatPtr *float64
2328+
BoolPtr *bool
2329+
}
2330+
s := testStruct{}
2331+
v := reflect.ValueOf(&s).Elem()
2332+
2333+
// Test each pointer type gets properly initialized
2334+
for i := 0; i < v.NumField(); i++ {
2335+
field := v.Field(i)
2336+
assert.True(t, field.IsNil(), "field %d should start as nil", i)
2337+
2338+
result, err := getValueInterface(field)
2339+
assert.NoError(t, err, "field %d should not error", i)
2340+
assert.NotNil(t, result, "field %d result should not be nil", i)
2341+
2342+
// After getValueInterface, pointer should be allocated
2343+
assert.False(t, field.IsNil(), "field %d should be allocated", i)
2344+
}
2345+
})
2346+
}
2347+
22082348
func stringPtr(s string) *string {
22092349
return &s
22102350
}

0 commit comments

Comments
 (0)