packages feed

hix-0.9.0: lib/Hix/Hackage.hs

module Hix.Hackage where

import qualified Data.Aeson as Aeson
import Data.Aeson (FromJSON (parseJSON), ToJSON, withObject, (.:))

import Hix.Data.Monad (M)
import Hix.Managed.Handlers.HackageClient (
  HackageClient (..),
  HackageError (..),
  HackageRequest (..),
  HackageResponse (HackageResponseJson),
  )
import Hix.Monad (fatalError)

data HackageVersions =
  HackageVersions {
    versions :: [String]
  }
  deriving stock (Eq, Show, Generic)

instance FromJSON HackageVersions where
  parseJSON = withObject "HackageVersions" \ o -> HackageVersions <$> o .: "normal-version"

hackageRequest ::
  ∀ a b .
  (a -> Either Text b) ->
  HackageClient ->
  HackageRequest a ->
  M (Either HackageError b)
hackageRequest process HackageClient {request = run} request = do
  response <- run request
  pure (first HackageParseError . process =<< response)

hackageGet ::
  ∀ a b .
  (a -> Either Text b) ->
  HackageClient ->
  Text ->
  HackageResponse a ->
  M (Either HackageError b)
hackageGet process client path accept =
  hackageRequest process client HackageRequest {
    method = "GET",
    path,
    body = Nothing,
    query = Nothing,
    accept
  }

hackagePostJson ::
  ∀ a b body .
  FromJSON a =>
  Typeable a =>
  ToJSON body =>
  (a -> Either Text b) ->
  HackageClient ->
  Text ->
  body ->
  M (Either HackageError b)
hackagePostJson process client path body =
  hackageRequest process client HackageRequest {
    method = "POST",
    path,
    body = Just (Right (Aeson.encode body)),
    query = Nothing,
    accept = HackageResponseJson
  }

hackagePostQuery ::
  ∀ a b .
  (a -> Either Text b) ->
  HackageClient ->
  Text ->
  NonEmpty (Text, Text) ->
  HackageResponse a ->
  M (Either HackageError b)
hackagePostQuery process client path query accept =
  hackageRequest process client HackageRequest {
    method = "POST",
    path,
    body = Nothing,
    query = Just (bimap encodeUtf8 encodeUtf8 <$> query),
    accept
  }

hackagePostForm ::
  ∀ a b .
  (a -> Either Text b) ->
  HackageClient ->
  Text ->
  NonEmpty (Text, Text) ->
  HackageResponse a ->
  M (Either HackageError b)
hackagePostForm process client path fields accept =
  hackageRequest process client HackageRequest {
    method = "POST",
    path,
    body = Just (Left fields),
    query = Nothing,
    accept
  }

hackagePut ::
  ∀ a b .
  FromJSON a =>
  Typeable a =>
  (a -> Either Text b) ->
  HackageClient ->
  Text ->
  M (Either HackageError b)
hackagePut process client path =
  hackageRequest process client HackageRequest {
    method = "PUT",
    path,
    body = Nothing,
    query = Nothing,
    accept = HackageResponseJson
  }

fatalHackageRequest :: Either HackageError a -> M a
fatalHackageRequest =
  leftA $ fatalError . \case
    HackageNotFound -> "Not found"
    HackageFatal msg -> msg
    HackageParseError msg -> msg