{-# LANGUAGE OverloadedStrings #-} -- | Types that can be used as both input and output types. module Language.GraphQL.Type.Definition ( Arguments(..) , Directive(..) , EnumType(..) , EnumValue(..) , ScalarType(..) , Subs , Value(..) , boolean , float , id , int , selection , string ) where import Data.Int (Int32) import Data.HashMap.Strict (HashMap) import qualified Data.HashMap.Strict as HashMap import Data.String (IsString(..)) import Data.Text (Text) import Language.GraphQL.AST (Name) import Prelude hiding (id) -- | Represents accordingly typed GraphQL values. data Value = Int Int32 | Float Double -- ^ GraphQL Float is double precision. | String Text | Boolean Bool | Null | Enum Name | List [Value] -- ^ Arbitrary nested list. | Object (HashMap Name Value) deriving (Eq, Show) instance IsString Value where fromString = String . fromString -- | Contains variables for the query. The key of the map is a variable name, -- and the value is the variable value. type Subs = HashMap Name Value -- | Argument list. newtype Arguments = Arguments (HashMap Name Value) deriving (Eq, Show) instance Semigroup Arguments where (Arguments x) <> (Arguments y) = Arguments $ x <> y instance Monoid Arguments where mempty = Arguments mempty -- | Scalar type definition. -- -- The leaf values of any request and input values to arguments are Scalars (or -- Enums) . data ScalarType = ScalarType Name (Maybe Text) instance Eq ScalarType where (ScalarType this _) == (ScalarType that _) = this == that -- | Enum type definition. -- -- Some leaf values of requests and input values are Enums. GraphQL serializes -- Enum values as strings, however internally Enums can be represented by any -- kind of type, often integers. data EnumType = EnumType Name (Maybe Text) (HashMap Name EnumValue) instance Eq EnumType where (EnumType this _ _) == (EnumType that _ _) = this == that -- | Enum value is a single member of an 'EnumType'. newtype EnumValue = EnumValue (Maybe Text) -- | The @String@ scalar type represents textual data, represented as UTF-8 -- character sequences. The String type is most often used by GraphQL to -- represent free-form human-readable text. string :: ScalarType string = ScalarType "String" (Just description) where description = "The `String` scalar type represents textual data, represented as \ \UTF-8 character sequences. The String type is most often used by \ \GraphQL to represent free-form human-readable text." -- | The @Boolean@ scalar type represents @true@ or @false@. boolean :: ScalarType boolean = ScalarType "Boolean" (Just description) where description = "The `Boolean` scalar type represents `true` or `false`." -- | The @Int@ scalar type represents non-fractional signed whole numeric -- values. Int can represent values between \(-2^{31}\) and \(2^{31 - 1}\). int :: ScalarType int = ScalarType "Int" (Just description) where description = "The `Int` scalar type represents non-fractional signed whole numeric \ \values. Int can represent values between -(2^31) and 2^31 - 1." -- | The @Float@ scalar type represents signed double-precision fractional -- values as specified by -- [IEEE 754](https://en.wikipedia.org/wiki/IEEE_floating_point). float :: ScalarType float = ScalarType "Float" (Just description) where description = "The `Float` scalar type represents signed double-precision fractional \ \values as specified by \ \[IEEE 754](https://en.wikipedia.org/wiki/IEEE_floating_point)." -- | The @ID@ scalar type represents a unique identifier, often used to refetch -- an object or as key for a cache. The ID type appears in a JSON response as a -- String; however, it is not intended to be human-readable. When expected as an -- input type, any string (such as @"4"@) or integer (such as @4@) input value -- will be accepted as an ID. id :: ScalarType id = ScalarType "ID" (Just description) where description = "The `ID` scalar type represents a unique identifier, often used to \ \refetch an object or as key for a cache. The ID type appears in a \ \JSON response as a String; however, it is not intended to be \ \human-readable. When expected as an input type, any string (such as \ \`\"4\"`) or integer (such as `4`) input value will be accepted as an ID." -- | Directive. data Directive = Directive Name Arguments deriving (Eq, Show) -- | Directive processing status. data Status = Skip -- ^ Skip the selection and stop directive processing | Include Directive -- ^ The directive was processed, try other handlers | Continue Directive -- ^ Directive handler mismatch, try other handlers -- | Takes a list of directives, handles supported directives and excludes them -- from the result. If the selection should be skipped, returns 'Nothing'. selection :: [Directive] -> Maybe [Directive] selection = foldr go (Just []) where go directive' directives' = case (skip . include) (Continue directive') of (Include _) -> directives' Skip -> Nothing (Continue x) -> (x :) <$> directives' handle :: (Directive -> Status) -> Status -> Status handle _ Skip = Skip handle handler (Continue directive) = handler directive handle handler (Include directive) = handler directive -- * Directive implementations skip :: Status -> Status skip = handle skip' where skip' directive'@(Directive "skip" (Arguments arguments)) = case HashMap.lookup "if" arguments of (Just (Boolean True)) -> Skip _ -> Include directive' skip' directive' = Continue directive' include :: Status -> Status include = handle include' where include' directive'@(Directive "include" (Arguments arguments)) = case HashMap.lookup "if" arguments of (Just (Boolean True)) -> Include directive' _ -> Skip include' directive' = Continue directive'