{- This Source Code Form is subject to the terms of the Mozilla Public License,
   v. 2.0. If a copy of the MPL was not distributed with this file, You can
   obtain one at https://mozilla.org/MPL/2.0/. -}

{-# LANGUAGE ExplicitForAll #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ViewPatterns #-}

-- | Types and functions used for input and result coercion.
module Language.GraphQL.Execute.Coerce
    ( Output(..)
    , Serialize(..)
    , VariableValue(..)
    , coerceInputLiteral
    , matchFieldValues
    ) where

import qualified Data.Aeson as Aeson
import Data.Int (Int32)
import Data.HashMap.Strict (HashMap)
import qualified Data.HashMap.Strict as HashMap
import Data.Map.Strict (Map)
import Data.String (IsString(..))
import Data.Text (Text)
import qualified Data.Text.Lazy as Text.Lazy
import qualified Data.Text.Lazy.Builder as Text.Builder
import qualified Data.Text.Lazy.Builder.Int as Text.Builder
import Data.Scientific (toBoundedInteger, toRealFloat)
import Language.GraphQL.AST (Name)
import qualified Language.GraphQL.Type as Type
import qualified Language.GraphQL.Type.In as In
import qualified Language.GraphQL.Type.Out as Out

-- | Since variables are passed separately from the query, in an independent
-- format, they should be first coerced to the internal representation used by
-- this implementation.
class VariableValue a where
    -- | Only a basic, format-specific, coercion must be done here. Type
    -- correctness or nullability shouldn't be validated here, they will be
    -- validated later. The type information is provided only as a hint.
    --
    -- For example @GraphQL@ prohibits the coercion from a 't:Float' to an
    -- 't:Int', but @JSON@ doesn't have integers, so whole numbers should be
    -- coerced to 't:Int` when receiving variables as a JSON object. The same
    -- holds for 't:Enum'. There are formats that support enumerations, @JSON@
    -- doesn't, so the type information is given and 'coerceVariableValue' can
    -- check that an 't:Enum' is expected and treat the given value
    -- appropriately. Even checking whether this value is a proper member of the
    -- corresponding 't:Enum' type isn't required here, since this can be
    -- checked independently.
    --
    -- Another example is an @ID@. @GraphQL@ explicitly allows to coerce
    -- integers and strings to @ID@s, so if an @ID@ is received as an integer,
    -- it can be left as is and will be coerced later.
    --
    -- If a value cannot be coerced without losing information, 'Nothing' should
    -- be returned, the coercion will fail then and the query won't be executed.
    coerceVariableValue
        :: In.Type -- ^ Expected type (variable type given in the query).
        -> a -- ^ Variable value being coerced.
        -> Maybe Type.Value -- ^ Coerced value on success, 'Nothing' otherwise.

instance VariableValue Aeson.Value where
    coerceVariableValue :: Type -> Value -> Maybe Value
coerceVariableValue _ Aeson.Null = Value -> Maybe Value
forall a. a -> Maybe a
Just Value
Type.Null
    coerceVariableValue (In.ScalarBaseType scalarType :: ScalarType
scalarType) value :: Value
value
        | (Aeson.String stringValue :: Text
stringValue) <- Value
value = Value -> Maybe Value
forall a. a -> Maybe a
Just (Value -> Maybe Value) -> Value -> Maybe Value
forall a b. (a -> b) -> a -> b
$ Text -> Value
Type.String Text
stringValue
        | (Aeson.Bool booleanValue :: Bool
booleanValue) <- Value
value = Value -> Maybe Value
forall a. a -> Maybe a
Just (Value -> Maybe Value) -> Value -> Maybe Value
forall a b. (a -> b) -> a -> b
$ Bool -> Value
Type.Boolean Bool
booleanValue
        | (Aeson.Number numberValue :: Scientific
numberValue) <- Value
value
        , (Type.ScalarType "Float" _) <- ScalarType
scalarType =
            Value -> Maybe Value
forall a. a -> Maybe a
Just (Value -> Maybe Value) -> Value -> Maybe Value
forall a b. (a -> b) -> a -> b
$ Double -> Value
Type.Float (Double -> Value) -> Double -> Value
forall a b. (a -> b) -> a -> b
$ Scientific -> Double
forall a. RealFloat a => Scientific -> a
toRealFloat Scientific
numberValue
        | (Aeson.Number numberValue :: Scientific
numberValue) <- Value
value = -- ID or Int
            Int32 -> Value
Type.Int (Int32 -> Value) -> Maybe Int32 -> Maybe Value
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Scientific -> Maybe Int32
forall i. (Integral i, Bounded i) => Scientific -> Maybe i
toBoundedInteger Scientific
numberValue
    coerceVariableValue (In.EnumBaseType _) (Aeson.String stringValue :: Text
stringValue) =
        Value -> Maybe Value
forall a. a -> Maybe a
Just (Value -> Maybe Value) -> Value -> Maybe Value
forall a b. (a -> b) -> a -> b
$ Text -> Value
Type.Enum Text
stringValue
    coerceVariableValue (In.InputObjectBaseType objectType :: InputObjectType
objectType) value :: Value
value
        | (Aeson.Object objectValue :: Object
objectValue) <- Value
value = do
            let (In.InputObjectType _ _ inputFields :: HashMap Text InputField
inputFields) = InputObjectType
objectType
            (newObjectValue :: Object
newObjectValue, resultMap :: HashMap Text Value
resultMap) <- Object
-> HashMap Text InputField -> Maybe (Object, HashMap Text Value)
forall v k.
(VariableValue v, Eq k, Hashable k) =>
HashMap k v
-> HashMap k InputField -> Maybe (HashMap k v, HashMap k Value)
foldWithKey Object
objectValue HashMap Text InputField
inputFields
            if Object -> Bool
forall k v. HashMap k v -> Bool
HashMap.null Object
newObjectValue
                then Value -> Maybe Value
forall a. a -> Maybe a
Just (Value -> Maybe Value) -> Value -> Maybe Value
forall a b. (a -> b) -> a -> b
$ HashMap Text Value -> Value
Type.Object HashMap Text Value
resultMap
                else Maybe Value
forall a. Maybe a
Nothing
      where
        foldWithKey :: HashMap k v
-> HashMap k InputField -> Maybe (HashMap k v, HashMap k Value)
foldWithKey objectValue :: HashMap k v
objectValue = (k
 -> InputField
 -> Maybe (HashMap k v, HashMap k Value)
 -> Maybe (HashMap k v, HashMap k Value))
-> Maybe (HashMap k v, HashMap k Value)
-> HashMap k InputField
-> Maybe (HashMap k v, HashMap k Value)
forall k v a. (k -> v -> a -> a) -> a -> HashMap k v -> a
HashMap.foldrWithKey k
-> InputField
-> Maybe (HashMap k v, HashMap k Value)
-> Maybe (HashMap k v, HashMap k Value)
forall k v.
(VariableValue v, Eq k, Hashable k) =>
k
-> InputField
-> Maybe (HashMap k v, HashMap k Value)
-> Maybe (HashMap k v, HashMap k Value)
matchFieldValues'
            (Maybe (HashMap k v, HashMap k Value)
 -> HashMap k InputField -> Maybe (HashMap k v, HashMap k Value))
-> Maybe (HashMap k v, HashMap k Value)
-> HashMap k InputField
-> Maybe (HashMap k v, HashMap k Value)
forall a b. (a -> b) -> a -> b
$ (HashMap k v, HashMap k Value)
-> Maybe (HashMap k v, HashMap k Value)
forall a. a -> Maybe a
Just (HashMap k v
objectValue, HashMap k Value
forall k v. HashMap k v
HashMap.empty)
        matchFieldValues' :: k
-> InputField
-> Maybe (HashMap k v, HashMap k Value)
-> Maybe (HashMap k v, HashMap k Value)
matchFieldValues' _ _ Nothing = Maybe (HashMap k v, HashMap k Value)
forall a. Maybe a
Nothing
        matchFieldValues' fieldName :: k
fieldName inputField :: InputField
inputField (Just (objectValue :: HashMap k v
objectValue, resultMap :: HashMap k Value
resultMap)) =
            let (In.InputField _ fieldType :: Type
fieldType _) = InputField
inputField
                insert :: Value -> HashMap k Value
insert = (Value -> HashMap k Value -> HashMap k Value)
-> HashMap k Value -> Value -> HashMap k Value
forall a b c. (a -> b -> c) -> b -> a -> c
flip (k -> Value -> HashMap k Value -> HashMap k Value
forall k v.
(Eq k, Hashable k) =>
k -> v -> HashMap k v -> HashMap k v
HashMap.insert k
fieldName) HashMap k Value
resultMap
                newObjectValue :: HashMap k v
newObjectValue = k -> HashMap k v -> HashMap k v
forall k v. (Eq k, Hashable k) => k -> HashMap k v -> HashMap k v
HashMap.delete k
fieldName HashMap k v
objectValue
             in case k -> HashMap k v -> Maybe v
forall k v. (Eq k, Hashable k) => k -> HashMap k v -> Maybe v
HashMap.lookup k
fieldName HashMap k v
objectValue of
                    Just variableValue :: v
variableValue -> do
                        Value
coerced <- Type -> v -> Maybe Value
forall a. VariableValue a => Type -> a -> Maybe Value
coerceVariableValue Type
fieldType v
variableValue
                        (HashMap k v, HashMap k Value)
-> Maybe (HashMap k v, HashMap k Value)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (HashMap k v
newObjectValue, Value -> HashMap k Value
insert Value
coerced)
                    Nothing -> (HashMap k v, HashMap k Value)
-> Maybe (HashMap k v, HashMap k Value)
forall a. a -> Maybe a
Just (HashMap k v
objectValue, HashMap k Value
resultMap)
    coerceVariableValue (In.ListBaseType listType :: Type
listType) value :: Value
value
        | (Aeson.Array arrayValue :: Array
arrayValue) <- Value
value =
            [Value] -> Value
Type.List ([Value] -> Value) -> Maybe [Value] -> Maybe Value
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Value -> Maybe [Value] -> Maybe [Value])
-> Maybe [Value] -> Array -> Maybe [Value]
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr Value -> Maybe [Value] -> Maybe [Value]
forall a. VariableValue a => a -> Maybe [Value] -> Maybe [Value]
foldVector ([Value] -> Maybe [Value]
forall a. a -> Maybe a
Just []) Array
arrayValue
        | Bool
otherwise = Type -> Value -> Maybe Value
forall a. VariableValue a => Type -> a -> Maybe Value
coerceVariableValue Type
listType Value
value
      where
        foldVector :: a -> Maybe [Value] -> Maybe [Value]
foldVector _ Nothing = Maybe [Value]
forall a. Maybe a
Nothing
        foldVector variableValue :: a
variableValue (Just list :: [Value]
list) = do
            Value
coerced <- Type -> a -> Maybe Value
forall a. VariableValue a => Type -> a -> Maybe Value
coerceVariableValue Type
listType a
variableValue
            [Value] -> Maybe [Value]
forall (f :: * -> *) a. Applicative f => a -> f a
pure ([Value] -> Maybe [Value]) -> [Value] -> Maybe [Value]
forall a b. (a -> b) -> a -> b
$ Value
coerced Value -> [Value] -> [Value]
forall a. a -> [a] -> [a]
: [Value]
list 
    coerceVariableValue _ _ = Maybe Value
forall a. Maybe a
Nothing

-- | Looks up a value by name in the given map, coerces it and inserts into the
-- result map. If the coercion fails, returns 'Nothing'. If the value isn't
-- given, but a default value is known, inserts the default value into the
-- result map. Otherwise it fails with 'Nothing' if the Input Type is a
-- Non-Nullable type, or returns the unchanged, original map.
matchFieldValues :: forall a
    . (In.Type -> a -> Maybe Type.Value)
    -> HashMap Name a
    -> Name
    -> In.Type
    -> Maybe Type.Value
    -> Maybe (HashMap Name Type.Value)
    -> Maybe (HashMap Name Type.Value)
matchFieldValues :: (Type -> a -> Maybe Value)
-> HashMap Text a
-> Text
-> Type
-> Maybe Value
-> Maybe (HashMap Text Value)
-> Maybe (HashMap Text Value)
matchFieldValues coerce :: Type -> a -> Maybe Value
coerce values' :: HashMap Text a
values' fieldName :: Text
fieldName type' :: Type
type' defaultValue :: Maybe Value
defaultValue resultMap :: Maybe (HashMap Text Value)
resultMap =
    case Text -> HashMap Text a -> Maybe a
forall k v. (Eq k, Hashable k) => k -> HashMap k v -> Maybe v
HashMap.lookup Text
fieldName HashMap Text a
values' of
        Just variableValue :: a
variableValue -> Maybe Value -> Maybe (HashMap Text Value)
coerceRuntimeValue (Maybe Value -> Maybe (HashMap Text Value))
-> Maybe Value -> Maybe (HashMap Text Value)
forall a b. (a -> b) -> a -> b
$ Type -> a -> Maybe Value
coerce Type
type' a
variableValue
        Nothing
            | Just value :: Value
value <- Maybe Value
defaultValue ->
                Text -> Value -> HashMap Text Value -> HashMap Text Value
forall k v.
(Eq k, Hashable k) =>
k -> v -> HashMap k v -> HashMap k v
HashMap.insert Text
fieldName Value
value (HashMap Text Value -> HashMap Text Value)
-> Maybe (HashMap Text Value) -> Maybe (HashMap Text Value)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Maybe (HashMap Text Value)
resultMap
            | Maybe Value
Nothing <- Maybe Value
defaultValue
            , Type -> Bool
In.isNonNullType Type
type' -> Maybe (HashMap Text Value)
forall a. Maybe a
Nothing
            | Bool
otherwise -> Maybe (HashMap Text Value)
resultMap
  where
    coerceRuntimeValue :: Maybe Value -> Maybe (HashMap Text Value)
coerceRuntimeValue (Just Type.Null)
        | Type -> Bool
In.isNonNullType Type
type' = Maybe (HashMap Text Value)
forall a. Maybe a
Nothing
    coerceRuntimeValue coercedValue :: Maybe Value
coercedValue =
        Text -> Value -> HashMap Text Value -> HashMap Text Value
forall k v.
(Eq k, Hashable k) =>
k -> v -> HashMap k v -> HashMap k v
HashMap.insert Text
fieldName (Value -> HashMap Text Value -> HashMap Text Value)
-> Maybe Value -> Maybe (HashMap Text Value -> HashMap Text Value)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Maybe Value
coercedValue Maybe (HashMap Text Value -> HashMap Text Value)
-> Maybe (HashMap Text Value) -> Maybe (HashMap Text Value)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Maybe (HashMap Text Value)
resultMap

-- | Coerces operation arguments according to the input coercion rules for the
-- corresponding types.
coerceInputLiteral :: In.Type -> Type.Value -> Maybe Type.Value
coerceInputLiteral :: Type -> Value -> Maybe Value
coerceInputLiteral (Type -> Bool
In.isNonNullType -> Bool
False) Type.Null = Value -> Maybe Value
forall a. a -> Maybe a
Just Value
Type.Null
coerceInputLiteral (In.ScalarBaseType type' :: ScalarType
type') value :: Value
value
    | (Type.String stringValue :: Text
stringValue) <- Value
value
    , (Type.ScalarType "String" _) <- ScalarType
type' = Value -> Maybe Value
forall a. a -> Maybe a
Just (Value -> Maybe Value) -> Value -> Maybe Value
forall a b. (a -> b) -> a -> b
$ Text -> Value
Type.String Text
stringValue
    | (Type.Boolean booleanValue :: Bool
booleanValue) <- Value
value
    , (Type.ScalarType "Boolean" _) <- ScalarType
type' = Value -> Maybe Value
forall a. a -> Maybe a
Just (Value -> Maybe Value) -> Value -> Maybe Value
forall a b. (a -> b) -> a -> b
$ Bool -> Value
Type.Boolean Bool
booleanValue
    | (Type.Int intValue :: Int32
intValue) <- Value
value
    , (Type.ScalarType "Int" _) <- ScalarType
type' = Value -> Maybe Value
forall a. a -> Maybe a
Just (Value -> Maybe Value) -> Value -> Maybe Value
forall a b. (a -> b) -> a -> b
$ Int32 -> Value
Type.Int Int32
intValue
    | (Type.Float floatValue :: Double
floatValue) <- Value
value
    , (Type.ScalarType "Float" _) <- ScalarType
type' = Value -> Maybe Value
forall a. a -> Maybe a
Just (Value -> Maybe Value) -> Value -> Maybe Value
forall a b. (a -> b) -> a -> b
$ Double -> Value
Type.Float Double
floatValue
    | (Type.Int intValue :: Int32
intValue) <- Value
value
    , (Type.ScalarType "Float" _) <- ScalarType
type' =
        Value -> Maybe Value
forall a. a -> Maybe a
Just (Value -> Maybe Value) -> Value -> Maybe Value
forall a b. (a -> b) -> a -> b
$ Double -> Value
Type.Float (Double -> Value) -> Double -> Value
forall a b. (a -> b) -> a -> b
$ Int32 -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int32
intValue
    | (Type.String stringValue :: Text
stringValue) <- Value
value
    , (Type.ScalarType "ID" _) <- ScalarType
type' = Value -> Maybe Value
forall a. a -> Maybe a
Just (Value -> Maybe Value) -> Value -> Maybe Value
forall a b. (a -> b) -> a -> b
$ Text -> Value
Type.String Text
stringValue
    | (Type.Int intValue :: Int32
intValue) <- Value
value
    , (Type.ScalarType "ID" _) <- ScalarType
type' = Value -> Maybe Value
forall a. a -> Maybe a
Just (Value -> Maybe Value) -> Value -> Maybe Value
forall a b. (a -> b) -> a -> b
$ Int32 -> Value
decimal Int32
intValue
  where
    decimal :: Int32 -> Value
decimal = Text -> Value
Type.String
        (Text -> Value) -> (Int32 -> Text) -> Int32 -> Value
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Text
Text.Lazy.toStrict
        (Text -> Text) -> (Int32 -> Text) -> Int32 -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Builder -> Text
Text.Builder.toLazyText
        (Builder -> Text) -> (Int32 -> Builder) -> Int32 -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int32 -> Builder
forall a. Integral a => a -> Builder
Text.Builder.decimal
coerceInputLiteral (In.EnumBaseType type' :: EnumType
type') (Type.Enum enumValue :: Text
enumValue)
    | Text -> EnumType -> Bool
member Text
enumValue EnumType
type' = Value -> Maybe Value
forall a. a -> Maybe a
Just (Value -> Maybe Value) -> Value -> Maybe Value
forall a b. (a -> b) -> a -> b
$ Text -> Value
Type.Enum Text
enumValue
  where
    member :: Text -> EnumType -> Bool
member value :: Text
value (Type.EnumType _ _ members :: HashMap Text EnumValue
members) = Text -> HashMap Text EnumValue -> Bool
forall k a. (Eq k, Hashable k) => k -> HashMap k a -> Bool
HashMap.member Text
value HashMap Text EnumValue
members
coerceInputLiteral (In.InputObjectBaseType type' :: InputObjectType
type') (Type.Object values :: HashMap Text Value
values) = 
    let (In.InputObjectType _ _ inputFields :: HashMap Text InputField
inputFields) = InputObjectType
type'
     in HashMap Text Value -> Value
Type.Object
            (HashMap Text Value -> Value)
-> Maybe (HashMap Text Value) -> Maybe Value
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Text
 -> InputField
 -> Maybe (HashMap Text Value)
 -> Maybe (HashMap Text Value))
-> Maybe (HashMap Text Value)
-> HashMap Text InputField
-> Maybe (HashMap Text Value)
forall k v a. (k -> v -> a -> a) -> a -> HashMap k v -> a
HashMap.foldrWithKey (HashMap Text Value
-> Text
-> InputField
-> Maybe (HashMap Text Value)
-> Maybe (HashMap Text Value)
matchFieldValues' HashMap Text Value
values) (HashMap Text Value -> Maybe (HashMap Text Value)
forall a. a -> Maybe a
Just HashMap Text Value
forall k v. HashMap k v
HashMap.empty) HashMap Text InputField
inputFields
  where
    matchFieldValues' :: HashMap Text Value
-> Text
-> InputField
-> Maybe (HashMap Text Value)
-> Maybe (HashMap Text Value)
matchFieldValues' values' :: HashMap Text Value
values' fieldName :: Text
fieldName (In.InputField _ inputFieldType :: Type
inputFieldType defaultValue :: Maybe Value
defaultValue) =
        (Type -> Value -> Maybe Value)
-> HashMap Text Value
-> Text
-> Type
-> Maybe Value
-> Maybe (HashMap Text Value)
-> Maybe (HashMap Text Value)
forall a.
(Type -> a -> Maybe Value)
-> HashMap Text a
-> Text
-> Type
-> Maybe Value
-> Maybe (HashMap Text Value)
-> Maybe (HashMap Text Value)
matchFieldValues Type -> Value -> Maybe Value
coerceInputLiteral HashMap Text Value
values' Text
fieldName Type
inputFieldType Maybe Value
defaultValue
coerceInputLiteral (In.ListBaseType listType :: Type
listType) (Type.List list :: [Value]
list) =
    [Value] -> Value
Type.List ([Value] -> Value) -> Maybe [Value] -> Maybe Value
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Value -> Maybe Value) -> [Value] -> Maybe [Value]
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse (Type -> Value -> Maybe Value
coerceInputLiteral Type
listType) [Value]
list
coerceInputLiteral (In.ListBaseType listType :: Type
listType) singleton :: Value
singleton =
    Type -> Value -> Maybe Value
