package models import ( "context" "database/sql/driver" "fmt" "github.com/oklog/ulid/v2" "gorm.io/gorm" "gorm.io/gorm/clause" ) // ULIDWrapper wraps ulid.ULID to allow method definitions type ULIDWrapper struct { ulid.ULID } // Compare implements the same comparison method as ulid.ULID func (u ULIDWrapper) Compare(other ULIDWrapper) int { return u.ULID.Compare(other.ULID) } // FromULID creates a ULIDWrapper from a ulid.ULID func FromULID(id ulid.ULID) ULIDWrapper { return ULIDWrapper{ULID: id} } // From String creates a ULIDWrapper from a string func ULIDWrapperFromString(id string) (ULIDWrapper, error) { parsed, err := ulid.Parse(id) if err != nil { return ULIDWrapper{}, fmt.Errorf("failed to parse ULID string: %w", err) } return FromULID(parsed), nil } // ToULID converts a ULIDWrapper to a ulid.ULID func (u ULIDWrapper) ToULID() ulid.ULID { return u.ULID } // GormValue implements the gorm.Valuer interface for ULIDWrapper func (u ULIDWrapper) GormValue(ctx context.Context, db *gorm.DB) clause.Expr { return clause.Expr{ SQL: "?", Vars: []any{u.String()}, } } // Scan implements the Scanner interface for ULIDWrapper func (u *ULIDWrapper) Scan(src any) error { switch v := src.(type) { case string: parsed, err := ulid.Parse(v) if err != nil { return fmt.Errorf("failed to parse ULID string: %w", err) } u.ULID = parsed return nil case []byte: parsed, err := ulid.Parse(string(v)) if err != nil { return fmt.Errorf("failed to parse ULID bytes: %w", err) } u.ULID = parsed return nil default: return fmt.Errorf("cannot scan %T into ULIDWrapper", src) } } // Value implements the driver.Valuer interface for ULIDWrapper func (u ULIDWrapper) Value() (driver.Value, error) { return u.String(), nil }