{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RecordWildCards #-} module Data.Morpheus.Parsing.Request.Selection ( parseSelectionSet , parseFragmentDefinition ) where import Text.Megaparsec ( label , try , (<|>) ) -- -- MORPHEUS import Data.Morpheus.Parsing.Internal.Internal ( Parser , getLocation ) import Data.Morpheus.Parsing.Internal.Pattern ( optionalDirectives ) import Data.Morpheus.Parsing.Internal.Terms ( keyword , parseAlias , parseName , parseTypeCondition , setOf , spreadLiteral , token ) import Data.Morpheus.Parsing.Internal.Arguments ( maybeArguments ) import Data.Morpheus.Types.Internal.AST ( Selection(..) , SelectionContent(..) , Ref(..) , Fragment(..) , Arguments , RAW , SelectionSet , Name , Position ) -- Selection Sets : https://graphql.github.io/graphql-spec/June2018/#sec-Selection-Sets -- -- SelectionSet: -- { Selection(list) } -- -- Selection: -- Field -- FragmentSpread -- InlineFragment -- parseSelectionSet :: Parser (SelectionSet RAW) parseSelectionSet = label "SelectionSet" $ setOf parseSelection where parseSelection = label "Selection" $ try inlineFragment <|> try spread <|> parseSelectionField -- Fields: https://graphql.github.io/graphql-spec/June2018/#sec-Language.Fields -- -- Field -- Alias(opt) Name Arguments(opt) Directives(opt) SelectionSet(opt) -- parseSelectionField :: Parser (Selection RAW) parseSelectionField = label "SelectionField" $ do selectionPosition <- getLocation selectionAlias <- parseAlias selectionName <- parseName selectionArguments <- maybeArguments -- TODO: handle Directives _directives <- optionalDirectives selSet selectionName selectionAlias selectionArguments <|> pure Selection { selectionContent = SelectionField, ..} where ----------------------------------------- selSet :: Name -> Maybe Name -> Arguments RAW -> Parser (Selection RAW) selSet selectionName selectionAlias selectionArguments = label "body" $ do selectionPosition <- getLocation selectionSet <- parseSelectionSet pure Selection { selectionContent = SelectionSet selectionSet, ..} -- -- Fragments: https://graphql.github.io/graphql-spec/June2018/#sec-Language.Fragments -- -- FragmentName : Name -- -- FragmentSpread -- ...FragmentName Directives(opt) -- spread :: Parser (Selection RAW) spread = label "FragmentSpread" $ do refPosition <- spreadLiteral refName <- token -- TODO: handle Directives _directives <- optionalDirectives pure $ Spread Ref { .. } -- FragmentDefinition : https://graphql.github.io/graphql-spec/June2018/#FragmentDefinition -- -- FragmentDefinition: -- fragment FragmentName TypeCondition Directives(opt) SelectionSet -- parseFragmentDefinition :: Parser Fragment parseFragmentDefinition = label "FragmentDefinition" $ do keyword "fragment" fragmentPosition <- getLocation fragmentName <- parseName fragmentBody fragmentName fragmentPosition -- Inline Fragments : https://graphql.github.io/graphql-spec/June2018/#sec-Inline-Fragments -- -- InlineFragment: -- ... TypeCondition(opt) Directives(opt) SelectionSet -- inlineFragment :: Parser (Selection RAW) inlineFragment = label "InlineFragment" $ do fragmentPosition <- spreadLiteral InlineFragment <$> fragmentBody "INLINE_FRAGMENT" fragmentPosition fragmentBody :: Name -> Position -> Parser Fragment fragmentBody fragmentName fragmentPosition = label "FragmentBody" $ do fragmentType <- parseTypeCondition -- TODO: handle Directives _directives <- optionalDirectives fragmentSelection <- parseSelectionSet pure $ Fragment { .. }