How to store and get a pointer reference in a global scope in GO - go

I have got the follow code:
package main
func main() {
// create a pointer referece of session of Mongo DB
session := mongoDB.CreateSession()
// Question 1 : How to store a pointer reference in a global scope and using anywhere of the code
defer session.Close()
// Note I suppose that the code call to handler methods that call to the Process in the package controller(the last one code)
}
Code of creating a session of MongoDB
package mongoDB
func CreateSession() *mgo.Session {
session, err := mgo.Dial("192.168.0.108:27017/databasename")
if err != nil {
panic(err)
}
session.SetMode(mgo.Monotonic, true)
return session
}
Place where I want to use the pointer reference that was store in the main
package controller
func Process() {
// Question 2 : How can a get the pointer reference store in Question 1 if is posible
collection := mongoDB.CreateCollection(session, "namedatabase", "colectionData")
mongoDB.InsertData(collection, "Ale", "45646565")
}
The idea is to avoid passing by reference session(my pointer reference in the main function) in every one of the functions created for all the project.

You can't have your controller package import main. That is not a good idea (and I am quite sure it is not even possible). But that doesn't mean you can't have a global session variable in the controller.
You can try this:
package main
import (
"controller"
"mongoDB"
)
func main() {
// create a pointer referece of session of Mongo DB
session := mongoDB.CreateSession()
defer session.Close()
controller.SetDBSession(session) // Or controller.Init or whatever you like
controller.Process()
}
And then in the controller package you have:
package controller
import "mongoDB"
// Global session var for the package
var session mongoDB.Session
// SetDBSession sets the mongoDB session to be used by the controller package.
// This function must be called before calling Process()
func SetDBSession(s mongoDB.Session) {
session = s
}
func Process() {
collection := mongoDB.CreateCollection(session, "namedatabase", "colectionData")
mongoDB.InsertData(collection, "Ale", "45646565")
}
Using this solution, you will only have to pass the session to the controller package once, letting main take care of the creating and closing of the session.

Related

How can I separate generated code package and user code but have them accessible from one place in code

