338294f957
Adds ParseStringKSUIDAny, ParseBinaryKSUIDAny, BinaryKSUID.BinExpr, and ExprStringKSUIDs. Co-authored-by: Cursor <cursoragent@cursor.com>
100 lines
2.7 KiB
Go
100 lines
2.7 KiB
Go
package dbx
|
|
|
|
import (
|
|
"database/sql/driver"
|
|
"fmt"
|
|
"io"
|
|
|
|
"github.com/go-jet/jet/v2/mysql"
|
|
"github.com/segmentio/ksuid"
|
|
)
|
|
|
|
// BinaryKSUID wraps segmentio/ksuid for binary-column storage (BINARY(20), BYTEA).
|
|
// SQL Scan/Value use the raw 20-byte encoding. GraphQL transit uses a string
|
|
// scalar (base62 KSUID).
|
|
type BinaryKSUID struct {
|
|
ksuid.KSUID
|
|
}
|
|
|
|
// NilBinaryKSUID is the zero/nil BinaryKSUID value.
|
|
var NilBinaryKSUID = BinaryKSUID{KSUID: ksuid.Nil}
|
|
|
|
// Equal reports whether two BinaryKSUID values represent the same identifier,
|
|
// treating two nil values as equal. Implements [ApplyInterface].
|
|
func (b BinaryKSUID) Equal(rh BinaryKSUID) bool {
|
|
return equalKSUID(b.KSUID, rh.KSUID)
|
|
}
|
|
|
|
// IsZero reports whether b is nil. Implements [ApplyInterface].
|
|
func (b BinaryKSUID) IsZero() bool {
|
|
return b.IsNil()
|
|
}
|
|
|
|
// NewBinaryKSUID generates a new BinaryKSUID.
|
|
func NewBinaryKSUID() BinaryKSUID {
|
|
return BinaryKSUID{KSUID: ksuid.New()}
|
|
}
|
|
|
|
// ParseBinaryKSUID parses a BinaryKSUID from its raw 20-byte form.
|
|
func ParseBinaryKSUID(b []byte) (BinaryKSUID, error) {
|
|
id, err := ksuid.FromBytes(b)
|
|
if err != nil {
|
|
return BinaryKSUID{}, err
|
|
}
|
|
return BinaryKSUID{KSUID: id}, nil
|
|
}
|
|
|
|
// BinExpr returns a Jet string expression for binary-encoded IN clauses.
|
|
func (b BinaryKSUID) BinExpr() mysql.StringExpression {
|
|
if b.IsNil() {
|
|
return mysql.StringExp(mysql.NULL)
|
|
}
|
|
return mysql.String(string(b.Bytes()))
|
|
}
|
|
|
|
// AsStringKSUID returns a StringKSUID view of the same identifier.
|
|
func (b BinaryKSUID) AsStringKSUID() StringKSUID {
|
|
return StringKSUID{KSUID: b.KSUID}
|
|
}
|
|
|
|
// Scan implements sql.Scanner for binary-backed KSUID columns.
|
|
func (b *BinaryKSUID) Scan(src any) error {
|
|
switch v := src.(type) {
|
|
case nil:
|
|
*b = BinaryKSUID{}
|
|
return nil
|
|
case []byte:
|
|
if len(v) == ksuidStringLength {
|
|
return fmt.Errorf("BinaryKSUID.Scan: string-encoded KSUID (%d bytes); use StringKSUID", len(v))
|
|
}
|
|
id, err := ksuid.FromBytes(v)
|
|
if err != nil {
|
|
return fmt.Errorf("BinaryKSUID.Scan: %w", err)
|
|
}
|
|
*b = BinaryKSUID{KSUID: id}
|
|
return nil
|
|
case string:
|
|
return fmt.Errorf("BinaryKSUID.Scan: string value %q; use StringKSUID or store raw bytes", v)
|
|
default:
|
|
return fmt.Errorf("BinaryKSUID.Scan: unable to scan type %T", v)
|
|
}
|
|
}
|
|
|
|
// Value implements driver.Valuer for binary-backed KSUID columns.
|
|
func (b BinaryKSUID) Value() (driver.Value, error) {
|
|
if b.IsNil() {
|
|
return nil, nil
|
|
}
|
|
return b.Bytes(), nil
|
|
}
|
|
|
|
// UnmarshalGQL implements the graphql.Unmarshaler interface.
|
|
func (b *BinaryKSUID) UnmarshalGQL(value any) error {
|
|
return unmarshalKSUIDFromGQL(value, b.UnmarshalText)
|
|
}
|
|
|
|
// MarshalGQL implements the graphql.Marshaler interface.
|
|
func (b BinaryKSUID) MarshalGQL(w io.Writer) {
|
|
marshalKSUIDToGQL(w, b.KSUID)
|
|
}
|