How to update a struct with a varable?

I have a struct which belongs to z. Let’s assume values are decimals.
s = %S{a: 1, b: 2}

I want to update s with a variable, k, of which value will be either :a or :b.

When k’s value is determined, I wanna update s like this;
s = Map.update!(s, k, &Decimal.add(&1, 5))

So, s will be update to %S{a: 6, b: 2} or %S{a: 1, b: 7}.

But s belongs to z, so, everytime s is updated, it needs put_assoc z repeatedly.
z |> put_assoc(:s, s) |> update

How to update s alone?

Thank you all.

:wave:

put_assoc acts on changesets, not plain structs. So are you trying to update plain nested structs, or nested changesets? I think the solutions would be a bit different for these two cases.

2 Likes

It’s tought to say, because when you mention put_assoc it sounds like you are talking about database structs, not just structs?

If you are updating database struct, then you can always just update the struct you need to update.

Why do you think you need to put_assoc s?

Repo.get(S, 1)
|> Ecto.Changeset.change(%{a: 6, b: 2})
|> Repo.update!

Would update the S record alone.

2 Likes

The issue is how to get %{a: 6, b: 2} map. It can be either %{a: 1, b: 7} or %{a: 6, b: 2} depending on the k value. So, the problem is how to apply k value to %{a: 1, b 2} to yield either %{a: 1, b: 7} or %{a: 6, b: 2}. Any idea?

PS> k is either :a or :b.

Would you see the comment below I just added?

It looks like you have it already, with the Map.update, the below does the same thing:

s = %S{a: 1, b: 2}
k = :a
%{ s | k => Decimal.add(Map.get(s, k), 5) }

# Another way:
s = %S{a: 1, b: 2}
k = :a
changes = %{ k =>  Decimal.add(Map.get(s, k), 5)  }
Ecto.Changeset.change(s, changes)

The above should return: %S{a: 6, b: 2}, but I think you already had that working. Is it something after that that you are stuck on?

1 Like

Exactly what I need.
Thank you, Adzz.