I am newer to golang, so I have some courses that I bought from udemy to help break me into the language. One of them I found very helpful for a general understanding as I took on a project in the language.
In the class that I took, all of the sql related functions were in the sqlc folder with the structure less broken out:
sqlc
generatedcode
store
One of those files is a querier that is generated by sqlc that contains an interface with all of the methods that were generated. Here is the general idea of what it currently looks like: https://github.com/techschool/simplebank/tree/master/db/sqlc
package db
import (
"context"
"github.com/google/uuid"
)
type Querier interface {
AddAccountBalance(ctx context.Context, arg AddAccountBalanceParams) (Account, error)
CreateAccount(ctx context.Context, arg CreateAccountParams) (Account, error)
...
}
var _ Querier = (*Queries)(nil)
Would it be possible to wrap both what sqlc generates AND any queries that a developer creates (dynamic queries) into a single querier? I'm also trying to have it so that the sqlc generated code is in its own folder. The structure I am aiming for is:
sql
sqlc
generatedcode
store - (wraps it all together)
dynamicsqlfiles
This should clear up what a I mean by store: https://github.com/techschool/simplebank/blob/master/db/sqlc/store.go
package db
import (
"context"
"database/sql"
"fmt"
)
// Store defines all functions to execute db queries and transactions
type Store interface {
Querier
TransferTx(ctx context.Context, arg TransferTxParams) (TransferTxResult, error)
}
// SQLStore provides all functions to execute SQL queries and transactions
type SQLStore struct {
db *sql.DB
*Queries
}
// NewStore creates a new store
func NewStore(db *sql.DB) Store {
return &SQLStore{
db: db,
Queries: New(db),
}
}
I'm trying to run everything through that store (both generated and my functions), so I can make a call similar to the CreateUser function in this file (server.store.): https://github.com/techschool/simplebank/blob/master/api/user.go
arg := db.CreateUserParams{
Username: req.Username,
HashedPassword: hashedPassword,
FullName: req.FullName,
Email: req.Email,
}
user, err := server.store.CreateUser(ctx, arg)
if err != nil {
if pqErr, ok := err.(*pq.Error); ok {
switch pqErr.Code.Name() {
case "unique_violation":
ctx.JSON(http.StatusForbidden, errorResponse(err))
return
}
}
ctx.JSON(http.StatusInternalServerError, errorResponse(err))
return
}
I've tried creating something that houses another querier interface that embeds the generated one, then creating my own db.go that uses the generated DBTX interface but has its own Queries struct, and New function. It always gives me an error that the Queries struct I created aren't implementing the functions I made, despite having it implemented in one of the custom methods I made.
I deleted that branch, and have been clicking through the simplebank project linked above to see if I can find another way this could be done, or if I missed something. If it can't be done, that's okay. I'm just using this as a good opportunity to learn a little more about the language, and keep some code separated if possible.
UPDATE:
There were only a few pieces I had to change, but I modified the store.go to look more like:
// sdb is imported, but points to the generated Querier
// Store provides all functions to execute db queries and transactions
type Store interface {
sdb.Querier
DynamicQuerier
}
// SQLStore provides all functions to execute SQL queries and transactions
type SQLStore struct {
db *sql.DB
*sdb.Queries
*dynamicQueries
}
// NewStore creates a new Store
func NewStore(db *sql.DB) Store {
return &SQLStore{
db: db,
Queries: sdb.New(db),
dynamicQueries: New(db),
}
}
Then just created a new Querier and struct for the methods I would be creating. Gave them their own New function, and tied it together in the above. Before, I was trying to figure out a way to reuse as much of the generated code as possible, which I think was the issue.
Why I wanted the Interface:
I wanted a structure that separated the files I would be working in more from the files that I would never touch (generated). This is the new structure:
I like how the generated code put everything in the Querier interface, then checked that anything implementing it satisfied all of the function requirements. So I wanted to replicate that for the dynamic portion which I would be creating on my own.
It might be complicating it a bit more than it would 'NEED' to be, but it also provides an additional set of error checking that is nice to have. And in this case, even while maybe not necessary, it ended up being doable.
Would it be possible to wrap both what sqlc generates AND any queries that a developer creates (dynamic queries) into a single querier?
If I'm understanding your question correctly I think that you are looking for something like the below (playground):
package main
import (
"context"
"database/sql"
)
// Sample SQL C Code
type DBTX interface {
ExecContext(context.Context, string, ...interface{}) (sql.Result, error)
PrepareContext(context.Context, string) (*sql.Stmt, error)
QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error)
QueryRowContext(context.Context, string, ...interface{}) *sql.Row
}
type Queries struct {
db DBTX
}
func (q *Queries) DeleteAccount(ctx context.Context, id int64) error {
// _, err := q.db.ExecContext(ctx, deleteAccount, id)
// return err
return nil // Pretend that this always works
}
type Querier interface {
DeleteAccount(ctx context.Context, id int64) error
}
//
// Your custom "dynamic" queries
//
type myDynamicQueries struct {
db DBTX
}
func (m *myDynamicQueries) GetDynamicResult(ctx context.Context) error {
// _, err := q.db.ExecContext(ctx, deleteAccount, id)
// return err
return nil // Pretend that this always works
}
type myDynamicQuerier interface {
GetDynamicResult(ctx context.Context) error
}
// Combine things
type allDatabase struct {
*Queries // Note: You could embed this directly into myDynamicQueries instead of having a seperate struct if that is your preference
*myDynamicQueries
}
type DatabaseFunctions interface {
Querier
myDynamicQuerier
}
func main() {
// Basic example
var db DatabaseFunctions
db = getDatabase()
db.DeleteAccount(context.Background(), 0)
db.GetDynamicResult(context.Background())
}
// getDatabase - Perform whatever is needed to connect to database...
func getDatabase() allDatabase {
sqlc := &Queries{db: nil} // In reality you would use New() to do this!
myDyn := &myDynamicQueries{db: nil} // Again it's often cleaner to use a function
return allDatabase{Queries: sqlc, myDynamicQueries: myDyn}
}
The above is all in one file for simplicity but could easily pull from multiple packages e.g.
type allDatabase struct {
*generatedcode.Queries
*store.myDynamicQueries
}
If this does not answer your question then please show one of your failed attempts (so we can see where you are going wrong).
One general comment - do you really need the interface? A common recommendation is "Accept interfaces, return structs". While this may not always apply I suspect you may be introducing interfaces where they are not really necessary and this may add unnecessary complexity.
I thought that the Store, which was housing both Queriers, was tying it all together. Can you explain a little with the example above (in the question post) why it's not necessary? How does SQLStore get access to all of the Querier interface functions?
The struct SQLStore is what is "tying it all together". As per the Go spec:
Given a struct type S and a named type T, promoted methods are included in the method set of the struct as follows:
If S contains an embedded field T, the method sets of S and *S both include promoted methods with receiver T. The method set of *S also includes promoted methods with receiver *T.
If S contains an embedded field *T, the method sets of S and *S both include promoted methods with receiver T or *T.
So an object of type SQLStore:
type SQLStore struct {
db *sql.DB
*sdb.Queries
*dynamicQueries
}
var foo SQLStore // Assume that we are actually providing values for all fields
Will implement all of the methods of sdb.Queries and, also, those in dynamicQueries (you can also access the sql.DB members via foo.db.XXX). This means that you can call foo.AddAccountBalance() and foo.MyGenericQuery() (assuming that is in dynamicQueries!) etc.
The spec says "In its most basic form an interface specifies a (possibly empty) list of methods". So you can think of an interface as a list of functions that must be implemented by whatever implementation (e.g. struct) you assign to the interface (the interface itself does not implement anything directly).
This example might help you understand.
Hopefully that helps a little (as I'm not sure which aspect you don't understand I'm not really sure what to focus on).

Pointer reference not stored in a struct in my go program

I am new to go-lang and I try to figure out how to work properly with structs and dependency injection. I am a bit stuck because I am not able to properly store a reference to another struct.
Here's my method that generates a CommandController. There is a valid reference to iris.Application.
func ProvideCommandController(application *iris.Application, commandRepository command.CommandRepository) (*interfaces.CommandController, error) {
commandController := interfaces.CommandController{}
commandController.Init(application, commandRepository)
commandController.Start()
return &commandController, nil
}
The struct looks like this:
type CommandController struct {
commandRepository command.CommandRepository
app *iris.Application
}
func (c CommandController) Init(app *iris.Application, repository command.CommandRepository) {
c.app = app
c.commandRepository = repository
}
func (c CommandController) Start() {
c.app.Get("/command", c.readAll)
c.app.Get("/command/{id:string}/execute", c.executeCommand)
c.app.Run(iris.Addr(":8080"))
}
When the ProvideCommandController function gets executed I can debug and observe that all references look good. Unfortunately, commandController.Start()fails because of c.app is nil.
What piece of understanding do I miss? Somehow, the stored reference get's deleted between the Init and the Start function call.
Thanks in advance :)
Change
func (c CommandController) Init(app *iris.Application, repository command.CommandRepository)
to
func (c *CommandController) Init(app *iris.Application, repository command.CommandRepository)
since Init receives c by value in your version, any changes it makes to c don't appear outside of the Init method.

