packages feed

morpheus-graphql-server (empty) → 0.22.0

raw patch · 307 files changed

+11284/−0 lines, 307 filesdep +aesondep +basedep +bytestring

Dependencies added: aeson, base, bytestring, containers, file-embed, morpheus-graphql-app, morpheus-graphql-core, morpheus-graphql-server, morpheus-graphql-subscriptions, morpheus-graphql-tests, mtl, relude, tasty, tasty-hunit, template-haskell, text, transformers, unordered-containers, vector

Files

+ LICENSE view
@@ -0,0 +1,21 @@+MIT License++Copyright (c) 2019 Daviti Nalchevanidze++Permission is hereby granted, free of charge, to any person obtaining a copy+of this software and associated documentation files (the "Software"), to deal+in the Software without restriction, including without limitation the rights+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+copies of the Software, and to permit persons to whom the Software is+furnished to do so, subject to the following conditions:++The above copyright notice and this permission notice shall be included in all+copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+SOFTWARE.
+ README.md view
@@ -0,0 +1,130 @@+# Morpheus GraphQL [![Hackage](https://img.shields.io/hackage/v/morpheus-graphql.svg)](https://hackage.haskell.org/package/morpheus-graphql) ![CI](https://github.com/morpheusgraphql/morpheus-graphql/workflows/CI/badge.svg)++Build GraphQL APIs with your favorite functional language!++Morpheus GraphQL (Server & Client) helps you to build GraphQL APIs in Haskell with native Haskell types.+Morpheus will convert your Haskell types to a GraphQL schema and all your resolvers are just native Haskell functions. Morpheus GraphQL can also convert your GraphQL Schema or Query to Haskell types and validate them in compile time.++Morpheus is still in an early stage of development, so any feedback is more than welcome, and we appreciate any contribution!+Just open an issue here on GitHub, or join [our Slack channel](https://morpheus-graphql-slack-invite.herokuapp.com/) to get in touch.++Please note that this readme file provides only a brief introduction to the library. If you are interested in more advanced topics, visit [Docs](https://morpheusgraphql.com/).++## Getting Started++### Setup++To get started with Morpheus, you first need to add it to your project's dependencies, as follows (assuming you're using hpack):++_package.yml_++```yaml+dependencies:+  - morpheus-graphql+```++Additionally, you should tell stack which version to pick:++_stack.yml_++```yaml+resolver: lts-16.2++extra-deps:+  - morpheus-graphql-0.17.0+  - morpheus-graphql-app-0.17.0+  - morpheus-graphql-core-0.17.0+```++As Morpheus is quite new, make sure stack can find morpheus-graphql by running `stack upgrade` and `stack update`++### Building your first GraphQL API++To define a GraphQL API with Morpheus we start by defining the API Schema as a native Haskell data type,+which derives the `Generic` type class. Using the `DeriveAnyClass` language extension we then also derive instances for the `GQLType` type class. Lazily resolvable fields on this `Query` type are defined via `a -> ResolverQ () IO b`, representing resolving a set of arguments `a` to a concrete value `b`.++```haskell+data Query m = Query+  { deity :: DeityArgs -> m Deity+  } deriving (Generic, GQLType)++data Deity = Deity+  { fullName :: Text         -- Non-Nullable Field+  , power    :: Maybe Text   -- Nullable Field+  } deriving (Generic, GQLType)++data DeityArgs = DeityArgs+  { name      :: Text        -- Required Argument+  , mythology :: Maybe Text  -- Optional Argument+  } deriving (Generic, GQLType)+```++For each field in the `Query` type defined via `a -> m b` (like `deity`) we will define a resolver implementation that provides the values during runtime by referring to+some data source, e.g. a database or another API. Fields that are defined without `a -> m b` you can just provide a value.++In above example, the field of `DeityArgs` could also be named using reserved identities (such as: `type`, `where`, etc), in order to avoid conflict, a prime symbol (`'`) must be attached. For example, you can have:++```haskell+data DeityArgs = DeityArgs+  { name      :: Text        -- Required Argument+  , mythology :: Maybe Text  -- Optional Argument+  , type'     :: Text+  } deriving (Generic, GQLType)+```++The field name in the final request will be `type` instead of `type'`. The Morpheus request parser converts each of the reserved identities in Haskell 2010 to their corresponding names internally. This also applies to selections.++```haskell+resolveDeity :: DeityArgs -> ResolverQ () IO Deity+resolveDeity DeityArgs { name, mythology } = liftEither $ dbDeity name mythology++askDB :: Text -> Maybe Text -> IO (Either String Deity)+askDB = ...+```++To make this `Query` type available as an API, we define a `RootResolver` and feed it to the Morpheus `interpreter`. A `RootResolver` consists of `query`, `mutation` and `subscription` definitions, while we omit the latter for this example:++```haskell+rootResolver :: RootResolver IO () Query Undefined Undefined+rootResolver =+  RootResolver+    { queryResolver = Query {deity = resolveDeity}+    , mutationResolver = Undefined+    , subscriptionResolver = Undefined+    }++gqlApi :: ByteString -> IO ByteString+gqlApi = interpreter rootResolver+```++As you can see, the API is defined as `ByteString -> IO ByteString` which we can either invoke directly or use inside an arbitrary web framework+such as `scotty` or `serverless-haskell`. We'll go for `scotty` in this example:++```haskell+main :: IO ()+main = scotty 3000 $ post "/api" $ raw =<< (liftIO . gqlApi =<< body)+```++If we now send a POST request to `http://localhost:3000/api` with a GraphQL Query as body for example in a tool like `Insomnia`:++```GraphQL+query GetDeity {+  deity (name: "Morpheus") {+    fullName+    power+  }+}+```++our query will be resolved!++```JSON+{+  "data": {+    "deity": {+      "fullName": "Morpheus",+      "power": "Shapeshifting"+    }+  }+}+```
+ changelog.md view
@@ -0,0 +1,3 @@+# Changelog++see latest changes on [Github](https://github.com/morpheusgraphql/morpheus-graphql/releases)
+ morpheus-graphql-server.cabal view
@@ -0,0 +1,382 @@+cabal-version: 1.12++-- This file has been generated from package.yaml by hpack version 0.35.0.+--+-- see: https://github.com/sol/hpack++name:           morpheus-graphql-server+version:        0.22.0+synopsis:       Morpheus GraphQL+description:    Build GraphQL APIs with your favourite functional language!+category:       web, graphql+homepage:       https://morpheusgraphql.com+bug-reports:    https://github.com/nalchevanidze/morpheus-graphql/issues+author:         Daviti Nalchevanidze+maintainer:     d.nalchevanidze@gmail.com+copyright:      (c) 2019 Daviti Nalchevanidze+license:        MIT+license-file:   LICENSE+build-type:     Simple+extra-source-files:+    README.md+    changelog.md+data-files:+    test/Feature/Collision/category-collision-fail/query.gql+    test/Feature/Collision/category-collision-success/query.gql+    test/Feature/Collision/name-collision/query.gql+    test/Feature/Directive/definition/introspect-directive/query.gql+    test/Feature/Directive/definition/introspect-enum/query.gql+    test/Feature/Directive/definition/introspect-type/query.gql+    test/Feature/Directive/enum-visitor/description/query.gql+    test/Feature/Directive/enum-visitor/name-decode/query.gql+    test/Feature/Directive/enum-visitor/name-encode/query.gql+    test/Feature/Directive/enum-visitor/name-introspection/query.gql+    test/Feature/Directive/field-visitor/description/query.gql+    test/Feature/Directive/field-visitor/name-decode/query.gql+    test/Feature/Directive/field-visitor/name-encode/query.gql+    test/Feature/Directive/field-visitor/name-introspection/query.gql+    test/Feature/Directive/type-visitor/description/query.gql+    test/Feature/Inference/object-and-enum/introspection/query.gql+    test/Feature/Inference/object-and-enum/resolving/query.gql+    test/Feature/Inference/tagged-arguments-fail/introspection/query.gql+    test/Feature/Inference/tagged-arguments-fail/resolving/query.gql+    test/Feature/Inference/tagged-arguments/introspection/query.gql+    test/Feature/Inference/tagged-arguments/resolving/query.gql+    test/Feature/Inference/type-guards/introspection/interface/query.gql+    test/Feature/Inference/type-guards/introspection/objects/query.gql+    test/Feature/Inference/type-guards/resolving/fail/query.gql+    test/Feature/Inference/type-guards/resolving/success/interface-fields/query.gql+    test/Feature/Inference/type-guards/resolving/success/type-casting/query.gql+    test/Feature/Inference/type-inference/introspection/enum/query.gql+    test/Feature/Inference/type-inference/introspection/input-union/empty/query.gql+    test/Feature/Inference/type-inference/introspection/input-union/input-union/query.gql+    test/Feature/Inference/type-inference/introspection/inputObject/query.gql+    test/Feature/Inference/type-inference/introspection/object/query.gql+    test/Feature/Inference/type-inference/introspection/union/named-products/query.gql+    test/Feature/Inference/type-inference/introspection/union/nullary-constructors/query.gql+    test/Feature/Inference/type-inference/introspection/union/positional-products/query.gql+    test/Feature/Inference/type-inference/introspection/union/scalars/query.gql+    test/Feature/Inference/type-inference/introspection/union/union/query.gql+    test/Feature/Inference/type-inference/introspection/unit/query.gql+    test/Feature/Inference/type-inference/resolving/complexUnion/query.gql+    test/Feature/Inference/type-inference/resolving/input/fail/query.gql+    test/Feature/Inference/type-inference/resolving/input/success/query.gql+    test/Feature/Inference/type-inference/resolving/object/query.gql+    test/Feature/Inference/union-type/cannotBeSpreadOnType/query.gql+    test/Feature/Inference/union-type/fragmentOnAAndB/query.gql+    test/Feature/Inference/union-type/fragmentOnlyOnA/query.gql+    test/Feature/Inference/union-type/inlineFragment/cannotBeSpreadOnType/query.gql+    test/Feature/Inference/union-type/inlineFragment/fragmentOnAAndB/query.gql+    test/Feature/Inference/union-type/selectionWithoutFragmentNotAllowed/query.gql+    test/Feature/Inference/wrapped-type/ignoreMutationResolver/query.gql+    test/Feature/Inference/wrapped-type/ignoreQueryResolver/query.gql+    test/Feature/Inference/wrapped-type/ignoreSubscriptionResolver/query.gql+    test/Feature/Inference/wrapped-type/validWrappedTypes/query.gql+    test/Feature/Input/collections/assoc/invalid/query.gql+    test/Feature/Input/collections/assoc/ok/query.gql+    test/Feature/Input/collections/map/invalid/query.gql+    test/Feature/Input/collections/map/ok/query.gql+    test/Feature/Input/collections/nonempty/invalid/query.gql+    test/Feature/Input/collections/nonempty/ok/query.gql+    test/Feature/Input/collections/product/invalid/query.gql+    test/Feature/Input/collections/product/ok/query.gql+    test/Feature/Input/collections/seq/query.gql+    test/Feature/Input/collections/set/invalid/query.gql+    test/Feature/Input/collections/set/ok/query.gql+    test/Feature/Input/collections/tuple/invalid/query.gql+    test/Feature/Input/collections/tuple/ok/query.gql+    test/Feature/Input/collections/vector/query.gql+    test/Feature/Input/enums/decode2Con/query.gql+    test/Feature/Input/enums/decode3Con/query.gql+    test/Feature/Input/enums/decodeInvalidValue/query.gql+    test/Feature/Input/enums/decodeMany/con0/query.gql+    test/Feature/Input/enums/decodeMany/con1/query.gql+    test/Feature/Input/enums/decodeMany/con2/query.gql+    test/Feature/Input/enums/decodeMany/con3/query.gql+    test/Feature/Input/enums/decodeMany/con4/query.gql+    test/Feature/Input/enums/decodeMany/con5/query.gql+    test/Feature/Input/enums/decodeMany/con6/query.gql+    test/Feature/Input/enums/invalidEnumFromJSONVariable/query.gql+    test/Feature/Input/enums/invalidStringDefaultValue/query.gql+    test/Feature/Input/enums/invalidStringInput/query.gql+    test/Feature/Input/enums/validEnumFromJSONVariable/query.gql+    test/Feature/Input/objects/nullableUndefinedField/query.gql+    test/Feature/Input/objects/resolveObject/query.gql+    test/Feature/Input/objects/resolveVariable/query.gql+    test/Feature/Input/objects/undefinedField/query.gql+    test/Feature/Input/objects/unexpectedValue/query.gql+    test/Feature/Input/objects/unexpectedVariable/query.gql+    test/Feature/Input/objects/unknownField/query.gql+    test/Feature/Input/scalars/numbers/decodeFloat/query.gql+    test/Feature/Input/scalars/numbers/decodeInt/query.gql+    test/Feature/Input/scalars/strings/block/query.gql+    test/Feature/Input/scalars/strings/escaped/query.gql+    test/Feature/Input/scalars/strings/regular/query.gql+    test/Feature/Input/scalars/strings/wrong-escaped/query.gql+    test/Feature/Input/scalars/strings/wrong-newline/query.gql+    test/Feature/Input/variables/incompatibleType/equalType/query.gql+    test/Feature/Input/variables/incompatibleType/stricterType/query.gql+    test/Feature/Input/variables/incompatibleType/weakerType1/query.gql+    test/Feature/Input/variables/incompatibleType/weakerType2/query.gql+    test/Feature/Input/variables/incompatibleType/weakerType3/query.gql+    test/Feature/Input/variables/invalidValue/invalidDefaultValue/query.gql+    test/Feature/Input/variables/invalidValue/invalidDefaultValueButVariableProvided/query.gql+    test/Feature/Input/variables/invalidValue/invalidListVariable/query.gql+    test/Feature/Input/variables/invalidValue/nestedListNonNullListReceivedNull/query.gql+    test/Feature/Input/variables/nameCollision/query.gql+    test/Feature/Input/variables/nestedListNullableListReceivedNull/query.gql+    test/Feature/Input/variables/nonInputTypeViolation/query.gql+    test/Feature/Input/variables/undefinedVariable/query.gql+    test/Feature/Input/variables/unknownType/query.gql+    test/Feature/Input/variables/unusedVariable/unusedVariables/query.gql+    test/Feature/Input/variables/unusedVariable/variableUsedInAlias/query.gql+    test/Feature/Input/variables/unusedVariable/variableUsedInFragment/query.gql+    test/Feature/Input/variables/unusedVariable/variableUsedInInlineFragment/query.gql+    test/Feature/Input/variables/validListVariable/query.gql+    test/Feature/Input/variables/valueNotProvided/nonNullVariable/query.gql+    test/Feature/Input/variables/valueNotProvided/nonNullVariableWithDefaultValue/query.gql+    test/Feature/Input/variables/valueNotProvided/nullableVariable/query.gql+    test/Feature/Collision/category-collision-fail/response.json+    test/Feature/Collision/category-collision-success/response.json+    test/Feature/Collision/name-collision/response.json+    test/Feature/Directive/definition/introspect-directive/response.json+    test/Feature/Directive/definition/introspect-enum/response.json+    test/Feature/Directive/definition/introspect-type/response.json+    test/Feature/Directive/enum-visitor/description/response.json+    test/Feature/Directive/enum-visitor/name-decode/response.json+    test/Feature/Directive/enum-visitor/name-encode/response.json+    test/Feature/Directive/enum-visitor/name-introspection/response.json+    test/Feature/Directive/field-visitor/description/response.json+    test/Feature/Directive/field-visitor/name-decode/response.json+    test/Feature/Directive/field-visitor/name-encode/response.json+    test/Feature/Directive/field-visitor/name-introspection/response.json+    test/Feature/Directive/type-visitor/description/response.json+    test/Feature/Inference/object-and-enum/introspection/response.json+    test/Feature/Inference/object-and-enum/resolving/response.json+    test/Feature/Inference/tagged-arguments-fail/introspection/response.json+    test/Feature/Inference/tagged-arguments-fail/resolving/response.json+    test/Feature/Inference/tagged-arguments/introspection/response.json+    test/Feature/Inference/tagged-arguments/resolving/response.json+    test/Feature/Inference/type-guards/introspection/interface/response.json+    test/Feature/Inference/type-guards/introspection/objects/response.json+    test/Feature/Inference/type-guards/resolving/fail/response.json+    test/Feature/Inference/type-guards/resolving/success/interface-fields/response.json+    test/Feature/Inference/type-guards/resolving/success/type-casting/response.json+    test/Feature/Inference/type-inference/introspection/enum/response.json+    test/Feature/Inference/type-inference/introspection/input-union/empty/response.json+    test/Feature/Inference/type-inference/introspection/input-union/input-union/response.json+    test/Feature/Inference/type-inference/introspection/inputObject/response.json+    test/Feature/Inference/type-inference/introspection/object/response.json+    test/Feature/Inference/type-inference/introspection/union/named-products/response.json+    test/Feature/Inference/type-inference/introspection/union/nullary-constructors/response.json+    test/Feature/Inference/type-inference/introspection/union/positional-products/response.json+    test/Feature/Inference/type-inference/introspection/union/scalars/response.json+    test/Feature/Inference/type-inference/introspection/union/union/response.json+    test/Feature/Inference/type-inference/introspection/unit/response.json+    test/Feature/Inference/type-inference/resolving/complexUnion/response.json+    test/Feature/Inference/type-inference/resolving/input/fail/response.json+    test/Feature/Inference/type-inference/resolving/input/success/response.json+    test/Feature/Inference/type-inference/resolving/object/response.json+    test/Feature/Inference/union-type/cannotBeSpreadOnType/response.json+    test/Feature/Inference/union-type/fragmentOnAAndB/response.json+    test/Feature/Inference/union-type/fragmentOnlyOnA/response.json+    test/Feature/Inference/union-type/inlineFragment/cannotBeSpreadOnType/response.json+    test/Feature/Inference/union-type/inlineFragment/fragmentOnAAndB/response.json+    test/Feature/Inference/union-type/selectionWithoutFragmentNotAllowed/response.json+    test/Feature/Inference/wrapped-type/ignoreMutationResolver/response.json+    test/Feature/Inference/wrapped-type/ignoreQueryResolver/response.json+    test/Feature/Inference/wrapped-type/ignoreSubscriptionResolver/response.json+    test/Feature/Inference/wrapped-type/validWrappedTypes/response.json+    test/Feature/Input/collections/assoc/invalid/response.json+    test/Feature/Input/collections/assoc/ok/response.json+    test/Feature/Input/collections/map/invalid/response.json+    test/Feature/Input/collections/map/ok/response.json+    test/Feature/Input/collections/nonempty/invalid/response.json+    test/Feature/Input/collections/nonempty/ok/response.json+    test/Feature/Input/collections/product/invalid/response.json+    test/Feature/Input/collections/product/ok/response.json+    test/Feature/Input/collections/seq/response.json+    test/Feature/Input/collections/set/invalid/response.json+    test/Feature/Input/collections/set/ok/response.json+    test/Feature/Input/collections/tuple/invalid/response.json+    test/Feature/Input/collections/tuple/ok/response.json+    test/Feature/Input/collections/vector/response.json+    test/Feature/Input/enums/decode2Con/response.json+    test/Feature/Input/enums/decode3Con/response.json+    test/Feature/Input/enums/decodeInvalidValue/response.json+    test/Feature/Input/enums/decodeMany/con0/response.json+    test/Feature/Input/enums/decodeMany/con1/response.json+    test/Feature/Input/enums/decodeMany/con2/response.json+    test/Feature/Input/enums/decodeMany/con3/response.json+    test/Feature/Input/enums/decodeMany/con4/response.json+    test/Feature/Input/enums/decodeMany/con5/response.json+    test/Feature/Input/enums/decodeMany/con6/response.json+    test/Feature/Input/enums/invalidEnumFromJSONVariable/response.json+    test/Feature/Input/enums/invalidEnumFromJSONVariable/variables.json+    test/Feature/Input/enums/invalidStringDefaultValue/response.json+    test/Feature/Input/enums/invalidStringInput/response.json+    test/Feature/Input/enums/validEnumFromJSONVariable/response.json+    test/Feature/Input/enums/validEnumFromJSONVariable/variables.json+    test/Feature/Input/objects/nullableUndefinedField/response.json+    test/Feature/Input/objects/resolveObject/response.json+    test/Feature/Input/objects/resolveVariable/response.json+    test/Feature/Input/objects/resolveVariable/variables.json+    test/Feature/Input/objects/undefinedField/response.json+    test/Feature/Input/objects/unexpectedValue/response.json+    test/Feature/Input/objects/unexpectedVariable/response.json+    test/Feature/Input/objects/unknownField/response.json+    test/Feature/Input/scalars/numbers/decodeFloat/response.json+    test/Feature/Input/scalars/numbers/decodeInt/response.json+    test/Feature/Input/scalars/strings/block/response.json+    test/Feature/Input/scalars/strings/escaped/response.json+    test/Feature/Input/scalars/strings/regular/response.json+    test/Feature/Input/scalars/strings/wrong-escaped/response.json+    test/Feature/Input/scalars/strings/wrong-newline/response.json+    test/Feature/Input/variables/incompatibleType/equalType/response.json+    test/Feature/Input/variables/incompatibleType/equalType/variables.json+    test/Feature/Input/variables/incompatibleType/stricterType/response.json+    test/Feature/Input/variables/incompatibleType/stricterType/variables.json+    test/Feature/Input/variables/incompatibleType/weakerType1/response.json+    test/Feature/Input/variables/incompatibleType/weakerType1/variables.json+    test/Feature/Input/variables/incompatibleType/weakerType2/response.json+    test/Feature/Input/variables/incompatibleType/weakerType2/variables.json+    test/Feature/Input/variables/incompatibleType/weakerType3/response.json+    test/Feature/Input/variables/incompatibleType/weakerType3/variables.json+    test/Feature/Input/variables/invalidValue/invalidDefaultValue/response.json+    test/Feature/Input/variables/invalidValue/invalidDefaultValueButVariableProvided/response.json+    test/Feature/Input/variables/invalidValue/invalidDefaultValueButVariableProvided/variables.json+    test/Feature/Input/variables/invalidValue/invalidListVariable/response.json+    test/Feature/Input/variables/invalidValue/invalidListVariable/variables.json+    test/Feature/Input/variables/invalidValue/nestedListNonNullListReceivedNull/response.json+    test/Feature/Input/variables/invalidValue/nestedListNonNullListReceivedNull/variables.json+    test/Feature/Input/variables/nameCollision/response.json+    test/Feature/Input/variables/nameCollision/variables.json+    test/Feature/Input/variables/nestedListNullableListReceivedNull/response.json+    test/Feature/Input/variables/nestedListNullableListReceivedNull/variables.json+    test/Feature/Input/variables/nonInputTypeViolation/response.json+    test/Feature/Input/variables/undefinedVariable/response.json+    test/Feature/Input/variables/unknownType/response.json+    test/Feature/Input/variables/unusedVariable/unusedVariables/response.json+    test/Feature/Input/variables/unusedVariable/variableUsedInAlias/response.json+    test/Feature/Input/variables/unusedVariable/variableUsedInAlias/variables.json+    test/Feature/Input/variables/unusedVariable/variableUsedInFragment/response.json+    test/Feature/Input/variables/unusedVariable/variableUsedInFragment/variables.json+    test/Feature/Input/variables/unusedVariable/variableUsedInInlineFragment/response.json+    test/Feature/Input/variables/unusedVariable/variableUsedInInlineFragment/variables.json+    test/Feature/Input/variables/validListVariable/response.json+    test/Feature/Input/variables/validListVariable/variables.json+    test/Feature/Input/variables/valueNotProvided/nonNullVariable/response.json+    test/Feature/Input/variables/valueNotProvided/nonNullVariableWithDefaultValue/response.json+    test/Feature/Input/variables/valueNotProvided/nullableVariable/response.json++source-repository head+  type: git+  location: https://github.com/nalchevanidze/morpheus-graphql++library+  exposed-modules:+      Data.Morpheus.Server+      Data.Morpheus.Server.Resolvers+      Data.Morpheus.Server.Types+  other-modules:+      Data.Morpheus.Server.Deriving.App+      Data.Morpheus.Server.Deriving.Channels+      Data.Morpheus.Server.Deriving.Decode+      Data.Morpheus.Server.Deriving.Encode+      Data.Morpheus.Server.Deriving.Named.Encode+      Data.Morpheus.Server.Deriving.Named.EncodeType+      Data.Morpheus.Server.Deriving.Named.EncodeValue+      Data.Morpheus.Server.Deriving.Schema+      Data.Morpheus.Server.Deriving.Schema.Directive+      Data.Morpheus.Server.Deriving.Schema.Enum+      Data.Morpheus.Server.Deriving.Schema.Internal+      Data.Morpheus.Server.Deriving.Schema.Object+      Data.Morpheus.Server.Deriving.Schema.TypeContent+      Data.Morpheus.Server.Deriving.Schema.Union+      Data.Morpheus.Server.Deriving.Utils+      Data.Morpheus.Server.Deriving.Utils.Decode+      Data.Morpheus.Server.Deriving.Utils.DeriveGType+      Data.Morpheus.Server.Deriving.Utils.GTraversable+      Data.Morpheus.Server.Deriving.Utils.Kinded+      Data.Morpheus.Server.Deriving.Utils.Proxy+      Data.Morpheus.Server.Deriving.Utils.Types+      Data.Morpheus.Server.NamedResolvers+      Data.Morpheus.Server.Playground+      Data.Morpheus.Server.Types.DirectiveDefinitions+      Data.Morpheus.Server.Types.Directives+      Data.Morpheus.Server.Types.GQLType+      Data.Morpheus.Server.Types.Internal+      Data.Morpheus.Server.Types.Kind+      Data.Morpheus.Server.Types.SchemaT+      Data.Morpheus.Server.Types.TypeName+      Data.Morpheus.Server.Types.Types+      Data.Morpheus.Server.Types.Visitors+      Paths_morpheus_graphql_server+  hs-source-dirs:+      src+  ghc-options: -Wall+  build-depends:+      aeson >=1.4.4 && <3.0.0+    , base >=4.7.0 && <5.0.0+    , bytestring >=0.10.4 && <0.12.0+    , containers >=0.4.2.1 && <0.7.0+    , morpheus-graphql-app >=0.22.0 && <0.23.0+    , morpheus-graphql-core >=0.22.0 && <0.23.0+    , mtl >=2.0.0 && <3.0.0+    , relude >=0.3.0 && <2.0.0+    , template-haskell >=2.0.0 && <3.0.0+    , text >=1.2.3 && <1.3.0+    , transformers >=0.3.0 && <0.6.0+    , unordered-containers >=0.2.8 && <0.3.0+    , vector >=0.12.0.1 && <0.13.0+  default-language: Haskell2010++test-suite morpheus-graphql-server-test+  type: exitcode-stdio-1.0+  main-is: Spec.hs+  other-modules:+      Feature.Collision.CategoryCollisionFail+      Feature.Collision.CategoryCollisionSuccess+      Feature.Collision.NameCollision+      Feature.Collision.NameCollisionHelper+      Feature.Directive.Definition+      Feature.Directive.EnumVisitor+      Feature.Directive.FieldVisitor+      Feature.Directive.TypeVisitor+      Feature.Inference.ObjectAndEnum+      Feature.Inference.TaggedArguments+      Feature.Inference.TaggedArgumentsFail+      Feature.Inference.TypeGuards+      Feature.Inference.TypeInference+      Feature.Inference.UnionType+      Feature.Inference.WrappedType+      Feature.Input.Collections+      Feature.Input.Enums+      Feature.Input.Objects+      Feature.Input.Scalars+      Feature.Input.Variables+      Paths_morpheus_graphql_server+  hs-source-dirs:+      test+  ghc-options: -Wall+  build-depends:+      aeson >=1.4.4 && <3.0.0+    , base >=4.7.0 && <5.0.0+    , bytestring >=0.10.4 && <0.12.0+    , containers >=0.4.2.1 && <0.7.0+    , file-embed >=0.0.10 && <1.0.0+    , morpheus-graphql-app >=0.22.0 && <0.23.0+    , morpheus-graphql-core >=0.22.0 && <0.23.0+    , morpheus-graphql-server+    , morpheus-graphql-subscriptions >=0.22.0 && <0.23.0+    , morpheus-graphql-tests >=0.22.0 && <0.23.0+    , mtl >=2.0.0 && <3.0.0+    , relude >=0.3.0 && <2.0.0+    , tasty >=0.1.0 && <1.5.0+    , tasty-hunit >=0.1.0 && <1.0.0+    , template-haskell >=2.0.0 && <3.0.0+    , text >=1.2.3 && <1.3.0+    , transformers >=0.3.0 && <0.6.0+    , unordered-containers >=0.2.8 && <0.3.0+    , vector >=0.12.0.1 && <0.13.0+  default-language: Haskell2010
+ src/Data/Morpheus/Server.hs view
@@ -0,0 +1,79 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE NoImplicitPrelude #-}++-- |  GraphQL Wai Server Applications+module Data.Morpheus.Server+  ( httpPlayground,+    compileTimeSchemaValidation,+    printSchema,+    RootResolverConstraint,+    interpreter,+    debugInterpreter,+    App,+    deriveApp,+    runApp,+    withDebugger,+  )+where++import Data.ByteString.Lazy.Char8+  ( ByteString,+    pack,+  )+import Data.Morpheus.App+  ( App (..),+    MapAPI,+    runApp,+    withDebugger,+  )+import Data.Morpheus.App.Internal.Resolving+  ( resultOr,+  )+import Data.Morpheus.Core+  ( render,+  )+import Data.Morpheus.Server.Deriving.App+  ( RootResolverConstraint,+    deriveApp,+    deriveSchema,+  )+import Data.Morpheus.Server.Deriving.Schema+  ( compileTimeSchemaValidation,+  )+import Data.Morpheus.Server.Playground+  ( httpPlayground,+  )+import Data.Morpheus.Server.Resolvers (RootResolver)+import Relude hiding (ByteString)++-- | Generates schema.gql file from 'RootResolver'+printSchema ::+  RootResolverConstraint m event query mut sub =>+  proxy (RootResolver m event query mut sub) ->+  ByteString+printSchema =+  resultOr (pack . show) render+    . deriveSchema++-- | main query processor and resolver+interpreter ::+  (MapAPI a b, RootResolverConstraint m e query mut sub) =>+  RootResolver m e query mut sub ->+  a ->+  m b+interpreter = runApp . deriveApp++debugInterpreter ::+  (MapAPI a b, RootResolverConstraint m e query mut sub) =>+  RootResolver m e query mut sub ->+  a ->+  m b+debugInterpreter = runApp . withDebugger . deriveApp
+ src/Data/Morpheus/Server/Deriving/App.hs view
@@ -0,0 +1,74 @@+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE TupleSections #-}+{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE NoImplicitPrelude #-}++module Data.Morpheus.Server.Deriving.App+  ( RootResolverConstraint,+    deriveSchema,+    deriveApp,+  )+where++import Data.Morpheus.App+  ( App (..),+    mkApp,+  )+import Data.Morpheus.App.Internal.Resolving+  ( resultOr,+  )+import Data.Morpheus.Server.Deriving.Encode+  ( EncodeConstraints,+    deriveModel,+  )+import Data.Morpheus.Server.Deriving.Named.Encode+  ( EncodeNamedConstraints,+    deriveNamedModel,+  )+import Data.Morpheus.Server.Deriving.Schema+  ( SchemaConstraints,+    deriveSchema,+  )+import Data.Morpheus.Server.Resolvers+  ( NamedResolvers,+    RootResolver (..),+  )+import Relude++type RootResolverConstraint m e query mutation subscription =+  ( EncodeConstraints e m query mutation subscription,+    SchemaConstraints e m query mutation subscription,+    Monad m+  )++type NamedResolversConstraint m e query mutation subscription =+  ( EncodeNamedConstraints e m query mutation subscription,+    SchemaConstraints e m query mutation subscription,+    Monad m+  )++class+  DeriveApp+    f+    m+    (event :: Type)+    (qu :: (Type -> Type) -> Type)+    (mu :: (Type -> Type) -> Type)+    (su :: (Type -> Type) -> Type)+  where+  deriveApp :: f m event qu mu su -> App event m++instance RootResolverConstraint m e query mut sub => DeriveApp RootResolver m e query mut sub where+  deriveApp root =+    resultOr FailApp (uncurry mkApp) $+      (,) <$> deriveSchema (Identity root) <*> deriveModel root++instance NamedResolversConstraint m e query mut sub => DeriveApp NamedResolvers m e query mut sub where+  deriveApp root =+    resultOr FailApp (uncurry mkApp) $+      (,deriveNamedModel root) <$> deriveSchema (Identity root)
+ src/Data/Morpheus/Server/Deriving/Channels.hs view
@@ -0,0 +1,160 @@+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE FunctionalDependencies #-}+{-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE NoImplicitPrelude #-}++module Data.Morpheus.Server.Deriving.Channels+  ( channelResolver,+    ChannelsConstraint,+  )+where++import Control.Monad.Except (throwError)+import qualified Data.HashMap.Lazy as HM+import Data.Morpheus.App.Internal.Resolving+  ( Channel,+    Resolver,+    ResolverState,+    SubscriptionField (..),+  )+import Data.Morpheus.Internal.Utils+  ( selectBy,+  )+import Data.Morpheus.Server.Deriving.Decode+  ( Decode,+    decodeArguments,+  )+import Data.Morpheus.Server.Deriving.Utils+  ( ConsRep (..),+    DataType (..),+    FieldRep (..),+  )+import Data.Morpheus.Server.Deriving.Utils.DeriveGType+  ( DeriveValueOptions (..),+    DeriveWith,+    deriveValue,+  )+import Data.Morpheus.Server.Deriving.Utils.Kinded (KindedProxy (..), kinded)+import Data.Morpheus.Server.Types.GQLType (GQLType (typeOptions), deriveTypename, __typeData)+import Data.Morpheus.Server.Types.Internal (defaultTypeOptions)+import Data.Morpheus.Server.Types.Types (Undefined)+import Data.Morpheus.Types.Internal.AST+  ( FieldName,+    OUT,+    SUBSCRIPTION,+    Selection (..),+    SelectionContent (..),+    VALID,+    internal,+  )+import GHC.Generics+import Relude hiding (Undefined)++newtype DerivedChannel e = DerivedChannel+  { _unpackChannel :: Channel e+  }++type ChannelRes (e :: Type) = Selection VALID -> ResolverState (DerivedChannel e)++type ChannelsConstraint e m (subs :: (Type -> Type) -> Type) =+  ExploreChannels (IsUndefined (subs (Resolver SUBSCRIPTION e m))) e (subs (Resolver SUBSCRIPTION e m))++channelResolver ::+  forall e m subs.+  ChannelsConstraint e m subs =>+  subs (Resolver SUBSCRIPTION e m) ->+  Selection VALID ->+  ResolverState (Channel e)+channelResolver value = fmap _unpackChannel . channelSelector+  where+    channelSelector ::+      Selection VALID ->+      ResolverState (DerivedChannel e)+    channelSelector =+      selectBySelection+        ( exploreChannels+            (Proxy @(IsUndefined (subs (Resolver SUBSCRIPTION e m))))+            value+        )++selectBySelection ::+  HashMap FieldName (ChannelRes e) ->+  Selection VALID ->+  ResolverState (DerivedChannel e)+selectBySelection channels = withSubscriptionSelection >=> selectSubscription channels++selectSubscription ::+  HashMap FieldName (ChannelRes e) ->+  Selection VALID ->+  ResolverState (DerivedChannel e)+selectSubscription channels sel@Selection {selectionName} =+  selectBy+    (internal "invalid subscription: no channel is selected.")+    selectionName+    channels+    >>= (sel &)++withSubscriptionSelection :: Selection VALID -> ResolverState (Selection VALID)+withSubscriptionSelection Selection {selectionContent = SelectionSet selSet} =+  case toList selSet of+    [sel] -> pure sel+    _ -> throwError (internal "invalid subscription: there can be only one top level selection")+withSubscriptionSelection _ = throwError (internal "invalid subscription: expected selectionSet")++class GetChannel e a | a -> e where+  getChannel :: a -> ChannelRes e++instance GetChannel e (SubscriptionField (Resolver SUBSCRIPTION e m a)) where+  getChannel x = const $ pure $ DerivedChannel $ channel x++instance+  Decode arg =>+  GetChannel e (arg -> SubscriptionField (Resolver SUBSCRIPTION e m a))+  where+  getChannel f sel@Selection {selectionArguments} =+    decodeArguments selectionArguments+      >>= (`getChannel` sel)+        . f++------------------------------------------------------++type family IsUndefined a :: Bool where+  IsUndefined (Undefined m) = 'True+  IsUndefined a = 'False++class ExploreChannels (t :: Bool) e a where+  exploreChannels :: f t -> a -> HashMap FieldName (ChannelRes e)++class (GQLType a, GetChannel e a) => ChannelConstraint e a++instance (GetChannel e a, GQLType a) => ChannelConstraint e a++instance (GQLType a, Generic a, DeriveWith (ChannelConstraint e) (ChannelRes e) (Rep a)) => ExploreChannels 'False e a where+  exploreChannels _ =+    HM.fromList+      . convertNode+      . deriveValue+        ( DeriveValueOptions+            { __valueApply = getChannel,+              __valueTypeName = deriveTypename (KindedProxy :: KindedProxy OUT a),+              __valueGQLOptions = typeOptions (Proxy @a) defaultTypeOptions,+              __valueGetType = __typeData . kinded (Proxy @OUT)+            } ::+            DeriveValueOptions OUT (ChannelConstraint e) (ChannelRes e)+        )++instance ExploreChannels 'True e (Undefined m) where+  exploreChannels _ = pure HM.empty++convertNode :: DataType (ChannelRes e) -> [(FieldName, ChannelRes e)]+convertNode DataType {tyCons = ConsRep {consFields}} = map toChannels consFields+  where+    toChannels FieldRep {fieldSelector, fieldValue} = (fieldSelector, fieldValue)
+ src/Data/Morpheus/Server/Deriving/Decode.hs view
@@ -0,0 +1,218 @@+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE NoImplicitPrelude #-}++module Data.Morpheus.Server.Deriving.Decode+  ( decodeArguments,+    Decode,+    decode,+  )+where++import Control.Monad.Except (MonadError (throwError))+import qualified Data.Map as M+import Data.Morpheus.App.Internal.Resolving+  ( ResolverState,+  )+import Data.Morpheus.Server.Deriving.Schema.Directive (visitEnumName, visitFieldName)+import Data.Morpheus.Server.Deriving.Utils+  ( selNameProxy,+    symbolName,+  )+import Data.Morpheus.Server.Deriving.Utils.Decode+  ( Context (..),+    DecoderT,+    DescribeCons,+    DescribeFields (countFields),+    decodeFieldWith,+    getFieldName,+    getUnionInfos,+    handleEither,+    setVariantRef,+    withInputObject,+    withInputUnion,+    withScalar,+  )+import Data.Morpheus.Server.Deriving.Utils.Kinded+  ( KindedProxy (..),+  )+import Data.Morpheus.Server.Types.GQLType+  ( GQLType+      ( KIND,+        typeOptions+      ),+    deriveTypename,+  )+import Data.Morpheus.Server.Types.Internal+  ( defaultTypeOptions,+  )+import Data.Morpheus.Server.Types.Kind+  ( CUSTOM,+    DerivingKind,+    SCALAR,+    TYPE,+    WRAPPER,+  )+import Data.Morpheus.Server.Types.Types (Arg (Arg))+import Data.Morpheus.Types.GQLScalar+  ( DecodeScalar (..),+  )+import Data.Morpheus.Types.GQLWrapper+  ( DecodeWrapper (..),+    DecodeWrapperConstraint,+  )+import Data.Morpheus.Types.Internal.AST+  ( Argument (..),+    Arguments,+    IN,+    LEAF,+    Object,+    ObjectEntry (..),+    TypeName,+    VALID,+    ValidObject,+    ValidValue,+    Value (..),+    internal,+    msg,+  )+import GHC.Generics+import GHC.TypeLits (KnownSymbol)+import Relude++-- GENERIC+decodeArguments :: forall a. Decode a => Arguments VALID -> ResolverState a+decodeArguments = decode . Object . fmap toEntry+  where+    toEntry Argument {..} = ObjectEntry argumentName argumentValue++type Decode a = (DecodeKind (KIND a) a)++decode :: forall a. Decode a => ValidValue -> ResolverState a+decode = decodeKind (Proxy @(KIND a))++-- | Decode GraphQL type with Specific Kind+class DecodeKind (kind :: DerivingKind) a where+  decodeKind :: Proxy kind -> ValidValue -> ResolverState a++-- SCALAR+instance (DecodeScalar a, GQLType a) => DecodeKind SCALAR a where+  decodeKind _ = withScalar (deriveTypename (KindedProxy :: KindedProxy LEAF a)) decodeScalar++-- INPUT_OBJECT and  INPUT_UNION+instance+  ( Generic a,+    GQLType a,+    DecodeRep (Rep a)+  ) =>+  DecodeKind TYPE a+  where+  decodeKind _ = fmap to . (`runReaderT` context) . decodeRep+    where+      context =+        Context+          { options = typeOptions proxy defaultTypeOptions,+            isVariantRef = False,+            typeName = deriveTypename (KindedProxy :: KindedProxy IN a),+            enumVisitor = visitEnumName proxy,+            fieldVisitor = visitFieldName proxy+          }+        where+          proxy = Proxy @a++instance (Decode a, DecodeWrapperConstraint f a, DecodeWrapper f) => DecodeKind WRAPPER (f a) where+  decodeKind _ value =+    runExceptT (decodeWrapper decode value)+      >>= handleEither++instance (Decode a, KnownSymbol name) => DecodeKind CUSTOM (Arg name a) where+  decodeKind _ value = Arg <$> withInputObject fieldDecoder value+    where+      fieldDecoder = decodeFieldWith decode fieldName+      fieldName = symbolName (Proxy @name)++--  Map+instance (Ord k, Decode (k, v)) => DecodeKind CUSTOM (Map k v) where+  decodeKind _ v = M.fromList <$> (decode v :: ResolverState [(k, v)])++decideEither ::+  (DecodeRep f, DecodeRep g) =>+  ([TypeName], [TypeName]) ->+  TypeName ->+  ValidValue ->+  DecoderT ((f :+: g) a)+decideEither (left, right) name value+  | name `elem` left = L1 <$> decodeRep value+  | name `elem` right = R1 <$> decodeRep value+  | otherwise =+      throwError $+        internal $+          "Constructor \""+            <> msg name+            <> "\" could not find in Union"++decodeInputUnionObject ::+  (DecodeRep f, DecodeRep g) =>+  ([TypeName], [TypeName]) ->+  TypeName ->+  Object VALID ->+  ValidObject ->+  DecoderT ((f :+: g) a)+decodeInputUnionObject (l, r) name unions object+  | [name] == l = L1 <$> decodeRep (Object object)+  | [name] == r = R1 <$> decodeRep (Object object)+  | otherwise = decideEither (l, r) name (Object unions)++class DecodeRep (f :: Type -> Type) where+  decodeRep :: ValidValue -> DecoderT (f a)++instance (Datatype d, DecodeRep f) => DecodeRep (M1 D d f) where+  decodeRep value = M1 <$> decodeRep value++instance (DescribeCons a, DescribeCons b, DecodeRep a, DecodeRep b) => DecodeRep (a :+: b) where+  decodeRep (Object obj) =+    do+      (kind, lr) <- getUnionInfos (Proxy @(a :+: b))+      setVariantRef kind $ withInputUnion (decodeInputUnionObject lr) obj+  decodeRep (Enum name) = do+    (_, (l, r)) <- getUnionInfos (Proxy @(a :+: b))+    visitor <- asks enumVisitor+    decideEither (map visitor l, map visitor r) name (Enum name)+  decodeRep _ = throwError (internal "lists and scalars are not allowed in Union")++instance (Constructor c, DecodeFields a) => DecodeRep (M1 C c a) where+  decodeRep = fmap M1 . decodeFields 0++class DecodeFields (f :: Type -> Type) where+  decodeFields :: Int -> ValidValue -> DecoderT (f a)++instance (DecodeFields f, DecodeFields g, DescribeFields g) => DecodeFields (f :*: g) where+  decodeFields index gql =+    (:*:)+      <$> decodeFields index gql+      <*> decodeFields (index + countFields (Proxy @g)) gql++instance (Selector s, GQLType a, Decode a) => DecodeFields (M1 S s (K1 i a)) where+  decodeFields index value =+    M1 . K1 <$> do+      Context {options, isVariantRef, fieldVisitor} <- ask+      if isVariantRef+        then lift (decode value)+        else+          let fieldName = fieldVisitor $ getFieldName (selNameProxy options (Proxy @s)) index+              fieldDecoder = decodeFieldWith (lift . decode) fieldName+           in withInputObject fieldDecoder value++instance DecodeFields U1 where+  decodeFields _ _ = pure U1
+ src/Data/Morpheus/Server/Deriving/Encode.hs view
@@ -0,0 +1,262 @@+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE PolyKinds #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE NoImplicitPrelude #-}++module Data.Morpheus.Server.Deriving.Encode+  ( deriveModel,+    EncodeConstraints,+    ContextValue (..),+  )+where++import Control.Monad.Except (MonadError)+import qualified Data.Map as M+import Data.Morpheus.App.Internal.Resolving+  ( LiftOperation,+    ObjectTypeResolver,+    Resolver,+    ResolverState,+    ResolverValue (..),+    RootResolverValue (..),+    getArguments,+    liftResolverState,+    mkEnum,+    mkObject,+    mkUnion,+    requireObject,+  )+import Data.Morpheus.Internal.Ext (GQLResult)+import Data.Morpheus.Server.Deriving.Channels+  ( ChannelsConstraint,+    channelResolver,+  )+import Data.Morpheus.Server.Deriving.Decode+  ( Decode,+    decodeArguments,+  )+import Data.Morpheus.Server.Deriving.Schema.Directive (toFieldRes, visitEnumName)+import Data.Morpheus.Server.Deriving.Utils+  ( ConsRep (..),+    DataType (..),+    FieldRep (..),+    isUnionRef,+  )+import Data.Morpheus.Server.Deriving.Utils.DeriveGType+  ( DeriveValueOptions (..),+    DeriveWith,+    deriveValue,+  )+import Data.Morpheus.Server.Deriving.Utils.Kinded (KindedProxy (KindedProxy), kinded)+import Data.Morpheus.Server.Resolvers+  ( RootResolver (..),+  )+import Data.Morpheus.Server.Types.GQLType+  ( GQLType (typeOptions),+    KIND,+    deriveTypename,+    __isEmptyType,+    __typeData,+  )+import Data.Morpheus.Server.Types.Internal (defaultTypeOptions)+import Data.Morpheus.Server.Types.Kind+  ( CUSTOM,+    DerivingKind,+    SCALAR,+    TYPE,+    WRAPPER,+  )+import Data.Morpheus.Server.Types.Types+  ( TypeGuard (..),+  )+import Data.Morpheus.Types.GQLScalar+  ( EncodeScalar (..),+  )+import Data.Morpheus.Types.GQLWrapper (EncodeWrapper (..))+import Data.Morpheus.Types.Internal.AST+  ( GQLError,+    IN,+    MUTATION,+    OperationType,+    QUERY,+    SUBSCRIPTION,+    TypeRef (..),+  )+import GHC.Generics+  ( Generic (..),+  )+import Relude++newtype ContextValue (kind :: DerivingKind) a = ContextValue+  { unContextValue :: a+  }++class Encode (m :: Type -> Type) resolver where+  encode :: resolver -> m (ResolverValue m)++instance (EncodeKind (KIND a) m a) => Encode m a where+  encode resolver = encodeKind (ContextValue resolver :: ContextValue (KIND a) a)++-- ENCODE GQL KIND+class EncodeKind (kind :: DerivingKind) (m :: Type -> Type) (a :: Type) where+  encodeKind :: ContextValue kind a -> m (ResolverValue m)++instance+  ( EncodeWrapper f,+    Encode m a,+    Monad m+  ) =>+  EncodeKind WRAPPER m (f a)+  where+  encodeKind = encodeWrapper encode . unContextValue++instance+  ( EncodeScalar a,+    Monad m+  ) =>+  EncodeKind SCALAR m a+  where+  encodeKind = pure . ResScalar . encodeScalar . unContextValue++instance+  ( EncodeConstraint m a,+    MonadError GQLError m+  ) =>+  EncodeKind TYPE m a+  where+  encodeKind = pure . exploreResolvers . unContextValue++--  Map+instance (Monad m, Encode m [(k, v)]) => EncodeKind CUSTOM m (Map k v) where+  encodeKind = encode . M.toList . unContextValue++--  INTERFACE Types+instance (MonadError GQLError m, EncodeConstraint m guard, EncodeConstraint m union) => EncodeKind CUSTOM m (TypeGuard guard union) where+  encodeKind (ContextValue (ResolveType value)) = pure (exploreResolvers value)+  encodeKind (ContextValue (ResolveInterface value)) = pure (exploreResolvers value)++--  GQL a -> Resolver b, MUTATION, SUBSCRIPTION, QUERY+instance+  ( Decode a,+    Generic a,+    Monad m,+    Encode (Resolver o e m) b,+    LiftOperation o+  ) =>+  EncodeKind CUSTOM (Resolver o e m) (a -> b)+  where+  encodeKind (ContextValue f) =+    getArguments+      >>= liftResolverState . decodeArguments+      >>= encode . f++--  GQL a -> Resolver b, MUTATION, SUBSCRIPTION, QUERY+instance+  (Monad m, Encode (Resolver o e m) b, LiftOperation o) =>+  EncodeKind CUSTOM (Resolver o e m) (Resolver o e m b)+  where+  encodeKind (ContextValue value) = value >>= encode++convertNode ::+  forall m f a.+  (MonadError GQLError m, GQLType a) =>+  f a ->+  DataType (m (ResolverValue m)) ->+  ResolverValue m+convertNode+  proxy+  DataType+    { dataTypeName,+      tyIsUnion,+      tyCons = cons@ConsRep {consFields, consName}+    } = encodeTypeFields consFields+    where+      -- ENUM+      encodeTypeFields ::+        [FieldRep (m (ResolverValue m))] ->+        ResolverValue m+      encodeTypeFields [] = mkEnum (visitEnumName proxy consName)+      encodeTypeFields fields+        | not tyIsUnion = mkObject dataTypeName (toFieldRes proxy <$> fields)+      -- Type References --------------------------------------------------------------+      encodeTypeFields [FieldRep {fieldTypeRef, fieldValue}]+        | isUnionRef dataTypeName cons = ResLazy (ResObject (Just (typeConName fieldTypeRef)) <$> (fieldValue >>= requireObject))+      -- Inline Union Types ----------------------------------------------------------------------------+      encodeTypeFields fields = mkUnion consName (toFieldRes proxy <$> fields)++-- Types & Constrains -------------------------------------------------------+class (Encode m a, GQLType a) => ExplorerConstraint m a++instance (Encode m a, GQLType a) => ExplorerConstraint m a++exploreResolvers ::+  forall m a.+  ( EncodeConstraint m a,+    MonadError GQLError m+  ) =>+  a ->+  ResolverValue m+exploreResolvers =+  convertNode (Proxy @a)+    . deriveValue+      ( DeriveValueOptions+          { __valueApply = encode,+            __valueTypeName = deriveTypename (KindedProxy :: KindedProxy IN a),+            __valueGQLOptions = typeOptions (Proxy @a) defaultTypeOptions,+            __valueGetType = __typeData . kinded (Proxy @IN)+          } ::+          DeriveValueOptions IN (ExplorerConstraint m) (m (ResolverValue m))+      )++----- HELPERS ----------------------------+objectResolvers ::+  ( EncodeConstraint m a,+    MonadError GQLError m+  ) =>+  a ->+  ResolverState (ObjectTypeResolver m)+objectResolvers value = requireObject (exploreResolvers value)++type EncodeConstraint (m :: Type -> Type) a =+  ( GQLType a,+    Generic a,+    DeriveWith (ExplorerConstraint m) (m (ResolverValue m)) (Rep a)+  )++type EncodeObjectConstraint (o :: OperationType) e (m :: Type -> Type) a =+  EncodeConstraint (Resolver o e m) (a (Resolver o e m))++type EncodeConstraints e m query mut sub =+  ( ChannelsConstraint e m sub,+    EncodeObjectConstraint QUERY e m query,+    EncodeObjectConstraint MUTATION e m mut,+    EncodeObjectConstraint SUBSCRIPTION e m sub+  )++deriveModel ::+  forall e m query mut sub.+  (Monad m, EncodeConstraints e m query mut sub) =>+  RootResolver m e query mut sub ->+  GQLResult (RootResolverValue e m)+deriveModel RootResolver {..} =+  pure+    RootResolverValue+      { queryResolver = objectResolvers queryResolver,+        mutationResolver = objectResolvers mutationResolver,+        subscriptionResolver = objectResolvers subscriptionResolver,+        channelMap+      }+  where+    channelMap+      | __isEmptyType (Proxy :: Proxy (sub (Resolver SUBSCRIPTION e m))) = Nothing+      | otherwise = Just (channelResolver subscriptionResolver)
+ src/Data/Morpheus/Server/Deriving/Named/Encode.hs view
@@ -0,0 +1,56 @@+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE PolyKinds #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE NoImplicitPrelude #-}++module Data.Morpheus.Server.Deriving.Named.Encode+  ( deriveNamedModel,+    EncodeNamedConstraints,+  )+where++import Data.Morpheus.App.Internal.Resolving+  ( NamedResolver (..),+    Resolver,+    RootResolverValue (..),+  )+import Data.Morpheus.Server.Deriving.Named.EncodeType+  ( EncodeTypeConstraint,+    deriveResolver,+  )+import Data.Morpheus.Server.Deriving.Utils.GTraversable+  ( traverseTypes,+  )+import Data.Morpheus.Server.NamedResolvers (NamedResolverT (..))+import Data.Morpheus.Server.Resolvers+  ( NamedResolvers (..),+  )+import Data.Morpheus.Types.Internal.AST+  ( QUERY,+  )+import qualified GHC.Exts as HM+import Relude++type EncodeNamedConstraints e m query mut sub =+  (EncodeTypeConstraint (Resolver QUERY e m) query)++deriveNamedModel ::+  forall e m query mut sub.+  (Monad m, EncodeNamedConstraints e m query mut sub) =>+  NamedResolvers m e query mut sub ->+  RootResolverValue e m+deriveNamedModel NamedResolvers =+  NamedResolversValue $+    HM.fromList $+      map (\x -> (resolverName x, x)) $+        join $+          toList $+            traverseTypes deriveResolver (Proxy @(query (NamedResolverT (Resolver QUERY e m))))
+ src/Data/Morpheus/Server/Deriving/Named/EncodeType.hs view
@@ -0,0 +1,107 @@+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE PolyKinds #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE NoImplicitPrelude #-}++module Data.Morpheus.Server.Deriving.Named.EncodeType+  ( deriveResolver,+    EncodeTypeConstraint,+    DeriveNamedResolver (..),+  )+where++import Data.Morpheus.App.Internal.Resolving+  ( LiftOperation,+    NamedResolver (..),+    Resolver,+    ResolverState,+    liftResolverState,+  )+import Data.Morpheus.Server.Deriving.Decode+  ( Decode,+    decode,+  )+import Data.Morpheus.Server.Deriving.Named.EncodeValue+  ( EncodeFieldKind,+    FieldConstraint,+    encodeResolverValue,+    getTypeName,+  )+import Data.Morpheus.Server.Deriving.Utils.GTraversable+import Data.Morpheus.Server.Deriving.Utils.Kinded (KindedProxy (KindedProxy))+import Data.Morpheus.Server.NamedResolvers (NamedResolverT (..), ResolveNamed (Dep, resolveNamed))+import Data.Morpheus.Server.Types.GQLType+  ( GQLType,+    KIND,+  )+import Data.Morpheus.Server.Types.Kind+  ( CUSTOM,+    DerivingKind,+    SCALAR,+    TYPE,+    WRAPPER,+  )+import Data.Morpheus.Types.Internal.AST+  ( ValidValue,+  )+import Relude++deriveResolver :: Mappable (DeriveNamedResolver m) [NamedResolver m] KindedProxy+deriveResolver = Mappable deriveNamedResolver++type EncodeTypeConstraint m a =+  ( GFmap+      (ScanConstraint (DeriveNamedResolver m))+      (KIND (a (NamedResolverT m)))+      (a (NamedResolverT m)),+    DeriveNamedResolver+      m+      (KIND (a (NamedResolverT m)))+      (a (NamedResolverT m)),+    GQLType (a (NamedResolverT m))+  )++class DeriveNamedResolver (m :: Type -> Type) (k :: DerivingKind) a where+  deriveNamedResolver :: f k a -> [NamedResolver m]++instance DeriveNamedResolver m SCALAR a where+  deriveNamedResolver _ = []++instance+  ( Monad m,+    LiftOperation o,+    Generic a,+    GQLType a,+    EncodeFieldKind (KIND a) (Resolver o e m) a,+    Decode (Dep a),+    ResolveNamed (Resolver o e m) a,+    FieldConstraint (Resolver o e m) a+  ) =>+  DeriveNamedResolver (Resolver o e m) TYPE (a :: Type)+  where+  deriveNamedResolver _ =+    [ NamedResolver+        { resolverName = getTypeName (Proxy @a),+          resolver = resolve >=> encodeResolverValue+        }+    ]+    where+      resolve :: ValidValue -> Resolver o e m a+      resolve x = liftResolverState (decode x :: ResolverState (Dep a)) >>= resolveNamed++instance DeriveNamedResolver m (KIND a) a => DeriveNamedResolver m CUSTOM (NamedResolverT m a) where+  deriveNamedResolver _ = deriveNamedResolver (KindedProxy :: KindedProxy (KIND a) a)++instance DeriveNamedResolver m (KIND a) a => DeriveNamedResolver m CUSTOM (input -> a) where+  deriveNamedResolver _ = deriveNamedResolver (KindedProxy :: KindedProxy (KIND a) a)++instance DeriveNamedResolver m (KIND a) a => DeriveNamedResolver m WRAPPER (f a) where+  deriveNamedResolver _ = deriveNamedResolver (KindedProxy :: KindedProxy (KIND a) a)
+ src/Data/Morpheus/Server/Deriving/Named/EncodeValue.hs view
@@ -0,0 +1,205 @@+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE PolyKinds #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE NoImplicitPrelude #-}++module Data.Morpheus.Server.Deriving.Named.EncodeValue+  ( EncodeFieldKind,+    Encode,+    getTypeName,+    encodeResolverValue,+    FieldConstraint,+  )+where++import Control.Monad.Except (MonadError (..))+import Data.Aeson (ToJSON (..))+import Data.Morpheus.App.Internal.Resolving+  ( LiftOperation,+    NamedResolverRef (..),+    NamedResolverResult (..),+    ObjectTypeResolver (..),+    Resolver,+    ResolverValue (..),+    getArguments,+    liftResolverState,+    mkList,+    mkNull,+  )+import Data.Morpheus.Server.Deriving.Decode+  ( Decode,+    decodeArguments,+  )+import Data.Morpheus.Server.Deriving.Encode+  ( ContextValue (..),+  )+import Data.Morpheus.Server.Deriving.Schema.Directive (toFieldRes)+import Data.Morpheus.Server.Deriving.Utils+  ( ConsRep (..),+    DataType (..),+    FieldRep (..),+  )+import Data.Morpheus.Server.Deriving.Utils.DeriveGType+  ( DeriveValueOptions (..),+    DeriveWith,+    deriveValue,+  )+import Data.Morpheus.Server.Deriving.Utils.Kinded+import Data.Morpheus.Server.NamedResolvers+  ( NamedResolverT (..),+    ResolveNamed (..),+  )+import Data.Morpheus.Server.Types (defaultTypeOptions)+import Data.Morpheus.Server.Types.GQLType+  ( GQLType (typeOptions, __type),+    KIND,+    deriveTypename,+    __typeData,+  )+import Data.Morpheus.Server.Types.Internal+  ( TypeData (gqlTypeName),+  )+import Data.Morpheus.Server.Types.Kind+  ( CUSTOM,+    DerivingKind,+    SCALAR,+    TYPE,+    WRAPPER,+  )+import Data.Morpheus.Types.GQLScalar+  ( EncodeScalar (..),+  )+import Data.Morpheus.Types.Internal.AST+  ( GQLError,+    OUT,+    TypeCategory (OUT),+    TypeName,+    internal,+    replaceValue,+  )+import qualified GHC.Exts as HM+import GHC.Generics+  ( Generic (..),+  )+import Relude++encodeResolverValue :: (MonadError GQLError m, FieldConstraint m a) => a -> m (NamedResolverResult m)+encodeResolverValue x = convertNamedNode (Identity x) (getFieldValues x)++type FieldConstraint m a =+  ( GQLType a,+    Generic a,+    DeriveWith (GValueMapConstraint m) (m (ResolverValue m)) (Rep a)+  )++class Encode (m :: Type -> Type) res where+  encodeField :: res -> m (ResolverValue m)++instance (EncodeFieldKind (KIND a) m a) => Encode m a where+  encodeField resolver = encodeFieldKind (ContextValue resolver :: ContextValue (KIND a) a)++class EncodeFieldKind (k :: DerivingKind) (m :: Type -> Type) (a :: Type) where+  encodeFieldKind :: ContextValue k a -> m (ResolverValue m)++instance (EncodeScalar a, Monad m) => EncodeFieldKind SCALAR m a where+  encodeFieldKind = pure . ResScalar . encodeScalar . unContextValue++instance (FieldConstraint m a, MonadError GQLError m) => EncodeFieldKind TYPE m a where+  encodeFieldKind (ContextValue _) = throwError (internal "types are resolved by Refs")++instance (GQLType a, Applicative m, EncodeFieldKind (KIND a) m a) => EncodeFieldKind WRAPPER m [a] where+  encodeFieldKind = fmap ResList . traverse encodeField . unContextValue++instance (GQLType a, EncodeFieldKind (KIND a) m a, Applicative m) => EncodeFieldKind WRAPPER m (Maybe a) where+  encodeFieldKind (ContextValue (Just x)) = encodeField x+  encodeFieldKind (ContextValue Nothing) = pure mkNull++instance+  ( Monad m,+    GQLType a,+    EncodeFieldKind (KIND a) m a,+    ToJSON (Dep a)+  ) =>+  EncodeFieldKind CUSTOM m (NamedResolverT m a)+  where+  encodeFieldKind = encodeRef . unContextValue+    where+      name :: TypeName+      name = getTypeName (Proxy @a)+      encodeRef :: Monad m => NamedResolverT m a -> m (ResolverValue m)+      encodeRef (Ref x) = pure $ ResRef (NamedResolverRef name . replaceValue . toJSON <$> x)+      encodeRef (Value value) = value >>= encodeField+      encodeRef (Refs refs) = mkList . map (ResRef . pure . NamedResolverRef name . replaceValue . toJSON) <$> refs++instance+  ( Decode a,+    Generic a,+    Monad m,+    Encode (Resolver o e m) b,+    LiftOperation o+  ) =>+  EncodeFieldKind CUSTOM (Resolver o e m) (a -> b)+  where+  encodeFieldKind (ContextValue f) =+    getArguments+      >>= liftResolverState . decodeArguments+      >>= encodeField . f++class (Encode m a, GQLType a) => GValueMapConstraint m a++instance (Encode m a, GQLType a) => GValueMapConstraint m a++getFieldValues :: forall m a. FieldConstraint m a => a -> DataType (m (ResolverValue m))+getFieldValues =+  deriveValue+    ( DeriveValueOptions+        { __valueApply = encodeField,+          __valueTypeName = deriveTypename (KindedProxy :: KindedProxy OUT a),+          __valueGQLOptions = typeOptions (Proxy @a) defaultTypeOptions,+          __valueGetType = __typeData . kinded (Proxy @OUT)+        } ::+        DeriveValueOptions OUT (GValueMapConstraint m) (m (ResolverValue m))+    )++convertNamedNode ::+  (GQLType a, MonadError GQLError m) =>+  f a ->+  DataType (m (ResolverValue m)) ->+  m (NamedResolverResult m)+convertNamedNode+  proxy+  DataType+    { tyIsUnion,+      tyCons = ConsRep {consFields, consName}+    }+    | null consFields = pure $ NamedEnumResolver consName+    | tyIsUnion = deriveUnion consFields+    | otherwise =+        pure $+          NamedObjectResolver+            ObjectTypeResolver+              { objectFields = HM.fromList (toFieldRes proxy <$> consFields)+              }++deriveUnion :: (MonadError GQLError m) => [FieldRep (m (ResolverValue m))] -> m (NamedResolverResult m)+deriveUnion [FieldRep {..}] =+  NamedUnionResolver <$> (fieldValue >>= getRef)+deriveUnion _ = throwError "only union references are supported!"++getRef :: MonadError GQLError m => ResolverValue m -> m NamedResolverRef+getRef (ResRef x) = x+getRef _ = throwError "only resolver references are supported!"++getTypeName :: GQLType a => f a -> TypeName+getTypeName proxy = gqlTypeName $ __type proxy OUT
+ src/Data/Morpheus/Server/Deriving/Schema.hs view
@@ -0,0 +1,297 @@+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE PolyKinds #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE NoImplicitPrelude #-}+{-# OPTIONS_GHC -Wno-orphans #-}++module Data.Morpheus.Server.Deriving.Schema+  ( compileTimeSchemaValidation,+    DeriveType,+    deriveSchema,+    SchemaConstraints,+    SchemaT,+  )+where++import Control.Monad.Except (throwError)+import Data.Morpheus.App.Internal.Resolving+  ( Resolver,+  )+import Data.Morpheus.Core (defaultConfig, validateSchema)+import Data.Morpheus.Internal.Ext+import Data.Morpheus.Internal.Utils (singleton)+import Data.Morpheus.Server.Deriving.Schema.Internal+  ( KindedType (..),+    TyContentM,+    fromSchema,+  )+import Data.Morpheus.Server.Deriving.Schema.Object+  ( asObjectType,+    withObject,+  )+import Data.Morpheus.Server.Deriving.Schema.TypeContent+import Data.Morpheus.Server.Deriving.Utils+  ( DeriveTypeOptions (..),+    DeriveWith,+    symbolName,+  )+import Data.Morpheus.Server.Deriving.Utils.Kinded+  ( CategoryValue (..),+    KindedProxy (..),+    inputType,+    kinded,+    outputType,+    setKind,+  )+import Data.Morpheus.Server.Types.GQLType+  ( DeriveArguments (..),+    GQLType (..),+    deriveTypename,+    __isEmptyType,+    __typeData,+  )+import Data.Morpheus.Server.Types.Internal (TypeData (..), defaultTypeOptions)+import Data.Morpheus.Server.Types.Kind+  ( CUSTOM,+    DerivingKind,+    SCALAR,+    TYPE,+    WRAPPER,+  )+import Data.Morpheus.Server.Types.SchemaT+  ( SchemaT,+    extendImplements,+    toSchema,+    withInput,+  )+import Data.Morpheus.Server.Types.Types+  ( Arg (..),+    TypeGuard,+  )+import Data.Morpheus.Types.GQLScalar+  ( DecodeScalar (..),+    scalarValidator,+  )+import Data.Morpheus.Types.Internal.AST+  ( CONST,+    FieldContent (..),+    FieldsDefinition,+    IN,+    LEAF,+    MUTATION,+    OBJECT,+    OUT,+    QUERY,+    SUBSCRIPTION,+    Schema (..),+    TRUE,+    TypeCategory,+    TypeContent (..),+    TypeDefinition (..),+    TypeName,+    TypeRef (..),+    UnionMember (memberName),+    fieldsToArguments,+    mkField,+  )+import GHC.Generics+import GHC.TypeLits+import Language.Haskell.TH (Exp, Q)+import Relude++type SchemaConstraints event (m :: Type -> Type) query mutation subscription =+  ( DeriveTypeConstraintOpt OUT (query (Resolver QUERY event m)),+    DeriveTypeConstraintOpt OUT (mutation (Resolver MUTATION event m)),+    DeriveTypeConstraintOpt OUT (subscription (Resolver SUBSCRIPTION event m))+  )++type DeriveTypeConstraintOpt kind a =+  ( GQLType a,+    DeriveWith (DeriveWithConstraint kind) (TyContentM kind) (Rep a)+  )++-- | normal morpheus server validates schema at runtime (after the schema derivation).+--   this method allows you to validate it at compile time.+compileTimeSchemaValidation ::+  (SchemaConstraints event m qu mu su) =>+  proxy (root m event qu mu su) ->+  Q Exp+compileTimeSchemaValidation =+  fromSchema . (deriveSchema >=> validateSchema True defaultConfig)++deriveSchema ::+  forall+    root+    proxy+    m+    e+    query+    mut+    subs.+  ( SchemaConstraints e m query mut subs+  ) =>+  proxy (root m e query mut subs) ->+  GQLResult (Schema CONST)+deriveSchema _ = toSchema schemaT+  where+    schemaT ::+      SchemaT+        OUT+        ( TypeDefinition OBJECT CONST,+          Maybe (TypeDefinition OBJECT CONST),+          Maybe (TypeDefinition OBJECT CONST)+        )+    schemaT =+      (,,)+        <$> deriveRoot (Proxy @(query (Resolver QUERY e m)))+        <*> deriveMaybeRoot (Proxy @(mut (Resolver MUTATION e m)))+        <*> deriveMaybeRoot (Proxy @(subs (Resolver SUBSCRIPTION e m)))++-- |  Generates internal GraphQL Schema for query validation and introspection rendering+class DeriveType (kind :: TypeCategory) (a :: Type) where+  deriveType :: f a -> SchemaT kind ()+  deriveContent :: f a -> TyContentM kind++instance (GQLType a, DeriveKindedType cat (KIND a) a) => DeriveType cat a where+  deriveType _ = deriveKindedType (KindedProxy :: KindedProxy (KIND a) a)+  deriveContent _ = deriveKindedContent (KindedProxy :: KindedProxy (KIND a) a)++-- | DeriveType With specific Kind: 'kind': object, scalar, enum ...+class DeriveKindedType (cat :: TypeCategory) (kind :: DerivingKind) a where+  deriveKindedType :: kinded kind a -> SchemaT cat ()+  deriveKindedContent :: kinded kind a -> TyContentM cat+  deriveKindedContent _ = pure Nothing++type DeriveTypeConstraint kind a =+  ( DeriveTypeConstraintOpt kind a,+    CategoryValue kind+  )++instance (GQLType a, DeriveType cat a) => DeriveKindedType cat WRAPPER (f a) where+  deriveKindedType _ = deriveType (KindedProxy :: KindedProxy cat a)++instance (GQLType a, DecodeScalar a) => DeriveKindedType cat SCALAR a where+  deriveKindedType = insertTypeContent deriveScalarContent . setKind (Proxy @LEAF)++instance DeriveTypeConstraint OUT a => DeriveKindedType OUT TYPE a where+  deriveKindedType = deriveOutputType++instance DeriveTypeConstraint IN a => DeriveKindedType IN TYPE a where+  deriveKindedType = deriveInputType++instance DeriveType cat a => DeriveKindedType cat CUSTOM (Resolver o e m a) where+  deriveKindedType _ = deriveType (Proxy @a)++instance DeriveType cat [(k, v)] => DeriveKindedType cat CUSTOM (Map k v) where+  deriveKindedType _ = deriveType (Proxy @[(k, v)])++instance+  ( DeriveTypeConstraint OUT interface,+    DeriveTypeConstraint OUT union+  ) =>+  DeriveKindedType OUT CUSTOM (TypeGuard interface union)+  where+  deriveKindedType _ = do+    insertTypeContent deriveInterfaceContent interfaceProxy+    content <- deriveTypeContent (OutputType :: KindedType OUT union)+    unionNames <- getUnionNames content+    extendImplements interfaceName unionNames+    where+      interfaceName :: TypeName+      interfaceName = deriveTypename interfaceProxy+      interfaceProxy :: KindedProxy OUT interface+      interfaceProxy = KindedProxy+      unionProxy :: KindedProxy OUT union+      unionProxy = KindedProxy+      getUnionNames :: TypeContent TRUE OUT CONST -> SchemaT OUT [TypeName]+      getUnionNames DataUnion {unionMembers} = pure $ toList $ memberName <$> unionMembers+      getUnionNames DataObject {} = pure [deriveTypename unionProxy]+      getUnionNames _ = throwError "guarded type must be an union or object"++instance+  ( GQLType b,+    DeriveKindedType OUT (KIND b) b,+    DeriveArguments (KIND a) a+  ) =>+  DeriveKindedType OUT CUSTOM (a -> b)+  where+  deriveKindedContent _ = do+    a <- deriveArgumentsDefinition (KindedProxy :: KindedProxy (KIND a) a)+    b <- deriveKindedContent (KindedProxy :: KindedProxy (KIND b) b)+    case b of+      Just (FieldArgs x) -> Just . FieldArgs <$> (a <:> x)+      Nothing -> pure $ Just (FieldArgs a)+  deriveKindedType _ = deriveType (outputType $ Proxy @b)++deriveScalarContent :: (DecodeScalar a) => f k a -> SchemaT cat (TypeContent TRUE LEAF CONST)+deriveScalarContent = pure . DataScalar . scalarValidator++deriveInterfaceContent :: DeriveTypeConstraint OUT a => f a -> SchemaT OUT (TypeContent TRUE OUT CONST)+deriveInterfaceContent = fmap DataInterface . deriveFields . outputType++instance DeriveTypeConstraint IN a => DeriveArguments TYPE a where+  deriveArgumentsDefinition = withInput . fmap fieldsToArguments . deriveFields . inputType++instance (KnownSymbol name, DeriveType IN a, GQLType a) => DeriveArguments CUSTOM (Arg name a) where+  deriveArgumentsDefinition _ = do+    withInput (deriveType proxy)+    pure $ fieldsToArguments $ singleton argName $ mkField Nothing argName argTypeRef+    where+      proxy :: KindedProxy IN a+      proxy = KindedProxy+      argName = symbolName (Proxy @name)+      argTypeRef = TypeRef {typeConName = gqlTypeName, typeWrappers = gqlWrappers}+      TypeData {gqlTypeName, gqlWrappers} = __typeData proxy++deriveFields :: DeriveTypeConstraint kind a => KindedType kind a -> SchemaT kind (FieldsDefinition kind CONST)+deriveFields kindedType = deriveTypeContent kindedType >>= withObject kindedType++deriveInputType :: DeriveTypeConstraint IN a => f a -> SchemaT IN ()+deriveInputType = insertTypeContent deriveTypeContent . inputType++deriveOutputType :: DeriveTypeConstraint OUT a => f a -> SchemaT OUT ()+deriveOutputType = insertTypeContent deriveTypeContent . outputType++deriveRoot :: DeriveTypeConstraint OUT a => f a -> SchemaT OUT (TypeDefinition OBJECT CONST)+deriveRoot = asObjectType (deriveFields . outputType)++deriveMaybeRoot :: DeriveTypeConstraint OUT a => f a -> SchemaT OUT (Maybe (TypeDefinition OBJECT CONST))+deriveMaybeRoot proxy+  | __isEmptyType proxy = pure Nothing+  | otherwise = Just <$> asObjectType (deriveFields . outputType) proxy++deriveFieldContent :: forall f kind a. (DeriveType kind a) => f a -> TyContentM kind+deriveFieldContent _ = deriveType kindedProxy *> deriveContent kindedProxy+  where+    kindedProxy :: KindedProxy kind a+    kindedProxy = KindedProxy++class (GQLType a, DeriveType k a) => DeriveWithConstraint k a++instance (GQLType a, DeriveType k a) => DeriveWithConstraint k a++deriveTypeContent ::+  forall kind a.+  DeriveTypeConstraint kind a =>+  KindedType kind a ->+  SchemaT kind (TypeContent TRUE kind CONST)+deriveTypeContent =+  deriveTypeContentWith+    ( DeriveTypeDefinitionOptions+        { __typeGQLOptions = typeOptions (Proxy @a) defaultTypeOptions,+          __typeGetType = __typeData . kinded (Proxy @kind),+          __typeApply = deriveFieldContent+        } ::+        DeriveTypeOptions kind (DeriveWithConstraint kind) (TyContentM kind)+    )
+ src/Data/Morpheus/Server/Deriving/Schema/Directive.hs view
@@ -0,0 +1,168 @@+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE PolyKinds #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE NoImplicitPrelude #-}++module Data.Morpheus.Server.Deriving.Schema.Directive+  ( deriveFieldDirectives,+    deriveTypeDirectives,+    deriveEnumDirectives,+    visitEnumValueDescription,+    visitFieldDescription,+    visitTypeDescription,+    visitEnumName,+    visitFieldName,+    toFieldRes,+  )+where++import Control.Monad.Except (throwError)+import qualified Data.HashMap.Lazy as HM+import Data.Morpheus.Internal.Ext (resultOr, unsafeFromList)+import Data.Morpheus.Internal.Utils (Empty (..))+import Data.Morpheus.Server.Deriving.Utils.Kinded+  ( KindedProxy (..),+  )+import Data.Morpheus.Server.Deriving.Utils.Types (FieldRep (..))+import Data.Morpheus.Server.Types.Directives+  ( GQLDirective (..),+    ToLocations,+    getLocations,+  )+import Data.Morpheus.Server.Types.GQLType+  ( DeriveArguments (..),+    DirectiveUsage (..),+    DirectiveUsages (..),+    GQLType (..),+    applyEnumDescription,+    applyEnumName,+    applyFieldDescription,+    applyFieldName,+    applyTypeDescription,+    deriveFingerprint,+    deriveTypename,+    encodeArguments,+  )+import Data.Morpheus.Server.Types.SchemaT+  ( SchemaT,+    insertDirectiveDefinition,+    outToAny,+  )+import Data.Morpheus.Types.Internal.AST+  ( CONST,+    Description,+    Directive (..),+    DirectiveDefinition (..),+    Directives,+    FieldName,+    IN,+    Position (Position),+    TypeName,+  )+import GHC.Generics ()+import GHC.TypeLits ()+import Relude hiding (empty)++type DirectiveDefinitionConstraint a =+  ( GQLDirective a,+    GQLType a,+    DeriveArguments (KIND a) a,+    ToLocations (DIRECTIVE_LOCATIONS a)+  )++deriveDirectiveDefinition ::+  forall a b kind.+  (DirectiveDefinitionConstraint a) =>+  a ->+  b ->+  SchemaT kind (DirectiveDefinition CONST)+deriveDirectiveDefinition _ _ = do+  directiveDefinitionArgs <- outToAny (deriveArgumentsDefinition (KindedProxy :: KindedProxy (KIND a) a))+  pure+    ( DirectiveDefinition+        { directiveDefinitionName = deriveDirectiveName proxy,+          directiveDefinitionDescription = description proxy,+          directiveDefinitionArgs,+          directiveDefinitionLocations = getLocations proxy+        }+    )+  where+    proxy = Proxy @a++deriveTypeDirectives :: forall c f a. GQLType a => f a -> SchemaT c (Directives CONST)+deriveTypeDirectives proxy = deriveDirectiveUsages (typeDirectives $ directives proxy)++deriveDirectiveUsages :: [DirectiveUsage] -> SchemaT c (Directives CONST)+deriveDirectiveUsages = fmap unsafeFromList . traverse toDirectiveTuple++deriveDirectiveName :: forall f a. GQLType a => f a -> FieldName+deriveDirectiveName _ = coerce $ deriveTypename (KindedProxy :: KindedProxy IN a)++toDirectiveTuple :: DirectiveUsage -> SchemaT c (FieldName, Directive CONST)+toDirectiveTuple (DirectiveUsage x) = do+  insertDirective (deriveDirectiveDefinition x) x+  let directiveName = deriveDirectiveName (Identity x)+  directiveArgs <- resultOr (const $ throwError "TODO: fix me") pure (encodeArguments x)+  pure+    ( directiveName,+      Directive+        { directivePosition = Position 0 0,+          directiveName,+          directiveArgs+        }+    )++insertDirective ::+  forall a c.+  (GQLType a) =>+  (KindedProxy IN a -> SchemaT c (DirectiveDefinition CONST)) ->+  a ->+  SchemaT c ()+insertDirective f _ = insertDirectiveDefinition (deriveFingerprint proxy) f proxy+  where+    proxy = KindedProxy :: KindedProxy IN a++getDirHM :: (Ord k, Hashable k, Empty a) => k -> HashMap k a -> a+getDirHM name xs = fromMaybe empty $ name `HM.lookup` xs++deriveFieldDirectives :: GQLType a => f a -> FieldName -> SchemaT c (Directives CONST)+deriveFieldDirectives proxy name = deriveDirectiveUsages $ getFieldDirectiveUsages name proxy++getEnumDirectiveUsages :: GQLType a => f a -> TypeName -> [DirectiveUsage]+getEnumDirectiveUsages proxy name = getDirHM name $ enumValueDirectives $ directives proxy++getFieldDirectiveUsages :: GQLType a => FieldName -> f a -> [DirectiveUsage]+getFieldDirectiveUsages name proxy = getDirHM name $ fieldDirectives $ directives proxy++deriveEnumDirectives :: GQLType a => f a -> TypeName -> SchemaT c (Directives CONST)+deriveEnumDirectives proxy name = deriveDirectiveUsages $ getEnumDirectiveUsages proxy name++visitEnumValueDescription :: GQLType a => f a -> TypeName -> Maybe Description -> Maybe Description+visitEnumValueDescription proxy name desc = foldr applyEnumDescription desc (getEnumDirectiveUsages proxy name)++visitEnumName :: GQLType a => f a -> TypeName -> TypeName+visitEnumName proxy name = foldr applyEnumName name (getEnumDirectiveUsages proxy name)++visitFieldDescription :: GQLType a => f a -> FieldName -> Maybe Description -> Maybe Description+visitFieldDescription proxy name desc = foldr applyFieldDescription desc (getFieldDirectiveUsages name proxy)++visitFieldName :: GQLType a => f a -> FieldName -> FieldName+visitFieldName proxy name = foldr applyFieldName name (getFieldDirectiveUsages name proxy)++visitTypeDescription :: GQLType a => f a -> Maybe Description -> Maybe Description+visitTypeDescription proxy desc = foldr applyTypeDescription desc (typeDirectives $ directives proxy)++toFieldRes :: GQLType a => f a -> FieldRep (m v) -> (FieldName, m v)+toFieldRes proxy FieldRep {..} = (visitFieldName proxy fieldSelector, fieldValue)
+ src/Data/Morpheus/Server/Deriving/Schema/Enum.hs view
@@ -0,0 +1,62 @@+{-# LANGUAGE GADTs #-}+{-# LANGUAGE RecordWildCards #-}++module Data.Morpheus.Server.Deriving.Schema.Enum+  ( buildEnumTypeContent,+    defineEnumUnit,+  )+where++import Data.Morpheus.Server.Deriving.Schema.Directive+  ( deriveEnumDirectives,+    visitEnumName,+    visitEnumValueDescription,+  )+import Data.Morpheus.Server.Deriving.Schema.Internal+  ( lookupDescription,+  )+import Data.Morpheus.Server.Deriving.Utils.Kinded+  ( KindedType (..),+  )+import Data.Morpheus.Server.Types.GQLType+  ( GQLType,+  )+import Data.Morpheus.Server.Types.SchemaT+  ( SchemaT,+    insertType,+  )+import Data.Morpheus.Types.Internal.AST+  ( CONST,+    DataEnumValue (..),+    LEAF,+    TRUE,+    TypeContent (..),+    TypeDefinition,+    TypeName,+    mkEnumContent,+    mkType,+    unitTypeName,+    unpackName,+  )++buildEnumTypeContent :: GQLType a => KindedType kind a -> [TypeName] -> SchemaT c (TypeContent TRUE kind CONST)+buildEnumTypeContent p@InputType enumCons = DataEnum <$> traverse (mkEnumValue p) enumCons+buildEnumTypeContent p@OutputType enumCons = DataEnum <$> traverse (mkEnumValue p) enumCons++mkEnumValue :: GQLType a => f a -> TypeName -> SchemaT c (DataEnumValue CONST)+mkEnumValue proxy enumName = do+  enumDirectives <- deriveEnumDirectives proxy enumName+  let desc = lookupDescription proxy (unpackName enumName)+  pure+    DataEnumValue+      { enumName = visitEnumName proxy enumName,+        enumDescription = visitEnumValueDescription proxy enumName desc,+        ..+      }++defineEnumUnit :: SchemaT cat ()+defineEnumUnit =+  insertType+    ( mkType unitTypeName (mkEnumContent [unitTypeName]) ::+        TypeDefinition LEAF CONST+    )
+ src/Data/Morpheus/Server/Deriving/Schema/Internal.hs view
@@ -0,0 +1,75 @@+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DefaultSignatures #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE StandaloneDeriving #-}+{-# LANGUAGE TemplateHaskellQuotes #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE NoImplicitPrelude #-}++module Data.Morpheus.Server.Deriving.Schema.Internal+  ( KindedType (..),+    TyContentM,+    TyContent,+    fromSchema,+    lookupDescription,+    lookupFieldContent,+  )+where++-- MORPHEUS++import qualified Data.Map as M+import Data.Morpheus.Internal.Ext+  ( GQLResult,+    Result (Failure, Success, errors),+  )+import Data.Morpheus.Server.Deriving.Utils.Kinded+  ( KindedType (..),+  )+import Data.Morpheus.Server.Types.GQLType+  ( GQLType (..),+  )+import Data.Morpheus.Server.Types.SchemaT+  ( SchemaT,+  )+import Data.Morpheus.Types.Internal.AST+  ( CONST,+    Description,+    FieldContent (..),+    Schema (..),+    TRUE,+    VALID,+  )+import Language.Haskell.TH (Exp, Q)+import Relude hiding (empty)++lookupDescription :: GQLType a => f a -> Text -> Maybe Description+lookupDescription proxy name = name `M.lookup` getDescriptions proxy++lookupFieldContent ::+  GQLType a =>+  KindedType kind a ->+  Text ->+  Maybe (FieldContent TRUE kind CONST)+lookupFieldContent proxy@InputType key = DefaultInputValue <$> key `M.lookup` defaultValues proxy+lookupFieldContent OutputType _ = Nothing++fromSchema :: GQLResult (Schema VALID) -> Q Exp+fromSchema Success {} = [|()|]+fromSchema Failure {errors} = fail (show errors)++type TyContentM kind = SchemaT kind (TyContent kind)++type TyContent kind = Maybe (FieldContent TRUE kind CONST)
+ src/Data/Morpheus/Server/Deriving/Schema/Object.hs view
@@ -0,0 +1,144 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE RecordWildCards #-}++module Data.Morpheus.Server.Deriving.Schema.Object+  ( asObjectType,+    withObject,+    buildObjectTypeContent,+    defineObjectType,+  )+where++import Control.Monad.Except (throwError)+import Data.Morpheus.Internal.Utils+  ( empty,+    singleton,+  )+import Data.Morpheus.Server.Deriving.Schema.Directive+  ( deriveFieldDirectives,+    visitFieldDescription,+    visitFieldName,+  )+import Data.Morpheus.Server.Deriving.Schema.Enum (defineEnumUnit)+import Data.Morpheus.Server.Deriving.Schema.Internal+  ( lookupDescription,+    lookupFieldContent,+  )+import Data.Morpheus.Server.Deriving.Utils+  ( ConsRep (..),+    FieldRep (..),+  )+import Data.Morpheus.Server.Deriving.Utils.Kinded+  ( CategoryValue (..),+    KindedType (..),+    outputType,+  )+import Data.Morpheus.Server.Types.GQLType+  ( GQLType,+    deriveTypename,+  )+import Data.Morpheus.Server.Types.SchemaT+  ( SchemaT,+    insertType,+  )+import Data.Morpheus.Types.Internal.AST+  ( CONST,+    FieldContent (..),+    FieldDefinition (..),+    FieldsDefinition,+    OBJECT,+    OUT,+    TRUE,+    TypeCategory,+    TypeContent (..),+    TypeDefinition,+    mkField,+    mkType,+    mkTypeRef,+    msg,+    unitFieldName,+    unitTypeName,+    unpackName,+    unsafeFromFields,+  )+import Relude hiding (empty)++defineObjectType ::+  KindedType kind a ->+  ConsRep (Maybe (FieldContent TRUE kind CONST)) ->+  SchemaT cat ()+defineObjectType proxy ConsRep {consName, consFields} = insertType . mkType consName . mkObjectTypeContent proxy =<< fields+  where+    fields+      | null consFields = defineEnumUnit $> singleton unitFieldName mkFieldUnit+      | otherwise = pure $ unsafeFromFields $ map repToFieldDefinition consFields++mkFieldUnit :: FieldDefinition cat s+mkFieldUnit = mkField Nothing unitFieldName (mkTypeRef unitTypeName)++buildObjectTypeContent ::+  GQLType a =>+  KindedType cat a ->+  [FieldRep (Maybe (FieldContent TRUE cat CONST))] ->+  SchemaT c (TypeContent TRUE cat CONST)+buildObjectTypeContent scope consFields = do+  xs <- traverse (setGQLTypeProps scope . repToFieldDefinition) consFields+  pure $ mkObjectTypeContent scope $ unsafeFromFields xs++repToFieldDefinition ::+  FieldRep (Maybe (FieldContent TRUE kind CONST)) ->+  FieldDefinition kind CONST+repToFieldDefinition+  FieldRep+    { fieldSelector = fieldName,+      fieldTypeRef = fieldType,+      fieldValue+    } =+    FieldDefinition+      { fieldDescription = mempty,+        fieldDirectives = empty,+        fieldContent = fieldValue,+        ..+      }++asObjectType ::+  (GQLType a) =>+  (f a -> SchemaT kind (FieldsDefinition OUT CONST)) ->+  f a ->+  SchemaT kind (TypeDefinition OBJECT CONST)+asObjectType f proxy =+  mkType+    (deriveTypename (outputType proxy))+    . DataObject []+    <$> f proxy++withObject :: (GQLType a, CategoryValue c) => KindedType c a -> TypeContent TRUE any s -> SchemaT c (FieldsDefinition c s)+withObject InputType DataInputObject {inputObjectFields} = pure inputObjectFields+withObject OutputType DataObject {objectFields} = pure objectFields+withObject x _ = failureOnlyObject x++failureOnlyObject :: forall (c :: TypeCategory) a b. (GQLType a, CategoryValue c) => KindedType c a -> SchemaT c b+failureOnlyObject proxy = throwError $ msg (deriveTypename proxy) <> " should have only one nonempty constructor"++mkObjectTypeContent :: KindedType kind a -> FieldsDefinition kind CONST -> TypeContent TRUE kind CONST+mkObjectTypeContent InputType = DataInputObject+mkObjectTypeContent OutputType = DataObject []++setGQLTypeProps :: GQLType a => KindedType kind a -> FieldDefinition kind CONST -> SchemaT c (FieldDefinition kind CONST)+setGQLTypeProps proxy FieldDefinition {..} = do+  dirs <- deriveFieldDirectives proxy fieldName+  pure+    FieldDefinition+      { fieldName = visitFieldName proxy fieldName,+        fieldDescription = visitFieldDescription proxy fieldName (lookupDescription proxy key),+        fieldContent = lookupFieldContent proxy key <|> fieldContent,+        fieldDirectives = dirs,+        ..+      }+  where+    key = unpackName fieldName
+ src/Data/Morpheus/Server/Deriving/Schema/TypeContent.hs view
@@ -0,0 +1,89 @@+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE RankNTypes #-}++module Data.Morpheus.Server.Deriving.Schema.TypeContent+  ( buildTypeContent,+    insertTypeContent,+    deriveTypeContentWith,+  )+where++import Data.Morpheus.Server.Deriving.Schema.Directive (deriveTypeDirectives, visitTypeDescription)+import Data.Morpheus.Server.Deriving.Schema.Enum+  ( buildEnumTypeContent,+  )+import Data.Morpheus.Server.Deriving.Schema.Internal+  ( KindedType (..),+    TyContent,+  )+import Data.Morpheus.Server.Deriving.Schema.Object+  ( buildObjectTypeContent,+  )+import Data.Morpheus.Server.Deriving.Schema.Union (buildUnionTypeContent)+import Data.Morpheus.Server.Deriving.Utils+  ( ConsRep (..),+    DeriveTypeOptions,+    DeriveWith,+    deriveTypeWith,+    isEmptyConstraint,+    unpackMonad,+  )+import Data.Morpheus.Server.Deriving.Utils.Kinded+  ( CategoryValue (..),+  )+import Data.Morpheus.Server.Types.GQLType+  ( GQLType (..),+    deriveFingerprint,+    deriveTypename,+  )+import Data.Morpheus.Server.Types.SchemaT+  ( SchemaT,+    updateSchema,+  )+import Data.Morpheus.Types.Internal.AST+import GHC.Generics (Rep)++buildTypeContent ::+  (GQLType a, CategoryValue kind) =>+  KindedType kind a ->+  [ConsRep (TyContent kind)] ->+  SchemaT kind (TypeContent TRUE kind CONST)+buildTypeContent scope cons | all isEmptyConstraint cons = buildEnumTypeContent scope (consName <$> cons)+buildTypeContent scope [ConsRep {consFields}] = buildObjectTypeContent scope consFields+buildTypeContent scope cons = buildUnionTypeContent scope cons++insertTypeContent ::+  (GQLType a, CategoryValue kind) =>+  (f kind a -> SchemaT c (TypeContent TRUE kind CONST)) ->+  f kind a ->+  SchemaT c ()+insertTypeContent f proxy =+  updateSchema+    (deriveFingerprint proxy)+    deriveD+    proxy+  where+    deriveD x = do+      content <- f x+      dirs <- deriveTypeDirectives proxy+      pure $+        TypeDefinition+          (visitTypeDescription proxy $ description proxy)+          (deriveTypename proxy)+          dirs+          content++deriveTypeContentWith ::+  ( CategoryValue kind,+    DeriveWith c (SchemaT kind (TyContent kind)) (Rep a),+    GQLType a+  ) =>+  DeriveTypeOptions kind c (SchemaT kind (TyContent kind)) ->+  KindedType kind a ->+  SchemaT kind (TypeContent TRUE kind CONST)+deriveTypeContentWith x kindedProxy =+  unpackMonad+    ( deriveTypeWith x kindedProxy+    )+    >>= buildTypeContent kindedProxy
+ src/Data/Morpheus/Server/Deriving/Schema/Union.hs view
@@ -0,0 +1,83 @@+{-# LANGUAGE GADTs #-}++module Data.Morpheus.Server.Deriving.Schema.Union+  ( buildUnionTypeContent,+  )+where++import Data.List (partition)+import Data.Morpheus.Internal.Utils (fromElems)+import Data.Morpheus.Server.Deriving.Schema.Enum+  ( defineEnumUnit,+  )+import Data.Morpheus.Server.Deriving.Schema.Object+  ( defineObjectType,+  )+import Data.Morpheus.Server.Deriving.Utils+  ( ConsRep (..),+    fieldTypeName,+    isEmptyConstraint,+    isUnionRef,+  )+import Data.Morpheus.Server.Deriving.Utils.Kinded+  ( CategoryValue,+    KindedType (..),+  )+import Data.Morpheus.Server.Types.GQLType (GQLType, deriveTypename)+import Data.Morpheus.Server.Types.SchemaT+  ( SchemaT,+  )+import Data.Morpheus.Types.Internal.AST+  ( CONST,+    FieldContent (..),+    IN,+    TRUE,+    TypeContent (..),+    TypeName,+    UnionMember (..),+    mkNullaryMember,+    mkUnionMember,+  )+import Relude++buildUnionTypeContent ::+  ( GQLType a,+    CategoryValue kind+  ) =>+  KindedType kind a ->+  [ConsRep (Maybe (FieldContent TRUE kind CONST))] ->+  SchemaT c (TypeContent TRUE kind CONST)+buildUnionTypeContent scope cons = mkUnionType scope unionRef unionCons+  where+    unionRef = fieldTypeName <$> concatMap consFields unionRefRep+    (unionRefRep, unionCons) = partition (isUnionRef (deriveTypename scope)) cons++mkUnionType ::+  GQLType a =>+  KindedType kind a ->+  [TypeName] ->+  [ConsRep (Maybe (FieldContent TRUE kind CONST))] ->+  SchemaT c (TypeContent TRUE kind CONST)+mkUnionType p@InputType unionRef unionCons = DataInputUnion <$> (typeMembers >>= fromElems)+  where+    (nullaryCons, cons) = partition isEmptyConstraint unionCons+    nullaryMembers :: [UnionMember IN CONST]+    nullaryMembers = mkNullaryMember . consName <$> nullaryCons+    defineEnumEmpty+      | null nullaryCons = pure ()+      | otherwise = defineEnumUnit+    typeMembers =+      (<> nullaryMembers) . withRefs+        <$> ( defineEnumEmpty *> buildUnions p cons+            )+      where+        withRefs = fmap mkUnionMember . (unionRef <>)+mkUnionType p@OutputType unionRef unionCons =+  DataUnion <$> (buildUnions p unionCons >>= fromElems . map mkUnionMember . (unionRef <>))++buildUnions ::+  KindedType kind a ->+  [ConsRep (Maybe (FieldContent TRUE kind CONST))] ->+  SchemaT c [TypeName]+buildUnions proxy cons =+  traverse_ (defineObjectType proxy) cons $> fmap consName cons
+ src/Data/Morpheus/Server/Deriving/Utils.hs view
@@ -0,0 +1,40 @@+{-# LANGUAGE NoImplicitPrelude #-}++module Data.Morpheus.Server.Deriving.Utils+  ( conNameProxy,+    isRecordProxy,+    selNameProxy,+    ConsRep (..),+    FieldRep (..),+    isEmptyConstraint,+    isUnionRef,+    fieldTypeName,+    unpackMonad,+    symbolName,+    DataType (..),+    DeriveWith (..),+    DeriveTypeOptions (..),+    deriveTypeWith,+  )+where++import Data.Morpheus.Server.Deriving.Utils.DeriveGType+  ( DeriveTypeOptions (..),+    DeriveWith (..),+    deriveTypeWith,+  )+import Data.Morpheus.Server.Deriving.Utils.Proxy+  ( conNameProxy,+    isRecordProxy,+    selNameProxy,+    symbolName,+  )+import Data.Morpheus.Server.Deriving.Utils.Types+  ( ConsRep (..),+    DataType (..),+    FieldRep (..),+    fieldTypeName,+    isEmptyConstraint,+    isUnionRef,+    unpackMonad,+  )
+ src/Data/Morpheus/Server/Deriving/Utils/Decode.hs view
@@ -0,0 +1,193 @@+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE NoImplicitPrelude #-}++module Data.Morpheus.Server.Deriving.Utils.Decode+  ( withInputObject,+    withEnum,+    withInputUnion,+    decodeFieldWith,+    withScalar,+    handleEither,+    getFieldName,+    DecoderT,+    setVariantRef,+    Context (..),+    getUnionInfos,+    DescribeCons,+    DescribeFields (countFields),+  )+where++import Control.Monad.Except (MonadError (throwError))+import Data.Morpheus.App.Internal.Resolving (ResolverState)+import Data.Morpheus.Internal.Utils+  ( selectOr,+  )+import Data.Morpheus.Server.Deriving.Utils (conNameProxy)+import Data.Morpheus.Server.Deriving.Utils.Kinded (KindedProxy (..))+import Data.Morpheus.Server.Types.GQLType+  ( GQLType,+    deriveTypename,+  )+import Data.Morpheus.Server.Types.Internal+import Data.Morpheus.Types.GQLScalar+  ( toScalar,+  )+import Data.Morpheus.Types.Internal.AST+  ( FieldName,+    GQLError,+    IN,+    Msg (msg),+    ObjectEntry (..),+    ScalarValue,+    Token,+    TypeName,+    VALID,+    ValidObject,+    ValidValue,+    Value (..),+    getInputUnionValue,+    internal,+  )+import GHC.Generics+import Relude++withInputObject ::+  MonadError GQLError m =>+  (ValidObject -> m a) ->+  ValidValue ->+  m a+withInputObject f (Object object) = f object+withInputObject _ isType = throwError (typeMismatch "InputObject" isType)++-- | Useful for more restrictive instances of lists (non empty, size indexed etc)+withEnum :: MonadError GQLError m => (TypeName -> m a) -> Value VALID -> m a+withEnum decode (Enum value) = decode value+withEnum _ isType = throwError (typeMismatch "Enum" isType)++withInputUnion ::+  (MonadError GQLError m, Monad m) =>+  (TypeName -> ValidObject -> ValidObject -> m a) ->+  ValidObject ->+  m a+withInputUnion decoder unions =+  either onFail onSuccess (getInputUnionValue unions)+  where+    onSuccess (name, value) = withInputObject (decoder name unions) value+    onFail = throwError . internal . msg++withScalar ::+  (Applicative m, MonadError GQLError m) =>+  TypeName ->+  (ScalarValue -> Either Token a) ->+  Value VALID ->+  m a+withScalar typename decodeScalar value = case toScalar value >>= decodeScalar of+  Right scalar -> pure scalar+  Left message ->+    throwError+      ( typeMismatch+          ("SCALAR(" <> msg typename <> ")" <> msg message)+          value+      )++decodeFieldWith :: (Value VALID -> m a) -> FieldName -> ValidObject -> m a+decodeFieldWith decoder = selectOr (decoder Null) (decoder . entryValue)++handleEither :: MonadError GQLError m => Either GQLError a -> m a+handleEither = either throwError pure++-- if value is already validated but value has different type+typeMismatch :: GQLError -> Value s -> GQLError+typeMismatch text jsType =+  internal $+    "Type mismatch! expected:"+      <> text+      <> ", got: "+      <> msg jsType++getFieldName :: FieldName -> Int -> FieldName+getFieldName "" index = "_" <> show index+getFieldName label _ = label++data VariantKind = InlineVariant | VariantRef deriving (Eq, Ord)++data Info = Info+  { kind :: VariantKind,+    tagName :: [TypeName]+  }++instance Semigroup Info where+  Info VariantRef t1 <> Info _ t2 = Info VariantRef (t1 <> t2)+  Info _ t1 <> Info VariantRef t2 = Info VariantRef (t1 <> t2)+  Info InlineVariant t1 <> Info InlineVariant t2 = Info InlineVariant (t1 <> t2)++data Context = Context+  { isVariantRef :: Bool,+    typeName :: TypeName,+    options :: GQLTypeOptions,+    enumVisitor :: TypeName -> TypeName,+    fieldVisitor :: FieldName -> FieldName+  }++type DecoderT = ReaderT Context ResolverState++setVariantRef :: Bool -> DecoderT a -> DecoderT a+setVariantRef isVariantRef = local (\ctx -> ctx {isVariantRef})++class DescribeCons (f :: Type -> Type) where+  tags :: Proxy f -> Context -> Info++instance (Datatype d, DescribeCons f) => DescribeCons (M1 D d f) where+  tags _ = tags (Proxy @f)++instance (DescribeCons a, DescribeCons b) => DescribeCons (a :+: b) where+  tags _ = tags (Proxy @a) <> tags (Proxy @b)++instance (Constructor c, DescribeFields a) => DescribeCons (M1 C c a) where+  tags _ Context {typeName, options} = getTag (refType (Proxy @a))+    where+      getTag (Just memberRef)+        | isUnionRef memberRef = Info {kind = VariantRef, tagName = [memberRef]}+        | otherwise = Info {kind = InlineVariant, tagName = [consName]}+      getTag Nothing = Info {kind = InlineVariant, tagName = [consName]}+      --------+      consName = conNameProxy options (Proxy @c)+      ----------+      isUnionRef x = typeName <> x == consName++getUnionInfos ::+  forall f a b.+  (DescribeCons a, DescribeCons b) =>+  f (a :+: b) ->+  DecoderT (Bool, ([TypeName], [TypeName]))+getUnionInfos _ = do+  context <- ask+  let l = tags (Proxy @a) context+  let r = tags (Proxy @b) context+  let k = kind (l <> r)+  pure (k == VariantRef, (tagName l, tagName r))++class DescribeFields (f :: Type -> Type) where+  refType :: Proxy f -> Maybe TypeName+  countFields :: Proxy f -> Int++instance (DescribeFields f, DescribeFields g) => DescribeFields (f :*: g) where+  refType _ = Nothing+  countFields _ = countFields (Proxy @f) + countFields (Proxy @g)++instance (Selector s, GQLType a) => DescribeFields (M1 S s (K1 i a)) where+  refType _ = Just $ deriveTypename (KindedProxy :: KindedProxy IN a)+  countFields _ = 1++instance DescribeFields U1 where+  refType _ = Nothing+  countFields _ = 0
+ src/Data/Morpheus/Server/Deriving/Utils/DeriveGType.hs view
@@ -0,0 +1,158 @@+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE PolyKinds #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE NoImplicitPrelude #-}++module Data.Morpheus.Server.Deriving.Utils.DeriveGType+  ( DeriveWith (..),+    DeriveValueOptions (..),+    DeriveTypeOptions (..),+    deriveValue,+    deriveTypeWith,+  )+where++import Data.Morpheus.Server.Deriving.Utils.Kinded+  ( CategoryValue (..),+  )+import Data.Morpheus.Server.Deriving.Utils.Proxy+  ( conNameProxy,+    isRecordProxy,+    selNameProxy,+  )+import Data.Morpheus.Server.Deriving.Utils.Types+import Data.Morpheus.Server.Types.Internal+  ( GQLTypeOptions (..),+    TypeData (..),+  )+import Data.Morpheus.Types.Internal.AST+  ( TypeName,+    TypeRef (..),+  )+import GHC.Generics+  ( C,+    Constructor,+    D,+    Datatype,+    Generic (..),+    K1 (..),+    M1 (..),+    Meta,+    Rec0,+    S,+    Selector,+    U1 (..),+    (:*:) (..),+    (:+:) (..),+  )+import Relude hiding (undefined)++data DeriveValueOptions kind c v = DeriveValueOptions+  { __valueTypeName :: TypeName,+    __valueGQLOptions :: GQLTypeOptions,+    __valueApply :: forall a. c a => a -> v,+    __valueGetType :: forall f a. c a => f a -> TypeData+  }++data DeriveTypeOptions kind c v = DeriveTypeDefinitionOptions+  { __typeGQLOptions :: GQLTypeOptions,+    __typeApply :: forall f a. c a => f a -> v,+    __typeGetType :: forall f a. c a => f a -> TypeData+  }++deriveValue ::+  (CategoryValue kind, Generic a, DeriveWith constraint value (Rep a)) =>+  DeriveValueOptions kind constraint value ->+  a ->+  DataType value+deriveValue options = deriveTypeValue options . from++deriveTypeWith ::+  forall kind c v kinded a.+  (CategoryValue kind, DeriveWith c v (Rep a)) =>+  DeriveTypeOptions kind c v ->+  kinded kind a ->+  [ConsRep v]+deriveTypeWith options _ = deriveTypeDefinition options (Proxy @(Rep a))++--  GENERIC UNION+class DeriveWith (c :: Type -> Constraint) (v :: Type) f where+  deriveTypeValue :: CategoryValue kind => DeriveValueOptions kind c v -> f a -> DataType v+  deriveTypeDefinition :: CategoryValue kind => DeriveTypeOptions kind c v -> proxy f -> [ConsRep v]++instance (Datatype d, DeriveWith c v f) => DeriveWith c v (M1 D d f) where+  deriveTypeValue options (M1 src) = (deriveTypeValue options src) {dataTypeName = __valueTypeName options}+  deriveTypeDefinition options _ = deriveTypeDefinition options (Proxy @f)++-- | recursion for Object types, both of them : 'INPUT_OBJECT' and 'OBJECT'+instance (DeriveWith c v a, DeriveWith c v b) => DeriveWith c v (a :+: b) where+  deriveTypeValue f (L1 x) = (deriveTypeValue f x) {tyIsUnion = True}+  deriveTypeValue f (R1 x) = (deriveTypeValue f x) {tyIsUnion = True}+  deriveTypeDefinition options _ = deriveTypeDefinition options (Proxy @a) <> deriveTypeDefinition options (Proxy @b)++instance (DeriveFieldRep con v f, Constructor c) => DeriveWith con v (M1 C c f) where+  deriveTypeValue options (M1 src) =+    DataType+      { dataTypeName = "",+        tyIsUnion = False,+        tyCons = deriveConsRep (__valueGQLOptions options) (Proxy @c) (toFieldRep options src)+      }+  deriveTypeDefinition options _ = [deriveConsRep (__typeGQLOptions options) (Proxy @c) (conRep options (Proxy @f))]++deriveConsRep ::+  Constructor (c :: Meta) =>+  GQLTypeOptions ->+  f c ->+  [FieldRep v] ->+  ConsRep v+deriveConsRep opt proxy fields =+  ConsRep+    { consName = conNameProxy opt proxy,+      consFields+    }+  where+    consFields+      | isRecordProxy proxy = fields+      | otherwise = enumerate fields++class DeriveFieldRep (c :: Type -> Constraint) (v :: Type) f where+  toFieldRep :: CategoryValue kind => DeriveValueOptions kind c v -> f a -> [FieldRep v]+  conRep :: CategoryValue kind => DeriveTypeOptions kind c v -> proxy f -> [FieldRep v]++instance (DeriveFieldRep c v a, DeriveFieldRep c v b) => DeriveFieldRep c v (a :*: b) where+  toFieldRep options (a :*: b) = toFieldRep options a <> toFieldRep options b+  conRep options _ = conRep options (Proxy @a) <> conRep options (Proxy @b)++instance (Selector s, c a) => DeriveFieldRep c v (M1 S s (Rec0 a)) where+  toFieldRep DeriveValueOptions {..} (M1 (K1 src)) =+    [ FieldRep+        { fieldSelector = selNameProxy __valueGQLOptions (Proxy @s),+          fieldTypeRef = TypeRef gqlTypeName gqlWrappers,+          fieldValue = __valueApply src+        }+    ]+    where+      TypeData {gqlTypeName, gqlWrappers} = __valueGetType (Proxy @a)+  conRep DeriveTypeDefinitionOptions {..} _ =+    [ FieldRep+        { fieldSelector = selNameProxy __typeGQLOptions (Proxy @s),+          fieldTypeRef = TypeRef gqlTypeName gqlWrappers,+          fieldValue = __typeApply (Proxy @a)+        }+    ]+    where+      TypeData {gqlTypeName, gqlWrappers} = __typeGetType (Proxy @a)++instance DeriveFieldRep c v U1 where+  toFieldRep _ _ = []+  conRep _ _ = []
+ src/Data/Morpheus/Server/Deriving/Utils/GTraversable.hs view
@@ -0,0 +1,115 @@+{-# LANGUAGE AllowAmbiguousTypes #-}+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE PolyKinds #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE UndecidableSuperClasses #-}+{-# LANGUAGE NoImplicitPrelude #-}++module Data.Morpheus.Server.Deriving.Utils.GTraversable where++import qualified Data.Map as M+import Data.Morpheus.Server.Deriving.Utils.Kinded+import Data.Morpheus.Server.NamedResolvers (NamedResolverT)+import Data.Morpheus.Server.Types.GQLType (GQLType (KIND, __type))+import Data.Morpheus.Server.Types.Internal+  ( TypeData (gqlFingerprint),+  )+import Data.Morpheus.Server.Types.Kind+import Data.Morpheus.Server.Types.SchemaT (TypeFingerprint)+import Data.Morpheus.Types.Internal.AST+import GHC.Generics+import Relude hiding (Undefined)++traverseTypes ::+  (GFmap (ScanConstraint c) (KIND a) a, c (KIND a) a, GQLType a) =>+  Mappable c v KindedProxy ->+  Proxy a ->+  Map TypeFingerprint v+traverseTypes f = runMappable (scanner f mempty) . withDerivable++class+  (GFmap (ScanConstraint c) (KIND a) a, c (KIND a) a) =>+  ScanConstraint+    (c :: DerivingKind -> Type -> Constraint)+    (k :: DerivingKind)+    (a :: Type)++instance (GFmap (ScanConstraint c) (KIND a) a, c (KIND a) a) => ScanConstraint c k a++scanner ::+  Mappable c v KindedProxy ->+  Map TypeFingerprint v ->+  Mappable (ScanConstraint c) (Map TypeFingerprint v) KindedProxy+scanner c@(Mappable f) lib =+  Mappable+    ( \proxy -> do+        let typeInfo = __type proxy OUT+        let fingerprint = gqlFingerprint typeInfo+        if M.member fingerprint lib+          then lib+          else do+            let newLib = M.insert fingerprint (f proxy) lib+            gfmap (scanner c newLib) proxy+    )++withDerivable :: proxy a -> KindedProxy (KIND a) a+withDerivable _ = KindedProxy++newtype Mappable (c :: DerivingKind -> Type -> Constraint) (v :: Type) (f :: DerivingKind -> Type -> Type) = Mappable+  { runMappable :: forall a. (GQLType a, c (KIND a) a) => KindedProxy (KIND a) a -> v+  }++-- Map+class GFmap (c :: DerivingKind -> Type -> Constraint) (t :: DerivingKind) a where+  gfmap :: (Monoid v, Semigroup v) => Mappable c v KindedProxy -> kinded t a -> v++instance (GQLType a, c (KIND a) a) => GFmap c SCALAR a where+  gfmap (Mappable f) _ = f (KindedProxy :: KindedProxy (KIND a) a)++instance (GQLType a, c (KIND a) a, GFunctor c (Rep a)) => GFmap c TYPE a where+  gfmap f@(Mappable fx) _ = fx (KindedProxy :: KindedProxy (KIND a) a) <> genericMap f (Proxy @(Rep a))++instance GFmap c (KIND a) a => GFmap c WRAPPER (f a) where+  gfmap f _ = gfmap f (KindedProxy :: KindedProxy (KIND a) a)++instance GFmap c (KIND a) a => GFmap c CUSTOM (input -> a) where+  gfmap f _ = gfmap f (KindedProxy :: KindedProxy (KIND a) a)++instance GFmap c (KIND a) a => GFmap c CUSTOM (NamedResolverT m a) where+  gfmap f _ = gfmap f (KindedProxy :: KindedProxy (KIND a) a)++--+--+-- GFunctor+--+--+class GFunctor (c :: DerivingKind -> Type -> Constraint) a where+  genericMap :: (Monoid v, Semigroup v) => Mappable c v p -> proxy a -> v++instance (Datatype d, GFunctor c a) => GFunctor c (M1 D d a) where+  genericMap fun _ = genericMap fun (Proxy @a)++instance (GFunctor con a) => GFunctor con (M1 C c a) where+  genericMap f _ = genericMap f (Proxy @a)++instance (GFunctor c a, GFunctor c b) => GFunctor c (a :+: b) where+  genericMap fun _ = genericMap fun (Proxy @a) <> genericMap fun (Proxy @b)++instance (GFunctor c a, GFunctor c b) => GFunctor c (a :*: b) where+  genericMap fun _ = genericMap fun (Proxy @a) <> genericMap fun (Proxy @b)++instance (GQLType a, c (KIND a) a) => GFunctor c (M1 S s (K1 x a)) where+  genericMap (Mappable f) _ = f (KindedProxy :: KindedProxy (KIND a) a)++instance GFunctor c U1 where+  genericMap _ _ = mempty
+ src/Data/Morpheus/Server/Deriving/Utils/Kinded.hs view
@@ -0,0 +1,69 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE PolyKinds #-}+{-# LANGUAGE StandaloneDeriving #-}+{-# LANGUAGE NoImplicitPrelude #-}++module Data.Morpheus.Server.Deriving.Utils.Kinded+  ( KindedProxy (..),+    setType,+    setKind,+    kinded,+    KindedType (..),+    inputType,+    outputType,+    CategoryValue (..),+  )+where++import Data.Morpheus.Types.Internal.AST+  ( IN,+    LEAF,+    OUT,+    TypeCategory (..),+  )+import Prelude (Show)++class CategoryValue (c :: TypeCategory) where+  categoryValue :: f c -> TypeCategory++instance CategoryValue OUT where+  categoryValue _ = OUT++instance CategoryValue IN where+  categoryValue _ = IN++instance CategoryValue LEAF where+  categoryValue _ = LEAF++-- | context , like Proxy with multiple parameters+-- * 'kind': object, scalar, enum ...+-- * 'a': actual gql type+data KindedProxy k a+  = KindedProxy++setType :: f a -> kinded (k :: t) a' -> KindedProxy k a+setType _ _ = KindedProxy++setKind :: f k -> kinded (k' :: t) a -> KindedProxy k a+setKind _ _ = KindedProxy++kinded :: f k -> f' a -> KindedProxy k a+kinded _ _ = KindedProxy++data KindedType (cat :: TypeCategory) a where+  InputType :: KindedType IN a+  OutputType :: KindedType OUT a++deriving instance Show (KindedType cat a)++-- converts:+--   f a -> KindedType IN a+-- or+--  f k a -> KindedType IN a+inputType :: f a -> KindedType IN a+inputType _ = InputType++outputType :: f a -> KindedType OUT a+outputType _ = OutputType
+ src/Data/Morpheus/Server/Deriving/Utils/Proxy.hs view
@@ -0,0 +1,75 @@+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE PolyKinds #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE NoImplicitPrelude #-}++module Data.Morpheus.Server.Deriving.Utils.Proxy+  ( conNameProxy,+    isRecordProxy,+    selNameProxy,+    symbolName,+    ContextValue (..),+  )+where++import Data.Morpheus.Server.Types.Internal+  ( GQLTypeOptions (..),+  )+import Data.Morpheus.Server.Types.Kind (DerivingKind)+import Data.Morpheus.Types.Internal.AST+  ( FieldName,+    TypeName,+    packName,+  )+import Data.Text+  ( pack,+  )+import qualified Data.Text as T+import GHC.Generics+  ( C,+    Constructor,+    M1 (..),+    Meta,+    S,+    Selector,+    U1 (..),+    conIsRecord,+    conName,+    selName,+  )+import GHC.TypeLits+import Relude hiding (undefined)+import Prelude (undefined)++conNameProxy :: forall f (c :: Meta). Constructor c => GQLTypeOptions -> f c -> TypeName+conNameProxy options _ =+  packName $ pack $ constructorTagModifier options $ conName (undefined :: M1 C c U1 a)++selNameProxy :: forall f (s :: Meta). Selector s => GQLTypeOptions -> f s -> FieldName+selNameProxy options _ =+  fromHaskellName $+    fieldLabelModifier options $+      selName (undefined :: M1 S s f a)++fromHaskellName :: String -> FieldName+fromHaskellName hsName+  | not (null hsName) && (T.last name == '\'') = packName (T.init name)+  | otherwise = packName name+  where+    name = T.pack hsName+{-# INLINE fromHaskellName #-}++isRecordProxy :: forall f (c :: Meta). Constructor c => f c -> Bool+isRecordProxy _ = conIsRecord (undefined :: (M1 C c f a))++symbolName :: KnownSymbol a => f a -> FieldName+symbolName = fromString . symbolVal++newtype ContextValue (kind :: DerivingKind) a = ContextValue+  { unContextValue :: a+  }
+ src/Data/Morpheus/Server/Deriving/Utils/Types.hs view
@@ -0,0 +1,72 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DeriveFunctor #-}+{-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE PolyKinds #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE NoImplicitPrelude #-}++module Data.Morpheus.Server.Deriving.Utils.Types+  ( ConsRep (..),+    FieldRep (..),+    DataType (..),+    enumerate,+    isEmptyConstraint,+    fieldTypeName,+    isUnionRef,+    unpackMonad,+  )+where++import Data.Morpheus.Types.Internal.AST+import qualified Data.Text as T+import Relude++data DataType (v :: Type) = DataType+  { dataTypeName :: TypeName,+    tyIsUnion :: Bool,+    tyCons :: ConsRep v+  }+  deriving (Functor)++data ConsRep (v :: Type) = ConsRep+  { consName :: TypeName,+    consFields :: [FieldRep v]+  }+  deriving (Functor)++data FieldRep (a :: Type) = FieldRep+  { fieldSelector :: FieldName,+    fieldTypeRef :: TypeRef,+    fieldValue :: a+  }+  deriving (Functor)++-- setFieldNames ::  Power Int Text -> Power { _1 :: Int, _2 :: Text }+enumerate :: [FieldRep a] -> [FieldRep a]+enumerate = zipWith setFieldName ([0 ..] :: [Int])+  where+    setFieldName i field = field {fieldSelector = packName $ "_" <> T.pack (show i)}++isEmptyConstraint :: ConsRep a -> Bool+isEmptyConstraint ConsRep {consFields = []} = True+isEmptyConstraint _ = False++fieldTypeName :: FieldRep k -> TypeName+fieldTypeName = typeConName . fieldTypeRef++isUnionRef :: TypeName -> ConsRep k -> Bool+isUnionRef baseName ConsRep {consName, consFields = [fieldRep]} =+  consName == baseName <> fieldTypeName fieldRep+isUnionRef _ _ = False++unpackMonad :: Monad m => [ConsRep (m a)] -> m [ConsRep a]+unpackMonad = traverse unpackMonadFromCons++unpackMonadFromField :: Monad m => FieldRep (m a) -> m (FieldRep a)+unpackMonadFromField FieldRep {..} = do+  cont <- fieldValue+  pure (FieldRep {fieldValue = cont, ..})++unpackMonadFromCons :: Monad m => ConsRep (m a) -> m (ConsRep a)+unpackMonadFromCons ConsRep {..} = ConsRep consName <$> traverse unpackMonadFromField consFields
+ src/Data/Morpheus/Server/NamedResolvers.hs view
@@ -0,0 +1,68 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE NoImplicitPrelude #-}++module Data.Morpheus.Server.NamedResolvers+  ( ResolveNamed (..),+    NamedResolverT (..),+    resolve,+  )+where++import Data.Aeson (ToJSON)+import Data.Morpheus.Types.ID (ID)+import Relude++instance Monad m => ResolveNamed m ID where+  type Dep ID = ID+  resolveNamed = pure++instance Monad m => ResolveNamed m Text where+  type Dep Text = Text+  resolveNamed = pure++class (ToJSON (Dep a)) => ResolveNamed (m :: Type -> Type) a where+  type Dep a :: Type+  resolveNamed :: Monad m => Dep a -> m a++instance (ResolveNamed m a) => ResolveNamed (m :: Type -> Type) (Maybe a) where+  type Dep (Maybe a) = Maybe (Dep a)+  resolveNamed (Just x) = Just <$> resolveNamed x+  resolveNamed Nothing = pure Nothing++instance (ResolveNamed m a) => ResolveNamed (m :: Type -> Type) [a] where+  type Dep [a] = [Dep a]+  resolveNamed = traverse resolveNamed++data NamedResolverT (m :: Type -> Type) a where+  Ref :: ResolveNamed m a => m (Dep a) -> NamedResolverT m a+  Refs :: ResolveNamed m a => m [Dep a] -> NamedResolverT m [a]+  Value :: m a -> NamedResolverT m a++-- RESOLVER TYPES+data RES = VALUE | LIST | REF++type family RES_TYPE a b :: RES where+  RES_TYPE a a = 'VALUE+  RES_TYPE [a] [b] = 'LIST+  RES_TYPE a b = 'REF++resolve :: forall m a b. (ResolveByType (RES_TYPE a b) m a b) => Monad m => m a -> NamedResolverT m b+resolve = resolveByType (Proxy :: Proxy (RES_TYPE a b))++class Dep b ~ a => ResolveByType (k :: RES) m a b where+  resolveByType :: Monad m => f k -> m a -> NamedResolverT m b++instance (ResolveNamed m a, Dep a ~ a) => ResolveByType 'VALUE m a a where+  resolveByType _ = Value++instance (ResolveNamed m b, Dep b ~ a) => ResolveByType 'LIST m [a] [b] where+  resolveByType _ = Refs++instance (ResolveNamed m b, Dep b ~ a) => ResolveByType 'REF m a b where+  resolveByType _ = Ref
+ src/Data/Morpheus/Server/Playground.hs view
@@ -0,0 +1,72 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE NoImplicitPrelude #-}++module Data.Morpheus.Server.Playground+  ( httpPlayground,+  )+where++import Data.ByteString.Lazy.Char8 (ByteString)+import Data.Functor (fmap)+import Data.Semigroup ((<>))+import Prelude+  ( mconcat,+    (.),+  )++link :: ByteString -> ByteString -> ByteString+link rel href = "<link rel=\"" <> rel <> "\"  href=\"" <> href <> "\" />"++meta :: [(ByteString, ByteString)] -> ByteString+meta attr = t "meta" attr []++tag :: ByteString -> [ByteString] -> ByteString+tag tagName = t tagName []++t :: ByteString -> [(ByteString, ByteString)] -> [ByteString] -> ByteString+t tagName attr children =+  "<" <> tagName <> " " <> mconcat (fmap renderAttr attr) <> " >" <> mconcat children <> "</" <> tagName <> ">"+  where+    renderAttr (name, value) = name <> "=\"" <> value <> "\" "++script :: [(ByteString, ByteString)] -> [ByteString] -> ByteString+script = t "script"++html :: [ByteString] -> ByteString+html = docType . t "html" []++docType :: ByteString -> ByteString+docType x = "<!DOCTYPE html>" <> x++httpPlayground :: ByteString+httpPlayground =+  html+    [ tag+        "head"+        [ meta [("charset", "utf-8")],+          meta+            [ ("name", "viewport"),+              ("content", "user-scalable=no, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, minimal-ui")+            ],+          tag "title" ["GraphQL Playground"],+          link "stylesheet" "//cdn.jsdelivr.net/npm/graphql-playground-react/build/static/css/index.css",+          link "shortcut icon" "//cdn.jsdelivr.net/npm/graphql-playground-react/build/favicon.png",+          script+            [("src", "//cdn.jsdelivr.net/npm/graphql-playground-react/build/static/js/middleware.js")]+            []+        ],+      tag+        "body"+        [ t "div" [("id", "root")] [],+          script+            []+            [ "  window.addEventListener('load', (_) => \+              \    GraphQLPlayground.init(document.getElementById('root'), {}) \+              \  );"+            ]+        ]+    ]
+ src/Data/Morpheus/Server/Resolvers.hs view
@@ -0,0 +1,99 @@+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE PolyKinds #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE NoImplicitPrelude #-}++module Data.Morpheus.Server.Resolvers+  ( ResolveNamed (..),+    NamedResolverT (..),+    resolve,+    NamedResolvers (..),+    RootResolver (..),+    defaultRootResolver,+    ResolverO,+    ComposedResolver,+    publish,+    constRes,+    ResolverQ,+    ResolverM,+    ResolverS,+  )+where++import Data.Morpheus.App.Internal.Resolving (PushEvents (pushEvents), Resolver, WithOperation)+import Data.Morpheus.Server.NamedResolvers+import Data.Morpheus.Server.Types.Types+  ( Undefined (..),+  )+import Data.Morpheus.Types.Internal.AST+import Relude hiding (Undefined)++data+  NamedResolvers+    (m :: Type -> Type)+    event+    (qu :: (Type -> Type) -> Type)+    (mu :: (Type -> Type) -> Type)+    (su :: (Type -> Type) -> Type)+  = ( ResolveNamed+        (Resolver QUERY event m)+        (qu (NamedResolverT (Resolver QUERY event m)))+    ) =>+    NamedResolvers++-- | GraphQL Root resolver, also the interpreter generates a GQL schema from it.+--  'queryResolver' is required, 'mutationResolver' and 'subscriptionResolver' are optional,+--  if your schema does not supports __mutation__ or __subscription__ , you can use __()__ for it.+data+  RootResolver+    (m :: Type -> Type)+    event+    (query :: (Type -> Type) -> Type)+    (mutation :: (Type -> Type) -> Type)+    (subscription :: (Type -> Type) -> Type) = RootResolver+  { queryResolver :: query (Resolver QUERY event m),+    mutationResolver :: mutation (Resolver MUTATION event m),+    subscriptionResolver :: subscription (Resolver SUBSCRIPTION event m)+  }++defaultRootResolver :: RootResolver m event Undefined Undefined Undefined+defaultRootResolver =+  RootResolver+    { queryResolver = Undefined False,+      mutationResolver = Undefined False,+      subscriptionResolver = Undefined False+    }++class FlexibleResolver (f :: Type -> Type) (a :: k) where+  type Flexible (m :: Type -> Type) a :: Type+  type Composed (m :: Type -> Type) f a :: Type++instance FlexibleResolver f (a :: Type) where+  type Flexible m a = m a+  type Composed m f a = m (f a)++instance FlexibleResolver f (a :: (Type -> Type) -> Type) where+  type Flexible m a = m (a m)+  type Composed m f a = m (f (a m))++type ComposedResolver o e m f a = Composed (Resolver o e m) f a++type ResolverO o e m a = Flexible (Resolver o e m) a++type ResolverQ e m a = Flexible (Resolver QUERY e m) a++type ResolverM e m a = Flexible (Resolver MUTATION e m) a++type ResolverS e m a = Flexible (Resolver SUBSCRIPTION e m) a++publish :: Monad m => [e] -> Resolver MUTATION e m ()+publish = pushEvents++constRes :: (WithOperation o, Monad m) => b -> a -> Resolver o e m b+constRes = const . pure
+ src/Data/Morpheus/Server/Types.hs view
@@ -0,0 +1,158 @@+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE PolyKinds #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE NoImplicitPrelude #-}++-- | GQL Types+module Data.Morpheus.Server.Types+  ( GQLType+      ( KIND,+        description,+        getDescriptions,+        typeOptions,+        getDirectives,+        defaultValues,+        directives+      ),+    EncodeScalar (..),+    EncodeWrapper (..),+    DecodeScalar (..),+    DecodeWrapper (..),+    GQLRequest (..),+    GQLResponse (..),+    ID (..),+    ScalarValue (..),+    Undefined,+    Resolver,+    QUERY,+    MUTATION,+    SUBSCRIPTION,+    lift,+    WithOperation,+    subscribe,+    unsafeInternalContext,+    ResolverContext (..),+    SubscriptionField,+    App,+    RenderGQL,+    render,+    TypeGuard (..),+    Arg (..),++    -- * GQLType naming configuration+    GQLTypeOptions,+    defaultTypeOptions,+    fieldLabelModifier,+    constructorTagModifier,+    typeNameModifier,++    -- * GQL directives API+    Prefixes (..),+    VisitType (..),+    VisitField (..),+    VisitEnum (..),+    typeDirective,+    fieldDirective,+    enumDirective,+    fieldDirective',+    enumDirective',++    -- * default GQL directives+    GQLDirective (..),+    Deprecated (..),+    Describe (..),+    dropNamespaceOptions,+    SCALAR,+    DerivingKind (..),+    TYPE,+    CUSTOM,+    WRAPPER,+    RootResolver (..),+    defaultRootResolver,+    Rename (..),+  )+where++import Data.Morpheus.App+  ( App,+  )+import Data.Morpheus.App.Internal.Resolving+  ( Resolver,+    ResolverContext (..),+    SubscriptionField,+    WithOperation,+    subscribe,+    unsafeInternalContext,+  )+import Data.Morpheus.Core+  ( RenderGQL,+    render,+  )+import Data.Morpheus.Server.Deriving.Encode ()+import Data.Morpheus.Server.Resolvers+  ( RootResolver (..),+    defaultRootResolver,+  )+import Data.Morpheus.Server.Types.DirectiveDefinitions+  ( Deprecated (..),+    Describe (..),+    Prefixes (..),+    Rename (..),+  )+import Data.Morpheus.Server.Types.Directives (GQLDirective (..))+import Data.Morpheus.Server.Types.GQLType+  ( GQLType (..),+    enumDirective,+    enumDirective',+    fieldDirective,+    fieldDirective',+    typeDirective,+  )+import Data.Morpheus.Server.Types.Internal+  ( GQLTypeOptions (..),+    defaultTypeOptions,+    dropNamespaceOptions,+  )+import Data.Morpheus.Server.Types.Kind+  ( CUSTOM,+    DerivingKind (..),+    SCALAR,+    TYPE,+    WRAPPER,+  )+import Data.Morpheus.Server.Types.Types+  ( Arg (..),+    TypeGuard (..),+    Undefined (..),+  )+import Data.Morpheus.Server.Types.Visitors+  ( VisitEnum (..),+    VisitField (..),+    VisitType (..),+  )+import Data.Morpheus.Types.GQLScalar+  ( DecodeScalar (..),+    EncodeScalar (..),+  )+import Data.Morpheus.Types.GQLWrapper+  ( DecodeWrapper (..),+    EncodeWrapper (..),+  )+import Data.Morpheus.Types.ID (ID (..))+import Data.Morpheus.Types.IO+  ( GQLRequest (..),+    GQLResponse (..),+  )+import Data.Morpheus.Types.Internal.AST+  ( MUTATION,+    QUERY,+    SUBSCRIPTION,+    ScalarValue (..),+  )+import Relude hiding (Undefined)
+ src/Data/Morpheus/Server/Types/DirectiveDefinitions.hs view
@@ -0,0 +1,134 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DeriveAnyClass #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE NoImplicitPrelude #-}++module Data.Morpheus.Server.Types.DirectiveDefinitions+  ( Prefixes (..),+    Deprecated (..),+    Describe (..),+    Rename (..),+  )+where++import Data.Morpheus.Server.Types.Directives (GQLDirective (..))+import Data.Morpheus.Server.Types.GQLType (GQLType (__type))+import Data.Morpheus.Server.Types.Internal (mkTypeData)+import Data.Morpheus.Server.Types.Visitors+  ( VisitEnum (..),+    VisitField (..),+    VisitType (..),+  )+import Data.Morpheus.Types.Internal.AST+  ( DirectiveLocation (..),+  )+import qualified Data.Text as T+import Relude++-- | a custom GraphQL directive for adding or removing+-- of prefixes+data Prefixes = Prefixes+  { addPrefix :: Text,+    removePrefix :: Text+  }+  deriving (Generic, GQLType)++instance GQLDirective Prefixes where+  type+    DIRECTIVE_LOCATIONS Prefixes =+      '[ 'OBJECT,+         'ENUM,+         'INPUT_OBJECT,+         'UNION,+         'SCALAR,+         'INTERFACE+       ]++instance VisitType Prefixes where+  visitTypeName Prefixes {addPrefix, removePrefix} name = addPrefix <> T.drop (T.length removePrefix) name+  visitTypeDescription _ = id++-- native GraphQL directive @deprecated+--+newtype Deprecated = Deprecated+  { reason :: Maybe Text+  }+  deriving+    ( Generic,+      VisitEnum,+      VisitField+    )++instance GQLType Deprecated where+  __type _ = mkTypeData "deprecated"++instance GQLDirective Deprecated where+  type+    DIRECTIVE_LOCATIONS Deprecated =+      '[ 'FIELD_DEFINITION,+         'ENUM_VALUE+       ]++-- description++newtype Describe = Describe {text :: Text}+  deriving+    ( GQLType,+      Generic+    )++instance GQLDirective Describe where+  type+    DIRECTIVE_LOCATIONS Describe =+      '[ 'ENUM_VALUE,+         'FIELD_DEFINITION,+         'INPUT_FIELD_DEFINITION,+         'OBJECT,+         'ENUM,+         'INPUT_OBJECT,+         'UNION,+         'SCALAR,+         'INTERFACE,+         'ARGUMENT_DEFINITION+       ]++instance VisitEnum Describe where+  visitEnumDescription Describe {text} _ = Just text++instance VisitField Describe where+  visitFieldDescription Describe {text} _ = Just text++instance VisitType Describe where+  visitTypeDescription Describe {text} _ = Just text++-- | a custom GraphQL directive for adding or removing+-- of prefixes+newtype Rename = Rename {name :: Text} deriving (Generic, GQLType)++instance GQLDirective Rename where+  type+    DIRECTIVE_LOCATIONS Rename =+      '[ 'OBJECT,+         'ENUM,+         'INPUT_OBJECT,+         'UNION,+         'SCALAR,+         'INTERFACE,+         'ENUM_VALUE,+         'FIELD_DEFINITION,+         'INPUT_FIELD_DEFINITION+       ]++instance VisitType Rename where+  visitTypeName Rename {name} _ = name+  visitTypeDescription _ = id++instance VisitEnum Rename where+  visitEnumName Rename {name} _ = name++instance VisitField Rename where+  visitFieldName Rename {name} _ = name
+ src/Data/Morpheus/Server/Types/Directives.hs view
@@ -0,0 +1,188 @@+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE PolyKinds #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE NoImplicitPrelude #-}++module Data.Morpheus.Server.Types.Directives+  ( GQLDirective (..),+    ToLocations (..),+    getLocations,+    -- visitors+    visitTypeName,+    visitTypeDescription,+    visitFieldName,+    visitFieldDescription,+    visitEnumName,+    visitEnumDescription,+  )+where++import Data.Morpheus.Server.Types.TypeName (getTypename)+import qualified Data.Morpheus.Server.Types.Visitors as Visitors+import Data.Morpheus.Types.Internal.AST+  ( Description,+    DirectiveLocation (..),+    FALSE,+    FieldName,+    TRUE,+    TypeName,+    packName,+    unpackName,+  )+import Relude++type family OR (a :: Bool) (b :: Bool) where+  OR FALSE FALSE = FALSE+  OR a b = TRUE++type family INCLUDES (x :: DirectiveLocation) (xs :: [DirectiveLocation]) :: Bool where+  INCLUDES x '[] = FALSE+  INCLUDES x (x ': xs) = TRUE+  INCLUDES x (a ': xs) = INCLUDES x xs++type family OVERLAPS (xs :: [DirectiveLocation]) (ys :: [DirectiveLocation]) :: Bool where+  OVERLAPS (x ': xs) ys = OR (INCLUDES x ys) (OVERLAPS xs ys)+  OVERLAPS '[] ys = FALSE++-- type VisitorOption (k :: DirectiveLocation) (a :: Type) = VisitorContext a (Allow k (ALLOWED_DIRECTIVE_LOCATIONS a))++class ToLocation (l :: DirectiveLocation) where+  toLocation :: f l -> DirectiveLocation++-- types+instance ToLocation 'OBJECT where+  toLocation = const OBJECT++instance ToLocation 'ENUM where+  toLocation = const ENUM++instance ToLocation 'INPUT_OBJECT where+  toLocation = const INPUT_OBJECT++instance ToLocation 'UNION where+  toLocation = const UNION++instance ToLocation 'SCALAR where+  toLocation = const SCALAR++instance ToLocation 'INTERFACE where+  toLocation = const INTERFACE++-- fields, values+instance ToLocation 'INPUT_FIELD_DEFINITION where+  toLocation = const INPUT_FIELD_DEFINITION++instance ToLocation 'ARGUMENT_DEFINITION where+  toLocation = const ARGUMENT_DEFINITION++instance ToLocation 'FIELD_DEFINITION where+  toLocation = const FIELD_DEFINITION++instance ToLocation 'ENUM_VALUE where+  toLocation = const ENUM_VALUE++class ToLocations (k :: [DirectiveLocation]) where+  toLocations :: f k -> [DirectiveLocation]++instance (ToLocation l, ToLocations ls) => ToLocations (l : ls) where+  toLocations _ = toLocation (Proxy @l) : toLocations (Proxy @ls)++instance ToLocations '[] where+  toLocations _ = []++getLocations :: forall f a. ToLocations (DIRECTIVE_LOCATIONS a) => f a -> [DirectiveLocation]+getLocations _ = toLocations (Proxy :: Proxy (DIRECTIVE_LOCATIONS a))++type ALLOWED (a :: Type) (l :: [DirectiveLocation]) = OVERLAPS l (DIRECTIVE_LOCATIONS a)++type WITH_VISITOR (a :: Type) (f :: Type -> Bool -> Constraint) (l :: [DirectiveLocation]) = f a (ALLOWED a l)++-- types++type TYPE_VISITOR_KIND = '[ 'OBJECT, 'ENUM, 'INPUT_OBJECT, 'UNION, 'SCALAR, 'INTERFACE]++type FIELD_VISITOR_KIND = '[ 'INPUT_FIELD_DEFINITION, 'FIELD_DEFINITION]++type ENUM_VISITOR_KIND = '[ 'ENUM_VALUE]++__directiveName :: GQLDirective a => f a -> FieldName+__directiveName = coerce . getTypename++class+  ( Typeable a,+    WITH_VISITOR a VISIT_TYPE TYPE_VISITOR_KIND,+    WITH_VISITOR a VISIT_FIELD FIELD_VISITOR_KIND,+    WITH_VISITOR a VISIT_ENUM ENUM_VISITOR_KIND+  ) =>+  GQLDirective a+  where+  type DIRECTIVE_LOCATIONS a :: [DirectiveLocation]++-- TYPE VISITORS++visitTypeName :: forall a. GQLDirective a => a -> TypeName -> TypeName+visitTypeName = __visitTypeName (Proxy :: Proxy (ALLOWED a TYPE_VISITOR_KIND))++visitTypeDescription :: forall a. GQLDirective a => a -> Maybe Description -> Maybe Description+visitTypeDescription = __visitTypeDescription (Proxy :: Proxy (ALLOWED a TYPE_VISITOR_KIND))++class VISIT_TYPE a (t :: Bool) where+  __visitTypeName :: f t -> a -> TypeName -> TypeName+  __visitTypeDescription :: f t -> a -> Maybe Description -> Maybe Description++instance VISIT_TYPE a 'False where+  __visitTypeName _ _ = id+  __visitTypeDescription _ _ = id++instance Visitors.VisitType a => VISIT_TYPE a TRUE where+  __visitTypeName _ x name = packName $ Visitors.visitTypeName x (unpackName name)+  __visitTypeDescription _ = Visitors.visitTypeDescription++-- FIELD VISITORS++visitFieldName :: forall a. GQLDirective a => a -> FieldName -> FieldName+visitFieldName = __visitFieldName (Proxy :: Proxy (ALLOWED a FIELD_VISITOR_KIND))++visitFieldDescription :: forall a. GQLDirective a => a -> Maybe Description -> Maybe Description+visitFieldDescription = __visitFieldDescription (Proxy :: Proxy (ALLOWED a FIELD_VISITOR_KIND))++class VISIT_FIELD a (t :: Bool) where+  __visitFieldName :: f t -> a -> FieldName -> FieldName+  __visitFieldDescription :: f t -> a -> Maybe Description -> Maybe Description++instance VISIT_FIELD a FALSE where+  __visitFieldName _ _ = id+  __visitFieldDescription _ _ = id++instance Visitors.VisitField a => VISIT_FIELD a TRUE where+  __visitFieldName _ x name = packName $ Visitors.visitFieldName x (unpackName name)+  __visitFieldDescription _ = Visitors.visitFieldDescription++-- VISIT_ENUM++visitEnumName :: forall a. GQLDirective a => a -> TypeName -> TypeName+visitEnumName = __visitEnumName (Proxy :: Proxy (ALLOWED a ENUM_VISITOR_KIND))++visitEnumDescription :: forall a. GQLDirective a => a -> Maybe Description -> Maybe Description+visitEnumDescription = __visitEnumDescription (Proxy :: Proxy (ALLOWED a ENUM_VISITOR_KIND))++class VISIT_ENUM a (t :: Bool) where+  __visitEnumName :: f t -> a -> TypeName -> TypeName+  __visitEnumDescription :: f t -> a -> Maybe Description -> Maybe Description++instance VISIT_ENUM a FALSE where+  __visitEnumName _ _ = id+  __visitEnumDescription _ _ = id++instance Visitors.VisitEnum a => VISIT_ENUM a TRUE where+  __visitEnumName _ x name = packName $ Visitors.visitEnumName x (unpackName name)+  __visitEnumDescription _ = Visitors.visitEnumDescription
+ src/Data/Morpheus/Server/Types/GQLType.hs view
@@ -0,0 +1,456 @@+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DefaultSignatures #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE Rank2Types #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE NoImplicitPrelude #-}++module Data.Morpheus.Server.Types.GQLType+  ( GQLType+      ( KIND,+        description,+        getDescriptions,+        typeOptions,+        getDirectives,+        defaultValues,+        directives,+        __type+      ),+    __typeData,+    deriveTypename,+    deriveFingerprint,+    encodeArguments,+    DirectiveUsage (..),+    DeriveArguments (..),+    DirectiveUsages (..),+    typeDirective,+    fieldDirective,+    fieldDirective',+    enumDirective,+    enumDirective',+    applyTypeName,+    applyTypeDescription,+    applyEnumName,+    applyEnumDescription,+    applyFieldName,+    applyFieldDescription,+    __isEmptyType,+  )+where++-- MORPHEUS++import Control.Monad.Except (MonadError (throwError))+import qualified Data.HashMap.Strict as M+import Data.Morpheus.App.Internal.Resolving+  ( Resolver,+    SubscriptionField,+  )+import Data.Morpheus.Internal.Ext+import Data.Morpheus.Internal.Utils+import Data.Morpheus.Server.Deriving.Utils (ConsRep (..), DataType (..), DeriveWith, FieldRep (..))+import Data.Morpheus.Server.Deriving.Utils.DeriveGType (DeriveValueOptions (..), deriveValue)+import Data.Morpheus.Server.Deriving.Utils.Kinded (CategoryValue (..), KindedProxy (KindedProxy), kinded)+import Data.Morpheus.Server.Deriving.Utils.Proxy (ContextValue (..))+import Data.Morpheus.Server.NamedResolvers (NamedResolverT (..))+import Data.Morpheus.Server.Types.Directives+  ( GQLDirective (..),+    ToLocations,+    visitEnumDescription,+    visitEnumName,+    visitFieldDescription,+    visitFieldName,+    visitTypeDescription,+    visitTypeName,+  )+import Data.Morpheus.Server.Types.Internal+  ( GQLTypeOptions (..),+    TypeData (..),+    defaultTypeOptions,+    mkTypeData,+    prefixInputs,+  )+import Data.Morpheus.Server.Types.Kind+  ( CUSTOM,+    DerivingKind (..),+    SCALAR,+    TYPE,+    WRAPPER,+  )+import Data.Morpheus.Server.Types.SchemaT (SchemaT)+import Data.Morpheus.Server.Types.TypeName (TypeFingerprint (..), getFingerprint, getTypename)+import Data.Morpheus.Server.Types.Types+  ( Arg,+    Pair,+    TypeGuard,+    Undefined (..),+    __typenameUndefined,+  )+import Data.Morpheus.Types.GQLScalar (EncodeScalar (..))+import Data.Morpheus.Types.GQLWrapper (EncodeWrapperValue (..))+import Data.Morpheus.Types.ID (ID)+import Data.Morpheus.Types.Internal.AST+  ( Argument (..),+    Arguments,+    ArgumentsDefinition,+    CONST,+    Description,+    Directives,+    FieldName,+    IN,+    OUT,+    ObjectEntry (..),+    Position (..),+    TypeCategory (..),+    TypeName,+    TypeWrapper (..),+    Value (..),+    internal,+    mkBaseType,+    packName,+    toNullable,+    unitTypeName,+    unpackName,+  )+import Data.Sequence (Seq)+import Data.Text+  ( pack,+    unpack,+  )+import Data.Vector (Vector)+import GHC.Generics+import qualified Language.Haskell.TH.Syntax as TH+import Relude hiding (Seq, Undefined, fromList, intercalate)++__isEmptyType :: forall f a. GQLType a => f a -> Bool+__isEmptyType _ = deriveFingerprint (KindedProxy :: KindedProxy OUT a) == InternalFingerprint __typenameUndefined++__typeData ::+  forall kinded (kind :: TypeCategory) (a :: Type).+  (GQLType a, CategoryValue kind) =>+  kinded kind a ->+  TypeData+__typeData proxy = __type proxy (categoryValue (Proxy @kind))++deriveTypename :: (GQLType a, CategoryValue kind) => kinded kind a -> TypeName+deriveTypename proxy = gqlTypeName $ __typeData proxy++deriveFingerprint :: (GQLType a, CategoryValue kind) => kinded kind a -> TypeFingerprint+deriveFingerprint proxy = gqlFingerprint $ __typeData proxy++deriveTypeData :: Typeable a => f a -> (Bool -> String -> String) -> TypeCategory -> TypeData+deriveTypeData proxy typeNameModifier cat =+  TypeData+    { gqlTypeName = packName . pack $ typeNameModifier (cat == IN) originalTypeName,+      gqlWrappers = mkBaseType,+      gqlFingerprint = getFingerprint cat proxy+    }+  where+    originalTypeName = unpack . unpackName $ getTypename proxy++list :: TypeWrapper -> TypeWrapper+list = flip TypeList True++wrapper :: (TypeWrapper -> TypeWrapper) -> TypeData -> TypeData+wrapper f TypeData {..} = TypeData {gqlWrappers = f gqlWrappers, ..}++-- | GraphQL type, every graphQL type should have an instance of 'GHC.Generics.Generic' and 'GQLType'.+--+--  @+--    ... deriving (Generic, GQLType)+--  @+--+-- if you want to add description+--+--  @+--       ... deriving (Generic)+--+--     instance GQLType ... where+--       description = const "your description ..."+--  @+{-# DEPRECATED getDirectives "use: directives" #-}++{-# DEPRECATED description "use: directive Describe { text } with typeDirective" #-}++{-# DEPRECATED getDescriptions "use: directive Describe { text } with fieldDirective" #-}++class GQLType a where+  type KIND a :: DerivingKind+  type KIND a = TYPE++  -- | A description of the type.+  --+  -- Used for documentation in the GraphQL schema.+  description :: f a -> Maybe Text+  description _ = Nothing++  directives :: f a -> DirectiveUsages+  directives _ = mempty++  -- | A dictionary of descriptions for fields, keyed on field name.+  --+  -- Used for documentation in the GraphQL schema.+  getDescriptions :: f a -> Map Text Description+  getDescriptions _ = mempty++  typeOptions :: f a -> GQLTypeOptions -> GQLTypeOptions+  typeOptions _ = id++  getDirectives :: f a -> Map Text (Directives CONST)+  getDirectives _ = mempty++  defaultValues :: f a -> Map Text (Value CONST)+  defaultValues _ = mempty++  __type :: f a -> TypeCategory -> TypeData+  default __type :: Typeable a => f a -> TypeCategory -> TypeData+  __type proxy category = editTypeData derivedType (directives proxy)+    where+      derivedType = deriveTypeData proxy typeNameModifier category+      GQLTypeOptions {typeNameModifier} = typeOptions proxy defaultTypeOptions++instance GQLType Int where+  type KIND Int = SCALAR+  __type _ = mkTypeData "Int"++instance GQLType Double where+  type KIND Double = SCALAR+  __type _ = mkTypeData "Float"++instance GQLType Float where+  type KIND Float = SCALAR+  __type _ = mkTypeData "Float32"++instance GQLType Text where+  type KIND Text = SCALAR+  __type _ = mkTypeData "String"++instance GQLType Bool where+  type KIND Bool = SCALAR+  __type _ = mkTypeData "Boolean"++instance GQLType ID where+  type KIND ID = SCALAR+  __type _ = mkTypeData "ID"++-- WRAPPERS+instance GQLType () where+  __type _ = mkTypeData unitTypeName++instance Typeable m => GQLType (Undefined m) where+  type KIND (Undefined m) = CUSTOM+  __type _ = mkTypeData __typenameUndefined++instance GQLType a => GQLType (Maybe a) where+  type KIND (Maybe a) = WRAPPER+  __type _ = wrapper toNullable . __type (Proxy @a)++instance GQLType a => GQLType [a] where+  type KIND [a] = WRAPPER+  __type _ = wrapper list . __type (Proxy @a)++instance GQLType a => GQLType (Set a) where+  type KIND (Set a) = WRAPPER+  __type _ = __type $ Proxy @[a]++instance GQLType a => GQLType (NonEmpty a) where+  type KIND (NonEmpty a) = WRAPPER+  __type _ = __type $ Proxy @[a]++instance GQLType a => GQLType (Seq a) where+  type KIND (Seq a) = WRAPPER+  __type _ = __type $ Proxy @[a]++instance GQLType a => GQLType (Vector a) where+  type KIND (Vector a) = WRAPPER+  __type _ = __type $ Proxy @[a]++instance GQLType a => GQLType (SubscriptionField a) where+  type KIND (SubscriptionField a) = WRAPPER+  __type _ = __type $ Proxy @a++instance (Typeable a, Typeable b, GQLType a, GQLType b) => GQLType (Pair a b) where+  typeOptions _ = prefixInputs++-- Manual++instance GQLType b => GQLType (a -> b) where+  type KIND (a -> b) = CUSTOM+  __type _ = __type $ Proxy @b++instance (GQLType k, GQLType v, Typeable k, Typeable v) => GQLType (Map k v) where+  type KIND (Map k v) = CUSTOM+  __type _ = __type $ Proxy @[Pair k v]++instance GQLType a => GQLType (Resolver o e m a) where+  type KIND (Resolver o e m a) = CUSTOM+  __type _ = __type $ Proxy @a++instance (Typeable a, Typeable b, GQLType a, GQLType b) => GQLType (a, b) where+  __type _ = __type $ Proxy @(Pair a b)+  typeOptions _ = prefixInputs++instance (GQLType value) => GQLType (Arg name value) where+  type KIND (Arg name value) = CUSTOM+  __type _ = __type (Proxy @value)++instance (GQLType interface) => GQLType (TypeGuard interface possibleTypes) where+  type KIND (TypeGuard interface possibleTypes) = CUSTOM+  __type _ = __type (Proxy @interface)++instance (GQLType a) => GQLType (Proxy a) where+  type KIND (Proxy a) = KIND a+  __type _ = __type (Proxy @a)++instance (GQLType a) => GQLType (NamedResolverT m a) where+  type KIND (NamedResolverT m a) = CUSTOM+  __type _ = __type (Proxy :: Proxy a)++type Decode a = EncodeKind (KIND a) a++encodeArguments :: forall a. Decode a => a -> GQLResult (Arguments CONST)+encodeArguments x = encode x >>= unpackValue+  where+    unpackValue (Object v) = pure $ fmap toArgument v+    unpackValue _ = throwError (internal "TODO: expected arguments!")+    toArgument ObjectEntry {..} = Argument (Position 0 0) entryName entryValue++encode :: forall a. Decode a => a -> GQLResult (Value CONST)+encode x = encodeKind (ContextValue x :: ContextValue (KIND a) a)++class EncodeKind (kind :: DerivingKind) (a :: Type) where+  encodeKind :: ContextValue kind a -> GQLResult (Value CONST)++instance (EncodeWrapperValue f, Decode a) => EncodeKind WRAPPER (f a) where+  encodeKind = encodeWrapperValue encode . unContextValue++instance (EncodeScalar a) => EncodeKind SCALAR a where+  encodeKind = pure . Scalar . encodeScalar . unContextValue++instance (EncodeConstraint a) => EncodeKind TYPE a where+  encodeKind = exploreResolvers . unContextValue++convertNode ::+  DataType (GQLResult (Value CONST)) ->+  GQLResult (Value CONST)+convertNode+  DataType+    { tyIsUnion,+      tyCons = ConsRep {consFields, consName}+    } = encodeTypeFields consFields+    where+      encodeTypeFields ::+        [FieldRep (GQLResult (Value CONST))] -> GQLResult (Value CONST)+      encodeTypeFields [] = pure $ Enum consName+      encodeTypeFields fields | not tyIsUnion = Object <$> (traverse fromField fields >>= fromElems)+        where+          fromField FieldRep {fieldSelector, fieldValue} = do+            entryValue <- fieldValue+            pure ObjectEntry {entryName = fieldSelector, entryValue}+      -- Type References --------------------------------------------------------------+      encodeTypeFields _ = throwError (internal "TODO: union not supported")++-- Types & Constrains -------------------------------------------------------+class (EncodeKind (KIND a) a, GQLType a) => ExplorerConstraint a++instance (EncodeKind (KIND a) a, GQLType a) => ExplorerConstraint a++exploreResolvers :: forall a. EncodeConstraint a => a -> GQLResult (Value CONST)+exploreResolvers =+  convertNode+    . deriveValue+      ( DeriveValueOptions+          { __valueApply = encode,+            __valueTypeName = deriveTypename (KindedProxy :: KindedProxy IN a),+            __valueGQLOptions = typeOptions (Proxy @a) defaultTypeOptions,+            __valueGetType = __typeData . kinded (Proxy @IN)+          } ::+          DeriveValueOptions IN ExplorerConstraint (GQLResult (Value CONST))+      )++type EncodeConstraint a =+  ( Generic a,+    GQLType a,+    DeriveWith ExplorerConstraint (GQLResult (Value CONST)) (Rep a)+  )++class DeriveArguments (k :: DerivingKind) a where+  deriveArgumentsDefinition :: f k a -> SchemaT OUT (ArgumentsDefinition CONST)++-- DIRECTIVES++data DirectiveUsages = DirectiveUsages+  { typeDirectives :: [DirectiveUsage],+    fieldDirectives :: M.HashMap FieldName [DirectiveUsage],+    enumValueDirectives :: M.HashMap TypeName [DirectiveUsage]+  }++instance Monoid DirectiveUsages where+  mempty = DirectiveUsages mempty mempty mempty++mergeDirs :: (Eq k, Hashable k, Semigroup v) => HashMap k v -> HashMap k v -> HashMap k v+mergeDirs a b = update a (M.toList b)+  where+    update m [] = m+    update m (x : xs) = update (upsert x m) xs++upsert :: (Eq k, Hashable k, Semigroup v) => (k, v) -> HashMap k v -> HashMap k v+upsert (k, v) = M.alter (Just . maybe v (v <>)) k++instance Semigroup DirectiveUsages where+  DirectiveUsages td1 fd1 ed1 <> DirectiveUsages td2 fd2 ed2 =+    DirectiveUsages (td1 <> td2) (mergeDirs fd1 fd2) (mergeDirs ed1 ed2)++type TypeDirectiveConstraint a = (GQLDirective a, GQLType a, Decode a, DeriveArguments (KIND a) a, ToLocations (DIRECTIVE_LOCATIONS a))++typeDirective :: TypeDirectiveConstraint a => a -> DirectiveUsages+typeDirective x = DirectiveUsages [DirectiveUsage x] mempty mempty++fieldDirective :: TypeDirectiveConstraint a => FieldName -> a -> DirectiveUsages+fieldDirective name x = DirectiveUsages mempty (M.singleton name [DirectiveUsage x]) mempty++fieldDirective' :: TypeDirectiveConstraint a => TH.Name -> a -> DirectiveUsages+fieldDirective' name = fieldDirective (packName name)++enumDirective :: TypeDirectiveConstraint a => TypeName -> a -> DirectiveUsages+enumDirective name x = DirectiveUsages mempty mempty (M.singleton name [DirectiveUsage x])++enumDirective' :: TypeDirectiveConstraint a => TH.Name -> a -> DirectiveUsages+enumDirective' name = enumDirective (packName name)++data DirectiveUsage where+  DirectiveUsage :: (GQLDirective a, GQLType a, Decode a, DeriveArguments (KIND a) a, ToLocations (DIRECTIVE_LOCATIONS a)) => a -> DirectiveUsage++applyTypeName :: DirectiveUsage -> TypeName -> TypeName+applyTypeName (DirectiveUsage x) = visitTypeName x++typeNameWithDirectives :: TypeName -> [DirectiveUsage] -> TypeName+typeNameWithDirectives = foldr applyTypeName++applyEnumDescription :: DirectiveUsage -> Maybe Description -> Maybe Description+applyEnumDescription (DirectiveUsage x) = visitEnumDescription x++applyEnumName :: DirectiveUsage -> TypeName -> TypeName+applyEnumName (DirectiveUsage x) = visitEnumName x++applyFieldDescription :: DirectiveUsage -> Maybe Description -> Maybe Description+applyFieldDescription (DirectiveUsage x) = visitFieldDescription x++applyFieldName :: DirectiveUsage -> FieldName -> FieldName+applyFieldName (DirectiveUsage x) = visitFieldName x++applyTypeDescription :: DirectiveUsage -> Maybe Description -> Maybe Description+applyTypeDescription (DirectiveUsage x) = visitTypeDescription x++editTypeData :: TypeData -> DirectiveUsages -> TypeData+editTypeData TypeData {..} DirectiveUsages {typeDirectives} = TypeData {gqlTypeName = typeNameWithDirectives gqlTypeName typeDirectives, ..}
+ src/Data/Morpheus/Server/Types/Internal.hs view
@@ -0,0 +1,98 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE NoImplicitPrelude #-}++module Data.Morpheus.Server.Types.Internal+  ( GQLTypeOptions (..),+    defaultTypeOptions,+    TypeData (..),+    prefixInputs,+    mkTypeData,+    dropNamespaceOptions,+  )+where++-- MORPHEUS++import Data.Char (toLower)+import Data.Morpheus.Server.Types.TypeName (TypeFingerprint (..))+import Data.Morpheus.Types.Internal.AST+  ( TypeKind (..),+    TypeName,+    TypeWrapper (..),+    mkBaseType,+  )+import qualified Data.Text as T+import Relude hiding (Seq, Undefined, intercalate)++data TypeData = TypeData+  { gqlTypeName :: TypeName,+    gqlWrappers :: TypeWrapper,+    gqlFingerprint :: TypeFingerprint+  }+  deriving (Show)++-- | Options that specify how to map GraphQL field, type, and constructor names+-- to and from their Haskell equivalent.+--+-- Options can be set using record syntax on 'defaultOptions' with the fields+-- below.+data GQLTypeOptions = GQLTypeOptions+  { -- | Function applied to field labels.+    -- Handy for removing common record prefixes for example.+    fieldLabelModifier :: String -> String,+    -- | Function applied to constructor tags.+    constructorTagModifier :: String -> String,+    -- | Construct a new type name depending on whether it is an input,+    -- and being given the original type name.+    typeNameModifier :: Bool -> String -> String+  }++-- | Default encoding 'GQLTypeOptions':+--+-- @+-- 'GQLTypeOptions'+--   { 'fieldLabelModifier'      = id+--   , 'constructorTagModifier'  = id+--   , 'typeNameModifier'        = const id+--   }+-- @+defaultTypeOptions :: GQLTypeOptions+defaultTypeOptions =+  GQLTypeOptions+    { fieldLabelModifier = id,+      constructorTagModifier = id,+      -- default is just a pass through for the original type name+      typeNameModifier = const id+    }++prefixInputs :: GQLTypeOptions -> GQLTypeOptions+prefixInputs options = options {typeNameModifier = \isInput name -> if isInput then "Input" <> name else name}++mkTypeData :: TypeName -> a -> TypeData+mkTypeData name _ =+  TypeData+    { gqlTypeName = name,+      gqlFingerprint = InternalFingerprint name,+      gqlWrappers = mkBaseType+    }++dropPrefix :: Text -> String -> String+dropPrefix name = drop (T.length name)++stripConstructorNamespace :: Text -> String -> String+stripConstructorNamespace = dropPrefix++stripFieldNamespace :: Text -> String -> String+stripFieldNamespace prefix = __uncapitalize . dropPrefix prefix+  where+    __uncapitalize [] = []+    __uncapitalize (x : xs) = toLower x : xs++dropNamespaceOptions :: TypeKind -> Text -> GQLTypeOptions -> GQLTypeOptions+dropNamespaceOptions KindInterface tName opt =+  opt+    { typeNameModifier = const (stripConstructorNamespace "Interface"),+      fieldLabelModifier = stripFieldNamespace tName+    }+dropNamespaceOptions KindEnum tName opt = opt {constructorTagModifier = stripConstructorNamespace tName}+dropNamespaceOptions _ tName opt = opt {fieldLabelModifier = stripFieldNamespace tName}
+ src/Data/Morpheus/Server/Types/Kind.hs view
@@ -0,0 +1,34 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE PolyKinds #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE NoImplicitPrelude #-}++-- | associating types to GraphQL Kinds+module Data.Morpheus.Server.Types.Kind+  ( SCALAR,+    DerivingKind (..),+    TYPE,+    CUSTOM,+    WRAPPER,+  )+where++import Relude++data DerivingKind+  = SCALAR+  | TYPE+  | WRAPPER+  | CUSTOM+  deriving (Show)++-- | GraphQL input, type, union , enum+type TYPE = 'TYPE++-- | GraphQL Scalar: Int, Float, String, Boolean or any user defined custom Scalar type+type SCALAR = 'SCALAR++-- | GraphQL Arrays , Resolvers and NonNull fields+type WRAPPER = 'WRAPPER++type CUSTOM = 'CUSTOM
+ src/Data/Morpheus/Server/Types/SchemaT.hs view
@@ -0,0 +1,215 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DeriveFunctor #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE TupleSections #-}+{-# LANGUAGE NoImplicitPrelude #-}++module Data.Morpheus.Server.Types.SchemaT+  ( SchemaT,+    updateSchema,+    insertType,+    TypeFingerprint (..),+    toSchema,+    withInput,+    extendImplements,+    insertDirectiveDefinition,+    outToAny,+  )+where++import Control.Monad.Except (MonadError (..))+import qualified Data.Map as Map+import Data.Morpheus.Internal.Ext (GQLResult)+import Data.Morpheus.Server.Types.TypeName+import Data.Morpheus.Types.Internal.AST+  ( ANY,+    CONST,+    DirectiveDefinition,+    GQLError,+    IN,+    OBJECT,+    OUT,+    Schema,+    TypeCategory (..),+    TypeContent (..),+    TypeDefinition (..),+    TypeName,+    defineDirective,+    defineSchemaWith,+    msg,+    toAny,+  )+import Relude hiding (empty)++data SchemaState where+  SchemaState ::+    { typeDefinitions :: Map TypeFingerprint (TypeDefinition ANY CONST),+      implements :: Map TypeName [TypeName],+      directiveDefinitions :: Map TypeFingerprint (DirectiveDefinition CONST)+    } ->+    SchemaState++emptyMyMap :: SchemaState+emptyMyMap =+  SchemaState+    { typeDefinitions = Map.empty,+      implements = Map.empty,+      directiveDefinitions = Map.empty+    }++-- Helper Functions+newtype SchemaT (cat :: TypeCategory) a = SchemaT+  { runSchemaT ::+      GQLResult+        ( a,+          [SchemaState -> GQLResult SchemaState]+        )+  }+  deriving (Functor)++instance MonadError GQLError (SchemaT c) where+  throwError = SchemaT . throwError+  catchError (SchemaT mx) f = SchemaT (catchError mx (runSchemaT . f))++instance Applicative (SchemaT c) where+  pure = SchemaT . pure . (,[])+  (SchemaT v1) <*> (SchemaT v2) = SchemaT $ do+    (f, u1) <- v1+    (a, u2) <- v2+    pure (f a, u1 <> u2)++instance Monad (SchemaT c) where+  return = pure+  (SchemaT v1) >>= f =+    SchemaT $ do+      (x, up1) <- v1+      (y, up2) <- runSchemaT (f x)+      pure (y, up1 <> up2)++toSchema ::+  SchemaT+    c+    ( TypeDefinition OBJECT CONST,+      Maybe (TypeDefinition OBJECT CONST),+      Maybe (TypeDefinition OBJECT CONST)+    ) ->+  GQLResult (Schema CONST)+toSchema (SchemaT v) = do+  ((q, m, s), typeDefs) <- v+  SchemaState {typeDefinitions, implements, directiveDefinitions} <- execUpdates emptyMyMap typeDefs+  types <- map (insertImplements implements) <$> checkTypeCollisions (Map.toList typeDefinitions)+  schema <- defineSchemaWith types (Just q, m, s)+  foldlM defineDirective schema directiveDefinitions++insertImplements :: Map TypeName [TypeName] -> TypeDefinition c CONST -> TypeDefinition c CONST+insertImplements x TypeDefinition {typeContent = DataObject {..}, ..} =+  TypeDefinition+    { typeContent =+        DataObject+          { objectImplements = objectImplements <> implements,+            ..+          },+      ..+    }+  where+    implements :: [TypeName]+    implements = Map.findWithDefault [] typeName x+insertImplements _ t = t++withInput :: SchemaT IN a -> SchemaT OUT a+withInput (SchemaT x) = SchemaT x++outToAny :: SchemaT OUT a -> SchemaT k' a+outToAny (SchemaT x) = SchemaT x++checkTypeCollisions :: [(TypeFingerprint, TypeDefinition k a)] -> GQLResult [TypeDefinition k a]+checkTypeCollisions = fmap Map.elems . foldlM collectTypes Map.empty+  where+    collectTypes :: Map (TypeName, TypeFingerprint) (TypeDefinition k a) -> (TypeFingerprint, TypeDefinition k a) -> GQLResult (Map (TypeName, TypeFingerprint) (TypeDefinition k a))+    collectTypes accum (fp, typ) = maybe addType (handleCollision typ) (key `Map.lookup` accum)+      where+        addType = pure $ Map.insert key typ accum+        key = (typeName typ, withSameCategory fp)+        handleCollision t1@TypeDefinition {typeContent = DataEnum {}} t2 | t1 == t2 = pure accum+        handleCollision TypeDefinition {typeContent = DataScalar {}} TypeDefinition {typeContent = DataScalar {}} = pure accum+        handleCollision TypeDefinition {typeName = name1} _ = failureRequirePrefix name1++failureRequirePrefix :: TypeName -> GQLResult b+failureRequirePrefix typename =+  throwError $+    "It appears that the Haskell type "+      <> msg typename+      <> " was used as both input and output type, which is not allowed by GraphQL specifications."+      <> "\n\n "+      <> "If you supply \"typeNameModifier\" in \"GQLType.typeOptions\", "+      <> "you can override the default type names for "+      <> msg typename+      <> " to solve this problem."++withSameCategory :: TypeFingerprint -> TypeFingerprint+withSameCategory (TypeableFingerprint _ xs) = TypeableFingerprint OUT xs+withSameCategory x = x++execUpdates :: Monad m => a -> [a -> m a] -> m a+execUpdates = foldlM (&)++insertType :: TypeDefinition cat CONST -> SchemaT cat' ()+insertType dt = updateSchema (CustomFingerprint (typeName dt)) (const $ pure dt) ()++updateSchema ::+  TypeFingerprint ->+  (a -> SchemaT cat' (TypeDefinition cat CONST)) ->+  a ->+  SchemaT cat' ()+updateSchema InternalFingerprint {} _ _ = SchemaT $ pure ((), [])+updateSchema fingerprint f x =+  SchemaT $ pure ((), [upLib])+  where+    upLib :: SchemaState -> GQLResult SchemaState+    upLib schema+      | Map.member fingerprint (typeDefinitions schema) = pure schema+      | otherwise = do+          (type', updates) <- runSchemaT (f x)+          execUpdates schema (update type' : updates)+      where+        update t schemaState =+          pure+            schemaState+              { typeDefinitions = Map.insert fingerprint (toAny t) (typeDefinitions schemaState)+              }++insertDirectiveDefinition ::+  TypeFingerprint ->+  (a -> SchemaT cat' (DirectiveDefinition CONST)) ->+  a ->+  SchemaT cat' ()+insertDirectiveDefinition InternalFingerprint {} _ _ = SchemaT $ pure ((), [])+insertDirectiveDefinition fingerprint f x =+  SchemaT $ pure ((), [upLib])+  where+    upLib :: SchemaState -> GQLResult SchemaState+    upLib schema+      | Map.member fingerprint (typeDefinitions schema) = pure schema+      | otherwise = do+          (type', updates) <- runSchemaT (f x)+          execUpdates schema (update type' : updates)+      where+        update t schemaState =+          pure+            schemaState+              { directiveDefinitions = Map.insert fingerprint t (directiveDefinitions schemaState)+              }++extendImplements :: TypeName -> [TypeName] -> SchemaT cat' ()+extendImplements interface types = SchemaT $ pure ((), [upLib])+  where+    -- TODO: what happens if interface name collides?+    upLib :: SchemaState -> GQLResult SchemaState+    upLib schema = pure schema {implements = foldr insertInterface (implements schema) types}+    insertInterface :: TypeName -> Map TypeName [TypeName] -> Map TypeName [TypeName]+    insertInterface = Map.alter (Just . (interface :) . fromMaybe [])
+ src/Data/Morpheus/Server/Types/TypeName.hs view
@@ -0,0 +1,86 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE Rank2Types #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE NoImplicitPrelude #-}++module Data.Morpheus.Server.Types.TypeName+  ( getTypename,+    getTypeConstructorNames,+    getFingerprint,+    TypeFingerprint (..),+  )+where++-- MORPHEUS++import Data.Data (tyConFingerprint)+import Data.Morpheus.App.Internal.Resolving+  ( Resolver,+  )+import Data.Morpheus.Server.NamedResolvers (NamedResolverT (..))+import Data.Morpheus.Server.Types.Types+  ( Pair,+  )+import Data.Morpheus.Types.Internal.AST+  ( TypeCategory,+    TypeName,+    packName,+  )+import Data.Text+  ( intercalate,+    pack,+  )+import Data.Typeable+  ( TyCon,+    TypeRep,+    splitTyConApp,+    tyConName,+    typeRep,+    typeRepTyCon,+  )+import GHC.Fingerprint+import Relude hiding (Seq, Undefined, intercalate)++data TypeFingerprint+  = TypeableFingerprint TypeCategory [Fingerprint]+  | InternalFingerprint TypeName+  | CustomFingerprint TypeName+  deriving+    ( Generic,+      Show,+      Eq,+      Ord+    )++getTypename :: Typeable a => f a -> TypeName+getTypename = packName . intercalate "" . getTypeConstructorNames++getTypeConstructorNames :: Typeable a => f a -> [Text]+getTypeConstructorNames = fmap (pack . tyConName . replacePairCon) . getTypeConstructors++getTypeConstructors :: Typeable a => f a -> [TyCon]+getTypeConstructors = ignoreResolver . splitTyConApp . typeRep++-- | replaces typeName (A,B) with Pair_A_B+replacePairCon :: TyCon -> TyCon+replacePairCon x | hsPair == x = gqlPair+  where+    hsPair = typeRepTyCon $ typeRep $ Proxy @(Int, Int)+    gqlPair = typeRepTyCon $ typeRep $ Proxy @(Pair Int Int)+replacePairCon x = x++-- Ignores Resolver name  from typeName+ignoreResolver :: (TyCon, [TypeRep]) -> [TyCon]+ignoreResolver (con, _) | con == typeRepTyCon (typeRep $ Proxy @Resolver) = []+ignoreResolver (con, _) | con == typeRepTyCon (typeRep $ Proxy @NamedResolverT) = []+ignoreResolver (con, args) =+  con : concatMap (ignoreResolver . splitTyConApp) args++getFingerprint :: Typeable a => TypeCategory -> f a -> TypeFingerprint+getFingerprint category = TypeableFingerprint category . fmap tyConFingerprint . getTypeConstructors
+ src/Data/Morpheus/Server/Types/Types.hs view
@@ -0,0 +1,39 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE NoImplicitPrelude #-}++module Data.Morpheus.Server.Types.Types+  ( Undefined (..),+    Pair (..),+    TypeGuard (..),+    Arg (..),+    __typenameUndefined,+  )+where++import Data.Kind (Type)+import Data.Morpheus.Types.Internal.AST (TypeName)+import GHC.Generics+  ( Generic,+  )+import GHC.TypeLits (Symbol)+import Prelude (Bool, Show)++__typenameUndefined :: TypeName+__typenameUndefined = "Undefined"++newtype Undefined (m :: Type -> Type) = Undefined Bool deriving (Show, Generic)++data Pair k v = Pair k v deriving (Generic)++data TypeGuard interface union+  = ResolveInterface interface+  | ResolveType union++newtype Arg (name :: Symbol) a = Arg {argValue :: a}+  deriving+    ( Show,+      Generic+    )
+ src/Data/Morpheus/Server/Types/Visitors.hs view
@@ -0,0 +1,40 @@+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DuplicateRecordFields #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE NoImplicitPrelude #-}++module Data.Morpheus.Server.Types.Visitors+  ( VisitType (..),+    VisitField (..),+    VisitEnum (..),+  )+where++import Relude++class VisitType a where+  visitTypeName :: a -> Text -> Text+  visitTypeName _ = id++  visitTypeDescription :: a -> Maybe Text -> Maybe Text+  visitTypeDescription = const id++class VisitField a where+  visitFieldName :: a -> Text -> Text+  visitFieldName _ = id++  visitFieldDescription :: a -> Maybe Text -> Maybe Text+  visitFieldDescription _ = id++class VisitEnum a where+  visitEnumName :: a -> Text -> Text+  visitEnumName _ = id++  visitEnumDescription :: a -> Maybe Text -> Maybe Text+  visitEnumDescription _ = id
+ test/Feature/Collision/CategoryCollisionFail.hs view
@@ -0,0 +1,61 @@+{-# LANGUAGE DeriveAnyClass #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE DuplicateRecordFields #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TypeFamilies #-}++-- fail if type was used as input and output type without prefixes+module Feature.Collision.CategoryCollisionFail+  ( api,+  )+where++import Data.Kind (Type)+import Data.Morpheus.Server (interpreter)+import Data.Morpheus.Server.Types+  ( GQLRequest,+    GQLResponse,+    GQLType (..),+    RootResolver (..),+    Undefined,+    defaultRootResolver,+  )+import Data.Text+  ( Text,+  )+import GHC.Generics (Generic)++data Deity = Deity+  { name :: Text,+    age :: Int+  }+  deriving (Show, Generic, GQLType)++newtype DeityArgs = DeityArgs+  { input :: Deity+  }+  deriving (Show, Generic, GQLType)++newtype Query (m :: Type -> Type) = Query+  { deity :: DeityArgs -> m Deity+  }+  deriving (Generic, GQLType)++rootResolver :: RootResolver IO () Query Undefined Undefined+rootResolver =+  defaultRootResolver+    { queryResolver =+        Query+          { deity =+              const $+                pure+                  Deity+                    { name =+                        "Morpheus",+                      age = 1000+                    }+          }+    }++api :: GQLRequest -> IO GQLResponse+api = interpreter rootResolver
+ test/Feature/Collision/CategoryCollisionSuccess.hs view
@@ -0,0 +1,68 @@+{-# LANGUAGE DeriveAnyClass #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE DuplicateRecordFields #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TypeFamilies #-}++module Feature.Collision.CategoryCollisionSuccess+  ( api,+  )+where++import Data.Kind (Type)+import Data.Morpheus.Server (interpreter)+import Data.Morpheus.Server.Types+  ( GQLRequest,+    GQLResponse,+    GQLType (..),+    GQLTypeOptions (..),+    RootResolver (..),+    Undefined,+    defaultRootResolver,+  )+import Data.Text+  ( Text,+  )+import GHC.Generics (Generic)++data Deity = Deity+  { name :: Text,+    age :: Int+  }+  deriving (Show, Generic)++nonClashingTypeNameModifier :: Bool -> String -> String+nonClashingTypeNameModifier True original = "Input" ++ original+nonClashingTypeNameModifier False original = original++instance GQLType Deity where+  typeOptions _ opt = opt {typeNameModifier = nonClashingTypeNameModifier}++newtype DeityArgs = DeityArgs+  { input :: Deity+  }+  deriving (Show, Generic, GQLType)++newtype Query (m :: Type -> Type) = Query+  { deity :: DeityArgs -> m Deity+  }+  deriving (Generic, GQLType)++rootResolver :: RootResolver IO () Query Undefined Undefined+rootResolver =+  defaultRootResolver+    { queryResolver =+        Query+          { deity =+              const $+                pure+                  Deity+                    { name =+                        "Morpheus",+                      age = 1000+                    }+          }+    }++api :: GQLRequest -> IO GQLResponse+api = interpreter rootResolver
+ test/Feature/Collision/NameCollision.hs view
@@ -0,0 +1,44 @@+{-# LANGUAGE DeriveAnyClass #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TypeFamilies #-}++module Feature.Collision.NameCollision+  ( api,+  )+where++import Data.Kind (Type)+import Data.Morpheus.Server (interpreter)+import Data.Morpheus.Server.Types+  ( GQLRequest,+    GQLResponse,+    GQLType (..),+    RootResolver (..),+    Undefined,+    defaultRootResolver,+  )+import Data.Text (Text)+import qualified Feature.Collision.NameCollisionHelper as A2 (A (..))+import GHC.Generics (Generic)++data A = A+  { aText :: Text,+    aInt :: Int+  }+  deriving (Generic, GQLType)++data Query (m :: Type -> Type) = Query+  { a1 :: A,+    a2 :: A2.A+  }+  deriving (Generic, GQLType)++rootResolver :: RootResolver IO () Query Undefined Undefined+rootResolver =+  defaultRootResolver+    { queryResolver = Query {a1 = A "" 0, a2 = A2.A 0}+    }++api :: GQLRequest -> IO GQLResponse+api = interpreter rootResolver
+ test/Feature/Collision/NameCollisionHelper.hs view
@@ -0,0 +1,16 @@+{-# LANGUAGE DeriveAnyClass #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE TypeFamilies #-}++module Feature.Collision.NameCollisionHelper+  ( A (..),+  )+where++import Data.Morpheus.Server.Types (GQLType)+import GHC.Generics (Generic)++newtype A = A+  { bla :: Int+  }+  deriving (Generic, GQLType)
+ test/Feature/Collision/category-collision-fail/query.gql view
@@ -0,0 +1,76 @@+query Get__Type {+  __type(name: "Deity") {+    ...FullType+  }+}++fragment FullType on __Type {+  kind+  name+  fields(includeDeprecated: true) {+    name+    args {+      ...InputValue+    }+    type {+      ...TypeRef+    }+    isDeprecated+    deprecationReason+  }+  inputFields {+    ...InputValue+  }+  interfaces {+    ...TypeRef+  }+  enumValues(includeDeprecated: true) {+    name+    isDeprecated+    deprecationReason+  }+  possibleTypes {+    ...TypeRef+  }+}++fragment InputValue on __InputValue {+  name+  type {+    ...TypeRef+  }+  defaultValue+}++fragment TypeRef on __Type {+  kind+  name+  ofType {+    kind+    name+    ofType {+      kind+      name+      ofType {+        kind+        name+        ofType {+          kind+          name+          ofType {+            kind+            name+            ofType {+              kind+              name+              ofType {+                kind+                name+              }+            }+          }+        }+      }+    }+  }+}
+ test/Feature/Collision/category-collision-fail/response.json view
@@ -0,0 +1,7 @@+{+  "errors": [+    {+      "message": "It appears that the Haskell type \"Deity\" was used as both input and output type, which is not allowed by GraphQL specifications.\n\n If you supply \"typeNameModifier\" in \"GQLType.typeOptions\", you can override the default type names for \"Deity\" to solve this problem."+    }+  ]+}
+ test/Feature/Collision/category-collision-success/query.gql view
@@ -0,0 +1,82 @@+query Get__Type {+  type: __type(name: "Deity") {+    ...FullType+  }+  input: __type(name: "InputDeity") {+    ...FullType+  }+  query: __type(name: "Query") {+    ...FullType+  }+}++fragment FullType on __Type {+  kind+  name+  fields(includeDeprecated: true) {+    name+    args {+      ...InputValue+    }+    type {+      ...TypeRef+    }+    isDeprecated+    deprecationReason+  }+  inputFields {+    ...InputValue+  }+  interfaces {+    ...TypeRef+  }+  enumValues(includeDeprecated: true) {+    name+    isDeprecated+    deprecationReason+  }+  possibleTypes {+    ...TypeRef+  }+}++fragment InputValue on __InputValue {+  name+  type {+    ...TypeRef+  }+  defaultValue+}++fragment TypeRef on __Type {+  kind+  name+  ofType {+    kind+    name+    ofType {+      kind+      name+      ofType {+        kind+        name+        ofType {+          kind+          name+          ofType {+            kind+            name+            ofType {+              kind+              name+              ofType {+                kind+                name+              }+            }+          }+        }+      }+    }+  }+}
+ test/Feature/Collision/category-collision-success/response.json view
@@ -0,0 +1,119 @@+{+  "data": {+    "type": {+      "kind": "OBJECT",+      "name": "Deity",+      "fields": [+        {+          "name": "name",+          "args": [],+          "type": {+            "kind": "NON_NULL",+            "name": null,+            "ofType": {+              "kind": "SCALAR",+              "name": "String",+              "ofType": null+            }+          },+          "isDeprecated": false,+          "deprecationReason": null+        },+        {+          "name": "age",+          "args": [],+          "type": {+            "kind": "NON_NULL",+            "name": null,+            "ofType": {+              "kind": "SCALAR",+              "name": "Int",+              "ofType": null+            }+          },+          "isDeprecated": false,+          "deprecationReason": null+        }+      ],+      "inputFields": null,+      "interfaces": [],+      "enumValues": null,+      "possibleTypes": null+    },+    "input": {+      "kind": "INPUT_OBJECT",+      "name": "InputDeity",+      "fields": null,+      "inputFields": [+        {+          "name": "name",+          "type": {+            "kind": "NON_NULL",+            "name": null,+            "ofType": {+              "kind": "SCALAR",+              "name": "String",+              "ofType": null+            }+          },+          "defaultValue": null+        },+        {+          "name": "age",+          "type": {+            "kind": "NON_NULL",+            "name": null,+            "ofType": {+              "kind": "SCALAR",+              "name": "Int",+              "ofType": null+            }+          },+          "defaultValue": null+        }+      ],+      "interfaces": null,+      "enumValues": null,+      "possibleTypes": null+    },+    "query": {+      "kind": "OBJECT",+      "name": "Query",+      "fields": [+        {+          "name": "deity",+          "args": [+            {+              "name": "input",+              "type": {+                "kind": "NON_NULL",+                "name": null,+                "ofType": {+                  "kind": "INPUT_OBJECT",+                  "name": "InputDeity",+                  "ofType": null+                }+              },+              "defaultValue": null+            }+          ],+          "type": {+            "kind": "NON_NULL",+            "name": null,+            "ofType": {+              "kind": "OBJECT",+              "name": "Deity",+              "ofType": null+            }+          },+          "isDeprecated": false,+          "deprecationReason": null+        }+      ],+      "inputFields": null,+      "interfaces": [],+      "enumValues": null,+      "possibleTypes": null+    }+  }+}
+ test/Feature/Collision/name-collision/query.gql view
@@ -0,0 +1,3 @@+{+  name+}
+ test/Feature/Collision/name-collision/response.json view
@@ -0,0 +1,10 @@+{+  "errors": [+    {+      "message": "There can Be only One TypeDefinition Named \"A\"."+    },+    {+      "message": "There can Be only One TypeDefinition Named \"A\"."+    }+  ]+}
+ test/Feature/Directive/Definition.hs view
@@ -0,0 +1,100 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DeriveAnyClass #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE DuplicateRecordFields #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TemplateHaskellQuotes #-}+{-# LANGUAGE TypeFamilies #-}++module Feature.Directive.Definition+  ( api,+  )+where++import Data.Kind (Type)+import Data.Morpheus.Server (interpreter)+import Data.Morpheus.Server.Types+  ( Deprecated (..),+    GQLDirective (..),+    GQLRequest,+    GQLResponse,+    GQLType (..),+    Prefixes (..),+    RootResolver (..),+    Undefined,+    VisitType (..),+    defaultRootResolver,+    enumDirective',+    fieldDirective',+    typeDirective,+  )+import Data.Morpheus.Types.Internal.AST+  ( DirectiveLocation (..),+  )+import Data.Text (Text)+import GHC.Generics (Generic)++data MythologyDeity = MythologyDeity+  { deityName :: Text,+    deprecatedField :: Maybe Text,+    deprecatedFieldWithReason :: Bool+  }+  deriving (Generic)++data Power = Power+  { name :: Text,+    isLimited :: Bool+  }+  deriving (GQLType, Generic)++instance GQLDirective Power where+  type DIRECTIVE_LOCATIONS Power = '[ 'OBJECT]++instance VisitType Power where+  visitTypeName _ = id++instance GQLType MythologyDeity where+  directives _ =+    typeDirective Power {name = "Lightning bolts", isLimited = False}+      <> typeDirective Prefixes {addPrefix = "", removePrefix = "Mythology"}+      <> fieldDirective' 'deprecatedField Deprecated {reason = Nothing}+      <> fieldDirective' 'deprecatedFieldWithReason Deprecated {reason = Just "this should be deprecated"}++data City+  = Athens+  | Sparta+  | Corinth+  | Delphi+  | Argos+  deriving+    (Generic)++instance GQLType City where+  directives _ =+    enumDirective' 'Sparta Deprecated {reason = Nothing}+      <> enumDirective' 'Delphi Deprecated {reason = Just "oracle left the place"}+      <> enumDirective' 'Argos Deprecated {reason = Just "for some reason"}++data Query (m :: Type -> Type) = Query+  { deity :: MythologyDeity,+    city :: City+  }+  deriving (Generic, GQLType)++root :: RootResolver IO () Query Undefined Undefined+root =+  defaultRootResolver+    { queryResolver =+        Query+          { deity =+              MythologyDeity+                { deityName = "morpheus",+                  deprecatedField = Nothing,+                  deprecatedFieldWithReason = False+                },+            city = Corinth+          }+    }++api :: GQLRequest -> IO GQLResponse+api = interpreter root
+ test/Feature/Directive/EnumVisitor.hs view
@@ -0,0 +1,74 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DeriveAnyClass #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE DuplicateRecordFields #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TemplateHaskellQuotes #-}+{-# LANGUAGE TypeFamilies #-}++module Feature.Directive.EnumVisitor+  ( api,+  )+where++import Data.Kind (Type)+import Data.Morpheus.Server (interpreter)+import Data.Morpheus.Server.Types+  ( Arg (..),+    Describe (..),+    GQLRequest,+    GQLResponse,+    GQLType (..),+    Rename (..),+    RootResolver (..),+    Undefined,+    defaultRootResolver,+    enumDirective',+  )+import Data.Text (Text, pack)+import GHC.Generics (Generic)++data City+  = Athens+  | Sparta+  | CORINTH__UGLY_ENUM_NAME+  | Delphi+  | ARgos+  deriving+    (Generic, Show)++instance GQLType City where+  directives _ =+    enumDirective' 'Sparta Describe {text = "city of warriors"}+      <> enumDirective' 'Delphi Describe {text = "city of oracle"}+      <> enumDirective' 'ARgos Describe {text = "city of argonauts"}+      <> enumDirective' 'Sparta Rename {name = "sparta"}+      <> enumDirective' 'Delphi Rename {name = "delphi"}+      <> enumDirective' 'Athens Rename {name = "_athens"}+      <> enumDirective' 'CORINTH__UGLY_ENUM_NAME Rename {name = "corinth"}+      <> enumDirective' 'ARgos Rename {name = "argos"}++data Query (m :: Type -> Type) = Query+  { cities :: [City],+    printCities :: Arg "cities" [City] -> m Text+  }+  deriving (Generic, GQLType)++root :: RootResolver IO () Query Undefined Undefined+root =+  defaultRootResolver+    { queryResolver =+        Query+          { cities =+              [ Athens,+                Sparta,+                CORINTH__UGLY_ENUM_NAME,+                Delphi,+                ARgos+              ],+            printCities = pure . pack . show . argValue+          }+    }++api :: GQLRequest -> IO GQLResponse+api = interpreter root
+ test/Feature/Directive/FieldVisitor.hs view
@@ -0,0 +1,68 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DeriveAnyClass #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE DuplicateRecordFields #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TemplateHaskellQuotes #-}+{-# LANGUAGE TypeFamilies #-}++module Feature.Directive.FieldVisitor+  ( api,+  )+where++import Data.Kind (Type)+import Data.Morpheus.Server (interpreter)+import Data.Morpheus.Server.Types+  ( Arg (..),+    Describe (..),+    GQLRequest,+    GQLResponse,+    GQLType (..),+    GQLTypeOptions (..),+    Rename (..),+    RootResolver (..),+    Undefined,+    defaultRootResolver,+    fieldDirective',+  )+import Data.Text (Text, pack)+import GHC.Generics (Generic)++data Deity = Deity+  { __name :: Text,+    __power :: Maybe Text+  }+  deriving (Generic, Show)++instance GQLType Deity where+  typeOptions _ options = options {typeNameModifier = \isInput n -> if isInput then "Input" <> n else n}++  directives _ =+    fieldDirective' '__name Describe {text = "name of the deity"}+      <> fieldDirective' '__power Describe {text = "extraterrestrial ability"}+      <> fieldDirective' '__name Rename {name = "name"}+      <> fieldDirective' '__power Rename {name = "power"}++data Query (m :: Type -> Type) = Query+  { deity :: Deity,+    printDeity :: Arg "deity" Deity -> m Text+  }+  deriving (Generic, GQLType)++root :: RootResolver IO () Query Undefined Undefined+root =+  defaultRootResolver+    { queryResolver =+        Query+          { deity =+              Deity+                { __name = "Morpheus",+                  __power = Just "Shapeshifting"+                },+            printDeity = pure . pack . show . argValue+          }+    }++api :: GQLRequest -> IO GQLResponse+api = interpreter root
+ test/Feature/Directive/TypeVisitor.hs view
@@ -0,0 +1,54 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DeriveAnyClass #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE DuplicateRecordFields #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TypeFamilies #-}++module Feature.Directive.TypeVisitor+  ( api,+  )+where++import Data.Kind (Type)+import Data.Morpheus.Server (interpreter)+import Data.Morpheus.Server.Types+  ( Describe (..),+    GQLRequest,+    GQLResponse,+    GQLType (..),+    RootResolver (..),+    Undefined,+    defaultRootResolver,+    typeDirective,+  )+import Data.Text (Text)+import GHC.Generics (Generic)++data Deity = Deity+  { name :: Text,+    power :: Maybe Text+  }+  deriving (Generic)++instance GQLType Deity where+  directives _ = typeDirective Describe {text = "A supernatural being considered divine and sacred"}++newtype Query (m :: Type -> Type) = Query {deity :: Deity}+  deriving (Generic, GQLType)++root :: RootResolver IO () Query Undefined Undefined+root =+  defaultRootResolver+    { queryResolver =+        Query+          { deity =+              Deity+                { name = "morpheus",+                  power = Nothing+                }+          }+    }++api :: GQLRequest -> IO GQLResponse+api = interpreter root
+ test/Feature/Directive/definition/introspect-directive/query.gql view
@@ -0,0 +1,53 @@+query Get__Type {+  __schema {+    directives {+      name+      description+      locations+      args {+        ...InputValue+      }+    }+  }+}++fragment InputValue on __InputValue {+  name+  type {+    ...TypeRef+  }+  defaultValue+}++fragment TypeRef on __Type {+  kind+  name+  ofType {+    kind+    name+    ofType {+      kind+      name+      ofType {+        kind+        name+        ofType {+          kind+          name+          ofType {+            kind+            name+            ofType {+              kind+              name+              ofType {+                kind+                name+              }+            }+          }+        }+      }+    }+  }+}
+ test/Feature/Directive/definition/introspect-directive/response.json view
@@ -0,0 +1,121 @@+{+  "data": {+    "__schema": {+      "directives": [+        {+          "args": [+            {+              "defaultValue": null,+              "name": "name",+              "type": {+                "kind": "NON_NULL",+                "name": null,+                "ofType": { "kind": "SCALAR", "name": "String", "ofType": null }+              }+            },+            {+              "defaultValue": null,+              "name": "isLimited",+              "type": {+                "kind": "NON_NULL",+                "name": null,+                "ofType": {+                  "kind": "SCALAR",+                  "name": "Boolean",+                  "ofType": null+                }+              }+            }+          ],+          "description": null,+          "locations": ["OBJECT"],+          "name": "Power"+        },+        {+          "args": [+            {+              "defaultValue": null,+              "name": "addPrefix",+              "type": {+                "kind": "NON_NULL",+                "name": null,+                "ofType": { "kind": "SCALAR", "name": "String", "ofType": null }+              }+            },+            {+              "defaultValue": null,+              "name": "removePrefix",+              "type": {+                "kind": "NON_NULL",+                "name": null,+                "ofType": { "kind": "SCALAR", "name": "String", "ofType": null }+              }+            }+          ],+          "description": null,+          "locations": [+            "OBJECT",+            "ENUM",+            "INPUT_OBJECT",+            "UNION",+            "SCALAR",+            "INTERFACE"+          ],+          "name": "Prefixes"+        },+        {+          "args": [+            {+              "defaultValue": null,+              "name": "reason",+              "type": { "kind": "SCALAR", "name": "String", "ofType": null }+            }+          ],+          "description": "\nMarks an element of a GraphQL schema as no longer supported.\n",+          "locations": ["FIELD_DEFINITION", "ENUM_VALUE"],+          "name": "deprecated"+        },+        {+          "args": [+            {+              "defaultValue": null,+              "name": "if",+              "type": {+                "kind": "NON_NULL",+                "name": null,+                "ofType": {+                  "kind": "SCALAR",+                  "name": "Boolean",+                  "ofType": null+                }+              }+            }+          ],+          "description": "\nDirects the executor to include this field or fragment only when the `if` argument is true.\n",+          "locations": ["FIELD", "FRAGMENT_SPREAD", "INLINE_FRAGMENT"],+          "name": "include"+        },+        {+          "args": [+            {+              "defaultValue": null,+              "name": "if",+              "type": {+                "kind": "NON_NULL",+                "name": null,+                "ofType": {+                  "kind": "SCALAR",+                  "name": "Boolean",+                  "ofType": null+                }+              }+            }+          ],+          "description": "\nDirects the executor to skip this field or fragment when the `if` argument is true.\n",+          "locations": ["FIELD", "FRAGMENT_SPREAD", "INLINE_FRAGMENT"],+          "name": "skip"+        }+      ]+    }+  }+}
+ test/Feature/Directive/definition/introspect-enum/query.gql view
@@ -0,0 +1,76 @@+query Get__Type {+  city: __type(name: "City") {+    ...FullType+  }+}++fragment FullType on __Type {+  kind+  name+  fields(includeDeprecated: true) {+    name+    args {+      ...InputValue+    }+    type {+      ...TypeRef+    }+    isDeprecated+    deprecationReason+  }+  inputFields {+    ...InputValue+  }+  interfaces {+    ...TypeRef+  }+  enumValues(includeDeprecated: true) {+    name+    isDeprecated+    deprecationReason+  }+  possibleTypes {+    ...TypeRef+  }+}++fragment InputValue on __InputValue {+  name+  type {+    ...TypeRef+  }+  defaultValue+}++fragment TypeRef on __Type {+  kind+  name+  ofType {+    kind+    name+    ofType {+      kind+      name+      ofType {+        kind+        name+        ofType {+          kind+          name+          ofType {+            kind+            name+            ofType {+              kind+              name+              ofType {+                kind+                name+              }+            }+          }+        }+      }+    }+  }+}
+ test/Feature/Directive/definition/introspect-enum/response.json view
@@ -0,0 +1,39 @@+{+  "data": {+    "city": {+      "enumValues": [+        {+          "deprecationReason": null,+          "isDeprecated": false,+          "name": "Athens"+        },+        {+          "deprecationReason": null,+          "isDeprecated": true,+          "name": "Sparta"+        },+        {+          "deprecationReason": null,+          "isDeprecated": false,+          "name": "Corinth"+        },+        {+          "deprecationReason": "oracle left the place",+          "isDeprecated": true,+          "name": "Delphi"+        },+        {+          "deprecationReason": "for some reason",+          "isDeprecated": true,+          "name": "Argos"+        }+      ],+      "fields": null,+      "inputFields": null,+      "interfaces": null,+      "kind": "ENUM",+      "name": "City",+      "possibleTypes": null+    }+  }+}
+ test/Feature/Directive/definition/introspect-type/query.gql view
@@ -0,0 +1,79 @@+query Get__Type {+  deity: __type(name: "Deity") {+    ...FullType+  }+  shouldBeNull: __type(name: "MythologyDeity") {+    ...FullType+  }+}++fragment FullType on __Type {+  kind+  name+  fields(includeDeprecated: true) {+    name+    args {+      ...InputValue+    }+    type {+      ...TypeRef+    }+    isDeprecated+    deprecationReason+  }+  inputFields {+    ...InputValue+  }+  interfaces {+    ...TypeRef+  }+  enumValues(includeDeprecated: true) {+    name+    isDeprecated+    deprecationReason+  }+  possibleTypes {+    ...TypeRef+  }+}++fragment InputValue on __InputValue {+  name+  type {+    ...TypeRef+  }+  defaultValue+}++fragment TypeRef on __Type {+  kind+  name+  ofType {+    kind+    name+    ofType {+      kind+      name+      ofType {+        kind+        name+        ofType {+          kind+          name+          ofType {+            kind+            name+            ofType {+              kind+              name+              ofType {+                kind+                name+              }+            }+          }+        }+      }+    }+  }+}
+ test/Feature/Directive/definition/introspect-type/response.json view
@@ -0,0 +1,56 @@+{+  "data": {+    "deity": {+      "enumValues": null,+      "fields": [+        {+          "args": [],+          "deprecationReason": null,+          "isDeprecated": false,+          "name": "deityName",+          "type": {+            "kind": "NON_NULL",+            "name": null,+            "ofType": {+              "kind": "SCALAR",+              "name": "String",+              "ofType": null+            }+          }+        },+        {+          "args": [],+          "deprecationReason": null,+          "isDeprecated": true,+          "name": "deprecatedField",+          "type": {+            "kind": "SCALAR",+            "name": "String",+            "ofType": null+          }+        },+        {+          "args": [],+          "deprecationReason": "this should be deprecated",+          "isDeprecated": true,+          "name": "deprecatedFieldWithReason",+          "type": {+            "kind": "NON_NULL",+            "name": null,+            "ofType": {+              "kind": "SCALAR",+              "name": "Boolean",+              "ofType": null+            }+          }+        }+      ],+      "inputFields": null,+      "interfaces": [],+      "kind": "OBJECT",+      "name": "Deity",+      "possibleTypes": null+    },+    "shouldBeNull": null+  }+}
+ test/Feature/Directive/enum-visitor/description/query.gql view
@@ -0,0 +1,8 @@+query Get__Type {+  city: __type(name: "City") {+    name+    enumValues{+      description+    }+  }+}
+ test/Feature/Directive/enum-visitor/description/response.json view
@@ -0,0 +1,14 @@+{+  "data": {+    "city": {+      "enumValues": [+        { "description": null },+        { "description": "city of warriors" },+        { "description": null },+        { "description": "city of oracle" },+        { "description": "city of argonauts" }+      ],+      "name": "City"+    }+  }+}
+ test/Feature/Directive/enum-visitor/name-decode/query.gql view
@@ -0,0 +1,3 @@+query Get__Type {+  printCities(cities: [_athens, sparta, corinth, delphi, argos])+}
+ test/Feature/Directive/enum-visitor/name-decode/response.json view
@@ -0,0 +1,5 @@+{+  "data": {+    "printCities": "[Athens,Sparta,CORINTH__UGLY_ENUM_NAME,Delphi,ARgos]"+  }+}
+ test/Feature/Directive/enum-visitor/name-encode/query.gql view
@@ -0,0 +1,3 @@+query Get__Type {+  cities+}
+ test/Feature/Directive/enum-visitor/name-encode/response.json view
@@ -0,0 +1,5 @@+{+  "data": {+    "cities": ["_athens", "sparta", "corinth", "delphi", "argos"]+  }+}
+ test/Feature/Directive/enum-visitor/name-introspection/query.gql view
@@ -0,0 +1,8 @@+query Get__Type {+  city: __type(name: "City") {+    name+    enumValues {+      name+    }+  }+}
+ test/Feature/Directive/enum-visitor/name-introspection/response.json view
@@ -0,0 +1,14 @@+{+  "data": {+    "city": {+      "enumValues": [+        { "name": "_athens" },+        { "name": "sparta" },+        { "name": "corinth" },+        { "name": "delphi" },+        { "name": "argos" }+      ],+      "name": "City"+    }+  }+}
+ test/Feature/Directive/field-visitor/description/query.gql view
@@ -0,0 +1,9 @@+query Get__Type {+  city: __type(name: "Deity") {+    kind+    name+    fields {+      description+    }+  }+}
+ test/Feature/Directive/field-visitor/description/response.json view
@@ -0,0 +1,16 @@+{+  "data": {+    "city": {+      "fields": [+        {+          "description": "name of the deity"+        },+        {+          "description": "extraterrestrial ability"+        }+      ],+      "kind": "OBJECT",+      "name": "Deity"+    }+  }+}
+ test/Feature/Directive/field-visitor/name-decode/query.gql view
@@ -0,0 +1,3 @@+query Get__Type {+  printDeity(deity: { name: "Zeus", power: "Shapeshifting" })+}
+ test/Feature/Directive/field-visitor/name-decode/response.json view
@@ -0,0 +1,5 @@+{+  "data": {+    "printDeity": "Deity {__name = \"Zeus\", __power = Just \"Shapeshifting\"}"+  }+}
+ test/Feature/Directive/field-visitor/name-encode/query.gql view
@@ -0,0 +1,6 @@+query Get__Type {+  deity {+    name+    power+  }+}
+ test/Feature/Directive/field-visitor/name-encode/response.json view
@@ -0,0 +1,8 @@+{+  "data": {+    "deity": {+      "name": "Morpheus",+      "power": "Shapeshifting"+    }+  }+}
+ test/Feature/Directive/field-visitor/name-introspection/query.gql view
@@ -0,0 +1,9 @@+query Get__Type {+  city: __type(name: "Deity") {+    kind+    name+    fields {+      name+    }+  }+}
+ test/Feature/Directive/field-visitor/name-introspection/response.json view
@@ -0,0 +1,16 @@+{+  "data": {+    "city": {+      "fields": [+        {+          "name": "name"+        },+        {+          "name": "power"+        }+      ],+      "kind": "OBJECT",+      "name": "Deity"+    }+  }+}
+ test/Feature/Directive/type-visitor/description/query.gql view
@@ -0,0 +1,7 @@+query Get__Type {+  city: __type(name: "Deity") {+    kind+    name+    description+  }+}
+ test/Feature/Directive/type-visitor/description/response.json view
@@ -0,0 +1,9 @@+{+  "data": {+    "city": {+      "description": "A supernatural being considered divine and sacred",+      "kind": "OBJECT",+      "name": "Deity"+    }+  }+}
+ test/Feature/Inference/ObjectAndEnum.hs view
@@ -0,0 +1,46 @@+{-# LANGUAGE DeriveAnyClass #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE DuplicateRecordFields #-}+{-# LANGUAGE TypeFamilies #-}++module Feature.Inference.ObjectAndEnum+  ( api,+  )+where++import Data.Kind (Type)+import Data.Morpheus.Server (interpreter)+import Data.Morpheus.Server.Types+  ( GQLRequest,+    GQLResponse,+    GQLType (..),+    RootResolver (..),+    Undefined,+    defaultRootResolver,+  )+import GHC.Generics (Generic)++data MyEnum = MyEnum deriving (Generic, GQLType)++newtype MyObject+  = MyObject Int+  deriving (Generic, GQLType)++data Query (m :: Type -> Type) = Query+  { enum :: MyEnum,+    object :: MyObject+  }+  deriving (Generic, GQLType)++root :: RootResolver IO () Query Undefined Undefined+root =+  defaultRootResolver+    { queryResolver =+        Query+          { enum = MyEnum,+            object = MyObject 0+          }+    }++api :: GQLRequest -> IO GQLResponse+api = interpreter root
+ test/Feature/Inference/TaggedArguments.hs view
@@ -0,0 +1,75 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DeriveAnyClass #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE DuplicateRecordFields #-}+{-# LANGUAGE TypeFamilies #-}++module Feature.Inference.TaggedArguments+  ( api,+  )+where++import Data.Kind (Type)+import Data.Morpheus.Server (interpreter)+import Data.Morpheus.Server.Types+  ( Arg (..),+    GQLRequest,+    GQLResponse,+    GQLType (..),+    RootResolver (..),+    Undefined,+    defaultRootResolver,+  )+import Data.Text+  ( Text,+    pack,+  )+import GHC.Generics (Generic)++data A = A+  { a1 :: Text,+    a2 :: Int+  }+  deriving+    ( Show,+      Generic,+      GQLType+    )++newtype B = B+  {b1 :: Text}+  deriving+    ( Show,+      Generic,+      GQLType+    )++newtype C = C+  {c1 :: Int}+  deriving+    ( Show,+      Generic,+      GQLType+    )++data Query (m :: Type -> Type) = Query+  { field1 :: A -> B -> C -> m Text,+    field2 :: A -> Arg "b1" Text -> Arg "c1" Int -> m Text+  }+  deriving+    ( Generic,+      GQLType+    )++root :: RootResolver IO () Query Undefined Undefined+root =+  defaultRootResolver+    { queryResolver =+        Query+          { field1 = \a b c -> pure $ pack $ show (a, b, c),+            field2 = \a b c -> pure $ pack $ show (a, b, c)+          }+    }++api :: GQLRequest -> IO GQLResponse+api = interpreter root
+ test/Feature/Inference/TaggedArgumentsFail.hs view
@@ -0,0 +1,53 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DeriveAnyClass #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE DuplicateRecordFields #-}+{-# LANGUAGE TypeFamilies #-}++module Feature.Inference.TaggedArgumentsFail+  ( api,+  )+where++import Data.Kind (Type)+import Data.Morpheus.Server (interpreter)+import Data.Morpheus.Server.Types+  ( GQLRequest,+    GQLResponse,+    GQLType (..),+    RootResolver (..),+    Undefined,+    defaultRootResolver,+  )+import Data.Text+  ( Text,+    pack,+  )+import GHC.Generics (Generic)++data A = A+  { a1 :: Text,+    a2 :: Int+  }+  deriving (Show, Generic, GQLType)++newtype B = B+  {a2 :: Text}+  deriving (Show, Generic, GQLType)++newtype Query (m :: Type -> Type) = Query+  { field1 :: A -> B -> m Text+  }+  deriving (Generic, GQLType)++rootResolver :: RootResolver IO () Query Undefined Undefined+rootResolver =+  defaultRootResolver+    { queryResolver =+        Query+          { field1 = \a b -> pure $ pack $ show (a, b)+          }+    }++api :: GQLRequest -> IO GQLResponse+api = interpreter rootResolver
+ test/Feature/Inference/TypeGuards.hs view
@@ -0,0 +1,77 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DeriveAnyClass #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE DuplicateRecordFields #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TypeFamilies #-}++module Feature.Inference.TypeGuards+  ( api,+  )+where++import Data.Kind (Type)+import Data.Morpheus.Server (interpreter)+import Data.Morpheus.Server.Types+  ( GQLRequest,+    GQLResponse,+    GQLType (..),+    RootResolver (..),+    TypeGuard (..),+    Undefined,+    defaultRootResolver,+  )+import Data.Text+  ( Text,+  )+import GHC.Generics (Generic)++data Character = Hydra+  { name :: Text,+    age :: Int+  }+  deriving (Show, Generic, GQLType)++data Deity (m :: Type -> Type) = Deity+  { name :: Text,+    age :: Int,+    power :: Text+  }+  deriving (Generic, GQLType)++data Implements (m :: Type -> Type)+  = ImplementsDeity (Deity m)+  | Creature {name :: Text, age :: Int}+  deriving (Generic, GQLType)++type Characters m = TypeGuard Character (Implements m)++newtype Query (m :: Type -> Type) = Query+  { characters :: [Characters m]+  }+  deriving (Generic, GQLType)++resolveCharacters :: [Characters m]+resolveCharacters =+  ResolveType+    <$> [ ImplementsDeity+            ( Deity+                { name = "Morpheus",+                  age = 2000,+                  power = "Shapeshift"+                }+            ),+          Creature+            { name = "Lamia",+              age = 205+            }+        ]++rootResolver :: RootResolver IO () Query Undefined Undefined+rootResolver =+  defaultRootResolver+    { queryResolver = Query {characters = resolveCharacters}+    }++api :: GQLRequest -> IO GQLResponse+api = interpreter rootResolver
+ test/Feature/Inference/TypeInference.hs view
@@ -0,0 +1,109 @@+{-# LANGUAGE DeriveAnyClass #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE DuplicateRecordFields #-}+{-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TypeFamilies #-}++module Feature.Inference.TypeInference+  ( api,+  )+where++import Data.Kind (Type)+import Data.Morpheus.Server (interpreter)+import Data.Morpheus.Server.Types+  ( GQLRequest,+    GQLResponse,+    GQLType (..),+    RootResolver (..),+    Undefined,+    defaultRootResolver,+  )+import Data.Text+  ( Text,+    pack,+  )+import GHC.Generics (Generic)++data Power+  = Thunderbolts+  | Shapeshift+  | Hurricanes+  deriving (Generic, GQLType)++data Deity (m :: Type -> Type) = Deity+  { name :: Text,+    power :: Power+  }+  deriving (Generic, GQLType)++deityRes :: Deity m+deityRes = Deity {name = "Morpheus", power = Shapeshift}++data Hydra = Hydra+  { name :: Text,+    age :: Int+  }+  deriving (Show, Generic, GQLType)++data Monster+  = MonsterHydra Hydra+  | Cerberus {name :: Text}+  | UnidentifiedMonster+  deriving (Show, Generic, GQLType)++data Character (m :: Type -> Type)+  = CharacterDeity (Deity m) -- Only <tyCon name><type ref name> should generate direct link+  | Creature {creatureName :: Text, creatureAge :: Int}+  | BoxedDeity {boxedDeity :: Deity m}+  | ScalarRecord {scalarText :: Text}+  | CharacterAge Int+  | SomeDeity (Deity m)+  | SomeCompound Int Text+  | Zeus+  | Cronus+  deriving (Generic, GQLType)++resolveCharacter :: [Character m]+resolveCharacter =+  [ CharacterDeity deityRes,+    Creature {creatureName = "Lamia", creatureAge = 205},+    BoxedDeity {boxedDeity = deityRes},+    ScalarRecord {scalarText = "Some Text"},+    SomeDeity deityRes,+    CharacterAge 12,+    SomeCompound 21 "some text",+    Zeus,+    Cronus+  ]++newtype MonsterArgs = MonsterArgs+  { monster :: Monster+  }+  deriving (Show, Generic, GQLType)++data Query (m :: Type -> Type) = Query+  { deity :: Deity m,+    character :: [Character m],+    showMonster :: MonsterArgs -> m Text,+    unitType :: m ()+  }+  deriving (Generic, GQLType)++rootResolver :: RootResolver IO () Query Undefined Undefined+rootResolver =+  defaultRootResolver+    { queryResolver =+        Query+          { deity = deityRes,+            character = resolveCharacter,+            showMonster,+            unitType = pure ()+          }+    }+  where+    showMonster MonsterArgs {monster} = pure (pack $ show monster)++api :: GQLRequest -> IO GQLResponse+api = interpreter rootResolver
+ test/Feature/Inference/UnionType.hs view
@@ -0,0 +1,68 @@+{-# LANGUAGE DeriveAnyClass #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TypeFamilies #-}++module Feature.Inference.UnionType+  ( api,+  )+where++import Data.Morpheus.Server (interpreter)+import Data.Morpheus.Server.Resolvers (ResolverQ)+import Data.Morpheus.Server.Types+  ( GQLRequest,+    GQLResponse,+    GQLType (..),+    RootResolver (..),+    Undefined,+    defaultRootResolver,+  )+import Data.Text (Text)+import GHC.Generics (Generic)++data A = A+  { aText :: Text,+    aInt :: Int+  }+  deriving (Generic, GQLType)++data B = B+  { bText :: Text,+    bInt :: Int+  }+  deriving (Generic, GQLType)++data C = C+  { cText :: Text,+    cInt :: Int+  }+  deriving (Generic, GQLType)++data Sum+  = SumA A+  | SumB B+  deriving (Generic, GQLType)++data Query m = Query+  { union :: m [Sum],+    fc :: C+  }+  deriving (Generic, GQLType)++resolveUnion :: ResolverQ () IO [Sum]+resolveUnion =+  return [SumA A {aText = "at", aInt = 1}, SumB B {bText = "bt", bInt = 2}]++rootResolver :: RootResolver IO () Query Undefined Undefined+rootResolver =+  defaultRootResolver+    { queryResolver =+        Query+          { union = resolveUnion,+            fc = C {cText = "", cInt = 3}+          }+    }++api :: GQLRequest -> IO GQLResponse+api = interpreter rootResolver
+ test/Feature/Inference/WrappedType.hs view
@@ -0,0 +1,84 @@+{-# LANGUAGE DeriveAnyClass #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE NoImplicitPrelude #-}++module Feature.Inference.WrappedType+  ( api,+  )+where++import Data.Morpheus.Server (interpreter)+import Data.Morpheus.Server.Resolvers+  ( constRes,+  )+import Data.Morpheus.Server.Types+  ( GQLRequest,+    GQLResponse,+    GQLType (..),+    RootResolver (..),+    SubscriptionField,+    subscribe,+  )+import Data.Morpheus.Subscriptions (Event)+import Relude++data Wrapped a b = Wrapped+  { fieldA :: a,+    fieldB :: b+  }+  deriving (Generic, GQLType)++data WA m = WA+  { aText :: m Text,+    aInt :: Int+  }+  deriving (Generic, GQLType)++type Wrapped1 = Wrapped Int Int++type Wrapped2 = Wrapped (Wrapped Text Int) Text++data Query m = Query+  { a1 :: WA m,+    a2 :: Maybe Wrapped1,+    a3 :: Maybe Wrapped2+  }+  deriving (Generic, GQLType)++data Mutation m = Mutation+  { mut1 :: Maybe (WA m),+    mut2 :: Maybe Wrapped1,+    mut3 :: Maybe Wrapped2+  }+  deriving (Generic, GQLType)++data Channel+  = Channel+  deriving (Show, Eq)++type EVENT = Event Channel ()++data Subscription (m :: Type -> Type) = Subscription+  { sub1 :: SubscriptionField (m (Maybe (WA m))),+    sub2 :: SubscriptionField (m (Maybe Wrapped1)),+    sub3 :: SubscriptionField (m (Maybe Wrapped2))+  }+  deriving (Generic, GQLType)++rootResolver :: RootResolver IO EVENT Query Mutation Subscription+rootResolver =+  RootResolver+    { queryResolver = Query {a1 = WA {aText = pure "test1", aInt = 0}, a2 = Nothing, a3 = Nothing},+      mutationResolver = Mutation {mut1 = Nothing, mut2 = Nothing, mut3 = Nothing},+      subscriptionResolver =+        Subscription+          { sub1 = subscribe Channel (pure $ constRes Nothing),+            sub2 = subscribe Channel (pure $ constRes Nothing),+            sub3 = subscribe Channel (pure $ constRes Nothing)+          }+    }++api :: GQLRequest -> IO GQLResponse+api = interpreter rootResolver
+ test/Feature/Inference/object-and-enum/introspection/query.gql view
@@ -0,0 +1,79 @@+query Get__Type {+  enum: __type(name: "MyEnum") {+    ...FullType+  }+  object: __type(name: "MyObject") {+    ...FullType+  }+}++fragment FullType on __Type {+  kind+  name+  fields(includeDeprecated: true) {+    name+    args {+      ...InputValue+    }+    type {+      ...TypeRef+    }+    isDeprecated+    deprecationReason+  }+  inputFields {+    ...InputValue+  }+  interfaces {+    ...TypeRef+  }+  enumValues(includeDeprecated: true) {+    name+    isDeprecated+    deprecationReason+  }+  possibleTypes {+    ...TypeRef+  }+}++fragment InputValue on __InputValue {+  name+  type {+    ...TypeRef+  }+  defaultValue+}++fragment TypeRef on __Type {+  kind+  name+  ofType {+    kind+    name+    ofType {+      kind+      name+      ofType {+        kind+        name+        ofType {+          kind+          name+          ofType {+            kind+            name+            ofType {+              kind+              name+              ofType {+                kind+                name+              }+            }+          }+        }+      }+    }+  }+}
+ test/Feature/Inference/object-and-enum/introspection/response.json view
@@ -0,0 +1,44 @@+{+  "data": {+    "enum": {+      "enumValues": [+        {+          "deprecationReason": null,+          "isDeprecated": false,+          "name": "MyEnum"+        }+      ],+      "fields": null,+      "inputFields": null,+      "interfaces": null,+      "kind": "ENUM",+      "name": "MyEnum",+      "possibleTypes": null+    },+    "object": {+      "enumValues": null,+      "fields": [+        {+          "args": [],+          "deprecationReason": null,+          "isDeprecated": false,+          "name": "_0",+          "type": {+            "kind": "NON_NULL",+            "name": null,+            "ofType": {+              "kind": "SCALAR",+              "name": "Int",+              "ofType": null+            }+          }+        }+      ],+      "inputFields": null,+      "interfaces": [],+      "kind": "OBJECT",+      "name": "MyObject",+      "possibleTypes": null+    }+  }+}
+ test/Feature/Inference/object-and-enum/resolving/query.gql view
@@ -0,0 +1,7 @@+{+  enum+  object {+    _0+    __typename+  }+}
+ test/Feature/Inference/object-and-enum/resolving/response.json view
@@ -0,0 +1,6 @@+{+  "data": {+    "enum": "MyEnum",+    "object": { "_0": 0, "__typename": "MyObject" }+  }+}
+ test/Feature/Inference/tagged-arguments-fail/introspection/query.gql view
@@ -0,0 +1,76 @@+query Get__Type {+  __type(name: "Query") {+    ...FullType+  }+}++fragment FullType on __Type {+  kind+  name+  fields(includeDeprecated: true) {+    name+    args {+      ...InputValue+    }+    type {+      ...TypeRef+    }+    isDeprecated+    deprecationReason+  }+  inputFields {+    ...InputValue+  }+  interfaces {+    ...TypeRef+  }+  enumValues(includeDeprecated: true) {+    name+    isDeprecated+    deprecationReason+  }+  possibleTypes {+    ...TypeRef+  }+}++fragment InputValue on __InputValue {+  name+  type {+    ...TypeRef+  }+  defaultValue+}++fragment TypeRef on __Type {+  kind+  name+  ofType {+    kind+    name+    ofType {+      kind+      name+      ofType {+        kind+        name+        ofType {+          kind+          name+          ofType {+            kind+            name+            ofType {+              kind+              name+              ofType {+                kind+                name+              }+            }+          }+        }+      }+    }+  }+}
+ test/Feature/Inference/tagged-arguments-fail/introspection/response.json view
@@ -0,0 +1,7 @@+{+  "errors": [+    {+      "message": "There can Be only One argument Named \"a2\""+    }+  ]+}
+ test/Feature/Inference/tagged-arguments-fail/resolving/query.gql view
@@ -0,0 +1,4 @@+query Get__Type {+  field1(a1: "f1", a2: 2, b1: "f3", c1: 4)+  field2(a1: "f1", a2: 2, b1: "f3", c1: 4)+}
+ test/Feature/Inference/tagged-arguments-fail/resolving/response.json view
@@ -0,0 +1,7 @@+{+  "errors": [+    {+      "message": "There can Be only One argument Named \"a2\""+    }+  ]+}
+ test/Feature/Inference/tagged-arguments/introspection/query.gql view
@@ -0,0 +1,76 @@+query Get__Type {+  __type(name: "Query") {+    ...FullType+  }+}++fragment FullType on __Type {+  kind+  name+  fields(includeDeprecated: true) {+    name+    args {+      ...InputValue+    }+    type {+      ...TypeRef+    }+    isDeprecated+    deprecationReason+  }+  inputFields {+    ...InputValue+  }+  interfaces {+    ...TypeRef+  }+  enumValues(includeDeprecated: true) {+    name+    isDeprecated+    deprecationReason+  }+  possibleTypes {+    ...TypeRef+  }+}++fragment InputValue on __InputValue {+  name+  type {+    ...TypeRef+  }+  defaultValue+}++fragment TypeRef on __Type {+  kind+  name+  ofType {+    kind+    name+    ofType {+      kind+      name+      ofType {+        kind+        name+        ofType {+          kind+          name+          ofType {+            kind+            name+            ofType {+              kind+              name+              ofType {+                kind+                name+              }+            }+          }+        }+      }+    }+  }+}
+ test/Feature/Inference/tagged-arguments/introspection/response.json view
@@ -0,0 +1,110 @@+{+  "data": {+    "__type": {+      "inputFields": null,+      "name": "Query",+      "possibleTypes": null,+      "interfaces": [],+      "kind": "OBJECT",+      "enumValues": null,+      "fields": [+        {+          "name": "field1",+          "type": {+            "name": null,+            "kind": "NON_NULL",+            "ofType": { "name": "String", "kind": "SCALAR", "ofType": null }+          },+          "deprecationReason": null,+          "args": [+            {+              "name": "a1",+              "type": {+                "name": null,+                "kind": "NON_NULL",+                "ofType": { "name": "String", "kind": "SCALAR", "ofType": null }+              },+              "defaultValue": null+            },+            {+              "name": "a2",+              "type": {+                "name": null,+                "kind": "NON_NULL",+                "ofType": { "name": "Int", "kind": "SCALAR", "ofType": null }+              },+              "defaultValue": null+            },+            {+              "name": "b1",+              "type": {+                "name": null,+                "kind": "NON_NULL",+                "ofType": { "name": "String", "kind": "SCALAR", "ofType": null }+              },+              "defaultValue": null+            },+            {+              "name": "c1",+              "type": {+                "name": null,+                "kind": "NON_NULL",+                "ofType": { "name": "Int", "kind": "SCALAR", "ofType": null }+              },+              "defaultValue": null+            }+          ],+          "isDeprecated": false+        },+        {+          "name": "field2",+          "type": {+            "name": null,+            "kind": "NON_NULL",+            "ofType": { "name": "String", "kind": "SCALAR", "ofType": null }+          },+          "deprecationReason": null,+          "args": [+            {+              "name": "a1",+              "type": {+                "name": null,+                "kind": "NON_NULL",+                "ofType": { "name": "String", "kind": "SCALAR", "ofType": null }+              },+              "defaultValue": null+            },+            {+              "name": "a2",+              "type": {+                "name": null,+                "kind": "NON_NULL",+                "ofType": { "name": "Int", "kind": "SCALAR", "ofType": null }+              },+              "defaultValue": null+            },+            {+              "name": "b1",+              "type": {+                "name": null,+                "kind": "NON_NULL",+                "ofType": { "name": "String", "kind": "SCALAR", "ofType": null }+              },+              "defaultValue": null+            },+            {+              "name": "c1",+              "type": {+                "name": null,+                "kind": "NON_NULL",+                "ofType": { "name": "Int", "kind": "SCALAR", "ofType": null }+              },+              "defaultValue": null+            }+          ],+          "isDeprecated": false+        }+      ]+    }+  }+}
+ test/Feature/Inference/tagged-arguments/resolving/query.gql view
@@ -0,0 +1,4 @@+query Get__Type {+  field1(a1: "f1", a2: 2, b1: "f3", c1: 4)+  field2(a1: "f1", a2: 2, b1: "f3", c1: 4)+}
+ test/Feature/Inference/tagged-arguments/resolving/response.json view
@@ -0,0 +1,6 @@+{+  "data": {+    "field1": "(A {a1 = \"f1\", a2 = 2},B {b1 = \"f3\"},C {c1 = 4})",+    "field2": "(A {a1 = \"f1\", a2 = 2},Arg {argValue = \"f3\"},Arg {argValue = 4})"+  }+}
+ test/Feature/Inference/type-guards/introspection/interface/query.gql view
@@ -0,0 +1,76 @@+query Get__Type {+  __type(name: "Character") {+    ...FullType+  }+}++fragment FullType on __Type {+  kind+  name+  fields(includeDeprecated: true) {+    name+    args {+      ...InputValue+    }+    type {+      ...TypeRef+    }+    isDeprecated+    deprecationReason+  }+  inputFields {+    ...InputValue+  }+  interfaces {+    ...TypeRef+  }+  enumValues(includeDeprecated: true) {+    name+    isDeprecated+    deprecationReason+  }+  possibleTypes {+    ...TypeRef+  }+}++fragment InputValue on __InputValue {+  name+  type {+    ...TypeRef+  }+  defaultValue+}++fragment TypeRef on __Type {+  kind+  name+  ofType {+    kind+    name+    ofType {+      kind+      name+      ofType {+        kind+        name+        ofType {+          kind+          name+          ofType {+            kind+            name+            ofType {+              kind+              name+              ofType {+                kind+                name+              }+            }+          }+        }+      }+    }+  }+}
+ test/Feature/Inference/type-guards/introspection/interface/response.json view
@@ -0,0 +1,39 @@+{+  "data": {+    "__type": {+      "kind": "INTERFACE",+      "possibleTypes": [+        { "kind": "OBJECT", "ofType": null, "name": "Deity" },+        { "kind": "OBJECT", "ofType": null, "name": "Creature" }+      ],+      "enumValues": null,+      "interfaces": null,+      "inputFields": null,+      "fields": [+        {+          "name": "name",+          "deprecationReason": null,+          "isDeprecated": false,+          "type": {+            "kind": "NON_NULL",+            "ofType": { "kind": "SCALAR", "ofType": null, "name": "String" },+            "name": null+          },+          "args": []+        },+        {+          "name": "age",+          "deprecationReason": null,+          "isDeprecated": false,+          "type": {+            "kind": "NON_NULL",+            "ofType": { "kind": "SCALAR", "ofType": null, "name": "Int" },+            "name": null+          },+          "args": []+        }+      ],+      "name": "Character"+    }+  }+}
+ test/Feature/Inference/type-guards/introspection/objects/query.gql view
@@ -0,0 +1,79 @@+query Get__Type {+  deity: __type(name: "Deity") {+    ...FullType+  }+  creature: __type(name: "Creature") {+    ...FullType+  }+}++fragment FullType on __Type {+  kind+  name+  fields(includeDeprecated: true) {+    name+    args {+      ...InputValue+    }+    type {+      ...TypeRef+    }+    isDeprecated+    deprecationReason+  }+  inputFields {+    ...InputValue+  }+  interfaces {+    ...TypeRef+  }+  enumValues(includeDeprecated: true) {+    name+    isDeprecated+    deprecationReason+  }+  possibleTypes {+    ...TypeRef+  }+}++fragment InputValue on __InputValue {+  name+  type {+    ...TypeRef+  }+  defaultValue+}++fragment TypeRef on __Type {+  kind+  name+  ofType {+    kind+    name+    ofType {+      kind+      name+      ofType {+        kind+        name+        ofType {+          kind+          name+          ofType {+            kind+            name+            ofType {+              kind+              name+              ofType {+                kind+                name+              }+            }+          }+        }+      }+    }+  }+}
+ test/Feature/Inference/type-guards/introspection/objects/response.json view
@@ -0,0 +1,83 @@+{+  "data": {+    "deity": {+      "kind": "OBJECT",+      "possibleTypes": null,+      "enumValues": null,+      "interfaces": [+        { "kind": "INTERFACE", "ofType": null, "name": "Character" }+      ],+      "inputFields": null,+      "fields": [+        {+          "name": "name",+          "deprecationReason": null,+          "isDeprecated": false,+          "type": {+            "kind": "NON_NULL",+            "ofType": { "kind": "SCALAR", "ofType": null, "name": "String" },+            "name": null+          },+          "args": []+        },+        {+          "name": "age",+          "deprecationReason": null,+          "isDeprecated": false,+          "type": {+            "kind": "NON_NULL",+            "ofType": { "kind": "SCALAR", "ofType": null, "name": "Int" },+            "name": null+          },+          "args": []+        },+        {+          "name": "power",+          "deprecationReason": null,+          "isDeprecated": false,+          "type": {+            "kind": "NON_NULL",+            "ofType": { "kind": "SCALAR", "ofType": null, "name": "String" },+            "name": null+          },+          "args": []+        }+      ],+      "name": "Deity"+    },+    "creature": {+      "kind": "OBJECT",+      "possibleTypes": null,+      "enumValues": null,+      "interfaces": [+        { "kind": "INTERFACE", "ofType": null, "name": "Character" }+      ],+      "inputFields": null,+      "fields": [+        {+          "name": "name",+          "deprecationReason": null,+          "isDeprecated": false,+          "type": {+            "kind": "NON_NULL",+            "ofType": { "kind": "SCALAR", "ofType": null, "name": "String" },+            "name": null+          },+          "args": []+        },+        {+          "name": "age",+          "deprecationReason": null,+          "isDeprecated": false,+          "type": {+            "kind": "NON_NULL",+            "ofType": { "kind": "SCALAR", "ofType": null, "name": "Int" },+            "name": null+          },+          "args": []+        }+      ],+      "name": "Creature"+    }+  }+}
+ test/Feature/Inference/type-guards/resolving/fail/query.gql view
@@ -0,0 +1,6 @@+{+  characters {+    name+    power+  }+}
+ test/Feature/Inference/type-guards/resolving/fail/response.json view
@@ -0,0 +1,8 @@+{+  "errors": [+    {+      "message": "Cannot query field \"power\" on type \"Character\".",+      "locations": [{ "line": 4, "column": 5 }]+    }+  ]+}
+ test/Feature/Inference/type-guards/resolving/success/interface-fields/query.gql view
@@ -0,0 +1,6 @@+{+  characters {+    name+    age+  }+}
+ test/Feature/Inference/type-guards/resolving/success/interface-fields/response.json view
@@ -0,0 +1,8 @@+{+  "data": {+    "characters": [+      { "age": 2000, "name": "Morpheus", "__typename": "Deity" },+      { "age": 205, "name": "Lamia", "__typename": "Creature" }+    ]+  }+}
+ test/Feature/Inference/type-guards/resolving/success/type-casting/query.gql view
@@ -0,0 +1,9 @@+{+  characters {+    name+    age+    ... on Deity {+      power+    }+  }+}
+ test/Feature/Inference/type-guards/resolving/success/type-casting/response.json view
@@ -0,0 +1,17 @@+{+  "data": {+    "characters": [+      {+        "__typename": "Deity",+        "name": "Morpheus",+        "power": "Shapeshift",+        "age": 2000+      },+      {+        "__typename": "Creature",+        "name": "Lamia",+        "age": 205+      }+    ]+  }+}
+ test/Feature/Inference/type-inference/introspection/enum/query.gql view
@@ -0,0 +1,76 @@+query Get__Type {+  __type(name: "Power") {+    ...FullType+  }+}++fragment FullType on __Type {+  kind+  name+  fields(includeDeprecated: true) {+    name+    args {+      ...InputValue+    }+    type {+      ...TypeRef+    }+    isDeprecated+    deprecationReason+  }+  inputFields {+    ...InputValue+  }+  interfaces {+    ...TypeRef+  }+  enumValues(includeDeprecated: true) {+    name+    isDeprecated+    deprecationReason+  }+  possibleTypes {+    ...TypeRef+  }+}++fragment InputValue on __InputValue {+  name+  type {+    ...TypeRef+  }+  defaultValue+}++fragment TypeRef on __Type {+  kind+  name+  ofType {+    kind+    name+    ofType {+      kind+      name+      ofType {+        kind+        name+        ofType {+          kind+          name+          ofType {+            kind+            name+            ofType {+              kind+              name+              ofType {+                kind+                name+              }+            }+          }+        }+      }+    }+  }+}
+ test/Feature/Inference/type-inference/introspection/enum/response.json view
@@ -0,0 +1,29 @@+{+  "data": {+    "__type": {+      "kind": "ENUM",+      "name": "Power",+      "fields": null,+      "inputFields": null,+      "interfaces": null,+      "enumValues": [+        {+          "name": "Thunderbolts",+          "isDeprecated": false,+          "deprecationReason": null+        },+        {+          "name": "Shapeshift",+          "isDeprecated": false,+          "deprecationReason": null+        },+        {+          "name": "Hurricanes",+          "isDeprecated": false,+          "deprecationReason": null+        }+      ],+      "possibleTypes": null+    }+  }+}
+ test/Feature/Inference/type-inference/introspection/input-union/empty/query.gql view
@@ -0,0 +1,76 @@+query Get__Type {+  __type(name: "Unit") {+    ...FullType+  }+}++fragment FullType on __Type {+  kind+  name+  fields(includeDeprecated: true) {+    name+    args {+      ...InputValue+    }+    type {+      ...TypeRef+    }+    isDeprecated+    deprecationReason+  }+  inputFields {+    ...InputValue+  }+  interfaces {+    ...TypeRef+  }+  enumValues(includeDeprecated: true) {+    name+    isDeprecated+    deprecationReason+  }+  possibleTypes {+    ...TypeRef+  }+}++fragment InputValue on __InputValue {+  name+  type {+    ...TypeRef+  }+  defaultValue+}++fragment TypeRef on __Type {+  kind+  name+  ofType {+    kind+    name+    ofType {+      kind+      name+      ofType {+        kind+        name+        ofType {+          kind+          name+          ofType {+            kind+            name+            ofType {+              kind+              name+              ofType {+                kind+                name+              }+            }+          }+        }+      }+    }+  }+}
+ test/Feature/Inference/type-inference/introspection/input-union/empty/response.json view
@@ -0,0 +1,19 @@+{+  "data": {+    "__type": {+      "kind": "ENUM",+      "name": "Unit",+      "fields": null,+      "inputFields": null,+      "interfaces": null,+      "enumValues": [+        {+          "name": "Unit",+          "isDeprecated": false,+          "deprecationReason": null+        }+      ],+      "possibleTypes": null+    }+  }+}
+ test/Feature/Inference/type-inference/introspection/input-union/input-union/query.gql view
@@ -0,0 +1,76 @@+query Get__Type {+  __type(name: "Monster") {+    ...FullType+  }+}++fragment FullType on __Type {+  kind+  name+  fields(includeDeprecated: true) {+    name+    args {+      ...InputValue+    }+    type {+      ...TypeRef+    }+    isDeprecated+    deprecationReason+  }+  inputFields {+    ...InputValue+  }+  interfaces {+    ...TypeRef+  }+  enumValues(includeDeprecated: true) {+    name+    isDeprecated+    deprecationReason+  }+  possibleTypes {+    ...TypeRef+  }+}++fragment InputValue on __InputValue {+  name+  type {+    ...TypeRef+  }+  defaultValue+}++fragment TypeRef on __Type {+  kind+  name+  ofType {+    kind+    name+    ofType {+      kind+      name+      ofType {+        kind+        name+        ofType {+          kind+          name+          ofType {+            kind+            name+            ofType {+              kind+              name+              ofType {+                kind+                name+              }+            }+          }+        }+      }+    }+  }+}
+ test/Feature/Inference/type-inference/introspection/input-union/input-union/response.json view
@@ -0,0 +1,41 @@+{+  "data": {+    "__type": {+      "kind": "INPUT_OBJECT",+      "name": "Monster",+      "fields": null,+      "inputFields": [+        {+          "name": "Hydra",+          "type": {+            "kind": "INPUT_OBJECT",+            "name": "Hydra",+            "ofType": null+          },+          "defaultValue": null+        },+        {+          "name": "Cerberus",+          "type": {+            "kind": "INPUT_OBJECT",+            "name": "Cerberus",+            "ofType": null+          },+          "defaultValue": null+        },+        {+          "name": "UnidentifiedMonster",+          "type": {+            "kind": "ENUM",+            "name": "Unit",+            "ofType": null+          },+          "defaultValue": null+        }+      ],+      "interfaces": null,+      "enumValues": null,+      "possibleTypes": null+    }+  }+}
+ test/Feature/Inference/type-inference/introspection/inputObject/query.gql view
@@ -0,0 +1,76 @@+query Get__Type {+  __type(name: "Hydra") {+    ...FullType+  }+}++fragment FullType on __Type {+  kind+  name+  fields(includeDeprecated: true) {+    name+    args {+      ...InputValue+    }+    type {+      ...TypeRef+    }+    isDeprecated+    deprecationReason+  }+  inputFields {+    ...InputValue+  }+  interfaces {+    ...TypeRef+  }+  enumValues(includeDeprecated: true) {+    name+    isDeprecated+    deprecationReason+  }+  possibleTypes {+    ...TypeRef+  }+}++fragment InputValue on __InputValue {+  name+  type {+    ...TypeRef+  }+  defaultValue+}++fragment TypeRef on __Type {+  kind+  name+  ofType {+    kind+    name+    ofType {+      kind+      name+      ofType {+        kind+        name+        ofType {+          kind+          name+          ofType {+            kind+            name+            ofType {+              kind+              name+              ofType {+                kind+                name+              }+            }+          }+        }+      }+    }+  }+}
+ test/Feature/Inference/type-inference/introspection/inputObject/response.json view
@@ -0,0 +1,32 @@+{+  "data": {+    "__type": {+      "kind": "INPUT_OBJECT",+      "name": "Hydra",+      "fields": null,+      "inputFields": [+        {+          "name": "name",+          "type": {+            "kind": "NON_NULL",+            "name": null,+            "ofType": { "kind": "SCALAR", "name": "String", "ofType": null }+          },+          "defaultValue": null+        },+        {+          "name": "age",+          "type": {+            "kind": "NON_NULL",+            "name": null,+            "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null }+          },+          "defaultValue": null+        }+      ],+      "interfaces": null,+      "enumValues": null,+      "possibleTypes": null+    }+  }+}
+ test/Feature/Inference/type-inference/introspection/object/query.gql view
@@ -0,0 +1,76 @@+query Get__Type {+  __type(name: "Deity") {+    ...FullType+  }+}++fragment FullType on __Type {+  kind+  name+  fields(includeDeprecated: true) {+    name+    args {+      ...InputValue+    }+    type {+      ...TypeRef+    }+    isDeprecated+    deprecationReason+  }+  inputFields {+    ...InputValue+  }+  interfaces {+    ...TypeRef+  }+  enumValues(includeDeprecated: true) {+    name+    isDeprecated+    deprecationReason+  }+  possibleTypes {+    ...TypeRef+  }+}++fragment InputValue on __InputValue {+  name+  type {+    ...TypeRef+  }+  defaultValue+}++fragment TypeRef on __Type {+  kind+  name+  ofType {+    kind+    name+    ofType {+      kind+      name+      ofType {+        kind+        name+        ofType {+          kind+          name+          ofType {+            kind+            name+            ofType {+              kind+              name+              ofType {+                kind+                name+              }+            }+          }+        }+      }+    }+  }+}
+ test/Feature/Inference/type-inference/introspection/object/response.json view
@@ -0,0 +1,36 @@+{+  "data": {+    "__type": {+      "kind": "OBJECT",+      "name": "Deity",+      "fields": [+        {+          "name": "name",+          "args": [],+          "type": {+            "kind": "NON_NULL",+            "name": null,+            "ofType": { "kind": "SCALAR", "name": "String", "ofType": null }+          },+          "isDeprecated": false,+          "deprecationReason": null+        },+        {+          "name": "power",+          "args": [],+          "type": {+            "kind": "NON_NULL",+            "name": null,+            "ofType": { "kind": "ENUM", "name": "Power", "ofType": null }+          },+          "isDeprecated": false,+          "deprecationReason": null+        }+      ],+      "inputFields": null,+      "interfaces": [],+      "enumValues": null,+      "possibleTypes": null+    }+  }+}
+ test/Feature/Inference/type-inference/introspection/union/named-products/query.gql view
@@ -0,0 +1,82 @@+query Get__Type {+  creature: __type(name: "Creature") {+    ...FullType+  }+  boxedDeity: __type(name: "BoxedDeity") {+    ...FullType+  }+  scalarRecord: __type(name: "ScalarRecord") {+    ...FullType+  }+}++fragment FullType on __Type {+  kind+  name+  fields(includeDeprecated: true) {+    name+    args {+      ...InputValue+    }+    type {+      ...TypeRef+    }+    isDeprecated+    deprecationReason+  }+  inputFields {+    ...InputValue+  }+  interfaces {+    ...TypeRef+  }+  enumValues(includeDeprecated: true) {+    name+    isDeprecated+    deprecationReason+  }+  possibleTypes {+    ...TypeRef+  }+}++fragment InputValue on __InputValue {+  name+  type {+    ...TypeRef+  }+  defaultValue+}++fragment TypeRef on __Type {+  kind+  name+  ofType {+    kind+    name+    ofType {+      kind+      name+      ofType {+        kind+        name+        ofType {+          kind+          name+          ofType {+            kind+            name+            ofType {+              kind+              name+              ofType {+                kind+                name+              }+            }+          }+        }+      }+    }+  }+}
+ test/Feature/Inference/type-inference/introspection/union/named-products/response.json view
@@ -0,0 +1,78 @@+{+  "data": {+    "creature": {+      "kind": "OBJECT",+      "name": "Creature",+      "fields": [+        {+          "name": "creatureName",+          "args": [],+          "type": {+            "kind": "NON_NULL",+            "name": null,+            "ofType": { "kind": "SCALAR", "name": "String", "ofType": null }+          },+          "isDeprecated": false,+          "deprecationReason": null+        },+        {+          "name": "creatureAge",+          "args": [],+          "type": {+            "kind": "NON_NULL",+            "name": null,+            "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null }+          },+          "isDeprecated": false,+          "deprecationReason": null+        }+      ],+      "inputFields": null,+      "interfaces": [],+      "enumValues": null,+      "possibleTypes": null+    },+    "boxedDeity": {+      "kind": "OBJECT",+      "name": "BoxedDeity",+      "fields": [+        {+          "name": "boxedDeity",+          "args": [],+          "type": {+            "kind": "NON_NULL",+            "name": null,+            "ofType": { "kind": "OBJECT", "name": "Deity", "ofType": null }+          },+          "isDeprecated": false,+          "deprecationReason": null+        }+      ],+      "inputFields": null,+      "interfaces": [],+      "enumValues": null,+      "possibleTypes": null+    },+    "scalarRecord": {+      "kind": "OBJECT",+      "name": "ScalarRecord",+      "fields": [+        {+          "name": "scalarText",+          "args": [],+          "type": {+            "kind": "NON_NULL",+            "name": null,+            "ofType": { "kind": "SCALAR", "name": "String", "ofType": null }+          },+          "isDeprecated": false,+          "deprecationReason": null+        }+      ],+      "inputFields": null,+      "interfaces": [],+      "enumValues": null,+      "possibleTypes": null+    }+  }+}
+ test/Feature/Inference/type-inference/introspection/union/nullary-constructors/query.gql view
@@ -0,0 +1,82 @@+query Get__Type {+  zeus: __type(name: "Zeus") {+    ...FullType+  }+  cronus: __type(name: "Cronus") {+    ...FullType+  }+  empty: __type(name: "Unit") {+    ...FullType+  }+}++fragment FullType on __Type {+  kind+  name+  fields(includeDeprecated: true) {+    name+    args {+      ...InputValue+    }+    type {+      ...TypeRef+    }+    isDeprecated+    deprecationReason+  }+  inputFields {+    ...InputValue+  }+  interfaces {+    ...TypeRef+  }+  enumValues(includeDeprecated: true) {+    name+    isDeprecated+    deprecationReason+  }+  possibleTypes {+    ...TypeRef+  }+}++fragment InputValue on __InputValue {+  name+  type {+    ...TypeRef+  }+  defaultValue+}++fragment TypeRef on __Type {+  kind+  name+  ofType {+    kind+    name+    ofType {+      kind+      name+      ofType {+        kind+        name+        ofType {+          kind+          name+          ofType {+            kind+            name+            ofType {+              kind+              name+              ofType {+                kind+                name+              }+            }+          }+        }+      }+    }+  }+}
+ test/Feature/Inference/type-inference/introspection/union/nullary-constructors/response.json view
@@ -0,0 +1,69 @@+{+  "data": {+    "zeus": {+      "kind": "OBJECT",+      "name": "Zeus",+      "fields": [+        {+          "name": "_",+          "args": [],+          "type": {+            "kind": "NON_NULL",+            "name": null,+            "ofType": {+              "kind": "ENUM",+              "name": "Unit",+              "ofType": null+            }+          },+          "isDeprecated": false,+          "deprecationReason": null+        }+      ],+      "inputFields": null,+      "interfaces": [],+      "enumValues": null,+      "possibleTypes": null+    },+    "cronus": {+      "kind": "OBJECT",+      "name": "Cronus",+      "fields": [+        {+          "name": "_",+          "args": [],+          "type": {+            "kind": "NON_NULL",+            "name": null,+            "ofType": {+              "kind": "ENUM",+              "name": "Unit",+              "ofType": null+            }+          },+          "isDeprecated": false,+          "deprecationReason": null+        }+      ],+      "inputFields": null,+      "interfaces": [],+      "enumValues": null,+      "possibleTypes": null+    },+    "empty": {+      "kind": "ENUM",+      "name": "Unit",+      "fields": null,+      "inputFields": null,+      "interfaces": null,+      "enumValues": [+        {+          "name": "Unit",+          "isDeprecated": false,+          "deprecationReason": null+        }+      ],+      "possibleTypes": null+    }+  }+}
+ test/Feature/Inference/type-inference/introspection/union/positional-products/query.gql view
@@ -0,0 +1,79 @@+query Get__Type {+  someDeity: __type(name: "SomeDeity") {+    ...FullType+  }+  someCompound: __type(name: "SomeCompound") {+    ...FullType+  }+}++fragment FullType on __Type {+  kind+  name+  fields(includeDeprecated: true) {+    name+    args {+      ...InputValue+    }+    type {+      ...TypeRef+    }+    isDeprecated+    deprecationReason+  }+  inputFields {+    ...InputValue+  }+  interfaces {+    ...TypeRef+  }+  enumValues(includeDeprecated: true) {+    name+    isDeprecated+    deprecationReason+  }+  possibleTypes {+    ...TypeRef+  }+}++fragment InputValue on __InputValue {+  name+  type {+    ...TypeRef+  }+  defaultValue+}++fragment TypeRef on __Type {+  kind+  name+  ofType {+    kind+    name+    ofType {+      kind+      name+      ofType {+        kind+        name+        ofType {+          kind+          name+          ofType {+            kind+            name+            ofType {+              kind+              name+              ofType {+                kind+                name+              }+            }+          }+        }+      }+    }+  }+}
+ test/Feature/Inference/type-inference/introspection/union/positional-products/response.json view
@@ -0,0 +1,57 @@+{+  "data": {+    "someDeity": {+      "kind": "OBJECT",+      "name": "SomeDeity",+      "fields": [+        {+          "name": "_0",+          "args": [],+          "type": {+            "kind": "NON_NULL",+            "name": null,+            "ofType": { "kind": "OBJECT", "name": "Deity", "ofType": null }+          },+          "isDeprecated": false,+          "deprecationReason": null+        }+      ],+      "inputFields": null,+      "interfaces": [],+      "enumValues": null,+      "possibleTypes": null+    },+    "someCompound": {+      "kind": "OBJECT",+      "name": "SomeCompound",+      "fields": [+        {+          "name": "_0",+          "args": [],+          "type": {+            "kind": "NON_NULL",+            "name": null,+            "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null }+          },+          "isDeprecated": false,+          "deprecationReason": null+        },+        {+          "name": "_1",+          "args": [],+          "type": {+            "kind": "NON_NULL",+            "name": null,+            "ofType": { "kind": "SCALAR", "name": "String", "ofType": null }+          },+          "isDeprecated": false,+          "deprecationReason": null+        }+      ],+      "inputFields": null,+      "interfaces": [],+      "enumValues": null,+      "possibleTypes": null+    }+  }+}
+ test/Feature/Inference/type-inference/introspection/union/scalars/query.gql view
@@ -0,0 +1,76 @@+query Get__Type {+  __type(name: "CharacterAge") {+    ...FullType+  }+}++fragment FullType on __Type {+  kind+  name+  fields(includeDeprecated: true) {+    name+    args {+      ...InputValue+    }+    type {+      ...TypeRef+    }+    isDeprecated+    deprecationReason+  }+  inputFields {+    ...InputValue+  }+  interfaces {+    ...TypeRef+  }+  enumValues(includeDeprecated: true) {+    name+    isDeprecated+    deprecationReason+  }+  possibleTypes {+    ...TypeRef+  }+}++fragment InputValue on __InputValue {+  name+  type {+    ...TypeRef+  }+  defaultValue+}++fragment TypeRef on __Type {+  kind+  name+  ofType {+    kind+    name+    ofType {+      kind+      name+      ofType {+        kind+        name+        ofType {+          kind+          name+          ofType {+            kind+            name+            ofType {+              kind+              name+              ofType {+                kind+                name+              }+            }+          }+        }+      }+    }+  }+}
+ test/Feature/Inference/type-inference/introspection/union/scalars/response.json view
@@ -0,0 +1,25 @@+{+  "data": {+    "__type": {+      "kind": "OBJECT",+      "name": "CharacterAge",+      "fields": [+        {+          "name": "_0",+          "args": [],+          "type": {+            "kind": "NON_NULL",+            "name": null,+            "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null }+          },+          "isDeprecated": false,+          "deprecationReason": null+        }+      ],+      "inputFields": null,+      "interfaces": [],+      "enumValues": null,+      "possibleTypes": null+    }+  }+}
+ test/Feature/Inference/type-inference/introspection/union/union/query.gql view
@@ -0,0 +1,76 @@+query Get__Type {+  __type(name: "Character") {+    ...FullType+  }+}++fragment FullType on __Type {+  kind+  name+  fields(includeDeprecated: true) {+    name+    args {+      ...InputValue+    }+    type {+      ...TypeRef+    }+    isDeprecated+    deprecationReason+  }+  inputFields {+    ...InputValue+  }+  interfaces {+    ...TypeRef+  }+  enumValues(includeDeprecated: true) {+    name+    isDeprecated+    deprecationReason+  }+  possibleTypes {+    ...TypeRef+  }+}++fragment InputValue on __InputValue {+  name+  type {+    ...TypeRef+  }+  defaultValue+}++fragment TypeRef on __Type {+  kind+  name+  ofType {+    kind+    name+    ofType {+      kind+      name+      ofType {+        kind+        name+        ofType {+          kind+          name+          ofType {+            kind+            name+            ofType {+              kind+              name+              ofType {+                kind+                name+              }+            }+          }+        }+      }+    }+  }+}
+ test/Feature/Inference/type-inference/introspection/union/union/response.json view
@@ -0,0 +1,23 @@+{+  "data": {+    "__type": {+      "kind": "UNION",+      "name": "Character",+      "fields": null,+      "inputFields": null,+      "interfaces": null,+      "enumValues": null,+      "possibleTypes": [+        { "kind": "OBJECT", "name": "Deity", "ofType": null },+        { "kind": "OBJECT", "name": "Creature", "ofType": null },+        { "kind": "OBJECT", "name": "BoxedDeity", "ofType": null },+        { "kind": "OBJECT", "name": "ScalarRecord", "ofType": null },+        { "kind": "OBJECT", "name": "CharacterAge", "ofType": null },+        { "kind": "OBJECT", "name": "SomeDeity", "ofType": null },+        { "kind": "OBJECT", "name": "SomeCompound", "ofType": null },+        { "kind": "OBJECT", "name": "Zeus", "ofType": null },+        { "kind": "OBJECT", "name": "Cronus", "ofType": null }+      ]+    }+  }+}
+ test/Feature/Inference/type-inference/introspection/unit/query.gql view
@@ -0,0 +1,79 @@+query Get__Type {+  unitType: __type(name: "Unit") {+    ...FullType+  }+  unitField: __type(name: "Query") {+    ...FullType+  }+}++fragment FullType on __Type {+  kind+  name+  fields(includeDeprecated: true) {+    name+    args {+      ...InputValue+    }+    type {+      ...TypeRef+    }+    isDeprecated+    deprecationReason+  }+  inputFields {+    ...InputValue+  }+  interfaces {+    ...TypeRef+  }+  enumValues(includeDeprecated: true) {+    name+    isDeprecated+    deprecationReason+  }+  possibleTypes {+    ...TypeRef+  }+}++fragment InputValue on __InputValue {+  name+  type {+    ...TypeRef+  }+  defaultValue+}++fragment TypeRef on __Type {+  kind+  name+  ofType {+    kind+    name+    ofType {+      kind+      name+      ofType {+        kind+        name+        ofType {+          kind+          name+          ofType {+            kind+            name+            ofType {+              kind+              name+              ofType {+                kind+                name+              }+            }+          }+        }+      }+    }+  }+}
+ test/Feature/Inference/type-inference/introspection/unit/response.json view
@@ -0,0 +1,103 @@+{+  "data": {+    "unitField": {+      "enumValues": null,+      "fields": [+        {+          "args": [],+          "deprecationReason": null,+          "isDeprecated": false,+          "name": "deity",+          "type": {+            "kind": "NON_NULL",+            "name": null,+            "ofType": {+              "kind": "OBJECT",+              "name": "Deity",+              "ofType": null+            }+          }+        },+        {+          "args": [],+          "deprecationReason": null,+          "isDeprecated": false,+          "name": "character",+          "type": {+            "kind": "NON_NULL",+            "name": null,+            "ofType": {+              "kind": "LIST",+              "name": null,+              "ofType": {+                "kind": "NON_NULL",+                "name": null,+                "ofType": {+                  "kind": "UNION",+                  "name": "Character",+                  "ofType": null+                }+              }+            }+          }+        },+        {+          "args": [+            {+              "defaultValue": null,+              "name": "monster",+              "type": {+                "kind": "NON_NULL",+                "name": null,+                "ofType": {+                  "kind": "INPUT_OBJECT",+                  "name": "Monster",+                  "ofType": null+                }+              }+            }+          ],+          "deprecationReason": null,+          "isDeprecated": false,+          "name": "showMonster",+          "type": {+            "kind": "NON_NULL",+            "name": null,+            "ofType": { "kind": "SCALAR", "name": "String", "ofType": null }+          }+        },+        {+          "args": [],+          "deprecationReason": null,+          "isDeprecated": false,+          "name": "unitType",+          "type": {+            "kind": "NON_NULL",+            "name": null,+            "ofType": { "kind": "ENUM", "name": "Unit", "ofType": null }+          }+        }+      ],+      "inputFields": null,+      "interfaces": [],+      "kind": "OBJECT",+      "name": "Query",+      "possibleTypes": null+    },+    "unitType": {+      "enumValues": [+        {+          "deprecationReason": null,+          "isDeprecated": false,+          "name": "Unit"+        }+      ],+      "fields": null,+      "inputFields": null,+      "interfaces": null,+      "kind": "ENUM",+      "name": "Unit",+      "possibleTypes": null+    }+  }+}
+ test/Feature/Inference/type-inference/resolving/complexUnion/query.gql view
@@ -0,0 +1,44 @@+{+  character {+    ## regular union+    __typename+    ... on Deity {+      name+    }++    ... on Creature {+      creatureName+      creatureAge+    }++    ... on BoxedDeity {+      boxedDeity {+        power+      }+    }++    ... on ScalarRecord {+      scalarText+    }++    ... on CharacterAge {+      _0+    }++    ... on SomeDeity {+      _0 {+        name+        power+      }+    }++    ... on SomeCompound {+      _0+      _1+    }++    ... on Zeus {+      _+    }+  }+}
+ test/Feature/Inference/type-inference/resolving/complexUnion/response.json view
@@ -0,0 +1,43 @@+{+  "data": {+    "character": [+      {+        "__typename": "Deity",+        "name": "Morpheus"+      },+      {+        "__typename": "Creature",+        "creatureName": "Lamia",+        "creatureAge": 205+      },+      {+        "__typename": "BoxedDeity",+        "boxedDeity": { "power": "Shapeshift" }+      },+      {+        "__typename": "ScalarRecord",+        "scalarText": "Some Text"+      },+      {+        "__typename": "SomeDeity",+        "_0": { "name": "Morpheus", "power": "Shapeshift" }+      },+      {+        "__typename": "CharacterAge",+        "_0": 12+      },+      {+        "__typename": "SomeCompound",+        "_0": 21,+        "_1": "some text"+      },+      {+        "__typename": "Zeus",+        "_": "Unit"+      },+      {+        "__typename": "Cronus"+      }+    ]+  }+}
+ test/Feature/Inference/type-inference/resolving/input/fail/query.gql view
@@ -0,0 +1,6 @@+{+  empty: showMonster(monster: {})+  multiple: showMonster(+    monster: { Hydra: { name: "someName", age: 12 }, UnidentifiedMonster: Unit }+  )+}
+ test/Feature/Inference/type-inference/resolving/input/fail/response.json view
@@ -0,0 +1,12 @@+{+  "errors": [+    {+      "message": "Argument \"monster\" got invalid value. Expected type \"Monster!\" found {}. Exclusive input objects must provide a value for at least one field.",+      "locations": [{ "line": 2, "column": 22 }]+    },+    {+      "message": "Argument \"monster\" got invalid value. Expected type \"Monster!\" found { Hydra: { name: \"someName\", age: 12 }, UnidentifiedMonster: Unit }. Exclusive input objects are not allowed to provide values for multiple fields.",+      "locations": [{ "line": 4, "column": 5 }]+    }+  ]+}
+ test/Feature/Inference/type-inference/resolving/input/success/query.gql view
@@ -0,0 +1,5 @@+{+  object: showMonster(monster: { Hydra: { name: "someName", age: 12 } })+  record: showMonster(monster: { Cerberus: { name: "someName" } })+  enum: showMonster(monster: { UnidentifiedMonster: Unit })+}
+ test/Feature/Inference/type-inference/resolving/input/success/response.json view
@@ -0,0 +1,7 @@+{+  "data": {+    "object": "MonsterHydra (Hydra {name = \"someName\", age = 12})",+    "record": "Cerberus {name = \"someName\"}",+    "enum": "UnidentifiedMonster"+  }+}
+ test/Feature/Inference/type-inference/resolving/object/query.gql view
@@ -0,0 +1,6 @@+{+  deity {+    name+    power+  }+}
+ test/Feature/Inference/type-inference/resolving/object/response.json view
@@ -0,0 +1,1 @@+{ "data": { "deity": { "name": "Morpheus", "power": "Shapeshift" } } }
+ test/Feature/Inference/union-type/cannotBeSpreadOnType/query.gql view
@@ -0,0 +1,9 @@+{+  union {+    ...FC+  }+}++fragment FC on C {+  cText+}
+ test/Feature/Inference/union-type/cannotBeSpreadOnType/response.json view
@@ -0,0 +1,13 @@+{+  "errors": [+    {+      "message": "Fragment \"FC\" cannot be spread here as objects of type \"A\", \"B\" can never be of type \"C\".",+      "locations": [+        {+          "line": 3,+          "column": 5+        }+      ]+    }+  ]+}
+ test/Feature/Inference/union-type/fragmentOnAAndB/query.gql view
@@ -0,0 +1,15 @@+{+  union {+    __typename+    ...FA+    ...FB+  }+}++fragment FA on A {+  aText+}++fragment FB on B {+  bText+}
+ test/Feature/Inference/union-type/fragmentOnAAndB/response.json view
@@ -0,0 +1,14 @@+{+  "data": {+    "union": [+      {+        "__typename": "A",+        "aText": "at"+      },+      {+        "__typename": "B",+        "bText": "bt"+      }+    ]+  }+}
+ test/Feature/Inference/union-type/fragmentOnlyOnA/query.gql view
@@ -0,0 +1,9 @@+{+  union {+    ...FA+  }+}++fragment FA on A {+  aText+}
+ test/Feature/Inference/union-type/fragmentOnlyOnA/response.json view
@@ -0,0 +1,13 @@+{+  "data": {+    "union": [+      {+        "aText": "at",+        "__typename": "A"+      },+      {+        "__typename": "B"+      }+    ]+  }+}
+ test/Feature/Inference/union-type/inlineFragment/cannotBeSpreadOnType/query.gql view
@@ -0,0 +1,7 @@+{+  union {+    ... on C {+      aText+    }+  }+}
+ test/Feature/Inference/union-type/inlineFragment/cannotBeSpreadOnType/response.json view
@@ -0,0 +1,8 @@+{+  "errors": [+    {+      "message": "Fragment cannot be spread here as objects of type \"A\", \"B\" can never be of type \"C\".",+      "locations": [{ "line": 3, "column": 5 }]+    }+  ]+}
+ test/Feature/Inference/union-type/inlineFragment/fragmentOnAAndB/query.gql view
@@ -0,0 +1,11 @@+{+  union {+    __typename+    ... on A {+      aText+    }+    ... on B {+      bText+    }+  }+}
+ test/Feature/Inference/union-type/inlineFragment/fragmentOnAAndB/response.json view
@@ -0,0 +1,14 @@+{+  "data": {+    "union": [+      {+        "__typename": "A",+        "aText": "at"+      },+      {+        "__typename": "B",+        "bText": "bt"+      }+    ]+  }+}
+ test/Feature/Inference/union-type/selectionWithoutFragmentNotAllowed/query.gql view
@@ -0,0 +1,10 @@+{+  union {+    ...FA+    aText+  }+}++fragment FA on A {+  aText+}
+ test/Feature/Inference/union-type/selectionWithoutFragmentNotAllowed/response.json view
@@ -0,0 +1,13 @@+{+  "errors": [+    {+      "message": "Cannot query field \"aText\" on type \"Sum\".",+      "locations": [+        {+          "line": 4,+          "column": 5+        }+      ]+    }+  ]+}
+ test/Feature/Inference/wrapped-type/ignoreMutationResolver/query.gql view
@@ -0,0 +1,76 @@+query Get__Type {+  __type(name: "Mutation") {+    ...FullType+  }+}++fragment FullType on __Type {+  kind+  name+  fields(includeDeprecated: true) {+    name+    args {+      ...InputValue+    }+    type {+      ...TypeRef+    }+    isDeprecated+    deprecationReason+  }+  inputFields {+    ...InputValue+  }+  interfaces {+    ...TypeRef+  }+  enumValues(includeDeprecated: true) {+    name+    isDeprecated+    deprecationReason+  }+  possibleTypes {+    ...TypeRef+  }+}++fragment InputValue on __InputValue {+  name+  type {+    ...TypeRef+  }+  defaultValue+}++fragment TypeRef on __Type {+  kind+  name+  ofType {+    kind+    name+    ofType {+      kind+      name+      ofType {+        kind+        name+        ofType {+          kind+          name+          ofType {+            kind+            name+            ofType {+              kind+              name+              ofType {+                kind+                name+              }+            }+          }+        }+      }+    }+  }+}
+ test/Feature/Inference/wrapped-type/ignoreMutationResolver/response.json view
@@ -0,0 +1,47 @@+{+  "data": {+    "__type": {+      "kind": "OBJECT",+      "name": "Mutation",+      "fields": [+        {+          "name": "mut1",+          "args": [],+          "type": {+            "kind": "OBJECT",+            "name": "WA",+            "ofType": null+          },+          "isDeprecated": false,+          "deprecationReason": null+        },+        {+          "name": "mut2",+          "args": [],+          "type": {+            "kind": "OBJECT",+            "name": "WrappedIntInt",+            "ofType": null+          },+          "isDeprecated": false,+          "deprecationReason": null+        },+        {+          "name": "mut3",+          "args": [],+          "type": {+            "kind": "OBJECT",+            "name": "WrappedWrappedTextIntText",+            "ofType": null+          },+          "isDeprecated": false,+          "deprecationReason": null+        }+      ],+      "inputFields": null,+      "interfaces": [],+      "enumValues": null,+      "possibleTypes": null+    }+  }+}
+ test/Feature/Inference/wrapped-type/ignoreQueryResolver/query.gql view
@@ -0,0 +1,76 @@+query Get__Type {+  __type(name: "Query") {+    ...FullType+  }+}++fragment FullType on __Type {+  kind+  name+  fields(includeDeprecated: true) {+    name+    args {+      ...InputValue+    }+    type {+      ...TypeRef+    }+    isDeprecated+    deprecationReason+  }+  inputFields {+    ...InputValue+  }+  interfaces {+    ...TypeRef+  }+  enumValues(includeDeprecated: true) {+    name+    isDeprecated+    deprecationReason+  }+  possibleTypes {+    ...TypeRef+  }+}++fragment InputValue on __InputValue {+  name+  type {+    ...TypeRef+  }+  defaultValue+}++fragment TypeRef on __Type {+  kind+  name+  ofType {+    kind+    name+    ofType {+      kind+      name+      ofType {+        kind+        name+        ofType {+          kind+          name+          ofType {+            kind+            name+            ofType {+              kind+              name+              ofType {+                kind+                name+              }+            }+          }+        }+      }+    }+  }+}
+ test/Feature/Inference/wrapped-type/ignoreQueryResolver/response.json view
@@ -0,0 +1,51 @@+{+  "data": {+    "__type": {+      "kind": "OBJECT",+      "name": "Query",+      "fields": [+        {+          "name": "a1",+          "args": [],+          "type": {+            "kind": "NON_NULL",+            "name": null,+            "ofType": {+              "kind": "OBJECT",+              "name": "WA",+              "ofType": null+            }+          },+          "isDeprecated": false,+          "deprecationReason": null+        },+        {+          "name": "a2",+          "args": [],+          "type": {+            "kind": "OBJECT",+            "name": "WrappedIntInt",+            "ofType": null+          },+          "isDeprecated": false,+          "deprecationReason": null+        },+        {+          "name": "a3",+          "args": [],+          "type": {+            "kind": "OBJECT",+            "name": "WrappedWrappedTextIntText",+            "ofType": null+          },+          "isDeprecated": false,+          "deprecationReason": null+        }+      ],+      "inputFields": null,+      "interfaces": [],+      "enumValues": null,+      "possibleTypes": null+    }+  }+}
+ test/Feature/Inference/wrapped-type/ignoreSubscriptionResolver/query.gql view
@@ -0,0 +1,76 @@+query Get__Type {+  __type(name: "Subscription") {+    ...FullType+  }+}++fragment FullType on __Type {+  kind+  name+  fields(includeDeprecated: true) {+    name+    args {+      ...InputValue+    }+    type {+      ...TypeRef+    }+    isDeprecated+    deprecationReason+  }+  inputFields {+    ...InputValue+  }+  interfaces {+    ...TypeRef+  }+  enumValues(includeDeprecated: true) {+    name+    isDeprecated+    deprecationReason+  }+  possibleTypes {+    ...TypeRef+  }+}++fragment InputValue on __InputValue {+  name+  type {+    ...TypeRef+  }+  defaultValue+}++fragment TypeRef on __Type {+  kind+  name+  ofType {+    kind+    name+    ofType {+      kind+      name+      ofType {+        kind+        name+        ofType {+          kind+          name+          ofType {+            kind+            name+            ofType {+              kind+              name+              ofType {+                kind+                name+              }+            }+          }+        }+      }+    }+  }+}
+ test/Feature/Inference/wrapped-type/ignoreSubscriptionResolver/response.json view
@@ -0,0 +1,47 @@+{+  "data": {+    "__type": {+      "kind": "OBJECT",+      "name": "Subscription",+      "fields": [+        {+          "name": "sub1",+          "args": [],+          "type": {+            "kind": "OBJECT",+            "name": "WA",+            "ofType": null+          },+          "isDeprecated": false,+          "deprecationReason": null+        },+        {+          "name": "sub2",+          "args": [],+          "type": {+            "kind": "OBJECT",+            "name": "WrappedIntInt",+            "ofType": null+          },+          "isDeprecated": false,+          "deprecationReason": null+        },+        {+          "name": "sub3",+          "args": [],+          "type": {+            "kind": "OBJECT",+            "name": "WrappedWrappedTextIntText",+            "ofType": null+          },+          "isDeprecated": false,+          "deprecationReason": null+        }+      ],+      "inputFields": null,+      "interfaces": [],+      "enumValues": null,+      "possibleTypes": null+    }+  }+}
+ test/Feature/Inference/wrapped-type/validWrappedTypes/query.gql view
@@ -0,0 +1,5 @@+{+  a1 {+    aText+  }+}
+ test/Feature/Inference/wrapped-type/validWrappedTypes/response.json view
@@ -0,0 +1,7 @@+{+  "data": {+    "a1": {+      "aText": "test1"+    }+  }+}
+ test/Feature/Input/Collections.hs view
@@ -0,0 +1,79 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DeriveAnyClass #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE TypeFamilies #-}++module Feature.Input.Collections+  ( api,+  )+where++import Data.List.NonEmpty (NonEmpty)+import Data.Map (Map)+import Data.Morpheus.Server (deriveApp, runApp)+import Data.Morpheus.Server.Types+  ( App,+    Arg (..),+    GQLRequest,+    GQLResponse,+    GQLType (..),+    GQLTypeOptions (..),+    RootResolver (..),+    Undefined,+    defaultRootResolver,+  )+import Data.Sequence (Seq)+import Data.Set (Set)+import Data.Text+import Data.Vector (Vector)+import GHC.Generics (Generic)++-- query+testRes :: Applicative m => Arg "value" a -> m a+testRes = pure . argValue++type Coll m a = Arg "value" a -> m a++data Product = Product Text Int Bool (Maybe Double)+  deriving (Generic)++instance GQLType Product where+  typeOptions _ options =+    options+      { typeNameModifier = \isInput name -> if isInput then "Input" <> name else name+      }++-- resolver+data Query m = Query+  { testSet :: Coll m (Set Int),+    testNonEmpty :: Coll m (NonEmpty Int),+    tesSeq :: Coll m (Seq Int),+    testVector :: Coll m (Vector Int),+    testProduct :: Coll m Product,+    testTuple :: Coll m (Text, Int),+    testMap :: Coll m (Map Text Int),+    testAssoc :: Coll m [(Text, Int)]+  }+  deriving (Generic, GQLType)++rootResolver :: RootResolver IO () Query Undefined Undefined+rootResolver =+  defaultRootResolver+    { queryResolver =+        Query+          { testSet = testRes,+            testNonEmpty = testRes,+            tesSeq = testRes,+            testVector = testRes,+            testTuple = testRes,+            testProduct = testRes,+            testMap = testRes,+            testAssoc = testRes+          }+    }++app :: App () IO+app = deriveApp rootResolver++api :: GQLRequest -> IO GQLResponse+api = runApp app
+ test/Feature/Input/Enums.hs view
@@ -0,0 +1,68 @@+{-# LANGUAGE DeriveAnyClass #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE TypeFamilies #-}++module Feature.Input.Enums+  ( api,+  )+where++import Data.Morpheus.Server (interpreter)+import Data.Morpheus.Server.Types+  ( GQLRequest,+    GQLResponse,+    GQLType (..),+    RootResolver (..),+    Undefined,+    defaultRootResolver,+  )+import GHC.Generics (Generic)++data TwoCon+  = LA+  | LB+  deriving (Show, Generic, GQLType)++data ThreeCon+  = T1+  | T2+  | T3+  deriving (Show, Generic, GQLType)++data Level+  = L0+  | L1+  | L2+  | L3+  | L4+  | L5+  | L6+  deriving (Show, Generic, GQLType)++-- types & args+newtype TestArgs a = TestArgs+  { level :: a+  }+  deriving (Generic, Show, GQLType)++-- query+testRes :: Applicative m => TestArgs a -> m a+testRes TestArgs {level} = pure level++-- resolver+data Query m = Query+  { test :: TestArgs Level -> m Level,+    test2 :: TestArgs TwoCon -> m TwoCon,+    test3 :: TestArgs ThreeCon -> m ThreeCon+  }+  deriving (Generic, GQLType)++rootResolver :: RootResolver IO () Query Undefined Undefined+rootResolver =+  defaultRootResolver+    { queryResolver = Query {test = testRes, test2 = testRes, test3 = testRes}+    }++api :: GQLRequest -> IO GQLResponse+api = interpreter rootResolver
+ test/Feature/Input/Objects.hs view
@@ -0,0 +1,56 @@+{-# LANGUAGE DeriveAnyClass #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE TypeFamilies #-}++module Feature.Input.Objects+  ( api,+  )+where++import Data.Morpheus.Server (interpreter)+import Data.Morpheus.Server.Types+  ( GQLRequest,+    GQLResponse,+    GQLType (..),+    RootResolver (..),+    Undefined,+    defaultRootResolver,+  )+import Data.Text+  ( Text,+    pack,+  )+import GHC.Generics (Generic)++data InputObject = InputObject+  { field :: Text,+    nullableField :: Maybe Int,+    recursive :: Maybe InputObject+  }+  deriving (Generic, Show, GQLType)++-- types & args+newtype Arg a = Arg+  { value :: a+  }+  deriving (Generic, Show, GQLType)++-- query+testRes :: Show a => Applicative m => Arg a -> m Text+testRes Arg {value} = pure $ pack $ show value++-- resolver+newtype Query m = Query+  { input :: Arg InputObject -> m Text+  }+  deriving (Generic, GQLType)++rootResolver :: RootResolver IO () Query Undefined Undefined+rootResolver =+  defaultRootResolver+    { queryResolver = Query {input = testRes}+    }++api :: GQLRequest -> IO GQLResponse+api = interpreter rootResolver
+ test/Feature/Input/Scalars.hs view
@@ -0,0 +1,53 @@+{-# LANGUAGE DeriveAnyClass #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE TypeFamilies #-}++module Feature.Input.Scalars+  ( api,+  )+where++import Data.Morpheus.Server (interpreter)+import Data.Morpheus.Server.Types+  ( GQLRequest,+    GQLResponse,+    GQLType,+    RootResolver (..),+    Undefined,+    defaultRootResolver,+  )+import Data.Text (Text)+import GHC.Generics (Generic)++-- types & args+newtype Arg a = Arg+  { value :: a+  }+  deriving (Generic, Show, GQLType)++-- query+testRes :: Applicative m => Arg a -> m a+testRes Arg {value} = pure value++-- resolver+data Query m = Query+  { testFloat :: Arg Double -> m Double,+    testInt :: Arg Int -> m Int,+    testString :: Arg Text -> m Text+  }+  deriving (Generic, GQLType)++rootResolver :: RootResolver IO () Query Undefined Undefined+rootResolver =+  defaultRootResolver+    { queryResolver =+        Query+          { testFloat = testRes,+            testInt = testRes,+            testString = testRes+          }+    }++api :: GQLRequest -> IO GQLResponse+api = interpreter rootResolver
+ test/Feature/Input/Variables.hs view
@@ -0,0 +1,62 @@+{-# LANGUAGE DeriveAnyClass #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TypeFamilies #-}++module Feature.Input.Variables+  ( api,+  )+where++import Data.Kind (Type)+import Data.Morpheus.Server (interpreter)+import Data.Morpheus.Server.Resolvers (ResolverQ)+import Data.Morpheus.Server.Types+  ( GQLRequest,+    GQLResponse,+    GQLType (..),+    RootResolver (..),+    Undefined,+    defaultRootResolver,+  )+import Data.Text (Text)+import GHC.Generics (Generic)++data F1Args = F1Args+  { arg1 :: Text,+    arg2 :: Maybe Int+  }+  deriving (Generic, GQLType)++data F2Args = F2Args+  { argList :: [Text],+    argNestedList :: [Maybe [[Int]]]+  }+  deriving (Generic, GQLType)++data A = A+  { a1 :: F1Args -> ResolverQ () IO Text,+    a2 :: F2Args -> ResolverQ () IO Int+  }+  deriving (Generic, GQLType)++newtype Query (m :: Type -> Type) = Query+  { q1 :: A+  }+  deriving (Generic, GQLType)++rootResolver :: RootResolver IO () Query Undefined Undefined+rootResolver =+  defaultRootResolver+    { queryResolver =+        Query+          { q1 =+              A+                { a1 = const $ return "a1Test",+                  a2 = const $ return 1+                }+          }+    }++api :: GQLRequest -> IO GQLResponse+api = interpreter rootResolver
+ test/Feature/Input/collections/assoc/invalid/query.gql view
@@ -0,0 +1,8 @@+query InvalidAssoc {+  f1: testAssoc(value: {})+  f2: testAssoc(value: 635)+  f3: testAssoc(value: [{ _0: "235" }])+  f4: testAssoc(value: [{ _0: "235", _1: "235235" }])+  f5: testAssoc(value: [{ _0: "235", _1: false }])+  f6: testAssoc(value: [{ _0: "34", _1: 2353 }])+}
+ test/Feature/Input/collections/assoc/invalid/response.json view
@@ -0,0 +1,28 @@+{+  "errors": [+    {+      "message": "Argument \"value\" got invalid value. Expected type \"[InputPairTextInt!]!\" found {}.",+      "locations": [{ "line": 2, "column": 17 }]+    },+    {+      "message": "Argument \"value\" got invalid value. Expected type \"[InputPairTextInt!]!\" found 635.",+      "locations": [{ "line": 3, "column": 17 }]+    },+    {+      "message": "Argument \"value\" got invalid value. Undefined Field \"_1\".",+      "locations": [{ "line": 4, "column": 17 }]+    },+    {+      "message": "Argument \"value\" got invalid value. in field \"_1\": Expected type \"Int!\" found \"235235\".",+      "locations": [{ "line": 5, "column": 17 }]+    },+    {+      "message": "Argument \"value\" got invalid value. in field \"_1\": Expected type \"Int!\" found false.",+      "locations": [{ "line": 6, "column": 17 }]+    },+    {+      "message": "Field \"testAssoc\" of type \"PairTextInt\" must have a selection of subfields",+      "locations": [{ "line": 7, "column": 3 }]+    }+  ]+}
+ test/Feature/Input/collections/assoc/ok/query.gql view
@@ -0,0 +1,19 @@+query ValidAssoc {+  f1: testAssoc(value: []) {+    ...Entry+  }+  f2: testAssoc(+    value: [+      { _0: "zeus", _1: 3468 }+      { _0: "morpheus", _1: 4236 }+      { _0: "cronos", _1: 547 }+    ]+  ) {+    ...Entry+  }+}++fragment Entry on PairTextInt {+  _0+  _1+}
+ test/Feature/Input/collections/assoc/ok/response.json view
@@ -0,0 +1,10 @@+{+  "data": {+    "f2": [+      { "_0": "zeus", "_1": 3468 },+      { "_0": "morpheus", "_1": 4236 },+      { "_0": "cronos", "_1": 547 }+    ],+    "f1": []+  }+}
+ test/Feature/Input/collections/map/invalid/query.gql view
@@ -0,0 +1,8 @@+query InvalidMap {+  f1: testMap(value: {})+  f2: testMap(value: 635)+  f3: testMap(value: [{ _0: "235" }])+  f4: testMap(value: [{ _0: "235", _1: "235235" }])+  f5: testMap(value: [{ _0: "235", _1: false }])+  f6: testMap(value: [{ _0: "34", _1: 2353 }])+}
+ test/Feature/Input/collections/map/invalid/response.json view
@@ -0,0 +1,28 @@+{+  "errors": [+    {+      "message": "Argument \"value\" got invalid value. Expected type \"[InputPairTextInt!]!\" found {}.",+      "locations": [{ "line": 2, "column": 15 }]+    },+    {+      "message": "Argument \"value\" got invalid value. Expected type \"[InputPairTextInt!]!\" found 635.",+      "locations": [{ "line": 3, "column": 15 }]+    },+    {+      "message": "Argument \"value\" got invalid value. Undefined Field \"_1\".",+      "locations": [{ "line": 4, "column": 15 }]+    },+    {+      "message": "Argument \"value\" got invalid value. in field \"_1\": Expected type \"Int!\" found \"235235\".",+      "locations": [{ "line": 5, "column": 15 }]+    },+    {+      "message": "Argument \"value\" got invalid value. in field \"_1\": Expected type \"Int!\" found false.",+      "locations": [{ "line": 6, "column": 15 }]+    },+    {+      "message": "Field \"testMap\" of type \"PairTextInt\" must have a selection of subfields",+      "locations": [{ "line": 7, "column": 3 }]+    }+  ]+}
+ test/Feature/Input/collections/map/ok/query.gql view
@@ -0,0 +1,19 @@+query ValidMap {+  f1: testMap(value: []) {+    ...Entry+  }+  f2: testMap(+    value: [+      { _0: "zeus", _1: 3468 }+      { _0: "morpheus", _1: 4236 }+      { _0: "cronos", _1: 547 }+    ]+  ) {+    ...Entry+  }+}++fragment Entry on PairTextInt {+  _0+  _1+}
+ test/Feature/Input/collections/map/ok/response.json view
@@ -0,0 +1,10 @@+{+  "data": {+    "f1": [],+    "f2": [+      { "_0": "cronos", "_1": 547 },+      { "_0": "morpheus", "_1": 4236 },+      { "_0": "zeus", "_1": 3468 }+    ]+  }+}
+ test/Feature/Input/collections/nonempty/invalid/query.gql view
@@ -0,0 +1,3 @@+query FailOnEmpty {+  testNonEmpty(value: [])+}
+ test/Feature/Input/collections/nonempty/invalid/response.json view
@@ -0,0 +1,8 @@+{+  "errors": [+    {+      "message": "Failure on Resolving Field \"testNonEmpty\": Type mismatch! expected:Expected a NonEmpty list, got: []",+      "locations": [{ "line": 2, "column": 3 }]+    }+  ]+}
+ test/Feature/Input/collections/nonempty/ok/query.gql view
@@ -0,0 +1,4 @@+query ValidNonEmpty {+  f1: testNonEmpty(value: [32])+  f2: testNonEmpty(value: [32, 235, 235, 6463, 352123])+}
+ test/Feature/Input/collections/nonempty/ok/response.json view
@@ -0,0 +1,6 @@+{+  "data": {+    "f1": [32],+    "f2": [32, 235, 235, 6463, 352123]+  }+}
+ test/Feature/Input/collections/product/invalid/query.gql view
@@ -0,0 +1,9 @@+query InvalidProduct {+  f1: testProduct(value: [])+  f2: testProduct(value: {})+  f3: testProduct(value: { _0: 2 })+  f4: testProduct(value: { _0: "235" })+  f4: testProduct(value: { _0: "235", _1: "235235" })+  f4: testProduct(value: { _0: "235", _1: false })+  f5: testProduct(value: { _0: "34", _1: 2353, _2: false })+}
+ test/Feature/Input/collections/product/invalid/response.json view
@@ -0,0 +1,60 @@+{+  "errors": [+    {+      "message": "Argument \"value\" got invalid value. Expected type \"InputProduct!\" found [].",+      "locations": [{ "line": 2, "column": 19 }]+    },+    {+      "message": "Argument \"value\" got invalid value. Undefined Field \"_0\".",+      "locations": [{ "line": 3, "column": 19 }]+    },+    {+      "message": "Argument \"value\" got invalid value. Undefined Field \"_1\".",+      "locations": [{ "line": 3, "column": 19 }]+    },+    {+      "message": "Argument \"value\" got invalid value. Undefined Field \"_2\".",+      "locations": [{ "line": 3, "column": 19 }]+    },+    {+      "message": "Argument \"value\" got invalid value. Undefined Field \"_1\".",+      "locations": [{ "line": 4, "column": 19 }]+    },+    {+      "message": "Argument \"value\" got invalid value. Undefined Field \"_2\".",+      "locations": [{ "line": 4, "column": 19 }]+    },+    {+      "message": "Argument \"value\" got invalid value. in field \"_0\": Expected type \"String!\" found 2.",+      "locations": [{ "line": 4, "column": 19 }]+    },+    {+      "message": "Argument \"value\" got invalid value. Undefined Field \"_1\".",+      "locations": [{ "line": 5, "column": 19 }]+    },+    {+      "message": "Argument \"value\" got invalid value. Undefined Field \"_2\".",+      "locations": [{ "line": 5, "column": 19 }]+    },+    {+      "message": "Argument \"value\" got invalid value. Undefined Field \"_2\".",+      "locations": [{ "line": 6, "column": 19 }]+    },+    {+      "message": "Argument \"value\" got invalid value. in field \"_1\": Expected type \"Int!\" found \"235235\".",+      "locations": [{ "line": 6, "column": 19 }]+    },+    {+      "message": "Argument \"value\" got invalid value. Undefined Field \"_2\".",+      "locations": [{ "line": 7, "column": 19 }]+    },+    {+      "message": "Argument \"value\" got invalid value. in field \"_1\": Expected type \"Int!\" found false.",+      "locations": [{ "line": 7, "column": 19 }]+    },+    {+      "message": "Field \"testProduct\" of type \"Product\" must have a selection of subfields",+      "locations": [{ "line": 8, "column": 3 }]+    }+  ]+}
+ test/Feature/Input/collections/product/ok/query.gql view
@@ -0,0 +1,15 @@+query ValidProduct {+  f1: testProduct(value: { _0: "abc", _1: 4235, _2: true }) {+    ...Product+  }+  f2: testProduct(value: { _0: "324523", _1: 3468, _2: false, _3: 0.635 }) {+    ...Product+  }+}++fragment Product on Product {+  _0+  _1+  _2+  _3+}
+ test/Feature/Input/collections/product/ok/response.json view
@@ -0,0 +1,16 @@+{+  "data": {+    "f1": {+      "_0": "abc",+      "_1": 4235,+      "_2": true,+      "_3": null+    },+    "f2": {+      "_0": "324523",+      "_1": 3468,+      "_2": false,+      "_3": 0.635+    }+  }+}
+ test/Feature/Input/collections/seq/query.gql view
@@ -0,0 +1,5 @@+query ValidSeq {+  f1: tesSeq(value: [])+  f2: tesSeq(value: [32])+  f3: tesSeq(value: [32, 235, 6463, 352123])+}
+ test/Feature/Input/collections/seq/response.json view
@@ -0,0 +1,7 @@+{+  "data": {+    "f1": [],+    "f2": [32],+    "f3": [32, 235, 6463, 352123]+  }+}
+ test/Feature/Input/collections/set/invalid/query.gql view
@@ -0,0 +1,5 @@+query FailSet {+  f1: testSet(value: [2, 2])+  f2: testSet(value: [32, 32, 32])+  f3: testSet(value: [32, 235, 235, 6463, 352123])+}
+ test/Feature/Input/collections/set/invalid/response.json view
@@ -0,0 +1,16 @@+{+  "errors": [+    {+      "message": "Failure on Resolving Field \"testSet\": Expected a List without duplicates, found 1 duplicates",+      "locations": [{ "line": 2, "column": 3 }]+    },+    {+      "message": "Failure on Resolving Field \"testSet\": Expected a List without duplicates, found 2 duplicates",+      "locations": [{ "line": 3, "column": 3 }]+    },+    {+      "message": "Failure on Resolving Field \"testSet\": Expected a List without duplicates, found 1 duplicates",+      "locations": [{ "line": 4, "column": 3 }]+    }+  ]+}
+ test/Feature/Input/collections/set/ok/query.gql view
@@ -0,0 +1,5 @@+query ValidSet {+  f1: testSet(value: [])+  f2: testSet(value: [32])+  f3: testSet(value: [32, 235, 6463, 352123])+}
+ test/Feature/Input/collections/set/ok/response.json view
@@ -0,0 +1,7 @@+{+  "data": {+    "f1": [],+    "f2": [32],+    "f3": [32, 235, 6463, 352123]+  }+}
+ test/Feature/Input/collections/tuple/invalid/query.gql view
@@ -0,0 +1,9 @@+query InvalidTuple {+  f1: testTuple(value: [])+  f2: testTuple(value: {})+  f3: testTuple(value: { _0: 2 })+  f4: testTuple(value: { _0: "235" })+  f4: testTuple(value: { _0: "235", _1: "235235" })+  f4: testTuple(value: { _0: "235", _1: false })+  f5: testTuple(value: { _0: "34", _1: 2353 })+}
+ test/Feature/Input/collections/tuple/invalid/response.json view
@@ -0,0 +1,40 @@+{+  "errors": [+    {+      "message": "Argument \"value\" got invalid value. Expected type \"InputPairTextInt!\" found [].",+      "locations": [{ "line": 2, "column": 17 }]+    },+    {+      "message": "Argument \"value\" got invalid value. Undefined Field \"_0\".",+      "locations": [{ "line": 3, "column": 17 }]+    },+    {+      "message": "Argument \"value\" got invalid value. Undefined Field \"_1\".",+      "locations": [{ "line": 3, "column": 17 }]+    },+    {+      "message": "Argument \"value\" got invalid value. Undefined Field \"_1\".",+      "locations": [{ "line": 4, "column": 17 }]+    },+    {+      "message": "Argument \"value\" got invalid value. in field \"_0\": Expected type \"String!\" found 2.",+      "locations": [{ "line": 4, "column": 17 }]+    },+    {+      "message": "Argument \"value\" got invalid value. Undefined Field \"_1\".",+      "locations": [{ "line": 5, "column": 17 }]+    },+    {+      "message": "Argument \"value\" got invalid value. in field \"_1\": Expected type \"Int!\" found \"235235\".",+      "locations": [{ "line": 6, "column": 17 }]+    },+    {+      "message": "Argument \"value\" got invalid value. in field \"_1\": Expected type \"Int!\" found false.",+      "locations": [{ "line": 7, "column": 17 }]+    },+    {+      "message": "Field \"testTuple\" of type \"PairTextInt\" must have a selection of subfields",+      "locations": [{ "line": 8, "column": 3 }]+    }+  ]+}
+ test/Feature/Input/collections/tuple/ok/query.gql view
@@ -0,0 +1,10 @@+query ValidTuple {+  f1: testTuple(value: { _0: "abc", _1: 4235 }) {+    _0+    _1+  }+  f2: testTuple(value: { _0: "324523", _1: 3468 }) {+    _0+    _1+  }+}
+ test/Feature/Input/collections/tuple/ok/response.json view
@@ -0,0 +1,12 @@+{+  "data": {+    "f1": {+      "_0": "abc",+      "_1": 4235+    },+    "f2": {+      "_0": "324523",+      "_1": 3468+    }+  }+}
+ test/Feature/Input/collections/vector/query.gql view
@@ -0,0 +1,5 @@+query ValidSeq {+  f1: testVector(value: [])+  f2: testVector(value: [32])+  f3: testVector(value: [32, 235, 6463, 352123])+}
+ test/Feature/Input/collections/vector/response.json view
@@ -0,0 +1,7 @@+{+  "data": {+    "f1": [],+    "f2": [32],+    "f3": [32, 235, 6463, 352123]+  }+}
+ test/Feature/Input/enums/decode2Con/query.gql view
@@ -0,0 +1,3 @@+query ValidDecoding {+  test2 (level:LA)+}
+ test/Feature/Input/enums/decode2Con/response.json view
@@ -0,0 +1,5 @@+{+  "data": {+    "test2": "LA"+  }+}
+ test/Feature/Input/enums/decode3Con/query.gql view
@@ -0,0 +1,3 @@+query ValidDecoding {+  test3 (level:T1)+}
+ test/Feature/Input/enums/decode3Con/response.json view
@@ -0,0 +1,5 @@+{+  "data": {+    "test3": "T1"+  }+}
+ test/Feature/Input/enums/decodeInvalidValue/query.gql view
@@ -0,0 +1,3 @@+query ValidDecoding {+  test2 ( level: LK )+}
+ test/Feature/Input/enums/decodeInvalidValue/response.json view
@@ -0,0 +1,13 @@+{+  "errors": [+    {+      "message": "Argument \"level\" got invalid value. Expected type \"TwoCon!\" found LK.",+      "locations": [+        {+          "line": 2,+          "column": 11+        }+      ]+    }+  ]+}
+ test/Feature/Input/enums/decodeMany/con0/query.gql view
@@ -0,0 +1,3 @@+query ValidDecoding {+  test (level:L0)+}
+ test/Feature/Input/enums/decodeMany/con0/response.json view
@@ -0,0 +1,5 @@+{+  "data": {+    "test":  "L0"+  }+}
+ test/Feature/Input/enums/decodeMany/con1/query.gql view
@@ -0,0 +1,3 @@+query ValidDecoding {+  test (level:L1)+}
+ test/Feature/Input/enums/decodeMany/con1/response.json view
@@ -0,0 +1,5 @@+{+  "data": {+    "test": "L1"+  }+}
+ test/Feature/Input/enums/decodeMany/con2/query.gql view
@@ -0,0 +1,3 @@+query ValidDecoding {+  test (level:L2)+}
+ test/Feature/Input/enums/decodeMany/con2/response.json view
@@ -0,0 +1,5 @@+{+  "data": {+    "test": "L2"+  }+}
+ test/Feature/Input/enums/decodeMany/con3/query.gql view
@@ -0,0 +1,3 @@+query ValidDecoding {+  test (level:L3)+}
+ test/Feature/Input/enums/decodeMany/con3/response.json view
@@ -0,0 +1,5 @@+{+  "data": {+    "test": "L3"+  }+}
+ test/Feature/Input/enums/decodeMany/con4/query.gql view
@@ -0,0 +1,3 @@+query ValidDecoding {+  test (level:L4)+}
+ test/Feature/Input/enums/decodeMany/con4/response.json view
@@ -0,0 +1,5 @@+{+  "data": {+    "test": "L4"+  }+}
+ test/Feature/Input/enums/decodeMany/con5/query.gql view
@@ -0,0 +1,3 @@+query ValidDecoding {+  test (level:L5)+}
+ test/Feature/Input/enums/decodeMany/con5/response.json view
@@ -0,0 +1,5 @@+{+  "data": {+    "test": "L5"+  }+}
+ test/Feature/Input/enums/decodeMany/con6/query.gql view
@@ -0,0 +1,3 @@+query ValidDecoding {+  test (level:L6)+}
+ test/Feature/Input/enums/decodeMany/con6/response.json view
@@ -0,0 +1,5 @@+{+  "data": {+    "test": "L6"+  }+}
+ test/Feature/Input/enums/invalidEnumFromJSONVariable/query.gql view
@@ -0,0 +1,3 @@+query ValidDecoding($x: TwoCon!) {+  test2(level: $x)+}
+ test/Feature/Input/enums/invalidEnumFromJSONVariable/response.json view
@@ -0,0 +1,8 @@+{+  "errors": [+    {+      "message": "Variable \"$x\" got invalid value. Expected type \"TwoCon!\" found \"BLA\".",+      "locations": [{ "line": 1, "column": 21 }]+    }+  ]+}
+ test/Feature/Input/enums/invalidEnumFromJSONVariable/variables.json view
@@ -0,0 +1,1 @@+{ "x": "BLA" }
+ test/Feature/Input/enums/invalidStringDefaultValue/query.gql view
@@ -0,0 +1,3 @@+query ValidDecoding($x: TwoCon! = "LA") {+  test2(level: $x)+}
+ test/Feature/Input/enums/invalidStringDefaultValue/response.json view
@@ -0,0 +1,8 @@+{+  "errors": [+    {+      "message": "Variable \"$x\" got invalid value. Expected type \"TwoCon!\" found \"LA\".",+      "locations": [{ "line": 1, "column": 21 }]+    }+  ]+}
+ test/Feature/Input/enums/invalidStringInput/query.gql view
@@ -0,0 +1,3 @@+query ValidDecoding {+  test2(level: "LA")+}
+ test/Feature/Input/enums/invalidStringInput/response.json view
@@ -0,0 +1,8 @@+{+  "errors": [+    {+      "message": "Argument \"level\" got invalid value. Expected type \"TwoCon!\" found \"LA\".",+      "locations": [{ "line": 2, "column": 9 }]+    }+  ]+}
+ test/Feature/Input/enums/validEnumFromJSONVariable/query.gql view
@@ -0,0 +1,3 @@+query ValidDecoding($x: TwoCon!) {+  test2(level: $x)+}
+ test/Feature/Input/enums/validEnumFromJSONVariable/response.json view
@@ -0,0 +1,5 @@+{+  "data": {+    "test2": "LA"+  }+}
+ test/Feature/Input/enums/validEnumFromJSONVariable/variables.json view
@@ -0,0 +1,1 @@+{ "x": "LA" }
+ test/Feature/Input/objects/nullableUndefinedField/query.gql view
@@ -0,0 +1,3 @@+query NullableUndefinedField {+  input(value: { field: "value" })+}
+ test/Feature/Input/objects/nullableUndefinedField/response.json view
@@ -0,0 +1,5 @@+{+  "data": {+    "input": "InputObject {field = \"value\", nullableField = Nothing, recursive = Nothing}"+  }+}
+ test/Feature/Input/objects/resolveObject/query.gql view
@@ -0,0 +1,4 @@+query ResolveObject {+  i1: input(value: { field: "v1", nullableField: 123 })+  i2: input(value: { field: "v2" , recursive: { field: "v3" } })+}
+ test/Feature/Input/objects/resolveObject/response.json view
@@ -0,0 +1,6 @@+{+  "data": {+    "i1": "InputObject {field = \"v1\", nullableField = Just 123, recursive = Nothing}",+    "i2": "InputObject {field = \"v2\", nullableField = Nothing, recursive = Just (InputObject {field = \"v3\", nullableField = Nothing, recursive = Nothing})}"+  }+}
+ test/Feature/Input/objects/resolveVariable/query.gql view
@@ -0,0 +1,4 @@+query ResolveVariable($v1: String!, $v2: Int!, $v3: Int) {+  i1: input(value: { field: $v1, nullableField: $v2 })+  i2: input(value: { field: "", nullableField: $v3 })+}
+ test/Feature/Input/objects/resolveVariable/response.json view
@@ -0,0 +1,6 @@+{+  "data": {+    "i1": "InputObject {field = \"string from variable\", nullableField = Just 123011, recursive = Nothing}",+    "i2": "InputObject {field = \"\", nullableField = Nothing, recursive = Nothing}"+  }+}
+ test/Feature/Input/objects/resolveVariable/variables.json view
@@ -0,0 +1,4 @@+{+  "v1": "string from variable",+  "v2": 123011+}
+ test/Feature/Input/objects/undefinedField/query.gql view
@@ -0,0 +1,5 @@+query UndefinedField {+  i1: input(value: { nullableField: 1 })+  i2: input(value: { })+  i3: input(value: { field: "v2" , recursive: { field: "v3" , recursive: {}  } })+}
+ test/Feature/Input/objects/undefinedField/response.json view
@@ -0,0 +1,31 @@+{+  "errors": [+    {+      "message": "Argument \"value\" got invalid value. Undefined Field \"field\".",+      "locations": [+        {+          "line": 2,+          "column": 13+        }+      ]+    },+    {+      "message": "Argument \"value\" got invalid value. Undefined Field \"field\".",+      "locations": [+        {+          "line": 3,+          "column": 13+        }+      ]+    },+    {+      "message": "Argument \"value\" got invalid value. in field \"recursive.recursive\": Undefined Field \"field\".",+      "locations": [+        {+          "line": 4,+          "column": 13+        }+      ]+    }+  ]+}
+ test/Feature/Input/objects/unexpectedValue/query.gql view
@@ -0,0 +1,9 @@+query UnexpectedValue {+  i1: input(value: "some text")+  i2: input(value: 1)+  i3: input(value: { field: {} })+  i4: input(value: { field: 3 })+  i5: input(value: { field: null } )+  # deep recursive+  i6: input(value: { field: "v2" , recursive: { field: "v3" , recursive: { field: 5 }  } })+}
+ test/Feature/Input/objects/unexpectedValue/response.json view
@@ -0,0 +1,58 @@+{+  "errors": [+    {+      "message": "Argument \"value\" got invalid value. Expected type \"InputObject!\" found \"some text\".",+      "locations": [+        {+          "line": 2,+          "column": 13+        }+      ]+    },+    {+      "message": "Argument \"value\" got invalid value. Expected type \"InputObject!\" found 1.",+      "locations": [+        {+          "line": 3,+          "column": 13+        }+      ]+    },+    {+      "message": "Argument \"value\" got invalid value. in field \"field\": Expected type \"String!\" found {}.",+      "locations": [+        {+          "line": 4,+          "column": 13+        }+      ]+    },+    {+      "message": "Argument \"value\" got invalid value. in field \"field\": Expected type \"String!\" found 3.",+      "locations": [+        {+          "line": 5,+          "column": 13+        }+      ]+    },+    {+      "message": "Argument \"value\" got invalid value. in field \"field\": Expected type \"String!\" found null.",+      "locations": [+        {+          "line": 6,+          "column": 13+        }+      ]+    },+    {+      "message": "Argument \"value\" got invalid value. in field \"recursive.recursive.field\": Expected type \"String!\" found 5.",+      "locations": [+        {+          "line": 8,+          "column": 13+        }+      ]+    }+  ]+}
+ test/Feature/Input/objects/unexpectedVariable/query.gql view
@@ -0,0 +1,4 @@+query Unexpectedvariable($v1: String, $v2: String) {+  i1: input(value: { field: $v1, nullableField: 1 })+  i2: input(value: { field: "", nullableField: $v2 })+}
+ test/Feature/Input/objects/unexpectedVariable/response.json view
@@ -0,0 +1,12 @@+{+  "errors": [+    {+      "message": "Variable \"$v1\" of type \"String\" used in position expecting type \"String!\".",+      "locations": [{ "line": 2, "column": 29 }]+    },+    {+      "message": "Variable \"$v2\" of type \"String\" used in position expecting type \"Int\".",+      "locations": [{ "line": 3, "column": 48 }]+    }+  ]+}
+ test/Feature/Input/objects/unknownField/query.gql view
@@ -0,0 +1,4 @@+query UnknownField {+  i1: input( value: { moo: 1, field: "some field" })+  i2: input(value: { field: "v2" , recursive: { field: "v3" , recursive: { field: "bal" , unkField : "test Unkown" }  } })+}
+ test/Feature/Input/objects/unknownField/response.json view
@@ -0,0 +1,22 @@+{+  "errors": [+    {+      "message": "Argument \"value\" got invalid value. Unknown Field \"moo\".",+      "locations": [+        {+          "line": 2,+          "column": 14+        }+      ]+    },+    {+      "message": "Argument \"value\" got invalid value. in field \"recursive.recursive\": Unknown Field \"unkField\".",+      "locations": [+        {+          "line": 3,+          "column": 13+        }+      ]+    }+  ]+}
+ test/Feature/Input/scalars/numbers/decodeFloat/query.gql view
@@ -0,0 +1,7 @@+query ValidDecoding {+  one: testFloat(value: 1.00)+  negOne: testFloat(value: -1)+  negNummber: testFloat(value: -1.235)+  expNumber: testFloat(value: 0.3e5)+  negExpNumber: testFloat(value: - 0.12e-35)+}
+ test/Feature/Input/scalars/numbers/decodeFloat/response.json view
@@ -0,0 +1,9 @@+{+  "data": {+    "one": 1,+    "negOne": -1,+    "negNummber": -1.235,+    "expNumber": 30000,+    "negExpNumber": -1.2e-36+  }+}
+ test/Feature/Input/scalars/numbers/decodeInt/query.gql view
@@ -0,0 +1,7 @@+query ValidDecoding {+  one: testInt(value: 1)+  negOne: testInt(value: -1)+  negNummber: testInt(value: -1235)+  expNumber: testInt(value: 123e5)+  negExpNumber: testInt(value: - 123e5)+}
+ test/Feature/Input/scalars/numbers/decodeInt/response.json view
@@ -0,0 +1,9 @@+{+  "data": {+    "one": 1,+    "negOne": -1,+    "negNummber": -1235,+    "expNumber": 12300000,+    "negExpNumber": -12300000+  }+}
+ test/Feature/Input/scalars/strings/block/query.gql view
@@ -0,0 +1,20 @@+query ValidDecoding {+  simple: testString(+    value: """+    bla bla \n+    """+  )+  sophisticated: testString(+    value: """+    ewrwe+        sdfd+        werte+      erqewr+++      this is some text++      bla+          bla+    """+  )+}
+ test/Feature/Input/scalars/strings/block/response.json view
@@ -0,0 +1,6 @@+{+  "data": {+    "simple": "\n    bla bla \\n\n    ",+    "sophisticated": "\n    ewrwe\n        sdfd\n        werte\n      erqewr+\n\n      this is some text\n\n      bla\n          bla\n    "+  }+}
+ test/Feature/Input/scalars/strings/escaped/query.gql view
@@ -0,0 +1,3 @@+query ValidDecoding {+  testString(value: " a b  \n \\ / bla  ")+}
+ test/Feature/Input/scalars/strings/escaped/response.json view
@@ -0,0 +1,1 @@+{ "data": { "testString": " a b  \n \\ / bla  " } }
+ test/Feature/Input/scalars/strings/regular/query.gql view
@@ -0,0 +1,3 @@+query ValidDecoding {+  testString(value: "some string bla b jasd qweq ")+}
+ test/Feature/Input/scalars/strings/regular/response.json view
@@ -0,0 +1,5 @@+{+  "data": {+    "testString": "some string bla b jasd qweq "+  }+}
+ test/Feature/Input/scalars/strings/wrong-escaped/query.gql view
@@ -0,0 +1,3 @@+query ValidDecoding {+  testString(value: " a b  \k  / bla  ")+}
+ test/Feature/Input/scalars/strings/wrong-escaped/response.json view
@@ -0,0 +1,8 @@+{+  "errors": [+    {+      "message": "offset=50:\nunexpected 'k'\nexpecting '\"', '/', '\\', 'b', 'f', 'n', 'r', or 't'\n",+      "locations": [{ "line": 2, "column": 29 }]+    }+  ]+}
+ test/Feature/Input/scalars/strings/wrong-newline/query.gql view
@@ -0,0 +1,7 @@+query ValidDecoding {+  testString+    (value: +      "some string bla b +      jasd qweq "+    )+}
+ test/Feature/Input/scalars/strings/wrong-newline/response.json view
@@ -0,0 +1,8 @@+{+  "errors": [+    {+      "message": "offset=74:\nunexpected newline\n",+      "locations": [{ "line": 5, "column": 1 }]+    }+  ]+}
+ test/Feature/Input/variables/incompatibleType/equalType/query.gql view
@@ -0,0 +1,5 @@+query invalidListVariable($v1: [[[Int!]!]]! ) {+  q1 {+    a2(argList: [],argNestedList: $v1)+  }+}
+ test/Feature/Input/variables/incompatibleType/equalType/response.json view
@@ -0,0 +1,7 @@+{+  "data": {+    "q1": {+      "a2": 1+    }+  }+}
+ test/Feature/Input/variables/incompatibleType/equalType/variables.json view
@@ -0,0 +1,4 @@+{+  "v1": [+  ]+}
+ test/Feature/Input/variables/incompatibleType/stricterType/query.gql view
@@ -0,0 +1,5 @@+query invalidListVariable($v1: [[[Int!]!]!]! ) {+  q1 {+    a2(argList: [],argNestedList: $v1)+  }+}
+ test/Feature/Input/variables/incompatibleType/stricterType/response.json view
@@ -0,0 +1,7 @@+{+  "data": {+    "q1": {+      "a2": 1+    }+  }+}
+ test/Feature/Input/variables/incompatibleType/stricterType/variables.json view
@@ -0,0 +1,4 @@+{+  "v1": [+  ]+}
+ test/Feature/Input/variables/incompatibleType/weakerType1/query.gql view
@@ -0,0 +1,5 @@+query invalidListVariable($v1: [[[Int]!]!]! ) {+  q1 {+    a2(argList: [],argNestedList: $v1)+  }+}
+ test/Feature/Input/variables/incompatibleType/weakerType1/response.json view
@@ -0,0 +1,13 @@+{+  "errors": [+    {+      "message": "Variable \"$v1\" of type \"[[[Int]!]!]!\" used in position expecting type \"[[[Int!]!]]!\".",+      "locations": [+        {+          "line": 3,+          "column": 35+        }+      ]+    }+  ]+}
+ test/Feature/Input/variables/incompatibleType/weakerType1/variables.json view
@@ -0,0 +1,4 @@+{+  "v1": [+  ]+}
+ test/Feature/Input/variables/incompatibleType/weakerType2/query.gql view
@@ -0,0 +1,5 @@+query invalidListVariable($v1: [[[Int!]!]!] ) {+  q1 {+    a2(argList: [],argNestedList: $v1)+  }+}
+ test/Feature/Input/variables/incompatibleType/weakerType2/response.json view
@@ -0,0 +1,13 @@+{+  "errors": [+    {+      "message": "Variable \"$v1\" of type \"[[[Int!]!]!]\" used in position expecting type \"[[[Int!]!]]!\".",+      "locations": [+        {+          "line": 3,+          "column": 35+        }+      ]+    }+  ]+}
+ test/Feature/Input/variables/incompatibleType/weakerType2/variables.json view
@@ -0,0 +1,4 @@+{+  "v1": [+  ]+}
+ test/Feature/Input/variables/incompatibleType/weakerType3/query.gql view
@@ -0,0 +1,5 @@+query invalidListVariable($v1: [[[Int!]]!]! ) {+  q1 {+    a2(argList: [],argNestedList: $v1)+  }+}
+ test/Feature/Input/variables/incompatibleType/weakerType3/response.json view
@@ -0,0 +1,13 @@+{+  "errors": [+    {+      "message": "Variable \"$v1\" of type \"[[[Int!]]!]!\" used in position expecting type \"[[[Int!]!]]!\".",+      "locations": [+        {+          "line": 3,+          "column": 35+        }+      ]+    }+  ]+}
+ test/Feature/Input/variables/incompatibleType/weakerType3/variables.json view
@@ -0,0 +1,4 @@+{+  "v1": [+  ]+}
+ test/Feature/Input/variables/invalidValue/invalidDefaultValue/query.gql view
@@ -0,0 +1,5 @@+query invalidListVariable($v1: [[[Int!]!]]! = { id: "12" }) {+  q1 {+    a2(argList: [], argNestedList: $v1)+  }+}
+ test/Feature/Input/variables/invalidValue/invalidDefaultValue/response.json view
@@ -0,0 +1,13 @@+{+  "errors": [+    {+      "message": "Variable \"$v1\" got invalid value. Expected type \"[[[Int!]!]]!\" found { id: \"12\" }.",+      "locations": [+        {+          "line": 1,+          "column": 27+        }+      ]+    }+  ]+}
+ test/Feature/Input/variables/invalidValue/invalidDefaultValueButVariableProvided/query.gql view
@@ -0,0 +1,5 @@+query invalidListVariable($v1: [[[Int!]!]]! = [["boo"]]) {+  q1 {+    a2(argList: [], argNestedList: $v1)+  }+}
+ test/Feature/Input/variables/invalidValue/invalidDefaultValueButVariableProvided/response.json view
@@ -0,0 +1,13 @@+{+  "errors": [+    {+      "message": "Variable \"$v1\" got invalid value. Expected type \"[Int!]!\" found \"boo\".",+      "locations": [+        {+          "line": 1,+          "column": 27+        }+      ]+    }+  ]+}
+ test/Feature/Input/variables/invalidValue/invalidDefaultValueButVariableProvided/variables.json view
@@ -0,0 +1,3 @@+{+  "v1": []+}
+ test/Feature/Input/variables/invalidValue/invalidListVariable/query.gql view
@@ -0,0 +1,5 @@+query invalidListVariable($v1: [String!] ) {+  q1 {+    a2(argList: $v1)+  }+}
+ test/Feature/Input/variables/invalidValue/invalidListVariable/response.json view
@@ -0,0 +1,13 @@+{+  "errors": [+    {+      "message": "Variable \"$v1\" got invalid value. Expected type \"String!\" found null.",+      "locations": [+        {+          "line": 1,+          "column": 27+        }+      ]+    }+  ]+}
+ test/Feature/Input/variables/invalidValue/invalidListVariable/variables.json view
@@ -0,0 +1,5 @@+{+  "v1": [+    null+  ]+}
+ test/Feature/Input/variables/invalidValue/nestedListNonNullListReceivedNull/query.gql view
@@ -0,0 +1,5 @@+query NonNullListReceivedNull($v1: [[[Int!]!]]!) {+  q1 {+    a2(argNestedList: $v1)+  }+}
+ test/Feature/Input/variables/invalidValue/nestedListNonNullListReceivedNull/response.json view
@@ -0,0 +1,13 @@+{+  "errors": [+    {+      "message": "Variable \"$v1\" got invalid value. Expected type \"[Int!]!\" found null.",+      "locations": [+        {+          "line": 1,+          "column": 31+        }+      ]+    }+  ]+}
+ test/Feature/Input/variables/invalidValue/nestedListNonNullListReceivedNull/variables.json view
@@ -0,0 +1,11 @@+{+  "v1": [+    [+      [+        1+      ],+      null+    ],+    null+  ]+}
+ test/Feature/Input/variables/nameCollision/query.gql view
@@ -0,0 +1,5 @@+query variableNameCollision($v1: String!, $v1: String! ) {+  q1 {+    a2(argList: $v1)+  }+}
+ test/Feature/Input/variables/nameCollision/response.json view
@@ -0,0 +1,22 @@+{+  "errors": [+    {+      "message": "There can Be only One Variable Named \"v1\"",+      "locations": [+        {+          "line": 1,+          "column": 29+        }+      ]+    },+    {+      "message": "There can Be only One Variable Named \"v1\"",+      "locations": [+        {+          "line": 1,+          "column": 43+        }+      ]+    }+  ]+}
+ test/Feature/Input/variables/nameCollision/variables.json view
@@ -0,0 +1,5 @@+{+  "v1": [+    "a"+  ]+}
+ test/Feature/Input/variables/nestedListNullableListReceivedNull/query.gql view
@@ -0,0 +1,5 @@+query NullableListReceivedNull($v1: [[[Int!]!]]!) {+  q1 {+    a2(argNestedList: $v1, argList:[])+  }+}
+ test/Feature/Input/variables/nestedListNullableListReceivedNull/response.json view
@@ -0,0 +1,7 @@+{+  "data": {+    "q1": {+      "a2": 1+    }+  }+}
+ test/Feature/Input/variables/nestedListNullableListReceivedNull/variables.json view
@@ -0,0 +1,10 @@+{+  "v1": [+    [+      [+        1+      ]+    ],+    null+  ]+}
+ test/Feature/Input/variables/nonInputTypeViolation/query.gql view
@@ -0,0 +1,5 @@+query testUnknownType ($bo: A ){+  q1 {+      a1(arg1:$bo)+  }+}
+ test/Feature/Input/variables/nonInputTypeViolation/response.json view
@@ -0,0 +1,13 @@+{+  "errors": [+    {+      "message": "Variable \"$bo\" cannot be non-input type \"A\".",+      "locations": [+        {+          "line": 1,+          "column": 24+        }+      ]+    }+  ]+}
+ test/Feature/Input/variables/undefinedVariable/query.gql view
@@ -0,0 +1,5 @@+query testUnknownType {+  q1 {+      a1(arg1:$bo)+  }+}
+ test/Feature/Input/variables/undefinedVariable/response.json view
@@ -0,0 +1,13 @@+{+  "errors": [+    {+      "message": "Variable \"bo\" is not defined by operation \"testUnknownType\".",+      "locations": [+        {+          "line": 3,+          "column": 15+        }+      ]+    }+  ]+}
+ test/Feature/Input/variables/unknownType/query.gql view
@@ -0,0 +1,5 @@+query testUnknownType ($bo: BA ){+  q1 {+      a1(arg1:$bo)+  }+}
+ test/Feature/Input/variables/unknownType/response.json view
@@ -0,0 +1,13 @@+{+  "errors": [+    {+      "message": "Unknown type \"BA\".",+      "locations": [+        {+          "line": 1,+          "column": 24+        }+      ]+    }+  ]+}
+ test/Feature/Input/variables/unusedVariable/unusedVariables/query.gql view
@@ -0,0 +1,5 @@+query TestUnusedVariables ($v1: String, $v2: String, $v3: Int) {+  q1 {+    a1(arg1: $v1)+  }+}
+ test/Feature/Input/variables/unusedVariable/unusedVariables/response.json view
@@ -0,0 +1,22 @@+{+  "errors": [+    {+      "message": "Variable \"$v2\" is never used in operation \"TestUnusedVariables\".",+      "locations": [+        {+          "line": 1,+          "column": 41+        }+      ]+    },+    {+      "message": "Variable \"$v3\" is never used in operation \"TestUnusedVariables\".",+      "locations": [+        {+          "line": 1,+          "column": 54+        }+      ]+    }+  ]+}
+ test/Feature/Input/variables/unusedVariable/variableUsedInAlias/query.gql view
@@ -0,0 +1,5 @@+query TestUsedVariable ($v1: String!) {+  q1 {+    x1:  a1(arg1: $v1)+  }+}
+ test/Feature/Input/variables/unusedVariable/variableUsedInAlias/response.json view
@@ -0,0 +1,7 @@+{+  "data": {+    "q1": {+      "x1": "a1Test"+    }+  }+}
+ test/Feature/Input/variables/unusedVariable/variableUsedInAlias/variables.json view
@@ -0,0 +1,3 @@+{+  "v1": ""+}
+ test/Feature/Input/variables/unusedVariable/variableUsedInFragment/query.gql view
@@ -0,0 +1,9 @@+query TestUsedVariable ($v1: String!) {+  q1 {+    ...F1+  }+}++fragment F1 on A {+  a1(arg1: $v1)+}
+ test/Feature/Input/variables/unusedVariable/variableUsedInFragment/response.json view
@@ -0,0 +1,7 @@+{+  "data": {+    "q1": {+      "a1": "a1Test"+    }+  }+}
+ test/Feature/Input/variables/unusedVariable/variableUsedInFragment/variables.json view
@@ -0,0 +1,3 @@+{+  "v1": ""+}
+ test/Feature/Input/variables/unusedVariable/variableUsedInInlineFragment/query.gql view
@@ -0,0 +1,7 @@+query TestUsedVariable ($v1: String!) {+  q1 {+    ...on A {+         a1(arg1: $v1)+     }+  }+}
+ test/Feature/Input/variables/unusedVariable/variableUsedInInlineFragment/response.json view
@@ -0,0 +1,7 @@+{+  "data": {+    "q1": {+      "a1": "a1Test"+    }+  }+}
+ test/Feature/Input/variables/unusedVariable/variableUsedInInlineFragment/variables.json view
@@ -0,0 +1,3 @@+{+  "v1": ""+}
+ test/Feature/Input/variables/validListVariable/query.gql view
@@ -0,0 +1,5 @@+query invalidListVariable($v1: [String!]!) {+  q1 {+    a2(argList: $v1, argNestedList: [])+  }+}
+ test/Feature/Input/variables/validListVariable/response.json view
@@ -0,0 +1,7 @@+{+  "data": {+    "q1": {+      "a2": 1+    }+  }+}
+ test/Feature/Input/variables/validListVariable/variables.json view
@@ -0,0 +1,5 @@+{+  "v1": [+    "a"+  ]+}
+ test/Feature/Input/variables/valueNotProvided/nonNullVariable/query.gql view
@@ -0,0 +1,5 @@+query TestNonNullVariable($i1: String!) {+  q1 {+    a1(arg1: $i1)+  }+}
+ test/Feature/Input/variables/valueNotProvided/nonNullVariable/response.json view
@@ -0,0 +1,13 @@+{+  "errors": [+    {+      "message": "Variable \"$i1\" of required type \"String!\" was not provided.",+      "locations": [+        {+          "line": 1,+          "column": 27+        }+      ]+    }+  ]+}
+ test/Feature/Input/variables/valueNotProvided/nonNullVariableWithDefaultValue/query.gql view
@@ -0,0 +1,5 @@+query TestNonNullVariable($i1: String! = "hello world") {+  q1 {+    a1(arg1: $i1)+  }+}
+ test/Feature/Input/variables/valueNotProvided/nonNullVariableWithDefaultValue/response.json view
@@ -0,0 +1,7 @@+{+  "data": {+    "q1": {+      "a1": "a1Test"+    }+  }+}
+ test/Feature/Input/variables/valueNotProvided/nullableVariable/query.gql view
@@ -0,0 +1,5 @@+query TestNullableVariable($i1: Int) {+  q1 {+    a1(arg1:"",arg2: $i1)+  }+}
+ test/Feature/Input/variables/valueNotProvided/nullableVariable/response.json view
@@ -0,0 +1,7 @@+{+  "data": {+    "q1": {+      "a1": "a1Test"+    }+  }+}
+ test/Spec.hs view
@@ -0,0 +1,91 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE NoImplicitPrelude #-}++module Main+  ( main,+  )+where++import Data.Morpheus.Server.Types (GQLRequest (..), GQLResponse (..))+import qualified Feature.Collision.CategoryCollisionFail as TypeCategoryCollisionFail+import qualified Feature.Collision.CategoryCollisionSuccess as TypeCategoryCollisionSuccess+import qualified Feature.Collision.NameCollision as NameCollision+import qualified Feature.Directive.Definition as DirectiveDefinition+import qualified Feature.Directive.EnumVisitor as EnumVisitor+import qualified Feature.Directive.FieldVisitor as FieldVisitor+import qualified Feature.Directive.TypeVisitor as TypeVisitor+import qualified Feature.Inference.ObjectAndEnum as ObjectAndEnum+import qualified Feature.Inference.TaggedArguments as TaggedArguments+import qualified Feature.Inference.TaggedArgumentsFail as TaggedArgumentsFail+import qualified Feature.Inference.TypeGuards as TypeGuards+import qualified Feature.Inference.TypeInference as TypeInference+import qualified Feature.Inference.UnionType as UnionType+import qualified Feature.Inference.WrappedType as WrappedType+import qualified Feature.Input.Collections as Collections+import qualified Feature.Input.Enums as Enums+import qualified Feature.Input.Objects as Objects+import qualified Feature.Input.Scalars as Scalars+import qualified Feature.Input.Variables as Variables+import Relude+import Test.Morpheus+  ( FileUrl,+    cd,+    mainTest,+    mkUrl,+    scan,+    testApi,+  )+import Test.Tasty+  ( TestTree,+    testGroup,+  )++mkFeatureUrl :: FilePath -> FilePath -> FileUrl+mkFeatureUrl groupName = cd (cd (mkUrl "Feature") groupName)++testFeature :: FilePath -> (GQLRequest -> IO GQLResponse, FilePath) -> IO TestTree+testFeature groupName (api, name) = scan (testApi api) (mkFeatureUrl groupName name)++testFeatures :: FilePath -> [(GQLRequest -> IO GQLResponse, FilePath)] -> IO TestTree+testFeatures name cases =+  testGroup name+    <$> traverse+      (testFeature name)+      cases++main :: IO ()+main =+  mainTest+    "Morpheus Graphql Tests"+    [ testFeatures+        "Input"+        [ (Variables.api, "variables"),+          (Enums.api, "enums"),+          (Scalars.api, "scalars"),+          (Objects.api, "objects"),+          (Collections.api, "collections")+        ],+      testFeatures+        "Collision"+        [ (TypeCategoryCollisionSuccess.api, "category-collision-success"),+          (TypeCategoryCollisionFail.api, "category-collision-fail"),+          (NameCollision.api, "name-collision")+        ],+      testFeatures+        "Inference"+        [ (WrappedType.api, "wrapped-type"),+          (TypeGuards.api, "type-guards"),+          (UnionType.api, "union-type"),+          (TypeInference.api, "type-inference"),+          (TaggedArguments.api, "tagged-arguments"),+          (TaggedArgumentsFail.api, "tagged-arguments-fail"),+          (ObjectAndEnum.api, "object-and-enum")+        ],+      testFeatures+        "Directive"+        [ (DirectiveDefinition.api, "definition"),+          (EnumVisitor.api, "enum-visitor"),+          (FieldVisitor.api, "field-visitor"),+          (TypeVisitor.api, "type-visitor")+        ]+    ]