Skip to content

Commit 922ff70

Browse files
[CHA-1633] - Fix ExtraData double-nesting behavior (#362)
* fix ExtraData double-nesting behavior * fixing test * bump major version * bumped go version
1 parent d00843e commit 922ff70

File tree

15 files changed

+101
-14
lines changed

15 files changed

+101
-14
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ jobs:
1717
max-parallel: 3
1818
fail-fast: false
1919
matrix:
20-
goVer: ['1.22', '1.23', '1.24']
20+
goVer: ['1.23', '1.24', '1.25']
2121
steps:
2222
- uses: actions/checkout@v4
2323

.github/workflows/lint.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ jobs:
1919
- name: Setup Go
2020
uses: actions/setup-go@v5
2121
with:
22-
go-version: "1.22"
22+
go-version: "1.25"
2323

2424
- name: Tidy
2525
run: go mod tidy -v && git diff --no-patch --exit-code || { git status; echo 'Unchecked diff, did you forget go mod tidy again?' ; false ; };

.github/workflows/reviewdog.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ jobs:
2020
- name: Setup Go
2121
uses: actions/setup-go@v5
2222
with:
23-
go-version: '1.22'
23+
go-version: '1.25'
2424

2525
- name: Install golangci-lint
2626
run: make install-golangci

.github/workflows/scheduled_test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ jobs:
1414

1515
- uses: actions/setup-go@v3
1616
with:
17-
go-version: "1.22"
17+
go-version: "1.25"
1818

1919
- name: Run tests
2020
env:

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Official Go SDK for [Stream Chat](https://getstream.io/chat/)
22

33
[![build](https://github.com/GetStream/stream-chat-go/workflows/build/badge.svg)](https://github.com/GetStream/stream-chat-go/actions)
4-
[![godoc](https://pkg.go.dev/badge/GetStream/stream-chat-go)](https://pkg.go.dev/github.com/GetStream/stream-chat-go/v7?tab=doc)
4+
[![godoc](https://pkg.go.dev/badge/GetStream/stream-chat-go)](https://pkg.go.dev/github.com/GetStream/stream-chat-go/v8?tab=doc)
55

66
<p align="center">
77
<img src="./assets/logo.svg" width="50%" height="50%">
@@ -28,7 +28,7 @@ For the client-side integrations (web and mobile) have a look at the JavaScript,
2828
## ⚙️ Installation
2929

3030
```shell
31-
go get github.com/GetStream/stream-chat-go/v7
31+
go get github.com/GetStream/stream-chat-go/v8
3232
```
3333

3434
## ✨ Getting started
@@ -39,7 +39,7 @@ package main
3939
import (
4040
"os"
4141

42-
stream "github.com/GetStream/stream-chat-go/v7"
42+
stream "github.com/GetStream/stream-chat-go/v8"
4343
)
4444

4545
var APIKey = os.Getenv("STREAM_KEY")

channel.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ func (m *ChannelMember) UnmarshalJSON(data []byte) error {
7070
}
7171

7272
removeFromMap(m.ExtraData, *m)
73+
flattenExtraData(m.ExtraData)
7374
return nil
7475
}
7576

@@ -144,6 +145,7 @@ func (ch *Channel) UnmarshalJSON(data []byte) error {
144145
}
145146

146147
removeFromMap(ch.ExtraData, *ch)
148+
flattenExtraData(ch.ExtraData)
147149
return nil
148150
}
149151

@@ -191,6 +193,7 @@ func (c *ChannelRequest) UnmarshalJSON(data []byte) error {
191193
}
192194

193195
removeFromMap(c.ExtraData, *c)
196+
flattenExtraData(c.ExtraData)
194197
return nil
195198
}
196199

event.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ func (e *Event) UnmarshalJSON(data []byte) error {
108108
}
109109

110110
removeFromMap(e.ExtraData, *e)
111+
flattenExtraData(e.ExtraData)
111112
return nil
112113
}
113114

@@ -161,6 +162,7 @@ func (e *UserCustomEvent) UnmarshalJSON(data []byte) error {
161162
}
162163

163164
removeFromMap(e.ExtraData, *e)
165+
flattenExtraData(e.ExtraData)
164166
return nil
165167
}
166168

go.mod

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
module github.com/GetStream/stream-chat-go/v7
1+
module github.com/GetStream/stream-chat-go/v8
22

3-
go 1.22
3+
go 1.23
44

55
require (
66
github.com/golang-jwt/jwt/v4 v4.5.1

json.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,22 @@ func removeFromMap(m map[string]interface{}, obj interface{}) {
2727
}
2828
}
2929

30+
// flattenExtraData flattens the nested "extra_data" key if it exists.
31+
// The API may return custom fields nested under an "extra_data" key,
32+
// which should be flattened to the root level of the ExtraData map.
33+
func flattenExtraData(m map[string]interface{}) {
34+
if extraData, ok := m["extra_data"]; ok {
35+
if extraDataMap, ok := extraData.(map[string]interface{}); ok {
36+
// Copy all fields from nested extra_data to root level
37+
for k, v := range extraDataMap {
38+
m[k] = v
39+
}
40+
// Remove the nested extra_data key
41+
delete(m, "extra_data")
42+
}
43+
}
44+
}
45+
3046
func addToMapAndMarshal(m map[string]interface{}, obj interface{}) ([]byte, error) {
3147
m2 := copyMap(m)
3248

json_test.go

Lines changed: 64 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,8 @@ func randomExtraData(in interface{}) {
1616
}
1717
f := v.FieldByName("ExtraData")
1818
f.Set(reflect.ValueOf(map[string]interface{}{
19-
"extra_data": map[string]interface{}{
20-
"mystring": randomString(10),
21-
"mybool": rand.Float64() < 0.5,
22-
},
19+
"mystring": randomString(10),
20+
"mybool": rand.Float64() < 0.5,
2321
"data": "custom",
2422
"custom_data": "really_custom",
2523
"extra": map[string]interface{}{
@@ -69,3 +67,65 @@ func TestJSON(t *testing.T) {
6967
var r, r2 Reaction
7068
testInvariantJSON(t, &r, &r2)
7169
}
70+
71+
// TestFlattenExtraData tests the flattenExtraData function directly
72+
func TestFlattenExtraData(t *testing.T) {
73+
t.Run("Flatten nested extra_data", func(t *testing.T) {
74+
m := map[string]interface{}{
75+
"field1": "value1",
76+
"extra_data": map[string]interface{}{
77+
"custom_field": "custom_value",
78+
"another_field": 123,
79+
},
80+
}
81+
82+
flattenExtraData(m)
83+
84+
// Fields should be flattened
85+
require.Equal(t, "custom_value", m["custom_field"])
86+
require.Equal(t, 123, m["another_field"])
87+
require.Equal(t, "value1", m["field1"])
88+
// The nested "extra_data" key should not exist
89+
require.NotContains(t, m, "extra_data")
90+
})
91+
92+
t.Run("No extra_data key", func(t *testing.T) {
93+
m := map[string]interface{}{
94+
"field1": "value1",
95+
"field2": 123,
96+
}
97+
98+
flattenExtraData(m)
99+
100+
// Map should be unchanged
101+
require.Equal(t, "value1", m["field1"])
102+
require.Equal(t, 123, m["field2"])
103+
require.Len(t, m, 2)
104+
})
105+
106+
t.Run("extra_data is not a map", func(t *testing.T) {
107+
m := map[string]interface{}{
108+
"field1": "value1",
109+
"extra_data": "not_a_map",
110+
}
111+
112+
flattenExtraData(m)
113+
114+
// extra_data should remain unchanged if it's not a map
115+
require.Equal(t, "not_a_map", m["extra_data"])
116+
require.Equal(t, "value1", m["field1"])
117+
})
118+
119+
t.Run("Empty extra_data map", func(t *testing.T) {
120+
m := map[string]interface{}{
121+
"field1": "value1",
122+
"extra_data": map[string]interface{}{},
123+
}
124+
125+
flattenExtraData(m)
126+
127+
// Empty extra_data should be removed
128+
require.NotContains(t, m, "extra_data")
129+
require.Equal(t, "value1", m["field1"])
130+
})
131+
}

0 commit comments

Comments
 (0)