Skip to content

Commit ca9c654

Browse files
committed
Merge branch 'master' into support-request-custom-field-not-set-err
2 parents b8a68ce + 801c283 commit ca9c654

File tree

23 files changed

+267
-95
lines changed

23 files changed

+267
-95
lines changed

.github/workflows/issue-translator.yml

Lines changed: 0 additions & 18 deletions
This file was deleted.

core/stores/redis/redis.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -609,6 +609,28 @@ func (s *Redis) GetBitCtx(ctx context.Context, key string, offset int64) (int, e
609609
return int(v), nil
610610
}
611611

612+
// GetDel is the implementation of redis getdel command.
613+
// Available since: redis version 6.2.0
614+
func (s *Redis) GetDel(key string) (string, error) {
615+
return s.GetDelCtx(context.Background(), key)
616+
}
617+
618+
// GetDelCtx is the implementation of redis getdel command.
619+
// Available since: redis version 6.2.0
620+
func (s *Redis) GetDelCtx(ctx context.Context, key string) (string, error) {
621+
conn, err := getRedis(s)
622+
if err != nil {
623+
return "", err
624+
}
625+
626+
val, err := conn.GetDel(ctx, key).Result()
627+
if errors.Is(err, red.Nil) {
628+
return "", nil
629+
}
630+
631+
return val, err
632+
}
633+
612634
// GetSet is the implementation of redis getset command.
613635
func (s *Redis) GetSet(key, value string) (string, error) {
614636
return s.GetSetCtx(context.Background(), key, value)

core/stores/redis/redis_test.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1071,6 +1071,34 @@ func TestRedis_Set(t *testing.T) {
10711071
})
10721072
}
10731073

1074+
func TestRedis_GetDel(t *testing.T) {
1075+
t.Run("get_del", func(t *testing.T) {
1076+
runOnRedis(t, func(client *Redis) {
1077+
val, err := newRedis(client.Addr).GetDel("hello")
1078+
assert.Equal(t, "", val)
1079+
assert.Nil(t, err)
1080+
err = client.Set("hello", "world")
1081+
assert.Nil(t, err)
1082+
val, err = client.Get("hello")
1083+
assert.Nil(t, err)
1084+
assert.Equal(t, "world", val)
1085+
val, err = client.GetDel("hello")
1086+
assert.Nil(t, err)
1087+
assert.Equal(t, "world", val)
1088+
val, err = client.Get("hello")
1089+
assert.Nil(t, err)
1090+
assert.Equal(t, "", val)
1091+
})
1092+
})
1093+
1094+
t.Run("get_del_with_error", func(t *testing.T) {
1095+
runOnRedisWithError(t, func(client *Redis) {
1096+
_, err := newRedis(client.Addr, badType()).GetDel("hello")
1097+
assert.Error(t, err)
1098+
})
1099+
})
1100+
}
1101+
10741102
func TestRedis_GetSet(t *testing.T) {
10751103
t.Run("set_get", func(t *testing.T) {
10761104
runOnRedis(t, func(client *Redis) {

core/stores/sqlx/orm_test.go

Lines changed: 87 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,20 @@ func TestUnmarshalRowStruct(t *testing.T) {
267267
}, "select name, age from users where user=?", "anyone"), ErrNotMatchDestination)
268268
})
269269

270+
dbtest.RunTest(t, func(db *sql.DB, mock sqlmock.Sqlmock) {
271+
value := new(struct {
272+
Name string
273+
age int
274+
})
275+
276+
rs := sqlmock.NewRows([]string{"name", "age"}).FromCSVString("liao,5")
277+
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
278+
279+
assert.ErrorIs(t, query(context.Background(), db, func(rows *sql.Rows) error {
280+
return unmarshalRow(value, rows, true)
281+
}, "select name, age from users where user=?", "anyone"), ErrNotMatchDestination)
282+
})
283+
270284
dbtest.RunTest(t, func(db *sql.DB, mock sqlmock.Sqlmock) {
271285
rs := sqlmock.NewRows([]string{"value"}).FromCSVString("8")
272286
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
@@ -310,6 +324,20 @@ func TestUnmarshalRowStructWithTags(t *testing.T) {
310324
}, "select name, age from users where user=?", "anyone"), ErrNotReadableValue)
311325
})
312326

