Rewrite selections into a Sequence. Fix #21

This commit is contained in:
Eugen Wissner 2019-11-16 11:41:40 +01:00
parent 115aa02672
commit 7b92e5bcfd
5 changed files with 27 additions and 26 deletions

View File

@ -28,6 +28,7 @@ data-files:
dependencies: dependencies:
- aeson - aeson
- base >= 4.7 && < 5 - base >= 4.7 && < 5
- containers
- megaparsec - megaparsec
- text - text
- transformers - transformers

View File

@ -15,6 +15,7 @@ module Language.GraphQL.AST.Core
import Data.Int (Int32) import Data.Int (Int32)
import Data.HashMap.Strict (HashMap) import Data.HashMap.Strict (HashMap)
import Data.List.NonEmpty (NonEmpty) import Data.List.NonEmpty (NonEmpty)
import Data.Sequence (Seq)
import Data.String (IsString(..)) import Data.String (IsString(..))
import Data.Text (Text) import Data.Text (Text)
import Language.GraphQL.AST (Alias, Name, TypeCondition) import Language.GraphQL.AST (Alias, Name, TypeCondition)
@ -26,19 +27,21 @@ type Document = NonEmpty Operation
-- --
-- Currently only queries and mutations are supported. -- Currently only queries and mutations are supported.
data Operation data Operation
= Query (Maybe Text) (NonEmpty Selection) = Query (Maybe Text) (Seq Selection)
| Mutation (Maybe Text) (NonEmpty Selection) | Mutation (Maybe Text) (Seq Selection)
deriving (Eq, Show) deriving (Eq, Show)
-- | Single GraphQL field. -- | Single GraphQL field.
data Field = Field (Maybe Alias) Name [Argument] [Selection] deriving (Eq, Show) data Field
= Field (Maybe Alias) Name [Argument] (Seq Selection)
deriving (Eq, Show)
-- | Single argument. -- | Single argument.
data Argument = Argument Name Value deriving (Eq, Show) data Argument = Argument Name Value deriving (Eq, Show)
-- | Represents fragments and inline fragments. -- | Represents fragments and inline fragments.
data Fragment data Fragment
= Fragment TypeCondition (NonEmpty Selection) = Fragment TypeCondition (Seq Selection)
deriving (Eq, Show) deriving (Eq, Show)
-- | Single selection element. -- | Single selection element.

View File

@ -13,17 +13,19 @@ import Control.Monad (foldM, unless)
import Control.Monad.Trans.Class (lift) import Control.Monad.Trans.Class (lift)
import Control.Monad.Trans.Reader (ReaderT, ask, runReaderT) import Control.Monad.Trans.Reader (ReaderT, ask, runReaderT)
import Control.Monad.Trans.State (StateT, evalStateT, gets, modify) import Control.Monad.Trans.State (StateT, evalStateT, gets, modify)
import Data.Foldable (toList)
import Data.HashMap.Strict (HashMap) import Data.HashMap.Strict (HashMap)
import qualified Data.HashMap.Strict as HashMap import qualified Data.HashMap.Strict as HashMap
import Data.List.NonEmpty (NonEmpty)
import qualified Data.List.NonEmpty as NonEmpty import qualified Data.List.NonEmpty as NonEmpty
import Data.Sequence (Seq, (<|), (><))
import qualified Data.Sequence as Sequence
import qualified Language.GraphQL.AST as Full import qualified Language.GraphQL.AST as Full
import qualified Language.GraphQL.AST.Core as Core import qualified Language.GraphQL.AST.Core as Core
import qualified Language.GraphQL.Schema as Schema import qualified Language.GraphQL.Schema as Schema
-- | Associates a fragment name with a list of 'Core.Field's. -- | Associates a fragment name with a list of 'Core.Field's.
data Replacement = Replacement data Replacement = Replacement
{ fragments :: HashMap Core.Name (NonEmpty Core.Selection) { fragments :: HashMap Core.Name (Seq Core.Selection)
, fragmentDefinitions :: HashMap Full.Name Full.FragmentDefinition , fragmentDefinitions :: HashMap Full.Name Full.FragmentDefinition
} }
@ -63,13 +65,13 @@ operation (Full.OperationDefinition Full.Mutation name _vars _dirs sels) =
selection :: selection ::
Full.Selection -> Full.Selection ->
TransformT (Either (NonEmpty Core.Selection) Core.Selection) TransformT (Either (Seq Core.Selection) Core.Selection)
selection (Full.SelectionField fld) = Right . Core.SelectionField <$> field fld selection (Full.SelectionField fld) = Right . Core.SelectionField <$> field fld
selection (Full.SelectionFragmentSpread (Full.FragmentSpread name _)) = do selection (Full.SelectionFragmentSpread (Full.FragmentSpread name _)) = do
fragments' <- gets fragments fragments' <- gets fragments
Left <$> maybe lookupDefinition liftJust (HashMap.lookup name fragments') Left <$> maybe lookupDefinition liftJust (HashMap.lookup name fragments')
where where
lookupDefinition :: TransformT (NonEmpty Core.Selection) lookupDefinition :: TransformT (Seq Core.Selection)
lookupDefinition = do lookupDefinition = do
fragmentDefinitions' <- gets fragmentDefinitions fragmentDefinitions' <- gets fragmentDefinitions
found <- lift . lift $ HashMap.lookup name fragmentDefinitions' found <- lift . lift $ HashMap.lookup name fragmentDefinitions'
@ -96,11 +98,11 @@ collectFragments = do
fragmentDefinition :: fragmentDefinition ::
Full.FragmentDefinition -> Full.FragmentDefinition ->
TransformT (NonEmpty Core.Selection) TransformT (Seq Core.Selection)
fragmentDefinition (Full.FragmentDefinition name _tc _dirs sels) = do fragmentDefinition (Full.FragmentDefinition name _tc _dirs sels) = do
modify deleteFragmentDefinition modify deleteFragmentDefinition
selections <- traverse selection sels selections <- traverse selection sels
let newValue = either id pure =<< selections let newValue = either id pure =<< Sequence.fromList (toList selections)
modify $ insertFragment newValue modify $ insertFragment newValue
liftJust newValue liftJust newValue
where where
@ -113,7 +115,7 @@ fragmentDefinition (Full.FragmentDefinition name _tc _dirs sels) = do
field :: Full.Field -> TransformT Core.Field field :: Full.Field -> TransformT Core.Field
field (Full.Field a n args _dirs sels) = do field (Full.Field a n args _dirs sels) = do
arguments <- traverse argument args arguments <- traverse argument args
selection' <- appendSelectionOpt sels selection' <- appendSelection sels
return $ Core.Field a n arguments selection' return $ Core.Field a n arguments selection'
argument :: Full.Argument -> TransformT Core.Argument argument :: Full.Argument -> TransformT Core.Argument
@ -137,22 +139,15 @@ value (Full.Object o) =
objectField :: Full.ObjectField -> TransformT (Core.Name, Core.Value) objectField :: Full.ObjectField -> TransformT (Core.Name, Core.Value)
objectField (Full.ObjectField n v) = (n,) <$> value v objectField (Full.ObjectField n v) = (n,) <$> value v
appendSelectionOpt :: appendSelection ::
Traversable t => Traversable t =>
t Full.Selection -> t Full.Selection ->
TransformT [Core.Selection] TransformT (Seq Core.Selection)
appendSelectionOpt = foldM go [] appendSelection = foldM go mempty
where where
go acc sel = append acc <$> selection sel go acc sel = append acc <$> selection sel
append acc (Left list) = NonEmpty.toList list <> acc append acc (Left list) = list >< acc
append acc (Right one) = one : acc append acc (Right one) = one <| acc
appendSelection ::
NonEmpty Full.Selection ->
TransformT (NonEmpty Core.Selection)
appendSelection fullSelection = do
coreSelection <-appendSelectionOpt fullSelection
lift . lift $ NonEmpty.nonEmpty coreSelection
liftJust :: forall a. a -> TransformT a liftJust :: forall a. a -> TransformT a
liftJust = lift . lift . Just liftJust = lift . lift . Just