Using a key value store in webserver application golang

I tried to get a simple key value store working inside of a go webserver app, which should store some information.
The issue is, I can only create one instance of it, since its writing to the disk and the folder is locked, so I need to find away to access the key value store with my Webserver.
So every current instance can access it (read/write).
How do I do that?
Currently My app looks like that: https://play.golang.org/p/_SmGBZlP0Vi
The Package I wanted to use is this: https://github.com/peterbourgon/diskv
Basically I would create an instance before the main and pass the instance of the key value store, to the rtt function, but that seems not directly be possible in go. Or do I something wrong?
Global Conn Instance
First create a package with a single instance of the key value store and make the connection a package variable that you connect once and then keep open for all future use. Here some pseudo code sample:
package kvstore
var conn *diskv.Conn // or whatever the type of the conn is
func Connect(...) {
// crate connection and fill conn
conn = diskv.New(...)
}
func Write(k, v []byte) error {
return conn.Write(k, v)
}
That way yo have a "global" connection that can be used from everywhere. Simply call kvstore.Write(...) anywhere to write to the store.
Sync concurrent access
If your application uses multiple goroutines that can access the kvstore you (might -- depending if the package you use already does this for you or not) need to sync the access. You can do this by using a mutex for the connection:
var (
conn *diskv.Conn // or whatever the type of the conn is
mutex sync.Mutex
)
func Write(k, v []byte) error {
// everywhere you use the conn object, lock the mutex before and unlock after
mutex.Lock()
defer mutex.Unlock()
return conn.Write(k, v)
}
You can also use the actor pattern. Here a post by Peter Bourgon that explains the actor pattern. With the actor pattern we can make sure the conn object is only used in one goroutine making the use of a mutex unnecessary.
Simple kvstore package implementation
package kvstore
import "github.com/peterbourgon/diskv"
var conn *diskv.Diskv
// Connect opens the global diskv db
func Connect(dir string) {
flatTransform := func(s string) []string { return []string{} }
conn = diskv.New(diskv.Options{
BasePath: dir,
Transform: flatTransform,
CacheSizeMax: 1024 * 1024,
})
}
// Write writes to the global diskv db
func Write(k string, v []byte) error {
return conn.Write(k, v)
}
// Read reads from the global diskv db
func Read(k string) ([]byte, error) {
return conn.Read(k)
}
// Erase deletes a key from the global discv db
func Erase(k string) error {
return conn.Erase(k)
}
Sample usage of kvstore
package main
import (
"github.com/tehsphinx/diskv"
)
func main() {
// call this once in startup sequence.
kvstore.Connect("my-data-dir")
// use this anywhere to write to key value store
kvstore.Write("alpha", []byte{'1', '2', '2'})
// use this anywhere to read from kvstore
kvstore.Read("alpha")
// use this anywhere to delete from kvstore
kvstore.Erase("alpha")
}
Just copy it in two different folders and try. It works.

