defmodule Manganese.EntityKit.Structs.EntityReferencesCollection do alias Manganese.EntityKit.Structs alias Manganese.EntityKit.Behaviors @type t :: %Structs.EntityReferencesCollection{ entity_ids: %{ optional(atom) => [ Behaviors.Entity.id ] } } defstruct [ entity_ids: %{} ] # Utilities @doc """ """ @spec new :: t def new, do: %Structs.EntityReferencesCollection{} @doc """ Check if an entity of the given type and ID are referenced in the collection. """ @spec has_entity?(t, atom, pos_integer) :: t def has_entity?(entity_references_collection, entity_type, id) do Enum.member?( Map.get(entity_references_collection.entity_ids, entity_type, []), id ) end @doc """ Add an entity reference to the collection. """ @spec put_entity_id(t, atom, pos_integer) :: t def put_entity_id(entity_references_collection, entity_type, id) do %Structs.EntityReferencesCollection{ entity_ids: entity_references_collection.entity_ids |> Map.put( entity_type, ((Map.get(entity_references_collection.entity_ids, entity_type) || []) ++ [ id ]) |> Enum.uniq ) } end @doc """ Add multiple entity references to the collection. """ @spec put_entity_ids(t, atom, [ pos_integer ]) :: t def put_entity_ids(entity_references_collection, entity_type, ids) do %Structs.EntityReferencesCollection{ entity_ids: entity_references_collection.entity_ids |> Map.put( entity_type, ((Map.get(entity_references_collection.entity_ids, entity_type) || []) ++ ids) |> Enum.uniq ) } end @doc """ """ @spec merge(t, t) :: t def merge(entity_references_collection1, entity_references_collection2) do %Structs.EntityReferencesCollection{ entity_ids: Map.merge( (entity_references_collection1 || %Structs.EntityReferencesCollection{}).entity_ids, (entity_references_collection2 || %Structs.EntityReferencesCollection{}).entity_ids, fn _entity_type, entity_ids1, entity_ids2 -> ((entity_ids1 || []) ++ (entity_ids2 || [])) |> Enum.uniq end ) } end @doc """ """ @spec filter(t, (atom, Behaviors.Entity.id -> boolean)) :: map def filter(entity_references_collection, filter) do end @doc """ """ @spec to_map(t) :: map def to_map(entity_references_collection) do %{ "entity_ids" => entity_references_collection.entity_ids |> Map.new(fn { entity_type, entity_ids_of_type } -> { Atom.to_string(entity_type), entity_ids_of_type } end) } end end defimpl Manganese.EntityKit.Protocols.FilterableCollection, for: Manganese.EntityKit.Structs.EntityReferencesCollection do alias Manganese.EntityKit.Structs def filter(entity_references_collection, filter) do %Structs.EntityReferencesCollection{ entity_ids: entity_references_collection.entity_ids |> Map.new(fn { entity_type, entity_ids_of_type } -> { entity_type, entity_ids_of_type |> Enum.filter(fn entity_id -> filter.(entity_type, entity_id) end) } end) |> Enum.filter(fn { _, entity_ids_of_type } -> !(is_nil(entity_ids_of_type) || (is_list(entity_ids_of_type) && length(entity_ids_of_type) == 0)) end) |> Enum.into(%{}) } end end