I struggle with Elixir and can’t get the Elixir right for this code. Desperately need some help here.
I have built a GenServer that will act as my SessionDataServer. My initial plan was to just create a key-store using a map where:
key was a session_id (I get from session in LiveView mount)
value was a struct %SessionData{ date_entered: Date.utc_today, user_data: []}
I was using the following to handle a call to :store_session_data:
@impl true
def handle_call( {:store_session_data, session_id, user_data}, _from, data ) do
Map.put(
data,
session_id,
%SessionData{date_entered: Date.utc_today(), user_data: user_data}
)
{:reply, data, data}
end
I got this error and think it’s because I’m passing a string in as the key and Map.put wants an atom:
exited in: GenServer.call(:session_data_server, {:store_session_data, "35ad0255-df9b-4e12-b6cb-9446079d32a4", []}, 5000) ** (EXIT) an exception was raised: ** (Protocol.UndefinedError) protocol String.Chars not implemented for %{} of type Map (elixir 1.13.2) lib/string/chars.ex:3: String.Chars.impl_for!/1 (elixir 1.13.2) lib/string/chars.ex:22: String.Chars.to_string/1 (sketch_links 0.1.0)
OK, so I redefined my struct to be as follows:
defmodule SessionData do
defstruct session_id: nil, date_entered: nil, user_data: []
end
And my GenServer now takes a list at startup because I want it to hold a list of structs:
def start_link(_args) do
IO.puts "Starting the SessionDataServer ..."
GenServer.start_link(__MODULE__, [], name: @name)
end
But I still can’t get at the data. I’m trying to use the following code to delete existing session data if it exists and replace it with new data:
@impl true
def handle_call( {:store_session_data, session_id, user_data}, _from, data ) do
# Remove old data for session id
existing_data = Enum.find(data, fn d -> d.session_id == session_id end)
data = List.delete(data, existing_data)
# Add new data
data = [ %SessionData{
session_id: session_id,
date_entered: Date.utc_today(),
user_data: user_data} | data ]
{:reply, data, data}
end
Now I’m getting this error:
exited in: GenServer.call(:session_data_server, {:store_session_data, "35ad0255-df9b-4e12-b6cb-9446079d32a4", []}, 5000) ** (EXIT) an exception was raised: ** (ArgumentError) cannot convert the given list to a string
Why is it trying to convert my list of structs to a string??? I know there is an Elixir master out there who can probably do this in one line. Should I have stuck with using the session_id as the key to my map? If so, how do I get it to stop throwing up an error?