BeniaminoBaggins
BeniaminoBaggins

Reputation: 12433

Elixir ensure value is not 0 or nil

In this function, I need to check if the "price" variable is 0 or nil before I convert it into a float by doing priceFloat = price / 1, or I get an arithmetic error.

  def insert_product_shop(conn, product_id, shop_id, price) do
    IO.inspect(price, label: "price")
    priceFloat = price / 1 
    changeset = Api.ProductShop.changeset(%Api.ProductShop{p_id: product_id, s_id: shop_id, not_in_shop_count: 0, price: priceFloat})
    errors = changeset.errors
    valid = changeset.valid?
    case insert(changeset) do
      {:ok, product_shop} ->
        {:ok, product_shop}
      {:error, changeset} ->
        {:error, :failure}
    end
  end

What is an idiomatic way to do so?

I tried this but I still get the arithmetic error:

  def insert_product_shop(conn, product_id, shop_id, price) do
    IO.inspect(price, label: "price")
    case {price} do 
      {price} when price > 0 ->
        priceFloat = price / 1 
        changeset = Api.ProductShop.changeset(%Api.ProductShop{p_id: product_id, s_id: shop_id, not_in_shop_count: 0, price: priceFloat})
        errors = changeset.errors
        valid = changeset.valid?
        case insert(changeset) do
          {:ok, product_shop} ->
            {:ok, product_shop}
          {:error, changeset} ->
            {:error, :failure}
        end
      end
  end

Upvotes: 1

Views: 4814

Answers (2)

Aleksei Matiushkin
Aleksei Matiushkin

Reputation: 121000

The idiomatic way to do this would be to pattern match directly in function clauses:

def insert_product_shop(conn, product_id, shop_id, price)
  when not is_number(price), do: {:error, :nil}
def insert_product_shop(conn, product_id, shop_id, price)
  when price <= 0, do: {:error, :not_positive}
def insert_product_shop(conn, product_id, shop_id, price) do
  priceFloat = price / 1
  changeset = 
    Api.ProductShop.changeset(
      %Api.ProductShop{p_id: product_id,
                       s_id: shop_id,
                       not_in_shop_count: 0,
                       price: priceFloat})
  errors = changeset.errors
  valid = changeset.valid?

  case insert(changeset) do
    {:ok, product_shop} ->
      {:ok, product_shop}
    {:error, changeset} ->
      {:error, :failure}
  end
end

First two clauses might be collapsed into one with a guard

when not is_number(price) or price <= 0

Upvotes: 3

Dogbert
Dogbert

Reputation: 222060

The reason your code doesn't work is because in Elixir, nil > 0 is true. You can do this instead:

if price not in [0, nil] do
  ...
else
  ...
end

or

if is_number(price) and price > 0 do
  ...
else
  ...
end

Upvotes: 6

Related Questions