How to deal with unknown variables or How to deal with multiple databases

go

Solution

If you want to preserve the interface with those methods, you should change a little your interface as:

Interface:

// The interface that all connectors should have
type Intfc interface {
    // Connect to the database, if an error occur at the moment
    // of connection, return the error
    Connect() error
    // Add returns a string, it returns an error if something occurs
    Add(string, string, string) (string, error)
    Get(string) (Object, bool)
}

MySQL:

type Mysql struct{
    conn *sql.DB // contains the connection to the DB
}

// Connect to mysql
func (f *Mysql) Connect() error {
    conn, err := sql.Open("mysql", "yourusername:yourpassword@/yourdatabase")
    if err != nil {
        return error
    }
    f.conn = conn
    return nil
}

// Add item to DB
func (f *Mysql) Add(owner string, refType string, object string) (string, error) {
    // do something
    return // a string and error
}

func (f *Mysql) Get(Uuid string) (dbinit.Object, bool) {
    // do something
    return // an object and a bool
}

Mongo:

type Mongo struct{
    session *mgo.Session
}

// Connect to mongo
func (f *Mongo) Connect() error {
    info := &mgo.DialInfo{
        // some data
    }

    session, err := mgo.DialWithInfo(info)
    if err != nil {
        return error
    }
    f.session = session
    return nil
}

// Add item to DB
func (f *Mongo) Add(owner string, refType string, object string) (string, error) {
    // do something
    return // a string and error (it could be nil at success)
}

func (f *Mongo) Get(Uuid string) (dbinit.Object, bool) {
    // do something
    return // an object and a bool
}

Main:

var selectedDb dbinit.Intfc

commandLineInput := "mysql"

if commandLineInput == "mysql" {
    selectedDb = &mysqlConnector.Mysql{}
} else if commandLineInput == "mongo" {
    selectedDb = &mongoConnector.Mongo{}
}

err := selectedDb.Connect()
if err != nil {
    panic(err)
}

// this runs everytime the API is called
api.HandlerFoobar = foobar.handlerFunction(func(params foobar.Params) middleware.Responder {
    data, err := selectedDb.Add(addStringA, addStringB, addStringC)
    if err != nil {
        // do something
    }

    return // the API response
})

But you also can remove the `Connect() error` method from `Intfc` and just use `Add` and `Get`, but you should update the packages like:

Mysql

// Connect to mysql, it could be any function name
func Connect() (*Mysql, error) {
    connection, err := sql.Open("mysql", "yourusername:yourpassword@/yourdatabase")
    if err != nil {
        return nil, error
    }
    return &Mysql{conn: connection}
}

Mongo

// Connect to mongo, it could be any function name
func Connect() (*Mongo, error) {
    info := &mgo.DialInfo{
        // some data
    }

    s, err := mgo.DialWithInfo(info)
    if err != nil {
        return nil, error
    }
    return &Mongo{session: s}
}

Main

var selectedDb dbinit.Intfc
var err error
commandLineInput := "mysql"

if commandLineInput == "mysql" {
    selectedDb, err = mysqlConnector.Connect()
} else if commandLineInput == "mongo" {
    selectedDb, err = mongoConnector.Connect()
}

if err != nil {
    panic(err)
}

Problem

I'm working on a Go RESTful API application with multiple databases. When starting the server, the user supplies which database they would like to use. In the application, I have three functions of which one handles the connection: `selectedDb.Get()`, `selectedDb.Add()`, `selectedDb.Connect()`. If somebody selects, Mysql, it handles things for Mysql, if someone selects MongoDB it handles things for Mongo and so on. This is how I try to accomplish this: DbInterface.go ``` package dbinit type Object struct { Uuid string Object string Deleted bool } // The interface that all connectors should have type Intfc interface { Connect() HERE_LIES_MY_PROBLEM Add(string, string, string) string Get(string) (Object, bool) } ``` MySQL.go ``` package mysqlConnector import ( ... ) type Mysql struct{} // Connect to mysql func (f Mysql) Connect() HERE_LIES_MY_PROBLEM { client, err = sql.Open("mysql", "yourusername:yourpassword@/yourdatabase") if err != nil { panic(err.Error()) } return client } // Add item to DB func (f Mysql) Add(owner string, refType string, object string) string { // do stuff related to this DB return // a string } func (f Mysql) Get(Uuid string) (dbinit.Object, bool) { // do stuff related to this DB return // an object and a bool } ``` Mongo.go ``` package mongoConnector import ( ... ) type Mongo struct{} // Connect to mongo func (f Mongo) Connect() HERE_LIES_MY_PROBLEM { info := &mgo.DialInfo{ Addrs: []string{hosts}, Timeout: 60 * time.Second, Database: database, Username: username, Password: password, } client, err := mgo.DialWithInfo(info) if err != nil { panic(err) } return client } // Add item to DB func (f Mongo) Add(owner string, refType string, object string) string { // do stuff related to this DB return // a string } func (f Mongo) Get(Uuid string) (dbinit.Object, bool) { // do stuff related to this DB return // an object and a bool } ``` main.go ``` ... var selectedDb dbinit.Intfc commandLineInput := "mysql" // just for the example if commandLineInput == "mysql" { selectedDb = mysqlConnector.Mysql{} } else if commandLineInput == "mongo" { selectedDb = mongoConnector.Mongo{} } client := selectedDb.Connect() // this runs everytime the API is called api.HandlerFoobar = foobar.handlerFunction(func(params foobar.Params) middleware.Responder { // Here I want to add something to the selected dbinit selectedDb.Get(client, addStringA, addStringB, addStringC) return // the API response }) ... ``` Problem statement When I return the client for Mysql, it doesn't work for Mongo and visa versa. I want to connect to the database ONLY when starting the server and store the `client` inside the client variable. The problem, however, is that Mongo returns another client than Mysql does and so forth. - What should be in the places where I have `HERE_LIES_MY_PROBLEM` in the code? - Or do I get the Go paradigm wrong for dealing with these things?

Original source