Pattern mathing :ok :error atoms from map not resulting in matchs

I have a mnesia with memento table following this struct

  use Memento.Table,
  attributes: [:c_identifier, :status, :contract_info],
  index: [:status],
  type: :set

I have this query that returns the a struct made of tuples, and them put the tuple into a map to be returned

  def get_record_by_pk(pk) do
    case Memento.transaction(fn ->
           Memento.Query.read(MnesiaContract, pk)
         end) do
      {:ok, nil} ->
        Logger.debug("1")
        {:error, :not_found}

      {:ok, %MnesiaContract{c_identifier: c_identifier, status: status, contract_info: contract_info}} ->
        extracted_map = %{
          c_identifier: c_identifier,
          status: status,
          contract_info: contract_info
        }
        Logger.debug("Extracted map: #{inspect(extracted_map)}")
          {:ok, extracted_map}

      {:error, reason} ->
        Logger.debug("2")
        {:error, reason}
    end
  end

status is a atom that can be error, or ok, registered by this module

defmodule Testespay.Genservers.ContractTask do
  @state_approved :approved
  @state_error :error
  alias Testespay.DataLayer.MnesiaDomain
  alias Testespay.Resources.RamContract
require Logger
  def populate2_async(request_map) do
   with {:ok, ram_contract} <- Contract.populate2(request_map),
        {:ok, _} <-  MnesiaDomain.insert_record(request_map["payload"], @state_approved, ram_contract) do
          Logger.debug("cfinfo")
          Logger.debug(inspect(ram_contract))
        else
          {:error, reason} ->
            MnesiaDomain.insert_record(request_map["payload"], @state_error, reason)
        end
  end
end

but when I try to pattern match the atom, no matter it doesnt
I already tried map matching


  def record_handle(record) do
    Logger.debug(is_map(record))
    IO.inspect(record)
    Logger.debug(record)
    case record do
      %{"status" => :ok, "reason" => reason} ->
          {:ok, reason} ##reason as contract
      %{"status" => :error, "reason" => reason} ->
        {:error, reason}
      _ ->
        {:error, "Formato de registro inválido"}
    end
  end

or pure

def record_handle(record) do
    Logger.debug(is_map(record))
    IO.inspect(record)
    Logger.debug(record)
    status = record["status"]
    case status do
      :ok ->
          {:ok, record[]} ##reason as contract

      :error ->
        {:error, reason}

      _ ->
        {:error, "Formato de registro inválido"}
    end
  end

calling code

defmodule TestespayWeb.Identify.Service do
  @doc """
  module responsible to find contract on cache on db, all contracts are live on system as ram_contracts (no privkey and only transactions usefull record)
  ram_contract has payhload as pk to be found on cache, after this pk is swapped to pubkey bcs payload are no more usefull
  """
  alias Testespay.Utils.FormatError
  alias Testespay.Schemas.Contract
  alias Testespay.Resources.RamContract
  alias Testespay.DataLayer.{MnesiaDomain, EctoContractDomain}
  require Logger

  @spec get_ram_contract_all_sourcs(pk :: String.t()) ::
          {:ok, contract: map()} | {:error,map()}



  def get_ram_contract_all_sourcs(pk) do
    case get_mnesia_record(pk) do
      {:ok, contract} ->
        {:ok, contract}
      {:error, _} ->
        get_mnesia_record(pk)
    end
  end

  def get_mnesia_record(pk) do
    case MnesiaDomain.get_record_by_pk(pk) do
      {:ok, record} ->
        Logger.info("Contract found in cache")
        record_handle(record)
      {:error, _reason} ->
        Logger.info("Contract not found in cache, querying database") ##consertar pra evitar bugs alem de not found in ca che, pode passar mt coisa
        pk
    end
  end

  def get_db_contract_payloadpk(pk) do
    case EctoContractDomain.get_contract_with_payload(pk, :ram_contract) do
      {:ok, contract} ->
        Logger.info("Contract found in database")
        record_handle(contract)

      {:error, reason} ->
        Logger.error("Contract not found in cache or database: #{inspect(reason)}")
        {:error, "Contract not found"}
        {:error, FormatError.initerror("db", "contrato não encontrado no banco de dados")}
    end
  end

  def get_db_contract_payload_aspk({:ok, contract}) do
    {:ok, contract}
  end

  def record_handle(record) do
    Logger.debug(is_map(record))
    IO.inspect(record)
    Logger.debug(record)
    status = record["status"]
    case status do
      :ok ->
          {:ok, record[]} ##reason as contract

      :error ->
        {:error, reason}

      _ ->
        {:error, "Formato de registro inválido"}
    end
  end

end

my controller in case its usefull

defmodule TestespayWeb.IdentifyController do
  alias TestespayWeb.Identify.Service, as: ControllerService
  require Logger
  use TestespayWeb, :controller

  def find(conn, %{"payload" => payload}) do
    with {:ok, ram_contrac} <- ControllerService.get_ram_contract_all_sourcs(payload) do

      conn
      |> put_resp_content_type("application/json")
      |> send_resp(200, map_tojson(ram_contrac))
    else
      {:error, reason} ->
        conn
        |> put_resp_content_type("application/json")
        |> send_resp(404, map_tojson(reason))
    end
  end

logs:

[debug] Extracted map: %{status: :error, contract_info: %{"field" => :payload, "msg" => "has already been taken"}, c_identifier: "00020126580014br.gov.bcb.pix0136ab09d852-14bd-43ac-91eb-d38b717e6aea520400005303986540534.005802BR5914Pedro Henrique6005Macae62290525PEDROHEN00000000568643ASA63049674"}
[info] Contract found in cache
%{
  status: :error,
  contract_info: %{"field" => :payload, "msg" => "has already been taken"},
  c_identifier: "00020126580014br.gov.bcb.pix0136ab09d852-14bd-43ac-91eb-d38b717e6aea520400005303986540534.005802BR5914Pedro Henrique6005Macae62290525PEDROHEN00000000568643ASA63049674"
}
[info] Sent 404 in 814µs

get_ram_contract_all_sourcs its supposed to query the cache and then the db if not found, but I removed some extras to understand why the handle isnt -well- handling the atom compare

The struct you are matching on is like:

So you need to do something like:

iex(1)> %{status: x} = %{other: 1, status: :error}
%{status: :error, other: 1}
iex(2)> x

:error

This won’t work - :status and "status" are not the same:

 iex(3)> %{"status" => x} = %{x: 1, status: :error}
 ** (MatchError) no match of right hand side value: %{status: :error, x: 1}
     (stdlib 4.3) erl_eval.erl:496: :erl_eval.expr/6
     iex:3: (file)

Hope this helps.

1 Like

I couldnt understand your example on iex, can you elaborate in a match body?
the return from mnesia is supposed to be a map (pk, status and info as string keys)

Oh I see now, maybe my map keys are being registered as atoms, so when I try to match on the handle usings string keys to match, it fails

1 Like