View File

@ -8,6 +8,7 @@ module Language.GraphQL.Execute
import Control.Monad.IO.Class (MonadIO) import Control.Monad.IO.Class (MonadIO)
import qualified Data.Aeson as Aeson import qualified Data.Aeson as Aeson
import Data.Foldable (toList)
import Data.List.NonEmpty (NonEmpty(..)) import Data.List.NonEmpty (NonEmpty(..))
import qualified Data.List.NonEmpty as NE import qualified Data.List.NonEmpty as NE
import Data.Text (Text) import Data.Text (Text)
@ -71,6 +72,6 @@ operation :: MonadIO m
-> AST.Core.Operation -> AST.Core.Operation
-> m Aeson.Value -> m Aeson.Value
operation schema (AST.Core.Query _ flds) operation schema (AST.Core.Query _ flds)
= runCollectErrs (Schema.resolve (NE.toList schema) (NE.toList flds)) = runCollectErrs (Schema.resolve (toList schema) flds)
operation schema (AST.Core.Mutation _ flds) operation schema (AST.Core.Mutation _ flds)
= runCollectErrs (Schema.resolve (NE.toList schema) (NE.toList flds)) = runCollectErrs (Schema.resolve (toList schema) flds)

View File

@ -28,6 +28,7 @@ import Data.Maybe (fromMaybe)
import qualified Data.Aeson as Aeson import qualified Data.Aeson as Aeson
import Data.HashMap.Strict (HashMap) import Data.HashMap.Strict (HashMap)
import qualified Data.HashMap.Strict as HashMap import qualified Data.HashMap.Strict as HashMap
import Data.Sequence (Seq)
import Data.Text (Text) import Data.Text (Text)
import qualified Data.Text as T import qualified Data.Text as T
import Language.GraphQL.AST.Core import Language.GraphQL.AST.Core
@ -118,7 +119,7 @@ withField v fld
-- 'Resolver' to each 'Field'. Resolves into a value containing the -- 'Resolver' to each 'Field'. Resolves into a value containing the
-- resolved 'Field', or a null value and error information. -- resolved 'Field', or a null value and error information.
resolve :: MonadIO m resolve :: MonadIO m
=> [Resolver m] -> [Selection] -> CollectErrsT m Aeson.Value => [Resolver m] -> Seq Selection -> CollectErrsT m Aeson.Value
resolve resolvers = fmap (Aeson.toJSON . fold) . traverse tryResolvers resolve resolvers = fmap (Aeson.toJSON . fold) . traverse tryResolvers
where where
resolveTypeName (Resolver "__typename" f) = do resolveTypeName (Resolver "__typename" f) = do