From 7587e61a8545bb68f2a69bfabe350a5d5a08ab0d Mon Sep 17 00:00:00 2001 From: Chase Pursley Date: Fri, 21 Jun 2024 11:10:05 -0400 Subject: [PATCH 1/4] Depreciate Destinations - take 1. --- README.md | 56 ++------------ lib/walex/config/config.ex | 29 +------- lib/walex/destinations/destinations.ex | 41 +---------- lib/walex/destinations/event_modules.ex | 4 +- lib/walex/destinations/event_relay.ex | 98 ------------------------- lib/walex/destinations/supervisor.ex | 18 +---- lib/walex/destinations/webhooks.ex | 96 ------------------------ test/walex/config/config_test.exs | 4 +- test/walex/database_test.exs | 2 +- test/walex/event/event_dsl_test.exs | 2 +- test/walex/event/event_test.exs | 2 +- 11 files changed, 22 insertions(+), 330 deletions(-) delete mode 100644 lib/walex/destinations/event_relay.ex delete mode 100644 lib/walex/destinations/webhooks.ex diff --git a/README.md b/README.md index 48c1f16..2467383 100644 --- a/README.md +++ b/README.md @@ -3,9 +3,9 @@ Simple and reliable Postgres [Change Data Capture (CDC)](https://en.wikipedia.org/wiki/Change_data_capture) in Elixir. -WalEx allows you to listen to change events on your Postgres tables then send them on to [destinations](#destinations) or perform callback-like actions with the data via the [DSL](#elixir-dsl). For example: +WalEx allows you to listen to change events on your Postgres tables then perform callback-like actions with the data via the [Event DSL](#elixir-dsl). For example: -- Stream database changes to an event service like [EventRelay](https://github.com/eventrelay/eventrelay) +- Stream database changes to an external service - Send a user a welcome email after they create a new account - Augment an existing Postgres-backed application with business logic - Send events to third party services (analytics, CRM, [webhooks](#webhooks)) @@ -122,21 +122,9 @@ config :my_app, WalEx, database: "postgres", publication: "events", subscriptions: ["user", "todo"], - # optional - destinations: [ - # WalEx assumes your module names match this pattern: MyApp.Events.User, MyApp.Events.ToDo, etc - # but you can also specify custom modules like so: - # modules: [MyApp.CustomModule, MyApp.OtherCustomModule], - webhooks: ["https://webhook.site/c2f32b47-33ef-425c-9ed2-f369529a0de8"], - event_relay_topic: "todos" - ], - webhook_signing_secret: "9da89f5f8f4717099c698a17c0d3a1869ee227de06c27b18", - event_relay: [ - host: "localhost", - port: "50051", - token: - "cmpiNmpFSGhtNVhORFVubDFzUW9OR1JqTlFZOVFFcjRwZWMxS2VWRzJIOnY5NkFRQVFjSVp0TWVmc3hpRl8ydVZuaW9FTC0wX3JrZjhXcTE4MS1EbnVLU1p5VF9OZkpBZGs1SlFuQlNNdVg=" - ], + # WalEx assumes your module names match this pattern: MyApp.Events.User, MyApp.Events.ToDo, etc + # but you can also specify custom modules like so: + # modules: [MyApp.CustomModule, MyApp.OtherCustomModule], name: MyApp ``` @@ -220,11 +208,9 @@ where _name_ field was changed): ] ``` -### Destinations +### Event Module -#### Event Module - -If your app is named _MyApp_ and you have a subscription called _:user_ (which represents a database table), WalEx assumes you have a module called `MyApp.Events.User` that uses WalEx Event. But you can also define any custom module, just be sure to add it to the _modules_ config under _destinations_. +If your app is named _MyApp_ and you have a subscription called _:user_ (which represents a database table), WalEx assumes you have a module called `MyApp.Events.User` that uses WalEx Event. But you can also define any custom module, just be sure to add it to the _modules_ config. Note that the result of `events` is a list. This is because WalEx returns a _List_ of _transactions_ for a particular table when there's a change event. Often times this will just contain one result, but it could be many (for example, if you use database triggers to update a column after an insert). @@ -312,26 +298,6 @@ defmodule MyApp.Events.User do end ``` -You can optionally [configure](#config) WalEx to automatically send events to the following destinations without needing to know Elixir: - -#### Webhooks - -Send subscribed events to one or more webhooks. WalEx supports the [Standard Webhooks](https://www.standardwebhooks.com) spec via the [webhoox](https://github.com/cpursley/webhoox) library (which can also be used to receive webhooks in Elixir). - -#### EventRelay - -If you need something more durable and flexible than webhooks, check out [EventRelay](https://github.com/eventrelay/eventrelay). - -In EventRelay, you'll need to create a topic matching what's in the WalEx destinations config. So, if your event_relay_topic is called _todos_ (usually this is the database name), then your topic name in EventRelay should be `todos`. Here's how to do it via grpcurl: - -```bash -grpcurl -H "Authorization: Bearer {api_key_token}" -plaintext -proto event_relay.proto -d '{"name": "todos"}' localhost:50051 eventrelay.Topics.CreateTopic -``` - -#### Coming Soon - -More destinations coming. Pull requests welcome! - ## Test You'll need a local Postgres instance running @@ -339,10 +305,4 @@ You'll need a local Postgres instance running ```bash MIX_ENV=test mix walex.setup MIX_ENV=test mix test -``` - -## Help? - -I would love to have your help! I do ask that if you do find a bug, please add a test to your PR that shows the bug and how it was fixed. - -Thanks! \ No newline at end of file +``` \ No newline at end of file diff --git a/lib/walex/config/config.ex b/lib/walex/config/config.ex index 48ec997..d278c40 100644 --- a/lib/walex/config/config.ex +++ b/lib/walex/config/config.ex @@ -8,11 +8,7 @@ defmodule WalEx.Config do alias WalEx.Config.Registry, as: WalExRegistry @allowed_config_value ~w(database hostname name password port publication username webhook_signing_secret slot_name durable_slot message_middleware)a - @allowed_config_values ~w(destinations event_relay modules subscriptions)a - - @type destinations_t :: [ - {:modules, [module]} | {:webhooks, [binary]} | {:event_relay_topic, binary} - ] + @allowed_config_values ~w(modules subscriptions)a @type start_opts :: [ {:database, binary} @@ -26,7 +22,6 @@ defmodule WalEx.Config do | {:slot_name, binary} | {:durable_slot, boolean} | {:message_middleware, (term, term -> :ok)} - | {:destinations, destinations_t()} | {:event_relay, keyword()} | {:modules, [module]} | {:subscriptions, [binary()]} @@ -71,22 +66,7 @@ defmodule WalEx.Config do def get_database(app_name), do: get_configs(app_name, :database) - def get_destination(app_name, destination) do - case get_configs(app_name, :destinations) do - destinations when is_list(destinations) and destinations != [] -> - destinations - |> Keyword.get(destination, nil) - - _ -> - nil - end - end - - def get_event_modules(app_name), do: get_destination(app_name, :modules) - - def get_webhooks(app_name), do: get_destination(app_name, :webhooks) - - def get_event_relay_topic(app_name), do: get_destination(app_name, :event_relay_topic) + def get_event_modules(app_name), do: get_configs(app_name, :modules) def add_config(app_name, key, new_values) when is_list(new_values) and key in @allowed_config_values do @@ -131,8 +111,7 @@ defmodule WalEx.Config do name = Keyword.get(configs, :name) subscriptions = Keyword.get(configs, :subscriptions, []) - destinations = Keyword.get(configs, :destinations, []) - modules = Keyword.get(destinations, :modules, []) + modules = Keyword.get(configs, :modules, []) module_names = build_module_names(name, modules, subscriptions) [ @@ -147,7 +126,7 @@ defmodule WalEx.Config do socket_options: Keyword.get(configs, :socket_options, []), subscriptions: subscriptions, publication: Keyword.get(configs, :publication), - destinations: Keyword.put(destinations, :modules, module_names), + modules: module_names, webhook_signing_secret: Keyword.get(configs, :webhook_signing_secret), event_relay: Keyword.get(configs, :event_relay), slot_name: Keyword.get(configs, :slot_name) |> parse_slot_name(name), diff --git a/lib/walex/destinations/destinations.ex b/lib/walex/destinations/destinations.ex index ade50fc..1fcb66c 100644 --- a/lib/walex/destinations/destinations.ex +++ b/lib/walex/destinations/destinations.ex @@ -5,9 +5,9 @@ defmodule WalEx.Destinations do use GenServer - alias WalEx.{Destinations, Config, Event, TransactionFilter} + alias WalEx.{Destinations, Config} alias Config.Registry - alias Destinations.{EventModules, EventRelay, Webhooks} + alias Destinations.EventModules def start_link(opts) do name = @@ -40,45 +40,8 @@ defmodule WalEx.Destinations do {:reply, :ok, state} end - defp filter_subscribed(txn, app_name) do - txn - |> TransactionFilter.filter_subscribed(app_name) - |> Event.cast_events(app_name) - end - defp process_destinations(txn, app_name) do # TODO: EventModules should be dynamic (only if modules exist) EventModules.process(txn, app_name) - - filtered_events = filter_subscribed(txn, app_name) - destinations = Config.get_configs(app_name, :destinations) - - if Config.has_config?(destinations, :webhooks) do - process_webhooks(filtered_events, app_name) - end - - if Config.has_config?(destinations, :event_relay_topic) do - process_event_relay(filtered_events, app_name) - end - end - - defp process_event_relay([], _app_name), do: :ok - - defp process_event_relay(filtered_events, app_name) do - event_relay_topic = Config.get_event_relay_topic(app_name) - - if is_binary(event_relay_topic) and event_relay_topic != "" do - EventRelay.process(filtered_events, app_name) - end - end - - defp process_webhooks([], _app_name), do: :ok - - defp process_webhooks(filtered_events, app_name) do - webhooks = Config.get_webhooks(app_name) - - if is_list(webhooks) and webhooks != [] do - Webhooks.process(filtered_events, app_name) - end end end diff --git a/lib/walex/destinations/event_modules.ex b/lib/walex/destinations/event_modules.ex index 553cdde..b6556d5 100755 --- a/lib/walex/destinations/event_modules.ex +++ b/lib/walex/destinations/event_modules.ex @@ -33,7 +33,7 @@ defmodule WalEx.Destinations.EventModules do @impl true def handle_call({:process, txn, server}, _from, state) do server - |> WalEx.Config.get_configs(:destinations) + |> WalEx.Config.get_configs(:modules) |> process_events(txn) {:reply, :ok, state} @@ -41,7 +41,7 @@ defmodule WalEx.Destinations.EventModules do defp process_events(nil, %{changes: [], commit_timestamp: _}), do: nil - defp process_events([modules: modules], txn) when is_list(modules) do + defp process_events(modules, txn) when is_list(modules) do process_modules(modules, txn) end diff --git a/lib/walex/destinations/event_relay.ex b/lib/walex/destinations/event_relay.ex deleted file mode 100644 index d286153..0000000 --- a/lib/walex/destinations/event_relay.ex +++ /dev/null @@ -1,98 +0,0 @@ -defmodule WalEx.Destinations.EventRelay do - @moduledoc """ - Responsible for sending events to EventRelay: https://github.com/eventrelay/eventrelay - """ - use GenServer - require Logger - - alias ERWeb.Grpc.Eventrelay - alias Eventrelay.Events.Stub, as: Client - alias Eventrelay.{NewEvent, PublishEventsRequest} - - alias WalEx.{Config, Helpers} - alias Config.Registry - - def start_link(opts) do - name = - opts - |> Keyword.get(:app_name) - |> registry_name - - GenServer.start_link(__MODULE__, opts, name: name) - end - - def process(changes, app_name) do - name = registry_name(app_name) - - GenServer.call(name, {:process, changes, app_name}, :infinity) - end - - defp registry_name(app_name) do - Registry.set_name(:set_gen_server, __MODULE__, app_name) - end - - @impl true - def init(_) do - {:ok, %{}} - end - - @impl true - def handle_call({:process, changes, app_name}, _from, state) do - process_events(changes, app_name) - - {:reply, :ok, state} - end - - def process_events(changes, app_name) do - case connect(app_name) do - {:ok, channel} -> - topic = Config.get_event_relay_topic(app_name) - events = build_events(changes) - - request = - %PublishEventsRequest{ - topic: topic, - durable: true, - events: events - } - - Client.publish_events(channel, request) - - error -> - Logger.error("EventRelay.process_events error=#{inspect(error)}") - error - end - end - - defp connect(app_name) do - config = Config.get_configs(app_name, :event_relay) - host = Keyword.get(config, :host) - port = Keyword.get(config, :port) - token = Keyword.get(config, :token) - - GRPC.Stub.connect("#{host}:#{port}", headers: [{"authorization", "Bearer #{token}"}]) - end - - def build_events(changes) do - changes - |> Enum.map(&Map.from_struct(&1)) - |> Enum.map(&build_event(&1)) - end - - def build_event(event = %{type: type, source: %{table: table}}) do - case Jason.encode(event) do - {:ok, data} -> - source = Helpers.set_source() - name = Helpers.set_type(table, type) - - %NewEvent{ - source: source, - name: name, - data: data - } - - error -> - Logger.error("EventRelay.process_events error=#{inspect(error)}") - end - end -end diff --git a/lib/walex/destinations/supervisor.ex b/lib/walex/destinations/supervisor.ex index 8a96eca..8eb4d49 100644 --- a/lib/walex/destinations/supervisor.ex +++ b/lib/walex/destinations/supervisor.ex @@ -5,7 +5,7 @@ defmodule WalEx.Destinations.Supervisor do alias WalEx.Config alias WalEx.Destinations - alias Destinations.{EventModules, EventRelay, Webhooks} + alias Destinations.EventModules def start_link(opts) do app_name = Keyword.get(opts, :name) @@ -23,8 +23,6 @@ defmodule WalEx.Destinations.Supervisor do children = [{Destinations, app_name: app_name}] |> maybe_event_modules(app_name) - |> maybe_webhooks(app_name) - |> maybe_event_relay(app_name) Supervisor.init(children, strategy: :one_for_one, max_restarts: 10) end @@ -36,20 +34,6 @@ defmodule WalEx.Destinations.Supervisor do maybe_set_child(children, has_module_config, {EventModules, app_name: app_name}) end - defp maybe_webhooks(children, app_name) do - webhooks = Config.get_webhooks(app_name) - has_webhook_config = is_list(webhooks) and webhooks != [] - - maybe_set_child(children, has_webhook_config, {Webhooks, app_name: app_name}) - end - - defp maybe_event_relay(children, app_name) do - event_relay = Config.get_event_relay_topic(app_name) - has_event_relay_config = is_binary(event_relay) and event_relay != "" - - maybe_set_child(children, has_event_relay_config, {EventRelay, app_name: app_name}) - end - defp maybe_set_child(children, true, child), do: children ++ [child] defp maybe_set_child(children, false, _child), do: children end diff --git a/lib/walex/destinations/webhooks.ex b/lib/walex/destinations/webhooks.ex deleted file mode 100644 index 643f17c..0000000 --- a/lib/walex/destinations/webhooks.ex +++ /dev/null @@ -1,96 +0,0 @@ -defmodule WalEx.Destinations.Webhooks do - @moduledoc """ - Webhooks destination - """ - - use GenServer - - alias WalEx.{Config, Helpers} - alias Config.Registry - alias Webhoox.Authentication.StandardWebhook - - def start_link(opts) do - name = - opts - |> Keyword.get(:app_name) - |> registry_name - - GenServer.start_link(__MODULE__, opts, name: name) - end - - def process(changes, app_name) do - name = registry_name(app_name) - - GenServer.call(name, {:process, changes, app_name}, :infinity) - end - - defp registry_name(app_name) do - Registry.set_name(:set_gen_server, __MODULE__, app_name) - end - - @impl true - def init(_) do - {:ok, %{}} - end - - @impl true - def handle_call({:process, changes, app_name}, _from, state) do - process_events(changes, app_name) - - {:reply, :ok, state} - end - - defp process_events(changes, app_name), do: Enum.map(changes, &process_event(&1, app_name)) - - defp process_event(change, app_name) do - webhooks = Config.get_webhooks(app_name) - signing_secret = get_signing_secret(app_name) - - send_webhooks(webhooks, signing_secret, change) - end - - defp get_signing_secret(app_name) do - Config.get_configs(app_name, :webhook_signing_secret) - end - - defp send_webhooks(nil, _signing_secret, _change), do: :ok - - defp send_webhooks(webhooks, signing_secret, change) do - Enum.each(webhooks, &send_webhook(&1, signing_secret, change)) - end - - defp send_webhook(webhook_url, signing_secret, change) do - body = set_body(change) - headers = set_headers(body, signing_secret) - - Req.post!(webhook_url, json: body, headers: headers) - end - - defp set_body(event = %{name: name, type: type}) do - name - |> Helpers.set_type(type) - |> event_body(event) - end - - def event_body(type, data) do - %{ - event_type: type, - data: data - } - end - - defp set_headers(body, signing_secret) do - user_agent = Helpers.set_source() - id = Uniq.UUID.uuid4() - timestamp = :os.system_time(:second) - signature = StandardWebhook.sign(id, timestamp, body, signing_secret) - - [ - "Content-Type": "application/json", - "User-Agent": user_agent, - "webhook-id": id, - "webhook-timestamp": Integer.to_string(timestamp), - "webhook-signature": signature - ] - end -end diff --git a/test/walex/config/config_test.exs b/test/walex/config/config_test.exs index 4254b0f..2c9034b 100644 --- a/test/walex/config/config_test.exs +++ b/test/walex/config/config_test.exs @@ -22,7 +22,7 @@ defmodule WalEx.ConfigTest do socket_options: [], subscriptions: ["subscriptions"], publication: "publication", - destinations: [modules: [MyApp.CustomModule]] + modules: [MyApp.CustomModule] ] setup_all do @@ -89,7 +89,7 @@ defmodule WalEx.ConfigTest do socket_options: [], subscriptions: ["subscriptions"], publication: "publication", - destinations: [modules: [MyApp.CustomModule]], + modules: [MyApp.CustomModule], webhook_signing_secret: nil, event_relay: nil, slot_name: "my_app_walex", diff --git a/test/walex/database_test.exs b/test/walex/database_test.exs index 38b5255..0ca98ed 100644 --- a/test/walex/database_test.exs +++ b/test/walex/database_test.exs @@ -19,7 +19,7 @@ defmodule WalEx.DatabaseTest do port: 5432, subscriptions: ["user", "todo"], publication: "events", - destinations: [modules: [TestModule]] + modules: [TestModule] ] @replication_slot %{ diff --git a/test/walex/event/event_dsl_test.exs b/test/walex/event/event_dsl_test.exs index 417e0ab..83f3efc 100644 --- a/test/walex/event/event_dsl_test.exs +++ b/test/walex/event/event_dsl_test.exs @@ -21,7 +21,7 @@ defmodule WalEx.EventDslTest do port: 5432, subscriptions: ["user", "todo"], publication: ["events"], - destinations: [modules: [TestApp.DslTestModule]] + modules: [TestApp.DslTestModule] ] describe "on_event/2" do diff --git a/test/walex/event/event_test.exs b/test/walex/event/event_test.exs index e4a1dd4..ebe09ba 100644 --- a/test/walex/event/event_test.exs +++ b/test/walex/event/event_test.exs @@ -23,7 +23,7 @@ defmodule WalEx.EventTest do port: 5432, subscriptions: ["user", "todo"], publication: ["events"], - destinations: [modules: [TestApp.TestModule]] + modules: [TestApp.TestModule] ] describe "process_all/1" do From 9658df8db165dda1999cb2782a506a75d2e9f43b Mon Sep 17 00:00:00 2001 From: Chase Pursley Date: Fri, 21 Jun 2024 11:29:37 -0400 Subject: [PATCH 2/4] Depreciate Destinations - take 2. --- mix.exs | 9 ++------- mix.lock | 42 +++++++++++------------------------------- 2 files changed, 13 insertions(+), 38 deletions(-) diff --git a/mix.exs b/mix.exs index 82b98b1..4532e08 100644 --- a/mix.exs +++ b/mix.exs @@ -30,18 +30,13 @@ defmodule WalEx.MixProject do # Run "mix help deps" to learn about dependencies. defp deps do [ - {:postgrex, "~> 0.17.4"}, + {:postgrex, "~> 0.18.0"}, {:decimal, "~> 2.1.1"}, {:jason, "~> 1.4"}, {:timex, "~> 3.7"}, - {:req, "~> 0.4.8"}, - {:uniq, "~> 0.6.1"}, - {:eventrelay_client, "~> 0.1.0"}, - # {:eventrelay_client, github: "eventrelay/eventrelay_client_elixir", branch: "main"}, - {:webhoox, "~> 0.3.0"}, # Dev & Test - {:ex_doc, "~> 0.31.1", only: :dev, runtime: false}, + {:ex_doc, "~> 0.34.1", only: :dev, runtime: false}, {:sobelow, "~> 0.12", only: [:dev, :test], runtime: false}, {:credo, "~> 1.7.3", only: [:dev, :test], runtime: false}, {:excoveralls, "~> 0.10", only: [:dev, :test], runtime: false}, diff --git a/mix.lock b/mix.lock index 75f8659..1bccb87 100644 --- a/mix.lock +++ b/mix.lock @@ -1,52 +1,32 @@ %{ "bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"}, - "castore": {:hex, :castore, "1.0.5", "9eeebb394cc9a0f3ae56b813459f990abb0a3dedee1be6b27fdb50301930502f", [:mix], [], "hexpm", "8d7c597c3e4a64c395980882d4bca3cebb8d74197c590dc272cfd3b6a6310578"}, "certifi": {:hex, :certifi, "2.12.0", "2d1cca2ec95f59643862af91f001478c9863c2ac9cb6e2f89780bfd8de987329", [:rebar3], [], "hexpm", "ee68d85df22e554040cdb4be100f33873ac6051387baf6a8f6ce82272340ff1c"}, "combine": {:hex, :combine, "0.10.0", "eff8224eeb56498a2af13011d142c5e7997a80c8f5b97c499f84c841032e429f", [:mix], [], "hexpm", "1b1dbc1790073076580d0d1d64e42eae2366583e7aecd455d1215b0d16f2451b"}, - "cowboy": {:hex, :cowboy, "2.10.0", "ff9ffeff91dae4ae270dd975642997afe2a1179d94b1887863e43f681a203e26", [:make, :rebar3], [{:cowlib, "2.12.1", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "3afdccb7183cc6f143cb14d3cf51fa00e53db9ec80cdcd525482f5e99bc41d6b"}, - "cowlib": {:hex, :cowlib, "2.12.1", "a9fa9a625f1d2025fe6b462cb865881329b5caff8f1854d1cbc9f9533f00e1e1", [:make, :rebar3], [], "hexpm", "163b73f6367a7341b33c794c4e88e7dbfe6498ac42dcd69ef44c5bc5507c8db0"}, - "credo": {:hex, :credo, "1.7.3", "05bb11eaf2f2b8db370ecaa6a6bda2ec49b2acd5e0418bc106b73b07128c0436", [:mix], [{:bunt, "~> 0.2.1 or ~> 1.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "35ea675a094c934c22fb1dca3696f3c31f2728ae6ef5a53b5d648c11180a4535"}, + "credo": {:hex, :credo, "1.7.7", "771445037228f763f9b2afd612b6aa2fd8e28432a95dbbc60d8e03ce71ba4446", [:mix], [{:bunt, "~> 0.2.1 or ~> 1.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "8bc87496c9aaacdc3f90f01b7b0582467b69b4bd2441fe8aae3109d843cc2f2e"}, "db_connection": {:hex, :db_connection, "2.6.0", "77d835c472b5b67fc4f29556dee74bf511bbafecdcaf98c27d27fa5918152086", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "c2f992d15725e721ec7fbc1189d4ecdb8afef76648c746a8e1cad35e3b8a35f3"}, "decimal": {:hex, :decimal, "2.1.1", "5611dca5d4b2c3dd497dec8f68751f1f1a54755e8ed2a966c2633cf885973ad6", [:mix], [], "hexpm", "53cfe5f497ed0e7771ae1a475575603d77425099ba5faef9394932b35020ffcc"}, "earmark_parser": {:hex, :earmark_parser, "1.4.39", "424642f8335b05bb9eb611aa1564c148a8ee35c9c8a8bba6e129d51a3e3c6769", [:mix], [], "hexpm", "06553a88d1f1846da9ef066b87b57c6f605552cfbe40d20bd8d59cc6bde41944"}, - "eventrelay_client": {:hex, :eventrelay_client, "0.1.0", "b81a469f573fc418171995d1816da3bac96450b5a9cc0cb998b0eba2f0803e6c", [:mix], [{:grpc, "~> 0.7.0", [hex: :grpc, repo: "hexpm", optional: false]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:nimble_options, "~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:protobuf, "~> 0.11", [hex: :protobuf, repo: "hexpm", optional: false]}], "hexpm", "29909f607248848d3bd62983382d7dd82c93325fad3b4c4b967f4f70823101f7"}, - "ex_doc": {:hex, :ex_doc, "0.31.1", "8a2355ac42b1cc7b2379da9e40243f2670143721dd50748bf6c3b1184dae2089", [:mix], [{:earmark_parser, "~> 1.4.39", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.1", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "3178c3a407c557d8343479e1ff117a96fd31bafe52a039079593fb0524ef61b0"}, - "excoveralls": {:hex, :excoveralls, "0.18.0", "b92497e69465dc51bc37a6422226ee690ab437e4c06877e836f1c18daeb35da9", [:mix], [{:castore, "~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "1109bb911f3cb583401760be49c02cbbd16aed66ea9509fc5479335d284da60b"}, - "expo": {:hex, :expo, "0.4.1", "1c61d18a5df197dfda38861673d392e642649a9cef7694d2f97a587b2cfb319b", [:mix], [], "hexpm", "2ff7ba7a798c8c543c12550fa0e2cbc81b95d4974c65855d8d15ba7b37a1ce47"}, + "ex_doc": {:hex, :ex_doc, "0.34.1", "9751a0419bc15bc7580c73fde506b17b07f6402a1e5243be9e0f05a68c723368", [:mix], [{:earmark_parser, "~> 1.4.39", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "d441f1a86a235f59088978eff870de2e815e290e44a8bd976fe5d64470a4c9d2"}, + "excoveralls": {:hex, :excoveralls, "0.18.1", "a6f547570c6b24ec13f122a5634833a063aec49218f6fff27de9df693a15588c", [:mix], [{:castore, "~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "d65f79db146bb20399f23046015974de0079668b9abb2f5aac074d078da60b8d"}, + "expo": {:hex, :expo, "0.5.2", "beba786aab8e3c5431813d7a44b828e7b922bfa431d6bfbada0904535342efe2", [:mix], [], "hexpm", "8c9bfa06ca017c9cb4020fabe980bc7fdb1aaec059fd004c2ab3bff03b1c599c"}, "file_system": {:hex, :file_system, "1.0.0", "b689cc7dcee665f774de94b5a832e578bd7963c8e637ef940cd44327db7de2cd", [:mix], [], "hexpm", "6752092d66aec5a10e662aefeed8ddb9531d79db0bc145bb8c40325ca1d8536d"}, - "finch": {:hex, :finch, "0.16.0", "40733f02c89f94a112518071c0a91fe86069560f5dbdb39f9150042f44dcfb1a", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: false]}, {:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.3", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 0.2.6 or ~> 1.0", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "f660174c4d519e5fec629016054d60edd822cdfe2b7270836739ac2f97735ec5"}, - "gettext": {:hex, :gettext, "0.23.1", "821e619a240e6000db2fc16a574ef68b3bd7fe0167ccc264a81563cc93e67a31", [:mix], [{:expo, "~> 0.4.0", [hex: :expo, repo: "hexpm", optional: false]}], "hexpm", "19d744a36b809d810d610b57c27b934425859d158ebd56561bc41f7eeb8795db"}, - "grpc": {:hex, :grpc, "0.7.0", "a86eab356b0b84406b526786a947ca50e9b9eae87108c873b51e321f8a71e8ed", [:mix], [{:cowboy, "~> 2.10", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowlib, "~> 2.12", [hex: :cowlib, repo: "hexpm", optional: false]}, {:gun, "~> 2.0", [hex: :gun, repo: "hexpm", optional: false]}, {:mint, "~> 1.5", [hex: :mint, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "632a9507da8d3c12b112b197db4d60da3c95bad02594d37711eeb622d032f254"}, - "gun": {:hex, :gun, "2.0.1", "160a9a5394800fcba41bc7e6d421295cf9a7894c2252c0678244948e3336ad73", [:make, :rebar3], [{:cowlib, "2.12.1", [hex: :cowlib, repo: "hexpm", optional: false]}], "hexpm", "a10bc8d6096b9502205022334f719cc9a08d9adcfbfc0dbee9ef31b56274a20b"}, - "hackney": {:hex, :hackney, "1.19.1", "59de4716e985dd2b5cbd4954fa1ae187e2b610a9c4520ffcb0b1653c3d6e5559", [:rebar3], [{:certifi, "~> 2.12.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~> 6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~> 1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~> 1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.4.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~> 1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "8aa08234bdefc269995c63c2282cf3cd0e36febe3a6bfab11b610572fdd1cad0"}, - "hpax": {:hex, :hpax, "0.1.2", "09a75600d9d8bbd064cdd741f21fc06fc1f4cf3d0fcc335e5aa19be1a7235c84", [:mix], [], "hexpm", "2c87843d5a23f5f16748ebe77969880e29809580efdaccd615cd3bed628a8c13"}, + "gettext": {:hex, :gettext, "0.24.0", "6f4d90ac5f3111673cbefc4ebee96fe5f37a114861ab8c7b7d5b30a1108ce6d8", [:mix], [{:expo, "~> 0.5.1", [hex: :expo, repo: "hexpm", optional: false]}], "hexpm", "bdf75cdfcbe9e4622dd18e034b227d77dd17f0f133853a1c73b97b3d6c770e8b"}, + "hackney": {:hex, :hackney, "1.20.1", "8d97aec62ddddd757d128bfd1df6c5861093419f8f7a4223823537bad5d064e2", [:rebar3], [{:certifi, "~> 2.12.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~> 6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~> 1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~> 1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.4.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~> 1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "fe9094e5f1a2a2c0a7d10918fee36bfec0ec2a979994cff8cfe8058cd9af38e3"}, "idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"}, "jason": {:hex, :jason, "1.4.1", "af1504e35f629ddcdd6addb3513c3853991f694921b1b9368b0bd32beb9f1b63", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "fbb01ecdfd565b56261302f7e1fcc27c4fb8f32d56eab74db621fc154604a7a1"}, - "makeup": {:hex, :makeup, "1.1.1", "fa0bc768698053b2b3869fa8a62616501ff9d11a562f3ce39580d60860c3a55e", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "5dc62fbdd0de44de194898b6710692490be74baa02d9d108bc29f007783b0b48"}, - "makeup_elixir": {:hex, :makeup_elixir, "0.16.1", "cc9e3ca312f1cfeccc572b37a09980287e243648108384b97ff2b76e505c3555", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "e127a341ad1b209bd80f7bd1620a15693a9908ed780c3b763bccf7d200c767c6"}, - "makeup_erlang": {:hex, :makeup_erlang, "0.1.3", "d684f4bac8690e70b06eb52dad65d26de2eefa44cd19d64a8095e1417df7c8fd", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "b78dc853d2e670ff6390b605d807263bf606da3c82be37f9d7f68635bd886fc9"}, + "makeup": {:hex, :makeup, "1.1.2", "9ba8837913bdf757787e71c1581c21f9d2455f4dd04cfca785c70bbfff1a76a3", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "cce1566b81fbcbd21eca8ffe808f33b221f9eee2cbc7a1706fc3da9ff18e6cac"}, + "makeup_elixir": {:hex, :makeup_elixir, "0.16.2", "627e84b8e8bf22e60a2579dad15067c755531fea049ae26ef1020cad58fe9578", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "41193978704763f6bbe6cc2758b84909e62984c7752b3784bd3c218bb341706b"}, + "makeup_erlang": {:hex, :makeup_erlang, "1.0.0", "6f0eff9c9c489f26b69b61440bf1b238d95badae49adac77973cbacae87e3c2e", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "ea7a9307de9d1548d2a72d299058d1fd2339e3d398560a0e46c27dab4891e4d2"}, "metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"}, - "mime": {:hex, :mime, "2.0.5", "dc34c8efd439abe6ae0343edbb8556f4d63f178594894720607772a041b04b02", [:mix], [], "hexpm", "da0d64a365c45bc9935cc5c8a7fc5e49a0e0f9932a761c55d6c52b142780a05c"}, - "mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm", "f278585650aa581986264638ebf698f8bb19df297f66ad91b18910dfc6e19323"}, - "mint": {:hex, :mint, "1.5.2", "4805e059f96028948870d23d7783613b7e6b0e2fb4e98d720383852a760067fd", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "d77d9e9ce4eb35941907f1d3df38d8f750c357865353e21d335bdcdf6d892a02"}, - "nimble_options": {:hex, :nimble_options, "1.1.0", "3b31a57ede9cb1502071fade751ab0c7b8dbe75a9a4c2b5bbb0943a690b63172", [:mix], [], "hexpm", "8bbbb3941af3ca9acc7835f5655ea062111c9c27bcac53e004460dfd19008a99"}, + "mimerl": {:hex, :mimerl, "1.3.0", "d0cd9fc04b9061f82490f6581e0128379830e78535e017f7780f37fea7545726", [:rebar3], [], "hexpm", "a1e15a50d1887217de95f0b9b0793e32853f7c258a5cd227650889b38839fe9d"}, "nimble_parsec": {:hex, :nimble_parsec, "1.4.0", "51f9b613ea62cfa97b25ccc2c1b4216e81df970acd8e16e8d1bdc58fef21370d", [:mix], [], "hexpm", "9c565862810fb383e9838c1dd2d7d2c437b3d13b267414ba6af33e50d2d1cf28"}, - "nimble_pool": {:hex, :nimble_pool, "1.0.0", "5eb82705d138f4dd4423f69ceb19ac667b3b492ae570c9f5c900bb3d2f50a847", [:mix], [], "hexpm", "80be3b882d2d351882256087078e1b1952a28bf98d0a287be87e4a24a710b67a"}, "parse_trans": {:hex, :parse_trans, "3.4.1", "6e6aa8167cb44cc8f39441d05193be6e6f4e7c2946cb2759f015f8c56b76e5ff", [:rebar3], [], "hexpm", "620a406ce75dada827b82e453c19cf06776be266f5a67cff34e1ef2cbb60e49a"}, - "plug": {:hex, :plug, "1.15.2", "94cf1fa375526f30ff8770837cb804798e0045fd97185f0bb9e5fcd858c792a3", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "02731fa0c2dcb03d8d21a1d941bdbbe99c2946c0db098eee31008e04c6283615"}, - "plug_crypto": {:hex, :plug_crypto, "2.0.0", "77515cc10af06645abbfb5e6ad7a3e9714f805ae118fa1a70205f80d2d70fe73", [:mix], [], "hexpm", "53695bae57cc4e54566d993eb01074e4d894b65a3766f1c43e2c61a1b0f45ea9"}, - "postgrex": {:hex, :postgrex, "0.17.4", "5777781f80f53b7c431a001c8dad83ee167bcebcf3a793e3906efff680ab62b3", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "6458f7d5b70652bc81c3ea759f91736c16a31be000f306d3c64bcdfe9a18b3cc"}, - "protobuf": {:hex, :protobuf, "0.12.0", "58c0dfea5f929b96b5aa54ec02b7130688f09d2de5ddc521d696eec2a015b223", [:mix], [{:jason, "~> 1.2", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "75fa6cbf262062073dd51be44dd0ab940500e18386a6c4e87d5819a58964dc45"}, + "postgrex": {:hex, :postgrex, "0.18.0", "f34664101eaca11ff24481ed4c378492fed2ff416cd9b06c399e90f321867d7e", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "a042989ba1bc1cca7383ebb9e461398e3f89f868c92ce6671feb7ef132a252d1"}, "rambo": {:hex, :rambo, "0.3.4", "8962ac3bd1a633ee9d0e8b44373c7913e3ce3d875b4151dcd060886092d2dce7", [:mix], [], "hexpm", "0cc54ed089fbbc84b65f4b8a774224ebfe60e5c80186fafc7910b3e379ad58f1"}, - "ranch": {:hex, :ranch, "1.8.0", "8c7a100a139fd57f17327b6413e4167ac559fbc04ca7448e9be9057311597a1d", [:make, :rebar3], [], "hexpm", "49fbcfd3682fab1f5d109351b61257676da1a2fdbe295904176d5e521a2ddfe5"}, - "req": {:hex, :req, "0.4.8", "2b754a3925ddbf4ad78c56f30208ced6aefe111a7ea07fb56c23dccc13eb87ae", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.9", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 1.6 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "7146e51d52593bb7f20d00b5308a5d7d17d663d6e85cd071452b613a8277100c"}, - "retry": {:hex, :retry, "0.18.0", "dc58ebe22c95aa00bc2459f9e0c5400e6005541cf8539925af0aa027dc860543", [:mix], [], "hexpm", "9483959cc7bf69c9e576d9dfb2b678b71c045d3e6f39ab7c9aa1489df4492d73"}, "sobelow": {:hex, :sobelow, "0.13.0", "218afe9075904793f5c64b8837cc356e493d88fddde126a463839351870b8d1e", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "cd6e9026b85fc35d7529da14f95e85a078d9dd1907a9097b3ba6ac7ebbe34a0d"}, "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.7", "354c321cf377240c7b8716899e182ce4890c5938111a1296add3ec74cf1715df", [:make, :mix, :rebar3], [], "hexpm", "fe4c190e8f37401d30167c8c405eda19469f34577987c76dde613e838bbc67f8"}, "telemetry": {:hex, :telemetry, "1.2.1", "68fdfe8d8f05a8428483a97d7aab2f268aaff24b49e0f599faa091f1d4e7f61c", [:rebar3], [], "hexpm", "dad9ce9d8effc621708f99eac538ef1cbe05d6a874dd741de2e689c47feafed5"}, "timex": {:hex, :timex, "3.7.11", "bb95cb4eb1d06e27346325de506bcc6c30f9c6dea40d1ebe390b262fad1862d1", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.20", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 1.1", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm", "8b9024f7efbabaf9bd7aa04f65cf8dcd7c9818ca5737677c7b76acbc6a94d1aa"}, "tzdata": {:hex, :tzdata, "1.1.1", "20c8043476dfda8504952d00adac41c6eda23912278add38edc140ae0c5bcc46", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "a69cec8352eafcd2e198dea28a34113b60fdc6cb57eb5ad65c10292a6ba89787"}, "unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"}, - "uniq": {:hex, :uniq, "0.6.1", "369660ecbc19051be526df3aa85dc393af5f61f45209bce2fa6d7adb051ae03c", [:mix], [{:ecto, "~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm", "6426c34d677054b3056947125b22e0daafd10367b85f349e24ac60f44effb916"}, - "webhoox": {:hex, :webhoox, "0.3.0", "96d015a4f4493074febf208276efbd9a07303492035abd38257ea10ecb116c18", [:mix], [{:plug, "~> 1.15.2", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "81f4f77c6652b81287dade96166461ab558942d192a7714123a77df3e642d5a6"}, } From 595fcfc47f36f2c5233898c7c881ce63120efbe7 Mon Sep 17 00:00:00 2001 From: Chase Pursley Date: Fri, 21 Jun 2024 12:01:54 -0400 Subject: [PATCH 3/4] Depreciate Destinations - take 3. --- .../{destinations => events}/event_modules.ex | 2 +- .../destinations.ex => events/events.ex} | 8 ++++---- lib/walex/{destinations => events}/supervisor.ex | 8 ++++---- lib/walex/replication/publisher.ex | 6 +++--- lib/walex/supervisor.ex | 4 ++-- test/walex/config/registry_test.exs | 6 ++---- test/walex/event/event_dsl_test.exs | 12 ++++++------ test/walex/event/event_test.exs | 14 +++++++------- 8 files changed, 29 insertions(+), 31 deletions(-) rename lib/walex/{destinations => events}/event_modules.ex (96%) rename lib/walex/{destinations/destinations.ex => events/events.ex} (86%) rename lib/walex/{destinations => events}/supervisor.ex (85%) diff --git a/lib/walex/destinations/event_modules.ex b/lib/walex/events/event_modules.ex similarity index 96% rename from lib/walex/destinations/event_modules.ex rename to lib/walex/events/event_modules.ex index b6556d5..e958e0a 100755 --- a/lib/walex/destinations/event_modules.ex +++ b/lib/walex/events/event_modules.ex @@ -1,4 +1,4 @@ -defmodule WalEx.Destinations.EventModules do +defmodule WalEx.Events.EventModules do @moduledoc """ Process events (call modules containing process functions) """ diff --git a/lib/walex/destinations/destinations.ex b/lib/walex/events/events.ex similarity index 86% rename from lib/walex/destinations/destinations.ex rename to lib/walex/events/events.ex index 1fcb66c..de0a406 100644 --- a/lib/walex/destinations/destinations.ex +++ b/lib/walex/events/events.ex @@ -1,13 +1,13 @@ -defmodule WalEx.Destinations do +defmodule WalEx.Events do @moduledoc """ - Process destinations + Process events """ use GenServer - alias WalEx.{Destinations, Config} + alias WalEx.{Events, Config} alias Config.Registry - alias Destinations.EventModules + alias Events.EventModules def start_link(opts) do name = diff --git a/lib/walex/destinations/supervisor.ex b/lib/walex/events/supervisor.ex similarity index 85% rename from lib/walex/destinations/supervisor.ex rename to lib/walex/events/supervisor.ex index 8eb4d49..75a574f 100644 --- a/lib/walex/destinations/supervisor.ex +++ b/lib/walex/events/supervisor.ex @@ -1,11 +1,11 @@ -defmodule WalEx.Destinations.Supervisor do +defmodule WalEx.Events.Supervisor do @moduledoc false use Supervisor alias WalEx.Config - alias WalEx.Destinations - alias Destinations.EventModules + alias WalEx.Events + alias Events.EventModules def start_link(opts) do app_name = Keyword.get(opts, :name) @@ -21,7 +21,7 @@ defmodule WalEx.Destinations.Supervisor do |> Keyword.get(:name) children = - [{Destinations, app_name: app_name}] + [{Events, app_name: app_name}] |> maybe_event_modules(app_name) Supervisor.init(children, strategy: :one_for_one, max_restarts: 10) diff --git a/lib/walex/replication/publisher.ex b/lib/walex/replication/publisher.ex index 327557d..b128777 100644 --- a/lib/walex/replication/publisher.ex +++ b/lib/walex/replication/publisher.ex @@ -1,10 +1,10 @@ defmodule WalEx.Replication.Publisher do @moduledoc """ - Publishes messages from Replication to Events & Destinations + Publishes messages from Replication to Events """ use GenServer - alias WalEx.{Changes, Config, Destinations, Types} + alias WalEx.{Changes, Config, Events, Types} alias WalEx.Decoder.Messages defmodule(State, @@ -72,7 +72,7 @@ defmodule WalEx.Replication.Publisher do %State{transaction: {current_txn_lsn, txn}, relations: _relations} = state ) when commit_lsn == current_txn_lsn do - Destinations.process(txn, app_name) + Events.process(txn, app_name) state end diff --git a/lib/walex/supervisor.ex b/lib/walex/supervisor.ex index 7d83288..9a1c4a4 100755 --- a/lib/walex/supervisor.ex +++ b/lib/walex/supervisor.ex @@ -4,7 +4,7 @@ defmodule WalEx.Supervisor do use Supervisor alias WalEx.Config, as: WalExConfig - alias WalEx.Destinations.Supervisor, as: DestinationsSupervisor + alias WalEx.Events.Supervisor, as: EventsSupervisor alias WalEx.Replication.Supervisor, as: ReplicationSupervisor alias WalExConfig.Registry, as: WalExRegistry @@ -69,7 +69,7 @@ defmodule WalEx.Supervisor do [ {WalExConfig, configs: configs}, - {DestinationsSupervisor, configs}, + {EventsSupervisor, configs}, {ReplicationSupervisor, app_name: app_name} ] end diff --git a/test/walex/config/registry_test.exs b/test/walex/config/registry_test.exs index 45cd4b4..115f4bf 100644 --- a/test/walex/config/registry_test.exs +++ b/test/walex/config/registry_test.exs @@ -57,7 +57,7 @@ defmodule WalEx.Config.RegistryTest do assert GenServer.whereis( WalExRegistry.set_name( :set_supervisor, - WalEx.Destinations.Supervisor, + WalEx.Events.Supervisor, :test_name ) ) @@ -72,9 +72,7 @@ defmodule WalEx.Config.RegistryTest do ) |> is_pid() - assert GenServer.whereis( - WalExRegistry.set_name(:set_gen_server, WalEx.Destinations, :test_name) - ) + assert GenServer.whereis(WalExRegistry.set_name(:set_gen_server, WalEx.Events, :test_name)) |> is_pid() assert GenServer.whereis( diff --git a/test/walex/event/event_dsl_test.exs b/test/walex/event/event_dsl_test.exs index 83f3efc..0856c23 100644 --- a/test/walex/event/event_dsl_test.exs +++ b/test/walex/event/event_dsl_test.exs @@ -2,8 +2,8 @@ defmodule WalEx.EventDslTest do use ExUnit.Case, async: false import WalEx.Support.TestHelpers - alias WalEx.Destinations.EventModules, as: DestinationsEventModules - alias WalEx.Destinations.Supervisor, as: DestinationsSupervisor + alias WalEx.Events.EventModules, as: EventsEventModules + alias WalEx.Events.Supervisor, as: EventsSupervisor alias WalEx.Supervisor, as: WalExSupervisor @app_name :test_app @@ -36,12 +36,12 @@ defmodule WalEx.EventDslTest do supervisor_pid: supervisor_pid, database_pid: database_pid } do - destinations_supervisor_pid = find_child_pid(supervisor_pid, DestinationsSupervisor) + destinations_supervisor_pid = find_child_pid(supervisor_pid, EventsSupervisor) assert is_pid(destinations_supervisor_pid) events_pid = - find_child_pid(destinations_supervisor_pid, DestinationsEventModules) + find_child_pid(destinations_supervisor_pid, EventsEventModules) assert is_pid(events_pid) @@ -69,12 +69,12 @@ defmodule WalEx.EventDslTest do supervisor_pid: supervisor_pid, database_pid: database_pid } do - destinations_supervisor_pid = find_child_pid(supervisor_pid, DestinationsSupervisor) + destinations_supervisor_pid = find_child_pid(supervisor_pid, EventsSupervisor) assert is_pid(destinations_supervisor_pid) events_pid = - find_child_pid(destinations_supervisor_pid, DestinationsEventModules) + find_child_pid(destinations_supervisor_pid, EventsEventModules) assert is_pid(events_pid) diff --git a/test/walex/event/event_test.exs b/test/walex/event/event_test.exs index ebe09ba..5c8ff07 100644 --- a/test/walex/event/event_test.exs +++ b/test/walex/event/event_test.exs @@ -2,8 +2,8 @@ defmodule WalEx.EventTest do use ExUnit.Case, async: false import WalEx.Support.TestHelpers - alias WalEx.Destinations.EventModules, as: DestinationsEventModules - alias WalEx.Destinations.Supervisor, as: DestinationsSupervisor + alias WalEx.Events.EventModules, as: EventsEventModules + alias WalEx.Events.Supervisor, as: EventsSupervisor alias WalEx.Supervisor, as: WalExSupervisor alias WalEx.Replication.Supervisor, as: ReplicationSupervisor alias WalEx.Replication.Publisher, as: ReplicationPublisher @@ -38,12 +38,12 @@ defmodule WalEx.EventTest do database_pid: database_pid, supervisor_pid: supervisor_pid } do - destinations_supervisor_pid = find_child_pid(supervisor_pid, DestinationsSupervisor) + destinations_supervisor_pid = find_child_pid(supervisor_pid, EventsSupervisor) assert is_pid(destinations_supervisor_pid) events_pid = - find_child_pid(destinations_supervisor_pid, DestinationsEventModules) + find_child_pid(destinations_supervisor_pid, EventsEventModules) assert is_pid(events_pid) @@ -89,11 +89,11 @@ defmodule WalEx.EventTest do database_pid: database_pid, supervisor_pid: supervisor_pid } do - destinations_supervisor_pid = find_child_pid(supervisor_pid, DestinationsSupervisor) + destinations_supervisor_pid = find_child_pid(supervisor_pid, EventsSupervisor) assert is_pid(destinations_supervisor_pid) - events_pid = find_child_pid(destinations_supervisor_pid, DestinationsEventModules) + events_pid = find_child_pid(destinations_supervisor_pid, EventsEventModules) assert is_pid(events_pid) @@ -123,7 +123,7 @@ defmodule WalEx.EventTest do :timer.sleep(1000) new_events_pid = - find_child_pid(destinations_supervisor_pid, DestinationsEventModules) + find_child_pid(destinations_supervisor_pid, EventsEventModules) assert is_pid(new_events_pid) refute events_pid == new_events_pid From 7dc4ae3ed53f12f1b4cbb0ba823e7674493c7a15 Mon Sep 17 00:00:00 2001 From: Chase Pursley Date: Fri, 21 Jun 2024 12:06:10 -0400 Subject: [PATCH 4/4] [BREAKING] 4.0.0 release. --- README.md | 2 +- mix.exs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 2467383..c382675 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ by adding `walex` to your list of dependencies in `mix.exs`: ```elixir def deps do [ - {:walex, "~> 3.8.0"} + {:walex, "~> 4.0.0"} ] end ``` diff --git a/mix.exs b/mix.exs index 4532e08..3a7f1e6 100644 --- a/mix.exs +++ b/mix.exs @@ -4,7 +4,7 @@ defmodule WalEx.MixProject do def project do [ app: :walex, - version: "3.8.0", + version: "4.0.0", elixir: "~> 1.15", build_embedded: Mix.env() == :prod, start_permanent: Mix.env() == :prod,