If condition for a variable > 0 not working

I have a column in my Postgres Database named “adjust_expense_from_income” data_type Decimal, I have retrieved the card details by triggering the function

cards = GameOfFortune.Repo.all(query)

which provides me all the cards as I need. In the template view, I have to check the “adjust_expense_from_income” if it is zero then show different edit links else show another edit link. But it is always going to If condition and not in the else condition. Out of 10 rows in my cards 7 rows contain value as zero for the column name " adjust_expense_from_income" and rest 3 have “adjust_expense_from_income” > zero but it not working as I expect why?

Below is the code of my view

<%= if card.adjust_expense_from_income >0  do %>
<%= link "Edit", to: Routes.admin_path(@conn, :edit_debt_card_adjust_income,card.id), class: "" %>
<% else %>
<%= link "Edit", to: Routes.admin_path(@conn, :edit_debt_card_single,card.id), class: "" %>
<% end %>

Do you get any errors?

Can you add <%= IO.inspect(card.adjust_expense_from_income) %> above the if block?

So you should be using Decimal.gt/2

but it not working as I expect why?

https://elixir-lang.org/getting-started/basic-operators.html#basic-operators

The reason we can compare different data types is pragmatism. Sorting algorithms don’t need to worry about different data types in order to sort. The overall sorting order is defined below:

number < atom < reference < function < port < pid < tuple < map < list < bitstring

Ultimately Decimal is a struct, which at the core is a map which will always be greater than a number which is what 0 is.

3 Likes

I have print the column value it has values either as 0 for most of the rows while some rows has values like 0.5 or 0.25 or 0.35.

My requirement is to show different link for the rows having column “adjust_income_from_expense” > 0 otherwise different link.

Is that possible? How should I achieve it. Please provide me sample code for it…

$ iex -S mix
Erlang/OTP 22 [erts-10.5.3] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [hipe] [dtrace]

==> decimal
Compiling 1 file (.ex)
Generated decimal app
==> dec
Compiling 1 file (.ex)
Generated dec app
Interactive Elixir (1.9.2) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> positive = Decimal.new("0.25")
#Decimal<0.25>
iex(2)> zero = Decimal.new(0)
#Decimal<0>
iex(3)> Decimal.gt?(positive,"0")
true
iex(4)> Decimal.gt?(zero, "0")
false
iex(5)> positive > 0
true
iex(6)> zero > 0    
true
iex(7)>

So

<%= if Decimal.gt?(card.adjust_expense_from_income, 0) do %>
  <%= link "Edit", to: Routes.admin_path(@conn, :edit_debt_card_adjust_income,card.id), class: "" %>
<% else %>
  <%= link "Edit", to: Routes.admin_path(@conn, :edit_debt_card_single,card.id), class: "" %>
<% end %>

Note: The Decimal module functions tend to accept the decimal() sum (union) type which is defined as:
decimal() :: t() | integer() | String.t() i.e.:

  • a Decimal.t struct,
  • an integer or
  • a string (to be parsed as a decimal number)

How can I use my own function created in the card module so that I just call the function instead of applying if… else condition in template view. Let’s say if I create a function in the card module as shown below:

def get_debt_card_type(card) do
    case do
    card.option_two_description && card.option_one_description ->
        :double_option
      Decimal.gt?(card.adjust_expense_from_income, 0) ->
        :adjust_income
      _ ->
        :single_option
    end
  end

When I created this function it giving me an error shown below:
" the function “case” cannot handle clauses with the -> operator because it is not a macro "
How can I make it correct and second how can I call it in my view where I am using if … else clause.

A case requires a match in the clauses, and also as first argument something it should match on.

It seems as if you want to use cond instead.

1 Like

To demonstrate:

# hello/lib/hello/domain/card.ex
defmodule Hello.Domain.Card do
  alias __MODULE__

  defstruct(
    option_one_description: nil,
    option_two_description: nil,
    adjust_expense_from_income: Decimal.new(0)
  )

  def new() do
    %Card{}
  end

  def new(one, two, value) do
    %Card{
      option_one_description: one,
      option_two_description: two,
      adjust_expense_from_income: value
    }
  end

  def get_debt_card_type(%Card{
        option_one_description: one,
        option_two_description: two,
        adjust_expense_from_income: value
      }) do
    cond do
      two && one ->
        :double_option

      Decimal.gt?(value, 0) ->
        :adjust_income

      true ->
        :single_option
    end
  end
end
# hello/lib/hello_web/controllers/page_controller.ex
defmodule HelloWeb.PageController do
  use HelloWeb, :controller

  def index(conn, _params) do
    list = [
      Hello.Domain.Card.new("", "", Decimal.new(0)),
      Hello.Domain.Card.new(nil, nil, Decimal.new("0.25")),
      Hello.Domain.Card.new()
    ]

    render(conn, "index.html", cards: list)
  end
end
# hello/lib/hello_web/views/page_view.ex
defmodule HelloWeb.PageView do
  use HelloWeb, :view

  # added 
  alias Hello.Domain.Card

  def debt_card_link(conn, card) do
    case Card.get_debt_card_type(card) do
      :double_option ->
        link("Double", to: Routes.page_path(conn, :index))

      :adjust_income ->
        link("Adjust", to: Routes.page_path(conn, :index))

      _ ->
        link("Single", to: Routes.page_path(conn, :index))
    end
  end
end
<!-- hello/lib/hello_web/templates/page/index.html.eex -->
<section>
  <%= for card <- @cards do %>
    <p><%= debt_card_link(@conn, card) %></p>
  <% end %>
</section>