lib/storage/adapters/genserver_adapter/create_portal.ex

defmodule Sorcery.Storage.GenserverAdapter.CreatePortal do
  @moduledoc """
  Pure functions for pulling a list of entities out of a portal.
  """
  use Norm
  alias Sorcery.Specs.Primative, as: T
  alias Sorcery.Specs.Portals, as: PT
  alias Sorcery.Storage.GenserverAdapter.Specs, as: AdapterT
  alias Sorcery.Storage.GenserverAdapter.ViewPortal


  def create_portal_map(attrs, pid) do
    attrs
    |> Map.put(:pid, pid)
    |> Sorcery.Portal.new()
    |> Map.from_struct()
  end


  @doc """
  This operation iterates over every presence, and does 2 things:
    1. solves the resolved guards
    2. Solves the indices
  """
  def parse_portal(portal, state) do
    portal
    |> resolve_guards(state)
    |> solve_indexes(state)
  end


  defp resolve_guard({:or, guards}, state) do
    values = Enum.map(guards, fn g -> resolve_guard(g, state) end)
    {:or, values}
  end
  defp resolve_guard({:in, attr, {ref, ref_attr}}, state) do
    ref_values = ViewPortal.view_portal(ref, state)
                |> Enum.map(fn {_, e} -> Map.get(e, ref_attr) end)
                |> MapSet.new()
    {:in, attr, ref_values}
  end
  defp resolve_guard(guard, _state), do: guard
  defp resolve_guards(portal, state) do
    resolved_guards = Enum.map(portal.guards, fn guard -> resolve_guard(guard, state) end)
    Map.put(portal, :resolved_guards, resolved_guards)
  end

  defp solve_indexes(portal, state) do
    entities = ViewPortal.view_portal(portal, state)
    Enum.reduce(portal.indices, portal, fn {attr, _}, acc ->
      index = rebuild_index(attr, entities)
      put_in(acc, [:indices, attr], index)
    end)
  end

  defp rebuild_index(attr, entities) do
    Enum.map(entities, fn {_id, entity} -> Map.get(entity, attr) end)
    |> MapSet.new()
  end

end