{"id":20102562,"url":"https://github.com/entrlcom/go-event-sourcing","last_synced_at":"2025-08-03T17:35:37.711Z","repository":{"id":254678848,"uuid":"836613150","full_name":"entrlcom/go-event-sourcing","owner":"entrlcom","description":"Event Sourcing in Go/Golang","archived":false,"fork":false,"pushed_at":"2024-09-01T08:05:45.000Z","size":19,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-01-13T04:29:30.495Z","etag":null,"topics":["cqrs","ddd","esdb","event-driven","event-sourcing","eventstore","eventstoredb","go","go-lib","go-library","golang","golang-lib","golang-library"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/entrlcom.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-08-01T08:03:48.000Z","updated_at":"2024-09-03T08:22:31.000Z","dependencies_parsed_at":"2024-11-13T17:35:47.146Z","dependency_job_id":"2be4fc93-6518-44a0-9974-c2a843474c79","html_url":"https://github.com/entrlcom/go-event-sourcing","commit_stats":null,"previous_names":["entrlcom/go-event-sourcing"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/entrlcom%2Fgo-event-sourcing","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/entrlcom%2Fgo-event-sourcing/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/entrlcom%2Fgo-event-sourcing/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/entrlcom%2Fgo-event-sourcing/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/entrlcom","download_url":"https://codeload.github.com/entrlcom/go-event-sourcing/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":241542132,"owners_count":19979258,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cqrs","ddd","esdb","event-driven","event-sourcing","eventstore","eventstoredb","go","go-lib","go-library","golang","golang-lib","golang-library"],"created_at":"2024-11-13T17:31:46.245Z","updated_at":"2025-03-02T17:21:02.999Z","avatar_url":"https://github.com/entrlcom.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Event Sourcing\n\n## Table of Content\n\n- [Examples](#examples)\n- [License](#license)\n\n## Examples\n\n```go\npackage main\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"time\"\n\n\t\"github.com/EventStore/EventStore-Client-Go/v4/esdb\"\n\t\"github.com/google/uuid\"\n\n\taggregate_model \"entrlcom.dev/event-sourcing/domain/model/aggregate\"\n\taggregate_id_model \"entrlcom.dev/event-sourcing/domain/model/aggregate/id\"\n\tevent_model \"entrlcom.dev/event-sourcing/domain/model/event\"\n\teventstore_repository \"entrlcom.dev/event-sourcing/infra/repository/aggregate/eventstore\"\n)\n\nfunc main() {\n\tctx := context.Background()\n\n\t// EventStore configuration.\n\teventStoreDBConfiguration, err := esdb.ParseConnectionString(\"esdb://localhost:2113/?tls=false\")\n\tif err != nil {\n\t\treturn\n\t}\n\t\n\t// EventStore client.\n\teventStoreDBClient, err := esdb.NewClient(eventStoreDBConfiguration)\n\tif err != nil {\n\t\treturn\n\t}\n\n\t// Repository.\n\trepository := eventstore_repository.NewEventStoreAggregateRepository(*eventStoreDBClient)\n\n\t// New account (aggregate).\n\taccount, err := NewAccount(NewAccountID())\n\tif err != nil {\n\t\treturn\n\t}\n\n\t// Load account (aggregate).\n\tif err = repository.Load(ctx, account._aggregate); err != nil {\n\t\tif !errors.Is(err, aggregate_model.ErrAggregateNotFound) {\n\t\t\treturn\n\t\t}\n\t}\n\n\tif err = account.ChangeName(\"A\"); err != nil {\n\t\treturn\n\t}\n\n\tif err = account.ChangeName(\"B\"); err != nil {\n\t\treturn\n\t}\n\n\t// Save account (aggregate).\n\tif err = repository.Save(ctx, account._aggregate); err != nil {\n\t\treturn\n\t}\n\n\tif err = account.ChangeName(\"C\"); err != nil {\n\t\treturn\n\t}\n\n\tif err = account.ChangeName(\"D\"); err != nil {\n\t\treturn\n\t}\n\n\t// Save account (aggregate).\n\tif err = repository.Save(ctx, account._aggregate); err != nil {\n\t\treturn\n\t}\n}\n\nvar ErrInvalidAccount = errors.New(\"invalid account\")\n\nconst AggregateType = \"Account\"\n\ntype Account struct {\n\t_aggregate *aggregate_model.BaseAggregate\n\n\tid   AccountID\n\tname string\n}\n\nfunc (x *Account) ChangeName(name string) error {\n\tevent := NewAccountNameChangedEvent(x.id.String(), name)\n\n\tdata, _ := json.Marshal(event)\n\n\te, err := event_model.NewBaseEvent(\n\t\tAccountNameChangedEventType,\n\t\tevent_model.WithAggregate(\n\t\t\tx._aggregate.GetID(),\n\t\t\tx._aggregate.GetType(),\n\t\t\tx._aggregate.GetVersion(),\n\t\t),\n\t\tevent_model.WithData(data),\n\t)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif err = x._aggregate.ApplyEvent(\u0026e); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc NewAccount(id AccountID) (*Account, error) {\n\tx := Account{\n\t\t_aggregate: nil,\n\t\tid:         id,\n\t\tname:       \"\",\n\t}\n\n\taggregateID, err := aggregate_id_model.NewAggregateIDFromString(id.String())\n\tif err != nil {\n\t\treturn nil, errors.Join(err, ErrInvalidAccount)\n\t}\n\n\taggregate, err := aggregate_model.NewBaseAggregate(\n\t\taggregateID,\n\t\tAggregateType,\n\t\taggregate_model.WithWhen(func(event event_model.Event) error {\n\t\t\tswitch event.GetType() {\n\t\t\tcase AccountNameChangedEventType:\n\t\t\t\tvar data AccountNameChangedEvent\n\n\t\t\t\tif err = json.Unmarshal(event.GetData(), \u0026data); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\n\t\t\t\tx.name = data.Name\n\n\t\t\t\treturn nil\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}),\n\t)\n\tif err != nil {\n\t\treturn nil, errors.Join(err, ErrInvalidAccount)\n\t}\n\n\tx._aggregate = \u0026aggregate\n\n\treturn \u0026x, nil\n}\n\nvar ErrInvalidAccountID = errors.New(\"invalid account id\")\n\ntype AccountID string\n\nfunc (x AccountID) IsEqualTo(accountID AccountID) bool {\n\treturn x == accountID\n}\n\nfunc (x AccountID) String() string {\n\treturn string(x)\n}\n\nfunc (x AccountID) Validate() error {\n\tv, err := uuid.Parse(string(x))\n\tif err != nil || v.Variant() != uuid.RFC4122 || v.Version() != 7 {\n\t\treturn ErrInvalidAccountID\n\t}\n\n\treturn nil\n}\n\nfunc NewAccountID() AccountID {\n\treturn AccountID(uuid.Must(uuid.NewV7()).String())\n}\n\nconst AccountNameChangedEventType = \"AccountNameChanged\"\n\ntype AccountNameChangedEvent struct {\n\tAccountID string `json:\"account_id,omitempty\"`\n\tName      string `json:\"name,omitempty\"`\n}\n\nfunc NewAccountNameChangedEvent(accountID, name string) AccountNameChangedEvent {\n\treturn AccountNameChangedEvent{\n\t\tAccountID: accountID,\n\t\tName:      name,\n\t}\n}\n\n```\n\n## License\n\n[MIT](https://choosealicense.com/licenses/mit/)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fentrlcom%2Fgo-event-sourcing","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fentrlcom%2Fgo-event-sourcing","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fentrlcom%2Fgo-event-sourcing/lists"}