cpursley / walex

Postgres change events (CDC) in Elixir
MIT License
276 stars 14 forks source link

Ability to take and apply a list of functions #23

Closed cpursley closed 8 months ago

cpursley commented 8 months ago

The function would take the event data as the arg. Functions could be applied asynchronously.

on_insert(:user, [:clear_cache, :send_email, :send_webhook],
  fn {:ok, user} -> IO.inspect(on_insert: user)
end)

def clear_cache(user) do
  # cache clearing logic here
end

# etc

This is probably a bad idea for a variety of reasons, but might be cool.

themusicman commented 8 months ago

Are you thinking of these like phoenix router pipelines?

cpursley commented 8 months ago

Yeah, kindof. I'm trying to get away from this sort of thing:

on_insert(:user, fn {:ok, user} ->
  clear_cache(user)
  send_email(user)
  send_webhook(user)
  # and possibly many more
end)

Well, I'm doing it like this actually:

on_insert(:user, fn {:ok, user} ->
  ~w(clear_cache send_email send_webhook)a
    |> EventProcessor.process_event_async(appraisal)
end)

# I know, I know
defmodule EventProcessor do
  defmacro process_event_async(functions, event) do
    quote do
      unquote(functions)
      |> Enum.each(fn function ->
        task_fn =
          case function do
            # If function is a tuple, treat it as {Module, function}
            {mod, func} when is_atom(mod) and is_atom(func) ->
              fn -> apply(mod, func, [unquote(event)]) end

            # If function is an atom, treat it as a local function in the current module
            func when is_atom(func) ->
              fn -> apply(__MODULE__, func, [unquote(event)]) end

            _ ->
              raise ArgumentError, "Invalid function spec: #{inspect(function)}"
          end

        Task.start(task_fn)
      end)
    end
  end
end
themusicman commented 8 months ago

Yeah. I like the idea. You could even pass a context through all the functions similar to setups in ExUnit.