Getting Started

Getting Started

Estoria requires Go >=1.25.

go get github.com/go-estoria/estoria

The core Estoria components only depend on the Go standard library and github.com/gofrs/uuid/v5 for UUID support. Vendor-specific components are imported separately as needed from estoria-contrib.

Quickstart

Run all of the code below in a Go playground. See other full runnable examples in estoria-examples.

Entities

Entities must implement estoria.Entity and provide a factory function:

type User struct {
	ID   uuid.UUID
	Name string
}

func (a User) EntityID() typeid.ID { return typeid.New("user", a.ID) }

func NewUser(id uuid.UUID) User {
	return User{ID: id, Name: "Unknown"}
}

Events

Events must implement estoria.EntityEvent:

type UserNameChanged struct {
	NewName string
}

func (UserNameChanged) EventType() string { return "namechanged" }

func (UserNameChanged) New() estoria.EntityEvent[User] {
	return &UserNameChanged{NewName: "Unknown User"}
}

func (e UserNameChanged) ApplyTo(_ context.Context, user User) (User, error) {
	user.Name = e.NewName
	return user, nil
}

Aggregates

Create an event store to store events:

eventStore, _ := memory.NewEventStore()

Then, create an aggregate store using the event store, your entity factory function, and your event types:

aggregateStore, _ := aggregatestore.New(eventStore, NewUser,
    aggregatestore.WithEventTypes(
        UserNameChanged{},
    ),
)

Now you can begin working with aggregates in your application:

userID := uuid.Must(uuid.NewV4())

// create a new User aggregate
newUser := aggregateStore.New(userID, 0)

// append an event
_ = newUser.Append(UserNameChanged{NewName: "Juliette"})

// save the aggregate
_ = aggregateStore.Save(ctx, newUser, nil)

// load the aggregate
loadedUser, _ := aggregateStore.Load(ctx, userID, nil)

// access the aggregate root
user := loadedUser.Entity()