feat(ksuid): add Equal and IsZero for ApplyInterfacePtr

StringKSUID and BinaryKSUID now implement ApplyInterface with nil-nil
equality semantics, enabling ApplyInterfacePtr in patch logic. Adds nil
sentinel vars and tests.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-06-29 18:24:07 -07:00
parent 0f8e79a890
commit cc44931ea9
6 changed files with 69 additions and 3 deletions
+1
View File
@@ -12,6 +12,7 @@
### Added
- `StringKSUID.Equal` / `IsZero`, `BinaryKSUID.Equal` / `IsZero`, and nil sentinel vars for [ApplyInterfacePtr].
- Context-aware variants for all query and mutation helpers.
- `Delete`, `DeleteAffected`, `WithTx`, `ContainsCol`, and `CurrentDialect()`.
- Package documentation (`doc.go`), expanded README, and subpackage docs for `dbxm` / `dbxp`.
+4 -3
View File
@@ -23,9 +23,10 @@
// # Identifier types
//
// [StringKSUID] and [BinaryKSUID] wrap segmentio/ksuid with storage-specific
// SQL encoding. Both share identical GraphQL string scalar transit. Choose StringKSUID
// for text columns (VARCHAR, TEXT); choose BinaryKSUID for binary columns
// (BINARY(20), BYTEA).
// SQL encoding. Both implement [ApplyInterface] via Equal and IsZero for use
// with [ApplyInterfacePtr]. Both share identical GraphQL string scalar transit.
// Choose StringKSUID for text columns (VARCHAR, TEXT); choose BinaryKSUID for
// binary columns (BINARY(20), BYTEA).
//
// [JSONB] provides map-based JSON column scanning for Postgres JSONB and MySQL JSON.
//
+14
View File
@@ -15,6 +15,20 @@ 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()}
+7
View File
@@ -28,3 +28,10 @@ const (
ksuidBinaryLength = 20
ksuidStringLength = 27
)
func equalKSUID(lh, rh ksuid.KSUID) bool {
if lh.IsNil() && rh.IsNil() {
return true
}
return lh.String() == rh.String()
}
+14
View File
@@ -15,6 +15,20 @@ 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()}
+29
View File
@@ -6,6 +6,7 @@ import (
"io"
"testing"
"github.com/go-jet/jet/v2/mysql"
"github.com/segmentio/ksuid"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -118,6 +119,34 @@ func TestBinaryKSUID_Conversion(t *testing.T) {
}
func TestStringKSUID_EqualIsZero(t *testing.T) {
id := NewStringKSUID()
assert.True(t, NilStringKSUID.Equal(NilStringKSUID))
assert.True(t, id.Equal(id))
assert.False(t, id.Equal(NilStringKSUID))
assert.True(t, NilStringKSUID.IsZero())
assert.False(t, id.IsZero())
}
func TestBinaryKSUID_EqualIsZero(t *testing.T) {
id := NewBinaryKSUID()
assert.True(t, NilBinaryKSUID.Equal(NilBinaryKSUID))
assert.True(t, id.Equal(id))
assert.False(t, id.Equal(NilBinaryKSUID))
assert.True(t, NilBinaryKSUID.IsZero())
assert.False(t, id.IsZero())
}
func TestStringKSUID_ApplyInterfacePtr(t *testing.T) {
targetCol := mysql.StringColumn("id")
modified := make(ColumnList, 0)
current := Ptr(NewStringKSUID())
updated := ApplyInterfacePtr(current, Ptr(NewStringKSUID()), &modified, targetCol)
require.NotNil(t, updated)
assert.Len(t, modified, 1)
assert.False(t, current.Equal(*updated))
}
func TestParseStringKSUID(t *testing.T) {
id := ksuid.New()
parsed, err := ParseStringKSUID(id.String())