I’m facing an issue with the structure of my data.
I have data that references one another bidirectionally and can’t find a satisfying way to deal with it.
type RequestCollection = RequestCollection Int [Request]
type ScenarioCollection = ScenarioCollection Int [Scenario]
-- a request can be attached to 0 to n scenario
type Request =
{ id: Int
...
}
-- a scenario is always attached to one request
type Scenario =
{ id : Int
, requestId : Int
}
requestColl : RequestCollection = ...
scenarioColl : ScenarioCollection = ...
I can easily deal with requestColl because it has directly access to requests. OTOH I scenarioColl only have a request ids so if I want to deal with a scenario’s request, I first need to first find it in requestColl. That is inconvenient because you then have to deal with Maybe.
Is there a way to deal with that kind of structure or should I am just stuck with dealing with Maybe?
If you use references, you place yourself in the context where the data might no longer be available.
So, either accept this and just use Maybe or copy the data in Scenario.
If you are 100% sure that the retrieval of the request cannot fail you can get rid of the Maybe by using defaults. For example:
type alias RequestCollection = Dict Int Request
getRequest : RequestCollection -> Int -> Request
getRequest requestDict id=
Dict.get id requestDict |> Maybe.withDefault defaultRequest
Please note that using patterns like this makes your code a little bit more error prone. Use it with care.
I unfortunately cannot use Maybe.withDefault because the defaultRequest I have is wrapped in a Maybe.
I hoped there was some pattern to deal with this kind of use case but I guess I’m stuck with either copying data or dealing with Maybe
defaultRequest is just a dummy request that you manually create. You use it because, in theory, all the calls to retrieve the requests from the requests collection will succeed.
A bit of offtopic, but instead of holding List Request and List Scenario, the “relational database” model is a pretty good alternative (but yeah, leaves you with a Maybe. @pdamoc’s note about Maybe.withDefault applies here as well.)
Here’s how it looks:
type alias Store =
{ requests : Dict Int Request
, scenarios : Dict Int Scenario
}
Or in case you’re getting your all data from API at once:
type alias Store =
{ requests : WebData (Dict Int Request)
, scenarios : WebData (Dict Int Scenario)
}
Or in case you’re getting your your data lazily, one by one, from the API:
type alias Store =
{ requests : Dict Int (WebData Request)
, scenarios : Dict Int (WebData Scenario)
}