packages feed

graphql 0.2.1 → 0.3

raw patch · 10 files changed

+377/−97 lines, 10 filesdep +tasty-hunitdep −bytestringdep −tasty-goldendep ~attoparsecdep ~textPVP ok

version bump matches the API change (PVP)

Dependencies added: tasty-hunit

Dependencies removed: bytestring, tasty-golden

Dependency ranges changed: attoparsec, text

API changes (from Hackage documentation)

- Data.GraphQL.Parser: bool :: Parser Bool
+ Data.GraphQL.AST: Node :: Name -> [VariableDefinition] -> [Directive] -> SelectionSet -> Node
+ Data.GraphQL.AST: StringValue :: Text -> StringValue
+ Data.GraphQL.AST: data Node
+ Data.GraphQL.AST: instance Eq Node
+ Data.GraphQL.AST: instance Eq StringValue
+ Data.GraphQL.AST: instance Show Node
+ Data.GraphQL.AST: instance Show StringValue
+ Data.GraphQL.AST: newtype StringValue
+ Data.GraphQL.Encoder: argument :: Argument -> Text
+ Data.GraphQL.Encoder: arguments :: [Argument] -> Text
+ Data.GraphQL.Encoder: argumentsDefinition :: ArgumentsDefinition -> Text
+ Data.GraphQL.Encoder: between :: Char -> Char -> Text -> Text
+ Data.GraphQL.Encoder: booleanValue :: Bool -> Text
+ Data.GraphQL.Encoder: braces :: Text -> Text
+ Data.GraphQL.Encoder: bracesCommas :: (a -> Text) -> [a] -> Text
+ Data.GraphQL.Encoder: brackets :: Text -> Text
+ Data.GraphQL.Encoder: bracketsCommas :: (a -> Text) -> [a] -> Text
+ Data.GraphQL.Encoder: defaultValue :: DefaultValue -> Text
+ Data.GraphQL.Encoder: definition :: Definition -> Text
+ Data.GraphQL.Encoder: directive :: Directive -> Text
+ Data.GraphQL.Encoder: directives :: [Directive] -> Text
+ Data.GraphQL.Encoder: document :: Document -> Text
+ Data.GraphQL.Encoder: enumTypeDefinition :: EnumTypeDefinition -> Text
+ Data.GraphQL.Encoder: enumValueDefinition :: EnumValueDefinition -> Text
+ Data.GraphQL.Encoder: field :: Field -> Text
+ Data.GraphQL.Encoder: fieldDefinition :: FieldDefinition -> Text
+ Data.GraphQL.Encoder: fieldDefinitions :: [FieldDefinition] -> Text
+ Data.GraphQL.Encoder: fragmentDefinition :: FragmentDefinition -> Text
+ Data.GraphQL.Encoder: fragmentSpread :: FragmentSpread -> Text
+ Data.GraphQL.Encoder: inlineFragment :: InlineFragment -> Text
+ Data.GraphQL.Encoder: inputObjectTypeDefinition :: InputObjectTypeDefinition -> Text
+ Data.GraphQL.Encoder: inputValueDefinition :: InputValueDefinition -> Text
+ Data.GraphQL.Encoder: inputValueDefinitions :: [InputValueDefinition] -> Text
+ Data.GraphQL.Encoder: interfaceTypeDefinition :: InterfaceTypeDefinition -> Text
+ Data.GraphQL.Encoder: interfaces :: Interfaces -> Text
+ Data.GraphQL.Encoder: listType :: ListType -> Text
+ Data.GraphQL.Encoder: listValue :: ListValue -> Text
+ Data.GraphQL.Encoder: namedType :: NamedType -> Text
+ Data.GraphQL.Encoder: node :: Node -> Text
+ Data.GraphQL.Encoder: nonNullType :: NonNullType -> Text
+ Data.GraphQL.Encoder: objectField :: ObjectField -> Text
+ Data.GraphQL.Encoder: objectTypeDefinition :: ObjectTypeDefinition -> Text
+ Data.GraphQL.Encoder: objectValue :: ObjectValue -> Text
+ Data.GraphQL.Encoder: operationDefinition :: OperationDefinition -> Text
+ Data.GraphQL.Encoder: optempty :: (Eq a, Monoid a, Monoid b) => (a -> b) -> a -> b
+ Data.GraphQL.Encoder: parens :: Text -> Text
+ Data.GraphQL.Encoder: parensCommas :: (a -> Text) -> [a] -> Text
+ Data.GraphQL.Encoder: quotes :: Text -> Text
+ Data.GraphQL.Encoder: scalarTypeDefinition :: ScalarTypeDefinition -> Text
+ Data.GraphQL.Encoder: selection :: Selection -> Text
+ Data.GraphQL.Encoder: selectionSet :: SelectionSet -> Text
+ Data.GraphQL.Encoder: spaced :: Text -> Text
+ Data.GraphQL.Encoder: spaces :: (a -> Text) -> [a] -> Text
+ Data.GraphQL.Encoder: stringValue :: StringValue -> Text
+ Data.GraphQL.Encoder: typeDefinition :: TypeDefinition -> Text
+ Data.GraphQL.Encoder: typeExtensionDefinition :: TypeExtensionDefinition -> Text
+ Data.GraphQL.Encoder: type_ :: Type -> Text
+ Data.GraphQL.Encoder: unionMembers :: [NamedType] -> Text
+ Data.GraphQL.Encoder: unionTypeDefinition :: UnionTypeDefinition -> Text
+ Data.GraphQL.Encoder: value :: Value -> Text
+ Data.GraphQL.Encoder: variable :: Variable -> Text
+ Data.GraphQL.Encoder: variableDefinition :: VariableDefinition -> Text
+ Data.GraphQL.Encoder: variableDefinitions :: [VariableDefinition] -> Text
+ Data.GraphQL.Parser: booleanValue :: Parser Bool
+ Data.GraphQL.Parser: node :: Parser Node
+ Data.GraphQL.Parser: stringValue :: Parser StringValue
- Data.GraphQL.AST: Mutation :: Name -> [VariableDefinition] -> [Directive] -> SelectionSet -> OperationDefinition
+ Data.GraphQL.AST: Mutation :: Node -> OperationDefinition
- Data.GraphQL.AST: Query :: Name -> [VariableDefinition] -> [Directive] -> SelectionSet -> OperationDefinition
+ Data.GraphQL.AST: Query :: Node -> OperationDefinition
- Data.GraphQL.AST: ValueInt :: Int -> Value
+ Data.GraphQL.AST: ValueInt :: Int32 -> Value
- Data.GraphQL.AST: ValueString :: Text -> Value
+ Data.GraphQL.AST: ValueString :: StringValue -> Value

