{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DeriveLift #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Data.Morpheus.Types.Internal.AST.Value
( Value(..)
, ScalarValue(..)
, Object
, GQLValue(..)
, replaceValue
, decodeScientific
, convertToJSONName
, convertToHaskellName
)
where
import qualified Data.Aeson as A
( FromJSON(..)
, ToJSON(..)
, Value(..)
, object
, pairs
, (.=)
)
import qualified Data.HashMap.Strict as M
( toList )
import Data.Scientific ( Scientific
, floatingOrInteger
)
import Data.Semigroup ( (<>) )
import Data.Text ( Text )
import qualified Data.Text as T
import qualified Data.Vector as V
( toList )
import GHC.Generics ( Generic )
import Instances.TH.Lift ( )
import Language.Haskell.TH.Syntax ( Lift )
isReserved :: Text -> Bool
isReserved "case" = True
isReserved "class" = True
isReserved "data" = True
isReserved "default" = True
isReserved "deriving" = True
isReserved "do" = True
isReserved "else" = True
isReserved "foreign" = True
isReserved "if" = True
isReserved "import" = True
isReserved "in" = True
isReserved "infix" = True
isReserved "infixl" = True
isReserved "infixr" = True
isReserved "instance" = True
isReserved "let" = True
isReserved "module" = True
isReserved "newtype" = True
isReserved "of" = True
isReserved "then" = True
isReserved "type" = True
isReserved "where" = True
isReserved "_" = True
isReserved _ = False
{-# INLINE isReserved #-}
convertToJSONName :: Text -> Text
convertToJSONName hsName
| not (T.null hsName) && isReserved name && (T.last hsName == '\'') = name
| otherwise = hsName
where name = T.init hsName
convertToHaskellName :: Text -> Text
convertToHaskellName name | isReserved name = name <> "'"
| otherwise = name
data ScalarValue
= Int Int
| Float Float
| String Text
| Boolean Bool
deriving (Show, Generic,Lift)
instance A.ToJSON ScalarValue where
toJSON (Float x) = A.toJSON x
toJSON (Int x) = A.toJSON x
toJSON (Boolean x) = A.toJSON x
toJSON (String x) = A.toJSON x
instance A.FromJSON ScalarValue where
parseJSON (A.Bool v) = pure $ Boolean v
parseJSON (A.Number v) = pure $ decodeScientific v
parseJSON (A.String v) = pure $ String v
parseJSON notScalar = fail $ "Expected Scalar got :" <> show notScalar
type Object = [(Text, Value)]
data Value
= Object Object
| List [Value]
| Enum Text
| Scalar ScalarValue
| Null
deriving (Show, Generic,Lift)
instance A.ToJSON Value where
toEncoding Null = A.toEncoding A.Null
toEncoding (Enum x ) = A.toEncoding x
toEncoding (List x ) = A.toEncoding x
toEncoding (Scalar x ) = A.toEncoding x
toEncoding (Object []) = A.toEncoding $ A.object []
toEncoding (Object x ) = A.pairs $ foldl1 (<>) $ map encodeField x
where encodeField (key, value) = convertToJSONName key A..= value
decodeScientific :: Scientific -> ScalarValue
decodeScientific v = case floatingOrInteger v of
Left float -> Float float
Right int -> Int int
replaceValue :: A.Value -> Value
replaceValue (A.Bool v) = gqlBoolean v
replaceValue (A.Number v) = Scalar $ decodeScientific v
replaceValue (A.String v) = gqlString v
replaceValue (A.Object v) = gqlObject $ map replace (M.toList v)
where
replace :: (a, A.Value) -> (a, Value)
replace (key, val) = (key, replaceValue val)
replaceValue (A.Array li) = gqlList (map replaceValue (V.toList li))
replaceValue A.Null = gqlNull
instance A.FromJSON Value where
parseJSON = pure . replaceValue
class GQLValue a where
gqlNull :: a
gqlScalar :: ScalarValue -> a
gqlBoolean :: Bool -> a
gqlString :: Text -> a
gqlList :: [a] -> a
gqlObject :: [(Text, a)] -> a
instance GQLValue Value where
gqlNull = Null
gqlScalar = Scalar
gqlBoolean = Scalar . Boolean
gqlString = Scalar . String
gqlList = List
gqlObject = Object