github.com/ydb-platform/ydb-go-sdk/v3@v3.89.2/topic/topicsugar/cdc-reader.go (about)

     1  //go:build go1.23
     2  
     3  package topicsugar
     4  
     5  import (
     6  	"context"
     7  	"encoding/json"
     8  	"fmt"
     9  
    10  	"github.com/ydb-platform/ydb-go-sdk/v3/internal/xiter"
    11  )
    12  
    13  // YDBCDCItem interface for represent record from table (and cdc event)
    14  // The interface will be removed in the future  (or may be set as optional)
    15  // and replaced by field annotations
    16  //
    17  // Experimental: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#experimental
    18  type YDBCDCItem[K any] interface {
    19  	comparable
    20  	ParseCDCKey(keyFields []json.RawMessage) (K, error)
    21  	SetPrimaryKey(key K)
    22  }
    23  
    24  // YDBCDCMessage is typed representation of cdc event
    25  //
    26  // Experimental: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#experimental
    27  type YDBCDCMessage[T YDBCDCItem[Key], Key any] struct {
    28  	Update   T
    29  	NewImage T
    30  	OldImage T
    31  	Key      Key
    32  	Erase    *struct{}
    33  	TS       []uint64
    34  }
    35  
    36  // IsErase returns true if the event about erase record
    37  func (c *YDBCDCMessage[T, Key]) IsErase() bool {
    38  	return c.Erase != nil
    39  }
    40  
    41  func (c *YDBCDCMessage[T, Key]) UnmarshalJSON(bytes []byte) error {
    42  	var rawItem struct {
    43  		Update   T                 `json:"update"`
    44  		NewImage T                 `json:"newImage"`
    45  		OldImage T                 `json:"oldImage"`
    46  		Key      []json.RawMessage `json:"key"`
    47  		Erase    *struct{}         `json:"erase"`
    48  		TS       []uint64          `json:"ts"`
    49  	}
    50  
    51  	err := json.Unmarshal(bytes, &rawItem)
    52  	if err != nil {
    53  		return fmt.Errorf("failed to unmarshal cdcevent for type %T: %w", c, err)
    54  	}
    55  
    56  	var tZero T
    57  	key, err := tZero.ParseCDCKey(rawItem.Key)
    58  	if err != nil {
    59  		return fmt.Errorf("failed to unmarshal cdcevent key for type %T: %w", c, err)
    60  	}
    61  
    62  	c.Update = rawItem.Update
    63  	c.NewImage = rawItem.NewImage
    64  	c.OldImage = rawItem.OldImage
    65  	c.Key = key
    66  	c.Erase = rawItem.Erase
    67  	c.TS = rawItem.TS
    68  
    69  	if c.Update != tZero {
    70  		c.Update.SetPrimaryKey(key)
    71  	}
    72  	if c.OldImage != tZero {
    73  		c.OldImage.SetPrimaryKey(key)
    74  	}
    75  	if c.NewImage != tZero {
    76  		c.NewImage.SetPrimaryKey(key)
    77  	}
    78  
    79  	return nil
    80  }
    81  
    82  func UnmarshalCDCStream[T YDBCDCItem[K], K any](
    83  	ctx context.Context,
    84  	reader TopicMessageReader,
    85  ) xiter.Seq2[*TypedTopicMessage[YDBCDCMessage[T, K]], error] {
    86  	var unmarshal TypedUnmarshalFunc[*YDBCDCMessage[T, K]] = func(data []byte, dst *YDBCDCMessage[T, K]) error {
    87  		return json.Unmarshal(data, dst)
    88  	}
    89  
    90  	return IteratorFunc[YDBCDCMessage[T, K]](ctx, reader, unmarshal)
    91  }