~bigbes/core-go

34c2db68235cabb69af635e0dbd3d8556daaeef8 — Drew DeVault 6 months ago 9ad4643
model: rename ID => RID, implement sql Valuer

As in "Resource" ID. I also changed the base32 alphabet to lowercase,
because I subjectively think it looks nicer.
1 files changed, 24 insertions(+), 17 deletions(-)

R model/{id => rid}.go
R model/id.go => model/rid.go +24 -17
@@ 1,6 1,7 @@
package model

import (
	"database/sql/driver"
	"encoding/base32"
	"fmt"
	"io"


@@ 10,62 11,68 @@ import (

// Crockford's low-ambiguity base32 alphabet
var base32Encoding = base32.
	NewEncoding("0123456789ABCDEFGHJKMNPQRSTVWXYZ").
	NewEncoding("0123456789abcdefghjkmnpqrstvwxyz").
	WithPadding(base32.NoPadding)

type ID struct {
// An RID is a unique resource ID.
type RID struct {
	uuid uuid.UUID
}

// Creates a new resource ID.
func NewID() ID {
func NewRID() RID {
	uuid, err := uuid.NewV7()
	if err != nil {
		panic(err)
	}
	return ID{
	return RID{
		uuid: uuid,
	}
}

// Returns the UUID representation of this ID.
func (id *ID) UUID() uuid.UUID {
	return id.uuid
// Returns the UUID representation of this RID.
func (rid *RID) UUID() uuid.UUID {
	return rid.uuid
}

// Returns the string representation of this ID.
func (id *ID) String() string {
	return base32Encoding.EncodeToString(id.uuid[:])
// Returns the string representation of this RID.
func (rid *RID) String() string {
	return base32Encoding.EncodeToString(rid.uuid[:])
}

func (id ID) MarshalGQL(w io.Writer) {
	w.Write(fmt.Appendf(nil, `"%s"`, id.String()))
func (rid RID) MarshalGQL(w io.Writer) {
	w.Write(fmt.Appendf(nil, `"%s"`, rid.String()))
}

func (id *ID) UnmarshalGQL(v any) error {
func (rid *RID) UnmarshalGQL(v any) error {
	switch v := v.(type) {
	case string:
		bytes, err := base32Encoding.DecodeString(v)
		if err != nil {
			return err
		}
		id.uuid, err = uuid.FromBytes(bytes)
		rid.uuid, err = uuid.FromBytes(bytes)
		if err != nil {
			return err
		}
		return nil
	default:
		return fmt.Errorf("%T is not a valid ID", v)
		return fmt.Errorf("%T is not a valid RID", v)
	}
}

// database/sql.Scanner
func (id *ID) Scan(src any) error {
func (rid *RID) Scan(src any) error {
	var uuid uuid.UUID
	err := uuid.Scan(src)
	if err != nil {
		return err
	}
	id.uuid = uuid
	rid.uuid = uuid
	return nil
}

// database/sql/driver.Valuer
func (rid RID) Value() (driver.Value, error) {
	return rid.UUID().Value()
}