Sorcery.LiveHelpers behaviour (sorcery v0.4.15)

Functions for combining Sorcery and LiveViews

Summary

Callbacks

Wherever you keep your handle_info functions, put this:

Puts a :sorcery key in socket.assigns, with a bunch of stuff used behind the scenes by Sorcery.

Get a list of entities at the given portal/lvar You probably want to use this inside heex

Creates a portal between the LiveView and the PortalServer, using the given arguments.

Functions

Get a list of entities at the given lvar.

Types

hook()

@type hook() :: (ElixirLS.LanguageServer.Plugins.Phoenix.LiveView.Socket, map() ->
             {:ok, ElixirLS.LanguageServer.Plugins.Phoenix.LiveView.Socket}
             | {:error, ElixirLS.LanguageServer.Plugins.Phoenix.LiveView.Socket})

socket_type()

@type socket_type() :: %ElixirLS.LanguageServer.Plugins.Phoenix.LiveView.Socket{
  optional(any()) => any(),
  assigns: map()
}

Callbacks

handle_sorcery({}, atom)

@callback handle_sorcery(
  {:sorcery, map()},
  ElixirLS.LanguageServer.Plugins.Phoenix.LiveView.Socket
) :: {:noreply, ElixirLS.LanguageServer.Plugins.Phoenix.LiveView.Socket}

handle_sorcery({}, atom, list)

@callback handle_sorcery(
  {:sorcery, map()},
  ElixirLS.LanguageServer.Plugins.Phoenix.LiveView.Socket,
  [
    hook()
  ]
) :: {:noreply, ElixirLS.LanguageServer.Plugins.Phoenix.LiveView.Socket}

Wherever you keep your handle_info functions, put this:

defmodule MyModule do
  use Sorcery.LiveHelpers

  def handle_info({:sorcery, _} = msg, socket), do: handle_sorcery(msg, socket)
  # If you have any other handle_info's, put them BELOW
end

By doing this, the socket will automatically communicate with the rest of Sorcery. For example whenever we receive new data about a portal, this is where it happens.

You can optionally pass in an options argument, which is handy for writing your own middleware.

defmodule SomeModule do
  def my_func(socket, msg), {:ok, socket}
  def another_func(socket, msg), {:ok, socket}
end

defmodule MyModule do
  use Sorcery.LiveHelpers

  def handle_info({:sorcery, _} = msg, socket), do: handle_sorcery(msg, socket,
    hook_before: [&SomeModule.my_func/2],
    hook_after: [&SomeModule.another_func/2],
  )
end

Note that every middleware function must return a tuple. Either {:ok, socket} or {:error, socket}

In this case, every time the LiveView receives a sorcery message, it will:

  1. Call all the functions in hook_before, in order
  2. Do some sorcery magic behind the scenes
  3. Call all the functions in hook_after, in order

Often in step 2, it will send a message to the parent PortalServer. Then 3 is called before we get a response. "After" means after you SEND the message, not after you RECEIVE a response. So this could take some advanced understanding of how Sorcery works, or a lot of fiddling and pattern matching on msg[:command]

initialize_sorcery(socket, body)

@callback initialize_sorcery(
  socket :: socket_type(),
  body :: %{
    optional(:sorcery_module) => module(),
    optional(:args) => map(),
    optional(:store_adapter) => module()
  }
) :: socket_type()

Puts a :sorcery key in socket.assigns, with a bunch of stuff used behind the scenes by Sorcery.

This is mandatory, before you can spawn any portals

You must pass in the sorcery_module. If you used the generator, it'll just be Src.

Examples

iex> body = %{sorcery_module: Src}
iex> socket = initialize_sorcery(socket, body)

portal_view(sorcery_config, portal_name, lvar)

@callback portal_view(sorcery_config :: map(), portal_name :: atom(), lvar :: binary()) ::
  list()

Get a list of entities at the given portal/lvar You probably want to use this inside heex

<% players = portal_view(@sorcery, :my_portal, "?all_players") %>

spawn_portal(socket, body, opts)

@callback spawn_portal(
  socket :: socket_type(),
  body :: %{
    portal_server: module(),
    portal_name: atom(),
    query_module: module(),
    query_args: map()
  },
  opts :: []
) :: socket_type()

Creates a portal between the LiveView and the PortalServer, using the given arguments.

Takes the socket, returns it unchanged.

Examples

iex> body = %{portal_server: Postgres, portal_name: :my_portal, query_module: MyQuery, query_args: %{player_id: 1}}
iex> socket = spawn_portal(socket, body)

Functions

__using__(_)

(macro)

Get a list of entities at the given lvar.

If this lvar only exists in ONE portal, you can leave out the portal_name, just know that it might be imperceptibly slower since the function needs to iterate over all portals until it finds one with that lvar..

<% players = portal_view(@sorcery, :my_portal, "?all_players") %>