wrapSingleton Type
listType Value
singleton
  where
      wrapSingleton :: Type -> Value -> Maybe Value
wrapSingleton (In.ListBaseType listType' :: Type
listType') singleton' :: Value
singleton' =
          [Value] -> Value
Type.List ([Value] -> Value) -> Maybe [Value] -> Maybe Value
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Maybe Value] -> Maybe [Value]
forall (t :: * -> *) (m :: * -> *) a.
(Traversable t, Monad m) =>
t (m a) -> m (t a)
sequence [Type -> Value -> Maybe Value
wrapSingleton Type
listType' Value
singleton']
      wrapSingleton listType' :: Type
listType' singleton' :: Value
singleton' =
          [Value] -> Value
Type.List ([Value] -> Value) -> Maybe [Value] -> Maybe Value
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Maybe Value] -> Maybe [Value]
forall (t :: * -> *) (m :: * -> *) a.
(Traversable t, Monad m) =>
t (m a) -> m (t a)
sequence [Type -> Value -> Maybe Value
coerceInputLiteral Type
listType' Value
singleton']
coerceInputLiteral _ _ = Maybe Value
forall a. Maybe a
Nothing

-- | 'Serialize' describes how a @GraphQL@ value should be serialized.
class Serialize a where
    -- | Serializes a @GraphQL@ value according to the given serialization
    -- format.
    --
    -- Type infomration is given as a hint, e.g. if you need to know what type
    -- is being serialized to serialize it properly. Don't do any validation for
    -- @GraphQL@ built-in types here.
    --
    -- If the value cannot be serialized without losing information, return
    -- 'Nothing' — it will cause a field error.
    serialize :: forall m
        . Out.Type m -- ^ Expected output type.
        -> Output a -- ^ The value to be serialized.
        -> Maybe a -- ^ Serialized value on success or 'Nothing'.
    -- | __null__ representation in the given serialization format.
    null :: a

-- | Intermediate type used to serialize a @GraphQL@ value.
--
-- The serialization is done during the execution, and 'Output' contains
-- already serialized data (in 'List' and 'Object') as well as the new layer
-- that has to be serialized in the current step. So 'Output' is parameterized
-- by the serialization format.
data Output a
    = Int Int32
    | Float Double
    | String Text
    | Boolean Bool
    | Enum Name
    | List [a]
    | Object (Map Name a)
    deriving (Output a -> Output a -> Bool
(Output a -> Output a -> Bool)
-> (Output a -> Output a -> Bool) -> Eq (Output a)
forall a. Eq a => Output a -> Output a -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Output a -> Output a -> Bool
$c/= :: forall a. Eq a => Output a -> Output a -> Bool
== :: Output a -> Output a -> Bool
$c== :: forall a. Eq a => Output a -> Output a -> Bool
Eq, Int -> Output a -> ShowS
[Output a] -> ShowS
Output a -> String
(Int -> Output a -> ShowS)
-> (Output a -> String) -> ([Output a] -> ShowS) -> Show (Output a)
forall a. Show a => Int -> Output a -> ShowS
forall a. Show a => [Output a] -> ShowS
forall a. Show a => Output a -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Output a] -> ShowS
$cshowList :: forall a. Show a => [Output a] -> ShowS
show :: Output a -> String
$cshow :: forall a. Show a => Output a -> String
showsPrec :: Int -> Output a -> ShowS
$cshowsPrec :: forall a. Show a => Int -> Output a -> ShowS
Show)

