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()
}