{-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE PolyKinds #-} module Hercules.API.Id ( Id (..), idText, uncheckedCast, ) where import Control.DeepSeq (NFData) import Control.Lens ((?~)) import Data.Aeson import Data.Aeson.Types (toJSONKeyText) import Data.Function ((&)) import Data.Hashable (Hashable (..)) import Data.Swagger ( NamedSchema (NamedSchema), ParamSchema, SwaggerType (SwaggerString), ToParamSchema (..), ToSchema (..), format, paramSchemaToSchema, type_, ) import Data.Text (Text) import Data.UUID (UUID) import qualified Data.UUID as UUID import GHC.Generics (Generic) import Web.HttpApiData import Prelude newtype Id (a :: k) = Id {idUUID :: UUID} deriving (Generic, Eq, Ord, NFData) instance Hashable (Id a) where hashWithSalt s (Id uuid) = let (a, b, c, d) = UUID.toWords uuid in s `hashWithSalt` a `hashWithSalt` b `hashWithSalt` c `hashWithSalt` d idText :: Id a -> Text idText = UUID.toText . idUUID uncheckedCast :: Id a -> Id b uncheckedCast (Id s) = Id s instance Show (Id a) where showsPrec n = showsPrec n . idText instance ToJSON (Id a) where toEncoding = toEncoding . idText toJSON = toJSON . idText instance FromJSON (Id a) where parseJSON = fmap Id . parseJSON instance ToJSONKey (Id a) where toJSONKey = toJSONKeyText idText instance FromJSONKey (Id a) where fromJSONKey = FromJSONKeyTextParser $ \text -> case UUID.fromText text of Just x -> pure $ Id x Nothing -> fail "Expected UUID" instance ToHttpApiData (Id a) where toUrlPiece = idText instance FromHttpApiData (Id a) where parseUrlPiece = fmap Id . parseUrlPiece instance ToSchema (Id a) where declareNamedSchema = pure . NamedSchema Nothing . paramSchemaToSchema instance ToParamSchema (Id a) where toParamSchema _ = (mempty :: ParamSchema t) & type_ ?~ SwaggerString & format ?~ "uuid"