From 529204f6161a9353a82a0fc9afe2004d15f69188 Mon Sep 17 00:00:00 2001 From: Danial Date: Fri, 13 Sep 2024 13:42:10 +0700 Subject: [PATCH 01/11] bump version goravel framework --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index e5df2e1..195d89d 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.21 require ( github.com/gin-gonic/gin v1.10.0 github.com/gookit/validate v1.5.2 - github.com/goravel/framework v1.14.5 + github.com/goravel/framework v1.14.6-0.20240912145232-6543aeadf1bc github.com/rs/cors v1.11.0 github.com/savioxavier/termlink v1.3.0 github.com/spf13/cast v1.6.0 diff --git a/go.sum b/go.sum index 835ebf6..c62e71b 100644 --- a/go.sum +++ b/go.sum @@ -400,6 +400,8 @@ github.com/goravel/file-rotatelogs/v2 v2.4.2 h1:g68AzbePXcm0V2CpUMc9j4qVzcDn7+7a github.com/goravel/file-rotatelogs/v2 v2.4.2/go.mod h1:23VuSW8cBS4ax5cmbV+5AaiLpq25b8UJ96IhbAkdo8I= github.com/goravel/framework v1.14.5 h1:FItqxRGkBK0h/TIknF24TuMZCtBRaSr3DnQLEzhfvXc= github.com/goravel/framework v1.14.5/go.mod h1:rScDXGQZdoVfyxemNPmijlz/2a+lWNOa4jTuak5GGVg= +github.com/goravel/framework v1.14.6-0.20240912145232-6543aeadf1bc h1:mWObAigy7PhrJkq1uK2KvV34JkTb8gIRxD8RU66MQVU= +github.com/goravel/framework v1.14.6-0.20240912145232-6543aeadf1bc/go.mod h1:rScDXGQZdoVfyxemNPmijlz/2a+lWNOa4jTuak5GGVg= github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI= From bded1819f2bd113d7f7ce44a88ae249b3dd3a7a3 Mon Sep 17 00:00:00 2001 From: Danial Date: Fri, 13 Sep 2024 13:42:28 +0700 Subject: [PATCH 02/11] ref: use any as the key type for WithValue --- context.go | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/context.go b/context.go index 34030a4..1f1d272 100644 --- a/context.go +++ b/context.go @@ -15,13 +15,16 @@ func Background() http.Context { return NewContext(ctx) } +type Ctx context.Context + type Context struct { + Ctx instance *gin.Context request http.ContextRequest } func NewContext(ctx *gin.Context) http.Context { - return &Context{instance: ctx} + return &Context{instance: ctx, Ctx: context.Background()} } func (c *Context) Request() http.ContextRequest { @@ -41,18 +44,18 @@ func (c *Context) Response() http.ContextResponse { return NewContextResponse(c.instance, &BodyWriter{ResponseWriter: c.instance.Writer}) } -func (c *Context) WithValue(key string, value any) { - c.instance.Set(key, value) +func (c *Context) WithValue(key any, value any) { + //nolint:all + c.Ctx = context.WithValue(c.Ctx, key, value) } func (c *Context) Context() context.Context { - ctx := context.Background() for key, value := range c.instance.Keys { // nolint - ctx = context.WithValue(ctx, key, value) + c.Ctx = context.WithValue(c.Ctx, key, value) } - return ctx + return c.Ctx } func (c *Context) Deadline() (deadline time.Time, ok bool) { @@ -68,7 +71,7 @@ func (c *Context) Err() error { } func (c *Context) Value(key any) any { - return c.instance.Value(key) + return c.Ctx.Value(key) } func (c *Context) Instance() *gin.Context { From 584e977930dbeb8ca1bd803fd042bc9e9009189c Mon Sep 17 00:00:00 2001 From: Danial Date: Fri, 13 Sep 2024 13:42:53 +0700 Subject: [PATCH 03/11] test: more test cases for WithValue and Context --- context_test.go | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/context_test.go b/context_test.go index 6d0427f..cba5891 100644 --- a/context_test.go +++ b/context_test.go @@ -7,10 +7,26 @@ import ( ) func TestContext(t *testing.T) { + // even with the same underlying empty struct, Go will still distinguish between + // each type declaration + type customType struct{} + type anotherCustomType struct{} + var customTypeKey customType + var anotherCustomTypeKey anotherCustomType + httpCtx := Background() httpCtx.WithValue("Hello", "world") httpCtx.WithValue("Hi", "Goravel") + httpCtx.WithValue(customTypeKey, "halo") + httpCtx.WithValue(anotherCustomTypeKey, "hola") + httpCtx.WithValue(1, "one") + httpCtx.WithValue(2.2, "two point two") + ctx := httpCtx.Context() assert.Equal(t, ctx.Value("Hello").(string), "world") assert.Equal(t, ctx.Value("Hi").(string), "Goravel") + assert.Equal(t, "halo", ctx.Value(customTypeKey)) + assert.Equal(t, "hola", ctx.Value(anotherCustomTypeKey)) + assert.Equal(t, "one", ctx.Value(1)) + assert.Equal(t, "two point two", ctx.Value(2.2)) } From 1ccb45f405cb0b05e112d792ac9acee84923809c Mon Sep 17 00:00:00 2001 From: Danial Date: Fri, 13 Sep 2024 13:44:41 +0700 Subject: [PATCH 04/11] test: swap the expected and actual value in assertion --- context_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/context_test.go b/context_test.go index cba5891..4127268 100644 --- a/context_test.go +++ b/context_test.go @@ -23,8 +23,8 @@ func TestContext(t *testing.T) { httpCtx.WithValue(2.2, "two point two") ctx := httpCtx.Context() - assert.Equal(t, ctx.Value("Hello").(string), "world") - assert.Equal(t, ctx.Value("Hi").(string), "Goravel") + assert.Equal(t, "world", ctx.Value("Hello")) + assert.Equal(t, "Goravel", ctx.Value("Hi")) assert.Equal(t, "halo", ctx.Value(customTypeKey)) assert.Equal(t, "hola", ctx.Value(anotherCustomTypeKey)) assert.Equal(t, "one", ctx.Value(1)) From a9fd2a86f08937f524f13426eb1ea6c5bd139d92 Mon Sep 17 00:00:00 2001 From: Danial Date: Fri, 13 Sep 2024 14:10:44 +0700 Subject: [PATCH 05/11] fix: need to store the key-val to underlying gin too --- context.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/context.go b/context.go index 1f1d272..1062a42 100644 --- a/context.go +++ b/context.go @@ -2,6 +2,7 @@ package gin import ( "context" + "fmt" "net/http/httptest" "time" @@ -45,6 +46,7 @@ func (c *Context) Response() http.ContextResponse { } func (c *Context) WithValue(key any, value any) { + c.instance.Set(fmt.Sprintf("%v", key), value) // need to store the key-val to the underlying gin too //nolint:all c.Ctx = context.WithValue(c.Ctx, key, value) } @@ -71,7 +73,7 @@ func (c *Context) Err() error { } func (c *Context) Value(key any) any { - return c.Ctx.Value(key) + return c.Context().Value(key) } func (c *Context) Instance() *gin.Context { From 8450da88d8be19ffec1b1d50637524d69efeb1dc Mon Sep 17 00:00:00 2001 From: Danial Date: Fri, 13 Sep 2024 14:11:29 +0700 Subject: [PATCH 06/11] test: remove type assert --- group_test.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/group_test.go b/group_test.go index 8bb5dca..a43422a 100644 --- a/group_test.go +++ b/group_test.go @@ -435,16 +435,16 @@ func TestGroup(t *testing.T) { route2.Get("/middleware/{id}", func(ctx contractshttp.Context) contractshttp.Response { return ctx.Response().Success().Json(contractshttp.Json{ "id": ctx.Request().Input("id"), - "ctx": ctx.Value("ctx").(string), - "ctx1": ctx.Value("ctx1").(string), + "ctx": ctx.Value("ctx"), + "ctx1": ctx.Value("ctx1"), }) }) }) route1.Middleware(contextMiddleware2()).Get("/middleware/{id}", func(ctx contractshttp.Context) contractshttp.Response { return ctx.Response().Success().Json(contractshttp.Json{ "id": ctx.Request().Input("id"), - "ctx": ctx.Value("ctx").(string), - "ctx2": ctx.Value("ctx2").(string), + "ctx": ctx.Value("ctx"), + "ctx2": ctx.Value("ctx2"), }) }) }) @@ -462,16 +462,16 @@ func TestGroup(t *testing.T) { route2.Get("/middleware/{id}", func(ctx contractshttp.Context) contractshttp.Response { return ctx.Response().Success().Json(contractshttp.Json{ "id": ctx.Request().Input("id"), - "ctx": ctx.Value("ctx").(string), - "ctx1": ctx.Value("ctx1").(string), + "ctx": ctx.Value("ctx"), + "ctx1": ctx.Value("ctx1"), }) }) }) route1.Middleware(contextMiddleware2()).Get("/middleware/{id}", func(ctx contractshttp.Context) contractshttp.Response { return ctx.Response().Success().Json(contractshttp.Json{ "id": ctx.Request().Input("id"), - "ctx": ctx.Value("ctx").(string), - "ctx2": ctx.Value("ctx2").(string), + "ctx": ctx.Value("ctx"), + "ctx2": ctx.Value("ctx2"), }) }) }) From 63dbea4d1710f4e774695b208abf69e33585cf72 Mon Sep 17 00:00:00 2001 From: Danial Date: Fri, 13 Sep 2024 16:37:44 +0700 Subject: [PATCH 07/11] ref: immediately use `context.Context` as field ctx instead --- context.go | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/context.go b/context.go index 1062a42..cb10159 100644 --- a/context.go +++ b/context.go @@ -16,16 +16,14 @@ func Background() http.Context { return NewContext(ctx) } -type Ctx context.Context - type Context struct { - Ctx + ctx context.Context instance *gin.Context request http.ContextRequest } func NewContext(ctx *gin.Context) http.Context { - return &Context{instance: ctx, Ctx: context.Background()} + return &Context{instance: ctx, ctx: context.Background()} } func (c *Context) Request() http.ContextRequest { @@ -48,16 +46,16 @@ func (c *Context) Response() http.ContextResponse { func (c *Context) WithValue(key any, value any) { c.instance.Set(fmt.Sprintf("%v", key), value) // need to store the key-val to the underlying gin too //nolint:all - c.Ctx = context.WithValue(c.Ctx, key, value) + c.ctx = context.WithValue(c.ctx, key, value) } func (c *Context) Context() context.Context { for key, value := range c.instance.Keys { // nolint - c.Ctx = context.WithValue(c.Ctx, key, value) + c.ctx = context.WithValue(c.ctx, key, value) } - return c.Ctx + return c.ctx } func (c *Context) Deadline() (deadline time.Time, ok bool) { From 3cc933c083d16b48c7049801c02e34a44fbd0009 Mon Sep 17 00:00:00 2001 From: Danial Date: Sat, 14 Sep 2024 23:12:35 +0700 Subject: [PATCH 08/11] feat: helper to get goravel data from gin context --- context.go | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/context.go b/context.go index cb10159..0df0ea3 100644 --- a/context.go +++ b/context.go @@ -11,6 +11,8 @@ import ( "github.com/goravel/framework/contracts/http" ) +const goravelContextKey = "goravel_contextKey" + func Background() http.Context { ctx, _ := gin.CreateTestContext(httptest.NewRecorder()) return NewContext(ctx) @@ -58,6 +60,15 @@ func (c *Context) Context() context.Context { return c.ctx } +func (c *Context) getGoravelCtx() map[any]any { + if val, exist := c.instance.Get(goravelContextKey); exist { + if goravelCtxVal, ok := val.(map[any]any); ok { + return goravelCtxVal + } + } + return make(map[any]any) +} + func (c *Context) Deadline() (deadline time.Time, ok bool) { return c.instance.Deadline() } From 308ae7da9aabd8e02f2283297c0f80ccc6f38ced Mon Sep 17 00:00:00 2001 From: Danial Date: Sat, 14 Sep 2024 23:13:22 +0700 Subject: [PATCH 09/11] ref: use helper to get goravel data from gin context instead --- context.go | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/context.go b/context.go index 0df0ea3..0a74488 100644 --- a/context.go +++ b/context.go @@ -2,7 +2,6 @@ package gin import ( "context" - "fmt" "net/http/httptest" "time" @@ -46,17 +45,16 @@ func (c *Context) Response() http.ContextResponse { } func (c *Context) WithValue(key any, value any) { - c.instance.Set(fmt.Sprintf("%v", key), value) // need to store the key-val to the underlying gin too - //nolint:all - c.ctx = context.WithValue(c.ctx, key, value) + goravelCtx := c.getGoravelCtx() + goravelCtx[key] = value + c.instance.Set(goravelContextKey, goravelCtx) } func (c *Context) Context() context.Context { - for key, value := range c.instance.Keys { - // nolint + for key, value := range c.getGoravelCtx() { + //nolint:all c.ctx = context.WithValue(c.ctx, key, value) } - return c.ctx } From af4a9ad7a066f3b9e4ac6dbad4fa472471987224 Mon Sep 17 00:00:00 2001 From: Danial Date: Sat, 14 Sep 2024 23:14:16 +0700 Subject: [PATCH 10/11] test: add custom key to `WithValue` in group_test --- group_test.go | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/group_test.go b/group_test.go index a43422a..fc3edd4 100644 --- a/group_test.go +++ b/group_test.go @@ -242,6 +242,10 @@ func TestGroup(t *testing.T) { resource := resourceController{} gin.GlobalMiddleware(func(ctx contractshttp.Context) { + type customKey struct{} + var customKeyCtx customKey + ctx.WithValue(customKeyCtx, "context with custom key") + ctx.WithValue(2.2, "two point two") ctx.WithValue("action", "index") ctx.Request().Next() }) @@ -263,6 +267,10 @@ func TestGroup(t *testing.T) { resource := resourceController{} gin.GlobalMiddleware(func(ctx contractshttp.Context) { + type customKey struct{} + var customKeyCtx customKey + ctx.WithValue(customKeyCtx, "context with custom key") + ctx.WithValue(2.2, "two point two") ctx.WithValue("action", "show") ctx.Request().Next() }) @@ -284,6 +292,10 @@ func TestGroup(t *testing.T) { resource := resourceController{} gin.GlobalMiddleware(func(ctx contractshttp.Context) { + type customKey struct{} + var customKeyCtx customKey + ctx.WithValue(customKeyCtx, "context with custom key") + ctx.WithValue(2.2, "two point two") ctx.WithValue("action", "store") ctx.Request().Next() }) @@ -305,6 +317,10 @@ func TestGroup(t *testing.T) { resource := resourceController{} gin.GlobalMiddleware(func(ctx contractshttp.Context) { + type customKey struct{} + var customKeyCtx customKey + ctx.WithValue(customKeyCtx, "context with custom key") + ctx.WithValue(2.2, "two point two") ctx.WithValue("action", "update") ctx.Request().Next() }) @@ -326,6 +342,10 @@ func TestGroup(t *testing.T) { resource := resourceController{} gin.GlobalMiddleware(func(ctx contractshttp.Context) { + type customKey struct{} + var customKeyCtx customKey + ctx.WithValue(customKeyCtx, "context with custom key") + ctx.WithValue(2.2, "two point two") ctx.WithValue("action", "update") ctx.Request().Next() }) @@ -347,6 +367,10 @@ func TestGroup(t *testing.T) { resource := resourceController{} gin.GlobalMiddleware(func(ctx contractshttp.Context) { + type customKey struct{} + var customKeyCtx customKey + ctx.WithValue(customKeyCtx, "context with custom key") + ctx.WithValue(2.2, "two point two") ctx.WithValue("action", "destroy") ctx.Request().Next() }) @@ -564,6 +588,9 @@ func abortMiddleware() contractshttp.Middleware { func contextMiddleware() contractshttp.Middleware { return func(ctx contractshttp.Context) { + type customKey struct{} + var customKeyCtx customKey + ctx.WithValue(customKeyCtx, "context with custom key") ctx.WithValue("ctx", "Goravel") ctx.Request().Next() @@ -572,6 +599,7 @@ func contextMiddleware() contractshttp.Middleware { func contextMiddleware1() contractshttp.Middleware { return func(ctx contractshttp.Context) { + ctx.WithValue(2.2, "two point two") ctx.WithValue("ctx1", "Hello") ctx.Request().Next() From 5eeae94d7c4edb4dccd44133ca45f00fab416196 Mon Sep 17 00:00:00 2001 From: Danial Date: Sun, 15 Sep 2024 13:21:21 +0700 Subject: [PATCH 11/11] ref: remove the unnecessary ctx of `context.Context` --- context.go | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/context.go b/context.go index 0a74488..9d87ee9 100644 --- a/context.go +++ b/context.go @@ -18,13 +18,12 @@ func Background() http.Context { } type Context struct { - ctx context.Context instance *gin.Context request http.ContextRequest } func NewContext(ctx *gin.Context) http.Context { - return &Context{instance: ctx, ctx: context.Background()} + return &Context{instance: ctx} } func (c *Context) Request() http.ContextRequest { @@ -50,13 +49,7 @@ func (c *Context) WithValue(key any, value any) { c.instance.Set(goravelContextKey, goravelCtx) } -func (c *Context) Context() context.Context { - for key, value := range c.getGoravelCtx() { - //nolint:all - c.ctx = context.WithValue(c.ctx, key, value) - } - return c.ctx -} +func (c *Context) Context() context.Context { return c } func (c *Context) getGoravelCtx() map[any]any { if val, exist := c.instance.Get(goravelContextKey); exist { @@ -80,7 +73,7 @@ func (c *Context) Err() error { } func (c *Context) Value(key any) any { - return c.Context().Value(key) + return c.getGoravelCtx()[key] } func (c *Context) Instance() *gin.Context {