{"id":13776704,"url":"https://github.com/elixir-toniq/maestro","last_synced_at":"2025-07-13T19:07:11.392Z","repository":{"id":57519113,"uuid":"106709130","full_name":"elixir-toniq/maestro","owner":"elixir-toniq","description":"an event store + cqrs","archived":false,"fork":false,"pushed_at":"2021-07-22T21:18:39.000Z","size":173,"stargazers_count":118,"open_issues_count":6,"forks_count":4,"subscribers_count":10,"default_branch":"master","last_synced_at":"2025-07-03T18:10:46.432Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Elixir","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/elixir-toniq.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}},"created_at":"2017-10-12T15:12:38.000Z","updated_at":"2025-06-13T19:34:54.000Z","dependencies_parsed_at":"2022-09-06T05:10:25.649Z","dependency_job_id":null,"html_url":"https://github.com/elixir-toniq/maestro","commit_stats":null,"previous_names":["toniqsystems/maestro"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/elixir-toniq/maestro","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elixir-toniq%2Fmaestro","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elixir-toniq%2Fmaestro/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elixir-toniq%2Fmaestro/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elixir-toniq%2Fmaestro/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/elixir-toniq","download_url":"https://codeload.github.com/elixir-toniq/maestro/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elixir-toniq%2Fmaestro/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":265191065,"owners_count":23725252,"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":[],"created_at":"2024-08-03T18:00:31.814Z","updated_at":"2025-07-13T19:07:11.365Z","avatar_url":"https://github.com/elixir-toniq.png","language":"Elixir","funding_links":[],"categories":["Libraries","Elixir"],"sub_categories":[],"readme":"# Maestro\n\nMaestro is an event sourcing _library_. It is inspired by CQRS and re-uses\nterminology where appropriate. The divergence from being a CQRS framework is\nintentional as Maestro focuses on processing commands in a consistent manner and\nreplaying events in a consistent order.\n\nCurrently, the only storage adapter suited to a multi-node environment is the\n`Maestro.Store.Postgres` adapter. The `Maestro.Store.InMemory` adapter exists\nfor testing purposes only.\n\n## Status\n[![Hex](http://img.shields.io/hexpm/v/maestro.svg?style=flat)](https://hex.pm/packages/maestro)\n[![Build Status](https://travis-ci.org/toniqsystems/maestro.svg?branch=master)](https://travis-ci.org/toniqsystems/maestro)\n[![Coverage](https://coveralls.io/repos/github/toniqsystems/maestro/badge.svg)](https://coveralls.io/github/toniqsystems/maestro)\n\nDocumentation is available [here](https://hexdocs.pm/maestro/).\n\n## Installation\n\n```elixir\ndef deps do\n  [{:maestro, \"~\u003e 0.2\"}]\nend\n```\n\n## Database Configuration\n\nMaestro is intended to be used alongside an existing database/ecto repo.\n\n```elixir\nconfig :maestro,\n  storage_adapter: Maestro.Store.Postgres,\n  repo: MyApp.Repo\n```\n\nTo generate the migrations for the snapshot and event logs, do:\n\n```bash\nmix maestro.create.event_store_migration\n```\n\n## Example\n\nThere are three behaviours that make the command/event lifecycle flow:\n`Maestro.Aggregate.CommandHandler`, `Maestro.Aggregate.EventHandler`, and\n`Maestro.Aggregate.ProjectionHandler`. Modules implementing the command and\nevent handler behaviours are looked up via a configurable `:command_prefix` and\n`:event_prefix` respectively. Projections are reserved for maintaining other\nmodels/representations within the event's transaction.\n\n```elixir\ndefmodule MyApp.Aggregate do\n  use Maestro.Aggregate.Root,\n    command_prefix: MyApp.Aggregate.Commands,\n    event_prefix: MyApp.Aggregate.Events\n\n  def initial_state, do: %{\"value\" =\u003e 0}\n\n  def prepare_snapshot(state), do: state\n\n  def use_snapshot(_curr, %Maestro.Types.Snapshot{body: state}), do: state\nend\n\ndefmodule MyApp.Aggregate.Commands.IncrementCounter do\n\n  @behaviour Maestro.Aggregate.CommandHandler\n\n  alias Maestro.Types.Event\n\n  def eval(aggregate, _command) do\n    [\n      %Event{\n        aggregate_id: aggregate.id,\n        type: \"counter_incremented\",\n        body: %{}\n      }\n    ]\n  end\nend\n\ndefmodule MyApp.Aggregate.Events.CounterIncremented do\n\n  @behaviour Maestro.Aggregate.EventHandler\n\n  def apply(state, _event), do: Map.update!(state, \"value\", \u0026(\u00261 + 1))\nend\n```\n\n```elixir\niex(1)\u003e {:ok, id} = MyApp.Aggregate.new()\niex(2)\u003e :ok = MyApp.Aggregate.evaluate(%Maestro.Types.Command{aggregate_id: id, type: \"increment_counter\", data: %{}})\niex(3)\u003e {:ok, %{\"value\" =\u003e 1}} = MyApp.Aggregate.get(id)\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Felixir-toniq%2Fmaestro","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Felixir-toniq%2Fmaestro","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Felixir-toniq%2Fmaestro/lists"}