github.com/pf-qiu/concourse/v6@v6.7.3-0.20201207032516-1f455d73275f/web/elm/src/Api/Pagination.elm (about)

     1  module Api.Pagination exposing (params, parseLinks, parsePagination)
     2  
     3  import Concourse.Pagination
     4      exposing
     5          ( Direction(..)
     6          , Page
     7          , Paginated
     8          , Pagination
     9          )
    10  import Dict
    11  import Http
    12  import Json.Decode
    13  import List.Extra
    14  import Maybe.Extra exposing (orElse)
    15  import Parser
    16      exposing
    17          ( (|.)
    18          , (|=)
    19          , Parser
    20          , backtrackable
    21          , chompWhile
    22          , getChompedString
    23          , keyword
    24          , map
    25          , oneOf
    26          , run
    27          , spaces
    28          , succeed
    29          , symbol
    30          )
    31  import String
    32  import Url
    33  import Url.Builder
    34  import Url.Parser exposing (parse, query)
    35  import Url.Parser.Query as Query
    36  
    37  
    38  params : Maybe Page -> List Url.Builder.QueryParameter
    39  params p =
    40      case p of
    41          Just { direction, limit } ->
    42              (case direction of
    43                  From from ->
    44                      [ Url.Builder.int "from" from ]
    45  
    46                  To to ->
    47                      [ Url.Builder.int "to" to ]
    48  
    49                  ToMostRecent ->
    50                      []
    51              )
    52                  ++ [ Url.Builder.int "limit" limit ]
    53  
    54          Nothing ->
    55              []
    56  
    57  
    58  parsePagination :
    59      Json.Decode.Decoder a
    60      -> Http.Response String
    61      -> Result String (Paginated a)
    62  parsePagination decoder response =
    63      response.body
    64          |> Json.Decode.decodeString (Json.Decode.list decoder)
    65          |> Result.mapError Json.Decode.errorToString
    66          |> Result.map
    67              (\content ->
    68                  { content = content, pagination = parseLinks response }
    69              )
    70  
    71  
    72  parseLinks : Http.Response String -> Pagination
    73  parseLinks =
    74      .headers
    75          >> Dict.toList
    76          >> List.Extra.find (Tuple.first >> String.toLower >> (==) "link")
    77          >> Maybe.map Tuple.second
    78          >> Maybe.andThen (run pagination >> Result.toMaybe)
    79          >> Maybe.withDefault { previousPage = Nothing, nextPage = Nothing }
    80  
    81  
    82  pagination : Parser Pagination
    83  pagination =
    84      let
    85          entry rel =
    86              backtrackable <|
    87                  succeed parsePage
    88                      |. symbol "<"
    89                      |= getChompedString (chompWhile <| (/=) '>')
    90                      |. symbol ">"
    91                      |. symbol ";"
    92                      |. spaces
    93                      |. keyword "rel"
    94                      |. symbol "="
    95                      |. symbol "\""
    96                      |. keyword rel
    97                      |. symbol "\""
    98      in
    99      oneOf
   100          [ succeed (\p n -> { previousPage = p, nextPage = n })
   101              |= entry previousRel
   102              |. symbol ","
   103              |. spaces
   104              |= entry nextRel
   105          , succeed (\n p -> { previousPage = p, nextPage = n })
   106              |= entry nextRel
   107              |. symbol ","
   108              |. spaces
   109              |= entry previousRel
   110          , succeed (\p -> { previousPage = p, nextPage = Nothing })
   111              |= entry previousRel
   112          , succeed (\n -> { previousPage = Nothing, nextPage = n })
   113              |= entry nextRel
   114          ]
   115  
   116  
   117  previousRel : String
   118  previousRel =
   119      "previous"
   120  
   121  
   122  nextRel : String
   123  nextRel =
   124      "next"
   125  
   126  
   127  parsePage : String -> Maybe Page
   128  parsePage url =
   129      let
   130          tryParam param =
   131              url
   132                  |> Url.fromString
   133                  -- for some reason, the `query` function returns parsers that
   134                  -- only work when the path is empty. This is probably a bug:
   135                  -- https://github.com/elm/url/issues/17
   136                  |> Maybe.map (\u -> { u | path = "" })
   137                  |> Maybe.andThen (parse <| query <| Query.int param)
   138                  |> Maybe.withDefault Nothing
   139  
   140          tryDirection dir =
   141              tryParam
   142                  >> Maybe.map
   143                      (\n ->
   144                          { direction = dir n
   145                          , limit = tryParam "limit" |> Maybe.withDefault 0
   146                          }
   147                      )
   148      in
   149      tryDirection From "from" |> orElse (tryDirection To "to")