327+
dbtest.RunTest(t, func(db *sql.DB, mock sqlmock.Sqlmock) {
328+
value := new(struct {
329+
age int `db:"age"`
330+
Name string `db:"name"`
331+
})
332+
333+
rs := sqlmock.NewRows([]string{"name", "age"}).FromCSVString("liao,5")
334+
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
335+
336+
assert.ErrorIs(t, query(context.Background(), db, func(rows *sql.Rows) error {
337+
return unmarshalRow(value, rows, true)
338+
}, "select name, age from users where user=?", "anyone"), ErrNotReadableValue)
339+
})
340+
313341
dbtest.RunTest(t, func(db *sql.DB, mock sqlmock.Sqlmock) {
314342
var value struct {
315343
Age *int `db:"age"`
@@ -1307,25 +1335,65 @@ func TestAnonymousStructPr(t *testing.T) {
13071335
}
13081336

13091337
func TestAnonymousStructPrError(t *testing.T) {
1310-
type Score struct {
1311-
Discipline string `db:"discipline"`
1312-
score uint `db:"score"`
1313-
}
1314-
type ClassType struct {
1315-
Grade sql.NullString `db:"grade"`
1316-
ClassName *string `db:"class_name"`
1317-
}
1318-
type Class struct {
1319-
*ClassType
1320-
Score
1321-
}
1322-
var value []*struct {
1323-
Age int64 `db:"age"`
1324-
Class
1325-
Name string `db:"name"`
1326-
}
1338+
dbtest.RunTest(t, func(db *sql.DB, mock sqlmock.Sqlmock) {
1339+
type Score struct {
1340+
Discipline string `db:"discipline"`
1341+
score uint `db:"score"`
1342+
}
1343+
type ClassType struct {
1344+
Grade sql.NullString `db:"grade"`
1345+
ClassName *string `db:"class_name"`
1346+
}
1347+
type Class struct {
1348+
*ClassType
1349+
Score
1350+
}
1351+
1352+
var value []*struct {
1353+
Age int64 `db:"age"`
1354+
Class
1355+
Name string `db:"name"`
1356+
}
1357+
rs := sqlmock.NewRows([]string{
1358+
"name",
1359+
"age",
1360+
"grade",
1361+
"discipline",
1362+
"class_name",
1363+
"score",
1364+
}).
1365+
AddRow("first", 2, nil, "math", "experimental class", 100).
1366+
AddRow("second", 3, "grade one", "chinese", "class three grade two", 99)
1367+
mock.ExpectQuery("select (.+) from users where user=?").
1368+
WithArgs("anyone").WillReturnRows(rs)
1369+
assert.ErrorIs(t, query(context.Background(), db, func(rows *sql.Rows) error {
1370+
return unmarshalRows(&value, rows, true)
1371+
}, "select name, age, grade, discipline, class_name, score from users where user=?",
1372+
"anyone"), ErrNotReadableValue)
1373+
if len(value) > 0 {
1374+
assert.Equal(t, value[0].score, 0)
1375+
}
1376+
})
13271377

13281378
dbtest.RunTest(t, func(db *sql.DB, mock sqlmock.Sqlmock) {
1379+
type Score struct {
1380+
Discipline string
1381+
score uint
1382+
}
1383+
type ClassType struct {
1384+
Grade sql.NullString
1385+
ClassName *string
1386+
}
1387+
type Class struct {
1388+
*ClassType
1389+
Score
1390+
}
1391+
1392+
var value []*struct {
1393+
Age int64
1394+
Class
1395+
Name string
1396+
}
13291397
rs := sqlmock.NewRows([]string{
13301398
"name",
13311399
"age",
@@ -1338,10 +1406,10 @@ func TestAnonymousStructPrError(t *testing.T) {
13381406
AddRow("second", 3, "grade one", "chinese", "class three grade two", 99)
13391407
mock.ExpectQuery("select (.+) from users where user=?").
13401408
WithArgs("anyone").WillReturnRows(rs)
1341-
assert.Error(t, query(context.Background(), db, func(rows *sql.Rows) error {
1409+
assert.ErrorIs(t, query(context.Background(), db, func(rows *sql.Rows) error {
13421410
return unmarshalRows(&value, rows, true)
13431411
}, "select name, age, grade, discipline, class_name, score from users where user=?",
1344-
"anyone"))
1412+
"anyone"), ErrNotMatchDestination)
13451413
if len(value) > 0 {
13461414
assert.Equal(t, value[0].score, 0)
13471415
}

go.mod

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,16 @@ require (
88
github.com/fatih/color v1.18.0
99
github.com/fullstorydev/grpcurl v1.9.3
1010
github.com/go-sql-driver/mysql v1.9.0
11-
github.com/golang-jwt/jwt/v4 v4.5.1
11+
github.com/golang-jwt/jwt/v4 v4.5.2
1212
github.com/golang/mock v1.6.0
1313
github.com/golang/protobuf v1.5.4
1414
github.com/google/uuid v1.6.0
15-
github.com/jackc/pgx/v5 v5.7.2
15+
github.com/jackc/pgx/v5 v5.7.4
1616
github.com/jhump/protoreflect v1.17.0
1717
github.com/olekukonko/tablewriter v0.0.5
1818
github.com/pelletier/go-toml/v2 v2.2.2
1919
github.com/prometheus/client_golang v1.21.1
20-
github.com/redis/go-redis/v9 v9.7.1
20+
github.com/redis/go-redis/v9 v9.7.3
2121
github.com/spaolacci/murmur3 v1.1.0
2222
github.com/stretchr/testify v1.10.0
2323
go.etcd.io/etcd/api/v3 v3.5.15

go.sum

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,8 @@ github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4
6262
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
6363
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
6464
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
65-
github.com/golang-jwt/jwt/v4 v4.5.1 h1:JdqV9zKUdtaa9gdPlywC3aeoEsR681PlKC+4F5gQgeo=
66-
github.com/golang-jwt/jwt/v4 v4.5.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
65+
github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI=
66+
github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
6767
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
6868
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
6969
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
@@ -90,8 +90,8 @@ github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsI
9090
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
9191
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
9292
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
93-
github.com/jackc/pgx/v5 v5.7.2 h1:mLoDLV6sonKlvjIEsV56SkWNCnuNv531l94GaIzO+XI=
94-
github.com/jackc/pgx/v5 v5.7.2/go.mod h1:ncY89UGWxg82EykZUwSpUKEfccBGGYq1xjrOpsbsfGQ=
93+
github.com/jackc/pgx/v5 v5.7.4 h1:9wKznZrhWa2QiHL+NjTSPP6yjl3451BX3imWDnokYlg=
94+
github.com/jackc/pgx/v5 v5.7.4/go.mod h1:ncY89UGWxg82EykZUwSpUKEfccBGGYq1xjrOpsbsfGQ=
9595
github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
9696
github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
9797
github.com/jhump/protoreflect v1.17.0 h1:qOEr613fac2lOuTgWN4tPAtLL7fUSbuJL5X5XumQh94=
@@ -159,8 +159,8 @@ github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ
159159
github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I=
160160
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
161161
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
162-
github.com/redis/go-redis/v9 v9.7.1 h1:4LhKRCIduqXqtvCUlaq9c8bdHOkICjDMrr1+Zb3osAc=
163-
github.com/redis/go-redis/v9 v9.7.1/go.mod h1:f6zhXITC7JUJIlPEiBOTXxJgPLdZcA93GewI7inzyWw=
162+
github.com/redis/go-redis/v9 v9.7.3 h1:YpPyAayJV+XErNsatSElgRZZVCwXX9QzkKYNvO7x0wM=
163+
github.com/redis/go-redis/v9 v9.7.3/go.mod h1:bGUrSggJ9X9GUmZpZNEOQKaANxSGgOEBRltRTZHSvrA=
164164
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
165165
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
166166
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=

rest/engine.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
"github.com/zeromicro/go-zero/rest/handler"
1616
"github.com/zeromicro/go-zero/rest/httpx"
1717
"github.com/zeromicro/go-zero/rest/internal"
18+
"github.com/zeromicro/go-zero/rest/internal/header"
1819
"github.com/zeromicro/go-zero/rest/internal/response"
1920
)
2021

@@ -54,6 +55,9 @@ func newEngine(c RestConf) *engine {
5455
}
5556

5657
func (ng *engine) addRoutes(r featuredRoutes) {
58+
if r.sse {
59+
r.routes = buildSSERoutes(r.routes)
60+
}
5761
ng.routes = append(ng.routes, r)
5862

5963
// need to guarantee the timeout is the max of all routes
@@ -63,6 +67,20 @@ func (ng *engine) addRoutes(r featuredRoutes) {
6367
}
6468
}
6569

70+
func buildSSERoutes(routes []Route) []Route {
71+
for i, route := range routes {
72+
h := route.Handler
73+
routes[i].Handler = func(w http.ResponseWriter, r *http.Request) {
74+
w.Header().Set(header.ContentType, header.ContentTypeEventStream)
75+
w.Header().Set(header.CacheControl, header.CacheControlNoCache)
76+
w.Header().Set(header.Connection, header.ConnectionKeepAlive)
77+
h(w, r)
78+
}
79+
}
80+
81+
return routes
82+
}
83+
6684
func (ng *engine) appendAuthHandler(fr featuredRoutes, chn chain.Chain,
6785
verifier func(chain.Chain) chain.Chain) chain.Chain {
6886
if fr.jwt.enabled {

rest/httpc/requests.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ func buildRequest(ctx context.Context, method, url string, data any) (*http.Requ
105105
req.URL.RawQuery = buildFormQuery(u, val[formKey])
106106
fillHeader(req, val[headerKey])
107107
if hasJsonBody {
108-
req.Header.Set(header.ContentType, header.JsonContentType)
108+
req.Header.Set(header.ContentType, header.ContentTypeJson)
109109
}
110110

111111
return req, nil

rest/httpc/requests_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ func TestDoRequest_NotFound(t *testing.T) {
4545
defer svr.Close()
4646
req, err := http.NewRequest(http.MethodPost, svr.URL, nil)
4747
assert.Nil(t, err)
48-
req.Header.Set(header.ContentType, header.JsonContentType)
48+
req.Header.Set(header.ContentType, header.ContentTypeJson)
4949
resp, err := DoRequest(req)
5050
assert.Nil(t, err)
5151
assert.Equal(t, http.StatusNotFound, resp.StatusCode)

rest/httpc/responses_test.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ func TestParse(t *testing.T) {
1818
}
1919
svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
2020
w.Header().Set("foo", "bar")
21-
w.Header().Set(header.ContentType, header.JsonContentType)
21+
w.Header().Set(header.ContentType, header.ContentTypeJson)
2222
w.Write([]byte(`{"name":"kevin","value":100}`))
2323
}))
2424
defer svr.Close()
@@ -38,7 +38,7 @@ func TestParseHeaderError(t *testing.T) {
3838
}
3939
svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
4040
w.Header().Set("foo", "bar")
41-
w.Header().Set(header.ContentType, header.JsonContentType)
41+
w.Header().Set(header.ContentType, header.ContentTypeJson)
4242
}))
4343
defer svr.Close()
4444
req, err := http.NewRequest(http.MethodGet, svr.URL, nil)
@@ -54,7 +54,7 @@ func TestParseNoBody(t *testing.T) {
5454
}
5555
svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
5656
w.Header().Set("foo", "bar")
57-
w.Header().Set(header.ContentType, header.JsonContentType)
57+
w.Header().Set(header.ContentType, header.ContentTypeJson)
5858
}))
5959
defer svr.Close()
6060
req, err := http.NewRequest(http.MethodGet, svr.URL, nil)
@@ -72,7 +72,7 @@ func TestParseWithZeroValue(t *testing.T) {
7272
}
7373
svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
7474
w.Header().Set("foo", "0")
75-
w.Header().Set(header.ContentType, header.JsonContentType)
75+
w.Header().Set(header.ContentType, header.ContentTypeJson)
7676
w.Write([]byte(`{"bar":0}`))
7777
}))
7878
defer svr.Close()
@@ -90,7 +90,7 @@ func TestParseWithNegativeContentLength(t *testing.T) {
9090
Bar int `json:"bar"`
9191
}
9292
svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
93-
w.Header().Set(header.ContentType, header.JsonContentType)
93+
w.Header().Set(header.ContentType, header.ContentTypeJson)
9494
w.Write([]byte(`{"bar":0}`))
9595
}))
9696
defer svr.Close()
@@ -124,7 +124,7 @@ func TestParseWithNegativeContentLength(t *testing.T) {
124124
func TestParseWithNegativeContentLengthNoBody(t *testing.T) {
125125
var val struct{}
126126
svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
127-
w.Header().Set(header.ContentType, header.JsonContentType)
127+
w.Header().Set(header.ContentType, header.ContentTypeJson)
128128
}))
129129
defer svr.Close()
130130
req, err := http.NewRequest(http.MethodGet, svr.URL, nil)
@@ -156,7 +156,7 @@ func TestParseWithNegativeContentLengthNoBody(t *testing.T) {
156156
func TestParseJsonBody_BodyError(t *testing.T) {
157157
var val struct{}
158158
svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
159-
w.Header().Set(header.ContentType, header.JsonContentType)
159+
w.Header().Set(header.ContentType, header.ContentTypeJson)
160160
}))
161161
defer svr.Close()
162162
req, err := http.NewRequest(http.MethodGet, svr.URL, nil)

0 commit comments

Comments
 (0)