2022-01-16 17:30:18 +01:00
|
|
|
{-# LANGUAGE OverloadedStrings #-}
|
|
|
|
|
2022-01-15 11:50:20 +01:00
|
|
|
module Language.GraphQL.Serialize
|
|
|
|
( JSON(..)
|
|
|
|
) where
|
|
|
|
|
|
|
|
import qualified Data.Aeson as Aeson
|
2022-01-16 17:30:18 +01:00
|
|
|
import qualified Data.Aeson.Key as Aeson.Key
|
2022-01-18 13:00:58 +01:00
|
|
|
import qualified Data.Aeson.KeyMap as KeyMap
|
|
|
|
import Data.HashMap.Strict (HashMap)
|
|
|
|
import qualified Data.HashMap.Strict as HashMap
|
|
|
|
import Data.Scientific (toBoundedInteger, toRealFloat)
|
|
|
|
import Data.Text (Text)
|
|
|
|
import Language.GraphQL.AST (Name)
|
2022-01-16 17:30:18 +01:00
|
|
|
import Language.GraphQL.Execute.Coerce
|
|
|
|
import qualified Language.GraphQL.Execute.OrderedMap as OrderedMap
|
2022-01-18 13:00:58 +01:00
|
|
|
import qualified Language.GraphQL.Type.In as In
|
2022-01-16 17:30:18 +01:00
|
|
|
import qualified Language.GraphQL.Type.Out as Out
|
|
|
|
import qualified Language.GraphQL.Type as Type
|
2022-01-15 11:50:20 +01:00
|
|
|
|
|
|
|
newtype JSON = JSON Aeson.Value
|
2022-01-16 17:30:18 +01:00
|
|
|
|
|
|
|
instance Aeson.ToJSON JSON where
|
|
|
|
toJSON (JSON value) = value
|
|
|
|
|
|
|
|
instance Aeson.FromJSON JSON where
|
|
|
|
parseJSON = pure . JSON
|
|
|
|
|
|
|
|
instance Serialize JSON where
|
|
|
|
serialize (Out.ScalarBaseType scalarType) value
|
|
|
|
| Type.ScalarType "Int" _ <- scalarType
|
|
|
|
, Int int <- value = Just $ JSON $ Aeson.Number $ fromIntegral int
|
|
|
|
| Type.ScalarType "Float" _ <- scalarType
|
|
|
|
, Float float <- value = Just $ JSON $ Aeson.toJSON float
|
|
|
|
| Type.ScalarType "String" _ <- scalarType
|
|
|
|
, String string <- value = Just $ JSON $ Aeson.String string
|
|
|
|
| Type.ScalarType "ID" _ <- scalarType
|
|
|
|
, String string <- value = Just $ JSON $ Aeson.String string
|
|
|
|
| Type.ScalarType "Boolean" _ <- scalarType
|
|
|
|
, Boolean boolean <- value = Just $ JSON $ Aeson.Bool boolean
|
|
|
|
serialize _ (Enum enum) = Just $ JSON $ Aeson.String enum
|
|
|
|
serialize _ (List list) = Just $ JSON $ Aeson.toJSON list
|
|
|
|
serialize _ (Object object) = Just
|
|
|
|
$ JSON
|
|
|
|
$ Aeson.object
|
|
|
|
$ toJSONKeyValue <$> OrderedMap.toList object
|
|
|
|
where
|
|
|
|
toJSONKeyValue (key, value) = (Aeson.Key.fromText key, Aeson.toJSON value)
|
|
|
|
serialize _ _ = Nothing
|
|
|
|
null = JSON Aeson.Null
|
2022-01-18 13:00:58 +01:00
|
|
|
|
2022-01-19 10:41:55 +01:00
|
|
|
instance VariableValue JSON where
|
|
|
|
coerceVariableValue _ (JSON Aeson.Null) = Just Type.Null
|
|
|
|
coerceVariableValue (In.ScalarBaseType scalarType) (JSON value)
|
2022-01-18 13:00:58 +01:00
|
|
|
| (Aeson.String stringValue) <- value = Just $ Type.String stringValue
|
|
|
|
| (Aeson.Bool booleanValue) <- value = Just $ Type.Boolean booleanValue
|
|
|
|
| (Aeson.Number numberValue) <- value
|
|
|
|
, (Type.ScalarType "Float" _) <- scalarType =
|
|
|
|
Just $ Type.Float $ toRealFloat numberValue
|
|
|
|
| (Aeson.Number numberValue) <- value = -- ID or Int
|
|
|
|
Type.Int <$> toBoundedInteger numberValue
|
2022-01-19 10:41:55 +01:00
|
|
|
coerceVariableValue (In.EnumBaseType _) (JSON (Aeson.String stringValue)) =
|
2022-01-18 13:00:58 +01:00
|
|
|
Just $ Type.Enum stringValue
|
2022-01-19 10:41:55 +01:00
|
|
|
coerceVariableValue (In.InputObjectBaseType objectType) (JSON value)
|
2022-01-18 13:00:58 +01:00
|
|
|
| (Aeson.Object objectValue) <- value = do
|
|
|
|
let (In.InputObjectType _ _ inputFields) = objectType
|
|
|
|
(newObjectValue, resultMap) <- foldWithKey objectValue inputFields
|
|
|
|
if KeyMap.null newObjectValue
|
|
|
|
then Just $ Type.Object resultMap
|
|
|
|
else Nothing
|
|
|
|
where
|
|
|
|
foldWithKey :: Aeson.Object
|
|
|
|
-> HashMap Name In.InputField
|
|
|
|
-> Maybe (Aeson.Object, HashMap Name Type.Value)
|
|
|
|
foldWithKey objectValue = HashMap.foldrWithKey matchFieldValues'
|
|
|
|
$ Just (objectValue, HashMap.empty)
|
|
|
|
matchFieldValues' :: Text
|
|
|
|
-> In.InputField
|
|
|
|
-> Maybe (Aeson.Object, HashMap Name Type.Value)
|
|
|
|
-> Maybe (Aeson.Object, HashMap Name Type.Value)
|
|
|
|
matchFieldValues' _ _ Nothing = Nothing
|
|
|
|
matchFieldValues' fieldName inputField (Just (objectValue, resultMap)) =
|
|
|
|
let fieldKey = Aeson.Key.fromText fieldName
|
|
|
|
In.InputField _ fieldType _ = inputField
|
|
|
|
insert = flip (HashMap.insert fieldName) resultMap
|
|
|
|
newObjectValue = KeyMap.delete fieldKey objectValue
|
|
|
|
in case KeyMap.lookup fieldKey objectValue of
|
|
|
|
Just variableValue -> do
|
2022-01-19 10:41:55 +01:00
|
|
|
coerced <- coerceVariableValue fieldType
|
|
|
|
$ JSON variableValue
|
2022-01-18 13:00:58 +01:00
|
|
|
pure (newObjectValue, insert coerced)
|
|
|
|
Nothing -> Just (objectValue, resultMap)
|
2022-01-19 10:41:55 +01:00
|
|
|
coerceVariableValue (In.ListBaseType listType) (JSON value)
|
2022-01-18 13:00:58 +01:00
|
|
|
| (Aeson.Array arrayValue) <- value =
|
|
|
|
Type.List <$> foldr foldVector (Just []) arrayValue
|
2022-01-19 10:41:55 +01:00
|
|
|
| otherwise = coerceVariableValue listType $ JSON value
|
2022-01-18 13:00:58 +01:00
|
|
|
where
|
|
|
|
foldVector _ Nothing = Nothing
|
|
|
|
foldVector variableValue (Just list) = do
|
2022-01-19 10:41:55 +01:00
|
|
|
coerced <- coerceVariableValue listType $ JSON variableValue
|
2022-01-18 13:00:58 +01:00
|
|
|
pure $ coerced : list
|
|
|
|
coerceVariableValue _ _ = Nothing
|