Files
dbx/ksuid_string.go
T
end a712ccc38f refactor(ksuid): replace BinExpr with top-level expr helpers
Adds StringKSUIDExpr and BinaryKSUIDExpr for use with ExprValues, plus
Expr() methods on both types. Removes ExprStringKSUIDs and BinExpr.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-29 18:49:19 -07:00

101 lines
2.6 KiB
Go

package dbx
import (
"database/sql/driver"
"fmt"
"io"
"github.com/segmentio/ksuid"
)
// StringKSUID wraps segmentio/ksuid for text-column storage (VARCHAR, TEXT).
// SQL Scan/Value use the base62 string encoding. GraphQL transit uses a string
// scalar (base62 KSUID).
type StringKSUID struct {
ksuid.KSUID
}
// NilStringKSUID is the zero/nil StringKSUID value.
var NilStringKSUID = StringKSUID{KSUID: ksuid.Nil}
// Equal reports whether two StringKSUID values represent the same identifier,
// treating two nil values as equal. Implements [ApplyInterface].
func (s StringKSUID) Equal(rh StringKSUID) bool {
return equalKSUID(s.KSUID, rh.KSUID)
}
// IsZero reports whether s is nil. Implements [ApplyInterface].
func (s StringKSUID) IsZero() bool {
return s.IsNil()
}
// NewStringKSUID generates a new StringKSUID.
func NewStringKSUID() StringKSUID {
return StringKSUID{KSUID: ksuid.New()}
}
// ParseStringKSUID parses a StringKSUID from its base62 string form.
func ParseStringKSUID(s string) (StringKSUID, error) {
id, err := ksuid.Parse(s)
if err != nil {
return StringKSUID{}, err
}
return StringKSUID{KSUID: id}, nil
}
// AsBinaryKSUID returns a BinaryKSUID view of the same identifier.
func (s StringKSUID) AsBinaryKSUID() BinaryKSUID {
return BinaryKSUID{KSUID: s.KSUID}
}
// Expr returns a Jet expression for this StringKSUID. See [StringKSUIDExpr].
func (s StringKSUID) Expr() Expression {
return StringKSUIDExpr(s)
}
// Scan implements sql.Scanner for string-backed KSUID columns.
func (s *StringKSUID) Scan(src any) error {
switch v := src.(type) {
case nil:
*s = StringKSUID{}
return nil
case string:
id, err := ksuid.Parse(v)
if err != nil {
return fmt.Errorf("StringKSUID.Scan: %w", err)
}
*s = StringKSUID{KSUID: id}
return nil
case []byte:
if len(v) == ksuidBinaryLength {
return fmt.Errorf("StringKSUID.Scan: binary KSUID payload (%d bytes); use BinaryKSUID", len(v))
}
id, err := ksuid.Parse(string(v))
if err != nil {
return fmt.Errorf("StringKSUID.Scan: %w", err)
}
*s = StringKSUID{KSUID: id}
return nil
default:
return fmt.Errorf("StringKSUID.Scan: unable to scan type %T", v)
}
}
// Value implements driver.Valuer for string-backed KSUID columns.
func (s StringKSUID) Value() (driver.Value, error) {
if s.IsNil() {
return nil, nil
}
return s.String(), nil
}
// UnmarshalGQL implements the graphql.Unmarshaler interface.
func (s *StringKSUID) UnmarshalGQL(value any) error {
return unmarshalKSUIDFromGQL(value, s.UnmarshalText)
}
// MarshalGQL implements the graphql.Marshaler interface.
func (s StringKSUID) MarshalGQL(w io.Writer) {
marshalKSUIDToGQL(w, s.KSUID)
}