2

In the current project we use Go and MongoDB via mgo driver. For every entity we have to implement DAO for CRUD operations, and it's basically copy-paste, e.g.

func (thisDao ClusterDao) FindAll() ([]*entity.User, error) {
    session, collection := thisDao.getCollection()
    defer session.Close()
    result := []*entity.User{} //create a new empty slice to return 
    q := bson.M{}
    err := collection.Find(q).All(&result)
    return result, err
}

For every other entity it's all the same but the result type.

Since Go has no generics, how could we avoid code duplication?

I've tried to pass the result interface{} param instead of creating it in the method, and call the method like this:

dao.FindAll([]*entity.User{})

but the collection.Find().All() method need a slice as the input, not just interface:

[restful] recover from panic situation: - result argument must be a slice address
/usr/local/go/src/runtime/asm_amd64.s:514
/usr/local/go/src/runtime/panic.go:489
/home/dds/gopath/src/gopkg.in/mgo.v2/session.go:3791
/home/dds/gopath/src/gopkg.in/mgo.v2/session.go:3818

Then I tried to make this param result []interface{}, but in that case it's impossible to pass []*entity.User{}:

cannot use []*entity.User literal (type []*entity.User) as type []interface {} in argument to thisDao.GenericDao.FindAll

Any idea how could I implement generic DAO in Go?

1 Answer 1

2

You should be able to pass a result interface{} to your FindAll function and just pass it along to mgo's Query.All method since the argument's would have the same type.

func (thisDao ClusterDao) FindAll(result interface{}) error {
    session, collection := thisDao.getCollection()
    defer session.Close()
    q := bson.M{}
    // just pass result as is, don't do & here
    // because that would be a pointer to the interface not
    // to the underlying slice, which mgo probably doesn't like
    return collection.Find(q).All(result)
}

// ...

users := []*entity.User{}
if err := dao.FindAll(&users); err != nil { // pass pointer to slice here
    panic(err)
}
log.Println(users)
Sign up to request clarification or add additional context in comments.

2 Comments

No, it does not work. The result: [restful] recover from panic situation: - result argument must be a slice address /usr/local/go/src/runtime/asm_amd64.s:514 /usr/local/go/src/runtime/panic.go:489 /home/dds/gopath/src/gopkg.in/mgo.v2/session.go:3791
Look, in your sample code you're not passing a pointer to a slice dao.FindAll([]*entity.User{}) <-- this is why you're getting that error, this is not a pointer to a slice, it's a slice of pointers to User structs, ok? In my example I added comments to point this out... Just tested the code in my example and it works. If you're sure you're passing a pointer to a slice please share more of your code so I can help.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.