Files

CHANGELOG.md view
@@ -1,6 +1,20 @@ # Change Log All notable changes to this project will be documented in this file. +## [0.3] - 2015-09-22+### Changed+- Exact match numeric types to spec.+- Names follow now the spec.+- AST slightly different for better readability or easier parsing.+- Replace golden test for test to validate parsing/encoding.++### Added+- Parsing errors in all cases where `Alternative` is used.+- GraphQL encoder.++### Fixed+- Expect braces `inputValueDefinitions` instead of parens when parsing.+ ## [0.2.1] - 2015-09-16 ### Fixed - Include data files for golden tests in Cabal package.@@ -19,5 +33,6 @@ ### Added - Data types for the GraphQL language. +[0.3]: https://github.com/jdnavarro/graphql-haskell/compare/v0.2.1...v0.3 [0.2.1]: https://github.com/jdnavarro/graphql-haskell/compare/v0.2...v0.2.1 [0.2]: https://github.com/jdnavarro/graphql-haskell/compare/v0.1...v0.2
Data/GraphQL/AST.hs view
@@ -1,5 +1,6 @@ module Data.GraphQL.AST where +import Data.Int (Int32) import Data.Text (Text)  -- * Name@@ -15,13 +16,13 @@                 | DefinitionType      TypeDefinition                   deriving (Eq,Show) -data OperationDefinition =-    Query        Name [VariableDefinition] [Directive] SelectionSet-  | Mutation     Name [VariableDefinition] [Directive] SelectionSet-  -- Not official yet-  -- -- | Subscription Name [VariableDefinition] [Directive] SelectionSet-    deriving (Eq,Show)+data OperationDefinition = Query    Node+                         | Mutation Node+                           deriving (Eq,Show) +data Node = Node Name [VariableDefinition] [Directive] SelectionSet+            deriving (Eq,Show)+ data VariableDefinition = VariableDefinition Variable Type (Maybe DefaultValue)                           deriving (Eq,Show) @@ -61,14 +62,17 @@ -- * Values  data Value = ValueVariable Variable-           | ValueInt Int -- TODO: Should this be `Integer`?-           | ValueFloat Double -- TODO: Should this be `Scientific`?+           | ValueInt Int32+           -- GraphQL Float is double precison+           | ValueFloat Double            | ValueBoolean Bool-           | ValueString Text+           | ValueString StringValue            | ValueEnum Name            | ValueList ListValue            | ValueObject ObjectValue              deriving (Eq,Show)++newtype StringValue = StringValue Text deriving (Eq,Show)  newtype ListValue = ListValue [Value] deriving (Eq,Show) 
+ Data/GraphQL/Encoder.hs view
@@ -0,0 +1,246 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE OverloadedStrings #-}+module Data.GraphQL.Encoder where++#if !MIN_VERSION_base(4,8,0)+import Control.Applicative ((<$>))+import Data.Monoid (Monoid, mconcat, mempty)+#endif+import Data.Monoid ((<>))++import Data.Text (Text, cons, intercalate, pack, snoc)++import Data.GraphQL.AST++-- * Document++-- TODO: Use query shorthand+document :: Document -> Text+document (Document defs) = (`snoc` '\n') . mconcat $ definition <$> defs++definition :: Definition -> Text+definition (DefinitionOperation x) = operationDefinition x+definition (DefinitionFragment  x) = fragmentDefinition x+definition (DefinitionType      x) = typeDefinition x++operationDefinition :: OperationDefinition -> Text+operationDefinition (Query    n) = "query "    <> node n+operationDefinition (Mutation n) = "mutation " <> node n++node :: Node -> Text+node (Node name vds ds ss) =+       name+    <> optempty variableDefinitions vds+    <> optempty directives ds+    <> selectionSet ss++variableDefinitions :: [VariableDefinition] -> Text+variableDefinitions = parensCommas variableDefinition++variableDefinition :: VariableDefinition -> Text+variableDefinition (VariableDefinition var ty dv) =+    variable var <> ":" <> type_ ty <> maybe mempty defaultValue dv++defaultValue :: DefaultValue -> Text+defaultValue val = "=" <> value val++variable :: Variable -> Text+variable (Variable name) = "$" <> name++selectionSet :: SelectionSet -> Text+selectionSet = bracesCommas selection++selection :: Selection -> Text+selection (SelectionField          x) = field x+selection (SelectionInlineFragment x) = inlineFragment x+selection (SelectionFragmentSpread x) = fragmentSpread x++field :: Field -> Text+field (Field alias name args ds ss) =+       optempty (`snoc` ':') alias+    <> name+    <> optempty arguments args+    <> optempty directives ds+    <> optempty selectionSet ss++arguments :: [Argument] -> Text+arguments = parensCommas argument++argument :: Argument -> Text+argument (Argument name v) = name <> ":" <> value v++-- * Fragments++fragmentSpread :: FragmentSpread -> Text+fragmentSpread (FragmentSpread name ds) =+    "..." <> name <> optempty directives ds++inlineFragment :: InlineFragment -> Text+inlineFragment (InlineFragment (NamedType tc) ds ss) =+    "... on " <> tc+              <> optempty directives ds+              <> optempty selectionSet ss++fragmentDefinition :: FragmentDefinition -> Text+fragmentDefinition (FragmentDefinition name (NamedType tc) ds ss) =+    "fragment " <> name <> " on " <> tc+                <> optempty directives ds+                <> selectionSet ss++-- * Values++value :: Value -> Text+value (ValueVariable x) = variable x+-- TODO: This will be replaced with `decimal` Buidler+value (ValueInt      x) = pack $ show x+-- TODO: This will be replaced with `decimal` Buidler+value (ValueFloat    x) = pack $ show x+value (ValueBoolean  x) = booleanValue x+value (ValueString   x) = stringValue x+value (ValueEnum     x) = x+value (ValueList     x) = listValue x+value (ValueObject   x) = objectValue x++booleanValue :: Bool -> Text+booleanValue True  = "true"+booleanValue False = "false"++-- TODO: Escape characters+stringValue :: StringValue -> Text+stringValue (StringValue v) = quotes v++listValue :: ListValue -> Text+listValue (ListValue vs) = bracketsCommas value vs++objectValue :: ObjectValue -> Text+objectValue (ObjectValue ofs) = bracesCommas objectField ofs++objectField :: ObjectField -> Text+objectField (ObjectField name v) = name <> ":" <> value v++-- * Directives++directives :: [Directive] -> Text+directives = spaces directive++directive :: Directive -> Text+directive (Directive name args) = "@" <> name <> optempty arguments args++-- * Type Reference++type_ :: Type -> Text+type_ (TypeNamed (NamedType x)) = x+type_ (TypeList x) = listType x+type_ (TypeNonNull x) = nonNullType x++namedType :: NamedType -> Text+namedType (NamedType name) = name++listType :: ListType -> Text+listType (ListType ty) = brackets (type_ ty)++nonNullType :: NonNullType -> Text+nonNullType (NonNullTypeNamed (NamedType x)) = x <> "!"+nonNullType (NonNullTypeList  x) = listType x <> "!"++typeDefinition :: TypeDefinition -> Text+typeDefinition (TypeDefinitionObject        x) = objectTypeDefinition x+typeDefinition (TypeDefinitionInterface     x) = interfaceTypeDefinition x+typeDefinition (TypeDefinitionUnion         x) = unionTypeDefinition x+typeDefinition (TypeDefinitionScalar        x) = scalarTypeDefinition x+typeDefinition (TypeDefinitionEnum          x) = enumTypeDefinition x+typeDefinition (TypeDefinitionInputObject   x) = inputObjectTypeDefinition x+typeDefinition (TypeDefinitionTypeExtension x) = typeExtensionDefinition x++objectTypeDefinition :: ObjectTypeDefinition -> Text+objectTypeDefinition (ObjectTypeDefinition name ifaces fds) =+    "type " <> name+            <> optempty (spaced . interfaces) ifaces+            <> optempty fieldDefinitions fds++interfaces :: Interfaces -> Text+interfaces = ("implements " <>) . spaces namedType++fieldDefinitions :: [FieldDefinition] -> Text+fieldDefinitions = bracesCommas fieldDefinition++fieldDefinition :: FieldDefinition -> Text+fieldDefinition (FieldDefinition name args ty) =+    name <> optempty argumentsDefinition args+         <> ":"+         <> type_ ty++argumentsDefinition :: ArgumentsDefinition -> Text+argumentsDefinition = parensCommas inputValueDefinition++interfaceTypeDefinition :: InterfaceTypeDefinition -> Text+interfaceTypeDefinition (InterfaceTypeDefinition name fds) =+    "interface " <> name <> fieldDefinitions fds++unionTypeDefinition :: UnionTypeDefinition -> Text+unionTypeDefinition (UnionTypeDefinition name ums) =+    "union " <> name <> "=" <> unionMembers ums++unionMembers :: [NamedType] -> Text+unionMembers = intercalate "|" . fmap namedType++scalarTypeDefinition :: ScalarTypeDefinition -> Text+scalarTypeDefinition (ScalarTypeDefinition name) = "scalar " <> name++enumTypeDefinition :: EnumTypeDefinition -> Text+enumTypeDefinition (EnumTypeDefinition name evds) =+    "enum " <> name+            <> bracesCommas enumValueDefinition evds++enumValueDefinition :: EnumValueDefinition -> Text+enumValueDefinition (EnumValueDefinition name) = name++inputObjectTypeDefinition :: InputObjectTypeDefinition -> Text+inputObjectTypeDefinition (InputObjectTypeDefinition name ivds) =+    "input " <> name <> inputValueDefinitions ivds++inputValueDefinitions :: [InputValueDefinition] -> Text+inputValueDefinitions = bracesCommas inputValueDefinition++inputValueDefinition :: InputValueDefinition -> Text+inputValueDefinition (InputValueDefinition name ty dv) =+    name <> ":" <> type_ ty <> maybe mempty defaultValue dv++typeExtensionDefinition :: TypeExtensionDefinition -> Text+typeExtensionDefinition (TypeExtensionDefinition otd) =+    "extend " <> objectTypeDefinition otd++-- * Internal++spaced :: Text -> Text+spaced = cons '\SP'++between :: Char -> Char -> Text -> Text+between open close = cons open . (`snoc` close)++parens :: Text -> Text+parens = between '(' ')'++brackets :: Text -> Text+brackets = between '[' ']'++braces :: Text -> Text+braces = between '{' '}'++quotes :: Text -> Text+quotes = between '"' '"'++spaces :: (a -> Text) -> [a] -> Text+spaces f = intercalate "\SP" . fmap f++parensCommas :: (a -> Text) -> [a] -> Text+parensCommas f = parens . intercalate "," . fmap f++bracketsCommas :: (a -> Text) -> [a] -> Text+bracketsCommas f = brackets . intercalate "," . fmap f++bracesCommas :: (a -> Text) -> [a] -> Text+bracesCommas f = braces . intercalate "," . fmap f++optempty :: (Eq a, Monoid a, Monoid b) => (a -> b) -> a -> b+optempty f xs = if xs == mempty then mempty else f xs
Data/GraphQL/Parser.hs view
@@ -1,6 +1,5 @@ {-# LANGUAGE CPP #-} {-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE LambdaCase #-} module Data.GraphQL.Parser where  import Prelude hiding (takeWhile)@@ -11,8 +10,10 @@ #endif import Control.Applicative ((<|>), empty, many, optional) import Control.Monad (when)-import Data.Char-import Data.Text (Text, pack)+import Data.Char (isDigit, isSpace)+import Data.Foldable (traverse_)++import Data.Text (Text, append) import Data.Attoparsec.Text   ( Parser   , (<?>)@@ -20,25 +21,27 @@   , decimal   , double   , endOfLine+  , inClass   , many1   , manyTill   , option   , peekChar-  , satisfy   , sepBy1   , signed+  , takeWhile+  , takeWhile1   )  import Data.GraphQL.AST  -- * Name --- XXX: Handle starting `_` and no number at the beginning:--- https://facebook.github.io/graphql/#sec-Names--- TODO: Use takeWhile1 instead for efficiency. With takeWhile1 there is no--- parsing failure. name :: Parser Name-name = tok $ pack <$> many1 (satisfy isAlphaNum)+name = tok $ append <$> takeWhile1 isA_z+                    <*> takeWhile ((||) <$> isDigit <*> isA_z)+  where+    -- `isAlpha` handles many more Unicode Chars+    isA_z =  inClass $ '_' : ['A'..'Z'] ++ ['a'..'z']  -- * Document @@ -48,7 +51,8 @@     -- Try SelectionSet when no definition     <|> (Document . pure                   . DefinitionOperation-                  . Query mempty empty empty+                  . Query+                  . Node mempty empty empty                 <$> selectionSet)     <?> "document error!" @@ -60,15 +64,16 @@  operationDefinition :: Parser OperationDefinition operationDefinition =-        op Query "query"-    <|> op Mutation "mutation"+        Query    <$ tok "query"    <*> node+    <|> Mutation <$ tok "mutation" <*> node     <?> "operationDefinition error!"-  where-    op f n = f <$ tok n <*> tok name-                        <*> optempty variableDefinitions-                        <*> optempty directives-                        <*> selectionSet +node :: Parser Node+node = Node <$> name+            <*> optempty variableDefinitions+            <*> optempty directives+            <*> selectionSet+ variableDefinitions :: Parser [VariableDefinition] variableDefinitions = parens (many1 variableDefinition) @@ -148,17 +153,25 @@ -- explicit types use the `typedValue` parser. value :: Parser Value value = ValueVariable <$> variable-        -- TODO: Handle arbitrary precision.-    <|> ValueInt     <$> tok (signed decimal)-    <|> ValueFloat   <$> tok (signed double)-    <|> ValueBoolean <$> bool-    -- TODO: Handle escape characters, unicode, etc-    <|> ValueString  <$> quotes name+    -- TODO: Handle maxBound, Int32 in spec.+    <|> ValueInt      <$> tok (signed decimal)+    <|> ValueFloat    <$> tok (signed double)+    <|> ValueBoolean  <$> booleanValue+    <|> ValueString   <$> stringValue     -- `true` and `false` have been tried before-    <|> ValueEnum    <$> name-    <|> ValueList    <$> listValue-    <|> ValueObject  <$> objectValue+    <|> ValueEnum     <$> name+    <|> ValueList     <$> listValue+    <|> ValueObject   <$> objectValue+    <?> "value error!" +booleanValue :: Parser Bool+booleanValue = True  <$ tok "true"+   <|> False <$ tok "false"++-- TODO: Escape characters. Look at `jsstring_` in aeson package.+stringValue :: Parser StringValue+stringValue = StringValue <$> quotes (takeWhile (/= '"'))+ -- Notice it can be empty listValue :: Parser ListValue listValue = ListValue <$> brackets (many value)@@ -170,10 +183,6 @@ objectField :: Parser ObjectField objectField = ObjectField <$> name <* tok ":" <*> value -bool :: Parser Bool-bool = True  <$ tok "true"-   <|> False <$ tok "false"- -- * Directives  directives :: Parser [Directive]@@ -188,9 +197,10 @@ -- * Type Reference  type_ :: Parser Type-type_ = TypeNamed   <$> namedType-    <|> TypeList    <$> listType+type_ = TypeList    <$> listType     <|> TypeNonNull <$> nonNullType+    <|> TypeNamed   <$> namedType+    <?> "type_ error!"  namedType :: Parser NamedType namedType = NamedType <$> name@@ -201,6 +211,7 @@ nonNullType :: Parser NonNullType nonNullType = NonNullTypeNamed <$> namedType <* tok "!"           <|> NonNullTypeList  <$> listType  <* tok "!"+          <?> "nonNullType error!"  -- * Type Definition @@ -221,7 +232,6 @@     <*> name     <*> optempty interfaces     <*> fieldDefinitions-    <?> "objectTypeDefinition error!"  interfaces :: Parser Interfaces interfaces = tok "implements" *> many1 namedType@@ -237,17 +247,7 @@     <*> type_  argumentsDefinition :: Parser ArgumentsDefinition-argumentsDefinition = inputValueDefinitions--inputValueDefinitions :: Parser [InputValueDefinition]-inputValueDefinitions = parens $ many1 inputValueDefinition--inputValueDefinition :: Parser InputValueDefinition-inputValueDefinition = InputValueDefinition-    <$> name-    <*  tok ":"-    <*> type_-    <*> optional defaultValue+argumentsDefinition = parens $ many1 inputValueDefinition  interfaceTypeDefinition :: Parser InterfaceTypeDefinition interfaceTypeDefinition = InterfaceTypeDefinition@@ -288,6 +288,16 @@     <*> name     <*> inputValueDefinitions +inputValueDefinitions :: Parser [InputValueDefinition]+inputValueDefinitions = braces $ many1 inputValueDefinition++inputValueDefinition :: Parser InputValueDefinition+inputValueDefinition = InputValueDefinition+    <$> name+    <*  tok ":"+    <*> type_+    <*> optional defaultValue+ typeExtensionDefinition :: Parser TypeExtensionDefinition typeExtensionDefinition = TypeExtensionDefinition     <$  tok "extend"@@ -320,8 +330,7 @@ -- ** WhiteSpace -- whiteSpace :: Parser ()-whiteSpace = peekChar >>= \case-    Just c -> if isSpace c || c == ','-              then anyChar *> whiteSpace-              else when (c == '#') $ manyTill anyChar endOfLine *> whiteSpace-    _ -> return ()+whiteSpace = peekChar >>= traverse_ (\c ->+    if isSpace c || c == ','+       then anyChar *> whiteSpace+       else when (c == '#') $ manyTill anyChar endOfLine *> whiteSpace)
README.md view
@@ -9,9 +9,11 @@ should include:  - [x] GraphQL AST-- [x] Parser for the GraphQL language. See TODO for caveats.+- [x] Parser for the GraphQL language. See TODO for limitations.+- [x] Printer for GraphQL. This is not pretty yet. - [ ] GraphQL Schema AST. - [ ] Parser for the GraphQL Schema language.+- [ ] Printer for the GraphQL Schema language. - [ ] Interpreter of GraphQL requests. - [ ] Utilities to define GraphQL types and schema. @@ -21,6 +23,6 @@  Suggestions, contributions and bug reports are welcome. -Feel free to contact me, jdnavarro, on the #haskell channel on the-[GraphQL Slack Server](https://graphql.slack.com). You can obtain an+Feel free to contact on Slack in [#haskell on+GraphQL](https://graphql.slack.com/messages/haskell/). You can obtain an invitation [here](https://graphql-slack.herokuapp.com/).
graphql.cabal view
@@ -1,5 +1,5 @@ name:                graphql-version:             0.2.1+version:             0.3 synopsis:            Haskell GraphQL implementation description:   This package provides a rudimentary parser for the@@ -17,29 +17,30 @@ tested-with:         GHC == 7.8.4, GHC == 7.10.2 extra-source-files:  README.md CHANGELOG.md stack.yaml data-files:          tests/data/*.graphql-                     tests/data/*.graphql.golden+                     tests/data/*.min.graphql  library   default-language:    Haskell2010   ghc-options:         -Wall   exposed-modules:     Data.GraphQL.AST+                       Data.GraphQL.Encoder                        Data.GraphQL.Parser-  build-depends:       base >= 4.7 && < 5,+  build-depends:       base >=4.7 && < 5,                        text >=0.11.3.1,                        attoparsec >=0.10.4.0 -test-suite golden+test-suite tasty   default-language:    Haskell2010   type:                exitcode-stdio-1.0   hs-source-dirs:      tests-  main-is:             golden.hs+  main-is:             tasty.hs   ghc-options:         -Wall-  build-depends:       base >= 4.6 && <5,-                       bytestring,-                       text,-                       attoparsec,+  other-modules:       Paths_graphql+  build-depends:       base >=4.6 && <5,+                       text >=0.11.3.1,+                       attoparsec >=0.10.4.0,                        tasty >=0.10,-                       tasty-golden,+                       tasty-hunit >=0.9,                        graphql  source-repository head
− tests/data/kitchen-sink.graphql.golden
@@ -1,1 +0,0 @@-Document [DefinitionOperation (Query "queryName" [VariableDefinition (Variable "foo") (TypeNamed (NamedType "ComplexType")) Nothing,VariableDefinition (Variable "site") (TypeNamed (NamedType "Site")) (Just (ValueEnum "MOBILE"))] [] [SelectionField (Field "whoever123is" "node" [Argument "id" (ValueList (ListValue [ValueInt 123,ValueInt 456]))] [] [SelectionField (Field "" "id" [] [] []),SelectionInlineFragment (InlineFragment (NamedType "User") [Directive "defer" []] [SelectionField (Field "" "field2" [] [] [SelectionField (Field "" "id" [] [] []),SelectionField (Field "alias" "field1" [Argument "first" (ValueInt 10),Argument "after" (ValueVariable (Variable "foo"))] [Directive "include" [Argument "if" (ValueVariable (Variable "foo"))]] [SelectionField (Field "" "id" [] [] []),SelectionFragmentSpread (FragmentSpread "frag" [])])])])])]),DefinitionOperation (Mutation "likeStory" [] [] [SelectionField (Field "" "like" [Argument "story" (ValueInt 123)] [Directive "defer" []] [SelectionField (Field "" "story" [] [] [SelectionField (Field "" "id" [] [] [])])])]),DefinitionFragment (FragmentDefinition "frag" (NamedType "Friend") [] [SelectionField (Field "" "foo" [Argument "size" (ValueVariable (Variable "size")),Argument "bar" (ValueVariable (Variable "b")),Argument "obj" (ValueObject (ObjectValue [ObjectField "key" (ValueString "value")]))] [] [])])]
+ tests/data/kitchen-sink.min.graphql view
@@ -0,0 +1,1 @@+query queryName($foo:ComplexType,$site:Site=MOBILE){whoever123is:node(id:[123,456]){id,... on User@defer{field2{id,alias:field1(first:10,after:$foo)@include(if:$foo){id,...frag}}}}}mutation likeStory{like(story:123)@defer{story{id}}}fragment frag on Friend{foo(size:$size,bar:$b,obj:{key:"value"})}
− tests/golden.hs
@@ -1,25 +0,0 @@-{-# LANGUAGE CPP #-}-{-# LANGUAGE OverloadedStrings #-}-module Main where--#if !MIN_VERSION_base(4,8,0)-import Control.Applicative ((<$>), (<*>), pure)-#endif-import Control.Monad ((>=>))-import Data.Attoparsec.Text (parseOnly)-import Data.ByteString.Lazy.Char8 as B8-import qualified Data.Text.IO as TIO-import Test.Tasty (defaultMain)-import Test.Tasty.Golden (goldenVsString)--import Paths_graphql (getDataFileName)-import Data.GraphQL.Parser (document)--main :: IO ()-main = defaultMain-   =<< goldenVsString "kitchen-sink.graphql"-   <$> getDataFileName "tests/data/kitchen-sink.graphql.graphql.golden"-   <*> (parse <$> getDataFileName "tests/data/kitchen-sink.graphql")-  where-    parse = fmap (parseOnly document) . TIO.readFile-        >=> pure . either B8.pack (flip B8.snoc '\n' . B8.pack . show)
+ tests/tasty.hs view
@@ -0,0 +1,28 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE OverloadedStrings #-}+module Main where++#if !MIN_VERSION_base(4,8,0)+import Control.Applicative ((<$>), (<*>))+#endif++import Data.Attoparsec.Text (parseOnly)+import qualified Data.Text.IO as Text+import Test.Tasty (defaultMain)+import Test.Tasty.HUnit++import qualified Data.GraphQL.Parser as Parser+import qualified Data.GraphQL.Encoder as Encoder++import Paths_graphql (getDataFileName)++main :: IO ()+main = defaultMain =<< testCase "Kitchen Sink"+                   <$> (assertEqual "Encode" <$> expected <*> actual)+  where+    expected = Text.readFile+           =<< getDataFileName "tests/data/kitchen-sink.min.graphql"++    actual = either (error "Parsing error!") Encoder.document+         <$> parseOnly Parser.document+         <$> expected