# `Ash.Notifier.PubSub`
[🔗](https://github.com/ash-project/ash/blob/v3.23.1/lib/ash/notifier/pub_sub/pub_sub.ex#L5)

A builtin notifier to help you publish events over any kind of pub-sub tooling.

This is plug and play with `Phoenix.PubSub`, but could be used with any pubsub system.

You configure a module that defines a `broadcast/3` function, and then add some "publications"
which configure under what conditions an event should be sent and what the topic should be.

## Example

```elixir
defmodule MyApp.User do
  use Ash.Resource,
    # ...
    notifiers: [Ash.Notifier.PubSub]

  # ...

  pub_sub do
    module MyAppWeb.Endpoint

    prefix "user"
    publish :update, ["updated", :_pkey]
  end
end
```

## Debugging PubSub

It can be quite frustrating when setting up pub_sub when everything appears to be set up properly, but
you aren't receiving events. This usually means some kind of mismatch between the event names produced
by the resource/config of your publications, and you can use the following flag to display debug
information about all pub sub events.

```elixir
config :ash, :pub_sub, debug?: true
```

## Topic Templates

Often you want to include some piece of data in the thing being changed, like the `:id` attribute. This
is done by providing a list as the topic, and using atoms which will be replaced by their corresponding
values. They will ultimately be joined with `:`.

For example:

```elixir
prefix "user"

publish :create, ["created", :user_id]
```

This might publish a message to "user:created:1" for example.

For updates, if the field in the template is being changed, a message is sent
to *both* values. So if you change `user 1` to `user 2`, the same message would
be published to `user:updated:1` and `user:updated:2`. If there are multiple
attributes in the template, and they are all being changed, a message is sent for
every combination of substitutions.

## Important

If the previous value was `nil` or the field was not selected on the data passed into the action, then a
notification is not sent for the previous value.

If the new value is `nil` then a notification is not sent for the new value.

## Template parts

Templates may contain lists, in which case all combinations of values in the list will be used. Add
`nil` to the list if you want to produce a pattern where that entry is omitted.

The atom `:_tenant` may be used. If the changeset has a tenant set on it, that
value will be used, otherwise that combination of values is ignored.

The atom `:_pkey` may be used. It will be a stringified, concatenation of the primary key fields,
or just the primary key if there is only one primary key field.

The atom `nil` may be used. It only makes sense to use it in the context of a list of alternatives,
and adds a pattern where that part is skipped.

```elixir
publish :updated, [[:team_id, :_tenant], "updated", [:id, nil]]
```

Would produce the following messages, given a `team_id` of 1, a `tenant` of `org_1`, and an `id` of `50`:

```elixir
"1:updated:50"
"1:updated"
"org_1:updated:50"
"org_1:updated"
```

## Custom Delimiters

It's possible to change the default delimiter used when generating topics. This is useful when working with message brokers
like RabbitMQ, which rely on a different set of delimiters for routing.

```elixir
pub_sub do
  delimiter "."
end
```

## Named Pubsub modules

If you are using a phoenix `Endpoint` module for pubsub then this is unnecessary. If you want to use a custom pub sub started
with something like `{Phoenix.PubSub, name: MyName}`, then you can provide `MyName` to here.

## Broadcast Types

Configured with `broadcast_type`.

- `:notification` just sends the notification
- `:phoenix_broadcast` sends a `%Phoenix.Socket.Broadcast{}` (see above)
- `:broadcast` sends `%{topic: (topic), event: (event), payload: (notification)}`

## Loading data before broadcast

Publications support a `load` option that declares fields to load onto `notification.data`
before the notification is broadcast. This is useful when a `transform` or `filter` function,
or a subscriber, needs access to related data that is not present on the record returned by
the action.

The value is any load statement accepted by `Ash.Query.load/2`.

```elixir
pub_sub do
  module MyAppWeb.Endpoint
  prefix "post"

  publish :create, "created", load: [:comment, author: [:full_name]]
  publish :update, ["updated", :id], load: [:comment, author: [:full_name]]
end
```

Different publications on the same resource can request different loads. Loads that are
identical across publications are deduplicated and fetched only once.

# `pub_sub`
*macro* 

# `to_payload`

---

*Consult [api-reference.md](api-reference.md) for complete listing*
