diff --git a/docs/advanced-guide/injecting-databases-drivers/page.md b/docs/advanced-guide/injecting-databases-drivers/page.md index f64045ae6..7b42419ec 100644 --- a/docs/advanced-guide/injecting-databases-drivers/page.md +++ b/docs/advanced-guide/injecting-databases-drivers/page.md @@ -260,3 +260,89 @@ func main() { app.Run() } ``` + +## Solr +GoFr supports injecting Solr database that supports the following interface. Any driver that implements the interface can be added +using `app.AddSolr()` method, and user's can use Solr DB across application with `gofr.Context`. + +```go +type Solr interface { + Search(ctx context.Context, collection string, params map[string]any) (any, error) + Create(ctx context.Context, collection string, document *bytes.Buffer, params map[string]any) (any, error) + Update(ctx context.Context, collection string, document *bytes.Buffer, params map[string]any) (any, error) + Delete(ctx context.Context, collection string, document *bytes.Buffer, params map[string]any) (any, error) + + Retrieve(ctx context.Context, collection string, params map[string]any) (any, error) + ListFields(ctx context.Context, collection string, params map[string]any) (any, error) + AddField(ctx context.Context, collection string, document *bytes.Buffer) (any, error) + UpdateField(ctx context.Context, collection string, document *bytes.Buffer) (any, error) + DeleteField(ctx context.Context, collection string, document *bytes.Buffer) (any, error) +} +``` + +User's can easily inject a driver that supports this interface, this provides usability +without compromising the extensibility to use multiple databases. + +```go +package main + +import ( + "bytes" + "encoding/json" + "errors" + + "gofr.dev/pkg/gofr" + "gofr.dev/pkg/gofr/datasource/solr" +) + +func main() { + app := gofr.New() + + app.AddSolr(solr.New(solr.Config{ + Host: "localhost", + Port: "2020", + })) + + app.POST("/solr", post) + app.GET("/solr", get) + + app.Run() +} + +type Person struct { + Name string + Age int +} + +func post(c *gofr.Context) (interface{}, error) { + p := Person{Name: "Srijan", Age: 24} + body, _ := json.Marshal(p) + + resp, err := c.Solr.Create(c, "test", bytes.NewBuffer(body), nil) + if err != nil { + return nil, err + } + + return resp, nil +} + +func get(c *gofr.Context) (interface{}, error) { + resp, err := c.Solr.Search(c, "test", nil) + if err != nil { + return nil, err + } + + res, ok := resp.(solr.Response) + if !ok { + return nil, errors.New("invalid response type") + } + + b, _ := json.Marshal(res.Data) + err = json.Unmarshal(b, &Person{}) + if err != nil { + return nil, err + } + + return resp, nil +} +``` diff --git a/go.mod b/go.mod index 5efedd1ca..65e311451 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( github.com/joho/godotenv v1.5.1 github.com/lib/pq v1.10.9 github.com/pkg/errors v0.9.1 - github.com/prometheus/client_golang v1.20.2 + github.com/prometheus/client_golang v1.20.3 github.com/redis/go-redis/extra/redisotel/v9 v9.0.5 github.com/redis/go-redis/v9 v9.6.1 github.com/segmentio/kafka-go v0.4.47 @@ -35,22 +35,22 @@ require ( go.opentelemetry.io/otel/sdk/metric v1.29.0 go.opentelemetry.io/otel/trace v1.29.0 go.uber.org/mock v0.4.0 - golang.org/x/oauth2 v0.22.0 + golang.org/x/oauth2 v0.23.0 golang.org/x/sync v0.8.0 - golang.org/x/term v0.23.0 - golang.org/x/text v0.17.0 + golang.org/x/term v0.24.0 + golang.org/x/text v0.18.0 google.golang.org/api v0.195.0 - google.golang.org/grpc v1.66.0 + google.golang.org/grpc v1.66.1 google.golang.org/protobuf v1.34.2 - modernc.org/sqlite v1.32.0 + modernc.org/sqlite v1.33.0 ) require ( cloud.google.com/go v0.115.1 // indirect - cloud.google.com/go/auth v0.9.1 // indirect + cloud.google.com/go/auth v0.9.3 // indirect cloud.google.com/go/auth/oauth2adapt v0.2.4 // indirect cloud.google.com/go/compute/metadata v0.5.0 // indirect - cloud.google.com/go/iam v1.1.13 // indirect + cloud.google.com/go/iam v1.2.0 // indirect filippo.io/edwards25519 v1.1.0 // indirect github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a // indirect github.com/beorn7/perks v1.0.1 // indirect @@ -65,7 +65,7 @@ require ( github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/google/go-cmp v0.6.0 // indirect github.com/google/s2a-go v0.1.8 // indirect - github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.3.3 // indirect github.com/googleapis/gax-go/v2 v2.13.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 // indirect github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect @@ -85,19 +85,18 @@ require ( github.com/yuin/gopher-lua v1.1.1 // indirect go.einride.tech/aip v0.67.1 // indirect go.opencensus.io v0.24.0 // indirect - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0 // indirect go.opentelemetry.io/proto/otlp v1.3.1 // indirect golang.org/x/crypto v0.26.0 // indirect golang.org/x/net v0.28.0 // indirect - golang.org/x/sys v0.24.0 // indirect + golang.org/x/sys v0.25.0 // indirect golang.org/x/time v0.6.0 // indirect - google.golang.org/genproto v0.0.0-20240823204242-4ba0660f739c // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240822170219-fc7c04adadcd // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240823204242-4ba0660f739c // indirect + google.golang.org/genproto v0.0.0-20240903143218-8af14fe29dc1 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240827150818-7e3bb234dfed // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 // indirect - modernc.org/libc v1.55.3 // indirect modernc.org/mathutil v1.6.0 // indirect modernc.org/memory v1.8.0 // indirect modernc.org/strutil v1.2.0 // indirect diff --git a/go.sum b/go.sum index f9e4b8f00..205761380 100644 --- a/go.sum +++ b/go.sum @@ -1,18 +1,18 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.115.1 h1:Jo0SM9cQnSkYfp44+v+NQXHpcHqlnRJk2qxh6yvxxxQ= cloud.google.com/go v0.115.1/go.mod h1:DuujITeaufu3gL68/lOFIirVNJwQeyf5UXyi+Wbgknc= -cloud.google.com/go/auth v0.9.1 h1:+pMtLEV2k0AXKvs/tGZojuj6QaioxfUjOpMsG5Gtx+w= -cloud.google.com/go/auth v0.9.1/go.mod h1:Sw8ocT5mhhXxFklyhT12Eiy0ed6tTrPMCJjSI8KhYLk= +cloud.google.com/go/auth v0.9.3 h1:VOEUIAADkkLtyfr3BLa3R8Ed/j6w1jTBmARx+wb5w5U= +cloud.google.com/go/auth v0.9.3/go.mod h1:7z6VY+7h3KUdRov5F1i8NDP5ZzWKYmEPO842BgCsmTk= cloud.google.com/go/auth/oauth2adapt v0.2.4 h1:0GWE/FUsXhf6C+jAkWgYm7X9tK8cuEIfy19DBn6B6bY= cloud.google.com/go/auth/oauth2adapt v0.2.4/go.mod h1:jC/jOpwFP6JBxhB3P5Rr0a9HLMC/Pe3eaL4NmdvqPtc= cloud.google.com/go/compute/metadata v0.5.0 h1:Zr0eK8JbFv6+Wi4ilXAR8FJ3wyNdpxHKJNPos6LTZOY= cloud.google.com/go/compute/metadata v0.5.0/go.mod h1:aHnloV2TPI38yx4s9+wAZhHykWvVCfu7hQbF+9CWoiY= -cloud.google.com/go/iam v1.1.13 h1:7zWBXG9ERbMLrzQBRhFliAV+kjcRToDTgQT3CTwYyv4= -cloud.google.com/go/iam v1.1.13/go.mod h1:K8mY0uSXwEXS30KrnVb+j54LB/ntfZu1dr+4zFMNbus= -cloud.google.com/go/kms v1.18.5 h1:75LSlVs60hyHK3ubs2OHd4sE63OAMcM2BdSJc2bkuM4= -cloud.google.com/go/kms v1.18.5/go.mod h1:yXunGUGzabH8rjUPImp2ndHiGolHeWJJ0LODLedicIY= -cloud.google.com/go/longrunning v0.5.12 h1:5LqSIdERr71CqfUsFlJdBpOkBH8FBCFD7P1nTWy3TYE= -cloud.google.com/go/longrunning v0.5.12/go.mod h1:S5hMV8CDJ6r50t2ubVJSKQVv5u0rmik5//KgLO3k4lU= +cloud.google.com/go/iam v1.2.0 h1:kZKMKVNk/IsSSc/udOb83K0hL/Yh/Gcqpz+oAkoIFN8= +cloud.google.com/go/iam v1.2.0/go.mod h1:zITGuWgsLZxd8OwAlX+eMFgZDXzBm7icj1PVTYG766Q= +cloud.google.com/go/kms v1.19.0 h1:x0OVJDl6UH1BSX4THKlMfdcFWoE4ruh90ZHuilZekrU= +cloud.google.com/go/kms v1.19.0/go.mod h1:e4imokuPJUc17Trz2s6lEXFDt8bgDmvpVynH39bdrHM= +cloud.google.com/go/longrunning v0.6.0 h1:mM1ZmaNsQsnb+5n1DNPeL0KwQd9jQRqSqSDEkBZr+aI= +cloud.google.com/go/longrunning v0.6.0/go.mod h1:uHzSZqW89h7/pasCWNYdUpwGz3PcVWhrWupreVPYLts= cloud.google.com/go/pubsub v1.42.0 h1:PVTbzorLryFL5ue8esTS2BfehUs0ahyNOY9qcd+HMOs= cloud.google.com/go/pubsub v1.42.0/go.mod h1:KADJ6s4MbTwhXmse/50SebEhE4SmUwHi48z3/dHar1Y= filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= @@ -108,8 +108,8 @@ github.com/google/s2a-go v0.1.8/go.mod h1:6iNWHTpQ+nfNRN5E00MSdfDwVesa8hhS32PhPO github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs= -github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= +github.com/googleapis/enterprise-certificate-proxy v0.3.3 h1:QRje2j5GZimBzlbhGA2V2QlGNgL8G6e+wGo/+/2bWI0= +github.com/googleapis/enterprise-certificate-proxy v0.3.3/go.mod h1:YKe7cfqYXjKGpGvmSg28/fFvhNzinZQm8DGnaburhGA= github.com/googleapis/gax-go/v2 v2.13.0 h1:yitjD5f7jQHhyDsnhKEBU52NdvvdSeGzlAnDPT0hH1s= github.com/googleapis/gax-go/v2 v2.13.0/go.mod h1:Z/fvTZXF8/uw7Xu5GuslPw+bplx6SS338j1Is2S+B7A= github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= @@ -165,8 +165,8 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v1.20.2 h1:5ctymQzZlyOON1666svgwn3s6IKWgfbjsejTMiXIyjg= -github.com/prometheus/client_golang v1.20.2/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= +github.com/prometheus/client_golang v1.20.3 h1:oPksm4K8B+Vt35tUhw6GbSNSgVlVSBH0qELP/7u83l4= +github.com/prometheus/client_golang v1.20.3/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= @@ -218,8 +218,8 @@ go.einride.tech/aip v0.67.1 h1:d/4TW92OxXBngkSOwWS2CH5rez869KpKMaN44mdxkFI= go.einride.tech/aip v0.67.1/go.mod h1:ZGX4/zKw8dcgzdLsrvpOOGxfxI2QSk12SlP7d6c0/XI= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 h1:4Pp6oUg3+e/6M4C0A/3kJ2VYa++dsWVTtGgLVj5xtHg= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0/go.mod h1:Mjt1i1INqiaoZOMGR1RIUJN+i3ChKoFRqzrRQhlkbs0= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0 h1:r6I7RJCN86bpD/FQwedZ0vSixDpwuWREjW9oRMsmqDc= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0/go.mod h1:B9yO6b04uB80CzjedvewuqDhxJxi11s7/GtiGa8bAjI= go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.53.0 h1:IVtyPth4Rs5P8wIf0mP2KVKFNTJ4paX9qQ4Hkh5gFdc= go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.53.0/go.mod h1:ImRBLMJv177/pwiLZ7tU7HDGNdBv7rS0HQ99eN/zBl8= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 h1:4K4tsIXefpVJtvA/8srF4V4y0akAoPHkIslgAkjixJA= @@ -287,8 +287,8 @@ golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.22.0 h1:BzDx2FehcG7jJwgWLELCdmLuxk2i+x9UDpSiss2u0ZA= -golang.org/x/oauth2 v0.22.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs= +golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -312,15 +312,15 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= -golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= +golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= -golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU= -golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk= +golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM= +golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= @@ -328,8 +328,8 @@ golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= -golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= +golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U= golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -357,20 +357,20 @@ google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoA google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20240823204242-4ba0660f739c h1:TYOEhrQMrNDTAd2rX9m+WgGr8Ku6YNuj1D7OX6rWSok= -google.golang.org/genproto v0.0.0-20240823204242-4ba0660f739c/go.mod h1:2rC5OendXvZ8wGEo/cSLheztrZDZaSoHanUcd1xtZnw= -google.golang.org/genproto/googleapis/api v0.0.0-20240822170219-fc7c04adadcd h1:BBOTEWLuuEGQy9n1y9MhVJ9Qt0BDu21X8qZs71/uPZo= -google.golang.org/genproto/googleapis/api v0.0.0-20240822170219-fc7c04adadcd/go.mod h1:fO8wJzT2zbQbAjbIoos1285VfEIYKDDY+Dt+WpTkh6g= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240823204242-4ba0660f739c h1:Kqjm4WpoWvwhMPcrAczoTyMySQmYa9Wy2iL6Con4zn8= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240823204242-4ba0660f739c/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= +google.golang.org/genproto v0.0.0-20240903143218-8af14fe29dc1 h1:BulPr26Jqjnd4eYDVe+YvyR7Yc2vJGkO5/0UxD0/jZU= +google.golang.org/genproto v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:hL97c3SYopEHblzpxRL4lSs523++l8DYxGM1FQiYmb4= +google.golang.org/genproto/googleapis/api v0.0.0-20240827150818-7e3bb234dfed h1:3RgNmBoI9MZhsj3QxC+AP/qQhNwpCLOvYDYYsFrhFt0= +google.golang.org/genproto/googleapis/api v0.0.0-20240827150818-7e3bb234dfed/go.mod h1:OCdP9MfskevB/rbYvHTsXTtKC+3bHWajPdoKgjcYkfo= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 h1:pPJltXNxVzT4pK9yD8vR9X75DaWYYmLGMsEvBfFQZzQ= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.66.0 h1:DibZuoBznOxbDQxRINckZcUvnCEvrW9pcWIE2yF9r1c= -google.golang.org/grpc v1.66.0/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y= +google.golang.org/grpc v1.66.1 h1:hO5qAXR19+/Z44hmvIM4dQFMSYX9XcWsByfoxutBpAM= +google.golang.org/grpc v1.66.1/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -398,28 +398,16 @@ gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU= gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -modernc.org/cc/v4 v4.21.4 h1:3Be/Rdo1fpr8GrQ7IVw9OHtplU4gWbb+wNgeoBMmGLQ= -modernc.org/cc/v4 v4.21.4/go.mod h1:HM7VJTZbUCR3rV8EYBi9wxnJ0ZBRiGE5OeGXNA0IsLQ= -modernc.org/ccgo/v4 v4.19.2 h1:lwQZgvboKD0jBwdaeVCTouxhxAyN6iawF3STraAal8Y= -modernc.org/ccgo/v4 v4.19.2/go.mod h1:ysS3mxiMV38XGRTTcgo0DQTeTmAO4oCmJl1nX9VFI3s= modernc.org/fileutil v1.3.0 h1:gQ5SIzK3H9kdfai/5x41oQiKValumqNTDXMvKo62HvE= modernc.org/fileutil v1.3.0/go.mod h1:XatxS8fZi3pS8/hKG2GH/ArUogfxjpEKs3Ku3aK4JyQ= -modernc.org/gc/v2 v2.4.1 h1:9cNzOqPyMJBvrUipmynX0ZohMhcxPtMccYgGOJdOiBw= -modernc.org/gc/v2 v2.4.1/go.mod h1:wzN5dK1AzVGoH6XOzc3YZ+ey/jPgYHLuVckd62P0GYU= modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 h1:5D53IMaUuA5InSeMu9eJtlQXS2NxAhyWQvkKEgXZhHI= modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6/go.mod h1:Qz0X07sNOR1jWYCrJMEnbW/X55x206Q7Vt4mz6/wHp4= -modernc.org/libc v1.55.3 h1:AzcW1mhlPNrRtjS5sS+eW2ISCgSOLLNyFzRh/V3Qj/U= -modernc.org/libc v1.55.3/go.mod h1:qFXepLhz+JjFThQ4kzwzOjA/y/artDeg+pcYnY+Q83w= modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4= modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo= modernc.org/memory v1.8.0 h1:IqGTL6eFMaDZZhEWwcREgeMXYwmW83LYW8cROZYkg+E= modernc.org/memory v1.8.0/go.mod h1:XPZ936zp5OMKGWPqbD3JShgd/ZoQ7899TUuQqxY+peU= -modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4= -modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= -modernc.org/sortutil v1.2.0 h1:jQiD3PfS2REGJNzNCMMaLSp/wdMNieTbKX920Cqdgqc= -modernc.org/sortutil v1.2.0/go.mod h1:TKU2s7kJMf1AE84OoiGppNHJwvB753OYfNl2WRb++Ss= -modernc.org/sqlite v1.32.0 h1:6BM4uGza7bWypsw4fdLRsLxut6bHe4c58VeqjRgST8s= -modernc.org/sqlite v1.32.0/go.mod h1:UqoylwmTb9F+IqXERT8bW9zzOWN8qwAIcLdzeBZs4hA= +modernc.org/sqlite v1.33.0 h1:WWkA/T2G17okiLGgKAj4/RMIvgyMT19yQ038160IeYk= +modernc.org/sqlite v1.33.0/go.mod h1:9uQ9hF/pCZoYZK73D/ud5Z7cIRIILSZI8NdIemVMTX8= modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA= modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0= modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= diff --git a/pkg/gofr/container/container.go b/pkg/gofr/container/container.go index 7db9062a3..ad933fd0c 100644 --- a/pkg/gofr/container/container.go +++ b/pkg/gofr/container/container.go @@ -44,6 +44,7 @@ type Container struct { Cassandra Cassandra Clickhouse Clickhouse Mongo Mongo + Solr Solr KVStore KVStore diff --git a/pkg/gofr/container/datasources.go b/pkg/gofr/container/datasources.go index 10f33d21b..8ba60a943 100644 --- a/pkg/gofr/container/datasources.go +++ b/pkg/gofr/container/datasources.go @@ -1,6 +1,7 @@ package container import ( + "bytes" "context" "database/sql" @@ -266,3 +267,24 @@ type KVStoreProvider interface { provider } + +type Solr interface { + Search(ctx context.Context, collection string, params map[string]any) (any, error) + Create(ctx context.Context, collection string, document *bytes.Buffer, params map[string]any) (any, error) + Update(ctx context.Context, collection string, document *bytes.Buffer, params map[string]any) (any, error) + Delete(ctx context.Context, collection string, document *bytes.Buffer, params map[string]any) (any, error) + + Retrieve(ctx context.Context, collection string, params map[string]any) (any, error) + ListFields(ctx context.Context, collection string, params map[string]any) (any, error) + AddField(ctx context.Context, collection string, document *bytes.Buffer) (any, error) + UpdateField(ctx context.Context, collection string, document *bytes.Buffer) (any, error) + DeleteField(ctx context.Context, collection string, document *bytes.Buffer) (any, error) + + HealthChecker +} + +type SolrProvider interface { + Solr + + provider +} diff --git a/pkg/gofr/container/mock_container.go b/pkg/gofr/container/mock_container.go index 368ed9e30..104f927d7 100644 --- a/pkg/gofr/container/mock_container.go +++ b/pkg/gofr/container/mock_container.go @@ -13,19 +13,35 @@ import ( "gofr.dev/pkg/gofr/datasource/pubsub" "gofr.dev/pkg/gofr/datasource/sql" "gofr.dev/pkg/gofr/logging" + "gofr.dev/pkg/gofr/service" ) type Mocks struct { - Redis *MockRedis - SQL *mockSQL - Clickhouse *MockClickhouse - Cassandra *MockCassandra - Mongo *MockMongo - KVStore *MockKVStore - File *file.MockFileSystemProvider + Redis *MockRedis + SQL *mockSQL + Clickhouse *MockClickhouse + Cassandra *MockCassandra + Mongo *MockMongo + KVStore *MockKVStore + File *file.MockFileSystemProvider + HTTPService *service.MockHTTP } -func NewMockContainer(t *testing.T) (*Container, Mocks) { +type options func(c *Container, ctrl *gomock.Controller) any + +//nolint:revive //Because user should not access the options, and we might change it to an interface in the future. +func WithMockHTTPService(httpServiceNames ...string) options { + return func(c *Container, ctrl *gomock.Controller) any { + mockservice := service.NewMockHTTP(ctrl) + for _, s := range httpServiceNames { + c.Services[s] = mockservice + } + + return mockservice + } +} + +func NewMockContainer(t *testing.T, options ...options) (*Container, Mocks) { t.Helper() container := &Container{} @@ -62,14 +78,28 @@ func NewMockContainer(t *testing.T) (*Container, Mocks) { fileStoreMock := file.NewMockFileSystemProvider(ctrl) container.File = fileStoreMock + var httpMock *service.MockHTTP + + container.Services = make(map[string]service.HTTP) + + for _, option := range options { + optionsAdded := option(container, ctrl) + + val, ok := optionsAdded.(*service.MockHTTP) + if ok { + httpMock = val + } + } + mocks := Mocks{ - Redis: redisMock, - SQL: sqlMockWrapper, - Clickhouse: clickhouseMock, - Cassandra: cassandraMock, - Mongo: mongoMock, - KVStore: kvStoreMock, - File: fileStoreMock, + Redis: redisMock, + SQL: sqlMockWrapper, + Clickhouse: clickhouseMock, + Cassandra: cassandraMock, + Mongo: mongoMock, + KVStore: kvStoreMock, + File: fileStoreMock, + HTTPService: httpMock, } redisMock.EXPECT().Close().AnyTimes() diff --git a/pkg/gofr/container/mockcontainer_test.go b/pkg/gofr/container/mockcontainer_test.go index 79b17be46..21a57680c 100644 --- a/pkg/gofr/container/mockcontainer_test.go +++ b/pkg/gofr/container/mockcontainer_test.go @@ -1,14 +1,59 @@ package container import ( + "bytes" "context" + "net/http/httptest" "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "gofr.dev/pkg/gofr/datasource" ) +func Test_HttpServiceMock(t *testing.T) { + test := struct { + desc string + path string + statusCode int + expectedRes string + }{ + + desc: "simple service handler", + path: "/fact", + expectedRes: `{"data":{"fact":"Cats have 3 eyelids.","length":20}}` + "\n", + statusCode: 200, + } + + httpservices := []string{"cat-facts", "cat-facts1", "cat-facts2"} + + _, mock := NewMockContainer(t, WithMockHTTPService(httpservices...)) + + res := httptest.NewRecorder() + res.Body = bytes.NewBufferString(`{"fact":"Cats have 3 eyelids.","length":20}` + "\n") + res.Code = test.statusCode + result := res.Result() + + // Setting mock expectations + mock.HTTPService.EXPECT().Get(context.Background(), "fact", map[string]interface{}{ + "max_length": 20, + }).Return(result, nil) + + resp, err := mock.HTTPService.Get(context.Background(), "fact", map[string]interface{}{ + "max_length": 20, + }) + + require.NoError(t, err) + assert.Equal(t, resp, result) + + err = result.Body.Close() + require.NoError(t, err) + + err = resp.Body.Close() + require.NoError(t, err) +} + // TestMockSQL_Select tests the successful operation of SQL mocking for SELECT statements. // It checks that the mock expectations are correctly set and that the SQL database function // is called as expected. diff --git a/pkg/gofr/datasource/README.md b/pkg/gofr/datasource/README.md index 4bb0c7b46..2912121f1 100644 --- a/pkg/gofr/datasource/README.md +++ b/pkg/gofr/datasource/README.md @@ -81,5 +81,4 @@ Therefore, GoFr utilizes a pluggable approach for new datasources by separating | Clickhouse | | ✅ | ✅ | | ✅ | | FTP | | ✅ | | | ✅ | | SFTP | | ✅ | | | ✅ | - - +| Solr | | ✅ | ✅ | | ✅ | diff --git a/pkg/gofr/datasource/file/sftp/go.mod b/pkg/gofr/datasource/file/sftp/go.mod index dd5dea8df..56803d4d6 100644 --- a/pkg/gofr/datasource/file/sftp/go.mod +++ b/pkg/gofr/datasource/file/sftp/go.mod @@ -8,7 +8,7 @@ require ( github.com/pkg/sftp v1.13.6 github.com/stretchr/testify v1.9.0 go.uber.org/mock v0.4.0 - gofr.dev v0.0.0-00010101000000-000000000000 + gofr.dev v0.19.0 golang.org/x/crypto v0.26.0 ) @@ -18,6 +18,6 @@ require ( github.com/kr/fs v0.1.0 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - golang.org/x/sys v0.24.0 // indirect + golang.org/x/sys v0.25.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/pkg/gofr/datasource/file/sftp/go.sum b/pkg/gofr/datasource/file/sftp/go.sum index c65cdd2e9..41f95311c 100644 --- a/pkg/gofr/datasource/file/sftp/go.sum +++ b/pkg/gofr/datasource/file/sftp/go.sum @@ -40,6 +40,7 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= diff --git a/pkg/gofr/datasource/solr/go.mod b/pkg/gofr/datasource/solr/go.mod new file mode 100644 index 000000000..4f4636168 --- /dev/null +++ b/pkg/gofr/datasource/solr/go.mod @@ -0,0 +1,14 @@ +module gofr.dev/pkg/gofr/datasource/solr + +go 1.22 + +require ( + github.com/stretchr/testify v1.9.0 + go.uber.org/mock v0.4.0 +) + +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/pkg/gofr/datasource/solr/go.sum b/pkg/gofr/datasource/solr/go.sum new file mode 100644 index 000000000..721144c3c --- /dev/null +++ b/pkg/gofr/datasource/solr/go.sum @@ -0,0 +1,12 @@ +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU= +go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/pkg/gofr/datasource/solr/logger.go b/pkg/gofr/datasource/solr/logger.go new file mode 100644 index 000000000..76117c471 --- /dev/null +++ b/pkg/gofr/datasource/solr/logger.go @@ -0,0 +1,42 @@ +package solr + +import ( + "fmt" + "io" + "regexp" + "strings" +) + +type Logger interface { + Debug(args ...any) + Debugf(pattern string, args ...any) + Info(args ...any) + Infof(pattern string, args ...any) + Error(args ...any) + Errorf(patter string, args ...any) +} + +type QueryLog struct { + Type string `json:"type"` + Url string `json:"Url"` + Duration int64 `json:"duration"` +} + +func (ql *QueryLog) PrettyPrint(writer io.Writer) { + fmt.Fprintf(writer, "\u001B[38;5;8m%-32s \u001B[38;5;206m%-6s\u001B[0m %8d\u001B[38;5;8mµs\u001B[0m %s\n", + clean(ql.Url), "SOLR", ql.Duration, clean(ql.Type)) +} + +// clean takes a string query as input and performs two operations to clean it up: +// 1. It replaces multiple consecutive whitespace characters with a single space. +// 2. It trims leading and trailing whitespace from the string. +// The cleaned-up query string is then returned. +func clean(query string) string { + // Replace multiple consecutive whitespace characters with a single space + query = regexp.MustCompile(`\s+`).ReplaceAllString(query, " ") + + // Trim leading and trailing whitespace from the string + query = strings.TrimSpace(query) + + return query +} diff --git a/pkg/gofr/datasource/solr/metrics.go b/pkg/gofr/datasource/solr/metrics.go new file mode 100644 index 000000000..a8adfd1c2 --- /dev/null +++ b/pkg/gofr/datasource/solr/metrics.go @@ -0,0 +1,9 @@ +package solr + +import "context" + +type Metrics interface { + NewHistogram(name, desc string, buckets ...float64) + + RecordHistogram(ctx context.Context, name string, value float64, labels ...string) +} diff --git a/pkg/gofr/datasource/solr/mock_logger.go b/pkg/gofr/datasource/solr/mock_logger.go new file mode 100644 index 000000000..150c40af7 --- /dev/null +++ b/pkg/gofr/datasource/solr/mock_logger.go @@ -0,0 +1,138 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: logger.go +// +// Generated by this command: +// +// mockgen -source=logger.go -destination=mock_logger.go -package=solr +// + +// Package solr is a generated GoMock package. +package solr + +import ( + reflect "reflect" + + gomock "go.uber.org/mock/gomock" +) + +// MockLogger is a mock of Logger interface. +type MockLogger struct { + ctrl *gomock.Controller + recorder *MockLoggerMockRecorder +} + +// MockLoggerMockRecorder is the mock recorder for MockLogger. +type MockLoggerMockRecorder struct { + mock *MockLogger +} + +// NewMockLogger creates a new mock instance. +func NewMockLogger(ctrl *gomock.Controller) *MockLogger { + mock := &MockLogger{ctrl: ctrl} + mock.recorder = &MockLoggerMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockLogger) EXPECT() *MockLoggerMockRecorder { + return m.recorder +} + +// Debug mocks base method. +func (m *MockLogger) Debug(args ...any) { + m.ctrl.T.Helper() + varargs := []any{} + for _, a := range args { + varargs = append(varargs, a) + } + m.ctrl.Call(m, "Debug", varargs...) +} + +// Debug indicates an expected call of Debug. +func (mr *MockLoggerMockRecorder) Debug(args ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Debug", reflect.TypeOf((*MockLogger)(nil).Debug), args...) +} + +// Debugf mocks base method. +func (m *MockLogger) Debugf(pattern string, args ...any) { + m.ctrl.T.Helper() + varargs := []any{pattern} + for _, a := range args { + varargs = append(varargs, a) + } + m.ctrl.Call(m, "Debugf", varargs...) +} + +// Debugf indicates an expected call of Debugf. +func (mr *MockLoggerMockRecorder) Debugf(pattern any, args ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{pattern}, args...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Debugf", reflect.TypeOf((*MockLogger)(nil).Debugf), varargs...) +} + +// Error mocks base method. +func (m *MockLogger) Error(args ...any) { + m.ctrl.T.Helper() + varargs := []any{} + for _, a := range args { + varargs = append(varargs, a) + } + m.ctrl.Call(m, "Error", varargs...) +} + +// Error indicates an expected call of Error. +func (mr *MockLoggerMockRecorder) Error(args ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Error", reflect.TypeOf((*MockLogger)(nil).Error), args...) +} + +// Errorf mocks base method. +func (m *MockLogger) Errorf(patter string, args ...any) { + m.ctrl.T.Helper() + varargs := []any{patter} + for _, a := range args { + varargs = append(varargs, a) + } + m.ctrl.Call(m, "Errorf", varargs...) +} + +// Errorf indicates an expected call of Errorf. +func (mr *MockLoggerMockRecorder) Errorf(patter any, args ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{patter}, args...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Errorf", reflect.TypeOf((*MockLogger)(nil).Errorf), varargs...) +} + +// Info mocks base method. +func (m *MockLogger) Info(args ...any) { + m.ctrl.T.Helper() + varargs := []any{} + for _, a := range args { + varargs = append(varargs, a) + } + m.ctrl.Call(m, "Info", varargs...) +} + +// Info indicates an expected call of Info. +func (mr *MockLoggerMockRecorder) Info(args ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Info", reflect.TypeOf((*MockLogger)(nil).Info), args...) +} + +// Infof mocks base method. +func (m *MockLogger) Infof(pattern string, args ...any) { + m.ctrl.T.Helper() + varargs := []any{pattern} + for _, a := range args { + varargs = append(varargs, a) + } + m.ctrl.Call(m, "Infof", varargs...) +} + +// Infof indicates an expected call of Infof. +func (mr *MockLoggerMockRecorder) Infof(pattern any, args ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{pattern}, args...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Infof", reflect.TypeOf((*MockLogger)(nil).Infof), varargs...) +} diff --git a/pkg/gofr/datasource/solr/mock_metrics.go b/pkg/gofr/datasource/solr/mock_metrics.go new file mode 100644 index 000000000..ae819659e --- /dev/null +++ b/pkg/gofr/datasource/solr/mock_metrics.go @@ -0,0 +1,74 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: metrics.go +// +// Generated by this command: +// +// mockgen -source=metrics.go -destination=mock_metrics.go -package=solr +// + +// Package solr is a generated GoMock package. +package solr + +import ( + context "context" + reflect "reflect" + + gomock "go.uber.org/mock/gomock" +) + +// MockMetrics is a mock of Metrics interface. +type MockMetrics struct { + ctrl *gomock.Controller + recorder *MockMetricsMockRecorder +} + +// MockMetricsMockRecorder is the mock recorder for MockMetrics. +type MockMetricsMockRecorder struct { + mock *MockMetrics +} + +// NewMockMetrics creates a new mock instance. +func NewMockMetrics(ctrl *gomock.Controller) *MockMetrics { + mock := &MockMetrics{ctrl: ctrl} + mock.recorder = &MockMetricsMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockMetrics) EXPECT() *MockMetricsMockRecorder { + return m.recorder +} + +// NewHistogram mocks base method. +func (m *MockMetrics) NewHistogram(name, desc string, buckets ...float64) { + m.ctrl.T.Helper() + varargs := []any{name, desc} + for _, a := range buckets { + varargs = append(varargs, a) + } + m.ctrl.Call(m, "NewHistogram", varargs...) +} + +// NewHistogram indicates an expected call of NewHistogram. +func (mr *MockMetricsMockRecorder) NewHistogram(name, desc any, buckets ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{name, desc}, buckets...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewHistogram", reflect.TypeOf((*MockMetrics)(nil).NewHistogram), varargs...) +} + +// RecordHistogram mocks base method. +func (m *MockMetrics) RecordHistogram(ctx context.Context, name string, value float64, labels ...string) { + m.ctrl.T.Helper() + varargs := []any{ctx, name, value} + for _, a := range labels { + varargs = append(varargs, a) + } + m.ctrl.Call(m, "RecordHistogram", varargs...) +} + +// RecordHistogram indicates an expected call of RecordHistogram. +func (mr *MockMetricsMockRecorder) RecordHistogram(ctx, name, value any, labels ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{ctx, name, value}, labels...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RecordHistogram", reflect.TypeOf((*MockMetrics)(nil).RecordHistogram), varargs...) +} diff --git a/pkg/gofr/datasource/solr/solr.go b/pkg/gofr/datasource/solr/solr.go new file mode 100644 index 000000000..f9268570f --- /dev/null +++ b/pkg/gofr/datasource/solr/solr.go @@ -0,0 +1,218 @@ +package solr + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "io" + "net/http" + "time" +) + +type Config struct { + Host string + Port string +} + +type Client struct { + url string + + logger Logger + metrics Metrics +} + +// New initializes Solr driver with the provided configuration. +// The Connect method must be called to establish a connection to Solr. +// Usage: +// client := New(config) +// client.UseLogger(loggerInstance) +// client.UseMetrics(metricsInstance) +// client.Connect() +func New(conf Config) *Client { + s := &Client{} + s.url = "http://" + conf.Host + ":" + conf.Port + "/solr" + + return s +} + +// UseLogger sets the logger for the Cassandra client which asserts the Logger interface. +func (c *Client) UseLogger(logger any) { + if l, ok := logger.(Logger); ok { + c.logger = l + } +} + +// UseMetrics sets the metrics for the Cassandra client which asserts the Metrics interface. +func (c *Client) UseMetrics(metrics any) { + if m, ok := metrics.(Metrics); ok { + c.metrics = m + } +} + +// Connect establishes a connection to Solr and registers metrics using the provided configuration when the client was Created. +func (c *Client) Connect() { + c.logger.Infof("connecting to Solr at %v", c.url) + + solrBuckets := []float64{.05, .075, .1, .125, .15, .2, .3, .5, .75, 1, 2, 3, 4, 5, 7.5, 10} + c.metrics.NewHistogram("app_solr_stats", "Response time of Solr operations in milliseconds.", solrBuckets...) + + return +} + +func (c *Client) HealthCheck(ctx context.Context) (any, error) { + return nil, nil +} + +// Search searches documents in the given collections based on the parameters specified. +// This can be used for making any queries to SOLR +func (c *Client) Search(ctx context.Context, collection string, params map[string]any) (any, error) { + url := c.url + "/" + collection + "/select" + + defer c.sendOperationStats(&QueryLog{Type: "Search", Url: url}, time.Now()) + + return call(ctx, http.MethodGet, url, params, nil) +} + +// Create makes documents in the specified collection. params can be used to send parameters like commit=true +func (c *Client) Create(ctx context.Context, collection string, document *bytes.Buffer, + params map[string]any) (any, error) { + url := c.url + collection + "/update" + + defer c.sendOperationStats(&QueryLog{Type: "Create", Url: url}, time.Now()) + + return call(ctx, http.MethodPost, url, params, document) +} + +// Update updates documents in the specified collection. params can be used to send parameters like commit=true +func (c *Client) Update(ctx context.Context, collection string, document *bytes.Buffer, + params map[string]any) (any, error) { + url := c.url + collection + "/update" + + defer c.sendOperationStats(&QueryLog{Type: "Update", Url: url}, time.Now()) + + return call(ctx, http.MethodPost, url, params, document) +} + +// Delete deletes documents in the specified collection. params can be used to send parameters like commit=true +func (c *Client) Delete(ctx context.Context, collection string, document *bytes.Buffer, + params map[string]any) (any, error) { + url := c.url + collection + "/update" + + defer c.sendOperationStats(&QueryLog{Type: "Delete", Url: url}, time.Now()) + + return call(ctx, http.MethodPost, url, params, document) +} + +// ListFields retrieves all the fields in the schema for the specified collection. +// params can be used to send query parameters like wt, fl, includeDynamic etc. +func (c *Client) ListFields(ctx context.Context, collection string, params map[string]any) (any, error) { + url := c.url + collection + "/schema/fields" + + defer c.sendOperationStats(&QueryLog{Type: "ListFields", Url: url}, time.Now()) + + return call(ctx, http.MethodGet, url, params, nil) +} + +// Retrieve retrieves the entire schema that includes all the fields,field types,dynamic rules and copy field rules. +// params can be used to specify the format of response +func (c *Client) Retrieve(ctx context.Context, collection string, params map[string]any) (any, error) { + url := c.url + collection + "/schema" + + defer c.sendOperationStats(&QueryLog{Type: "Retrieve", Url: url}, time.Now()) + + return call(ctx, http.MethodGet, url, params, nil) +} + +// AddField adds Field in the schema for the specified collection +func (c *Client) AddField(ctx context.Context, collection string, document *bytes.Buffer) (any, error) { + url := c.url + collection + "/schema" + + defer c.sendOperationStats(&QueryLog{Type: "AddField", Url: url}, time.Now()) + + return call(ctx, http.MethodPost, url, nil, document) +} + +// UpdateField updates the field definitions in the schema for the specified collection +func (c *Client) UpdateField(ctx context.Context, collection string, document *bytes.Buffer) (any, error) { + url := c.url + collection + "/schema" + + defer c.sendOperationStats(&QueryLog{Type: "UpdateField", Url: url}, time.Now()) + + return call(ctx, http.MethodPost, url, nil, document) +} + +// DeleteField deletes the field definitions in the schema for the specified collection +func (c *Client) DeleteField(ctx context.Context, collection string, document *bytes.Buffer) (any, error) { + url := c.url + collection + "/schema" + + defer c.sendOperationStats(&QueryLog{Type: "DeleteField", Url: url}, time.Now()) + + return call(ctx, http.MethodPost, url, nil, document) +} + +// Response stores the response from SOLR +type Response struct { + Code int + Data any +} + +// call forms the http request and makes a call to solr and populates the solr response +func call(ctx context.Context, method, url string, params map[string]any, body io.Reader) (any, error) { + req, err := http.NewRequest(method, url, body) + if err != nil { + return nil, err + } + + if method != http.MethodGet { + req.Header.Add("content-type", "application/json") + } + + q := req.URL.Query() + + for k, val := range params { + switch v := val.(type) { + case []string: + for _, val := range v { + q.Add(k, val) + } + default: + q.Add(k, fmt.Sprint(val)) + } + } + + req.URL.RawQuery = q.Encode() + + client := &http.Client{} + + resp, err := client.Do(req.WithContext(ctx)) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + var respBody any + + b, err := io.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + err = json.Unmarshal(b, &respBody) + if err != nil { + return nil, err + } + + return Response{resp.StatusCode, respBody}, nil +} + +func (c *Client) sendOperationStats(ql *QueryLog, startTime time.Time) { + duration := time.Since(startTime).Milliseconds() + + ql.Duration = duration + + c.logger.Debug(ql) + + c.metrics.RecordHistogram(context.Background(), "app_solr_stats", float64(duration), + "type", ql.Type) +} diff --git a/pkg/gofr/datasource/solr/solr_test.go b/pkg/gofr/datasource/solr/solr_test.go new file mode 100644 index 000000000..3a4469867 --- /dev/null +++ b/pkg/gofr/datasource/solr/solr_test.go @@ -0,0 +1,182 @@ +package solr + +import ( + "bytes" + "context" + "net/http" + "net/http/httptest" + "strings" + "testing" + + "github.com/stretchr/testify/require" + "go.uber.org/mock/gomock" +) + +func Test_InvalidRequest(t *testing.T) { + _, err := call(context.Background(), "GET", ":/localhost:", nil, nil) + + require.Error(t, err, "TEST Failed.\n") +} + +func Test_InvalidJSONBody(t *testing.T) { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + _, _ = w.Write([]byte(`Not a JSON`)) + })) + defer ts.Close() + + _, err := call(context.Background(), "GET", ts.URL, nil, nil) + + require.Error(t, err, "TEST Failed.\n") +} + +func Test_ErrorResponse(t *testing.T) { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + http.Error(w, "some error", http.StatusLocked) + })) + ts.Close() + + _, err := call(context.Background(), "GET", ts.URL, nil, nil) + + require.Error(t, err, "TEST Failed.\n") +} + +func setupClient(t *testing.T) *Client { + t.Helper() + + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + _, _ = w.Write([]byte(`{ + "responseHeader": { + "rf": 1, + "status": 0}}`)) + })) + + t.Cleanup(func() { + ts.Close() + }) + + a := ts.Listener.Addr().String() + addr := strings.Split(a, ":") + + ctrl := gomock.NewController(t) + mockLogger := NewMockLogger(ctrl) + mockMetrics := NewMockMetrics(ctrl) + + mockLogger.EXPECT().Debug(gomock.Any()) + mockMetrics.EXPECT().RecordHistogram(gomock.Any(), "app_solr_stats", gomock.Any(), "type", gomock.Any()) + + s := New(Config{Host: addr[0], Port: addr[1]}) + s.metrics = mockMetrics + s.logger = mockLogger + + return s +} + +func Test_ClientSearch(t *testing.T) { + s := setupClient(t) + + resp, err := s.Search(context.Background(), "test", map[string]any{"id": []string{"1234"}}) + + require.NoError(t, err, "TEST Failed.\n") + require.NotNil(t, resp, "TEST Failed.\n") +} + +func Test_ClientCreate(t *testing.T) { + s := setupClient(t) + + body := bytes.NewBuffer([]byte(`{ + "id": "1234567", + "cat": [ + "Book" + ], + "genere_s": "Hello There"}`)) + + resp, err := s.Create(context.Background(), "test", body, map[string]any{"commit": "true"}) + + require.NoError(t, err, "TEST Failed.\n") + require.NotNil(t, resp, "TEST Failed.\n") +} + +func Test_ClientUpdate(t *testing.T) { + s := setupClient(t) + + body := bytes.NewBuffer([]byte(`{ + "id": "1234567", + "cat": [ + "Book" + ]}`)) + resp, err := s.Update(context.Background(), "test", body, map[string]any{"commit": "true"}) + + require.NoError(t, err, "TEST Failed.\n") + require.NotNil(t, resp, "TEST Failed.\n") +} + +func Test_ClientDelete(t *testing.T) { + s := setupClient(t) + + body := bytes.NewBuffer([]byte(`{"delete":[ + "1234", + "12345" + ]}`)) + + resp, err := s.Delete(context.Background(), "test", body, map[string]any{"commit": "true"}) + + require.NoError(t, err, "TEST Failed.\n") + require.NotNil(t, resp, "TEST Failed.\n") +} + +func Test_ClientRetrieve(t *testing.T) { + s := setupClient(t) + + resp, err := s.Retrieve(context.Background(), "test", map[string]any{"wt": "xml"}) + + require.NoError(t, err, "TEST Failed.\n") + require.NotNil(t, resp, "TEST Failed.\n") +} + +func Test_ClientListFields(t *testing.T) { + s := setupClient(t) + + resp, err := s.ListFields(context.Background(), "test", map[string]any{"includeDynamic": true}) + + require.NoError(t, err, "TEST Failed.\n") + require.NotNil(t, resp, "TEST Failed.\n") +} + +func Test_ClientAddField(t *testing.T) { + s := setupClient(t) + + body := bytes.NewBuffer([]byte(`{"add-field":{ + "name":"merchant", + "type":"string", + "stored":true }}`)) + resp, err := s.AddField(context.Background(), "test", body) + + require.NoError(t, err, "TEST Failed.\n") + require.NotNil(t, resp, "TEST Failed.\n") +} + +func Test_ClientUpdateField(t *testing.T) { + s := setupClient(t) + + body := bytes.NewBuffer([]byte(`{"replace-field":{ + "name":"merchant", + "type":"text_general"}}`)) + + resp, err := s.UpdateField(context.Background(), "test", body) + + require.NoError(t, err, "TEST Failed.\n") + require.NotNil(t, resp, "TEST Failed.\n") +} + +func Test_ClientDeleteField(t *testing.T) { + s := setupClient(t) + + body := bytes.NewBuffer([]byte(`{"delete-field":{ + "name":"merchant", + "type":"text_general"}}`)) + + resp, err := s.DeleteField(context.Background(), "test", body) + + require.NoError(t, err, "TEST Failed.\n") + require.NotNil(t, resp, "TEST Failed.\n") +} diff --git a/pkg/gofr/external_db.go b/pkg/gofr/external_db.go index e8d81b68e..42de6699f 100644 --- a/pkg/gofr/external_db.go +++ b/pkg/gofr/external_db.go @@ -72,3 +72,13 @@ func (a *App) AddKVStore(db container.KVStoreProvider) { a.container.KVStore = db } + +// AddSolr sets the Solr datasource in the app's container. +func (a *App) AddSolr(db container.SolrProvider) { + db.UseLogger(a.Logger()) + db.UseMetrics(a.Metrics()) + + db.Connect() + + a.container.Solr = db +} diff --git a/pkg/gofr/service/mock_http_service.go b/pkg/gofr/service/mock_http_service.go new file mode 100644 index 000000000..90f2fd83e --- /dev/null +++ b/pkg/gofr/service/mock_http_service.go @@ -0,0 +1,392 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: ../service/new.go +// +// Generated by this command: +// +// mockgen -source=../service/new.go -destination=../service/mock_http_service.go -package=service HTTP +// + +// Package service is a generated GoMock package. +package service + +import ( + context "context" + http "net/http" + reflect "reflect" + + gomock "go.uber.org/mock/gomock" +) + +// MockHTTP is a mock of HTTP interface. +type MockHTTP struct { + ctrl *gomock.Controller + recorder *MockHTTPMockRecorder +} + +// MockHTTPMockRecorder is the mock recorder for MockHTTP. +type MockHTTPMockRecorder struct { + mock *MockHTTP +} + +// NewMockHTTP creates a new mock instance. +func NewMockHTTP(ctrl *gomock.Controller) *MockHTTP { + mock := &MockHTTP{ctrl: ctrl} + mock.recorder = &MockHTTPMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockHTTP) EXPECT() *MockHTTPMockRecorder { + return m.recorder +} + +// Delete mocks base method. +func (m *MockHTTP) Delete(ctx context.Context, api string, body []byte) (*http.Response, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Delete", ctx, api, body) + ret0, _ := ret[0].(*http.Response) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Delete indicates an expected call of Delete. +func (mr *MockHTTPMockRecorder) Delete(ctx, api, body any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockHTTP)(nil).Delete), ctx, api, body) +} + +// DeleteWithHeaders mocks base method. +func (m *MockHTTP) DeleteWithHeaders(ctx context.Context, api string, body []byte, headers map[string]string) (*http.Response, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeleteWithHeaders", ctx, api, body, headers) + ret0, _ := ret[0].(*http.Response) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// DeleteWithHeaders indicates an expected call of DeleteWithHeaders. +func (mr *MockHTTPMockRecorder) DeleteWithHeaders(ctx, api, body, headers any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteWithHeaders", reflect.TypeOf((*MockHTTP)(nil).DeleteWithHeaders), ctx, api, body, headers) +} + +// Get mocks base method. +func (m *MockHTTP) Get(ctx context.Context, api string, queryParams map[string]any) (*http.Response, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Get", ctx, api, queryParams) + ret0, _ := ret[0].(*http.Response) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Get indicates an expected call of Get. +func (mr *MockHTTPMockRecorder) Get(ctx, api, queryParams any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockHTTP)(nil).Get), ctx, api, queryParams) +} + +// GetWithHeaders mocks base method. +func (m *MockHTTP) GetWithHeaders(ctx context.Context, path string, queryParams map[string]any, headers map[string]string) (*http.Response, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetWithHeaders", ctx, path, queryParams, headers) + ret0, _ := ret[0].(*http.Response) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetWithHeaders indicates an expected call of GetWithHeaders. +func (mr *MockHTTPMockRecorder) GetWithHeaders(ctx, path, queryParams, headers any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetWithHeaders", reflect.TypeOf((*MockHTTP)(nil).GetWithHeaders), ctx, path, queryParams, headers) +} + +// HealthCheck mocks base method. +func (m *MockHTTP) HealthCheck(ctx context.Context) *Health { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "HealthCheck", ctx) + ret0, _ := ret[0].(*Health) + return ret0 +} + +// HealthCheck indicates an expected call of HealthCheck. +func (mr *MockHTTPMockRecorder) HealthCheck(ctx any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HealthCheck", reflect.TypeOf((*MockHTTP)(nil).HealthCheck), ctx) +} + +// Patch mocks base method. +func (m *MockHTTP) Patch(ctx context.Context, api string, queryParams map[string]any, body []byte) (*http.Response, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Patch", ctx, api, queryParams, body) + ret0, _ := ret[0].(*http.Response) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Patch indicates an expected call of Patch. +func (mr *MockHTTPMockRecorder) Patch(ctx, api, queryParams, body any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Patch", reflect.TypeOf((*MockHTTP)(nil).Patch), ctx, api, queryParams, body) +} + +// PatchWithHeaders mocks base method. +func (m *MockHTTP) PatchWithHeaders(ctx context.Context, api string, queryParams map[string]any, body []byte, headers map[string]string) (*http.Response, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "PatchWithHeaders", ctx, api, queryParams, body, headers) + ret0, _ := ret[0].(*http.Response) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// PatchWithHeaders indicates an expected call of PatchWithHeaders. +func (mr *MockHTTPMockRecorder) PatchWithHeaders(ctx, api, queryParams, body, headers any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PatchWithHeaders", reflect.TypeOf((*MockHTTP)(nil).PatchWithHeaders), ctx, api, queryParams, body, headers) +} + +// Post mocks base method. +func (m *MockHTTP) Post(ctx context.Context, path string, queryParams map[string]any, body []byte) (*http.Response, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Post", ctx, path, queryParams, body) + ret0, _ := ret[0].(*http.Response) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Post indicates an expected call of Post. +func (mr *MockHTTPMockRecorder) Post(ctx, path, queryParams, body any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Post", reflect.TypeOf((*MockHTTP)(nil).Post), ctx, path, queryParams, body) +} + +// PostWithHeaders mocks base method. +func (m *MockHTTP) PostWithHeaders(ctx context.Context, path string, queryParams map[string]any, body []byte, headers map[string]string) (*http.Response, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "PostWithHeaders", ctx, path, queryParams, body, headers) + ret0, _ := ret[0].(*http.Response) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// PostWithHeaders indicates an expected call of PostWithHeaders. +func (mr *MockHTTPMockRecorder) PostWithHeaders(ctx, path, queryParams, body, headers any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PostWithHeaders", reflect.TypeOf((*MockHTTP)(nil).PostWithHeaders), ctx, path, queryParams, body, headers) +} + +// Put mocks base method. +func (m *MockHTTP) Put(ctx context.Context, api string, queryParams map[string]any, body []byte) (*http.Response, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Put", ctx, api, queryParams, body) + ret0, _ := ret[0].(*http.Response) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Put indicates an expected call of Put. +func (mr *MockHTTPMockRecorder) Put(ctx, api, queryParams, body any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Put", reflect.TypeOf((*MockHTTP)(nil).Put), ctx, api, queryParams, body) +} + +// PutWithHeaders mocks base method. +func (m *MockHTTP) PutWithHeaders(ctx context.Context, api string, queryParams map[string]any, body []byte, headers map[string]string) (*http.Response, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "PutWithHeaders", ctx, api, queryParams, body, headers) + ret0, _ := ret[0].(*http.Response) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// PutWithHeaders indicates an expected call of PutWithHeaders. +func (mr *MockHTTPMockRecorder) PutWithHeaders(ctx, api, queryParams, body, headers any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PutWithHeaders", reflect.TypeOf((*MockHTTP)(nil).PutWithHeaders), ctx, api, queryParams, body, headers) +} + +// getHealthResponseForEndpoint mocks base method. +func (m *MockHTTP) getHealthResponseForEndpoint(ctx context.Context, endpoint string, timeout int) *Health { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "getHealthResponseForEndpoint", ctx, endpoint, timeout) + ret0, _ := ret[0].(*Health) + return ret0 +} + +// getHealthResponseForEndpoint indicates an expected call of getHealthResponseForEndpoint. +func (mr *MockHTTPMockRecorder) getHealthResponseForEndpoint(ctx, endpoint, timeout any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "getHealthResponseForEndpoint", reflect.TypeOf((*MockHTTP)(nil).getHealthResponseForEndpoint), ctx, endpoint, timeout) +} + +// MockhttpClient is a mock of httpClient interface. +type MockhttpClient struct { + ctrl *gomock.Controller + recorder *MockhttpClientMockRecorder +} + +// MockhttpClientMockRecorder is the mock recorder for MockhttpClient. +type MockhttpClientMockRecorder struct { + mock *MockhttpClient +} + +// NewMockhttpClient creates a new mock instance. +func NewMockhttpClient(ctrl *gomock.Controller) *MockhttpClient { + mock := &MockhttpClient{ctrl: ctrl} + mock.recorder = &MockhttpClientMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockhttpClient) EXPECT() *MockhttpClientMockRecorder { + return m.recorder +} + +// Delete mocks base method. +func (m *MockhttpClient) Delete(ctx context.Context, api string, body []byte) (*http.Response, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Delete", ctx, api, body) + ret0, _ := ret[0].(*http.Response) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Delete indicates an expected call of Delete. +func (mr *MockhttpClientMockRecorder) Delete(ctx, api, body any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockhttpClient)(nil).Delete), ctx, api, body) +} + +// DeleteWithHeaders mocks base method. +func (m *MockhttpClient) DeleteWithHeaders(ctx context.Context, api string, body []byte, headers map[string]string) (*http.Response, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeleteWithHeaders", ctx, api, body, headers) + ret0, _ := ret[0].(*http.Response) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// DeleteWithHeaders indicates an expected call of DeleteWithHeaders. +func (mr *MockhttpClientMockRecorder) DeleteWithHeaders(ctx, api, body, headers any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteWithHeaders", reflect.TypeOf((*MockhttpClient)(nil).DeleteWithHeaders), ctx, api, body, headers) +} + +// Get mocks base method. +func (m *MockhttpClient) Get(ctx context.Context, api string, queryParams map[string]any) (*http.Response, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Get", ctx, api, queryParams) + ret0, _ := ret[0].(*http.Response) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Get indicates an expected call of Get. +func (mr *MockhttpClientMockRecorder) Get(ctx, api, queryParams any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockhttpClient)(nil).Get), ctx, api, queryParams) +} + +// GetWithHeaders mocks base method. +func (m *MockhttpClient) GetWithHeaders(ctx context.Context, path string, queryParams map[string]any, headers map[string]string) (*http.Response, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetWithHeaders", ctx, path, queryParams, headers) + ret0, _ := ret[0].(*http.Response) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetWithHeaders indicates an expected call of GetWithHeaders. +func (mr *MockhttpClientMockRecorder) GetWithHeaders(ctx, path, queryParams, headers any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetWithHeaders", reflect.TypeOf((*MockhttpClient)(nil).GetWithHeaders), ctx, path, queryParams, headers) +} + +// Patch mocks base method. +func (m *MockhttpClient) Patch(ctx context.Context, api string, queryParams map[string]any, body []byte) (*http.Response, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Patch", ctx, api, queryParams, body) + ret0, _ := ret[0].(*http.Response) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Patch indicates an expected call of Patch. +func (mr *MockhttpClientMockRecorder) Patch(ctx, api, queryParams, body any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Patch", reflect.TypeOf((*MockhttpClient)(nil).Patch), ctx, api, queryParams, body) +} + +// PatchWithHeaders mocks base method. +func (m *MockhttpClient) PatchWithHeaders(ctx context.Context, api string, queryParams map[string]any, body []byte, headers map[string]string) (*http.Response, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "PatchWithHeaders", ctx, api, queryParams, body, headers) + ret0, _ := ret[0].(*http.Response) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// PatchWithHeaders indicates an expected call of PatchWithHeaders. +func (mr *MockhttpClientMockRecorder) PatchWithHeaders(ctx, api, queryParams, body, headers any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PatchWithHeaders", reflect.TypeOf((*MockhttpClient)(nil).PatchWithHeaders), ctx, api, queryParams, body, headers) +} + +// Post mocks base method. +func (m *MockhttpClient) Post(ctx context.Context, path string, queryParams map[string]any, body []byte) (*http.Response, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Post", ctx, path, queryParams, body) + ret0, _ := ret[0].(*http.Response) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Post indicates an expected call of Post. +func (mr *MockhttpClientMockRecorder) Post(ctx, path, queryParams, body any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Post", reflect.TypeOf((*MockhttpClient)(nil).Post), ctx, path, queryParams, body) +} + +// PostWithHeaders mocks base method. +func (m *MockhttpClient) PostWithHeaders(ctx context.Context, path string, queryParams map[string]any, body []byte, headers map[string]string) (*http.Response, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "PostWithHeaders", ctx, path, queryParams, body, headers) + ret0, _ := ret[0].(*http.Response) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// PostWithHeaders indicates an expected call of PostWithHeaders. +func (mr *MockhttpClientMockRecorder) PostWithHeaders(ctx, path, queryParams, body, headers any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PostWithHeaders", reflect.TypeOf((*MockhttpClient)(nil).PostWithHeaders), ctx, path, queryParams, body, headers) +} + +// Put mocks base method. +func (m *MockhttpClient) Put(ctx context.Context, api string, queryParams map[string]any, body []byte) (*http.Response, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Put", ctx, api, queryParams, body) + ret0, _ := ret[0].(*http.Response) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Put indicates an expected call of Put. +func (mr *MockhttpClientMockRecorder) Put(ctx, api, queryParams, body any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Put", reflect.TypeOf((*MockhttpClient)(nil).Put), ctx, api, queryParams, body) +} + +// PutWithHeaders mocks base method. +func (m *MockhttpClient) PutWithHeaders(ctx context.Context, api string, queryParams map[string]any, body []byte, headers map[string]string) (*http.Response, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "PutWithHeaders", ctx, api, queryParams, body, headers) + ret0, _ := ret[0].(*http.Response) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// PutWithHeaders indicates an expected call of PutWithHeaders. +func (mr *MockhttpClientMockRecorder) PutWithHeaders(ctx, api, queryParams, body, headers any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PutWithHeaders", reflect.TypeOf((*MockhttpClient)(nil).PutWithHeaders), ctx, api, queryParams, body, headers) +} diff --git a/pkg/gofr/version/version.go b/pkg/gofr/version/version.go index 730c1c83c..d4314d73a 100644 --- a/pkg/gofr/version/version.go +++ b/pkg/gofr/version/version.go @@ -1,3 +1,3 @@ package version -const Framework = "v1.19.1" +const Framework = "v1.20.0"