All checks were successful
CI / build (pull_request) Successful in 15s
- Add Metadata field (map[string]string) to Event struct with omitempty - Add helper methods for common metadata: SetCorrelationID/GetCorrelationID, SetCausationID/GetCausationID, SetUserID/GetUserID, SetTraceID/GetTraceID, SetSpanID/GetSpanID - Add WithMetadataFrom helper for copying metadata between events - Add metadata key constants for standard fields - Add comprehensive unit tests for metadata serialization and helpers - Add store tests verifying metadata persistence Closes #7 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
133 lines
4.0 KiB
Go
133 lines
4.0 KiB
Go
package aether
|
|
|
|
import (
|
|
"time"
|
|
)
|
|
|
|
// Event represents a domain event in the system
|
|
type Event struct {
|
|
ID string `json:"id"`
|
|
EventType string `json:"eventType"`
|
|
ActorID string `json:"actorId"`
|
|
CommandID string `json:"commandId,omitempty"` // Correlation ID for command that triggered this event
|
|
Version int64 `json:"version"`
|
|
Data map[string]interface{} `json:"data"`
|
|
Metadata map[string]string `json:"metadata,omitempty"` // Optional metadata for tracing and auditing
|
|
Timestamp time.Time `json:"timestamp"`
|
|
}
|
|
|
|
// Common metadata keys for distributed tracing and auditing
|
|
const (
|
|
// MetadataKeyCorrelationID identifies related events across services
|
|
MetadataKeyCorrelationID = "correlationId"
|
|
// MetadataKeyCausationID identifies the event that caused this event
|
|
MetadataKeyCausationID = "causationId"
|
|
// MetadataKeyUserID identifies the user who triggered this event
|
|
MetadataKeyUserID = "userId"
|
|
// MetadataKeyTraceID for distributed tracing integration (e.g., OpenTelemetry)
|
|
MetadataKeyTraceID = "traceId"
|
|
// MetadataKeySpanID for distributed tracing integration
|
|
MetadataKeySpanID = "spanId"
|
|
)
|
|
|
|
// SetMetadata sets a metadata key-value pair, initializing the map if needed
|
|
func (e *Event) SetMetadata(key, value string) {
|
|
if e.Metadata == nil {
|
|
e.Metadata = make(map[string]string)
|
|
}
|
|
e.Metadata[key] = value
|
|
}
|
|
|
|
// GetMetadata returns the value for a metadata key, or empty string if not found
|
|
func (e *Event) GetMetadata(key string) string {
|
|
if e.Metadata == nil {
|
|
return ""
|
|
}
|
|
return e.Metadata[key]
|
|
}
|
|
|
|
// SetCorrelationID sets the correlation ID metadata
|
|
func (e *Event) SetCorrelationID(correlationID string) {
|
|
e.SetMetadata(MetadataKeyCorrelationID, correlationID)
|
|
}
|
|
|
|
// GetCorrelationID returns the correlation ID metadata
|
|
func (e *Event) GetCorrelationID() string {
|
|
return e.GetMetadata(MetadataKeyCorrelationID)
|
|
}
|
|
|
|
// SetCausationID sets the causation ID metadata
|
|
func (e *Event) SetCausationID(causationID string) {
|
|
e.SetMetadata(MetadataKeyCausationID, causationID)
|
|
}
|
|
|
|
// GetCausationID returns the causation ID metadata
|
|
func (e *Event) GetCausationID() string {
|
|
return e.GetMetadata(MetadataKeyCausationID)
|
|
}
|
|
|
|
// SetUserID sets the user ID metadata
|
|
func (e *Event) SetUserID(userID string) {
|
|
e.SetMetadata(MetadataKeyUserID, userID)
|
|
}
|
|
|
|
// GetUserID returns the user ID metadata
|
|
func (e *Event) GetUserID() string {
|
|
return e.GetMetadata(MetadataKeyUserID)
|
|
}
|
|
|
|
// SetTraceID sets the trace ID metadata for distributed tracing
|
|
func (e *Event) SetTraceID(traceID string) {
|
|
e.SetMetadata(MetadataKeyTraceID, traceID)
|
|
}
|
|
|
|
// GetTraceID returns the trace ID metadata
|
|
func (e *Event) GetTraceID() string {
|
|
return e.GetMetadata(MetadataKeyTraceID)
|
|
}
|
|
|
|
// SetSpanID sets the span ID metadata for distributed tracing
|
|
func (e *Event) SetSpanID(spanID string) {
|
|
e.SetMetadata(MetadataKeySpanID, spanID)
|
|
}
|
|
|
|
// GetSpanID returns the span ID metadata
|
|
func (e *Event) GetSpanID() string {
|
|
return e.GetMetadata(MetadataKeySpanID)
|
|
}
|
|
|
|
// WithMetadataFrom copies metadata from another event (useful for event chaining)
|
|
func (e *Event) WithMetadataFrom(source *Event) {
|
|
if source == nil || source.Metadata == nil {
|
|
return
|
|
}
|
|
if e.Metadata == nil {
|
|
e.Metadata = make(map[string]string)
|
|
}
|
|
for k, v := range source.Metadata {
|
|
e.Metadata[k] = v
|
|
}
|
|
}
|
|
|
|
// ActorSnapshot represents a point-in-time state snapshot
|
|
type ActorSnapshot struct {
|
|
ActorID string `json:"actorId"`
|
|
Version int64 `json:"version"`
|
|
State map[string]interface{} `json:"state"`
|
|
Timestamp time.Time `json:"timestamp"`
|
|
}
|
|
|
|
// EventStore defines the interface for event persistence
|
|
type EventStore interface {
|
|
SaveEvent(event *Event) error
|
|
GetEvents(actorID string, fromVersion int64) ([]*Event, error)
|
|
GetLatestVersion(actorID string) (int64, error)
|
|
}
|
|
|
|
// SnapshotStore extends EventStore with snapshot capabilities
|
|
type SnapshotStore interface {
|
|
EventStore
|
|
GetLatestSnapshot(actorID string) (*ActorSnapshot, error)
|
|
SaveSnapshot(snapshot *ActorSnapshot) error
|
|
}
|