First of all I am a newbie in Go. I wrote a CRUD REST API that consists of handlers, a database layer and so on, and it contains a lot of code duplication. I see some patterns here, and I know how to reuse code in some other languages like JS or Java using generics or dynamic types.
What are my options in Go? Note that I don't want to use interface{}.
Here is my userdb CRUD set of function that create, update and so on.
package userdb
import (
"github.com/atsman/interviewr-go/models"
"github.com/op/go-logging"
"gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
)
var log = logging.MustGetLogger("db.user")
func GetUserC(db *mgo.Database) *mgo.Collection {
return db.C(models.CollectionUsers)
}
func Create(db *mgo.Database, user *models.User) error {
return GetUserC(db).Insert(user)
}
func Update(db *mgo.Database, id *bson.ObjectId, user *map[string]interface{}) (error, *models.User) {
var updatedUser = models.User{}
err := GetUserC(db).UpdateId(id, bson.M{
"$set": user,
})
if err != nil {
return err, &updatedUser
}
err = GetUserC(db).FindId(id).One(&updatedUser)
return err, &updatedUser
}
func List(db *mgo.Database, query *bson.M) (error, *[]models.User) {
var users []models.User
err := GetUserC(db).Find(bson.M{}).All(&users)
return err, &users
}
func Delete(db *mgo.Database, id *bson.ObjectId) (error, *models.User) {
var user = models.User{}
err := GetUserC(db).FindId(id).One(&user)
if err != nil {
return err, &user
}
err = GetUserC(db).RemoveId(id)
if err != nil {
return err, &user
}
return nil, &user
}
And here is my companydb package. Its goals are almost the same except with the Company model.
package companydb
import (
"github.com/atsman/interviewr-go/models"
"github.com/op/go-logging"
"gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
)
var log = logging.MustGetLogger("db.company")
func GetCompanyC(db *mgo.Database) *mgo.Collection {
return db.C(models.CollectionCompanies)
}
func Create(db *mgo.Database, company *models.Company) error {
return GetCompanyC(db).Insert(company)
}
func Update(db *mgo.Database, id *bson.ObjectId, user *map[string]interface{}) (error, *models.Company) {
updatedCompany := models.Company{}
err := GetCompanyC(db).UpdateId(id, bson.M{
"$set": updatedCompany,
})
if err != nil {
return err, &updatedCompany
}
err = GetCompanyC(db).FindId(id).One(&updatedCompany)
return err, &updatedCompany
}
func List(db *mgo.Database, query *bson.M) (error, *[]models.Company) {
var companies []models.Company
err := GetCompanyC(db).Find(bson.M{}).All(&companies)
return err, &companies
}
func Delete(db *mgo.Database, id *bson.ObjectId) (error, *models.Company) {
company := models.Company{}
err := GetCompanyC(db).FindId(id).One(&company)
if err != nil {
return err, &company
}
err = GetCompanyC(db).RemoveId(id)
if err != nil {
return err, &company
}
return nil, &company
}
The same duplication exists in my handlers. There is a lot of stuff like get struct from JSON, check for errors and so on. I am thinking of some generic stuff.
So, I think the question is quite easy for guys with some experience. How can I generalize this? Or I shouldn't care at all, maybe it is not a big deal here?