Use one case statement value inside another statement

I want to use the value inside one case statement into an other . This is my code

   select when is_map(select) ->
        query = from(p in queryable, select: %{})

        fields =
          Enum.reduce(select, [], fn {key, value}, fields ->
            Enum.reduce(value, query, fn {k, v}, query ->
              case k do
                "$avg" ->
                  val = Enum.at(v, 0)

                  query =
                    from(
                      p in query,
                      select_merge: %{avg: avg(field(p, ^String.to_atom(val)))}
                    )

                "$count" ->
                  val = Enum.at(v, 0)

                  query =
                    from(
                      p in query,
                      select_merge: %{count: count(field(p, ^String.to_atom(val)))}
                    )

                "$min" ->
                  val = Enum.at(v, 0)

                  query =
                    from(
                      p in query,
                      select_merge: %{min: min(field(p, ^String.to_atom(val)))}
                    )

                "$max" ->
                  val = Enum.at(v, 0)

                  query =
                    from(
                      p in query,
                      select_merge: %{max: max(field(p, ^String.to_atom(val)))}
                    )

                "$sum" ->
                  val = Enum.at(v, 0)

                  query =
                    from(
                      p in query,
                      select_merge: %{sum: sum(field(p, ^String.to_atom(val)))}
                    )

                "$fields" ->
                  fields = Enum.map(v, &String.to_atom/1)
                  query
              
                _ ->
               relation_name = String.to_atom(k)
             

             

               case queryable.__schema__(:association, relation_name) do
                %Ecto.Association.Has{
                   owner: _owner,
                   owner_key: owner_key,
                   related: _related,
                   related_key: _related_key
                } ->
                  va = fields ++
                    [owner_key] ++
                     [{relation_name, Enum.map(v, &String.to_existing_atom/1)}]
                     query =  from p in query, select_merge: %{asso_field: ^va}

                 %Ecto.Association.BelongsTo{
                   owner: _owner,
                   owner_key: owner_key,
                   related: _related,
                   related_key: _related_key
                 } ->
                   va = fields ++
                     [owner_key] ++
                     [{relation_name, Enum.map(v, &String.to_existing_atom/1)}]
                     query =  from p in query, select_merge: %{asso_field: ^va}
          end
        end)
       end)
    end

I want to use the fields variable in $fields inside the _ statement. Is it possible? How can it be achieved?

Any work around may be?
Any help will be much appreciated
Thanks

You can not access fields on the right hand side of =, since everything you do on the right hand side of = is actually to create a value for fields.

Can you get a little bit more into detail, why you want to do that? Perhaps we can find a solution if we knew more about what your goal is?

1 Like

I just updated the question with the additional code. I am building up a select query using select merge. I need fields list to build up a query with the associated model. but i am not getting the fields value and its setting empty in the query. The code works fine but the fields value is empty . and thats the last piece of the puzzle. How to access it. I am using fields inside the outer Enum. Hoping that it will accessed every where. But its empty not updating…

Oh, I do only realise now that you named your accumulator of the outer reduce fields as well. I though you were talking about the fields you are binding the result of the expression to.

But as far as I can see on a first glance, your inner reduce does always return some ecto-query, so the current value of fields will always be the query from the last run as I understand your current code.

yes because it return query . It not setting the fields value for outer fields accumulator. So any suggestions ?

I could be misunderstanding your question but it sounds like you are referring to this particular section:

"$fields" -> 
  fields = Enum.map(v, &String.to_atom/1) 
  query 
_ -> 
  relation_name = String.to_atom(k)

The short answer is no.

Unless "$fields" is evaluated before _. In that case you can store the “last fields value” in the accumulator by using a tuple (in the entire reduce).

Instead of accumulating query, accumulate {query,fields_value} e.g.:

Enum.reduce(value, {query,nil}, fn {k, v}, {query, fields_value} ->
...
    "$sum" ->
       val = Enum.at(v, 0)

       query =
         from(
           p in query,
           select_merge: %{sum: sum(field(p, ^String.to_atom(val)))}
         )
       {query, fields_value}

    "$fields" -> 
      fields = Enum.map(v, &String.to_atom/1) 
      {query, fields}

    _ -> 
      relation_name = String.to_atom(k)
                ... = fields_value

Question: What is v? In particular, why are you using Enum.at(v, 0)? If v is a list then there is hd/1.

1 Like

If you make a complete mini-project on GitHub demonstrating the problem then I’ll be willing to help you.

2 Likes