How do I change the import file?

I have the following function in golang:
import (
"github.com/aws/aws-sdk-go/service/iam"
"github.com/aws/aws-sdk-go/aws/session"
"fmt"
)
func NewIAM() *SphinxIAM {
// awsConfig := aws.NewConfig()
sess, err := session.NewSession()
if err != nil {
fmt.Println("Failed to create session,", err)
return nil
}
session := &SphinxIAM{iam: iam.New(sess)}
return session
}
Now, I am getting the following error when I run this:
cannot use sess (type *session.Session) as type "github.com/aws/aws-sdk-go/aws/client".ConfigProvider in argument to iam.New:
*session.Session does not implement "github.com/aws/aws-sdk-go/aws/client".ConfigProvider (wrong type for ClientConfig method)
have ClientConfig(string, ...*"stash/cloud/sphinx/vendor/github.com/aws/aws-sdk-go/aws".Config) "stash/cloud/sphinx/vendor/github.com/aws/aws-sdk-go/aws/client".Config
want ClientConfig(string, ...*"github.com/aws/aws-sdk-go/aws".Config) "github.com/aws/aws-sdk-go/aws/client".Config
I have to change the method getting imported but how do I exactly do that?
Thanks!
The problem here is that your github.com/aws/aws-sdk-go/aws/session package is vendored, it is loaded from the folder stash/cloud/sphinx/vendor/github.com/aws/aws-sdk-go/aws.
But the function you want to pass it: iam.New() is not vendored, it does not come from the same vendor folder (stash/cloud/sphinx/vendor/xxx) but it comes directly from github.com/aws/aws-sdk-go/service/iam.
Either put both packages under the same vendor folder, or none. It is possible that one of your dependency tool does this, (e.g. glide), in which case you should instruct your tool to handle both as vendored.

How to access flags outside of main package?

We parse flags in main.go which is in main package, of course. Then we have another package where we want to read some flag's value.
flags.Args() work fine, it will return all non-flag values.
But I cannot figure out to how read already parsed value for a flag in a package other than main.
Is it possible?
Thanks
Amer
I had the same requirement recently and I wanted a solution that avoided calling flag.Parse repeatedly in init functions.
Perusing the flag package I found Lookup(name string) which returns a Flag which has a Value. Every built in Value implements the flag.Getter interface. The call chain looks like this:
flag.Lookup("httplog").Value.(flag.Getter).Get().(bool)
If you mistype the flag name or use the wrong type you get a runtime error. I wrapped the lookup in a function that I call directly where needed since the lookup and get methods are fast and the function is not called often. So the main package declares the flag.
// main.go
package main
import "flag"
var httplog = flag.Bool("httplog", false, "Log every HTTP request and response.")
func main() {
flag.Parse()
// ...
}
And the utility package, which is decoupled from main except for the flag name, reads the flag value.
// httpdiag.go
package utility
import "flag"
func logging() bool {
return flag.Lookup("httplog").Value.(flag.Getter).Get().(bool)
}
You can define the var storing the flag in the separate package, as an exported variable, then call the flag parsing in the main package to use that variable, like this:
mypackage/const.go
var (
MyExportedVar string
)
mainpackage/main.go
func init() {
flag.StringVar(&mypackage.MyExportedVar, "flagName", "defaultValue", "usage")
flag.Parse()
}
This way, everybody can access that flag, including that package itself.
Note:
this only works for exported variables.
You can define the flag in that package and call flag.Parse() in func init(), flag.Parse can be called multiple times.
However, if you want to access the flag's value from multiple packages you have to expose it or create an exposed function to check it.
for example:
// pkgA
var A = flag.Bool("a", false, "why a?")
func init() {
flag.Parse()
}
// main package
func main() {
flag.Parse()
if *pkgA.A {
// stuff
}
}
Also you can use FlagSet.Parse(os.Args) if you want to reparse the args.
When you parse your flags, parse them into global variables which start with an initial Capital so they are public, eg
package main
var Species = flag.String("species", "gopher", "the species we are studying")
func main() {
flag.Parse()
}
Then in your other package you can refer to them as
package other
import "/path/to/package/main"
func Whatever() {
fmt.Println(main.Species)
}

Resources