package cursor import ( "encoding/json" "testing" "time" "github.com/go-jet/jet/v2/mysql" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestColumnKey(t *testing.T) { assert := assert.New(t) empty := ColumnKey{} assert.True(empty.IsEmpty()) assert.Equal("user.id", NewColumnKey(User.ID).String()) columnKey := NewColumnKey(User.ID) assert.Equal(User.TableName(), columnKey.Table) assert.Equal(User.ID.Name(), columnKey.Column) assert.False(columnKey.IsEmpty()) bytes, err := json.Marshal(columnKey) assert.NoError(err) assert.Equal(`{"table":"user","column":"id"}`, string(bytes)) var res ColumnKey err = json.Unmarshal(bytes, &res) assert.NoError(err) assert.Equal(User.TableName(), res.Table) assert.Equal(User.ID.Name(), res.Column) } func TestColumnRegistry(t *testing.T) { assert := assert.New(t) RegisterColumn(User.ID) col, err := GetColumn(User.TableName(), User.ID.Name()) assert.NoError(err) assert.Equal(User.ID, col) _, err = GetColumn(User.TableName(), "nonexistent") assert.Error(err) col, err = GetColumnByKey(ColumnKey{ Table: User.TableName(), Column: User.ID.Name(), }) assert.NoError(err) assert.Equal(User.ID, col) _, err = GetColumnByKey(ColumnKey{ Table: User.TableName(), Column: "nonexistent", }) assert.Error(err) _, err = GetColumn(User.TableName(), User.CreatedAt.Name()) assert.Error(err) } func TestRegisterColumnList(t *testing.T) { assert := assert.New(t) RegisterColumnList(Address.AllColumns) col, err := GetColumn(Address.TableName(), Address.ID.Name()) assert.NoError(err) assert.Equal(Address.ID, col) } func TestOrderDirection(t *testing.T) { assert := assert.New(t) bytes, err := json.Marshal(OrderAscending) assert.NoError(err) assert.Equal(`"ASC"`, string(bytes)) var res OrderDirection err = json.Unmarshal(bytes, &res) assert.NoError(err) assert.Equal(OrderAscending, res) bytes, err = json.Marshal(OrderDescending) assert.NoError(err) assert.Equal(`"DESC"`, string(bytes)) err = json.Unmarshal(bytes, &res) assert.NoError(err) assert.Equal(OrderDescending, res) var invalid OrderDirection err = json.Unmarshal([]byte(`"INVALID"`), &invalid) assert.Error(err) _, err = OrderDirection(99).MarshalJSON() assert.Error(err) } func TestInt64Value(t *testing.T) { assert := assert.New(t) v := NewInt64Value(1, Scratch.ID) assert.Equal(int64(1), v.Val) assert.Equal(Scratch.ID.Name(), v.Key.Column) assert.Equal(Scratch.TableName(), v.Key.Table) assert.Equal(mysql.Int64(1), v.Expr()) assert.Panics(func() { v.Col() }) RegisterColumn(Scratch.ID) assert.Equal(Scratch.ID, v.Col()) assert.False(v.IsEmpty()) bytes, err := json.Marshal(v) assert.NoError(err) assert.Equal(`{"key":{"table":"scratch","column":"id"},"val":1}`, string(bytes)) var res Int64Value assert.True(res.IsEmpty()) err = json.Unmarshal(bytes, &res) assert.NoError(err) assert.Equal(int64(1), res.Val) assert.Equal(Scratch.ID.Name(), res.Key.Column) assert.Equal(Scratch.TableName(), res.Key.Table) assert.Equal(mysql.Int64(1), res.Expr()) assert.Equal(Scratch.ID, v.Col()) } func TestUint64Value(t *testing.T) { assert := assert.New(t) v := NewUint64Value(42, Spare.ID) assert.Equal(uint64(42), v.Val) assert.Equal(mysql.Uint64(42), v.Expr()) assert.Panics(func() { v.Col() }) RegisterColumn(Spare.ID) assert.Equal(Spare.ID, v.Col()) assert.False(v.IsEmpty()) bytes, err := json.Marshal(v) assert.NoError(err) var res Uint64Value assert.True(res.IsEmpty()) err = json.Unmarshal(bytes, &res) assert.NoError(err) assert.Equal(uint64(42), res.Val) } func TestStringValueIsEmpty(t *testing.T) { assert := assert.New(t) registerMeetingCursorColumns(t) empty := NewStringValue("", Meeting.ID) assert.True(empty.IsEmpty()) nonEmpty := NewStringValue("meeting-uuid-1", Meeting.ID) assert.False(nonEmpty.IsEmpty()) defaultMeetingCursor := NewCursor( NewStringValue("", Meeting.ID), Meeting.StartTime, OrderDescending, ) assert.True(defaultMeetingCursor.IsEmpty()) } func TestNewCursor(t *testing.T) { assert := assert.New(t) empty := Cursor[mysql.IntegerExpression, mysql.ColumnInteger]{} assert.True(empty.IsEmpty()) v := NewInt64Value(1, User.ID) cursor := NewCursor(v, User.ID, OrderAscending) assert.Equal(v, cursor.Index) assert.Equal(NewColumnKey(User.ID), cursor.OrderColumnKey) assert.Equal(OrderAscending, cursor.OrderDir) bytes, err := json.Marshal(cursor) assert.NoError(err) assert.Equal(`{"index":{"key":{"table":"user","column":"id"},"val":1},"order_col":{"table":"user","column":"id"},"order_dir":"ASC"}`, string(bytes)) } func TestCopyWithVal(t *testing.T) { assert := assert.New(t) RegisterColumn(User.ID) original := NewCursor(NewInt64Value(1, User.ID), User.ID, OrderDescending) copied := original.CopyWithVal(NewInt64Value(99, User.ID)) assert.Equal(int64(99), copied.Index.(*Int64Value).Val) assert.Equal(OrderDescending, copied.OrderDir) assert.Equal(NewColumnKey(User.ID), copied.OrderColumnKey) } func TestNewCursorFromJSON(t *testing.T) { assert := assert.New(t) v := NewInt64Value(1, User.ID) cursor := NewCursor(v, User.ID, OrderDescending) bytes, err := json.Marshal(cursor) assert.NoError(err) zv := NewInt64Value(0, User.ID) res, err := NewCursorFromJSON(zv, bytes) assert.NoError(err) assert.NotNil(res) assert.Equal(int64(1), res.Index.(*Int64Value).Val) assert.Equal(NewColumnKey(User.ID), res.OrderColumnKey) assert.Equal(OrderDescending, res.OrderDir) } func TestNewCursorFromJSONComposite(t *testing.T) { assert := assert.New(t) registerMeetingCursorColumns(t) when := time.Date(2026, 6, 1, 9, 0, 0, 0, time.UTC) original := NewCursor( NewStringValue("", Meeting.ID), Meeting.StartTime, OrderDescending, ).CopyWithVals( NewStringValue("meeting-uuid-1", Meeting.ID), NewTimestampValue(when, Meeting.StartTime), ) bytes, err := json.Marshal(original) require.NoError(t, err) zv := NewStringValue("", Meeting.ID) res, err := NewCursorFromJSON(zv, bytes) require.NoError(t, err) assert.True(res.IsComposite()) assert.Equal("meeting-uuid-1", res.Index.(*StringValue).Val) assert.Equal(when, res.GenericOrderValue().(*TimestampValue).Val) } func TestDecodeAndOrder(t *testing.T) { assert := assert.New(t) RegisterColumn(User.ID) encoded, err := NewCursor( NewInt64Value(5, User.ID), User.ID, OrderDescending, ).Encode() require.NoError(t, err) c := NewCursor(NewInt64Value(0, User.ID), User.ID, OrderAscending) require.NoError(t, c.DecodeAndOrder(encoded, OrderAscending)) assert.Equal(OrderAscending, c.OrderDir) assert.Equal(int64(5), c.Index.(*Int64Value).Val) } func TestCursorDecodeNilReceiver(t *testing.T) { var c *Cursor[mysql.IntegerExpression, mysql.ColumnInteger] assert.Error(t, c.Decode("{}")) } func TestNewCursorFromAfterPtr(t *testing.T) { assert := assert.New(t) require := require.New(t) RegisterColumn(User.ID) newZero := func() *Cursor[mysql.IntegerExpression, mysql.ColumnInteger] { return NewCursor(NewInt64Value(0, User.ID), User.ID, OrderDescending) } c, err := NewCursorFromAfterPtr(newZero, nil) require.NoError(err) assert.Nil(c) empty := "" c, err = NewCursorFromAfterPtr(newZero, &empty) require.NoError(err) assert.Nil(c) encoded, err := NewCursor( NewInt64Value(42, User.ID), User.ID, OrderDescending, ).Encode() require.NoError(err) c, err = NewCursorFromAfterPtr(newZero, &encoded) require.NoError(err) require.NotNil(c) assert.Equal(int64(42), c.Index.(*Int64Value).Val) }