instance forall a. IsString (Output a) where
    fromString :: String -> Output a
fromString = Text -> Output a
forall a. Text -> Output a
String (Text -> Output a) -> (String -> Text) -> String -> Output a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Text
forall a. IsString a => String -> a
fromString

instance Serialize Aeson.Value where
    serialize :: Type m -> Output Value -> Maybe Value
serialize (Out.ScalarBaseType scalarType :: ScalarType
scalarType) value :: Output Value
value
        | Type.ScalarType "Int" _ <- ScalarType
scalarType
        , Int int :: Int32
int <- Output Value
value = Value -> Maybe Value
forall a. a -> Maybe a
Just (Value -> Maybe Value) -> Value -> Maybe Value
forall a b. (a -> b) -> a -> b
$ Int32 -> Value
forall a. ToJSON a => a -> Value
Aeson.toJSON Int32
int
        | Type.ScalarType "Float" _ <- ScalarType
scalarType
        , Float float :: Double
float <- Output Value
value = Value -> Maybe Value
forall a. a -> Maybe a
Just (Value -> Maybe Value) -> Value -> Maybe Value
forall a b. (a -> b) -> a -> b
$ Double -> Value
forall a. ToJSON a => a -> Value
Aeson.toJSON Double
float
        | Type.ScalarType "String" _ <- ScalarType
