Hey everyone, coming from Rails and new to Elixir, so bear with me as I’m still learning.
I’m currently writing tests and as I want them to run fast, I’m going to skip the database if possible. So instead of updating associations and reloading them to have the data available in the tests, I want to do something like this
user |> put_in(["integrations", "state"], "deleted") # this marks the integration as deleted
but this blows up with: User does not implement the Access behaviour Both User and Integration are Ecto schemas.
Am I doing something wrong? Why isn’t the Access behaviour implemented for Ecto.Schema's?
If you really need it, maybe you can implement this behaviour yourself by using either Map.from_struct or some metaprogramming (it’s just 4 callbacks).
defmodule User do
@behaviour Access
# ... schema and stuff
# Access callbacks the easy way
def fetch(term, key) do
term
|> Map.from_struct()
|> Map.fetch(key)
end
def get(term, key, default) do
term
|> Map.from_struct()
|> Map.get(key, default)
end
def get_and_update(data, key, function) do
data
|> Map.from_struct()
|> Map.get_and_update(key, function)
end
def pop(data, key) do
data
|> Map.from_struct()
|> Map.pop(key)
end
end
You might also want to read this
But in ecto the schema structs usually represent rows in a table, and modifications to these rows are then done via changesets. So your example can be probably expressed via them.
Ah if only @derive [Access] still worked. Protocol’izing Access was inefficient in the old days, however if rewritten in my ProtocolEx then it would have no runtime cost at all, even faster than the built-in one as it stands.
Well for compiling the access implementations itself they should either be defined in things that don’t use access or do direct calls to the proper implementations themselves, after that it should matter for any user code regardless.
Hmm, potential ideas for reifying that into the API instead of calling it as necessary manually…
Do note, mine supports staged recompilation, so you can consolidate it when a base set that could then be used in other implementations later and recompiled as necessary if something depends on a specific implementation.
Ah if only Elixir were typed, then you wouldn’t need such hacks. ^.^