1
votes

I have a nested model and wanted to do some basic piping. My end goal is to remove any nested map where id == "" for the below params:

params = %{"name" => "OuterModelName", "InnerModel" => %{"0" => %{"id" => "2"}, "1" => %{"id" => "3"}, "2" => %{"id" => ""}}}

To remove the id =="" the following pipe works:

blanksRemoved = 
        params 
        |> Map.update! "InnerModel", fn(innerMap) -> 
            Enum.filter(innerMap,fn{k,v} -> byte_size(v["id"]) !=0 end) end

blanksRemoved is now:

%{"name" => "OuterModelName", "InnerModel" => [{"0", %{"id" => "2"}}, {"1", %{"id" => "3"}}]}

Notice the innerModel became an array so I need to turn that array back into a struct.

asStruct = 
      blanksRemoved |> Map.update! "InnerModel", fn(innerMap) -> 
            Enum.into(innerMap,%{}) end 

And that works as intended and I get:

%{"name" => "OuterModelName", "InnerModel" => %{"0" => %{"id" => "2"}, "1" => %{"id" => "3"}}}

However when I try simply combining the two pipes with the below pipe, , I get an error.

combinedPipes = 
        params 
        |> Map.update! "InnerModel", fn(innerMap) -> 
            Enum.filter(innerMap,fn{k,v} -> byte_size(v["id"]) !=0 end) end
        |> Map.update! "InnerModel", fn(innerMap) -> 
            Enum.into(innerMap,%{}) end 

And the error:

argument error
    (stdlib) :maps.find("InnerModel", #Function<2.64012156

I know the error is because it can't find "InnerModel" but I don't know why it can't find that when it's working when I separate the pipes. Can someone tell me what's going on here?

1
keep in mind that [{"0", %{"id" => "2"}}, {"1", %{"id" => "3"}}] denotes a list, not an array; the difference is not trivial.Chris Meyer

1 Answers

5
votes

EDIT On the master branch of Elixir, the compiler will warn if a function is piped into without parentheses if there are arguments.


You need explicit parenthesis around your function calls as the function call has a higher precedence than the pipe operator.

combinedPipes = 
        params 
        |> Map.update!("InnerModel", fn(innerMap) -> 
            Enum.filter(innerMap,fn{k,v} -> byte_size(v["id"]) !=0 end) end)
        |> Map.update!("InnerModel", fn(innerMap) -> 
            Enum.into(innerMap,%{}) end)

You can read a more detailed explanation at Why Can't I Chain String.replace?