-
Notifications
You must be signed in to change notification settings - Fork 13
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow to marshal slices #16
Comments
Hi! I might add support for slices soon (as it's requested now), but the simplest workaround for you would be using the Thanks for reporting 🙂 |
I'm not sure if this works. Here's an example: package main
import (
"context"
"encoding/json"
"fmt"
"log"
"github.com/dranikpg/gtrs"
"github.com/redis/go-redis/v9"
)
type Data struct {
Items []Item `json:"items"`
}
type Item struct {
Name string `json:"name"`
}
func (d *Data) ToMap() (m map[string]any, e error) {
data, err := json.Marshal(d)
if err != nil {
return nil, fmt.Errorf("marsal struct to json: %w", err)
}
if err = json.Unmarshal(data, &m); err != nil {
return nil, fmt.Errorf("marsal json to map: %w", err)
}
return m, nil
}
func (d *Data) FromMap(m map[string]any) error {
data, err := json.Marshal(m)
if err != nil {
return fmt.Errorf("marsal map to json: %w", err)
}
if err = json.Unmarshal(data, &d); err != nil {
return fmt.Errorf("marsal json to struct: %w", err)
}
return nil
}
func main() {
client := redis.NewClient(&redis.Options{
Addr: "0.0.0.0:7777",
Password: "sider",
DB: 0,
})
stream := gtrs.NewStream[Data](
client, "main", >rs.Options{},
)
_, err := stream.Add(
context.Background(),
Data{
Items: []Item{
{Name: "a"},
{Name: "b"},
{Name: "c"},
},
},
)
if err != nil {
log.Fatal(err)
}
} It produces:
Why does it require implementing another marshaler if This kinda works, but it doesn't need package main
import (
"context"
"encoding/json"
"fmt"
"log"
"github.com/dranikpg/gtrs"
"github.com/redis/go-redis/v9"
)
type Items []Item
type Data struct {
Items Items `json:"items"`
}
type Item struct {
Name string `json:"name"`
}
func (d *Data) ToMap() (m map[string]any, e error) {
data, err := json.Marshal(d)
if err != nil {
return nil, fmt.Errorf("marsal struct to json: %w", err)
}
if err = json.Unmarshal(data, &m); err != nil {
return nil, fmt.Errorf("marsal json to map: %w", err)
}
return m, nil
}
func (d *Data) FromMap(m map[string]any) error {
data, err := json.Marshal(m)
if err != nil {
return fmt.Errorf("marsal map to json: %w", err)
}
if err = json.Unmarshal(data, &d); err != nil {
return fmt.Errorf("marsal json to struct: %w", err)
}
return nil
}
func (i Items) MarshalBinary() ([]byte, error) {
return json.Marshal(i)
}
func main() {
client := redis.NewClient(&redis.Options{
Addr: "0.0.0.0:7777",
Password: "sider",
DB: 0,
})
stream := gtrs.NewStream[Data](
client, "main", >rs.Options{},
)
_, err := stream.Add(
context.Background(),
Data{
Items: []Item{
{Name: "a"},
{Name: "b"},
{Name: "c"},
},
},
)
if err != nil {
log.Fatal(err)
}
} |
Also, looks like you can't unmarshal slice back after consuming:
package main
import (
"context"
"encoding/json"
"log"
"github.com/dranikpg/gtrs"
"github.com/redis/go-redis/v9"
)
type Items []Item
type Data struct {
Items Items `json:"items"`
}
type Item struct {
Name string `json:"name"`
}
func (i Items) UnmarshalBinary(data []byte) error {
return json.Unmarshal(data, &i)
}
func main() {
client := redis.NewClient(&redis.Options{
Addr: "0.0.0.0:7777",
Password: "sider",
DB: 0,
})
stream := gtrs.NewConsumer[Data](
context.Background(), client,
gtrs.StreamIDs{"main": "0-0"},
)
defer stream.Close()
log.Println("consuming")
for msg := range stream.Chan() {
switch v := msg.Err.(type) {
case gtrs.AckError:
log.Println("fail to ack stream:", msg.Stream, msg.ID)
continue
case gtrs.ParseError:
log.Println("fail to parse stream:", v.Data, msg.Err)
continue
case gtrs.ReadError:
log.Println("fail to read stream:", msg.Err)
return
case nil:
for _, item := range msg.Data.Items {
log.Println("item:", item.Name)
}
log.Println()
}
}
} Producer: package main
import (
"context"
"encoding/json"
"log"
"github.com/dranikpg/gtrs"
"github.com/redis/go-redis/v9"
)
type Items []Item
type Data struct {
Items Items `json:"items"`
}
type Item struct {
Name string `json:"name"`
}
func (i Items) MarshalBinary() ([]byte, error) {
return json.Marshal(i)
}
func main() {
client := redis.NewClient(&redis.Options{
Addr: "0.0.0.0:7777",
Password: "sider",
DB: 0,
})
stream := gtrs.NewStream[Data](
client, "main", >rs.Options{},
)
_, err := stream.Add(
context.Background(),
Data{
Items: []Item{
{Name: "a"},
{Name: "b"},
{Name: "c"},
},
},
)
if err != nil {
log.Fatal(err)
}
} |
This is not a solution for this case: func (i Items) MarshalBinary() ([]byte, error) {
return json.Marshal(i)
} It will result to escaped nested arrays, therefore they cannot be parsed through
It could work if the consumer output called the
|
Please confirm my observations: redis (and streams too) does not support nested objects and they have to be escaped into strings and folded into each other, and then expanded back. As far as I understand, this process was done for structures in the library, but not for slices, right? |
So the simple answer (or more like my thoughts when I implemented it): When I implemented it, I saw Convertible just as a way to manipulate the key/value pairs at the highest level. All values are passed on to the redis client, as it's technically not the libraries job to handle complex serialization. Not a feature that was promised 😄
Yes, I agree that's a problem, because for serialization it happens automatically - here not. The only way currently is to do it with Convertible -> unnecessary boilerplate I see that #17 adds this functionality, so we can actually incorporate it |
@dranikpg mind pushing a new release and we can close this i think ? |
Closed as with https://github.com/dranikpg/gtrs/releases/tag/v0.6.0 |
Problem
An event cannot be made a slice or thrown anywhere in the structure.
On slice instead of structure:
panic: reflect: call of reflect.Value.NumField on slice Value
On slice field inside structure even if it has BinaryMarshal:
read error: redis: can't marshal []struct (implement encoding.BinaryMarshaler)
The text was updated successfully, but these errors were encountered: