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 }