package model import ( "database/sql/driver" "encoding/base32" "fmt" "io" "github.com/google/uuid" ) // Crockford's low-ambiguity base32 alphabet var base32Encoding = base32. NewEncoding("0123456789abcdefghjkmnpqrstvwxyz"). WithPadding(base32.NoPadding) // An RID is a unique resource ID. type RID struct { uuid uuid.NullUUID } // Creates a new resource ID. func NewRID() RID { uu, err := uuid.NewV7() if err != nil { panic(err) } return RID{ uuid: uuid.NullUUID{ UUID: uu, Valid: true, }, } } // Returns the UUID representation of this RID. func (rid *RID) UUID() uuid.UUID { if !rid.uuid.Valid { panic(fmt.Errorf("invalid UUID")) } return rid.uuid.UUID } // Returns the string representation of this RID. func (rid *RID) String() string { if !rid.uuid.Valid { return "" } return base32Encoding.EncodeToString(rid.uuid.UUID[:]) } func (rid RID) MarshalGQL(w io.Writer) { w.Write(fmt.Appendf(nil, `"%s"`, rid.String())) } func (rid *RID) unmarshalString(s string) error { if len(s) == 0 { rid.uuid.Valid = false return nil } bytes, err := base32Encoding.DecodeString(s) if err != nil { return err } rid.uuid.UUID, err = uuid.FromBytes(bytes) if err != nil { rid.uuid.Valid = false return err } rid.uuid.Valid = true return nil } func (rid *RID) UnmarshalGQL(v any) error { switch v := v.(type) { case string: return rid.unmarshalString(v) default: return fmt.Errorf("%T is not a valid RID", v) } } // database/sql.Scanner func (rid *RID) Scan(src any) error { switch src := src.(type) { case string: return rid.unmarshalString(src) default: return rid.uuid.Scan(src) } } // database/sql/driver.Valuer func (rid RID) Value() (driver.Value, error) { return rid.uuid.Value() }