84 lines
2.5 KiB
Elm
84 lines
2.5 KiB
Elm
module Paginated exposing (..)
|
|
|
|
import Dict
|
|
import Http
|
|
import Json.Decode
|
|
import Maybe.Extra
|
|
import Regex
|
|
import Url
|
|
|
|
|
|
type alias Page a =
|
|
{ prev : Maybe Url.Url
|
|
, next : Maybe Url.Url
|
|
, values : List a
|
|
}
|
|
|
|
|
|
empty : Page a
|
|
empty =
|
|
{ prev = Nothing
|
|
, next = Nothing
|
|
, values = []
|
|
}
|
|
|
|
|
|
expectJson : (Result Http.Error (Page value) -> msg) -> Json.Decode.Decoder value -> Http.Expect msg
|
|
expectJson toMsg decoder =
|
|
let
|
|
linkPattern : Regex.Regex
|
|
linkPattern =
|
|
Regex.fromString "<(.*?)>; rel=\"(.*?)\""
|
|
|> Maybe.withDefault Regex.never
|
|
|
|
links : String -> Dict.Dict String String
|
|
links s =
|
|
let
|
|
toTuples xs =
|
|
case xs of
|
|
[ Just a, Just b ] ->
|
|
Just ( b, a )
|
|
|
|
_ ->
|
|
Nothing
|
|
in
|
|
Regex.find linkPattern s
|
|
|> List.map .submatches
|
|
|> List.map toTuples
|
|
|> Maybe.Extra.values
|
|
|> Dict.fromList
|
|
in
|
|
Http.expectStringResponse toMsg <|
|
|
\response ->
|
|
case response of
|
|
Http.BadUrl_ url ->
|
|
Err (Http.BadUrl url)
|
|
|
|
Http.Timeout_ ->
|
|
Err Http.Timeout
|
|
|
|
Http.NetworkError_ ->
|
|
Err Http.NetworkError
|
|
|
|
Http.BadStatus_ metadata _ ->
|
|
Err (Http.BadStatus metadata.statusCode)
|
|
|
|
Http.GoodStatus_ metadata body ->
|
|
case Json.Decode.decodeString (Json.Decode.list decoder) body of
|
|
Ok values ->
|
|
Ok
|
|
{ prev =
|
|
Dict.get "link" metadata.headers
|
|
|> Maybe.map links
|
|
|> Maybe.andThen (Dict.get "prev")
|
|
|> Maybe.andThen Url.fromString
|
|
, next =
|
|
Dict.get "link" metadata.headers
|
|
|> Maybe.map links
|
|
|> Maybe.andThen (Dict.get "next")
|
|
|> Maybe.andThen Url.fromString
|
|
, values = values
|
|
}
|
|
|
|
Err err ->
|
|
Err (Http.BadBody (Json.Decode.errorToString err))
|