lib/src/utils.ex

defmodule Sorcery.Src.Utils do
  use Norm
  alias Sorcery.Specs.Primative, as: T


  @contract remove_dels_from_db(T.db(), coll_of({T.tk(), T.id()})) :: T.db()
  def remove_dels_from_db(db, dels) do
    Enum.reduce(dels, db, fn {tk, id}, acc ->
      case Map.get(acc, tk) do
        nil -> acc
        table -> 
          table = Map.delete(table, id)
          Map.put(acc, tk, table)
      end
    end)
  end


  @contract all_ids(T.src(), T.tk()) :: coll_of(T.id())
  def all_ids(%{original_db: db1, changes_db: db2, deletes: dels}, tk) do
    db1 = remove_dels_from_db(db1, dels)
    db2 = remove_dels_from_db(db2, dels)
    table1 = Map.get(db1, tk, %{})
    table2 = Map.get(db2, tk, %{})
    ids1 = Map.keys(table1) |> MapSet.new()
    ids2 = Map.keys(table2) |> MapSet.new()
    MapSet.union(ids1, ids2)
    |> MapSet.to_list()
  end


  @contract entities_set(T.src()) :: coll_of({T.tk(), T.id()})
  def entities_set(%{original_db: og, changes_db: ch, deletes: del}) do
    delset = MapSet.new(del)
    oset = Enum.reduce(og, MapSet.new(), fn {tk, table}, acc ->
      ids = Map.keys(table)
      Enum.reduce(ids, acc, fn id, acc -> MapSet.put(acc, {tk, id}) end)
    end)
    Enum.reduce(ch, oset, fn {tk, table}, acc ->
      ids = Map.keys(table)
      Enum.reduce(ids, acc, fn id, acc -> MapSet.put(acc, {tk, id}) end)
    end)
    |> MapSet.difference(delset)
  end


end