{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE NoImplicitPrelude #-}

module Data.Morpheus.Types.ID
  ( ID (..),
  )
where

import Data.Aeson (FromJSON (..), ToJSON (..))
import Data.Hashable
import Data.Morpheus.Types.GQLScalar
  ( DecodeScalar (..),
    EncodeScalar (..),
    scalarFromJSON,
    scalarToJSON,
  )
import Data.Morpheus.Types.Internal.AST
  ( ScalarValue (..),
  )
import Data.Text (pack)
import Relude

-- | default GraphQL type,
-- parses only 'String' and 'Int' values,
-- serialized always as 'String'
newtype ID = ID
  { ID -> Text
unpackID :: Text
  }
  deriving
    ( Int -> ID -> ShowS
[ID] -> ShowS
ID -> String
(Int -> ID -> ShowS)
-> (ID -> String) -> ([ID] -> ShowS) -> Show ID
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [ID] -> ShowS
$cshowList :: [ID] -> ShowS
show :: ID -> String
$cshow :: ID -> String
showsPrec :: Int -> ID -> ShowS
$cshowsPrec :: Int -> ID -> ShowS
Show,
      (forall x. ID -> Rep ID x)
-> (forall x. Rep ID x -> ID) -> Generic ID
forall x. Rep ID x -> ID
forall x. ID -> Rep ID x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep ID x -> ID
$cfrom :: forall x. ID -> Rep ID x
Generic,
      ID -> ID -> Bool
(ID -> ID -> Bool) -> (ID -> ID -> Bool) -> Eq ID
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: ID -> ID -> Bool
$c/= :: ID -> ID -> Bool
== :: ID -> ID -> Bool
$c== :: ID -> ID -> Bool
Eq,
      Int -> ID -> Int
ID -> Int
(Int -> ID -> Int) -> (ID -> Int) -> Hashable ID
forall a. (Int -> a -> Int) -> (a -> Int) -> Hashable a
hash :: ID -> Int
$chash :: ID -> Int
hashWithSalt :: Int -> ID -> Int
$chashWithSalt :: Int -> ID -> Int
Hashable,
      String -> ID
(String -> ID) -> IsString ID
forall a. (String -> a) -> IsString a
fromString :: String -> ID
$cfromString :: String -> ID
IsString
    )

instance DecodeScalar ID where
  decodeScalar :: ScalarValue -> Either Text ID
decodeScalar (Int Int
x) = ID -> Either Text ID
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Text -> ID
ID (Text -> ID) -> Text -> ID
forall a b. (a -> b) -> a -> b
$ String -> Text
pack (String -> Text) -> String -> Text
forall a b. (a -> b) -> a -> b
$ Int -> String
forall b a. (Show a, IsString b) => a -> b
show Int
x)
  decodeScalar (String Text
x) = ID -> Either Text ID
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Text -> ID
ID Text
x)
  decodeScalar ScalarValue
_ = Text -> Either Text ID
forall a b. a -> Either a b
Left Text
"ID can only be String or number"

instance EncodeScalar ID where
  encodeScalar :: ID -> ScalarValue
encodeScalar (ID Text
x) = Text -> ScalarValue
String Text
x

instance ToJSON ID where
  toJSON :: ID -> Value
toJSON = ID -> Value
forall a. EncodeScalar a => a -> Value
scalarToJSON

instance FromJSON ID where
  parseJSON :: Value -> Parser ID
parseJSON = Value -> Parser ID
forall (m :: * -> *) a.
(Monad m, MonadFail m, DecodeScalar a) =>
Value -> m a
scalarFromJSON