AE
Ash Elixir•5d ago
Jakub

How to use datetime_add in set_attribute?

Hi guys, a quick question, maybe I'm doing something stupid... I want to increase trial_ends_at by 7 days in an action. I thought
change set_attribute(:trial_ends_at, expr(datetime_add(trial_ends_at, 7, "day")))
change set_attribute(:trial_ends_at, expr(datetime_add(trial_ends_at, 7, "day")))
should work, but it isn't
%Ash.Error.Invalid{changeset: "#Changeset<>", errors: [%Ash.Error.Changes.InvalidAttribute{field: :trial_ends_at, message: "Could not cast input to datetime", private_vars: nil, value: datetime_add(trial_ends_at, 7, :day), splode: Ash.Error, bread_crumbs: [], vars: [], path: [], stacktrace: #Splode.Stacktrace<>, class: :invalid}]}
%Ash.Error.Invalid{changeset: "#Changeset<>", errors: [%Ash.Error.Changes.InvalidAttribute{field: :trial_ends_at, message: "Could not cast input to datetime", private_vars: nil, value: datetime_add(trial_ends_at, 7, :day), splode: Ash.Error, bread_crumbs: [], vars: [], path: [], stacktrace: #Splode.Stacktrace<>, class: :invalid}]}
What I'm doing wrong? 🤔
11 Replies
barnabasj
barnabasj•5d ago
try atomic_update(:trial_ends_at, expr(datetime_add(trial_ends_at, 7, "day"))) I don't think you can use expr with set_attribute
Jakub
JakubOP•5d ago
it works, thank you! Just curious, why it doesn't work with expr?
barnabasj
barnabasj•5d ago
you need the guaranties atomic updates give you to be able to reference old values in a concurrency safe manner.
ZachDaniel
ZachDaniel•5d ago
Correct. You can write a custom change that looks at the old and new manually if you want just know that it won't be atomic
mcoll
mcoll•4d ago
So this has been causing some dissonance in me a bit, so Ash atomic goes a bit beyond atomicity of changes in (say) postgres, and it is closely related to the idea of serializability, right? An atomic change is one that can happen at the data layer, with the data layer ensuring that it is consistent. Everything regardless of atomicity runs in a transaction (so it's using basic atomicity, as in, all changes will either succeed or fail, no intermediate steps), but by default (without Ash atomics) it's not serializable. Correct?
ZachDaniel
ZachDaniel•4d ago
Yes and no. Its actually a bit more complex as we allow a slightly looser definition of atomics. We allow after_action hooks, but everything else must be confirmed to be atomic. But if you factor out after action hooks then yes, the idea is one single statement This also means that you don't need transactions if there are no hooks at all, which reduces load in the data layer So for an update action w/ no hooks that is being done atomically, there is no BEGIN/END sent also
mcoll
mcoll•4d ago
Makes sense, you can find out if you can do it in a single statement and just run that, but if needed you do a BEGIN/COMMIT
ZachDaniel
ZachDaniel•4d ago
yep!
mcoll
mcoll•4d ago
require_atomic? false was scaring me a bit at first, because I thought then changes may not be fully atomic and if something fails I had a partial state in the DB I checked the logs and saw that transactions were happening, so I calmed down
ZachDaniel
ZachDaniel•4d ago
I see your point, and it could be debatably called require_serializable or something else But we are where we are 😆
mcoll
mcoll•4d ago
yes, it may be interesting to explicitly mention in the docs, since it was a bit scary at first

Did you find this page helpful?