Is there a neat way to check if you are trying to set one value that depends on another one?

For example if you were to set latitude and longitude,
you wouldn’t one to be set without the other one, is there some neat way to do this?

Using validations, either from ecto or exvalibur or perhaps any other validation library, or smart constructors, or providing a function that accepts only long/lat pair as arguments or whatever you can think of…

There are many ways to do this.

in ecto/postgres:
https://hexdocs.pm/ecto/Ecto.Changeset.html#check_constraint/3

https://hexdocs.pm/ecto_sql/Ecto.Migration.html#constraint/3

create constraint(“locations”, :must_have_both_lat_lon_or_none, check: “(LAT IS NULL AND LON IS NOT NULL) OR
(LAT IS NOT NULL AND LON IS NULL)”)

not totally sure of check: syntax but above should be good…

2 Likes

this approach is nice, a small tweak to the check:

"(latitude IS NULL AND longitude IS NULL) OR (latitude IS NOT NULL AND longitude IS NOT NULL)"
1 Like

well actually after I posted I think this is so simple and overkill to put in the DB… (and having to hit the db to get the error…)

so maybe just a custom validate function on the changeset - using some pattern matching of course

def changeset(%Location{} = location, attrs) do
  location
  |> cast(attrs, [:lat, :lon])
  |> validate_both_lat_lon_or_none
end

defp validate_both_lat_lon_or_none(changeset) do
  lat = get_field(changeset, :lat)
  lon = get_field(changeset, :lon)

  validate_both_lat_lon_or_none(changeset, lat, lon)
end

defp validate_both_lat_lon_or_none(changeset, lat, lon) when lat == nil and lon != nil do
  add_error(changeset, :lat, "lat missing")
end

defp validate_both_lat_lon_or_none(changeset, lat, lon) when lat != nil and lon == nil do
  add_error(changeset, :lon, "lon missing")
end

defp validate_both_lat_lon_or_none(changeset, _, _), do: changeset

untested code…

1 Like

yeah, i was thinking something like this as my first approach, so i just need to decide between the 2

1 Like

Do both, having it as a constraint in the DB means the data will be known for sure coherent, and if you have a check on the changeset too then it keeps from hitting the DB. Though I’d doubt it would be hit often enough to matter so I’d just let the DB handle it.

2 Likes