{"id":21178790,"url":"https://github.com/nfibrokerage/spear","last_synced_at":"2025-04-06T03:09:08.446Z","repository":{"id":38811852,"uuid":"354068815","full_name":"NFIBrokerage/spear","owner":"NFIBrokerage","description":"A sharp EventStoreDB v20+ client backed by Mint :yum:","archived":false,"fork":false,"pushed_at":"2024-08-03T23:46:39.000Z","size":822,"stargazers_count":93,"open_issues_count":5,"forks_count":14,"subscribers_count":11,"default_branch":"main","last_synced_at":"2025-03-30T01:13:14.582Z","etag":null,"topics":["elixir","event-sourcing","eventstoredb","grpc","mint"],"latest_commit_sha":null,"homepage":"https://hex.pm/packages/spear","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/NFIBrokerage.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","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":"2021-04-02T16:07:58.000Z","updated_at":"2025-03-10T00:37:49.000Z","dependencies_parsed_at":"2024-02-06T01:45:36.448Z","dependency_job_id":"2ee29d05-6a5b-4a9a-a17b-2c6555f4904b","html_url":"https://github.com/NFIBrokerage/spear","commit_stats":{"total_commits":258,"total_committers":9,"mean_commits":"28.666666666666668","dds":"0.18604651162790697","last_synced_commit":"e923d074f4132d07df9ba59fcf4ff158590bf0af"},"previous_names":[],"tags_count":31,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NFIBrokerage%2Fspear","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NFIBrokerage%2Fspear/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NFIBrokerage%2Fspear/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NFIBrokerage%2Fspear/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/NFIBrokerage","download_url":"https://codeload.github.com/NFIBrokerage/spear/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247427006,"owners_count":20937201,"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":["elixir","event-sourcing","eventstoredb","grpc","mint"],"created_at":"2024-11-20T17:26:26.252Z","updated_at":"2025-04-06T03:09:08.430Z","avatar_url":"https://github.com/NFIBrokerage.png","language":"Elixir","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Spear\n\n![CI](https://github.com/NFIBrokerage/spear/workflows/CI/badge.svg)\n[![Coverage Status](https://coveralls.io/repos/github/NFIBrokerage/spear/badge.svg)](https://coveralls.io/github/NFIBrokerage/spear)\n[![hex.pm version](https://img.shields.io/hexpm/v/spear.svg)](https://hex.pm/packages/spear)\n[![hex.pm license](https://img.shields.io/hexpm/l/spear.svg)](https://github.com/NFIBrokerage/spear/blob/master/LICENSE)\n[![Last Updated](https://img.shields.io/github/last-commit/NFIBrokerage/spear.svg)](https://github.com/NFIBrokerage/spear/commits/main)\n\nA sharp EventStoreDB 20+ client backed by mint :yum:\n\n## FAQ\n\n**What's EventStoreDB?**\n\n[EventStoreDB](https://www.eventstore.com/) is a database designed for\n[Event Sourcing](https://microservices.io/patterns/data/event-sourcing.html).\nInstead of tables with rows and columns, EventStoreDB stores information in\nimmutable _events_ which are appended to _streams_.\n\n**Why the name \"spear\"?**\n\n1. best gum flavor\n1. obligatory programmer reference to ancient greek, roman, or egyptian history\n1. sounds cool :sunglasses:\n\n**Backed by... Mint?**\n\n[`elixir-mint/mint`](https://github.com/elixir-mint/mint) is a functional\nHTTP client which supports HTTP2.\n\ngRPC is pretty thin protocol built on top of HTTP/2. Practically speaking,\ngRPC just adds some well-known headers and a message format that allows\nmessages to not be aligned with HTTP2 DATA frames.  It's relatively trivial\nto implement gRPC with a nice HTTP2 library like mint :slightly_smiling_face:.\n\n**Why not [`elixir-grpc/grpc`](https://github.com/elixir-grpc/grpc)?**\n\nThat project looks good but it depends on\n[`:gun`](https://github.com/ninenines/gun) which doesn't play nice with\nother dependencies[^1]. It also provides a server and client implementation in\none library. This library only needs a client.\n\n**Does TLS work?**\n\nYep! As of v0.1.3, custom and public CAs may be used for encrypted connections.\n\n**Does this work with EventStore \u003c20?**\n\nSadly no. This library only provides a gRPC client which showed up in\nEventStoreDB 20+. If you're looking for a similarly fashioned TCP client,\nNFIBrokerage uses\n[`exponentially/extreme`](https://github.com/exponentially/extreme) extensively\nin production (specifically the v1.0.0 branch). Spear and Extreme have\ncompatible dependencies and similar styles of making connections.\n\n**How many dependencies are we talking here?**\n\nSpear's reliance on Mint and `:gpb` give it a somewhat small dependency tree:\n\n```\n$ mix deps.tree --only prod\nspear\n├── connection ~\u003e 1.0 (Hex package)\n├── event_store_db_gpb_protobufs ~\u003e 2.0 (Hex package)\n│   └── gpb ~\u003e 4.0 (Hex package)\n├── gpb ~\u003e 4.0 (Hex package)\n├── jason \u003e= 0.0.0 (Hex package)\n└── mint ~\u003e 1.0 (Hex package)\n```\n\n(And `jason` is optional!)\n\n**How close is this to being able to be used?**\n\nWe `@NFIBrokerage` already use Spear for some production connections to\nEvent Store Cloud. See the roadmap in\n[#7](https://github.com/NFIBrokerage/spear/issues/7) with the plans for\nreaching the v1.0.0 release.\n\n## Installation\n\nAdd `:spear` to your mix dependencies in `mix.exs`\n\n```elixir\ndef deps do\n  [\n    {:spear, \"~\u003e 1.0\"},\n    # If you want to encode events as JSON, :jason is a great library for\n    # encoding and decoding and works out-of-the-box with spear.\n    # Any JSON (de)serializer should work though, so you don't *need* to add\n    # :jason to your dependencies.\n    {:jason, \"~\u003e 1.0\"},\n    # If you're connecting to an EventStoreDB with a TLS certificate signed\n    # by a public Certificate Authority (CA), include :castore\n    {:castore, \"\u003e= 0.0.0\"}\n  ]\nend\n```\n\n## Usage\n\n\u003cdetails\u003e\u003csummary\u003eMaking a connection...\u003c/summary\u003e\n\u003cbr\u003e\n\nFamiliar with [`Ecto.Repo`](https://hexdocs.pm/ecto/Ecto.Repo.html)? It lets\nyou write a database connection like a module\n\n```elixir\n# note this is for illustration purposes and NOT directly related to Spear\n# lib/my_app/repo.ex\ndefmodule MyApp.Repo do\n  use Ecto.Repo,\n    otp_app: :my_app,\n    adapter: Ecto.Adapters.Postgres\nend\n```\n\nand then configure it with application-config (`config/*.exs`)\n\n```elixir\n# note this is for illustration purposes and NOT directly related to Spear\n# config/config.exs\nconfig :my_app, MyApp.Repo,\n  url: \"ecto://postgres:postgres@localhost/my_database\"\n```\n\nSpear lets you do the same with a connection to the EventStoreDB:\n\n```elixir\n# lib/my_app/event_store_db_client.ex\ndefmodule MyApp.EventStoreDbClient do\n  use Spear.Client,\n    otp_app: :my_app\nend\n```\n\nand configure it,\n\n```elixir\n# config/config.exs\nconfig :my_app, MyApp.EventStoreDbClient,\n  connection_string: \"esdb://localhost:2113\"\n```\n\nadd it to your application's supervision tree in `lib/my_app/application.ex`\n\n```elixir\n# lib/my_app/application.ex\ndefmodule MyApp.Application do\n  use Application\n\n  def start(_type, _args) do\n    children = [\n      MyApp.EventStoreDbClient\n    ]\n    \n    Supervisor.start_link(children, strategy: :one_for_one, name: MyApp.Supervisor)\n  end\nend\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003eOr connecting in IEx...\u003c/summary\u003e\n\u003cbr\u003e\n\nA `Spear.Connection` is just a regular ole' GenServer with a default of pulling\nconfiguration from application-config. You can start a `Spear.Connection`\nlike any other process, even in IEx! Plus you can provide the configuration\nstraight to the `Spear.Connection.start_link/1` function.\n\nLet's use the new `Mix.install/1` function from Elixir 1.12 to try out\nSpear. Say that you have an EventStoreDB instance running locally with the\n`--insecure` option.\n\n```elixir\niex\u003e Mix.install([:spear, :jason])\n# a bunch of installation text here\n:ok\niex\u003e {:ok, conn} = Spear.Connection.start_link(connection_string: \"esdb://localhost:2113\")\n{:ok, #PID\u003c0.1518.0\u003e}\n```\n\nAnd we're up and running reading and writing events!\n\n\u003c/details\u003e\n\n\u003cdetails open\u003e\u003csummary\u003eReading and writing streams...\u003c/summary\u003e\n\u003cbr\u003e\n\nNow that we have a connection process (we'll call it `conn`), let's read and\nwrite some events!\n\n```elixir\niex\u003e event = Spear.Event.new(\"IExAndSpear\", %{\"hello\" =\u003e \"world\"})\n%Spear.Event{\n  body: %{\"hello\" =\u003e \"world\"},\n  id: \"9e3a8bcf-0c22-4a38-85c6-2054a0342ec8\",\n  metadata: %{content_type: \"application/json\", custom_metadata: \"\"},\n  type: \"IExAndSpear\"\n}\niex\u003e [event] |\u003e Spear.append(conn, \"MySpearDemo\")\n:ok\niex\u003e Spear.stream!(conn, \"MySpearDemo\")\n#Stream\u003c[\n  enum: #Function\u003c62.80860365/2 in Stream.unfold/2\u003e,\n  funs: [#Function\u003c48.80860365/1 in Stream.map/2\u003e]\n]\u003e\niex\u003e Spear.stream!(conn, \"MySpearDemo\") |\u003e Enum.to_list()\n[\n  %Spear.Event{\n    body: %{\"hello\" =\u003e \"world\"},\n    id: \"9e3a8bcf-0c22-4a38-85c6-2054a0342ec8\",\n    metadata: %{\n      commit_position: 18446744073709551615,\n      content_type: \"application/json\",\n      created: ~U[2021-04-12 20:05:17.757215Z],\n      custom_metadata: \"\",\n      prepare_position: 18446744073709551615,\n      stream_name: \"MySpearDemo\",\n      stream_revision: 0\n    },\n    type: \"IExAndSpear\"\n  }\n]\n```\n\nSpear uses Elixir `Stream`s to provide a flexible and efficient interface\nfor EventStoreDB streams.\n\n```elixir\niex\u003e Stream.repeatedly(fn -\u003e Spear.Event.new(\"TinyEvent\", %{}) end)\n#Function\u003c51.80860365/2 in Stream.repeatedly/1\u003e\niex\u003e Stream.repeatedly(fn -\u003e Spear.Event.new(\"TinyEvent\", %{}) end) |\u003e Stream.take(10_000) |\u003e Spear.append(conn, \"LongStream\")\n:ok\niex\u003e Spear.stream!(conn, \"LongStream\")\n#Stream\u003c[\n  enum: #Function\u003c62.80860365/2 in Stream.unfold/2\u003e,\n  funs: [#Function\u003c48.80860365/1 in Stream.map/2\u003e]\n]\u003e\niex\u003e Spear.stream!(conn, \"LongStream\") |\u003e Enum.count\n10000\n```\n\n\u003c/details\u003e\n\nAnd that's the basics! Check out the [Spear documentation on\nhex](https://hexdocs.pm/spear/Spear.html). Interested in writing\nefficient event-processing pipelines and topologies with EventStoreDB\nvia [GenStage](https://github.com/elixir-lang/gen_stage) and\n[Broadway](https://github.com/dashbitco/broadway) producers? Check out\n[Volley](https://github.com/NFIBrokerage/volley).\n\n[^1]: https://github.com/NFIBrokerage/spear/issues/66\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnfibrokerage%2Fspear","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnfibrokerage%2Fspear","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnfibrokerage%2Fspear/lists"}