Skip to content

Instantly share code, notes, and snippets.

@saniales
Last active February 20, 2022 15:58
Show Gist options
  • Save saniales/532774ca61a17980431890fbef9438ad to your computer and use it in GitHub Desktop.
Save saniales/532774ca61a17980431890fbef9438ad to your computer and use it in GitHub Desktop.
Unmarshal UUID in mongo in Go using Mongo Go Driver

Usage

Copy in a separated package called mongoutil the content of the .go file, then use it as follows

import (
  "path/of/mongoutil" 
)

type example struct {
  Field1 int             `bson:"field_1"`
  Field2 *mongoutil.UUID `bson:"field_2"`
}

Usage with Goa (v1)

This is the proper way to use the UUID type in Goa V1, a similar way can be used with other versions. Remember to copy the func_helpers.go file in the design directory of your project.

package design

// ... 

var myType = Type("myType", func() {
    BSONMember("field_1", Integer)
    BSONMember("field_2", UUID, func() {
        Metadata("struct:field:type", "*mongoutil.UUID", "path/of/mongoutil")
        // if you use Goa v2, use Meta(...) instead of Metadata
    })
})
package design
import (
. "github.com/goadesign/goa/design/apidsl"
)
func applyStructTags(name string) {
Metadata("struct:tag:bson", name)
Metadata("struct:tag:json", name)
}
func bson(name string, args []interface{}) []interface{} {
dsl := func() {
applyStructTags(name)
}
if len(args) > 0 {
if d, ok := args[len(args)-1].(func()); ok {
mdsl := dsl
dsl = func() { d(); mdsl() }
args = args[:len(args)-1]
}
}
return append(args, dsl)
}
// BSONAttribute creates a normal apidsl Attribute with extra `bson` struct tag when using `goagen`.
func BSONAttribute(name string, args ...interface{}) {
args = bson(name, args)
Attribute(name, args...)
}
// BSONMember creates a normal apidsl BSONMember with extra `bson` struct tag when using `goagen`.
func BSONMember(name string, args ...interface{}) {
args = bson(name, args)
Member(name, args...)
}
package mongoutil
import (
"bytes"
"fmt"
"github.com/gofrs/uuid"
"go.mongodb.org/mongo-driver/bson/bsontype"
"go.mongodb.org/mongo-driver/x/bsonx/bsoncore"
)
// UUID represents a UUID as saved in MongoDB
type UUID struct{ uuid.UUID }
const uuidSubType byte = 0x04
// NewUUID generates a new MongoDB compatible UUID.
func NewUUID() (*UUID, error) {
id, err := uuid.NewV4()
if err != nil {
return nil, err
}
return &UUID{UUID: id}, nil
}
// UUIDFromStringOrNil returns a UUID parsed from the input string.
func UUIDFromStringOrNil(input string) *UUID {
id := uuid.FromStringOrNil(input)
if id == uuid.Nil {
return nil
}
return &UUID{id}
}
// MarshalBSONValue implements the bson.ValueMarshaler interface.
func (id UUID) MarshalBSONValue() (bsontype.Type, []byte, error) {
return bsontype.Binary, bsoncore.AppendBinary(nil, 4, id.UUID[:]), nil
}
// UnmarshalBSONValue implements the bson.ValueUnmarshaler interface.
func (id *UUID) UnmarshalBSONValue(t bsontype.Type, raw []byte) error {
if t != bsontype.Binary {
return fmt.Errorf("invalid format on unmarshal bson value")
}
_, data, _, ok := bsoncore.ReadBinary(raw)
if !ok {
return fmt.Errorf("not enough bytes to unmarshal bson value")
}
copy(id.UUID[:], data)
return nil
}
// IsZero implements the bson.Zeroer interface.
func (id *UUID) IsZero() bool {
return bytes.Compare(id.Bytes(), uuid.Nil.Bytes()) == 0
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment