package model import ( "encoding/base32" "fmt" "io" "github.com/google/uuid" ) // Crockford's low-ambiguity base32 alphabet var base32Encoding = base32. NewEncoding("0123456789ABCDEFGHJKMNPQRSTVWXYZ"). WithPadding(base32.NoPadding) type ID struct { uuid uuid.UUID } // Creates a new resource ID. func NewID() ID { uuid, err := uuid.NewV7() if err != nil { panic(err) } return ID{ uuid: uuid, } } // Returns the UUID representation of this ID. func (id *ID) UUID() uuid.UUID { return id.uuid } // Returns the string representation of this ID. func (id *ID) String() string { return base32Encoding.EncodeToString(id.uuid[:]) } func (id ID) MarshalGQL(w io.Writer) { w.Write([]byte(fmt.Sprintf(`"%s"`, id.String()))) } func (id *ID) UnmarshalGQL(v interface{}) error { switch v := v.(type) { case string: bytes, err := base32Encoding.DecodeString(v) if err != nil { return err } id.uuid, err = uuid.FromBytes(bytes) if err != nil { return err } return nil default: return fmt.Errorf("%T is not a valid ID", v) } } // database/sql.Scanner func (id *ID) Scan(src any) error { var uuid uuid.UUID err := uuid.Scan(src) if err != nil { return err } id.uuid = uuid return nil }