packages feed

mig-extra-0.1.0.0: src/Mig/Extra/Derive.hs

{-# LANGUAGE PartialTypeSignatures #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE TemplateHaskell #-}

-- | Derive standard HTTP-classes
module Mig.Extra.Derive (
  deriveParam,
  deriveNewtypeParam,
  deriveBody,
  deriveParamBody,
  deriveNewtypeBody,
  deriveNewtypeParamBody,
  deriveHttp,
  deriveNewtypeHttp,
  deriveNewtypeForm,
  deriveForm,
  mapDerive,

  -- * useful with derive-topdown library
  paramClasses,
  bodyClasses,
  paramBodyClasses,
  httpClasses,
) where

import Data.Aeson (FromJSON, ToJSON)
import Data.OpenApi (ToParamSchema, ToSchema)
import GHC.Generics (Generic)
import Language.Haskell.TH
import Web.FormUrlEncoded (FromForm, ToForm)
import Web.HttpApiData (FromHttpApiData, ToHttpApiData)

paramClasses :: [Name]
paramClasses = [''Show, ''Eq, ''Ord, ''Generic, ''ToJSON, ''FromJSON, ''ToParamSchema, ''ToHttpApiData, ''FromHttpApiData]

bodyClasses :: [Name]
bodyClasses = [''Show, ''Eq, ''Ord, ''Generic, ''ToJSON, ''FromJSON, ''ToSchema, ''ToHttpApiData, ''FromHttpApiData]

paramBodyClasses :: [Name]
paramBodyClasses = [''Show, ''Eq, ''Ord, ''Generic, ''ToJSON, ''FromJSON, ''ToParamSchema, ''ToSchema, ''ToHttpApiData, ''FromHttpApiData]

httpClasses :: [Name]
httpClasses = [''Show, ''Eq, ''Ord, ''Generic, ''ToJSON, ''FromJSON, ''ToParamSchema, ''ToSchema, ''ToHttpApiData, ''FromHttpApiData]

mapDerive :: (Name -> Q [Dec]) -> [Name] -> Q [Dec]
mapDerive f types = fmap concat (mapM f types)

-- | Derives standard WEB-classes for a newtype suitable for request parameter
deriveNewtypeParam :: Name -> Q [Dec]
deriveNewtypeParam typeName = do
  let typeCon = conT typeName
  [d|
    deriving newtype instance Show $(typeCon)

    deriving newtype instance Eq $(typeCon)

    deriving newtype instance Ord $(typeCon)

    deriving newtype instance ToJSON $(typeCon)

    deriving newtype instance FromJSON $(typeCon)

    deriving newtype instance ToParamSchema $(typeCon)

    deriving newtype instance ToHttpApiData $(typeCon)

    deriving newtype instance FromHttpApiData $(typeCon)
    |]

-- | Derives standard WEB-classes for a type suitable for request parameter
deriveParam :: Name -> Q [Dec]
deriveParam typeName = do
  let typeCon = conT typeName
  [d|
    deriving stock instance Show $(typeCon)

    deriving stock instance Eq $(typeCon)

    deriving stock instance Ord $(typeCon)

    deriving instance Generic $(typeCon)

    deriving anyclass instance ToJSON $(typeCon)

    deriving anyclass instance FromJSON $(typeCon)

    deriving anyclass instance ToParamSchema $(typeCon)

    deriving anyclass instance ToHttpApiData $(typeCon)

    deriving anyclass instance FromHttpApiData $(typeCon)
    |]

-- | Derives standard WEB-classes for a newtype suitable for request body or response
deriveNewtypeBody :: Name -> Q [Dec]
deriveNewtypeBody typeName = do
  let typeCon = conT typeName
  [d|
    deriving newtype instance Show $(typeCon)

    deriving newtype instance Eq $(typeCon)

    deriving newtype instance Ord $(typeCon)

    deriving newtype instance ToJSON $(typeCon)

    deriving newtype instance FromJSON $(typeCon)

    deriving newtype instance ToSchema $(typeCon)
    |]

-- | Derives standard WEB-classes for a type suitable for request body or response
deriveBody :: Name -> Q [Dec]
deriveBody typeName = do
  let typeCon = conT typeName
  [d|
    deriving instance Show $(typeCon)

    deriving instance Eq $(typeCon)

    deriving instance Ord $(typeCon)

    deriving instance Generic $(typeCon)

    deriving instance ToJSON $(typeCon)

    deriving instance FromJSON $(typeCon)

    deriving instance ToSchema $(typeCon)
    |]

-- | Derives standard WEB-classes for a newtype suitable for request form
deriveNewtypeForm :: Name -> Q [Dec]
deriveNewtypeForm typeName = do
  let typeCon = conT typeName
  [d|
    deriving newtype instance Show $(typeCon)

    deriving newtype instance Eq $(typeCon)

    deriving newtype instance Ord $(typeCon)

    deriving newtype instance ToForm $(typeCon)

    deriving newtype instance FromForm $(typeCon)

    deriving newtype instance ToSchema $(typeCon)
    |]

-- | Derives standard WEB-classes for a type suitable for request form
deriveForm :: Name -> Q [Dec]
deriveForm typeName = do
  let typeCon = conT typeName
  [d|
    deriving instance Show $(typeCon)

    deriving instance Eq $(typeCon)

    deriving instance Ord $(typeCon)

    deriving instance Generic $(typeCon)

    deriving instance FromForm $(typeCon)

    deriving instance ToForm $(typeCon)

    deriving instance ToSchema $(typeCon)
    |]

deriveNewtypeHttp :: Name -> Q [Dec]
deriveNewtypeHttp = deriveNewtypeParamBody

deriveHttp :: Name -> Q [Dec]
deriveHttp = deriveParamBody

-- | Derives standard WEB-classes for a newtype which is both body and param
deriveNewtypeParamBody :: Name -> Q [Dec]
deriveNewtypeParamBody typeName = do
  let typeCon = conT typeName
  [d|
    deriving newtype instance Show $(typeCon)

    deriving newtype instance Eq $(typeCon)

    deriving newtype instance Ord $(typeCon)

    deriving newtype instance ToJSON $(typeCon)

    deriving newtype instance FromJSON $(typeCon)

    deriving newtype instance ToSchema $(typeCon)

    deriving newtype instance ToParamSchema $(typeCon)

    deriving newtype instance ToHttpApiData $(typeCon)

    deriving newtype instance FromHttpApiData $(typeCon)
    |]

-- | Derives standard WEB-classes for a type which is both body and param
deriveParamBody :: Name -> Q [Dec]
deriveParamBody typeName = do
  let typeCon = conT typeName
  [d|
    deriving stock instance Show $(typeCon)

    deriving stock instance Eq $(typeCon)

    deriving stock instance Ord $(typeCon)

    deriving stock instance Generic $(typeCon)

    deriving anyclass instance ToJSON $(typeCon)

    deriving anyclass instance FromJSON $(typeCon)

    deriving anyclass instance ToSchema $(typeCon)

    deriving anyclass instance ToParamSchema $(typeCon)

    deriving anyclass instance ToHttpApiData $(typeCon)

    deriving anyclass instance FromHttpApiData $(typeCon)
    |]