Where to get the Context for DB query? - go

I am using https://entgo.io/ as entity framework and https://echo.labstack.com/ as web framework.
Consider the following code snippet:
func main() {
client, err := Open("postgresql://pgadmin:pgpw#127.0.0.1/nfeed")
if err != nil {
log.Fatal(err.Error())
return
}
ctx := context.Background()
if err := client.Schema.Create(ctx); err != nil {
log.Fatal(err)
return
}
e := echo.New()
e.GET("/hashtags", func(c echo.Context) error {
pattern := c.QueryParam("pattern")
if len(pattern) == 0 {
return c.JSON(http.StatusNotFound, err)
}
hs, err := client.Hashtag.Query().All(????)
return c.JSON(http.StatusOK, "Hello")
})
e.Logger.Fatal(e.Start(":3000"))
}
The function call client.Hashtag.Query().All(context) expects https://pkg.go.dev/context as parameter.
The question is, how or where can I get the context?
In my opinion, the Echo framework should provide me a Context. Unfortunately, I could not found within the Echo module.

You define a context variable on the line ctx := context.Background(), which is a valid context type, there's good documentation on this in your own link https://pkg.go.dev/context.
There's no reason that wouldn't work, if you need more then you can check the documentation on how to make a more in depth context variable.

Related

What do empty returns in the main function mean?

