PaackEng / paack-remotedata / Remote.Recyclable

This module extends Data preserving the information when reloading the same source.

It helps in scenarios like the following routine:

  1. Data was never requested

    • Start it with Recyclable.NeverAsked
  2. Request was sent

    • Pipe it into:

      |> Recyclable.toLoading
      
    • At this point, it will be:

      Recyclable.Loading
      
  3. Request's Response was received (a Failure error)

    • Pipe it into:

      |> Recyclable.mergeResponse response
      
    • At this point, it will be:

      Recyclable.Failure error
      
  4. User press "Retry" button, a new request was sent

    • Pipe it into:

      |> Recyclable.toLoading
      
    • At this point, it will be:

      Recyclable.Loading
      
  5. Request's Response was received (a Success data)

    • Pipe it into:

      |> Recyclable.mergeResponse response
      
    • At this point, it will be:

      Recyclable.Ready data
      
  6. User press "Refresh" button, a new request was sent

    • Pipe it into:

      |> Recyclable.toLoading
      
    • At this point, it will be:

      Recyclable.Recycling data Recyclable.Loading
      
  7. Request's Response was received (a Failure error)

    • Pipe it into:

      |> Recyclable.mergeResponse response
      
    • At this point, it will be:

      Recyclable.Ready (Recyclable.Recycling data (Recyclable.Failure error))
      
  8. User press "Refresh" button, a new request was sent

    • Pipe it into:

      |> Recyclable.toLoading
      
    • At this point, it will be:

      Recyclable.Recycling data Recyclable.Loading
      
  9. Request's Response was received (a Success data)

    • Pipe it into:

      |> Recyclable.mergeResponse response
      
    • At this point, it will be:

      Recyclable.Ready data
      

Types


type Recyclable transportError customError object
    = NeverAsked
    | Loading
    | Failure (Remote.Errors.RemoteError transportError customError)
    | Ready object
    | Recycling object (RecyclingStage transportError customError)

A representation for fetchable data with eight states:

First routine states:

Future cycles states:


type RecyclingStage transportError customError
    = LoadingStage
    | FailureStage (Remote.Errors.RemoteError transportError customError)

Indicates FailureStage and LoadingStage stage when data is/was being fetched.


type alias GraphqlHttpRecyclable error object =
Recyclable (Graphql.Http.RawError () Graphql.Http.HttpError) error object

While Recyclable can model any type of errors, the most common one Paack has encountered is when fetching data from a Graphql query, and getting back a GraphqlError. Because of that, GraphqlHttpRecyclable is provided as a useful alias.

Model

First, when initializing a "Model", you will use either:

firstLoading : Recyclable transportError customError object

It's very common to initialize the model already requesting the data, use firstLoading in this case. Like this:

init : RequestConfig -> ( Model, Cmd Msg )
init requestConfig =
    ( Recyclable.firstLoading
    , modelRequestCmd requestConfig
    )

Update

Then, on "update" you're gonna be using either:

mergeResponse : Remote.Response.Response transportError customError object -> Recyclable transportError customError object -> Recyclable transportError customError object

This is the update routine for when overwriting the current data with a new freshily-fetched response.

update msg model =
    case msg of
        CardFetched response ->
            { model
                | card =
                    Recyclable.mergeResponse response model.card
            }

toLoading : Recyclable transportError customError object -> Recyclable transportError customError object

Returns a Recyclable to its loading state. Keeping the information when available.

fromResponse : Remote.Response.Response transportError customError object -> Recyclable transportError customError object

Convert a Response, probably produced from a query result, to a Recyclable value.

NOTE: As this function discards the previous information, in most cases you should be using mergeResponse instead.

Identity crisis

isReady : Recyclable transportError customError object -> Basics.Bool

True when Ready _.

NOTE: This function opposes the purpose of this package by eliminating not aimed states. Always evaluate using a switch-case instead.

isError : Recyclable transportError customError object -> Basics.Bool

True when _ (Failure _).

NOTE: This function opposes the purpose of this package by eliminating not aimed states. Always evaluate using a switch-case instead.

isCustomError : Recyclable transportError customError object -> Basics.Bool

True when _ (Failure (Custom _)).

NOTE: This function opposes the purpose of this package by eliminating not aimed states. Always evaluate using a switch-case instead.

isTransportError : Recyclable transportError customError object -> Basics.Bool

True when _ (Failure (Transport _)).

NOTE: This function opposes the purpose of this package by eliminating not aimed states. Always evaluate using a switch-case instead.

isLoading : Recyclable transportError customError object -> Basics.Bool

True when _ Loading.

NOTE: This function opposes the purpose of this package by eliminating not aimed states. Always evaluate using a switch-case instead.

isNeverAsked : Recyclable transportError customError object -> Basics.Bool

True when NeverAsked.

NOTE: This function opposes the purpose of this package by eliminating not aimed states. Always evaluate using a switch-case instead.

Common transformations

toError : Recyclable transportError customError object -> Maybe (Remote.Errors.RemoteError transportError customError)

Transforms Failure error into Just error, and anything else into Nothing.

NOTE: This function opposes the purpose of this package by eliminating not aimed states. Always evaluate using a switch-case instead.

map : (a -> b) -> Recyclable transportError customError a -> Recyclable transportError customError b

Apply a function to the values in Recycling value _ and Ready value. If the data is anything else, the same value will propagate through.

mapCustomError : (customError -> a) -> Recyclable transportError customError object -> Recyclable transportError a object

Transform a Failure (Custom a) value. If the data is Failure (Custom a), it will be converted. If the data is anything else, the same value will propagate through.

mapTransportError : (transportError -> a) -> Recyclable transportError customError object -> Recyclable a customError object

Transform a Failure (Transport a) value. If the data is Failure (Transport a), it will be converted. If the data is anything else, the same value will propagate through.

mapErrors : (Remote.Errors.RemoteError transportError customError -> a) -> Recyclable transportError customError b -> Recyclable a a b

Transform a Failure value. If the data is Failure, it will be converted. If the data is anything else, the same value will propagate through.

withDefault : object -> Recyclable transportError customError object -> object

If the recyclable is Success return the value, but if the recyclable is anything else, then return a given default value.

NOTE: This function opposes the purpose of this package by eliminating not aimed states. Always evaluate using a switch-case instead.

merge : object -> Recyclable object object object -> object

For doing pipes instead of switch-case