From 7f322a5e2233e371ba63d16a824737fc73ce43b5 Mon Sep 17 00:00:00 2001 From: Tom Nunn Date: Tue, 7 Mar 2023 20:39:24 +0000 Subject: [PATCH] Accept any error type in request --- examples/src/EffectRequestExample.elm | 6 +++--- examples/tests/RequestTest.elm | 4 ++-- src/Internal/Update.elm | 6 +++--- src/Internal/UpdateOptions.elm | 12 ++++++------ src/Select.elm | 26 +++++++++++++------------- src/Select/Effect.elm | 27 +++++++++++++-------------- 6 files changed, 40 insertions(+), 41 deletions(-) diff --git a/examples/src/EffectRequestExample.elm b/examples/src/EffectRequestExample.elm index 48d4467..25fbb4d 100644 --- a/examples/src/EffectRequestExample.elm +++ b/examples/src/EffectRequestExample.elm @@ -67,12 +67,12 @@ update msg model = |> Tuple.mapBoth (\select -> { model | select = select }) SelectEffect -fetchCocktails : String -> (Result String (List Cocktail) -> Msg) -> Cmd Msg +fetchCocktails : String -> (Result Http.Error (List Cocktail) -> Msg) -> Cmd Msg fetchCocktails query tagger = Http.get { url = "https://thecocktaildb.com/api/json/v1/1/search.php?s=" ++ String.replace " " "+" query , expect = - Http.expectJson (Result.mapError (\_ -> "Failed fetching cocktails") >> tagger) + Http.expectJson tagger (Decode.field "drinks" (Decode.oneOf [ Decode.list cocktailDecoder @@ -90,7 +90,7 @@ fetchCocktails query tagger = type MyEffect = NoEffect | SelectEffect (Select.Effect MyEffect Msg) - | FetchCocktails String (Result String (List Cocktail) -> Msg) + | FetchCocktails String (Result Http.Error (List Cocktail) -> Msg) performEffect : MyEffect -> Cmd Msg diff --git a/examples/tests/RequestTest.elm b/examples/tests/RequestTest.elm index fbcd38d..a97cc6b 100644 --- a/examples/tests/RequestTest.elm +++ b/examples/tests/RequestTest.elm @@ -71,12 +71,12 @@ simulateEffect effect = fetchCocktails query msg -fetchCocktails : String -> (Result String (List App.Cocktail) -> msg) -> SimulatedEffect msg +fetchCocktails : String -> (Result SimulateHttp.Error (List App.Cocktail) -> msg) -> SimulatedEffect msg fetchCocktails query tagger = SimulateHttp.get { url = "https://thecocktaildb.com/api/json/v1/1/search.php?s=" ++ String.replace " " "+" query , expect = - SimulateHttp.expectJson (Result.mapError (\_ -> "Failed fetching cocktails") >> tagger) + SimulateHttp.expectJson tagger (Decode.field "drinks" (Decode.oneOf [ Decode.list App.cocktailDecoder diff --git a/src/Internal/Update.elm b/src/Internal/Update.elm index 1f7e0fa..c2997ed 100644 --- a/src/Internal/Update.elm +++ b/src/Internal/Update.elm @@ -8,7 +8,7 @@ import Internal.RequestState exposing (RequestState(..)) import Internal.UpdateOptions exposing (UpdateOptions) -update : UpdateOptions effect a msg -> (Msg a -> msg) -> Msg a -> Model a -> ( Model a, Effect effect msg ) +update : UpdateOptions err effect a msg -> (Msg a -> msg) -> Msg a -> Model a -> ( Model a, Effect effect msg ) update ({ onSelect } as options) tagger msg model = update_ options tagger msg model |> withEffect @@ -22,7 +22,7 @@ update ({ onSelect } as options) tagger msg model = ) -update_ : UpdateOptions effect a msg -> (Msg a -> msg) -> Msg a -> Model a -> ( Model a, Effect effect msg ) +update_ : UpdateOptions err effect a msg -> (Msg a -> msg) -> Msg a -> Model a -> ( Model a, Effect effect msg ) update_ { request, requestMinInputLength, debounceRequest, onFocus, onLoseFocus, onInput } tagger msg model = case msg of InputChanged val -> @@ -128,7 +128,7 @@ update_ { request, requestMinInputLength, debounceRequest, onFocus, onLoseFocus, InputDebounceReturned val -> if val == Model.toInputValue model then ( Model.setRequestState (Just Loading) model - , Maybe.map (\effect -> Effect.Request (effect val (GotRequestResponse val >> tagger))) request + , Maybe.map (\effect -> Effect.Request (effect val (Result.mapError (\_ -> "") >> GotRequestResponse val >> tagger))) request |> Maybe.withDefault Effect.none ) diff --git a/src/Internal/UpdateOptions.elm b/src/Internal/UpdateOptions.elm index 180ed84..57d68ba 100644 --- a/src/Internal/UpdateOptions.elm +++ b/src/Internal/UpdateOptions.elm @@ -1,8 +1,8 @@ module Internal.UpdateOptions exposing (UpdateOption(..), UpdateOptions, fromList) -type UpdateOption effect a msg - = Request (String -> (Result String (List a) -> msg) -> effect) +type UpdateOption err effect a msg + = Request (String -> (Result err (List a) -> msg) -> effect) | DebounceRequest Float | RequestMinInputLength Int | OnSelect (Maybe a -> msg) @@ -11,8 +11,8 @@ type UpdateOption effect a msg | OnInput (String -> msg) -type alias UpdateOptions effect a msg = - { request : Maybe (String -> (Result String (List a) -> msg) -> effect) +type alias UpdateOptions err effect a msg = + { request : Maybe (String -> (Result err (List a) -> msg) -> effect) , debounceRequest : Float , requestMinInputLength : Int , onSelect : Maybe (Maybe a -> msg) @@ -22,7 +22,7 @@ type alias UpdateOptions effect a msg = } -init : UpdateOptions effect a msg +init : UpdateOptions err effect a msg init = { request = Nothing , debounceRequest = 300 @@ -34,7 +34,7 @@ init = } -fromList : List (UpdateOption effect a msg) -> UpdateOptions effect a msg +fromList : List (UpdateOption err effect a msg) -> UpdateOptions err effect a msg fromList = List.foldl (\opt opts -> diff --git a/src/Select.elm b/src/Select.elm index 32c2bd0..6b89880 100644 --- a/src/Select.elm +++ b/src/Select.elm @@ -260,7 +260,7 @@ update tagger msg select = Debug.todo "Do something when the thing is selected/deselected" -} -updateWith : List (UpdateOption a msg) -> (Msg a -> msg) -> Msg a -> Select a -> ( Select a, Cmd msg ) +updateWith : List (UpdateOption err a msg) -> (Msg a -> msg) -> Msg a -> Select a -> ( Select a, Cmd msg ) updateWith options tagger msg select = Update.update (UpdateOptions.fromList options) tagger msg select |> Tuple.mapSecond (Effect.perform identity) @@ -268,13 +268,13 @@ updateWith options tagger msg select = {-| Options for use with updateWith. -} -type alias UpdateOption a msg = - UpdateOptions.UpdateOption (Cmd msg) a msg +type alias UpdateOption err a msg = + UpdateOptions.UpdateOption err (Cmd msg) a msg {-| Use an HTTP request to retrieve matching remote results. ote that in order to avoid an elm/http dependency in this package, you will need to provide the request Cmd yourself. Provide a function that takes the input value and a msg tagger and returns a Cmd. -Update will return this Cmd when the user types in the input. Note, you need to map the error of the response to String before passing to the msg tagger. +Update will return this Cmd when the user types in the input. update : Msg -> Model -> ( Model, Cmd Msg ) update msg model = @@ -283,17 +283,17 @@ Update will return this Cmd when the user types in the input. Note, you need to Select.updateWith [ Select.request fetchThings ] SelectMsg subMsg model.select |> Tuple.mapFirst (\select -> { model | select = select }) - fetchThings : String -> (Result String (List Thing) -> Msg) -> Cmd Msg + fetchThings : String -> (Result Http.Error (List Thing) -> Msg) -> Cmd Msg fetchThings query tagger = Http.get { url = "https://awesome-thing.api/things?search=" ++ query , expect = - Http.expectJson (Result.mapError (\_ -> "Failed fetching things") >> tagger) + Http.expectJson tagger (Decode.list thingDecoder) } -} -request : (String -> (Result String (List a) -> msg) -> Cmd msg) -> UpdateOption a msg +request : (String -> (Result err (List a) -> msg) -> Cmd msg) -> UpdateOption err a msg request effect = UpdateOptions.Request effect @@ -303,7 +303,7 @@ request effect = Select.updateWith [ Select.request fetchThings, Select.requestDebounceDelay 500 ] SelectMsg subMsg model.select -} -requestDebounceDelay : Float -> UpdateOption a msg +requestDebounceDelay : Float -> UpdateOption err a msg requestDebounceDelay delay = UpdateOptions.DebounceRequest delay @@ -314,7 +314,7 @@ If this is too low you may get an unmanagable number of results! Default is 3 ch Select.updateWith [ Select.request fetchThings, Select.requestMinInputLength 4 ] SelectMsg subMsg model.select -} -requestMinInputLength : Int -> UpdateOption a msg +requestMinInputLength : Int -> UpdateOption err a msg requestMinInputLength len = UpdateOptions.RequestMinInputLength len @@ -324,28 +324,28 @@ requestMinInputLength len = Select.updateWith [ Select.onSelectedChange SelectionChanged ] SelectMsg subMsg model.select -} -onSelectedChange : (Maybe a -> msg) -> UpdateOption a msg +onSelectedChange : (Maybe a -> msg) -> UpdateOption err a msg onSelectedChange msg = UpdateOptions.OnSelect msg {-| If provided this msg will be sent whenever the input value changes. -} -onInput : (String -> msg) -> UpdateOption a msg +onInput : (String -> msg) -> UpdateOption err a msg onInput msg = UpdateOptions.OnInput msg {-| If provided this msg will be sent whenever the input is focused. -} -onFocus : msg -> UpdateOption a msg +onFocus : msg -> UpdateOption err a msg onFocus msg = UpdateOptions.OnFocus msg {-| If provided this msg will be sent whenever the input loses focus. -} -onLoseFocus : msg -> UpdateOption a msg +onLoseFocus : msg -> UpdateOption err a msg onLoseFocus msg = UpdateOptions.OnLoseFocus msg diff --git a/src/Select/Effect.elm b/src/Select/Effect.elm index 715b532..068ef80 100644 --- a/src/Select/Effect.elm +++ b/src/Select/Effect.elm @@ -109,29 +109,28 @@ update = Debug.todo "Do something when the thing is selected/deselected" -} -updateWith : List (UpdateOption effect a msg) -> (Msg a -> msg) -> Msg a -> Select a -> ( Select a, Effect effect msg ) +updateWith : List (UpdateOption err effect a msg) -> (Msg a -> msg) -> Msg a -> Select a -> ( Select a, Effect effect msg ) updateWith options = Update.update (UpdateOptions.fromList options) {-| Options for use with updateWith. -} -type alias UpdateOption effect a msg = - UpdateOptions.UpdateOption effect a msg +type alias UpdateOption err effect a msg = + UpdateOptions.UpdateOption err effect a msg {-| Update with an HTTP request to retrieve matching remote results. Note that in order to avoid an elm/http dependency in this package, you will need to provide the request Effect yourself. -Provide an effect (your app's own Effect type) that uses the input value and a msg tagger that can be used to perform an HTTP request. +Provide an effect (your app's own Effect type) that uses the input value and a msg tagger that can perform an HTTP request. Update will use this Effect when the user types into the input. When the effect is performed you must use Select.Effect.performWithRequest instead of Select.Effect.perform. -You need to map the error of the request to string before passing to the msg tagger. type MyEffect = SelectEffect (Select.Effect MyEffect Msg) - | FetchThings String (Result String (List Thing) -> Msg) + | FetchThings String (Result Http.Error (List Thing) -> Msg) update : Msg -> Model -> ( Model, MyEffect ) update msg model = @@ -151,19 +150,19 @@ You need to map the error of the request to string before passing to the msg tag Http.get { url = "https://awesome-thing.api/things?search=" ++ query , expect = - Http.expectJson (Result.mapError (\_ -> "Failed fetching things") >> tagger) + Http.expectJson tagger (Decode.list thingDecoder) } -} -request : (String -> (Result String (List a) -> msg) -> effect) -> UpdateOption effect a msg +request : (String -> (Result err (List a) -> msg) -> effect) -> UpdateOption err effect a msg request effect = UpdateOptions.Request effect {-| Configure debouncing for the request. How long should we wait in milliseconds after the user stops typing to send the request? Default is 300. -} -requestDebounceDelay : Float -> UpdateOption effect a msg +requestDebounceDelay : Float -> UpdateOption err effect a msg requestDebounceDelay delay = UpdateOptions.DebounceRequest delay @@ -171,35 +170,35 @@ requestDebounceDelay delay = {-| How many characters does a user need to type before a request is sent? If this is too low you may get an unmanagable number of results! Default is 3 characters. -} -requestMinInputLength : Int -> UpdateOption effect a msg +requestMinInputLength : Int -> UpdateOption err effect a msg requestMinInputLength len = UpdateOptions.RequestMinInputLength len {-| If provided this msg will be sent whenever the selected item changes. -} -onSelectedChange : (Maybe a -> msg) -> UpdateOption effect a msg +onSelectedChange : (Maybe a -> msg) -> UpdateOption err effect a msg onSelectedChange msg = UpdateOptions.OnSelect msg {-| If provided this msg will be sent whenever the input value changes. -} -onInput : (String -> msg) -> UpdateOption effect a msg +onInput : (String -> msg) -> UpdateOption err effect a msg onInput msg = UpdateOptions.OnInput msg {-| If provided this msg will be sent whenever the input gets focus. -} -onFocus : msg -> UpdateOption effect a msg +onFocus : msg -> UpdateOption err effect a msg onFocus msg = UpdateOptions.OnFocus msg {-| If provided this msg will be sent whenever the input loses focus. -} -onLoseFocus : msg -> UpdateOption effect a msg +onLoseFocus : msg -> UpdateOption err effect a msg onLoseFocus msg = UpdateOptions.OnLoseFocus msg