I copy-pasted the code from an API (https://api.magiceden.dev/). This code gets the link and prints a slice. Here's the code:
func main() {
url := "https://api-mainnet.magiceden.dev/v2/wallets/6xX3z7uxTNB68izZW2GHKnzno49dizqeVVc5ncVzdjFM/activities?offset=0&limit=100"
method := "GET"
client := &http.Client{}
req, err := http.NewRequest(method, url, nil)
if err != nil {
fmt.Println(err)
return
}
res, err := client.Do(req)
if err != nil {
fmt.Println(err)
return
}
defer res.Body.Close()
body, err := ioutil.ReadAll(res.Body)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(string(body))
}
I'm new to Go, and I know about empty return statements in other functions, but what is returned in main function? That's the question and I still haven't found the answer.
I tried googling it, but I couldn't find any info or examples of empty return statements in main function.
When there is no return type in the function signature the return in such a function just stops the processing of the function at this point. No further statement are run then, but the registered defer functions are processed in the reverse order they have been registered.

Check if any variable conforms any interface using generics in Go

I am writing an API using go-fiber, and I want to check, if passed JSON conforms an interface that I want to see. So I decided to use 1.18's feature - generics. Here is what I did, but it does not work due to type problem.
func checkDataConformsInterface[I any](format I, c *fiber.Ctx) (I, error) {
if err := c.BodyParser(&format); err != nil {
return nil, err
}
return c.JSON(format), nil
}
The errors say
src/endpoints/v1/tasks.go:36:10: cannot use nil as I value in return statement
src/endpoints/v1/tasks.go:39:9: cannot use c.JSON(format) (value of type error) as type I in return statement
And I want to call the function like this:
type CreateTaskDF struct {
Target string `json:"target"`
Deepness int `json:"deepness"`
}
func CreateTask(c *fiber.Ctx) error {
data, err := checkDataConformsInterface[CreateTaskDF](&CreateTaskDF{}, c)
if err != nil {
log.Fatal(err)
}
// work with data here
...
How should I convert the return value in the function to make it work? Thanks!
It probably could work like this(if you do not consider any lib-based payload validators, which exist in almost every golang routing lib or web framework). So, to just validate your data you can use this:
func checkDataConformsInterface[I any](format I, c *fiber.Ctx) bool {
if err := c.BodyParser(&format); err != nil {
return false
}
return true
}
So I came up with the following solution
func checkDataConformsInterface[I any](format *I, c *fiber.Ctx) error {
if err := c.BodyParser(&format); err != nil {
return err
}
err := c.JSON(format)
if err != nil {
return err
}
return nil
}
which can be called like
func CreateTask(c *fiber.Ctx) error {
parsedData := CreateTaskDF{}
err := checkDataConformsInterface[CreateTaskDF](&parsedData, c)
if err != nil {
c.SendStatus(400)
return c.SendString("Wrong data")
}
Please, point me the problems if any

golang bigquery docs specify done operator but it generates a compile error

So the docs here state specifically to use iterator.Done:
Next loads the next row into dst. Its return value is iterator.Done if there are no more results. Once Next returns iterator.Done, all subsequent calls will return iterator.Done.
However if I attempt to use Done it generates a compiler error. Indeed, Done is not defined on the RowIterator docs here.
My code (almost identical to the docs):
it, err := job.Read(ctx)
if err != nil {
fmt.Println(err)
}
for {
var rec MyType
err := it.Next(&rec)
// the docs say to use Done, but it provides an error
if err == it.Done {
break
}
if err != nil {
fmt.Println(err)
}
rows = append(rows, rec)
}
When I try to build it, I get:
./test.go:94:15: it.Done undefined (type *"cloud.google.com/go/bigquery".RowIterator has no field or method Done)
What am I missing?
iterator.Done is a variable defined in the iterator package. So replace it.Done with iterator.Done. This is shown in this example:
package main
import (
"cloud.google.com/go/bigquery"
"context"
"fmt"
"google.golang.org/api/iterator"
)
func main() {
ctx := context.Background()
client, err := bigquery.NewClient(ctx, "project-id")
if err != nil {
// TODO: Handle error.
}
q := client.Query("select name, num from t1")
it, err := q.Read(ctx)
if err != nil {
// TODO: Handle error.
}
for {
var row []bigquery.Value
err := it.Next(&row)
if err == iterator.Done {
break
}
if err != nil {
// TODO: Handle error.
}
fmt.Println(row)
}
}
You have confused between the iterator returned from the Job.Read call i.e. the RowIterator and the generic Google API iterator in https://pkg.go.dev/google.golang.org/api/iterator
You should check the return value from the latter i.e. err == iterator.Done to check if the the iteration is complete. The sample codes under the documentation has useful examples explained - https://github.com/GoogleCloudPlatform/golang-samples/tree/master/bigquery

What is the proper style and usage of golang Context?

I am new to golang and trying to get a better understanding of context.
In the below snippet, it appears to me that I've instantiated my computeService with a context. why do I have to pass it again to the .Context() function when calling Stop()?
package main
func stopTaggedMachines(ctx context.Context, svc *compute.Service, project, zone, tag string) ([]string, error) {
var instances []string
f := func(page *compute.InstanceList) error {
for _, v := range page.Items {
if v.Labels["gcp-idler-managed"] == "true" {
result, err := svc.Instances.Stop(project, zone, v.Name).Context(ctx).Do()
if err != nil {
log.Fatal(err)
}
fmt.Printf("[INFO] gcp-machine-idler: Instance in state %v, Stopping %v... Response: %v \n", v.Status, v.Name, result.HTTPStatusCode)
}
}
return nil
}
call := svc.Instances.List("my-project", "us-west1-b")
if err := call.Pages(oauth2.NoContext, f); err != nil {
return instances, nil
}
return instances, nil
}
func main() {
// Use oauth2.NoContext if there isn't a good context to pass in.
ctx := context.Background()
computeService, err := compute.NewService(ctx)
if err != nil {
log.Fatal(err)
}
stopTaggedMachines(ctx, computeService, "my-project", "us-west1-b", "gcp-idler-managed")
return
}
It seems redundant to me that I pass ctx into compute.NewService(), then again into stopTaggedMachines()
Is this really the correct convention or usage of context? Why does my call to svc.Instances.Stop(project, zone, v.Name).Context(ctx).Do() need to be passed ctx yet again as a parameter?
svc.Instances.Stop(project, zone, v.Name) returns InstanceStopCall
By calling Context(ctx) you are setting the context to be used in this call's Do method. This allows the HTTP request to be aborted if the context is canceled.
The Stop method can take a long time (as in minutes). This allows a user to cancel waiting for a VM to shutdown.

gomock, Go,mango package ,MongoMock

I am trying to mock the below method using gomock
func GetS(tenantName string) (*mgo.Session, error) {
ctx := apiContext.TContext{}
url, err := connectionURLList.get(tenantName)
if err != nil {
log.GenericWarning(ctx,
fmt.Sprintf("connection to %s not yet created, creating one: %v", tenantName, err), nil)
if err := connectMongo(tenantName); err == nil {
return GetS(tenantName) //singleton recursion to again call GetS
}
return nil, err
}
// ignoring error, expected we will always setting session in session map
session, _ := connectionList.get(url)
return session.Copy(), err
}
My Interface
type MongoManager interface {
GetS(tenantName string)
}
func TestGetS(t *testing.T) {
//var mgoCall *mgo.Session
mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
mockManagerObj := mocks.NewMockMongoManager(mockCtrl)
mockManagerObj.EXPECT().GetS("cacargroup").Return(nil)
}
I am Getting the below error . Can someone help
$ go test
--- FAIL: TestGetS (0.00s)
mongoManager_test.go:20: missing call(s) to *mocks.MockMongoManager.GetS(is equal to cacargroup) /Users/charles/workspace/src/bitbucket.org/tekion/tbaas/mongoManager/mongoManager_test.go:16
mongoManager_test.go:20: aborting test due to missing call(s) FAIL exit status 1
You see actually the method in your interface implemented with return type of an error. But you are using like it returns nothing and chaining the implementation. Just remove the return type of GetS.
type fn func(string) (*mgo.Session, error)
type MongoManager interface {
NewFunction(GetS, "cascade")
}
func TestGetS(t *testing.T) {
//var mgoCall *mgo.Session
mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
mockManagerObj := mocks.NewMockMongoManager(mockCtrl)
mockManagerObj.EXPECT().GetS("cacargroup").Return(nil)
}
Also you have to remove it from GetS function too
func NewFunction(GetS fn, value string){
GetS("cascade")
}
func GetS(tenantName string) (*mgo.Session, error){
ctx := apiContext.TContext{}
url, err := connectionURLList.get(tenantName)
if err != nil {
log.GenericWarning(ctx,
fmt.Sprintf("connection to %s not yet created, creating one: %v", tenantName, err), nil)
if err := connectMongo(tenantName); err == nil {
return GetS(tenantName) //singleton recursion to again call GetS
}
return nil, err
}
// ignoring error, expected we will always setting session in session map
session, _ := connectionList.get(url)
}

Resources