Skip to content

Instantly share code, notes, and snippets.

@aliuygur
Created September 8, 2017 10:55
Show Gist options
  • Save aliuygur/2bd0e815aa898cb501f3d67a7c53b91e to your computer and use it in GitHub Desktop.
Save aliuygur/2bd0e815aa898cb501f3d67a7c53b91e to your computer and use it in GitHub Desktop.
mongo golang examples
package mongo
import (
mgo "gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
)
type (
nextID struct {
Next uint64 `bson:"n"`
}
)
const idTbl = `ids`
// id returns next id.
// if sess nil then it uses default session
func (r *repository) id(c string) uint64 {
ids := r.c(idTbl)
change := mgo.Change{
Update: bson.M{"$inc": bson.M{"n": 1}},
Upsert: true,
ReturnNew: true,
}
id := new(nextID)
ids.Find(bson.M{"_id": c}).Apply(change, id)
return id.Next
}
package mongo
import (
"github.com/alioygur/fb-tinder-app/domain"
"github.com/alioygur/fb-tinder-app/service"
"gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
)
type (
fakePicture interface {
PutPicture(*domain.Image) error
PicturesByUserID(uint64) ([]*domain.Image, error)
ProfilePicture(uint64) (*domain.Image, error)
PictureByID(uint64) (*domain.Image, error)
PictureExistsByUserIDAndIsProfile(uint64, bool) (bool, error)
UpdatePicture(*domain.Image) error
DeletePicture(uint64) error
}
repository struct {
fakePicture
sess *mgo.Session
}
)
const (
usersTbl = `users`
reactionsTbl = `reactions`
creditsTbl = `credits`
friendshipsTbl = `friendships`
matchesTbl = `matches`
abusesTbl = `abuses`
imagesTbl = `images`
)
// New instances new repository
func New(sess *mgo.Session) service.Repository {
return &repository{sess: sess}
}
// c returns mgo collection.
// if sess nil then it uses default session
func (r *repository) c(c string) *mgo.Collection {
return r.sess.DB("").C(c)
}
func (r *repository) oneBy(c *mgo.Collection, q interface{}, result interface{}) error {
return c.Find(q).One(result)
}
func (r *repository) oneByID(c *mgo.Collection, id uint64, result interface{}) error {
return r.oneBy(c, bson.M{"id": id}, result)
}
func (r *repository) existsBy(c *mgo.Collection, q interface{}) (bool, error) {
n, err := c.Find(q).Limit(1).Count()
return n > 0, err
}
func wrapErr(err error) error {
return err
}
package mongo
import (
"time"
"strconv"
mgo "gopkg.in/mgo.v2"
)
func randDBName() string {
return "testdb_" + strconv.Itoa(time.Now().Nanosecond())
}
func newTestRepo(dropDB bool) (*repository, func(), error) {
dbname := randDBName()
sess, err := mgo.Dial("localhost/" + dbname)
if err != nil {
return nil, nil, nil
}
deferFnc := func() {
if dropDB {
sess.DB("").DropDatabase()
}
sess.Close()
}
r := repository{sess: sess}
return &r, deferFnc, nil
}
package mongo
import (
"time"
"gopkg.in/mgo.v2/bson"
"github.com/alioygur/fb-tinder-app/domain"
"github.com/pkg/errors"
)
type (
user struct {
domain.User `bson:",inline"`
FriendList []uint64 `bson:"friend_list"`
}
)
func (r *repository) AddUser(du *domain.User) error {
now := time.Now().Round(time.Second)
du.CreatedAt = now
du.UpdatedAt = now
du.ID = r.id(usersTbl)
var u user
u.User = *du
return r.c(usersTbl).Insert(&u)
}
func (r *repository) UserByID(id uint64) (*domain.User, error) {
var u domain.User
err := r.c(usersTbl).Find(bson.M{"id": id}).One(&u)
return &u, errors.WithStack(wrapErr(err))
}
func (r *repository) UserByEmail(email string) (*domain.User, error) {
var u domain.User
err := r.c(usersTbl).Find(bson.M{"email": email}).One(&u)
return &u, errors.WithStack(wrapErr(err))
}
func (r *repository) UserByFacebookID(id uint64) (*domain.User, error) {
var u domain.User
err := r.c(usersTbl).Find(bson.M{"facebook_id": id}).One(&u)
return &u, errors.WithStack(wrapErr(err))
}
func (r *repository) ExistsByEmail(email string) (bool, error) {
n, err := r.c(usersTbl).Find(bson.M{"email": email}).Count()
return n > 0, errors.WithStack(err)
}
func (r *repository) UserExistsByID(id uint64) (bool, error) {
n, err := r.c(usersTbl).Find(bson.M{"id": id}).Count()
return n > 0, errors.WithStack(err)
}
func (r *repository) UserExistsByFacebookID(id uint64) (bool, error) {
n, err := r.c(usersTbl).Find(bson.M{"facebook_id": id}).Count()
return n > 0, errors.WithStack(err)
}
func (r *repository) UpdateUser(u *domain.User) error {
u.UpdatedAt = time.Now()
err := r.c(usersTbl).Update(bson.M{"id": u.ID}, u)
return errors.WithStack(wrapErr(err))
}
func (r *repository) SyncUserFriendsByFacebookID(user uint64, friends []uint64) error {
return nil
}
func (r *repository) BindFriends(users ...*domain.User) error {
count := len(users)
errc := make(chan error, count)
for _, u := range users {
go func(u *domain.User) {
sess := r.sess.Copy()
defer sess.Close()
c := r.c(usersTbl).With(sess)
var res struct {
FriendList []uint64 `bson:"friend_list"`
}
if err := c.Find(bson.M{"id": u.ID}).Select(bson.M{"friend_list": 1}).One(&res); err != nil {
errc <- errors.WithStack(err)
return
}
err := c.Find(bson.M{"id": bson.M{"$in": res.FriendList}}).All(&u.Friends)
errc <- errors.WithStack(err)
}(u)
}
// check for errors
for i := 0; i < count; i++ {
if err := <-errc; err != nil {
return err
}
}
return nil
}
package mongo
import (
"testing"
"gopkg.in/mgo.v2/bson"
"reflect"
"github.com/alioygur/fb-tinder-app/domain"
)
func Test_repository_PutUser(t *testing.T) {
r, deferFnc, err := newTestRepo(true)
if err != nil {
t.Fatal(err)
}
defer deferFnc()
want := domain.NewUser()
want.FirstName = "Ali"
want.LastName = "OYGUR"
want.Email = "alioygur@gmail.com"
if err := r.AddUser(want); err != nil {
t.Error(err)
return
}
var got domain.User
if err := r.c(usersTbl).Find(bson.M{"id": want.ID}).One(&got); err != nil {
t.Error(err)
return
}
got.Friends = make([]*domain.User, 0)
if !reflect.DeepEqual(got, *want) {
t.Errorf("not equal, got %+v, want %+v", got, want)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment