EventStore / EventStore-Client-Go

Go Client for Event Store version 20 and above.
Apache License 2.0
105 stars 27 forks source link

bug: AppendEvents does not persist Metadata if more than one event is provided. #174

Closed seanppayne closed 6 months ago

seanppayne commented 7 months ago

I make the following function call in my codebase

_, err = e.client.AppendToStream(
    ctx,
    streamID,
    appendOptions,
    esdbEvents...,
)

When esdbEvents contains more than one event, anything I put in the metadata field of the EventData is not persisted to the DB (not visible in UI, not accessible when reading stream).

When esdbEvents contains only one event, the metadata is persisted as expected.

My metadata

metadata := UserMetadata{
    CausedBy:  event.UUID().String(),
    ReceiptNo: event.ReceiptNumber(),
    ReqId:     event.RequestId(),
    TermId:    event.TerminalId(),
    DealNo:    event.DealNumber(),
}

I am wondering is this a bug or is this intended behavior?

YoEight commented 7 months ago

Hey @seanppayne ,

I need you to share exactly how you wrote your metadata. I don't need to see the data of course but I need to ascertain you use the API correctly first.

seanppayne commented 7 months ago

Sure thing, I create the events/metadata as follows:

metadata := UserMetadata{
    CausedBy:  event.UUID().String(),
    ReceiptNo: event.ReceiptNumber(),
    ReqId:     event.RequestId(),
    TermId:    event.TerminalId(),
    DealNo:    event.DealNumber(),
}

metadataBytes, err := json.Marshal(metadata)

if err != nil {
    return esdbEvents, fmt.Errorf("error occurred while marshalling metadata EventType: %s Err: %v", event.EventType(), err)
}

esdbEvents[i] = esdb.EventData{
    ContentType: esdb.ContentTypeJson,
    EventType:   event.EventType(),
    Data:        eventBytes,
    EventID:     event.UUID(),
    Metadata:    metadataBytes,
}
YoEight commented 7 months ago

You confirm that all the events you write have their metadata set to UserMetada of yours?

seanppayne commented 7 months ago

@YoEight Yes, here is a screenshot. This is when only one event is provided. If there is more than one event these fields do not show up.

Screenshot 2024-04-18 at 14 40 25
YoEight commented 7 months ago

Hey @seanppayne,

I wrote an unit test to try to reproduce your issue. Unfortunately, it's still working as expected:

func eventMetadataOperation(db *esdb.Client) TestCall {
    return func(t *testing.T) {
        streamID := NAME_GENERATOR.Generate()
        ctx, cancel := context.WithTimeout(context.Background(), time.Duration(5)*time.Second)
        defer cancel()

        var events []esdb.EventData

        type data struct {
            Baz int
        }

        type meta struct {
            Zaz int
        }

        for i := 0; i < 3; i++ {
            data, _ := json.Marshal(data{
                Baz: i,
            })

            meta, _ := json.Marshal(meta{
                Zaz: i,
            })

            events = append(events, esdb.EventData{
                EventID:     uuid.New(),
                EventType:   "event-tested",
                ContentType: esdb.ContentTypeJson,
                Data:        data,
                Metadata:    meta,
            })
        }

        _, err := db.AppendToStream(ctx, streamID, esdb.AppendToStreamOptions{}, events...)
        assert.Nil(t, err)

        ctx, cancel = context.WithTimeout(context.Background(), time.Duration(5)*time.Second)
        defer cancel()

        stream, err := db.ReadStream(ctx, streamID, esdb.ReadStreamOptions{
            From:      esdb.Start{},
            Direction: esdb.Forwards,
        }, 128)

        defer stream.Close()

        assert.Nil(t, err)

        for i := 0; i < 3; i++ {
            event, err := stream.Recv()
            assert.Nil(t, err)

            var data data
            err = json.Unmarshal(event.OriginalEvent().Data, &data)
            assert.Nil(t, err)

            var meta meta
            err = json.Unmarshal(event.OriginalEvent().UserMetadata, &meta)
            assert.Nil(t, err)

            assert.Equal(t, i, data.Baz)
            assert.Equal(t, i, meta.Zaz)
        }
    }

Is that snippet close to your code? If not, could you tell me what should I change?

seanppayne commented 6 months ago

@YoEight I apologize for the delayed response, but I was unable to reproduce the behavior after returning to this, so I am not sure what happened. I have to chalk it up to user error on my part.

Thank you for taking the time to write this test.