scalarType
        , String string :: Text
string <- Output Value
value = Value -> Maybe Value
forall a. a -> Maybe a
Just (Value -> Maybe Value) -> Value -> Maybe Value
forall a b. (a -> b) -> a -> b
$ Text -> Value
Aeson.String Text
string
        | Type.ScalarType "ID" _ <- ScalarType
scalarType
        , String string :: Text
string <- Output Value
value = Value -> Maybe Value
forall a. a -> Maybe a
Just (Value -> Maybe Value) -> Value -> Maybe Value
forall a b. (a -> b) -> a -> b
$ Text -> Value
Aeson.String Text
string
        | Type.ScalarType "Boolean" _ <- ScalarType
scalarType
        , Boolean boolean :: Bool
boolean <- Output Value
value = Value -> Maybe Value
forall a. a -> Maybe a
Just (Value -> Maybe Value) -> Value -> Maybe Value
forall a b. (a -> b) -> a -> b
$ Bool -> Value
Aeson.Bool Bool
boolean
    serialize _ (Enum enum :: Text
enum) = Value -> Maybe Value
forall a. a -> Maybe a
Just (Value -> Maybe Value) -> Value -> Maybe Value
forall a b. (a -> b) -> a -> b
$ Text -> Value
Aeson.String Text
enum
    serialize _ (List list :: [Value]
list) = Value -> Maybe Value
forall a. a -> Maybe a
Just (Value -> Maybe Value) -> Value -> Maybe Value
forall a b. (a -> b) -> a -> b
$ [Value] -> Value
forall a. ToJSON a => a -> Value
Aeson.toJSON [Value]
list
    serialize _ (Object object :: Map Text Value
object) = Value -> Maybe Value
forall a. a -> Maybe a
Just (Value -> Maybe Value) -> Value -> Maybe Value
forall a b. (a -> b) -> a -> b
$ Map Text Value -> Value
forall a. ToJSON a => a -> Value
Aeson.toJSON Map Text Value
object
    serialize _ _ = Maybe Value
forall a. Maybe a
Nothing
    null :: Value
null = Value
Aeson.Null