Fail on cyclic fragments, fix #22
This commit is contained in:
		@@ -94,17 +94,21 @@ collectFragments = do
 | 
				
			|||||||
        _ <- fragmentDefinition nextValue
 | 
					        _ <- fragmentDefinition nextValue
 | 
				
			||||||
        collectFragments
 | 
					        collectFragments
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fragmentDefinition :: Full.FragmentDefinition -> TransformT (NonEmpty Core.Selection)
 | 
					fragmentDefinition ::
 | 
				
			||||||
 | 
					    Full.FragmentDefinition ->
 | 
				
			||||||
 | 
					    TransformT (NonEmpty Core.Selection)
 | 
				
			||||||
fragmentDefinition (Full.FragmentDefinition name _tc _dirs sels) = do
 | 
					fragmentDefinition (Full.FragmentDefinition name _tc _dirs sels) = do
 | 
				
			||||||
 | 
					    modify deleteFragmentDefinition
 | 
				
			||||||
    selections <- traverse selection sels
 | 
					    selections <- traverse selection sels
 | 
				
			||||||
    let newValue = either id pure =<< selections
 | 
					    let newValue = either id pure =<< selections
 | 
				
			||||||
    modify $ moveFragment newValue
 | 
					    modify $ insertFragment newValue
 | 
				
			||||||
    liftJust newValue
 | 
					    liftJust newValue
 | 
				
			||||||
  where
 | 
					  where
 | 
				
			||||||
    moveFragment newValue (Replacement fullFragments emptyFragDefs) =
 | 
					    deleteFragmentDefinition (Replacement fragments' fragmentDefinitions') =
 | 
				
			||||||
        let newFragments = HashMap.insert name newValue fullFragments
 | 
					        Replacement fragments' $ HashMap.delete name fragmentDefinitions'
 | 
				
			||||||
            newDefinitions = HashMap.delete name emptyFragDefs
 | 
					    insertFragment newValue (Replacement fragments' fragmentDefinitions') =
 | 
				
			||||||
         in Replacement newFragments newDefinitions
 | 
					        let newFragments = HashMap.insert name newValue fragments'
 | 
				
			||||||
 | 
					         in Replacement newFragments fragmentDefinitions'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
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
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,7 +10,13 @@ import Data.List.NonEmpty (NonEmpty(..))
 | 
				
			|||||||
import Data.Text (Text)
 | 
					import Data.Text (Text)
 | 
				
			||||||
import Language.GraphQL
 | 
					import Language.GraphQL
 | 
				
			||||||
import qualified Language.GraphQL.Schema as Schema
 | 
					import qualified Language.GraphQL.Schema as Schema
 | 
				
			||||||
import Test.Hspec (Spec, describe, it, shouldBe, shouldNotSatisfy)
 | 
					import Test.Hspec ( Spec
 | 
				
			||||||
 | 
					                  , describe
 | 
				
			||||||
 | 
					                  , it
 | 
				
			||||||
 | 
					                  , shouldBe
 | 
				
			||||||
 | 
					                  , shouldSatisfy
 | 
				
			||||||
 | 
					                  , shouldNotSatisfy
 | 
				
			||||||
 | 
					                  )
 | 
				
			||||||
import Text.RawString.QQ (r)
 | 
					import Text.RawString.QQ (r)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
size :: Schema.Resolver IO
 | 
					size :: Schema.Resolver IO
 | 
				
			||||||
@@ -37,6 +43,10 @@ inlineQuery = [r|{
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
}|]
 | 
					}|]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					hasErrors :: Value -> Bool
 | 
				
			||||||
 | 
					hasErrors (Object object') = HashMap.member "errors" object'
 | 
				
			||||||
 | 
					hasErrors _ = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
spec :: Spec
 | 
					spec :: Spec
 | 
				
			||||||
spec = describe "Inline fragment executor" $ do
 | 
					spec = describe "Inline fragment executor" $ do
 | 
				
			||||||
    it "chooses the first selection if the type matches" $ do
 | 
					    it "chooses the first selection if the type matches" $ do
 | 
				
			||||||
@@ -91,9 +101,7 @@ spec = describe "Inline fragment executor" $ do
 | 
				
			|||||||
        }|]
 | 
					        }|]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        actual <- graphql (size :| []) query
 | 
					        actual <- graphql (size :| []) query
 | 
				
			||||||
        let hasErrors (Object object') = HashMap.member "errors" object'
 | 
					        actual `shouldNotSatisfy` hasErrors
 | 
				
			||||||
            hasErrors _ = True
 | 
					 | 
				
			||||||
         in actual `shouldNotSatisfy` hasErrors
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    it "evaluates nested fragments" $ do
 | 
					    it "evaluates nested fragments" $ do
 | 
				
			||||||
        let query = [r|
 | 
					        let query = [r|
 | 
				
			||||||
@@ -140,3 +148,17 @@ spec = describe "Inline fragment executor" $ do
 | 
				
			|||||||
                    ]
 | 
					                    ]
 | 
				
			||||||
                ]
 | 
					                ]
 | 
				
			||||||
         in actual `shouldBe` expected
 | 
					         in actual `shouldBe` expected
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    it "rejects recursive" $ do
 | 
				
			||||||
 | 
					        let query = [r|
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            ...circumferenceFragment
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          fragment circumferenceFragment on Hat {
 | 
				
			||||||
 | 
					            ...circumferenceFragment
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        |]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        actual <- graphql (circumference :| []) query
 | 
				
			||||||
 | 
					        actual `shouldSatisfy` hasErrors
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user