2
Justfile
|
|
@ -9,7 +9,7 @@ migrate-database:
|
|||
|
||||
reset-database:
|
||||
mix ash.reset
|
||||
MIX_ENV=test mix ash.setup
|
||||
MIX_ENV=test mix ash.reset
|
||||
|
carla marked this conversation as resolved
Outdated
|
||||
|
||||
seed-database:
|
||||
mix run priv/repo/seeds.exs
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ defmodule Mv.Membership.Member do
|
|||
end
|
||||
|
||||
actions do
|
||||
defaults [:read]
|
||||
defaults [:read, :destroy]
|
||||
|
||||
create :create_member do
|
||||
primary? true
|
||||
|
|
@ -34,11 +34,6 @@ defmodule Mv.Membership.Member do
|
|||
change manage_relationship(:properties, type: :create)
|
||||
end
|
||||
|
||||
destroy :destroy do
|
||||
primary? true
|
||||
change Ash.Resource.Change.Builtins.cascade_destroy(:properties)
|
||||
end
|
||||
|
||||
update :update_member do
|
||||
primary? true
|
||||
require_atomic? false
|
||||
|
carla marked this conversation as resolved
Outdated
rafael
commented
I think this will run using ash's "notifiers", and as such will run outside the transaction used for the destroy itself. This means that we could end up with errors if postgres detects that a property does not have an associated member. Also, I think the "references" block in the property's postgres configuration should take make this line obsolete because it tells postgres to cascade delete properties when a member is deleted? 🤔 I think this will run using ash's "notifiers", and as such [will run outside the transaction used for the destroy itself](https://hexdocs.pm/ash/notifiers.html#transactions). This means that we could end up with errors if postgres detects that a property does not have an associated member.
Also, I think the "references" block in the property's postgres configuration should take make this line obsolete because it tells postgres to cascade delete properties when a member is deleted? 🤔
moritz
commented
I tried different approaches to get the cascade deletion working. I think in the end the postgres reference block has done the job and this is still a leftover. I will try to run it without this change. I tried different approaches to get the cascade deletion working. I think in the end the postgres reference block has done the job and this is still a leftover. I will try to run it without this change.
carla
commented
Seems that properties are deleted using default :destroy with the reference block Seems that properties are deleted using default :destroy with the reference block
|
||||
|
|
@ -73,71 +68,33 @@ defmodule Mv.Membership.Member do
|
|||
validate present(:email)
|
||||
|
||||
# Birth date not in the future
|
||||
validate fn changeset, _ ->
|
||||
birth_date = Ash.Changeset.get_attribute(changeset, :birth_date)
|
||||
|
||||
if birth_date && Date.compare(birth_date, Date.utc_today()) == :gt do
|
||||
{:error, field: :birth_date, message: "cannot be in the future"}
|
||||
else
|
||||
:ok
|
||||
end
|
||||
end
|
||||
validate compare(:birth_date, less_than_or_equal_to: &Date.utc_today/0),
|
||||
where: [present(:birth_date)],
|
||||
message: "cannot be in the future"
|
||||
|
||||
# Join date not in the future
|
||||
validate fn changeset, _ ->
|
||||
join_date = Ash.Changeset.get_attribute(changeset, :join_date)
|
||||
validate compare(:join_date, less_than_or_equal_to: &Date.utc_today/0),
|
||||
where: [present(:join_date)],
|
||||
message: "cannot be in the future"
|
||||
|
||||
if join_date && Date.compare(join_date, Date.utc_today()) == :gt do
|
||||
{:error, field: :join_date, message: "cannot be in the future"}
|
||||
else
|
||||
:ok
|
||||
end
|
||||
end
|
||||
|
||||
# Exit date not before join date
|
||||
validate fn changeset, _ ->
|
||||
join_date = Ash.Changeset.get_attribute(changeset, :join_date)
|
||||
exit_date = Ash.Changeset.get_attribute(changeset, :exit_date)
|
||||
validate compare(:exit_date, greater_than: :join_date),
|
||||
where: [present([:join_date, :exit_date])],
|
||||
message: "cannot be before join date"
|
||||
|
||||
if join_date && exit_date && Date.compare(exit_date, join_date) == :lt do
|
||||
{:error, field: :exit_date, message: "cannot be before join date"}
|
||||
else
|
||||
:ok
|
||||
end
|
||||
end
|
||||
|
||||
# Phone number format (only if set)
|
||||
validate fn changeset, _ ->
|
||||
phone = Ash.Changeset.get_attribute(changeset, :phone_number)
|
||||
validate match(:phone_number, ~r/^\+?[0-9\- ]{6,20}$/),
|
||||
where: [present(:phone_number)],
|
||||
message: "is not a valid phone number"
|
||||
|
carla marked this conversation as resolved
Outdated
rafael
commented
I'm fine with doing this using custom validations as I think "real" code is easier to read than DSLs - but I think if we wanted to, we could achieve this in a more concise way using ash's built-in compare validation, e.g.: Not sure if I got the syntax exactly right, but I hope you get what I mean. I think this approach would work for other custom validations in this file as well, e.g. using the built-in One advantage of using the built-in validations is that they are "atomic", meaning they can run in the database directly, which can improve performance. I'm fine with doing this using custom validations as I think "real" code is easier to read than DSLs - but I think if we wanted to, we could achieve this in a more concise way using ash's [built-in compare validation](https://hexdocs.pm/ash/Ash.Resource.Validation.Builtins.html#compare/2), e.g.:
```elixir
validate compare(:join_date, less_than: &Date.utc_today/0),
where: [present(:join_date)],
message: "cannot be in the future"
```
Not sure if I got the syntax exactly right, but I hope you get what I mean. I think this approach would work for other custom validations in this file as well, e.g. using the built-in `match` validation for regexes.
One advantage of using the built-in validations is that they are "atomic", meaning they can run in the database directly, which can improve performance.
moritz
commented
Thank you for the hint, I will apply it and test if it works. Thank you for the hint, I will apply it and test if it works.
carla
commented
Maybe not from a technical but from a user perspective: Why should it not be possible to add members already, where the membership starts maybe beginning of next month? Should we take the question to the Pilotvereine? Maybe not from a technical but from a user perspective: Why should it not be possible to add members already, where the membership starts maybe beginning of next month? Should we take the question to the Pilotvereine?
|
||||
|
||||
if phone && !Regex.match?(~r/^\+?[0-9\- ]{6,20}$/, phone) do
|
||||
{:error, field: :phone_number, message: "is not a valid phone number"}
|
||||
else
|
||||
:ok
|
||||
end
|
||||
end
|
||||
|
||||
# Postal code format (only if set)
|
||||
validate fn changeset, _ ->
|
||||
postal_code = Ash.Changeset.get_attribute(changeset, :postal_code)
|
||||
validate match(:postal_code, ~r/^\d{5}$/),
|
||||
where: [present(:postal_code)],
|
||||
message: "must consist of 5 digits"
|
||||
|
||||
if postal_code && !Regex.match?(~r/^\d{5}$/, postal_code) do
|
||||
{:error, field: :postal_code, message: "must consist of 5 digits"}
|
||||
else
|
||||
:ok
|
||||
end
|
||||
end
|
||||
|
||||
# paid must be boolean if set
|
||||
validate fn changeset, _ ->
|
||||
paid = Ash.Changeset.get_attribute(changeset, :paid)
|
||||
|
||||
if not is_nil(paid) and not is_boolean(paid) do
|
||||
{:error, field: :paid, message: "must be true or false"}
|
||||
else
|
||||
:ok
|
||||
end
|
||||
end
|
||||
|
||||
# Email validation with EctoCommons.EmailValidator
|
||||
validate fn changeset, _ ->
|
||||
|
|
@ -216,6 +173,6 @@ defmodule Mv.Membership.Member do
|
|||
end
|
||||
|
||||
relationships do
|
||||
has_many :properties, Mv.Membership.Property, destination_attribute: :member_id
|
||||
has_many :properties, Mv.Membership.Property
|
||||
end
|
||||
end
|
||||
|
|
|
|||
Why not use
ash.resethere as well?typo that works as well. but i change it