├── .editorconfig ├── .gitignore ├── .travis.yml ├── GraphQLCore.sln ├── LICENSE ├── README.md ├── appveyor.yml ├── createArtifacts.ps1 ├── data └── KitchenSink.graphql ├── docs ├── input-object-definition │ └── overview.md ├── interfaces │ └── overview.md ├── overview.md ├── typed-object-definition │ └── overview.md └── untyped-object-definition │ └── overview.md ├── examples └── GraphQLCore.GraphiQLExample │ ├── Controllers │ └── GraphQLController.cs │ ├── Data │ └── Characters.cs │ ├── GraphQLCore.GraphiQLExample.v3.ncrunchproject │ ├── GraphQLCore.GraphiQLExample.xproj │ ├── Middlewares │ ├── GraphQLWs │ │ ├── GraphQLInitHandler.cs │ │ ├── GraphQLSubscriptionEndHandler.cs │ │ ├── GraphQLSubscriptionStartHandler.cs │ │ ├── IGraphQLWsHandler.cs │ │ └── WsInputObject.cs │ └── GraphQLWsMiddleware.cs │ ├── Models │ ├── Droid.cs │ ├── Episode.cs │ ├── GraphiQLInput.cs │ ├── Human.cs │ └── ICharacter.cs │ ├── Program.cs │ ├── Properties │ └── launchSettings.json │ ├── Schema │ ├── GraphQLCharacterInterface.cs │ ├── GraphQLCharacterUnion.cs │ ├── GraphQLDroidInputObject.cs │ ├── GraphQLDroidObject.cs │ ├── GraphQLEpisodeEnum.cs │ ├── GraphQLHumanObject.cs │ ├── Mutation.cs │ ├── Query.cs │ ├── StarWarsSchema.cs │ └── Subscription.cs │ ├── Services │ └── CharacterService.cs │ ├── Startup.cs │ ├── appsettings.json │ ├── project.json │ ├── public │ ├── index.html │ └── subscrition-transport-ws.js │ └── web.config ├── global.json ├── images ├── fork.png ├── graphql-dotnetcore-logo.png └── graphql-dotnetcore.png ├── src └── GraphQLCore │ ├── Events │ ├── EventBusSubscription.cs │ ├── IEventBus.cs │ ├── InMemoryEventBus.cs │ └── OnMessageReceivedEventArgs.cs │ ├── Exceptions │ ├── GraphQLException.cs │ ├── GraphQLResolveException.cs │ ├── GraphQLSyntaxErrorException.cs │ └── GraphQLValidationException.cs │ ├── Execution │ ├── ExecutionContext.cs │ ├── ExecutionManager.cs │ ├── FieldCollector.cs │ ├── FieldContext`1.cs │ ├── FieldScope.cs │ ├── IContext`1.cs │ ├── IFieldCollector.cs │ ├── IVariableResolver.cs │ └── VariableResolver.cs │ ├── GraphQLCore.v3.ncrunchproject │ ├── GraphQLCore.xproj │ ├── Language │ ├── AST │ │ ├── ASTNode.cs │ │ ├── Enums.cs │ │ ├── GraphQLArgument.cs │ │ ├── GraphQLDirective.cs │ │ ├── GraphQLDirectiveDefinition.cs │ │ ├── GraphQLDocument.cs │ │ ├── GraphQLEnumTypeDefinition.cs │ │ ├── GraphQLEnumValueDefinition.cs │ │ ├── GraphQLFieldDefinition.cs │ │ ├── GraphQLFieldSelection.cs │ │ ├── GraphQLFragmentDefinition.cs │ │ ├── GraphQLFragmentSpread.cs │ │ ├── GraphQLInlineFragment.cs │ │ ├── GraphQLInputObjectTypeDefinition.cs │ │ ├── GraphQLInputValueDefinition.cs │ │ ├── GraphQLInterfaceTypeDefinition.cs │ │ ├── GraphQLListType.cs │ │ ├── GraphQLListValue.cs │ │ ├── GraphQLLocation.cs │ │ ├── GraphQLName.cs │ │ ├── GraphQLNamedType.cs │ │ ├── GraphQLNonNullType.cs │ │ ├── GraphQLNullValue.cs │ │ ├── GraphQLObjectField.cs │ │ ├── GraphQLObjectTypeDefinition.cs │ │ ├── GraphQLObjectValue.cs │ │ ├── GraphQLOperationDefinition.cs │ │ ├── GraphQLOperationTypeDefinition.cs │ │ ├── GraphQLScalarTypeDefinition.cs │ │ ├── GraphQLScalarValue.cs │ │ ├── GraphQLSchemaDefinition.cs │ │ ├── GraphQLSelectionSet.cs │ │ ├── GraphQLType.cs │ │ ├── GraphQLTypeDefinition.cs │ │ ├── GraphQLTypeExtensionDefinition.cs │ │ ├── GraphQLUnionTypeDefinition.cs │ │ ├── GraphQLValue.cs │ │ ├── GraphQLVariable.cs │ │ ├── GraphQLVariableDefinition.cs │ │ └── IWithDirectives.cs │ ├── GraphQLAstVisitor.cs │ ├── ILexer.cs │ ├── ISource.cs │ ├── Lexer.cs │ ├── LexerContext.cs │ ├── Location.cs │ ├── Parser.cs │ ├── ParserContext.cs │ ├── Source.cs │ └── Token.cs │ ├── Properties │ └── AssemblyInfo.cs │ ├── Type │ ├── Complex │ │ ├── Builders │ │ │ ├── ArgumentDefinitionBuilder.cs │ │ │ ├── EnumValueDefinitionBuilder.cs │ │ │ ├── FieldDefinitionBuilder.cs │ │ │ ├── FieldDefinitionBuilder`2.cs │ │ │ ├── InputFieldDefinitionBuilder`1.cs │ │ │ ├── SubscriptionFieldDefinitionBuilderExtensions.cs │ │ │ └── SubscriptionFieldDefinitionBuilder`1.cs │ │ ├── GraphQLComplexType.cs │ │ ├── GraphQLFieldInfo.cs │ │ ├── GraphQLInputObjectType.cs │ │ ├── GraphQLInputObjectTypeFieldInfo.cs │ │ ├── GraphQLInputObjectType`1.cs │ │ ├── GraphQLInterfaceType.cs │ │ ├── GraphQLInterfaceType`1.cs │ │ ├── GraphQLObjectType.cs │ │ ├── GraphQLObjectTypeArgumentInfo.cs │ │ ├── GraphQLObjectTypeExtensions.cs │ │ ├── GraphQLObjectTypeFieldInfo.cs │ │ ├── GraphQLObjectType`1.cs │ │ ├── GraphQLSubscriptionType.cs │ │ ├── GraphQLSubscriptionTypeExtensions.cs │ │ ├── GraphQLSubscriptionTypeFieldInfo.cs │ │ └── GraphQLUnionType.cs │ ├── DefaultValue.cs │ ├── Directives │ │ ├── DirectiveLocation.cs │ │ ├── GraphQLDirectiveType.cs │ │ ├── GraphQLIncludeDirectiveType.cs │ │ └── GraphQLSkipDirectiveType.cs │ ├── GraphQLBaseType.cs │ ├── GraphQLEnumType.cs │ ├── GraphQLEnumType`1.cs │ ├── GraphQLEnumValueInfo.cs │ ├── GraphQLInputType.cs │ ├── GraphQLList.cs │ ├── GraphQLNonNull.cs │ ├── GraphQLSchema.cs │ ├── IGraphQLSchema.cs │ ├── ISystemTypeBound.cs │ ├── Introspection │ │ ├── ComplexIntrospectedType.cs │ │ ├── IntrospectedDirective.cs │ │ ├── IntrospectedDirectiveLocationType.cs │ │ ├── IntrospectedDirectiveType.cs │ │ ├── IntrospectedEnumValue.cs │ │ ├── IntrospectedEnumValueType.cs │ │ ├── IntrospectedField.cs │ │ ├── IntrospectedFieldType.cs │ │ ├── IntrospectedInputObject.cs │ │ ├── IntrospectedInputValue.cs │ │ ├── IntrospectedInputValueType.cs │ │ ├── IntrospectedSchemaType.cs │ │ ├── IntrospectedType.cs │ │ ├── IntrospectedTypeKindType.cs │ │ └── IntrospectedTypeType.cs │ ├── NonNullable.cs │ ├── Result.cs │ ├── Scalar │ │ ├── GraphQLBoolean.cs │ │ ├── GraphQLFloat.cs │ │ ├── GraphQLID.cs │ │ ├── GraphQLInt.cs │ │ ├── GraphQLLong.cs │ │ ├── GraphQLScalarType.cs │ │ ├── GraphQLString.cs │ │ └── ID.cs │ └── Translation │ │ ├── ISchemaRepository.cs │ │ └── SchemaRepository.cs │ ├── Utils │ ├── ReflectionUtilities.cs │ ├── SchemaPrinter.cs │ ├── SchemaUtils.cs │ ├── StringUtils.cs │ ├── TypeComparators.cs │ └── TypeUtilitites.cs │ ├── Validation │ ├── LiteralValueValidator.cs │ ├── Rules │ │ ├── Abstract │ │ │ └── VariableValidationVisitor.cs │ │ ├── ArgumentsOfCorrectType.cs │ │ ├── ArgumentsOfCorrectTypeVisitor.cs │ │ ├── Conflict.cs │ │ ├── DefaultValuesOfCorrectType.cs │ │ ├── DefaultValuesOfCorrectTypeVisitor.cs │ │ ├── FieldsOnCorrectType.cs │ │ ├── FieldsOnCorrectTypeVisitor.cs │ │ ├── FragmentsOnCompositeTypes.cs │ │ ├── FragmentsOnCompositeTypesVisitor.cs │ │ ├── IValidationRule.cs │ │ ├── KnownArgumentNames.cs │ │ ├── KnownArgumentNamesVisitor.cs │ │ ├── KnownDirectives.cs │ │ ├── KnownDirectivesVisitor.cs │ │ ├── KnownFragmentNames.cs │ │ ├── KnownFragmentNamesVisitor.cs │ │ ├── KnownTypeNames.cs │ │ ├── KnownTypeNamesVisitor.cs │ │ ├── LoneAnonymousOperation.cs │ │ ├── LoneAnonymousOperationVisitor.cs │ │ ├── NoFragmentCycles.cs │ │ ├── NoFragmentCyclesVisitor.cs │ │ ├── NoUndefinedVariables.cs │ │ ├── NoUndefinedVariablesVisitor.cs │ │ ├── NoUnusedFragments.cs │ │ ├── NoUnusedFragmentsVisitor.cs │ │ ├── NoUnusedVariables.cs │ │ ├── NoUnusedVariablesVisitor.cs │ │ ├── NodeAndDefinitions.cs │ │ ├── OverlappingFieldsCanBeMerged.cs │ │ ├── OverlappingFieldsCanBeMergedVisitor.cs │ │ ├── PossibleFragmentSpreads.cs │ │ ├── PossibleFragmentSpreadsVisitor.cs │ │ ├── ProvidedNonNullArguments.cs │ │ ├── ProvidedNonNullArgumentsVisitor.cs │ │ ├── ScalarLeafs.cs │ │ ├── ScalarLeafsVisitor.cs │ │ ├── SingleFieldSubscriptions.cs │ │ ├── SingleFieldSubscriptionsVisitor.cs │ │ ├── UniqueArguments.cs │ │ ├── UniqueArgumentsVisitor.cs │ │ ├── UniqueDirectivesPerLocation.cs │ │ ├── UniqueDirectivesPerLocationVisitor.cs │ │ ├── UniqueFragmentNames.cs │ │ ├── UniqueFragmentNamesVisitor.cs │ │ ├── UniqueInputFieldNames.cs │ │ ├── UniqueInputFieldNamesVisitor.cs │ │ ├── UniqueOperationNames.cs │ │ ├── UniqueOperationNamesVisitor.cs │ │ ├── UniqueVariableNames.cs │ │ ├── UniqueVariableNamesVisitor.cs │ │ ├── VariablesAreInputTypes.cs │ │ ├── VariablesAreInputTypesVisitor.cs │ │ ├── VariablesInAllowedPositions.cs │ │ └── VariablesInAllowedPositionsVisitor.cs │ ├── ValidationASTVisitor.cs │ ├── ValidationContext.cs │ ├── VariableUsage.cs │ └── VariableUsagesProvider.cs │ ├── project.json │ ├── ruleset.ruleset │ └── stylecop.json └── test └── GraphQLCore.Tests ├── Events └── InMemoryEventBusTests.cs ├── Exceptions └── GraphQLExceptionTests.cs ├── Execution ├── ExecutionContext_Arguments.cs ├── ExecutionContext_AsyncExecution.cs ├── ExecutionContext_Directives.cs ├── ExecutionContext_Exceptions.cs ├── ExecutionContext_FragmentDefinition.cs ├── ExecutionContext_InputObjectTypes.cs ├── ExecutionContext_Introspection.cs ├── ExecutionContext_NonNull.cs ├── ExecutionContext_Resolve.cs ├── ExecutionContext_Subscription.cs ├── ExecutionContext_ThisInResolver.cs ├── ExecutionContext_Variables.cs └── VariableResolverTests.cs ├── GraphQLCore.Tests.v3.ncrunchproject ├── GraphQLCore.Tests.xproj ├── Language ├── GraphQLAstVisitorTests.cs ├── LexerTests.cs ├── ParserTests.cs ├── SourceTests.cs └── Validation │ ├── LexerValidationTests.cs │ └── ParserValidationTests.cs ├── Properties └── AssemblyInfo.cs ├── Schemas └── TestSchema.cs ├── Type ├── AstFromValueTests.cs ├── Directives │ └── GraphQLDirectiveTypeTests.cs ├── GraphQLInputObjectTypeTests.cs ├── GraphQLInterfaceTypeTests.cs ├── GraphQLObjectTypeTests.cs ├── GraphQLSchemaTests.cs ├── GraphQLSubscriptionTypeTests.cs ├── GraphqlUnionTypeTests.cs ├── IDTests.cs ├── NonNullableTests.cs ├── Scalars │ └── GraphQLIntTests.cs ├── Translation │ └── SchemaRepositoryTests.cs └── ValueFromAstTests.cs ├── Utils ├── PrintSchemaTests.cs ├── ReflectionUtilsTests.cs └── StringUtilsTests.cs ├── Validation ├── ErrorAssert.cs ├── Rules │ ├── ArgumentsOfCorrectTypeTests.cs │ ├── DefaultValuesOfCorrectTypeTests.cs │ ├── FieldsOnCorrectTypeTests.cs │ ├── FragmentsOnCompositeTypesTests.cs │ ├── KnownArgumentNamesTests.cs │ ├── KnownDirectivesTests.cs │ ├── KnownFragmentNamesTests.cs │ ├── KnownTypeNamesTests.cs │ ├── LoneAnonymousOperationTests.cs │ ├── NoFragmentCyclesTests.cs │ ├── NoUndefinedVariablesTests.cs │ ├── NoUnusedFragmentsTests.cs │ ├── NoUnusedVariablesTests.cs │ ├── OverlappingFieldsCanBeMergedTests.cs │ ├── PossibleFragmentSpreadsTests.cs │ ├── ProvidedNonNullArgumentsTests.cs │ ├── ScalarLeafsTests.cs │ ├── SingleFieldSubscriptionsTests.cs │ ├── UniqueArgumentsTests.cs │ ├── UniqueDirectivesPerLocationTests.cs │ ├── UniqueFragmentNamesTest.cs │ ├── UniqueInputFieldNamesTests.cs │ ├── UniqueOperationNamesTests.cs │ ├── UniqueVariableNamesTests.cs │ ├── VariablesAreInputTypesTests.cs │ └── VariablesInAllowedPositionsTests.cs ├── ValidationTestBase.cs └── VariableUsagesProviderTests.cs ├── coverage.cmd ├── data └── KitchenSink.graphql ├── project.json └── watch.cmd /.editorconfig: -------------------------------------------------------------------------------- 1 | root=true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 4 6 | x=a 7 | 8 | [*.cshtml] 9 | indent_style = space 10 | indent_size = 4 11 | 12 | [*.js] 13 | indent_style = space 14 | indent_size = 2 15 | 16 | [*.fsx] 17 | indent_style = space 18 | indent_size = 4 19 | 20 | [*.markdown] 21 | indent_style = space 22 | indent_size = 2 23 | 24 | [*.json] 25 | indent_style = space 26 | indent_size = 4 -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ################### 2 | # compiled source # 3 | ################### 4 | *.com 5 | *.class 6 | *.dll 7 | *.exe 8 | *.pdb 9 | *.dll.config 10 | *.cache 11 | *.suo 12 | # Include dlls if they�re in the NuGet packages directory 13 | !/packages/*/lib/*.dll 14 | !/packages/*/lib/*/*.dll 15 | # Include dlls if they're in the CommonReferences directory 16 | !*CommonReferences/*.dll 17 | #################### 18 | # VS Upgrade stuff # 19 | #################### 20 | UpgradeLog.XML 21 | _UpgradeReport_Files/ 22 | ############### 23 | # Directories # 24 | ############### 25 | bin/ 26 | obj/ 27 | TestResults/ 28 | ################### 29 | # Web publish log # 30 | ################### 31 | *.Publish.xml 32 | ############# 33 | # Resharper # 34 | ############# 35 | /_ReSharper.* 36 | *.ReSharper.* 37 | ############ 38 | # Packages # 39 | ############ 40 | # it�s better to unpack these files and commit the raw source 41 | # git has its own built in compression methods 42 | *.7z 43 | *.dmg 44 | *.gz 45 | *.iso 46 | *.jar 47 | *.rar 48 | *.tar 49 | *.zip 50 | ###################### 51 | # Logs and databases # 52 | ###################### 53 | *.log 54 | *.sqlite 55 | # OS generated files # 56 | ###################### 57 | .DS_Store? 58 | ehthumbs.db 59 | Icon? 60 | Thumbs.db 61 | [Bb]in 62 | [Oo]bj 63 | [Tt]est[Rr]esults 64 | *.suo 65 | *.user 66 | *.[Cc]ache 67 | *[Rr]esharper* 68 | packages 69 | NuGet.exe 70 | _[Ss]cripts 71 | *.exe 72 | *.dll 73 | *.nupkg 74 | *.ncrunchsolution 75 | *.dot[Cc]over 76 | coverage 77 | .vs 78 | *.lock.json 79 | TestResult.xml 80 | coverage.xml 81 | .vscode -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: csharp 2 | sudo: required 3 | dist: trusty 4 | env: 5 | - CLI_VERSION="1.0.0-preview3-003223" 6 | addons: 7 | apt: 8 | packages: 9 | - gettext 10 | - libcurl4-openssl-dev 11 | - libicu-dev 12 | - libssl-dev 13 | - libunwind8 14 | mono: 15 | - latest 16 | os: 17 | - linux 18 | osx_image: xcode7.1 19 | before_install: 20 | - if test "$TRAVIS_OS_NAME" == "osx"; then brew update; brew install openssl; brew link --force openssl; fi 21 | install: 22 | - export DOTNET_INSTALL_DIR="$PWD/.dotnetcli" 23 | - curl -sSL https://raw.githubusercontent.com/dotnet/cli/rel/1.0.0/scripts/obtain/dotnet-install.sh | bash /dev/stdin --version "$CLI_VERSION" --install-dir "$DOTNET_INSTALL_DIR" 24 | - export PATH="$DOTNET_INSTALL_DIR:$PATH" 25 | script: 26 | - dotnet restore 27 | - dotnet build src/GraphQLCore 28 | - dotnet build test/GraphQLCore.Tests 29 | - dotnet test test/GraphQLCore.Tests -f netcoreapp1.0 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Marek Magdziak 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | version: 1.0.{build} 2 | pull_requests: 3 | do_not_increment_build_number: true 4 | nuget: 5 | disable_publish_on_pr: true 6 | configuration: Release 7 | environment: 8 | COVERALLS_REPO_TOKEN: 9 | secure: VaoXqrBdXlsfTTyw2gXbSCvLkOKmb+ick5BAhLdERh/bM6cbgIkOS44IMFL/jH5/ 10 | init: 11 | - ps: iex ((new-object net.webclient).DownloadString('https://gist.githubusercontent.com/PureKrome/0f79e25693d574807939/raw/8cf3160c9516ef1f4effc825c0a44acc918a0b5a/appveyor-build-info.ps')) 12 | before_build: 13 | - nuget install OpenCover -Version 4.6.519 -OutputDirectory .\OpenCover 14 | - nuget install coveralls.net -Version 0.6.0 -OutputDirectory .\coveralls.net 15 | - dotnet restore 16 | build_script: 17 | - dotnet build src\GraphQLCore --configuration Release 18 | - ps: .\CreateArtifacts.ps1 19 | test_script: 20 | - dotnet test .\test\GraphQLCore.Tests\ 21 | - where dotnet 22 | - .\OpenCover\OpenCover.4.6.519\tools\OpenCover.Console.exe -oldstyle -target:"C:\\Program Files\\dotnet\\dotnet.exe" -targetargs:"test .\test\GraphQLCore.Tests" -output:coverage.xml -register:user 23 | - .\coveralls.net\coveralls.net.0.6.0\tools\csmacnz.coveralls.exe --opencover -i .\coverage.xml 24 | artifacts: 25 | - path: .\artifacts\**\*.nupkg 26 | name: NuGet 27 | deploy: 28 | - provider: NuGet 29 | server: https://www.myget.org/F/graphqlcore-ci/api/v2/package 30 | api_key: 31 | secure: HBFsroegv2i8MgKqviGCPhk+1MuouIORGImfdz2jZl4CJOkmOgU6XbwvHdA0O+vf 32 | skip_symbols: true 33 | on: 34 | branch: develop 35 | - provider: NuGet 36 | name: production 37 | api_key: 38 | secure: /MthxnuF3ameISXW4ic3FRRjIc8VU/KFxOOFUHLlH7pJwRftyq8WG+28KGnQGg12 39 | on: 40 | branch: master 41 | -------------------------------------------------------------------------------- /createArtifacts.ps1: -------------------------------------------------------------------------------- 1 | $revision = @{ $true = $env:APPVEYOR_BUILD_NUMBER; $false = 1 }[$env:APPVEYOR_BUILD_NUMBER -ne $NULL]; 2 | $revision = "{0:D4}" -f [convert]::ToInt32($revision, 10) 3 | 4 | dotnet pack .\src\GraphQLCore -c Release -o .\artifacts --version-suffix=$revision -------------------------------------------------------------------------------- /docs/input-object-definition/overview.md: -------------------------------------------------------------------------------- 1 | # Input object definition 2 | 3 | Input object definitions are for defining the form of object that 4 | you can send into the query either through variable or inline. 5 | This definition needs to be separated from an output object definition 6 | due to the fact that input object definitions don't support any 7 | resolvers or nested types. 8 | 9 | ## Example 10 | ### Definition 11 | 12 | ```csharp 13 | public class GraphQLDroidInputObject : GraphQLInputObjectType 14 | { 15 | public GraphQLDroidInputObject() 16 | : base("InputDroid", "Input object for a character in the Star Wars Trilogy") 17 | { 18 | this.Field("id", e => e.Id); 19 | this.Field("name", e => e.Name); 20 | this.Field("appearsIn", e => e.AppearsIn); 21 | this.Field("primaryFunction", e => e.PrimaryFunction); 22 | } 23 | } 24 | 25 | public class Mutation : GraphQLObjectType 26 | { 27 | private CharacterService service = new CharacterService(); 28 | 29 | public Mutation() : base("Mutation", "") 30 | { 31 | this.Field("addDroid", (Droid droid) => this.CreateAndGet(droid)); 32 | } 33 | 34 | private Droid CreateAndGet(Droid droid) 35 | { 36 | return service.CreateDroid(droid); 37 | } 38 | } 39 | ``` 40 | 41 | ### Query 42 | 43 | ```graphql 44 | mutation { 45 | addDroid(droid: { 46 | name : "Death Star Droid", 47 | appearsIn: [NEWHOPE], 48 | primaryFunction: "Spying on Imperial officers" 49 | }) { 50 | id, 51 | name, 52 | appearsIn, 53 | primaryFunction 54 | } 55 | } 56 | ``` 57 | 58 | ### Result 59 | 60 | ```json 61 | { 62 | "addDroid": { 63 | "id" : "c8d97725-d750-4a70-bde2-caad69305904", 64 | "name" : "Death Star Droid", 65 | "appearsIn" : [ "NEWHOPE" ], 66 | "primaryFunction" : "Spying on Imperial officers" 67 | } 68 | } 69 | ``` 70 | 71 | ## Accessors 72 | On input object types you can define only accessors. 73 | For more information about accessors have a look into the 74 | [typed object definition section](../typed-object-definition/overview.md#accessors). -------------------------------------------------------------------------------- /docs/overview.md: -------------------------------------------------------------------------------- 1 | # GraphQL for .NET core documentation 2 | 3 | 1. Scalar type translation 4 | 2. Nullability 5 | 3. [Untyped object definition](untyped-object-definition/overview.md) 6 | - [Resolvers](untyped-object-definition/overview.md#resolvers) 7 | 4. [Typed object definition](typed-object-definition/overview.md) 8 | - [Accessors](typed-object-definition/overview.md#accessors) 9 | - [Resolvers](typed-object-definition/overview.md#resolvers) 10 | 5. [Interfaces](interfaces/overview.md) 11 | - [Accessors](interfaces/overview.md#accessors) 12 | 6. [Input object definition](input-object-definition/overview.md) 13 | - [Accessors](input-object-definition/overview.md#accessors) 14 | 7. Schema 15 | - Queries 16 | - Mutations 17 | - Subscriptions (TBD) 18 | - Execution 19 | 8. Introspection 20 | 9. Validation 21 | 10. Roadmap 22 | 11. Wanna contribute? -------------------------------------------------------------------------------- /docs/typed-object-definition/overview.md: -------------------------------------------------------------------------------- 1 | # Typed object definition 2 | 3 | Typed object definitions are GraphQL definitions bound to a specific 4 | POCO\*. These definitions can't be a root query but a root query can 5 | reference its fields to these definitions by returning a class 6 | object with type that's specified in a typed definition. 7 | 8 | Translation from returned POCO\* to a specific definition is done 9 | automatically. 10 | 11 | ## Example 12 | ### Definition 13 | 14 | ```csharp 15 | class Model 16 | { 17 | public string StringProperty { get; set; } 18 | } 19 | 20 | public class ModelType : GraphQLObjectType 21 | { 22 | public ModelType() : base("Model", "Sample model definition") 23 | { 24 | this.Field("stringProp", e => e.StringProperty); 25 | } 26 | } 27 | 28 | public class Query : GraphQLObjectType 29 | { 30 | public Query() : base("Query", "Sample root query defintion") 31 | { 32 | this.Field("model", () => this.GetModel()); 33 | } 34 | 35 | private Model GetModel() 36 | { 37 | return new Model() { StringProperty = "Test" }; 38 | } 39 | } 40 | ``` 41 | 42 | ### Query 43 | 44 | ```graphql 45 | { 46 | model { 47 | stringProp 48 | } 49 | } 50 | ``` 51 | 52 | ### Result 53 | 54 | ```json 55 | { 56 | "model" : { 57 | "stringProp" : "Test" 58 | } 59 | } 60 | ``` 61 | 62 | ## Accessors 63 | Accessors are field definitions that aim to a specific property of 64 | a given POCO\*. These definitions can't have any input arguments. 65 | Accessors are defined by a lambda expression which contains one parameter 66 | of the defined POCO\* type which represents the instance itself. 67 | 68 | ## Resolvers 69 | 70 | Also in typed input object you can define additional resolvers. 71 | For discovering how resolvers work please referer the resolvers 72 | section in the 73 | [untyped object definition section](../untyped-object-definition/overview.md#resolvers). 74 | 75 | _\* POCO is a plain old CLR object._ -------------------------------------------------------------------------------- /examples/GraphQLCore.GraphiQLExample/Controllers/GraphQLController.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.GraphiQLExample.Controllers 2 | { 3 | using Microsoft.AspNetCore.Mvc; 4 | using Models; 5 | using Newtonsoft.Json; 6 | using System.Dynamic; 7 | using Type; 8 | 9 | [Route("api/[controller]")] 10 | public class GraphQLController : Controller 11 | { 12 | private IGraphQLSchema schema; 13 | 14 | public GraphQLController(IGraphQLSchema schema) 15 | { 16 | this.schema = schema; 17 | } 18 | 19 | [HttpPost] 20 | public JsonResult Post([FromBody] GraphiQLInput input) 21 | { 22 | return this.Json(this.schema.Execute(input.Query, GetVariables(input), input.OperationName)); 23 | } 24 | 25 | private static dynamic GetVariables(GraphiQLInput input) 26 | { 27 | var variables = input.Variables?.ToString(); 28 | 29 | if (string.IsNullOrEmpty(variables)) 30 | return new ExpandoObject(); 31 | 32 | return JsonConvert.DeserializeObject(variables); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /examples/GraphQLCore.GraphiQLExample/GraphQLCore.GraphiQLExample.v3.ncrunchproject: -------------------------------------------------------------------------------- 1 |  2 | 3 | True 4 | 5 | -------------------------------------------------------------------------------- /examples/GraphQLCore.GraphiQLExample/GraphQLCore.GraphiQLExample.xproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 14.0 5 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 6 | 7 | 8 | 9 | 7461d627-8c7a-4ddb-98a1-22c396af749f 10 | GraphQLCore.GraphiQLExample 11 | .\obj 12 | .\bin\ 13 | v4.5.2 14 | 15 | 16 | 2.0 17 | 18 | 19 | -------------------------------------------------------------------------------- /examples/GraphQLCore.GraphiQLExample/Middlewares/GraphQLWs/GraphQLInitHandler.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.GraphiQLExample.Middlewares.GraphQLWs 2 | { 3 | using GraphQLCore.Exceptions; 4 | using GraphQLCore.Type; 5 | using Newtonsoft.Json; 6 | using System; 7 | using System.Net.WebSockets; 8 | using System.Threading; 9 | using System.Threading.Tasks; 10 | 11 | public class GraphQLInitHandler : IGraphQLWsHandler 12 | { 13 | public async Task Handle(WebSocket socket, string clientId, IGraphQLSchema schema, WsInputObject input) 14 | { 15 | var dataString = schema == null 16 | ? CreateFailDataString(new GraphQLException("The server schema is invalid or does not exist.")) 17 | : CreateSuccessDataString(); 18 | 19 | var resultBuffer = System.Text.Encoding.UTF8.GetBytes(dataString); 20 | 21 | await socket.SendAsync( 22 | new ArraySegment(resultBuffer), WebSocketMessageType.Text, true, CancellationToken.None); 23 | } 24 | 25 | private static string CreateSuccessDataString() 26 | { 27 | return JsonConvert.SerializeObject(new 28 | { 29 | type = "init_success" 30 | }); 31 | } 32 | 33 | private static string CreateFailDataString(Exception error) 34 | { 35 | return JsonConvert.SerializeObject(new 36 | { 37 | type = "init_fail", 38 | error 39 | }); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /examples/GraphQLCore.GraphiQLExample/Middlewares/GraphQLWs/GraphQLSubscriptionEndHandler.cs: -------------------------------------------------------------------------------- 1 | using GraphQLCore.Type; 2 | using Newtonsoft.Json; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Net.WebSockets; 7 | using System.Threading; 8 | using System.Threading.Tasks; 9 | 10 | namespace GraphQLCore.GraphiQLExample.Middlewares.GraphQLWs 11 | { 12 | public class GraphQLSubscriptionEndHandler : IGraphQLWsHandler 13 | { 14 | public async Task Handle(WebSocket socket, string clientId, IGraphQLSchema schema, WsInputObject input) 15 | { 16 | await Task.Yield(); 17 | 18 | if (input.Id.HasValue) 19 | { 20 | schema.Unsubscribe(clientId, input.Id.Value); 21 | } 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /examples/GraphQLCore.GraphiQLExample/Middlewares/GraphQLWs/GraphQLSubscriptionStartHandler.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.GraphiQLExample.Middlewares.GraphQLWs 2 | { 3 | using GraphQLCore.Exceptions; 4 | using GraphQLCore.Type; 5 | using Newtonsoft.Json; 6 | using System; 7 | using System.Collections.Generic; 8 | using System.Net.WebSockets; 9 | using System.Threading; 10 | using System.Threading.Tasks; 11 | 12 | public class GraphQLSubscriptionStartHandler : IGraphQLWsHandler 13 | { 14 | public async Task Handle(WebSocket socket, string clientId, IGraphQLSchema schema, WsInputObject input) 15 | { 16 | await Subscribe(socket, clientId, schema, input); 17 | } 18 | 19 | private static async Task Subscribe(WebSocket socket, string clientId, IGraphQLSchema schema, WsInputObject input) 20 | { 21 | var data = (IDictionary)schema.Execute(input.Query, null, null, clientId, input.Id.Value); 22 | 23 | if (data.ContainsKey("errors")) 24 | await SendResponseToExceptions(socket, input.Id.Value, data["errors"]); 25 | else 26 | { 27 | var dataString = JsonConvert.SerializeObject(new {id = input.Id, type = "subscription_success"}); 28 | await SendResponse(socket, dataString); 29 | } 30 | } 31 | 32 | private static async Task SendResponseToExceptions(WebSocket socket, int id, object errors) 33 | { 34 | var dataString = JsonConvert.SerializeObject(new 35 | { 36 | id, 37 | type = "subscription_fail", 38 | payload = new 39 | { 40 | errors 41 | } 42 | }); 43 | 44 | await SendResponse(socket, dataString); 45 | } 46 | 47 | private static async Task SendResponse(WebSocket socket, string dataString) 48 | { 49 | var resultBuffer = System.Text.Encoding.UTF8.GetBytes(dataString); 50 | 51 | await socket.SendAsync( 52 | new ArraySegment(resultBuffer), WebSocketMessageType.Text, true, CancellationToken.None); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /examples/GraphQLCore.GraphiQLExample/Middlewares/GraphQLWs/IGraphQLWsHandler.cs: -------------------------------------------------------------------------------- 1 | using GraphQLCore.Type; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Net.WebSockets; 6 | using System.Threading.Tasks; 7 | 8 | namespace GraphQLCore.GraphiQLExample.Middlewares.GraphQLWs 9 | { 10 | public interface IGraphQLWsHandler 11 | { 12 | Task Handle(WebSocket socket, string clientId, IGraphQLSchema schema, WsInputObject input); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /examples/GraphQLCore.GraphiQLExample/Middlewares/GraphQLWs/WsInputObject.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | 7 | namespace GraphQLCore.GraphiQLExample.Middlewares.GraphQLWs 8 | { 9 | public class WsInputObject 10 | { 11 | [JsonProperty(PropertyName = "type")] 12 | public string Type { get; set; } 13 | 14 | [JsonProperty(PropertyName = "query")] 15 | public string Query { get; set; } 16 | 17 | [JsonProperty(PropertyName = "id")] 18 | public int? Id { get; set; } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /examples/GraphQLCore.GraphiQLExample/Models/Droid.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.GraphiQLExample.Models 2 | { 3 | using System.Collections.Generic; 4 | using Type.Scalar; 5 | 6 | public class Droid : ICharacter 7 | { 8 | public IEnumerable AppearsIn { get; set; } 9 | public IEnumerable Friends { get; set; } 10 | public ID Id { get; set; } 11 | public string Name { get; set; } 12 | public string PrimaryFunction { get; set; } 13 | } 14 | } -------------------------------------------------------------------------------- /examples/GraphQLCore.GraphiQLExample/Models/Episode.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.GraphiQLExample.Models 2 | { 3 | public enum Episode 4 | { 5 | NEWHOPE = 4, 6 | EMPIRE = 5, 7 | JEDI = 6 8 | } 9 | } -------------------------------------------------------------------------------- /examples/GraphQLCore.GraphiQLExample/Models/GraphiQLInput.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.GraphiQLExample.Models 2 | { 3 | public class GraphiQLInput 4 | { 5 | public string OperationName { get; set; } 6 | public string Query { get; set; } 7 | public dynamic Variables { get; set; } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /examples/GraphQLCore.GraphiQLExample/Models/Human.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.GraphiQLExample.Models 2 | { 3 | using System; 4 | using System.Collections.Generic; 5 | using Type.Scalar; 6 | 7 | public class Human : ICharacter 8 | { 9 | public IEnumerable AppearsIn { get; set; } 10 | public IEnumerable Friends { get; set; } 11 | public string HomePlanet { get; set; } 12 | public ID Id { get; set; } 13 | public string Name { get; set; } 14 | public string SecretBackstory { get { throw new Exception("secretBackstory is secret."); } } 15 | } 16 | } -------------------------------------------------------------------------------- /examples/GraphQLCore.GraphiQLExample/Models/ICharacter.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.GraphiQLExample.Models 2 | { 3 | using System.Collections.Generic; 4 | using Type.Scalar; 5 | 6 | public interface ICharacter 7 | { 8 | IEnumerable AppearsIn { get; set; } 9 | IEnumerable Friends { get; set; } 10 | ID Id { get; set; } 11 | string Name { get; set; } 12 | } 13 | } -------------------------------------------------------------------------------- /examples/GraphQLCore.GraphiQLExample/Program.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Builder; 2 | using Microsoft.AspNetCore.Hosting; 3 | using System.IO; 4 | 5 | namespace GraphQLCore.GraphiQLExample 6 | { 7 | public class Program 8 | { 9 | public static void Main(string[] args) 10 | { 11 | var host = new WebHostBuilder() 12 | .UseKestrel() 13 | .UseContentRoot(Directory.GetCurrentDirectory()) 14 | .UseIISIntegration() 15 | .UseStartup() 16 | .Build(); 17 | 18 | host.Run(); 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /examples/GraphQLCore.GraphiQLExample/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:53515/", 7 | "sslPort": 0 8 | } 9 | }, 10 | "profiles": { 11 | "IIS Express": { 12 | "commandName": "IISExpress", 13 | "launchBrowser": true, 14 | "launchUrl": "public/index.html", 15 | "environmentVariables": { 16 | "ASPNETCORE_ENVIRONMENT": "Development" 17 | } 18 | }, 19 | "GraphQLCore.GraphiQLExample": { 20 | "commandName": "Project", 21 | "launchBrowser": true, 22 | "launchUrl": "http://localhost:5000/public/index.html", 23 | "environmentVariables": { 24 | "ASPNETCORE_ENVIRONMENT": "Development" 25 | } 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /examples/GraphQLCore.GraphiQLExample/Schema/GraphQLCharacterInterface.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.GraphiQLExample.Schema 2 | { 3 | using Models; 4 | using Type; 5 | 6 | public class GraphQLCharacterInterface : GraphQLInterfaceType 7 | { 8 | public GraphQLCharacterInterface() 9 | : base("Character", "A character in the Star Wars Trilogy") 10 | { 11 | this.Field("id", e => e.Id).WithDescription( 12 | "The id of the character."); 13 | 14 | this.Field("name", e => e.Name).WithDescription( 15 | "The name of the character."); 16 | 17 | this.Field("friends", e => e.Friends).WithDescription( 18 | "The friends of the character, or an empty list if they " + 19 | "have none."); 20 | 21 | this.Field("appearsIn", e => e.AppearsIn).WithDescription( 22 | "Which movies they appear in."); 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /examples/GraphQLCore.GraphiQLExample/Schema/GraphQLCharacterUnion.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.GraphiQLExample.Schema 2 | { 3 | using System; 4 | using Models; 5 | using Type; 6 | 7 | public class GraphQLCharacterUnion : GraphQLUnionType 8 | { 9 | public GraphQLCharacterUnion() 10 | : base("CharacterUnion", "An union of characters in the Star Wars Trilogy") 11 | { 12 | this.AddPossibleType(typeof(Droid)); 13 | this.AddPossibleType(typeof(Human)); 14 | } 15 | 16 | public override Type ResolveType(object data) 17 | { 18 | if (data is Droid) 19 | return typeof(Droid); 20 | else if (data is Human) 21 | return typeof(Human); 22 | 23 | //If null is returned then the result won't be returned 24 | return null; 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /examples/GraphQLCore.GraphiQLExample/Schema/GraphQLDroidInputObject.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.GraphiQLExample.Schema 2 | { 3 | using Models; 4 | using Type; 5 | 6 | public class GraphQLDroidInputObject : GraphQLInputObjectType 7 | { 8 | public GraphQLDroidInputObject() 9 | : base("InputDroid", "Input object for a character in the Star Wars Trilogy") 10 | { 11 | this.Field("name", e => e.Name) 12 | .WithDefaultValue("DEFAULT_DROID_NAME"); 13 | this.Field("appearsIn", e => e.AppearsIn); 14 | this.Field("primaryFunction", e => e.PrimaryFunction); 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /examples/GraphQLCore.GraphiQLExample/Schema/GraphQLDroidObject.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.GraphiQLExample.Schema 2 | { 3 | using Models; 4 | using Type; 5 | 6 | public class GraphQLDroidObject : GraphQLObjectType 7 | { 8 | public GraphQLDroidObject() 9 | : base("Droid", "A character in the Star Wars Trilogy") 10 | { 11 | this.Field("id", e => e.Id).WithDescription("The id of the droid."); 12 | this.Field("name", e => e.Name).WithDescription("The name of the droid."); 13 | this.Field("friends", e => e.Friends).WithDescription("The friends of the droid, or an empty list if they have none."); 14 | this.Field("appearsIn", e => e.AppearsIn).WithDescription("Which movies they appear in."); 15 | this.Field("primaryFunction", e => e.PrimaryFunction).WithDescription("The primary function of the droid."); 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /examples/GraphQLCore.GraphiQLExample/Schema/GraphQLEpisodeEnum.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.GraphiQLExample.Schema 2 | { 3 | using Models; 4 | using Type; 5 | 6 | public class GraphQLEpisodeEnum : GraphQLEnumType 7 | { 8 | public GraphQLEpisodeEnum() : 9 | base("Episode", "One of the films in the Star Wars Trilogy") 10 | { 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /examples/GraphQLCore.GraphiQLExample/Schema/GraphQLHumanObject.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.GraphiQLExample.Schema 2 | { 3 | using Models; 4 | using Type; 5 | 6 | public class GraphQLHumanObject : GraphQLObjectType 7 | { 8 | public GraphQLHumanObject() 9 | : base("Human", "A humanoid creature in the Star Wars universe.") 10 | { 11 | this.Field("id", e => e.Id).WithDescription("The id of the human."); 12 | this.Field("name", e => e.Name).WithDescription("The name of the human."); 13 | this.Field("friends", e => e.Friends).WithDescription("The friends of the human, or an empty list if they have none."); 14 | this.Field("appearsIn", e => e.AppearsIn).WithDescription("Which movies they appear in."); 15 | this.Field("secretBackstory", e => e.SecretBackstory).WithDescription("Where are they from and how they came to be who they are."); 16 | this.Field("homePlanet", e => e.HomePlanet).WithDescription("The home planet of the human, or null if unknown."); 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /examples/GraphQLCore.GraphiQLExample/Schema/Mutation.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.GraphiQLExample.Schema 2 | { 3 | using Models; 4 | using Services; 5 | using Type; 6 | 7 | public class Mutation : GraphQLObjectType 8 | { 9 | private CharacterService service = new CharacterService(); 10 | 11 | public Mutation() : base("Mutation", "") 12 | { 13 | this.Field("addDroid", (NonNullable droid) => this.CreateAndGet(droid)) 14 | .OnChannel("characters") 15 | .OnChannel("droid"); 16 | } 17 | 18 | private Droid CreateAndGet(Droid droid) 19 | { 20 | return service.CreateDroid(droid); 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /examples/GraphQLCore.GraphiQLExample/Schema/Query.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.GraphiQLExample.Schema 2 | { 3 | using Models; 4 | using Services; 5 | using Type; 6 | 7 | public class Query : GraphQLObjectType 8 | { 9 | public Query() : base("Query", "") 10 | { 11 | var service = new CharacterService(); 12 | 13 | this.Field("hero", (Episode episode) => service.List(episode)); 14 | this.Field("human", (string id) => service.GetHumanById(id)) 15 | .WithDefaultValue("id", "1000"); 16 | this.Field("droid", (string id) => service.GetDroidById(id)); 17 | this.Field("characterUnion", 18 | (string id) => (service.GetDroidById(id) as object) ?? (service.GetHumanById(id) as object)) 19 | .ResolveWithUnion(); 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /examples/GraphQLCore.GraphiQLExample/Schema/StarWarsSchema.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.GraphiQLExample.Schema 2 | { 3 | using Type; 4 | 5 | public class StarWarsSchema : GraphQLSchema 6 | { 7 | public StarWarsSchema() 8 | { 9 | var rootQuery = new Query(); 10 | var rootMutation = new Mutation(); 11 | var subscriptionType = new Subscription(); 12 | 13 | this.AddKnownType(new GraphQLCharacterUnion()); 14 | this.AddKnownType(new GraphQLCharacterInterface()); 15 | this.AddKnownType(new GraphQLHumanObject()); 16 | this.AddKnownType(new GraphQLDroidObject()); 17 | this.AddKnownType(new GraphQLEpisodeEnum()); 18 | this.AddKnownType(new GraphQLDroidInputObject()); 19 | this.AddKnownType(rootQuery); 20 | this.AddKnownType(rootMutation); 21 | this.AddKnownType(subscriptionType); 22 | 23 | this.Query(rootQuery); 24 | this.Mutation(rootMutation); 25 | this.Subscription(subscriptionType); 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /examples/GraphQLCore.GraphiQLExample/Schema/Subscription.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.GraphiQLExample.Schema 2 | { 3 | using Events; 4 | using Execution; 5 | using Models; 6 | using Services; 7 | using System.Linq; 8 | using Type.Complex; 9 | 10 | public class Subscription : GraphQLSubscriptionType 11 | { 12 | public Subscription() : base("Subscription", "", new InMemoryEventBus()) 13 | { 14 | var service = new CharacterService(); 15 | this.Field("characters", (Episode episode) => service.List(episode)) 16 | .WithSubscriptionFilter((IContext ctx, Episode episode) => 17 | ctx.Instance.AppearsIn != null && ctx.Instance.AppearsIn.Contains(episode) == true) 18 | .OnChannel("characters"); 19 | 20 | this.Field("newDroid", ((IContext ctx) => service.GetDroidById(ctx.Instance.Id))) 21 | .OnChannel("droid"); 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /examples/GraphQLCore.GraphiQLExample/Services/CharacterService.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.GraphiQLExample.Services 2 | { 3 | using Data; 4 | using Models; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | 9 | public class CharacterService 10 | { 11 | private static List characterList = new List(); 12 | private static Characters characters = new Characters(); 13 | 14 | static CharacterService() 15 | { 16 | characterList = new List { 17 | characters.Artoo, characters.Han, characters.Leia, characters.Luke, 18 | characters.Tarkin, characters.Threepio, characters.Vader 19 | }; 20 | } 21 | 22 | public Droid GetDroidById(string id) 23 | { 24 | return characterList.SingleOrDefault(e => e.Id == id) as Droid; 25 | } 26 | 27 | public Human GetHumanById(string id) 28 | { 29 | return characterList.SingleOrDefault(e => e.Id == id) as Human; 30 | } 31 | 32 | public IEnumerable List(Episode episode) 33 | { 34 | return characterList.Where(e => e.AppearsIn?.Contains(episode) == true); 35 | } 36 | 37 | internal Droid CreateDroid(Droid droid) 38 | { 39 | var model = new Droid() 40 | { 41 | Id = Guid.NewGuid().ToString(), 42 | AppearsIn = droid.AppearsIn, 43 | Name = droid.Name, 44 | PrimaryFunction = droid.PrimaryFunction 45 | }; 46 | 47 | characterList.Add(model); 48 | 49 | return model; 50 | } 51 | } 52 | } -------------------------------------------------------------------------------- /examples/GraphQLCore.GraphiQLExample/Startup.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.GraphiQLExample 2 | { 3 | using GraphQLCore.GraphiQLExample.Schema; 4 | using GraphQLCore.Type; 5 | using Microsoft.AspNetCore.Builder; 6 | using Microsoft.AspNetCore.Hosting; 7 | using Microsoft.AspNetCore.Http; 8 | using Microsoft.Extensions.Configuration; 9 | using Microsoft.Extensions.DependencyInjection; 10 | using Microsoft.Extensions.FileProviders; 11 | using Microsoft.Extensions.Logging; 12 | using Middlewares; 13 | using System; 14 | using System.IO; 15 | 16 | public class Startup 17 | { 18 | public Startup(IHostingEnvironment env) 19 | { 20 | var builder = new ConfigurationBuilder() 21 | .SetBasePath(env.ContentRootPath) 22 | .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) 23 | .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true) 24 | .AddEnvironmentVariables(); 25 | Configuration = builder.Build(); 26 | } 27 | 28 | public IConfigurationRoot Configuration { get; } 29 | 30 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. 31 | public void Configure( 32 | IApplicationBuilder app, 33 | IServiceProvider serviceProvider, 34 | ILoggerFactory loggerFactory) 35 | { 36 | loggerFactory.AddConsole(Configuration.GetSection("Logging")); 37 | loggerFactory.AddDebug(); 38 | 39 | app.UseWebSockets(); 40 | 41 | app.UseMvc(); 42 | app.UseStaticFiles(new StaticFileOptions() 43 | { 44 | FileProvider = new PhysicalFileProvider(Path.Combine(Directory.GetCurrentDirectory(), @"public")), 45 | RequestPath = new PathString("/public") 46 | }); 47 | 48 | app.AddGraphQLWs(); 49 | } 50 | 51 | // This method gets called by the runtime. Use this method to add services to the container. 52 | public void ConfigureServices(IServiceCollection services) 53 | { 54 | // Add framework services. 55 | services.AddMvc(); 56 | 57 | //Add GraphQLScheme 58 | services.AddSingleton(); 59 | } 60 | } 61 | } -------------------------------------------------------------------------------- /examples/GraphQLCore.GraphiQLExample/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "IncludeScopes": false, 4 | "LogLevel": { 5 | "Default": "Debug", 6 | "System": "Information", 7 | "Microsoft": "Information" 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /examples/GraphQLCore.GraphiQLExample/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "Microsoft.NETCore.App": { 4 | "version": "1.0.0", 5 | "type": "platform" 6 | }, 7 | "Microsoft.AspNetCore.Mvc": "1.0.0", 8 | "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0", 9 | "Microsoft.AspNetCore.Server.Kestrel": "1.0.0", 10 | "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0", 11 | "Microsoft.Extensions.Configuration.FileExtensions": "1.0.0", 12 | "Microsoft.Extensions.Configuration.Json": "1.0.0", 13 | "Microsoft.Extensions.Logging": "1.0.0", 14 | "Microsoft.Extensions.Logging.Console": "1.0.0", 15 | "Microsoft.Extensions.Logging.Debug": "1.0.0", 16 | "Microsoft.AspNetCore.StaticFiles": "1.0.0", 17 | "GraphQLCore": "1.0.0-beta", 18 | "Microsoft.AspNetCore.WebSockets": "1.0.2" 19 | }, 20 | 21 | "tools": { 22 | "Microsoft.AspNetCore.Server.IISIntegration.Tools": "1.0.0-preview2-final" 23 | }, 24 | 25 | "frameworks": { 26 | "netcoreapp1.0": { 27 | "imports": [ 28 | "dotnet5.6", 29 | "dnxcore50", 30 | "portable-net45+win8" 31 | ] 32 | } 33 | }, 34 | 35 | "buildOptions": { 36 | "emitEntryPoint": true, 37 | "preserveCompilationContext": true 38 | }, 39 | 40 | "runtimeOptions": { 41 | "gcServer": true 42 | }, 43 | 44 | "publishOptions": { 45 | "include": [ 46 | "public", 47 | "appsettings.json", 48 | "web.config" 49 | ] 50 | }, 51 | 52 | "scripts": { 53 | "postpublish": [ "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%" ] 54 | } 55 | } -------------------------------------------------------------------------------- /examples/GraphQLCore.GraphiQLExample/web.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /global.json: -------------------------------------------------------------------------------- 1 | { 2 | "projects": [ "src", "test" ], 3 | "sdk": { 4 | "version": "1.0.0-preview2-003121" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /images/fork.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mkmarek/graphql-dotnetcore/8f69b2dd59a097adf94c448d2529b0b7667eddbf/images/fork.png -------------------------------------------------------------------------------- /images/graphql-dotnetcore-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mkmarek/graphql-dotnetcore/8f69b2dd59a097adf94c448d2529b0b7667eddbf/images/graphql-dotnetcore-logo.png -------------------------------------------------------------------------------- /images/graphql-dotnetcore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mkmarek/graphql-dotnetcore/8f69b2dd59a097adf94c448d2529b0b7667eddbf/images/graphql-dotnetcore.png -------------------------------------------------------------------------------- /src/GraphQLCore/Events/IEventBus.cs: -------------------------------------------------------------------------------- 1 | using GraphQLCore.Language.AST; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq.Expressions; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace GraphQLCore.Events 9 | { 10 | public delegate Task MessageReceived(OnMessageReceivedEventArgs args); 11 | 12 | public interface IEventBus 13 | { 14 | event MessageReceived OnMessageReceived; 15 | Task Publish(object data, string channel); 16 | Task Subscribe(EventBusSubscription eventBusSubscription); 17 | void Unsubscribe(string clientId, int subscriptionId); 18 | void Unsubscribe(string clientId); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/GraphQLCore/Events/OnMessageReceivedEventArgs.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using GraphQLCore.Language.AST; 5 | 6 | namespace GraphQLCore.Events 7 | { 8 | public class OnMessageReceivedEventArgs 9 | { 10 | public string ClientId { get; set; } 11 | public int SubscriptionId { get; set; } 12 | public string Channel { get; set; } 13 | public GraphQLDocument Document { get; set; } 14 | public string OperationToExecute { get; set; } 15 | public dynamic Variables { get; internal set; } 16 | public object Data { get; internal set; } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/GraphQLCore/Exceptions/GraphQLResolveException.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Exceptions 2 | { 3 | using System; 4 | 5 | public class GraphQLResolveException : Exception 6 | { 7 | internal GraphQLResolveException(string message) : base(message) 8 | { 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/GraphQLCore/Exceptions/GraphQLValidationException.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Exceptions 2 | { 3 | using System; 4 | using System.Collections.Generic; 5 | 6 | public class GraphQLValidationException : Exception 7 | { 8 | public IEnumerable Errors { get; private set; } 9 | 10 | public GraphQLValidationException(string message, IEnumerable errors) : base(message) 11 | { 12 | this.Errors = errors; 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Execution/ExecutionContext.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Execution 2 | { 3 | using GraphQLCore.Language.AST; 4 | using GraphQLCore.Type; 5 | using GraphQLCore.Type.Translation; 6 | 7 | public class ExecutionContext 8 | { 9 | public ISchemaRepository SchemaRepository { get; set; } 10 | public IVariableResolver VariableResolver { get; set; } 11 | public IFieldCollector FieldCollector { get; set; } 12 | public IGraphQLSchema Schema { get; set; } 13 | public OperationType OperationType { get; set; } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/GraphQLCore/Execution/FieldContext`1.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | 6 | namespace GraphQLCore.Execution 7 | { 8 | internal class FieldContext : IContext 9 | { 10 | public T Instance { get; private set; } 11 | 12 | public FieldContext(T instance) 13 | { 14 | this.Instance = instance; 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/GraphQLCore/Execution/IContext`1.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | namespace GraphQLCore.Execution 3 | { 4 | public interface IContext 5 | { 6 | T Instance { get; } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/GraphQLCore/Execution/IFieldCollector.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Execution 2 | { 3 | using Language.AST; 4 | using System.Collections.Generic; 5 | using Type; 6 | 7 | public interface IFieldCollector 8 | { 9 | Dictionary> CollectFields(GraphQLComplexType runtimeType, GraphQLSelectionSet selectionSet); 10 | } 11 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Execution/IVariableResolver.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Execution 2 | { 3 | using Language.AST; 4 | using Type; 5 | 6 | public interface IVariableResolver 7 | { 8 | Result GetValue(string variableName); 9 | 10 | Result GetValue(GraphQLVariable value); 11 | } 12 | } -------------------------------------------------------------------------------- /src/GraphQLCore/GraphQLCore.v3.ncrunchproject: -------------------------------------------------------------------------------- 1 |  2 | 3 | True 4 | 5 | -------------------------------------------------------------------------------- /src/GraphQLCore/GraphQLCore.xproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 14.0 5 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 6 | 7 | 8 | 9 | 174e41cb-364c-47f1-90d4-838eae75e755 10 | GraphQLCore 11 | .\obj 12 | .\bin\ 13 | v4.5.2 14 | 15 | 16 | 2.0 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/GraphQLCore/Language/AST/ASTNode.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Language.AST 2 | { 3 | public abstract class ASTNode 4 | { 5 | public abstract ASTNodeKind Kind { get; } 6 | public GraphQLLocation Location { get; set; } 7 | } 8 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Language/AST/Enums.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Language.AST 2 | { 3 | public enum ASTNodeKind 4 | { 5 | Name, 6 | Document, 7 | OperationDefinition, 8 | VariableDefinition, 9 | Variable, 10 | SelectionSet, 11 | Field, 12 | Argument, 13 | FragmentSpread, 14 | InlineFragment, 15 | FragmentDefinition, 16 | IntValue, 17 | FloatValue, 18 | StringValue, 19 | BooleanValue, 20 | NullValue, 21 | EnumValue, 22 | ListValue, 23 | ObjectValue, 24 | ObjectField, 25 | Directive, 26 | NamedType, 27 | ListType, 28 | NonNullType, 29 | SchemaDefinition, 30 | OperationTypeDefinition, 31 | ScalarTypeDefinition, 32 | ObjectTypeDefinition, 33 | FieldDefinition, 34 | InputValueDefinition, 35 | InterfaceTypeDefinition, 36 | UnionTypeDefinition, 37 | EnumTypeDefinition, 38 | EnumValueDefinition, 39 | InputObjectTypeDefinition, 40 | TypeExtensionDefinition, 41 | DirectiveDefinition 42 | } 43 | 44 | public enum OperationType 45 | { 46 | Query, 47 | Mutation, 48 | Subscription 49 | } 50 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Language/AST/GraphQLArgument.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Language.AST 2 | { 3 | public class GraphQLArgument : ASTNode 4 | { 5 | public override ASTNodeKind Kind 6 | { 7 | get 8 | { 9 | return ASTNodeKind.Argument; 10 | } 11 | } 12 | 13 | public GraphQLName Name { get; set; } 14 | public GraphQLValue Value { get; set; } 15 | } 16 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Language/AST/GraphQLDirective.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace GraphQLCore.Language.AST 4 | { 5 | public class GraphQLDirective : ASTNode 6 | { 7 | public IEnumerable Arguments { get; set; } 8 | 9 | public override ASTNodeKind Kind 10 | { 11 | get 12 | { 13 | return ASTNodeKind.Directive; 14 | } 15 | } 16 | 17 | public GraphQLName Name { get; set; } 18 | } 19 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Language/AST/GraphQLDirectiveDefinition.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Language.AST 2 | { 3 | using System.Collections.Generic; 4 | 5 | public class GraphQLDirectiveDefinition : GraphQLTypeDefinition 6 | { 7 | public IEnumerable Arguments { get; set; } 8 | 9 | public override ASTNodeKind Kind 10 | { 11 | get 12 | { 13 | return ASTNodeKind.DirectiveDefinition; 14 | } 15 | } 16 | 17 | public IEnumerable Locations { get; set; } 18 | public GraphQLName Name { get; set; } 19 | } 20 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Language/AST/GraphQLDocument.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace GraphQLCore.Language.AST 4 | { 5 | public class GraphQLDocument : ASTNode 6 | { 7 | public IEnumerable Definitions { get; set; } 8 | 9 | public override ASTNodeKind Kind 10 | { 11 | get 12 | { 13 | return ASTNodeKind.Document; 14 | } 15 | } 16 | 17 | public static GraphQLDocument GetAst(string expression) 18 | { 19 | return new Parser(new Lexer()).Parse(new Source(expression)); 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Language/AST/GraphQLEnumTypeDefinition.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace GraphQLCore.Language.AST 4 | { 5 | public class GraphQLEnumTypeDefinition : GraphQLTypeDefinition, IWithDirectives 6 | { 7 | public IEnumerable Directives { get; set; } 8 | 9 | public override ASTNodeKind Kind 10 | { 11 | get 12 | { 13 | return ASTNodeKind.EnumTypeDefinition; 14 | } 15 | } 16 | 17 | public GraphQLName Name { get; set; } 18 | public IEnumerable Values { get; set; } 19 | } 20 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Language/AST/GraphQLEnumValueDefinition.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace GraphQLCore.Language.AST 4 | { 5 | public class GraphQLEnumValueDefinition : GraphQLTypeDefinition, IWithDirectives 6 | { 7 | public IEnumerable Directives { get; set; } 8 | 9 | public override ASTNodeKind Kind 10 | { 11 | get 12 | { 13 | return ASTNodeKind.EnumValueDefinition; 14 | } 15 | } 16 | 17 | public GraphQLName Name { get; set; } 18 | } 19 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Language/AST/GraphQLFieldDefinition.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace GraphQLCore.Language.AST 4 | { 5 | public class GraphQLFieldDefinition : GraphQLTypeDefinition, IWithDirectives 6 | { 7 | public IEnumerable Arguments { get; set; } 8 | 9 | public IEnumerable Directives { get; set; } 10 | 11 | public override ASTNodeKind Kind 12 | { 13 | get 14 | { 15 | return ASTNodeKind.FieldDefinition; 16 | } 17 | } 18 | 19 | public GraphQLName Name { get; set; } 20 | public GraphQLType Type { get; set; } 21 | } 22 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Language/AST/GraphQLFieldSelection.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace GraphQLCore.Language.AST 4 | { 5 | public class GraphQLFieldSelection : ASTNode, IWithDirectives 6 | { 7 | public GraphQLName Alias { get; set; } 8 | 9 | public IEnumerable Arguments { get; set; } 10 | 11 | public IEnumerable Directives { get; set; } 12 | 13 | public override ASTNodeKind Kind 14 | { 15 | get 16 | { 17 | return ASTNodeKind.Field; 18 | } 19 | } 20 | 21 | public GraphQLName Name { get; set; } 22 | public GraphQLSelectionSet SelectionSet { get; set; } 23 | } 24 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Language/AST/GraphQLFragmentDefinition.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Language.AST 2 | { 3 | public class GraphQLFragmentDefinition : GraphQLInlineFragment 4 | { 5 | public override ASTNodeKind Kind 6 | { 7 | get 8 | { 9 | return ASTNodeKind.FragmentDefinition; 10 | } 11 | } 12 | 13 | public GraphQLName Name { get; set; } 14 | } 15 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Language/AST/GraphQLFragmentSpread.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace GraphQLCore.Language.AST 4 | { 5 | public class GraphQLFragmentSpread : ASTNode, IWithDirectives 6 | { 7 | public IEnumerable Directives { get; set; } 8 | 9 | public override ASTNodeKind Kind 10 | { 11 | get 12 | { 13 | return ASTNodeKind.FragmentSpread; 14 | } 15 | } 16 | 17 | public GraphQLName Name { get; set; } 18 | } 19 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Language/AST/GraphQLInlineFragment.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Language.AST 2 | { 3 | using System.Collections.Generic; 4 | 5 | public class GraphQLInlineFragment : ASTNode, IWithDirectives 6 | { 7 | public IEnumerable Directives { get; set; } 8 | 9 | public override ASTNodeKind Kind 10 | { 11 | get 12 | { 13 | return ASTNodeKind.InlineFragment; 14 | } 15 | } 16 | 17 | public GraphQLSelectionSet SelectionSet { get; set; } 18 | public GraphQLNamedType TypeCondition { get; set; } 19 | } 20 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Language/AST/GraphQLInputObjectTypeDefinition.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Language.AST 2 | { 3 | using System.Collections.Generic; 4 | 5 | public class GraphQLInputObjectTypeDefinition : GraphQLTypeDefinition, IWithDirectives 6 | { 7 | public IEnumerable Directives { get; set; } 8 | 9 | public IEnumerable Fields { get; set; } 10 | 11 | public override ASTNodeKind Kind 12 | { 13 | get 14 | { 15 | return ASTNodeKind.InputObjectTypeDefinition; 16 | } 17 | } 18 | 19 | public GraphQLName Name { get; set; } 20 | } 21 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Language/AST/GraphQLInputValueDefinition.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace GraphQLCore.Language.AST 4 | { 5 | public class GraphQLInputValueDefinition : GraphQLTypeDefinition, IWithDirectives 6 | { 7 | public GraphQLValue DefaultValue { get; set; } 8 | 9 | public IEnumerable Directives { get; set; } 10 | 11 | public override ASTNodeKind Kind 12 | { 13 | get 14 | { 15 | return ASTNodeKind.InputValueDefinition; 16 | } 17 | } 18 | 19 | public GraphQLName Name { get; set; } 20 | public GraphQLType Type { get; set; } 21 | } 22 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Language/AST/GraphQLInterfaceTypeDefinition.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace GraphQLCore.Language.AST 4 | { 5 | public class GraphQLInterfaceTypeDefinition : GraphQLTypeDefinition, IWithDirectives 6 | { 7 | public IEnumerable Directives { get; set; } 8 | 9 | public IEnumerable Fields { get; set; } 10 | 11 | public override ASTNodeKind Kind 12 | { 13 | get 14 | { 15 | return ASTNodeKind.InterfaceTypeDefinition; 16 | } 17 | } 18 | 19 | public GraphQLName Name { get; set; } 20 | } 21 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Language/AST/GraphQLListType.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Language.AST 2 | { 3 | public class GraphQLListType : GraphQLType 4 | { 5 | public override ASTNodeKind Kind 6 | { 7 | get 8 | { 9 | return ASTNodeKind.ListType; 10 | } 11 | } 12 | 13 | public GraphQLType Type { get; set; } 14 | 15 | public override string ToString() 16 | { 17 | return $"[{this.Type}]"; 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Language/AST/GraphQLListValue.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Language.AST 2 | { 3 | using System.Collections.Generic; 4 | 5 | public class GraphQLListValue : GraphQLValue 6 | { 7 | private ASTNodeKind kindField; 8 | 9 | public GraphQLListValue(ASTNodeKind kind) 10 | { 11 | this.kindField = kind; 12 | } 13 | 14 | public override ASTNodeKind Kind 15 | { 16 | get 17 | { 18 | return this.kindField; 19 | } 20 | } 21 | 22 | public IEnumerable Values { get; set; } 23 | 24 | public override string ToString() 25 | { 26 | var values = string.Join(", ", this.Values); 27 | 28 | return $"[{values}]"; 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/GraphQLCore/Language/AST/GraphQLLocation.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Language.AST 2 | { 3 | public class GraphQLLocation 4 | { 5 | public int End { get; set; } 6 | public int Start { get; set; } 7 | public ISource Source { get; set; } 8 | } 9 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Language/AST/GraphQLName.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Language.AST 2 | { 3 | public class GraphQLName : ASTNode 4 | { 5 | public override ASTNodeKind Kind 6 | { 7 | get 8 | { 9 | return ASTNodeKind.Name; 10 | } 11 | } 12 | 13 | public string Value { get; set; } 14 | } 15 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Language/AST/GraphQLNamedType.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Language.AST 2 | { 3 | public class GraphQLNamedType : GraphQLType 4 | { 5 | public override ASTNodeKind Kind 6 | { 7 | get 8 | { 9 | return ASTNodeKind.NamedType; 10 | } 11 | } 12 | 13 | public GraphQLName Name { get; set; } 14 | 15 | public override string ToString() 16 | { 17 | return this.Name.Value; 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Language/AST/GraphQLNonNullType.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Language.AST 2 | { 3 | public class GraphQLNonNullType : GraphQLType 4 | { 5 | public override ASTNodeKind Kind 6 | { 7 | get 8 | { 9 | return ASTNodeKind.NonNullType; 10 | } 11 | } 12 | 13 | public GraphQLType Type { get; set; } 14 | 15 | public override string ToString() 16 | { 17 | return this.Type.ToString() + "!"; 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Language/AST/GraphQLNullValue.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Language.AST 2 | { 3 | public class GraphQLNullValue : GraphQLValue 4 | { 5 | public override ASTNodeKind Kind 6 | { 7 | get 8 | { 9 | return ASTNodeKind.NullValue; 10 | } 11 | } 12 | 13 | public override string ToString() 14 | { 15 | return "null"; 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/GraphQLCore/Language/AST/GraphQLObjectField.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Language.AST 2 | { 3 | public class GraphQLObjectField : ASTNode 4 | { 5 | public override ASTNodeKind Kind 6 | { 7 | get 8 | { 9 | return ASTNodeKind.ObjectField; 10 | } 11 | } 12 | 13 | public GraphQLName Name { get; set; } 14 | public GraphQLValue Value { get; set; } 15 | } 16 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Language/AST/GraphQLObjectTypeDefinition.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace GraphQLCore.Language.AST 4 | { 5 | public class GraphQLObjectTypeDefinition : ASTNode, IWithDirectives 6 | { 7 | public IEnumerable Directives { get; set; } 8 | 9 | public IEnumerable Fields { get; set; } 10 | 11 | public IEnumerable Interfaces { get; set; } 12 | 13 | public override ASTNodeKind Kind 14 | { 15 | get 16 | { 17 | return ASTNodeKind.ObjectTypeDefinition; 18 | } 19 | } 20 | 21 | public GraphQLName Name { get; set; } 22 | } 23 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Language/AST/GraphQLObjectValue.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Language.AST 2 | { 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | 6 | public class GraphQLObjectValue : GraphQLValue 7 | { 8 | public IEnumerable Fields { get; set; } 9 | 10 | public override ASTNodeKind Kind 11 | { 12 | get 13 | { 14 | return ASTNodeKind.ObjectValue; 15 | } 16 | } 17 | 18 | public override string ToString() 19 | { 20 | var serializedFields = this.Fields.Select(e => $"{e.Name.Value}: {e.Value}"); 21 | var serializedObject = string.Join(", ", serializedFields); 22 | 23 | return $"{{{serializedObject}}}"; 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/GraphQLCore/Language/AST/GraphQLOperationDefinition.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace GraphQLCore.Language.AST 4 | { 5 | public class GraphQLOperationDefinition : ASTNode, IWithDirectives 6 | { 7 | public IEnumerable Directives { get; set; } 8 | 9 | public override ASTNodeKind Kind 10 | { 11 | get 12 | { 13 | return ASTNodeKind.OperationDefinition; 14 | } 15 | } 16 | 17 | public GraphQLName Name { get; set; } 18 | public OperationType Operation { get; set; } 19 | public GraphQLSelectionSet SelectionSet { get; set; } 20 | public IEnumerable VariableDefinitions { get; set; } 21 | } 22 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Language/AST/GraphQLOperationTypeDefinition.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Language.AST 2 | { 3 | public class GraphQLOperationTypeDefinition : ASTNode 4 | { 5 | public override ASTNodeKind Kind 6 | { 7 | get 8 | { 9 | return ASTNodeKind.OperationTypeDefinition; 10 | } 11 | } 12 | 13 | public OperationType Operation { get; set; } 14 | public GraphQLNamedType Type { get; set; } 15 | } 16 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Language/AST/GraphQLScalarTypeDefinition.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace GraphQLCore.Language.AST 4 | { 5 | public class GraphQLScalarTypeDefinition : GraphQLTypeDefinition, IWithDirectives 6 | { 7 | public IEnumerable Directives { get; set; } 8 | 9 | public override ASTNodeKind Kind 10 | { 11 | get 12 | { 13 | return ASTNodeKind.ScalarTypeDefinition; 14 | } 15 | } 16 | 17 | public GraphQLName Name { get; set; } 18 | } 19 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Language/AST/GraphQLScalarValue.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Language.AST 2 | { 3 | public class GraphQLScalarValue : GraphQLValue 4 | { 5 | private ASTNodeKind kindField; 6 | 7 | public GraphQLScalarValue(ASTNodeKind kind) 8 | { 9 | this.kindField = kind; 10 | } 11 | 12 | public override ASTNodeKind Kind 13 | { 14 | get 15 | { 16 | return this.kindField; 17 | } 18 | } 19 | 20 | public string Value { get; set; } 21 | 22 | public override string ToString() 23 | { 24 | if (this.Kind == ASTNodeKind.StringValue) 25 | return $"\"{this.Value}\""; 26 | 27 | return this.Value.ToString(); 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Language/AST/GraphQLSchemaDefinition.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace GraphQLCore.Language.AST 4 | { 5 | public class GraphQLSchemaDefinition : ASTNode, IWithDirectives 6 | { 7 | public IEnumerable Directives { get; set; } 8 | 9 | public override ASTNodeKind Kind 10 | { 11 | get 12 | { 13 | return ASTNodeKind.SchemaDefinition; 14 | } 15 | } 16 | 17 | public IEnumerable OperationTypes { get; set; } 18 | } 19 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Language/AST/GraphQLSelectionSet.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace GraphQLCore.Language.AST 4 | { 5 | public class GraphQLSelectionSet : ASTNode 6 | { 7 | public override ASTNodeKind Kind 8 | { 9 | get 10 | { 11 | return ASTNodeKind.SelectionSet; 12 | } 13 | } 14 | 15 | public IEnumerable Selections { get; set; } 16 | } 17 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Language/AST/GraphQLType.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Language.AST 2 | { 3 | public abstract class GraphQLType : ASTNode 4 | { 5 | } 6 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Language/AST/GraphQLTypeDefinition.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Language.AST 2 | { 3 | public abstract class GraphQLTypeDefinition : ASTNode 4 | { 5 | } 6 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Language/AST/GraphQLTypeExtensionDefinition.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Language.AST 2 | { 3 | public class GraphQLTypeExtensionDefinition : GraphQLTypeDefinition 4 | { 5 | public GraphQLObjectTypeDefinition Definition { get; set; } 6 | 7 | public override ASTNodeKind Kind 8 | { 9 | get 10 | { 11 | return ASTNodeKind.TypeExtensionDefinition; 12 | } 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Language/AST/GraphQLUnionTypeDefinition.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace GraphQLCore.Language.AST 4 | { 5 | public class GraphQLUnionTypeDefinition : GraphQLTypeDefinition, IWithDirectives 6 | { 7 | public IEnumerable Directives { get; set; } 8 | 9 | public override ASTNodeKind Kind 10 | { 11 | get 12 | { 13 | return ASTNodeKind.UnionTypeDefinition; 14 | } 15 | } 16 | 17 | public GraphQLName Name { get; set; } 18 | public IEnumerable Types { get; set; } 19 | } 20 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Language/AST/GraphQLValue.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Language.AST 2 | { 3 | public abstract class GraphQLValue : ASTNode 4 | { 5 | } 6 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Language/AST/GraphQLVariable.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Language.AST 2 | { 3 | public class GraphQLVariable : GraphQLValue 4 | { 5 | public override ASTNodeKind Kind 6 | { 7 | get 8 | { 9 | return ASTNodeKind.Variable; 10 | } 11 | } 12 | 13 | public GraphQLName Name { get; set; } 14 | } 15 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Language/AST/GraphQLVariableDefinition.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Language.AST 2 | { 3 | public class GraphQLVariableDefinition : ASTNode 4 | { 5 | public GraphQLValue DefaultValue { get; set; } 6 | 7 | public override ASTNodeKind Kind 8 | { 9 | get 10 | { 11 | return ASTNodeKind.VariableDefinition; 12 | } 13 | } 14 | 15 | public GraphQLType Type { get; set; } 16 | public GraphQLVariable Variable { get; set; } 17 | } 18 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Language/AST/IWithDirectives.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | 6 | namespace GraphQLCore.Language.AST 7 | { 8 | public interface IWithDirectives 9 | { 10 | IEnumerable Directives { get; set; } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/GraphQLCore/Language/ILexer.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Language 2 | { 3 | public interface ILexer 4 | { 5 | Token Lex(ISource source); 6 | 7 | Token Lex(ISource source, int start); 8 | } 9 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Language/ISource.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Language 2 | { 3 | public interface ISource 4 | { 5 | string Body { get; set; } 6 | string Name { get; set; } 7 | } 8 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Language/Lexer.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Language 2 | { 3 | public class Lexer : ILexer 4 | { 5 | public Token Lex(ISource source) 6 | { 7 | return this.Lex(source, 0); 8 | } 9 | 10 | public Token Lex(ISource source, int start) 11 | { 12 | using (var context = new LexerContext(source, start)) 13 | { 14 | return context.GetToken(); 15 | } 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Language/Location.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Language 2 | { 3 | using System.Runtime.Serialization; 4 | using System.Text.RegularExpressions; 5 | 6 | public class Location : ISerializable 7 | { 8 | public Location(ISource source, int position) 9 | { 10 | var lineRegex = new Regex("\r\n|[\n\r]", RegexOptions.ECMAScript); 11 | this.Line = 1; 12 | this.Column = position + 1; 13 | 14 | var matches = lineRegex.Matches(source.Body); 15 | foreach (Match match in matches) 16 | { 17 | if (match.Index >= position) 18 | break; 19 | 20 | this.Line++; 21 | this.Column = position + 1 - (match.Index + matches[0].Length); 22 | } 23 | } 24 | 25 | public int Column { get; } 26 | public int Line { get; } 27 | 28 | public void GetObjectData(SerializationInfo info, StreamingContext context) 29 | { 30 | info.AddValue("line", this.Line); 31 | info.AddValue("column", this.Column); 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Language/Parser.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Language 2 | { 3 | using GraphQLCore.Language.AST; 4 | 5 | public class Parser 6 | { 7 | private ILexer lexer; 8 | 9 | public Parser(ILexer lexer) 10 | { 11 | this.lexer = lexer; 12 | } 13 | 14 | public GraphQLDocument Parse(ISource source) 15 | { 16 | using (var context = new ParserContext(source, this.lexer)) 17 | { 18 | return context.Parse(); 19 | } 20 | } 21 | 22 | public GraphQLValue ParseValue(ISource source) 23 | { 24 | using (var context = new ParserContext(source, this.lexer)) 25 | { 26 | return context.ParseValueLiteral(false); 27 | } 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Language/Source.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Language 2 | { 3 | public class Source : ISource 4 | { 5 | public Source(string body) : this(body, "GraphQL") 6 | { 7 | } 8 | 9 | public Source(string body, string name) 10 | { 11 | this.Name = name; 12 | this.Body = MonetizeLineBreaks(body); 13 | } 14 | 15 | public string Body { get; set; } 16 | public string Name { get; set; } 17 | 18 | private static string MonetizeLineBreaks(string input) 19 | { 20 | return (input ?? string.Empty) 21 | .Replace("\r\n", "\n") 22 | .Replace("\r", "\n"); 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Language/Token.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Language 2 | { 3 | public enum TokenKind 4 | { 5 | EOF = 1, 6 | BANG = 2, 7 | DOLLAR = 3, 8 | PAREN_L = 4, 9 | PAREN_R = 5, 10 | SPREAD = 6, 11 | COLON = 7, 12 | EQUALS = 8, 13 | AT = 9, 14 | BRACKET_L = 10, 15 | BRACKET_R = 11, 16 | BRACE_L = 12, 17 | PIPE = 13, 18 | BRACE_R = 14, 19 | NAME = 15, 20 | INT = 16, 21 | FLOAT = 17, 22 | STRING = 18 23 | } 24 | 25 | public class Token 26 | { 27 | public int End { get; set; } 28 | public TokenKind Kind { get; set; } 29 | public int Start { get; set; } 30 | public string Value { get; set; } 31 | 32 | public static string GetTokenKindDescription(TokenKind kind) 33 | { 34 | switch (kind) 35 | { 36 | case TokenKind.EOF: return "EOF"; 37 | case TokenKind.BANG: return "!"; 38 | case TokenKind.DOLLAR: return "$"; 39 | case TokenKind.PAREN_L: return "("; 40 | case TokenKind.PAREN_R: return ")"; 41 | case TokenKind.SPREAD: return "..."; 42 | case TokenKind.COLON: return ":"; 43 | case TokenKind.EQUALS: return "="; 44 | case TokenKind.AT: return "@"; 45 | case TokenKind.BRACKET_L: return "["; 46 | case TokenKind.BRACKET_R: return "]"; 47 | case TokenKind.BRACE_L: return "{"; 48 | case TokenKind.PIPE: return "|"; 49 | case TokenKind.BRACE_R: return "}"; 50 | case TokenKind.NAME: return "Name"; 51 | case TokenKind.INT: return "Int"; 52 | case TokenKind.FLOAT: return "Float"; 53 | case TokenKind.STRING: return "String"; 54 | } 55 | 56 | return string.Empty; 57 | } 58 | 59 | public override string ToString() 60 | { 61 | return this.Value != null 62 | ? $"{GetTokenKindDescription(this.Kind)} \"{this.Value}\"" 63 | : GetTokenKindDescription(this.Kind); 64 | } 65 | } 66 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | 4 | [assembly: AssemblyTitle("GraphQLCore")] 5 | [assembly: AssemblyProduct("GraphQLCore")] 6 | [assembly: AssemblyDescription("GraphQL for .NET Core")] 7 | [assembly: AssemblyCopyright("Copyright 2015-2016 Marek Magdziak All rights reserved.")] 8 | [assembly: AssemblyVersion("1.0.0.0")] 9 | [assembly: AssemblyFileVersion("1.0.0.0")] 10 | [assembly: CLSCompliant(false)] -------------------------------------------------------------------------------- /src/GraphQLCore/Type/Complex/Builders/ArgumentDefinitionBuilder.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Type.Complex 2 | { 3 | using Exceptions; 4 | 5 | public class ArgumentDefinitionBuilder : FieldDefinitionBuilder 6 | { 7 | public ArgumentDefinitionBuilder(GraphQLObjectTypeArgumentInfo argumentInfo) : base(argumentInfo) 8 | { 9 | } 10 | 11 | public ArgumentDefinitionBuilder WithDefaultValue(object defaultValue) 12 | { 13 | this.FieldInfo.DefaultValue = new DefaultValue(defaultValue, this.FieldInfo.SystemType); 14 | 15 | return this; 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/GraphQLCore/Type/Complex/Builders/EnumValueDefinitionBuilder.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Type.Complex 2 | { 3 | public class EnumValueDefinitionBuilder : FieldDefinitionBuilder 4 | { 5 | public EnumValueDefinitionBuilder(GraphQLEnumValueInfo valueInfo) : base(valueInfo) 6 | { 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/GraphQLCore/Type/Complex/Builders/FieldDefinitionBuilder.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Type.Complex 2 | { 3 | using Exceptions; 4 | 5 | public class FieldDefinitionBuilder : FieldDefinitionBuilder 6 | { 7 | public FieldDefinitionBuilder(GraphQLObjectTypeFieldInfo fieldInfo) 8 | : base(fieldInfo) 9 | { 10 | } 11 | 12 | public FieldDefinitionBuilder OnChannel(string channelName) 13 | { 14 | this.FieldInfo.Channel = channelName; 15 | 16 | return this; 17 | } 18 | 19 | public FieldDefinitionBuilder WithDefaultValue(string parameterName, object defaultValue) 20 | { 21 | if (!this.FieldInfo.Arguments.ContainsKey(parameterName)) 22 | throw new GraphQLException($"Argument {parameterName} does not exist."); 23 | 24 | var argument = this.FieldInfo.Arguments[parameterName]; 25 | argument.DefaultValue = new DefaultValue(defaultValue, argument.SystemType); 26 | 27 | return this; 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/GraphQLCore/Type/Complex/Builders/FieldDefinitionBuilder`2.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Type.Complex 2 | { 3 | public abstract class FieldDefinitionBuilder 4 | where TFieldInfo : GraphQLFieldInfo 5 | where TDefinitionBuilder : FieldDefinitionBuilder 6 | { 7 | protected TFieldInfo FieldInfo { get; } 8 | 9 | protected FieldDefinitionBuilder(TFieldInfo fieldInfo) 10 | { 11 | this.FieldInfo = fieldInfo; 12 | } 13 | 14 | public TDefinitionBuilder ResolveWithUnion() 15 | where TUnionType : GraphQLUnionType 16 | { 17 | this.FieldInfo.SystemType = typeof(TUnionType); 18 | 19 | return (TDefinitionBuilder)this; 20 | } 21 | 22 | public TDefinitionBuilder WithDescription(string description) 23 | { 24 | this.FieldInfo.Description = description; 25 | 26 | return (TDefinitionBuilder)this; 27 | } 28 | 29 | public TDefinitionBuilder IsDeprecated(string deprecationReason = "No longer supported") 30 | { 31 | if (deprecationReason != null) 32 | { 33 | this.FieldInfo.IsDeprecated = true; 34 | this.FieldInfo.DeprecationReason = deprecationReason; 35 | } 36 | 37 | return (TDefinitionBuilder)this; 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/GraphQLCore/Type/Complex/Builders/InputFieldDefinitionBuilder`1.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Type.Complex 2 | { 3 | public class InputFieldDefinitionBuilder 4 | : FieldDefinitionBuilder, GraphQLInputObjectTypeFieldInfo> 5 | { 6 | public InputFieldDefinitionBuilder(GraphQLInputObjectTypeFieldInfo fieldInfo) 7 | : base(fieldInfo) 8 | { 9 | } 10 | 11 | public InputFieldDefinitionBuilder WithDefaultValue(TEntityType value) 12 | { 13 | this.FieldInfo.DefaultValue = new DefaultValue(value, this.FieldInfo.SystemType); 14 | 15 | return this; 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/GraphQLCore/Type/Complex/Builders/SubscriptionFieldDefinitionBuilder`1.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Type.Complex 2 | { 3 | using System; 4 | using System.Linq.Expressions; 5 | 6 | public class SubscriptionFieldDefinitionBuilder 7 | : FieldDefinitionBuilder, GraphQLSubscriptionTypeFieldInfo> 8 | { 9 | public SubscriptionFieldDefinitionBuilder(GraphQLSubscriptionTypeFieldInfo fieldInfo) : base(fieldInfo) 10 | { 11 | } 12 | 13 | public SubscriptionFieldDefinitionBuilder WithSubscriptionFilter(Expression> filter) 14 | { 15 | this.FieldInfo.Filter = filter; 16 | 17 | return this; 18 | } 19 | 20 | public SubscriptionFieldDefinitionBuilder WithSubscriptionFilter(LambdaExpression filter) 21 | { 22 | this.FieldInfo.Filter = filter; 23 | 24 | return this; 25 | } 26 | 27 | public SubscriptionFieldDefinitionBuilder OnChannel(string channelName) 28 | { 29 | this.FieldInfo.Channel = channelName; 30 | 31 | return this; 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/GraphQLCore/Type/Complex/GraphQLFieldInfo.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Type.Complex 2 | { 3 | using Introspection; 4 | using System; 5 | using System.Collections.Generic; 6 | using Translation; 7 | 8 | public abstract class GraphQLFieldInfo 9 | { 10 | public string Name { get; set; } 11 | public string Description { get; set; } 12 | public bool IsDeprecated { get; set; } 13 | public string DeprecationReason { get; set; } 14 | public DefaultValue DefaultValue { get; set; } 15 | 16 | public IDictionary Arguments { get; set; } 17 | public abstract Type SystemType { get; set; } 18 | 19 | public GraphQLBaseType GetGraphQLType(ISchemaRepository schemaRepository) 20 | { 21 | return this.GetSchemaType(this.SystemType, schemaRepository); 22 | } 23 | 24 | public NonNullable Introspect(ISchemaRepository schemaRepository) 25 | { 26 | var type = this.GetGraphQLType(schemaRepository) as GraphQLInputType; 27 | 28 | return new IntrospectedInputValue() 29 | { 30 | Name = this.Name, 31 | Description = this.Description, 32 | DefaultValue = this.DefaultValue.GetSerialized(type, schemaRepository), 33 | Type = type.Introspect(schemaRepository) 34 | }; 35 | } 36 | 37 | protected abstract GraphQLBaseType GetSchemaType(Type type, ISchemaRepository schemaRepository); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/GraphQLCore/Type/Complex/GraphQLInputObjectType.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Type 2 | { 3 | using Complex; 4 | using Introspection; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | using Translation; 9 | 10 | public abstract class GraphQLInputObjectType : GraphQLInputType, ISystemTypeBound 11 | { 12 | public abstract Type SystemType { get; protected set; } 13 | 14 | public GraphQLInputObjectType(string name, string description) : base(name, description) 15 | { 16 | this.Fields = new Dictionary(); 17 | } 18 | 19 | protected Dictionary Fields { get; set; } 20 | 21 | public bool ContainsField(string fieldName) 22 | { 23 | return this.Fields.ContainsKey(fieldName); 24 | } 25 | 26 | public GraphQLInputObjectTypeFieldInfo GetFieldInfo(string fieldName) 27 | { 28 | if (!this.ContainsField(fieldName)) 29 | return null; 30 | 31 | return this.Fields[fieldName]; 32 | } 33 | 34 | public GraphQLInputObjectTypeFieldInfo[] GetFieldsInfo() 35 | { 36 | return this.Fields.Select(e => e.Value) 37 | .ToArray(); 38 | } 39 | 40 | public override NonNullable Introspect(ISchemaRepository schemaRepository) 41 | { 42 | var introspectedType = new IntrospectedInputObject(schemaRepository, this); 43 | 44 | introspectedType.Name = this.Name; 45 | introspectedType.Description = this.Description; 46 | introspectedType.Kind = TypeKind.INPUT_OBJECT; 47 | 48 | return introspectedType; 49 | } 50 | } 51 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Type/Complex/GraphQLInputObjectTypeFieldInfo.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Type.Complex 2 | { 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq.Expressions; 6 | using Translation; 7 | using Utils; 8 | 9 | public class GraphQLInputObjectTypeFieldInfo : GraphQLFieldInfo 10 | { 11 | public LambdaExpression Lambda { get; set; } 12 | public override Type SystemType { get; set; } 13 | 14 | public static GraphQLInputObjectTypeFieldInfo CreateAccessorFieldInfo(string fieldName, LambdaExpression accessor, string description) 15 | { 16 | return new GraphQLInputObjectTypeFieldInfo() 17 | { 18 | Name = fieldName, 19 | Arguments = new Dictionary(), 20 | Lambda = accessor, 21 | SystemType = ReflectionUtilities.GetReturnValueFromLambdaExpression(accessor), 22 | Description = description 23 | }; 24 | } 25 | 26 | protected override GraphQLBaseType GetSchemaType(Type type, ISchemaRepository schemaRepository) 27 | { 28 | return schemaRepository.GetSchemaInputTypeFor(type); 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Type/Complex/GraphQLInterfaceType.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Type 2 | { 3 | using Exceptions; 4 | using Introspection; 5 | using System; 6 | using System.Reflection; 7 | using Translation; 8 | 9 | public abstract class GraphQLInterfaceType : GraphQLComplexType 10 | { 11 | private Type interfaceType; 12 | 13 | public GraphQLInterfaceType(string name, string description, Type interfaceType) : base(name, description) 14 | { 15 | if (!interfaceType.GetTypeInfo().IsInterface) 16 | throw new GraphQLException($"Type {interfaceType.FullName} has to be an interface type"); 17 | 18 | this.interfaceType = interfaceType; 19 | } 20 | 21 | public override NonNullable Introspect(ISchemaRepository schemaRepository) 22 | { 23 | var type = base.Introspect(schemaRepository); 24 | 25 | type.Value.Kind = TypeKind.INTERFACE; 26 | 27 | return type; 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Type/Complex/GraphQLInterfaceType`1.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Type 2 | { 3 | using Complex; 4 | using Exceptions; 5 | using System; 6 | using System.Linq.Expressions; 7 | 8 | public abstract class GraphQLInterfaceType : GraphQLInterfaceType 9 | where T : class 10 | { 11 | public override Type SystemType { get; protected set; } 12 | 13 | public GraphQLInterfaceType(string name, string description) : base(name, description, typeof(T)) 14 | { 15 | this.SystemType = typeof(T); 16 | } 17 | 18 | public FieldDefinitionBuilder Field(string fieldName, Expression> accessor, string description = null) 19 | { 20 | if (this.ContainsField(fieldName)) 21 | throw new GraphQLException("Can't insert two fields with the same name."); 22 | 23 | var fieldInfo = this.CreateFieldInfo(fieldName, accessor, description); 24 | this.Fields.Add(fieldName, fieldInfo); 25 | 26 | return new FieldDefinitionBuilder(fieldInfo); 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Type/Complex/GraphQLObjectType.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Type 2 | { 3 | using Complex; 4 | using Exceptions; 5 | using Execution; 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | using System.Linq.Expressions; 9 | using System.Reflection; 10 | 11 | public abstract class GraphQLObjectType : GraphQLComplexType 12 | { 13 | public override System.Type SystemType { get; protected set; } 14 | 15 | public GraphQLObjectType(string name, string description) : base(name, description) 16 | { 17 | this.Fields = new Dictionary(); 18 | this.SystemType = this.GetType(); 19 | } 20 | 21 | public FieldDefinitionBuilder Field(string fieldName, LambdaExpression fieldLambda, string description) 22 | { 23 | return this.AddField(fieldName, fieldLambda, description); 24 | } 25 | 26 | protected virtual FieldDefinitionBuilder AddField(string fieldName, LambdaExpression resolver, string description) 27 | { 28 | if (this.ContainsField(fieldName)) 29 | throw new GraphQLException("Can't insert two fields with the same name."); 30 | 31 | this.ValidateResolver(resolver); 32 | 33 | var fieldInfo = this.CreateResolverFieldInfo(fieldName, resolver, description); 34 | 35 | this.Fields.Add(fieldName, fieldInfo); 36 | 37 | return new FieldDefinitionBuilder(fieldInfo); 38 | } 39 | 40 | private GraphQLObjectTypeFieldInfo CreateResolverFieldInfo(string fieldName, LambdaExpression resolver, string description) 41 | { 42 | return GraphQLObjectTypeFieldInfo.CreateResolverFieldInfo(fieldName, resolver, description); 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Type/Complex/GraphQLObjectTypeArgumentInfo.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Type.Complex 2 | { 3 | using System; 4 | using Translation; 5 | 6 | public class GraphQLObjectTypeArgumentInfo : GraphQLFieldInfo 7 | { 8 | public override Type SystemType { get; set; } 9 | 10 | protected override GraphQLBaseType GetSchemaType(Type type, ISchemaRepository schemaRepository) 11 | { 12 | return schemaRepository.GetSchemaInputTypeFor(type); 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Type/Complex/GraphQLObjectType`1.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Type 2 | { 3 | using Exceptions; 4 | using GraphQLCore.Type.Complex; 5 | using System; 6 | using System.Linq.Expressions; 7 | using Utils; 8 | 9 | public abstract class GraphQLObjectType : GraphQLObjectType 10 | { 11 | public GraphQLObjectType(string name, string description) : base(name, description) 12 | { 13 | this.SystemType = typeof(T); 14 | } 15 | 16 | public FieldDefinitionBuilder Field(string fieldName, Expression> accessor, string description = null) 17 | { 18 | if (this.ContainsField(fieldName)) 19 | throw new GraphQLException("Can't insert two fields with the same name."); 20 | 21 | var fieldInfo = this.CreateFieldInfo(fieldName, accessor, description); 22 | 23 | this.Fields.Add(fieldName, fieldInfo); 24 | 25 | return new FieldDefinitionBuilder(fieldInfo); 26 | } 27 | 28 | public FieldDefinitionBuilder Field(Expression> accessor, string description = null) 29 | { 30 | return this.Field(ReflectionUtilities.GetPropertyInfo(accessor).Name, accessor, description); 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Type/Complex/GraphQLSubscriptionType.cs: -------------------------------------------------------------------------------- 1 | using GraphQLCore.Events; 2 | using GraphQLCore.Exceptions; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq.Expressions; 6 | using System.Text; 7 | 8 | namespace GraphQLCore.Type.Complex 9 | { 10 | public class GraphQLSubscriptionType : GraphQLObjectType 11 | { 12 | public IEventBus EventBus { get; private set; } 13 | 14 | public override System.Type SystemType { get; protected set; } 15 | 16 | public GraphQLSubscriptionType( 17 | string name, 18 | string description, 19 | IEventBus eventBus) : base(name, description) 20 | { 21 | this.EventBus = eventBus; 22 | this.SystemType = this.GetType(); 23 | } 24 | 25 | public SubscriptionFieldDefinitionBuilder Field(string fieldName, LambdaExpression fieldLambda) 26 | { 27 | return this.AddField(fieldName, fieldLambda); 28 | } 29 | 30 | protected virtual SubscriptionFieldDefinitionBuilder AddField( 31 | string fieldName, LambdaExpression resolver) 32 | { 33 | if (this.ContainsField(fieldName)) 34 | throw new GraphQLException("Can't insert two fields with the same name."); 35 | 36 | var fieldInfo = this.CreateResolverFieldInfo(fieldName, resolver); 37 | 38 | this.Fields.Add(fieldName, fieldInfo); 39 | 40 | return new SubscriptionFieldDefinitionBuilder(fieldInfo); 41 | } 42 | 43 | private GraphQLSubscriptionTypeFieldInfo CreateResolverFieldInfo(string fieldName, LambdaExpression resolver) 44 | { 45 | return GraphQLSubscriptionTypeFieldInfo.CreateResolverFieldInfo(fieldName, resolver); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/GraphQLCore/Type/Complex/GraphQLSubscriptionTypeFieldInfo.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Type.Complex 2 | { 3 | using Execution; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Linq.Expressions; 8 | using System.Reflection; 9 | using Translation; 10 | using Utils; 11 | 12 | public class GraphQLSubscriptionTypeFieldInfo : GraphQLObjectTypeFieldInfo 13 | { 14 | public LambdaExpression Filter { get; set; } 15 | 16 | public new static GraphQLSubscriptionTypeFieldInfo CreateResolverFieldInfo(string fieldName, LambdaExpression resolver) 17 | { 18 | return new GraphQLSubscriptionTypeFieldInfo() 19 | { 20 | Name = fieldName, 21 | IsResolver = true, 22 | Lambda = resolver, 23 | Arguments = GetArguments(resolver), 24 | SystemType = ReflectionUtilities.GetReturnValueFromLambdaExpression(resolver), 25 | }; 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Type/Complex/GraphQLUnionType.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Type 2 | { 3 | using Introspection; 4 | using System; 5 | using System.Collections.Generic; 6 | using Translation; 7 | 8 | public abstract class GraphQLUnionType : GraphQLComplexType 9 | { 10 | public override Type SystemType { get; protected set; } 11 | 12 | private List possibleTypes; 13 | public IEnumerable PossibleTypes { get { return this.possibleTypes; } } 14 | 15 | public GraphQLUnionType(string name, string description) : base(name, description) 16 | { 17 | this.SystemType = this.GetType(); 18 | this.possibleTypes = new List(); 19 | } 20 | 21 | public abstract Type ResolveType(object data); 22 | 23 | public override NonNullable Introspect(ISchemaRepository schemaRepository) 24 | { 25 | var introspectedType = base.Introspect(schemaRepository); 26 | 27 | introspectedType.Value.Kind = TypeKind.UNION; 28 | 29 | return introspectedType; 30 | } 31 | 32 | protected void AddPossibleType(Type type) { this.possibleTypes.Add(type); } 33 | } 34 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Type/DefaultValue.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Type 2 | { 3 | using Language.AST; 4 | using System; 5 | using Translation; 6 | using Utils; 7 | 8 | public struct DefaultValue 9 | { 10 | public object Value { get; } 11 | public bool IsSet { get; } 12 | 13 | public DefaultValue(object value, Type systemType) 14 | { 15 | var result = ReflectionUtilities.ChangeValueTypeWithResult(value, systemType); 16 | 17 | this.Value = result.Value; 18 | this.IsSet = result.IsValid; 19 | } 20 | 21 | public GraphQLValue GetAstValue(GraphQLInputType type, ISchemaRepository schemaRepository) 22 | { 23 | if (!this.IsSet) 24 | return null; 25 | 26 | return type.GetAstFromValue(this.Value, schemaRepository); 27 | } 28 | 29 | public string GetSerialized(GraphQLInputType type, ISchemaRepository schemaRepository) 30 | { 31 | return this.GetAstValue(type, schemaRepository)?.ToString(); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/GraphQLCore/Type/Directives/DirectiveLocation.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Type.Directives 2 | { 3 | using System; 4 | 5 | [Flags] 6 | public enum DirectiveLocation 7 | { 8 | // Operations 9 | QUERY = 1, 10 | MUTATION = 2, 11 | SUBSCRIPTION = 4, 12 | FIELD = 8, 13 | FRAGMENT_DEFINITION = 16, 14 | FRAGMENT_SPREAD = 32, 15 | INLINE_FRAGMENT = 64, 16 | 17 | // Schema Definitions 18 | SCHEMA = 128, 19 | SCALAR = 256, 20 | OBJECT = 512, 21 | FIELD_DEFINITION = 1024, 22 | ARGUMENT_DEFINITION = 2048, 23 | INTERFACE = 4096, 24 | UNION = 8192, 25 | ENUM = 16384, 26 | ENUM_VALUE = 32768, 27 | INPUT_OBJECT = 65536, 28 | INPUT_FIELD_DEFINITION = 131072, 29 | } 30 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Type/Directives/GraphQLIncludeDirectiveType.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Type.Directives 2 | { 3 | using GraphQLCore.Type.Scalar; 4 | using GraphQLCore.Type.Translation; 5 | using Language.AST; 6 | using System; 7 | using System.Linq; 8 | using System.Linq.Expressions; 9 | using System.Threading.Tasks; 10 | 11 | public class GraphQLIncludeDirectiveType : GraphQLDirectiveType 12 | { 13 | public GraphQLIncludeDirectiveType() 14 | : base( 15 | "include", 16 | "Directs the executor to include this field or fragment only when the `if` argument is true.", 17 | DirectiveLocation.FIELD, 18 | DirectiveLocation.FRAGMENT_SPREAD, 19 | DirectiveLocation.INLINE_FRAGMENT) 20 | { 21 | this.Argument("if").WithDescription("Included when true."); 22 | } 23 | 24 | public override bool PreExecutionIncludeFieldIntoResult( 25 | GraphQLDirective directive, 26 | ISchemaRepository schemaRepository) 27 | { 28 | var argument = directive.Arguments.Single(e => e.Name.Value == "if"); 29 | var booleanType = new GraphQLBoolean(); 30 | 31 | var result = booleanType.GetFromAst(argument.Value, schemaRepository); 32 | 33 | return (bool)result.Value; 34 | } 35 | 36 | public override LambdaExpression GetResolver(Func> valueGetter, object parentValue) 37 | { 38 | Expression> resolver = (@if) => valueGetter().Result; 39 | 40 | return resolver; 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Type/Directives/GraphQLSkipDirectiveType.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Type.Directives 2 | { 3 | using GraphQLCore.Type.Scalar; 4 | using GraphQLCore.Type.Translation; 5 | using Language.AST; 6 | using System; 7 | using System.Linq; 8 | using System.Linq.Expressions; 9 | using System.Threading.Tasks; 10 | 11 | public class GraphQLSkipDirectiveType : GraphQLDirectiveType 12 | { 13 | public GraphQLSkipDirectiveType() 14 | : base( 15 | "skip", 16 | "Directs the executor to skip this field or fragment when the `if` argument is true.", 17 | DirectiveLocation.FIELD, 18 | DirectiveLocation.FRAGMENT_SPREAD, 19 | DirectiveLocation.INLINE_FRAGMENT) 20 | { 21 | this.Argument("if").WithDescription("Skipped when true."); 22 | } 23 | 24 | public override bool PreExecutionIncludeFieldIntoResult( 25 | GraphQLDirective directive, 26 | ISchemaRepository schemaRepository) 27 | { 28 | var argument = directive.Arguments.Single(e => e.Name.Value == "if"); 29 | var booleanType = new GraphQLBoolean(); 30 | 31 | var result = booleanType.GetFromAst(argument.Value, schemaRepository); 32 | 33 | return !(bool)result.Value; 34 | } 35 | 36 | public override LambdaExpression GetResolver(Func> valueGetter, object parentValue) 37 | { 38 | Expression> resolver = (@if) => valueGetter().Result; 39 | 40 | return resolver; 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Type/GraphQLBaseType.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Type 2 | { 3 | using Introspection; 4 | using Translation; 5 | 6 | public abstract class GraphQLBaseType 7 | { 8 | public GraphQLBaseType(string name, string description) 9 | { 10 | this.Name = name; 11 | this.Description = description; 12 | } 13 | 14 | public string Description { get; protected set; } 15 | public string Name { get; protected set; } 16 | 17 | public abstract NonNullable Introspect(ISchemaRepository schemaRepository); 18 | 19 | public override string ToString() 20 | { 21 | return this.Name; 22 | } 23 | 24 | public abstract bool IsLeafType { get; } 25 | } 26 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Type/GraphQLEnumType`1.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Type 2 | { 3 | using Complex; 4 | using System; 5 | 6 | public class GraphQLEnumType : GraphQLEnumType 7 | where T : struct, IConvertible 8 | { 9 | public GraphQLEnumType(string name, string description) : base(name, description, typeof(T)) 10 | { 11 | } 12 | 13 | protected EnumValueDefinitionBuilder EnumValue(T value) 14 | { 15 | return new EnumValueDefinitionBuilder(this.Values[value.ToString()]); 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Type/GraphQLEnumValueInfo.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Type 2 | { 3 | using Complex; 4 | using Introspection; 5 | using System; 6 | using Translation; 7 | 8 | public class GraphQLEnumValueInfo : GraphQLFieldInfo 9 | { 10 | public override Type SystemType { get; set; } 11 | 12 | protected override GraphQLBaseType GetSchemaType(Type type, ISchemaRepository schemaRepository) 13 | { 14 | return this.GetGraphQLType(schemaRepository); 15 | } 16 | 17 | public NonNullable Introspect() 18 | { 19 | return new IntrospectedEnumValue() 20 | { 21 | Name = this.Name, 22 | Description = this.Description, 23 | IsDeprecated = this.IsDeprecated, 24 | DeprecationReason = this.DeprecationReason 25 | }; 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/GraphQLCore/Type/GraphQLInputType.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Type 2 | { 3 | using Language.AST; 4 | using Translation; 5 | 6 | public abstract class GraphQLInputType : GraphQLBaseType 7 | { 8 | public override bool IsLeafType 9 | { 10 | get 11 | { 12 | return false; 13 | } 14 | } 15 | 16 | public GraphQLInputType(string name, string description) : base(name, description) 17 | { 18 | } 19 | 20 | public abstract Result GetValueFromAst(GraphQLValue astValue, ISchemaRepository schemaRepository); 21 | 22 | public Result GetFromAst(GraphQLValue astValue, ISchemaRepository schemaRepository) 23 | { 24 | if (!(this is GraphQLNonNull) && (astValue == null || astValue.Kind == ASTNodeKind.NullValue)) 25 | return new Result(null); 26 | 27 | if (astValue?.Kind == ASTNodeKind.Variable) 28 | { 29 | var result = schemaRepository.VariableResolver.GetValue((GraphQLVariable)astValue); 30 | 31 | if (result.Value == null && this is GraphQLNonNull) 32 | return Result.Invalid; 33 | 34 | return result; 35 | } 36 | 37 | return this.GetValueFromAst(astValue, schemaRepository); 38 | } 39 | 40 | public GraphQLValue GetAstFromValue(object value, ISchemaRepository schemaRepository) 41 | { 42 | if (value == null && !(this is GraphQLNonNull)) 43 | return new GraphQLNullValue(); 44 | 45 | return this.GetAst(value, schemaRepository); 46 | } 47 | 48 | protected abstract GraphQLValue GetAst(object value, ISchemaRepository schemaRepository); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/GraphQLCore/Type/GraphQLNonNull.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Type 2 | { 3 | using GraphQLCore.Type.Introspection; 4 | using Language.AST; 5 | using Translation; 6 | 7 | public class GraphQLNonNull : GraphQLInputType 8 | { 9 | public override bool IsLeafType 10 | { 11 | get 12 | { 13 | return this.UnderlyingNullableType.IsLeafType; 14 | } 15 | } 16 | 17 | public GraphQLNonNull(GraphQLBaseType nullableType) : base(null, null) 18 | { 19 | this.UnderlyingNullableType = nullableType; 20 | 21 | if (nullableType != null) 22 | this.Name = nullableType.ToString(); 23 | } 24 | 25 | public GraphQLBaseType UnderlyingNullableType { get; private set; } 26 | 27 | public override Result GetValueFromAst(GraphQLValue astValue, ISchemaRepository schemaRepository) 28 | { 29 | if (this.UnderlyingNullableType is GraphQLInputType) 30 | { 31 | var result = ((GraphQLInputType)this.UnderlyingNullableType).GetFromAst(astValue, schemaRepository); 32 | 33 | return result.Value != null ? result : Result.Invalid; 34 | } 35 | 36 | return Result.Invalid; 37 | } 38 | 39 | public override NonNullable Introspect(ISchemaRepository schemaRepository) 40 | { 41 | var introspectedType = new IntrospectedType(); 42 | introspectedType.Kind = TypeKind.NON_NULL; 43 | introspectedType.OfType = this.UnderlyingNullableType.Introspect(schemaRepository); 44 | 45 | return introspectedType; 46 | } 47 | 48 | public override string ToString() 49 | { 50 | return this.UnderlyingNullableType.ToString() + "!"; 51 | } 52 | 53 | protected override GraphQLValue GetAst(object value, ISchemaRepository schemaRepository) 54 | { 55 | if (this.UnderlyingNullableType is GraphQLInputType) 56 | { 57 | var astValue = ((GraphQLInputType)this.UnderlyingNullableType).GetAstFromValue(value, schemaRepository); 58 | 59 | if (astValue.Kind == ASTNodeKind.NullValue) 60 | return null; 61 | 62 | return astValue; 63 | } 64 | 65 | return null; 66 | } 67 | } 68 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Type/IGraphQLSchema.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Type 2 | { 3 | using GraphQLCore.Type.Complex; 4 | using Introspection; 5 | using System.Threading.Tasks; 6 | using Translation; 7 | 8 | public interface IGraphQLSchema 9 | { 10 | event SubscriptionMessageReceived OnSubscriptionMessageReceived; 11 | GraphQLObjectType MutationType { get; } 12 | GraphQLObjectType QueryType { get; } 13 | GraphQLSubscriptionType SubscriptionType { get; } 14 | IntrospectedSchemaType IntrospectedSchema { get; } 15 | ISchemaRepository SchemaRepository { get; } 16 | 17 | dynamic Execute(string expression); 18 | 19 | dynamic Execute(string query, dynamic variables); 20 | 21 | dynamic Execute(string query, dynamic variables, string operationToExecute); 22 | 23 | dynamic Execute(string query, dynamic variables, string operationToExecute, string clientId, int subscriptionId); 24 | 25 | Task ExecuteAsync(string expression); 26 | 27 | Task ExecuteAsync(string query, dynamic variables); 28 | 29 | Task ExecuteAsync(string query, dynamic variables, string operationToExecute); 30 | 31 | Task ExecuteAsync(string query, dynamic variables, string operationToExecute, string clientId, int subscriptionId); 32 | 33 | void Unsubscribe(string clientId, int subscriptionId); 34 | 35 | void Query(GraphQLObjectType root); 36 | 37 | IntrospectedType IntrospectType(string name); 38 | void Unsubscribe(string clientId); 39 | } 40 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Type/ISystemTypeBound.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Type 2 | { 3 | internal interface ISystemTypeBound 4 | { 5 | System.Type SystemType { get; } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/GraphQLCore/Type/Introspection/IntrospectedDirective.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Type.Introspection 2 | { 3 | using Directives; 4 | 5 | public class IntrospectedDirective 6 | { 7 | public NonNullable Name { get; set; } 8 | public string Description { get; set; } 9 | public NonNullable Locations { get; set; } 10 | public NonNullable[]> Arguments { get; set; } 11 | } 12 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Type/Introspection/IntrospectedDirectiveType.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Type.Introspection 2 | { 3 | public class IntrospectedDirectiveType : GraphQLObjectType 4 | { 5 | public IntrospectedDirectiveType() : base( 6 | "__Directive", 7 | "A Directive provides a way to describe alternate runtime execution " + 8 | "and type validation behavior in a GraphQL document.\n\n" + 9 | "In some cases, you need to provide options to alter GraphQL's " + 10 | "execution behavior in ways field arguments will not suffice, such as " + 11 | "conditionally including or skipping a field. Directives provide this by " + 12 | "describing additional information to the executor.") 13 | { 14 | this.Field("name", e => e.Name); 15 | this.Field("description", e => e.Description); 16 | this.Field("locations", e => e.Locations); 17 | this.Field("args", e => e.Arguments); 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Type/Introspection/IntrospectedEnumValue.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Type.Introspection 2 | { 3 | public class IntrospectedEnumValue 4 | { 5 | public NonNullable Name { get; set; } 6 | public string Description { get; set; } 7 | public bool IsDeprecated { get; set; } 8 | public string DeprecationReason { get; set; } 9 | } 10 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Type/Introspection/IntrospectedEnumValueType.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Type.Introspection 2 | { 3 | public class IntrospectedEnumValueType : GraphQLObjectType 4 | { 5 | public IntrospectedEnumValueType() : base( 6 | "__EnumValue", 7 | "One possible value for a given Enum. Enum values are unique " + 8 | "values, not a placeholder for a string or numeric value. However an " + 9 | "Enum value is returned in a JSON response as a string.") 10 | { 11 | this.Field("name", e => e.Name); 12 | this.Field("description", e => e.Description); 13 | this.Field("isDeprecated", e => e.IsDeprecated); 14 | this.Field("deprecationReason", e => e.DeprecationReason); 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Type/Introspection/IntrospectedField.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Type.Introspection 2 | { 3 | public class IntrospectedField 4 | { 5 | public NonNullable[]> Arguments { get; set; } 6 | public string DeprecationReason { get; set; } 7 | public string Description { get; set; } 8 | public bool IsDeprecated { get; set; } 9 | public NonNullable Name { get; set; } 10 | public NonNullable Type { get; set; } 11 | } 12 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Type/Introspection/IntrospectedFieldType.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Type.Introspection 2 | { 3 | public class IntrospectedFieldType : GraphQLObjectType 4 | { 5 | public IntrospectedFieldType() : base( 6 | "__Field", 7 | "Object and Interface types are described by a list of Fields, each of " + 8 | "which has a name, potentially a list of arguments, and a return type.") 9 | { 10 | this.Field("name", e => e.Name); 11 | this.Field("description", e => e.Description); 12 | this.Field("args", e => e.Arguments); 13 | this.Field("type", e => e.Type); 14 | this.Field("isDeprecated", e => e.IsDeprecated); 15 | this.Field("deprecationReason", e => e.DeprecationReason); 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Type/Introspection/IntrospectedInputObject.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Type 2 | { 3 | using Introspection; 4 | using System.Linq; 5 | using Translation; 6 | 7 | public class IntrospectedInputObject : IntrospectedType 8 | { 9 | private ISchemaRepository schemaRepository; 10 | private GraphQLInputObjectType type; 11 | 12 | public IntrospectedInputObject(ISchemaRepository schemaRepository, GraphQLInputObjectType type) 13 | { 14 | this.type = type; 15 | this.schemaRepository = schemaRepository; 16 | } 17 | 18 | public override NonNullable[] InputFields 19 | { 20 | get 21 | { 22 | return this.type.GetFieldsInfo() 23 | .Select(e => e.Introspect(this.schemaRepository)) 24 | .ToArray(); 25 | } 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Type/Introspection/IntrospectedInputValue.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Type.Introspection 2 | { 3 | public class IntrospectedInputValue 4 | { 5 | public NonNullable Name { get; set; } 6 | public string Description { get; set; } 7 | public NonNullable Type { get; set; } 8 | public string DefaultValue { get; set; } 9 | } 10 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Type/Introspection/IntrospectedInputValueType.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Type.Introspection 2 | { 3 | public class IntrospectedInputValueType : GraphQLObjectType 4 | { 5 | public IntrospectedInputValueType() : base( 6 | "__InputValue", 7 | "Arguments provided to Fields or Directives and the input fields of an " + 8 | "InputObject are represented as Input Values which describe their " + 9 | "type and optionally a default value.") 10 | { 11 | this.Field("name", e => e.Name); 12 | this.Field("description", e => e.Description); 13 | this.Field("type", e => e.Type); 14 | this.Field("defaultValue", e => e.DefaultValue).WithDescription( 15 | "A GraphQL-formatted string representing the default value for this " + 16 | "input value."); 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Type/Introspection/IntrospectedType.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Type.Introspection 2 | { 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | 6 | public class IntrospectedType 7 | { 8 | public string Description { get; set; } 9 | 10 | public virtual NonNullable[] EnumValues { get; set; } 11 | 12 | public virtual NonNullable[] Fields { get { return null; } } 13 | 14 | public virtual NonNullable[] InputFields { get { return null; } } 15 | 16 | public virtual NonNullable[] Interfaces { get { return null; } } 17 | 18 | public TypeKind Kind { get; set; } 19 | 20 | public string Name { get; set; } 21 | 22 | public IntrospectedType OfType { get; set; } 23 | 24 | public virtual NonNullable[] PossibleTypes { get { return null; } } 25 | 26 | public IEnumerable> GetFields(bool includeDeprecated) 27 | { 28 | return this.Fields?.Where(e => includeDeprecated || !e.Value.IsDeprecated); 29 | } 30 | 31 | public IEnumerable> GetEnumValues(bool includeDeprecated) 32 | { 33 | return this.EnumValues?.Where(e => includeDeprecated || !e.Value.IsDeprecated); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/GraphQLCore/Type/Introspection/IntrospectedTypeKindType.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Type.Introspection 2 | { 3 | public enum TypeKind 4 | { 5 | SCALAR, 6 | OBJECT, 7 | INTERFACE, 8 | UNION, 9 | ENUM, 10 | INPUT_OBJECT, 11 | LIST, 12 | NON_NULL 13 | } 14 | 15 | public class IntrospectedTypeKindType : GraphQLEnumType 16 | { 17 | public IntrospectedTypeKindType() : base( 18 | "__TypeKind", 19 | "An enum describing what kind of type a given `__Type` is.") 20 | { 21 | this.EnumValue(TypeKind.SCALAR) 22 | .WithDescription("Indicates this type is a scalar."); 23 | this.EnumValue(TypeKind.OBJECT) 24 | .WithDescription("Indicates this type is an object. `fields` and `interfaces` are valid fields."); 25 | this.EnumValue(TypeKind.INTERFACE) 26 | .WithDescription("Indicates this type is an interface. `fields` and `possibleTypes` are valid fields."); 27 | this.EnumValue(TypeKind.UNION) 28 | .WithDescription("Indicates this type is a union. `possibleTypes` is a valid field."); 29 | this.EnumValue(TypeKind.ENUM) 30 | .WithDescription("Indicates this type is an enum. `enumValues` is a valid field."); 31 | this.EnumValue(TypeKind.INPUT_OBJECT) 32 | .WithDescription("Indicates this type is an input object. `inputFields` is a valid field."); 33 | this.EnumValue(TypeKind.LIST) 34 | .WithDescription("Indicates this type is a list. `ofType` is a valid field."); 35 | this.EnumValue(TypeKind.NON_NULL) 36 | .WithDescription("Indicates this type is a non-null. `ofType` is a valid field."); 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Type/Introspection/IntrospectedTypeType.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Type.Introspection 2 | { 3 | using Execution; 4 | 5 | public class IntrospectedTypeType : GraphQLObjectType 6 | { 7 | public IntrospectedTypeType() : base( 8 | "__Type", 9 | "The fundamental unit of any GraphQL Schema is the type. There are " + 10 | "many kinds of types in GraphQL as represented by the `__TypeKind` enum." + 11 | "\n\nDepending on the kind of a type, certain fields describe " + 12 | "information about that type. Scalar types provide no information " + 13 | "beyond a name and description, while Enum types provide their values. " + 14 | "Object and Interface types provide the fields they describe. Abstract " + 15 | "types, Union and Interface, provide the Object types possible " + 16 | "at runtime. List and NonNull types compose other types.") 17 | { 18 | this.Field("kind", e => e.Kind); 19 | this.Field("name", e => e.Name); 20 | this.Field("description", e => e.Description); 21 | this.Field("fields", (IContext type, bool? includeDeprecated) => 22 | type.Instance.GetFields(includeDeprecated.Value)) 23 | .WithDefaultValue("includeDeprecated", false); 24 | this.Field("interfaces", e => e.Interfaces); 25 | this.Field("possibleTypes", e => e.PossibleTypes); 26 | this.Field("enumValues", (IContext type, bool? includeDeprecated) => 27 | type.Instance.GetEnumValues(includeDeprecated.Value)) 28 | .WithDefaultValue("includeDeprecated", false); 29 | this.Field("inputFields", e => e.InputFields); 30 | this.Field("ofType", e => e.OfType); 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Type/Result.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Type 2 | { 3 | public class Result 4 | { 5 | public bool IsValid { get; private set; } 6 | public object Value { get; } 7 | 8 | public Result(object value) 9 | { 10 | this.IsValid = true; 11 | this.Value = value; 12 | } 13 | 14 | public static readonly Result Invalid = new Result(null) 15 | { 16 | IsValid = false 17 | }; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/GraphQLCore/Type/Scalar/GraphQLBoolean.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Type.Scalar 2 | { 3 | using Language.AST; 4 | using System; 5 | using Translation; 6 | using Utils; 7 | 8 | public class GraphQLBoolean : GraphQLScalarType 9 | { 10 | public GraphQLBoolean() : base( 11 | "Boolean", 12 | "The `Boolean` scalar type represents `true` or `false`.") 13 | { 14 | } 15 | 16 | public override Result GetValueFromAst(GraphQLValue astValue, ISchemaRepository schemaRepository) 17 | { 18 | if (astValue.Kind == ASTNodeKind.BooleanValue) 19 | return new Result(((GraphQLScalarValue)astValue).Value.ParseBoolOrGiveNull()); 20 | 21 | return Result.Invalid; 22 | } 23 | 24 | protected override GraphQLValue GetAst(object value, ISchemaRepository schemaRepository) 25 | { 26 | if (value is int) 27 | value = Convert.ToBoolean(value); 28 | 29 | if (!(value is bool)) 30 | return null; 31 | 32 | var stringValue = (bool)value ? "true" : "false"; 33 | 34 | return new GraphQLScalarValue(ASTNodeKind.BooleanValue) 35 | { 36 | Value = stringValue 37 | }; 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Type/Scalar/GraphQLFloat.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Type.Scalar 2 | { 3 | using Language.AST; 4 | using System; 5 | using System.Globalization; 6 | using Translation; 7 | using Utils; 8 | 9 | public class GraphQLFloat : GraphQLScalarType 10 | { 11 | public GraphQLFloat() : base( 12 | "Float", 13 | "The `Float` scalar type represents signed double-precision fractional " + 14 | "values as specified by " + 15 | "[IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point). ") 16 | { 17 | } 18 | 19 | public override Result GetValueFromAst(GraphQLValue astValue, ISchemaRepository schemaRepository) 20 | { 21 | if (astValue.Kind == ASTNodeKind.FloatValue || astValue.Kind == ASTNodeKind.IntValue) 22 | { 23 | var value = ((GraphQLScalarValue)astValue).Value.ParseFloatOrGiveNull(); 24 | if (value != null) 25 | return new Result(value); 26 | } 27 | 28 | return Result.Invalid; 29 | } 30 | 31 | protected override GraphQLValue GetAst(object value, ISchemaRepository schemaRepository) 32 | { 33 | if (!(value is int) && !(value is float) && !(value is double)) 34 | return null; 35 | 36 | var stringValue = value.ToString(); 37 | 38 | var intValue = stringValue.ParseIntOrGiveNull(); 39 | if (intValue != null) 40 | return new GraphQLScalarValue(ASTNodeKind.IntValue) 41 | { 42 | Value = intValue.ToString() 43 | }; 44 | 45 | return new GraphQLScalarValue(ASTNodeKind.FloatValue) 46 | { 47 | Value = ((double)value).ToString(CultureInfo.InvariantCulture).ToLower() 48 | }; 49 | } 50 | } 51 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Type/Scalar/GraphQLID.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Type.Scalar 2 | { 3 | using Language.AST; 4 | using System.Text.RegularExpressions; 5 | using Translation; 6 | using Utils; 7 | 8 | public class GraphQLID : GraphQLScalarType 9 | { 10 | public GraphQLID() : base( 11 | "ID", 12 | "The `ID` scalar type represents a unique identifier, often used to " + 13 | "refetch an object or as key for a cache. The ID type appears in a JSON " + 14 | "response as a String; however, it is not intended to be human-readable. " + 15 | "When expected as an input type, any string (such as `\"4\"`) or integer " + 16 | "(such as `4`) input value will be accepted as an ID.") 17 | { 18 | } 19 | 20 | public override Result GetValueFromAst(GraphQLValue astValue, ISchemaRepository schemaRepository) 21 | { 22 | if (astValue.Kind == ASTNodeKind.StringValue || astValue.Kind == ASTNodeKind.IntValue) 23 | return new Result(((GraphQLScalarValue)astValue).Value); 24 | 25 | return Result.Invalid; 26 | } 27 | 28 | protected override GraphQLValue GetAst(object value, ISchemaRepository schemaRepository) 29 | { 30 | if (value is bool) 31 | value = value.ToString().ToLower(); 32 | 33 | var stringValue = value.ToString(); 34 | if (stringValue.ParseIntOrGiveNull() != null) 35 | return new GraphQLScalarValue(ASTNodeKind.IntValue) 36 | { 37 | Value = stringValue 38 | }; 39 | 40 | return new GraphQLScalarValue(ASTNodeKind.StringValue) 41 | { 42 | Value = Regex.Escape(stringValue) 43 | }; 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/GraphQLCore/Type/Scalar/GraphQLInt.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Type.Scalar 2 | { 3 | using Language.AST; 4 | using System; 5 | using Translation; 6 | using Utils; 7 | 8 | public class GraphQLInt : GraphQLScalarType 9 | { 10 | public GraphQLInt() : base( 11 | "Int", 12 | "The `Int` scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1.") 13 | { 14 | } 15 | 16 | public override Result GetValueFromAst(GraphQLValue astValue, ISchemaRepository schemaRepository) 17 | { 18 | if (astValue.Kind == ASTNodeKind.IntValue) 19 | { 20 | decimal value; 21 | if (!decimal.TryParse(((GraphQLScalarValue)astValue).Value, out value)) 22 | return Result.Invalid; 23 | 24 | if (value <= int.MaxValue && value >= int.MinValue) 25 | return new Result(Convert.ToInt32(value)); 26 | } 27 | 28 | return Result.Invalid; 29 | } 30 | 31 | protected override GraphQLValue GetAst(object value, ISchemaRepository schemaRepository) 32 | { 33 | if (value is float || value is double) 34 | value = value.ToString().ParseIntOrGiveNull(); 35 | 36 | if (!(value is int)) 37 | return null; 38 | 39 | return new GraphQLScalarValue(ASTNodeKind.IntValue) 40 | { 41 | Value = value.ToString() 42 | }; 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Type/Scalar/GraphQLLong.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Type.Scalar 2 | { 3 | using Language.AST; 4 | using System; 5 | using Translation; 6 | using Utils; 7 | 8 | public class GraphQLLong : GraphQLScalarType 9 | { 10 | public GraphQLLong() : base( 11 | "Long", 12 | "The `Long` scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^63) and 2^63 - 1.") 13 | { 14 | } 15 | 16 | public override Result GetValueFromAst(GraphQLValue astValue, ISchemaRepository schemaRepository) 17 | { 18 | if (astValue.Kind == ASTNodeKind.IntValue) 19 | { 20 | decimal value; 21 | if (!decimal.TryParse(((GraphQLScalarValue)astValue).Value, out value)) 22 | return Result.Invalid; 23 | 24 | if (value <= long.MaxValue && value >= long.MinValue) 25 | return new Result(Convert.ToInt64(value)); 26 | } 27 | 28 | return Result.Invalid; 29 | } 30 | 31 | protected override GraphQLValue GetAst(object value, ISchemaRepository schemaRepository) 32 | { 33 | if (value is float || value is double) 34 | value = value.ToString().ParseLongOrGiveNull(); 35 | 36 | if (!(value is long) && !(value is int)) 37 | return null; 38 | 39 | return new GraphQLScalarValue(ASTNodeKind.IntValue) 40 | { 41 | Value = value.ToString() 42 | }; 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Type/Scalar/GraphQLScalarType.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Type.Scalar 2 | { 3 | using Introspection; 4 | using Translation; 5 | 6 | public abstract class GraphQLScalarType : GraphQLInputType 7 | { 8 | public override bool IsLeafType 9 | { 10 | get 11 | { 12 | return true; 13 | } 14 | } 15 | 16 | public GraphQLScalarType(string name, string description) : base(name, description) 17 | { 18 | } 19 | 20 | public override NonNullable Introspect(ISchemaRepository schemaRepository) 21 | { 22 | var introspectedType = new IntrospectedType(); 23 | introspectedType.Name = this.Name; 24 | introspectedType.Description = this.Description; 25 | introspectedType.Kind = TypeKind.SCALAR; 26 | 27 | return introspectedType; 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Type/Scalar/GraphQLString.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Type.Scalar 2 | { 3 | using Language.AST; 4 | using System.Text.RegularExpressions; 5 | using Translation; 6 | using Utils; 7 | 8 | public class GraphQLString : GraphQLScalarType 9 | { 10 | public GraphQLString() : base( 11 | "String", 12 | "The `String` scalar type represents textual data, represented as UTF-8 " + 13 | "character sequences. The String type is most often used by GraphQL to " + 14 | "represent free-form human-readable text.") 15 | { 16 | } 17 | 18 | public override Result GetValueFromAst(GraphQLValue astValue, ISchemaRepository schemaRepository) 19 | { 20 | if (astValue.Kind == ASTNodeKind.StringValue) 21 | return new Result(((GraphQLScalarValue)astValue).Value); 22 | 23 | return Result.Invalid; 24 | } 25 | 26 | protected override GraphQLValue GetAst(object value, ISchemaRepository schemaRepository) 27 | { 28 | return new GraphQLScalarValue(ASTNodeKind.StringValue) 29 | { 30 | Value = value.ParseString() 31 | }; 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Type/Scalar/ID.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Type.Scalar 2 | { 3 | public struct ID 4 | { 5 | private readonly string value; 6 | 7 | public ID(string value) 8 | { 9 | this.value = value; 10 | } 11 | 12 | public static implicit operator ID(string value) 13 | { 14 | return new ID(value); 15 | } 16 | 17 | public static implicit operator ID(uint value) 18 | { 19 | return new ID(value.ToString()); 20 | } 21 | 22 | public static implicit operator ID(ulong value) 23 | { 24 | return new ID(value.ToString()); 25 | } 26 | 27 | public static implicit operator string(ID id) 28 | { 29 | return id.value; 30 | } 31 | 32 | public override string ToString() 33 | { 34 | return this.value; 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/GraphQLCore/Type/Translation/ISchemaRepository.cs: -------------------------------------------------------------------------------- 1 | using GraphQLCore.Execution; 2 | 3 | namespace GraphQLCore.Type.Translation 4 | { 5 | using GraphQLCore.Type.Directives; 6 | using System; 7 | using System.Collections.Generic; 8 | 9 | public interface ISchemaRepository 10 | { 11 | IVariableResolver VariableResolver { get; set; } 12 | 13 | void AddKnownType(GraphQLBaseType type); 14 | 15 | void AddOrReplaceDirective(GraphQLDirectiveType directive); 16 | 17 | GraphQLDirectiveType GetDirective(string name); 18 | 19 | IEnumerable GetDirectives(); 20 | 21 | GraphQLComplexType[] GetImplementingInterfaces(GraphQLComplexType type); 22 | 23 | IEnumerable GetInputKnownTypes(); 24 | 25 | IEnumerable GetOutputKnownTypes(); 26 | 27 | IEnumerable GetAllKnownTypes(); 28 | 29 | GraphQLInputType GetSchemaInputTypeFor(Type type); 30 | 31 | GraphQLBaseType GetSchemaTypeFor(Type type); 32 | 33 | Type GetInputSystemTypeFor(GraphQLBaseType type); 34 | 35 | GraphQLComplexType[] GetTypesImplementing(GraphQLInterfaceType objectType); 36 | 37 | GraphQLComplexType[] GetPossibleTypesForUnion(GraphQLUnionType unionType); 38 | 39 | GraphQLInputType GetSchemaInputTypeByName(string value); 40 | 41 | GraphQLBaseType GetSchemaOutputTypeByName(string value); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/GraphQLCore/Utils/SchemaUtils.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Utils 2 | { 3 | using Type; 4 | 5 | public static class SchemaUtils 6 | { 7 | public static string PrintSchema(IGraphQLSchema schema) 8 | { 9 | var printer = new SchemaPrinter(schema); 10 | return printer.PrintSchema(); 11 | } 12 | 13 | public static string PrintIntrospectionSchema(IGraphQLSchema schema) 14 | { 15 | var printer = new SchemaPrinter(schema); 16 | return printer.PrintIntrospectionSchema(); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/GraphQLCore/Utils/TypeUtilitites.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Utils 2 | { 3 | using System.Globalization; 4 | 5 | public static class TypeUtilitites 6 | { 7 | public static object ParseBoolOrGiveNull(this string valueToParse) 8 | { 9 | bool outValue; 10 | 11 | if (bool.TryParse(valueToParse, out outValue)) 12 | return outValue; 13 | 14 | return null; 15 | } 16 | 17 | public static object ParseFloatOrGiveNull(this string valueToParse) 18 | { 19 | float outValue; 20 | 21 | if (float.TryParse(valueToParse, NumberStyles.Float, CultureInfo.InvariantCulture, out outValue)) 22 | return outValue; 23 | 24 | return null; 25 | } 26 | 27 | public static object ParseIntOrGiveNull(this string valueToParse) 28 | { 29 | int outValue; 30 | 31 | if (int.TryParse(valueToParse, NumberStyles.Integer, CultureInfo.InvariantCulture, out outValue)) 32 | return outValue; 33 | 34 | return null; 35 | } 36 | 37 | public static object ParseLongOrGiveNull(this string valueToParse) 38 | { 39 | long outValue; 40 | 41 | if (long.TryParse(valueToParse, NumberStyles.Integer, CultureInfo.InvariantCulture, out outValue)) 42 | return outValue; 43 | 44 | return null; 45 | } 46 | 47 | public static string ParseString(this object valueToParse) 48 | { 49 | if (valueToParse is bool) 50 | return valueToParse.ToString().ToLower(); 51 | 52 | return valueToParse.ToString().JsonEscape(); 53 | } 54 | } 55 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Validation/Rules/ArgumentsOfCorrectType.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Validation.Rules 2 | { 3 | using Exceptions; 4 | using Language.AST; 5 | using System.Collections.Generic; 6 | using Type; 7 | 8 | public class ArgumentsOfCorrectType : IValidationRule 9 | { 10 | public IEnumerable Validate(GraphQLDocument document, IGraphQLSchema schema) 11 | { 12 | var visitor = new ArgumentsOfCorrectTypeVisitor(schema); 13 | visitor.Visit(document); 14 | 15 | return visitor.Errors; 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Validation/Rules/ArgumentsOfCorrectTypeVisitor.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Validation.Rules 2 | { 3 | using Exceptions; 4 | using Language.AST; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using Type; 8 | 9 | public class ArgumentsOfCorrectTypeVisitor : ValidationASTVisitor 10 | { 11 | public ArgumentsOfCorrectTypeVisitor(IGraphQLSchema schema) : base(schema) 12 | { 13 | this.Errors = new List(); 14 | } 15 | 16 | public List Errors { get; private set; } 17 | 18 | public override GraphQLArgument EndVisitArgument(GraphQLArgument argument) 19 | { 20 | var argumentType = this.GetLastArgumentType(argument); 21 | var astValue = argument.Value; 22 | 23 | var errors = this.LiteralValueValidator.IsValid(argumentType, astValue); 24 | 25 | if (errors.Any()) 26 | this.Errors.Add(this.ComposeError(argument, astValue, errors)); 27 | 28 | return base.EndVisitArgument(argument); 29 | } 30 | 31 | private GraphQLException ComposeError(GraphQLArgument argument, GraphQLValue astValue, IEnumerable innerExceptions) 32 | { 33 | var innerMessage = string.Join("\n", innerExceptions.Select(e => e.Message)); 34 | var exceptionMessage = $"Argument \"{argument.Name.Value}\" has invalid value {astValue}.\n{innerMessage}"; 35 | 36 | return new GraphQLException(exceptionMessage, new[] { argument.Value }); 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Validation/Rules/Conflict.cs: -------------------------------------------------------------------------------- 1 | using GraphQLCore.Language.AST; 2 | 3 | namespace GraphQLCore.Validation.Rules 4 | { 5 | public class Conflict 6 | { 7 | public string ResponseName { get; set; } 8 | public string Reason { get; set; } 9 | public Conflict[] Subreasons { get; set; } 10 | public GraphQLFieldSelection[] Field1 { get; internal set; } 11 | public GraphQLFieldSelection[] Field2 { get; internal set; } 12 | } 13 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Validation/Rules/DefaultValuesOfCorrectType.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Validation.Rules 2 | { 3 | using Exceptions; 4 | using Language.AST; 5 | using System.Collections.Generic; 6 | using Type; 7 | 8 | public class DefaultValuesOfCorrectType : IValidationRule 9 | { 10 | public IEnumerable Validate(GraphQLDocument document, IGraphQLSchema schema) 11 | { 12 | var visitor = new DefaultValuesOfCorrectTypeVisitor(schema); 13 | visitor.Visit(document); 14 | 15 | return visitor.Errors; 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/GraphQLCore/Validation/Rules/FieldsOnCorrectType.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Validation.Rules 2 | { 3 | using Exceptions; 4 | using Language.AST; 5 | using System.Collections.Generic; 6 | using Type; 7 | 8 | public class FieldsOnCorrectType : IValidationRule 9 | { 10 | public IEnumerable Validate(GraphQLDocument document, IGraphQLSchema schema) 11 | { 12 | var visitor = new FieldsOnCorrectTypeVisitor(schema); 13 | visitor.Visit(document); 14 | 15 | return visitor.Errors; 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/GraphQLCore/Validation/Rules/FragmentsOnCompositeTypes.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Validation.Rules 2 | { 3 | using Exceptions; 4 | using Language.AST; 5 | using System.Collections.Generic; 6 | using Type; 7 | 8 | public class FragmentsOnCompositeTypes : IValidationRule 9 | { 10 | public IEnumerable Validate(GraphQLDocument document, IGraphQLSchema schema) 11 | { 12 | var visitor = new FragmentsOnCompositeTypesVisitor(schema); 13 | visitor.Visit(document); 14 | 15 | return visitor.Errors; 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/GraphQLCore/Validation/Rules/IValidationRule.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Validation.Rules 2 | { 3 | using Exceptions; 4 | using Language.AST; 5 | using System.Collections.Generic; 6 | using Type; 7 | 8 | public interface IValidationRule 9 | { 10 | IEnumerable Validate(GraphQLDocument document, IGraphQLSchema schema); 11 | } 12 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Validation/Rules/KnownArgumentNames.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Validation.Rules 2 | { 3 | using Exceptions; 4 | using Language.AST; 5 | using System.Collections.Generic; 6 | using Type; 7 | 8 | public class KnownArgumentNames : IValidationRule 9 | { 10 | public IEnumerable Validate(GraphQLDocument document, IGraphQLSchema schema) 11 | { 12 | var visitor = new KnownArgumentNamesVisitor(schema); 13 | visitor.Visit(document); 14 | 15 | return visitor.Errors; 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Validation/Rules/KnownDirectives.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Validation.Rules 2 | { 3 | using Exceptions; 4 | using Language.AST; 5 | using System.Collections.Generic; 6 | using Type; 7 | 8 | public class KnownDirectives : IValidationRule 9 | { 10 | public IEnumerable Validate(GraphQLDocument document, IGraphQLSchema schema) 11 | { 12 | var visitor = new KnownDirectivesVisitor(schema); 13 | visitor.Visit(document); 14 | 15 | return visitor.Errors; 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Validation/Rules/KnownFragmentNames.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Validation.Rules 2 | { 3 | using Exceptions; 4 | using Language.AST; 5 | using System.Collections.Generic; 6 | using Type; 7 | 8 | public class KnownFragmentNames : IValidationRule 9 | { 10 | public IEnumerable Validate(GraphQLDocument document, IGraphQLSchema schema) 11 | { 12 | var visitor = new KnownFragmentNamesVisitor(schema); 13 | visitor.Visit(document); 14 | 15 | return visitor.Errors; 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/GraphQLCore/Validation/Rules/KnownFragmentNamesVisitor.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Validation.Rules 2 | { 3 | using Exceptions; 4 | using Language; 5 | using Language.AST; 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | using Type; 9 | 10 | public class KnownFragmentNamesVisitor : GraphQLAstVisitor 11 | { 12 | private Dictionary fragmentDefinitions; 13 | 14 | public KnownFragmentNamesVisitor(IGraphQLSchema schema) 15 | { 16 | this.Errors = new List(); 17 | this.fragmentDefinitions = new Dictionary(); 18 | } 19 | 20 | public List Errors { get; private set; } 21 | 22 | public override void Visit(GraphQLDocument document) 23 | { 24 | var fragments = document.Definitions 25 | .Where(e => e.Kind == ASTNodeKind.FragmentDefinition) 26 | .Cast(); 27 | 28 | foreach (var fragment in fragments) 29 | { 30 | if (!this.fragmentDefinitions.ContainsKey(fragment.Name.Value)) 31 | { 32 | this.fragmentDefinitions.Add(fragment.Name.Value, fragment); 33 | } 34 | } 35 | 36 | base.Visit(document); 37 | } 38 | 39 | public override GraphQLFragmentSpread BeginVisitFragmentSpread(GraphQLFragmentSpread node) 40 | { 41 | if (this.GetFragment(node.Name.Value) == null) 42 | this.Errors.Add(new GraphQLException(this.GetErrorMessage(node.Name.Value), new[] { node.Name })); 43 | 44 | return base.BeginVisitFragmentSpread(node); 45 | } 46 | 47 | private GraphQLFragmentDefinition GetFragment(string name) 48 | { 49 | if (this.fragmentDefinitions.ContainsKey(name)) 50 | return this.fragmentDefinitions[name]; 51 | 52 | return null; 53 | } 54 | 55 | private string GetErrorMessage(string fragmentName) 56 | { 57 | return $"Unknown fragment \"{fragmentName}\"."; 58 | } 59 | } 60 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Validation/Rules/KnownTypeNames.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Validation.Rules 2 | { 3 | using Exceptions; 4 | using Language.AST; 5 | using System.Collections.Generic; 6 | using Type; 7 | 8 | public class KnownTypeNames : IValidationRule 9 | { 10 | public IEnumerable Validate(GraphQLDocument document, IGraphQLSchema schema) 11 | { 12 | var visitor = new KnownTypeNamesVisitor(schema); 13 | visitor.Visit(document); 14 | 15 | return visitor.Errors; 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Validation/Rules/KnownTypeNamesVisitor.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Validation.Rules 2 | { 3 | using Exceptions; 4 | using Language; 5 | using Language.AST; 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | using Type; 9 | using Type.Translation; 10 | using Utils; 11 | 12 | public class KnownTypeNamesVisitor : GraphQLAstVisitor 13 | { 14 | private ISchemaRepository schemaRepository; 15 | 16 | public KnownTypeNamesVisitor(IGraphQLSchema schema) 17 | { 18 | this.schemaRepository = schema.SchemaRepository; 19 | this.Errors = new List(); 20 | } 21 | 22 | public List Errors { get; private set; } 23 | 24 | public override GraphQLNamedType BeginVisitNamedType(GraphQLNamedType namedType) 25 | { 26 | var typeName = namedType.Name.Value; 27 | var type = this.GetTypeFromSchema(typeName); 28 | 29 | if (type == null) 30 | { 31 | this.Errors.Add( 32 | new GraphQLException(this.ComposeErrorMessage(typeName), new[] { namedType })); 33 | } 34 | 35 | return base.BeginVisitNamedType(namedType); 36 | } 37 | 38 | private string ComposeErrorMessage(string typeName) 39 | { 40 | var schemaTypeNames = this.schemaRepository.GetInputKnownTypes() 41 | .Select(e => e.Name) 42 | .Union(this.schemaRepository.GetOutputKnownTypes() 43 | .Select(e => e.Name)) 44 | .ToArray(); 45 | 46 | var suggestedTypes = StringUtils.SuggestionList(typeName, schemaTypeNames); 47 | 48 | return $"Unknown type \"{typeName}\"." + 49 | (suggestedTypes.Any() 50 | ? $" Did you mean {StringUtils.QuotedOrList(suggestedTypes)}?" 51 | : string.Empty); 52 | } 53 | 54 | private GraphQLBaseType GetTypeFromSchema(string typeName) 55 | { 56 | return this.schemaRepository.GetSchemaInputTypeByName(typeName) ?? 57 | this.schemaRepository.GetSchemaOutputTypeByName(typeName); 58 | } 59 | } 60 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Validation/Rules/LoneAnonymousOperation.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Validation.Rules 2 | { 3 | using Exceptions; 4 | using Language.AST; 5 | using System.Collections.Generic; 6 | using Type; 7 | 8 | public class LoneAnonymousOperation : IValidationRule 9 | { 10 | public IEnumerable Validate(GraphQLDocument document, IGraphQLSchema schema) 11 | { 12 | var visitor = new LoneAnonymousOperationVisitor(schema); 13 | visitor.Visit(document); 14 | 15 | return visitor.Errors; 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Validation/Rules/LoneAnonymousOperationVisitor.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Validation.Rules 2 | { 3 | using Exceptions; 4 | using Language.AST; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using Type; 8 | 9 | public class LoneAnonymousOperationVisitor : ValidationASTVisitor 10 | { 11 | private int operationCount; 12 | 13 | public LoneAnonymousOperationVisitor(IGraphQLSchema schema) : base(schema) 14 | { 15 | this.Errors = new List(); 16 | } 17 | 18 | public List Errors { get; private set; } 19 | 20 | public override void Visit(GraphQLDocument document) 21 | { 22 | this.operationCount = document.Definitions 23 | .Where(e => e.Kind == ASTNodeKind.OperationDefinition) 24 | .Count(); 25 | 26 | base.Visit(document); 27 | } 28 | 29 | public override GraphQLOperationDefinition BeginVisitOperationDefinition(GraphQLOperationDefinition definition) 30 | { 31 | if (definition.Name == null && this.operationCount > 1) 32 | { 33 | this.Errors.Add(new GraphQLException("This anonymous operation must be the only defined operation.", new[] { definition })); 34 | } 35 | 36 | return definition; 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Validation/Rules/NoFragmentCycles.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Validation.Rules 2 | { 3 | using Exceptions; 4 | using Language.AST; 5 | using System.Collections.Generic; 6 | using Type; 7 | 8 | public class NoFragmentCycles : IValidationRule 9 | { 10 | public IEnumerable Validate(GraphQLDocument document, IGraphQLSchema schema) 11 | { 12 | var visitor = new NoFragmentCyclesVisitor(schema); 13 | visitor.Visit(document); 14 | 15 | return visitor.Errors; 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/GraphQLCore/Validation/Rules/NoUndefinedVariables.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Validation.Rules 2 | { 3 | using Exceptions; 4 | using Language.AST; 5 | using System.Collections.Generic; 6 | using Type; 7 | 8 | public class NoUndefinedVariables : IValidationRule 9 | { 10 | public IEnumerable Validate(GraphQLDocument document, IGraphQLSchema schema) 11 | { 12 | var visitor = new NoUndefinedVariablesVisitor(schema); 13 | visitor.Visit(document); 14 | 15 | return visitor.Errors; 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/GraphQLCore/Validation/Rules/NoUnusedFragments.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Validation.Rules 2 | { 3 | using Exceptions; 4 | using Language.AST; 5 | using System.Collections.Generic; 6 | using Type; 7 | 8 | public class NoUnusedFragments : IValidationRule 9 | { 10 | public IEnumerable Validate(GraphQLDocument document, IGraphQLSchema schema) 11 | { 12 | var visitor = new NoUnusedFragmentsVisitor(schema); 13 | visitor.Visit(document); 14 | 15 | return visitor.Errors; 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Validation/Rules/NoUnusedFragmentsVisitor.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Validation.Rules 2 | { 3 | using Exceptions; 4 | using Language; 5 | using Language.AST; 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | using Type; 9 | 10 | public class NoUnusedFragmentsVisitor : GraphQLAstVisitor 11 | { 12 | private Dictionary fragmentDefinitions; 13 | 14 | public NoUnusedFragmentsVisitor(IGraphQLSchema schema) 15 | { 16 | this.fragmentDefinitions = new Dictionary(); 17 | this.Errors = new List(); 18 | } 19 | 20 | public List Errors { get; private set; } 21 | 22 | public override GraphQLFragmentSpread BeginVisitFragmentSpread(GraphQLFragmentSpread fragmentSpread) 23 | { 24 | var key = fragmentSpread.Name.Value; 25 | 26 | if (this.fragmentDefinitions.ContainsKey(key)) 27 | { 28 | var definition = this.fragmentDefinitions[key]; 29 | this.fragmentDefinitions.Remove(key); 30 | 31 | base.BeginVisitFragmentDefinition(definition); 32 | } 33 | 34 | return base.BeginVisitFragmentSpread(fragmentSpread); 35 | } 36 | 37 | public override GraphQLFragmentDefinition BeginVisitFragmentDefinition(GraphQLFragmentDefinition node) 38 | { 39 | return node; 40 | } 41 | 42 | public override void Visit(GraphQLDocument ast) 43 | { 44 | var fragments = ast.Definitions 45 | .Where(e => e.Kind == ASTNodeKind.FragmentDefinition) 46 | .Cast(); 47 | 48 | foreach (var fragment in fragments) 49 | { 50 | if (!this.fragmentDefinitions.ContainsKey(fragment.Name.Value)) 51 | { 52 | this.fragmentDefinitions.Add(fragment.Name.Value, fragment); 53 | } 54 | } 55 | 56 | base.Visit(ast); 57 | 58 | foreach (var unusedFragment in this.fragmentDefinitions) 59 | { 60 | this.Errors.Add(new GraphQLException($"Fragment \"{unusedFragment.Key}\" is never used.", 61 | new[] { unusedFragment.Value })); 62 | } 63 | } 64 | } 65 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Validation/Rules/NoUnusedVariables.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Validation.Rules 2 | { 3 | using Exceptions; 4 | using Language.AST; 5 | using System.Collections.Generic; 6 | using Type; 7 | 8 | public class NoUnusedVariables : IValidationRule 9 | { 10 | public IEnumerable Validate(GraphQLDocument document, IGraphQLSchema schema) 11 | { 12 | var visitor = new NoUnusedVariablesVisitor(schema); 13 | visitor.Visit(document); 14 | 15 | return visitor.Errors; 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Validation/Rules/NodeAndDefinitions.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Validation.Rules 2 | { 3 | using GraphQLCore.Language.AST; 4 | using GraphQLCore.Type; 5 | using GraphQLCore.Type.Complex; 6 | 7 | public class NodeAndDefinitions 8 | { 9 | public string PresumedParentName { get; set; } 10 | public GraphQLObjectTypeFieldInfo FieldDefinition { get; set; } 11 | public GraphQLBaseType ParentType { get; set; } 12 | public GraphQLFieldSelection Selection { get; set; } 13 | } 14 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Validation/Rules/OverlappingFieldsCanBeMerged.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Validation.Rules 2 | { 3 | using Exceptions; 4 | using Language.AST; 5 | using System.Collections.Generic; 6 | using Type; 7 | 8 | public class OverlappingFieldsCanBeMerged : IValidationRule 9 | { 10 | public IEnumerable Validate(GraphQLDocument document, IGraphQLSchema schema) 11 | { 12 | var visitor = new OverlappingFieldsCanBeMergedVisitor(schema); 13 | visitor.Visit(document); 14 | 15 | return visitor.Errors; 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Validation/Rules/PossibleFragmentSpreads.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Validation.Rules 2 | { 3 | using Exceptions; 4 | using Language.AST; 5 | using System.Collections.Generic; 6 | using Type; 7 | 8 | public class PossibleFragmentSpreads : IValidationRule 9 | { 10 | public IEnumerable Validate(GraphQLDocument document, IGraphQLSchema schema) 11 | { 12 | var visitor = new PossibleFragmentSpreadsVisitor(schema); 13 | visitor.Visit(document); 14 | 15 | return visitor.Errors; 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Validation/Rules/ProvidedNonNullArguments.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Validation.Rules 2 | { 3 | using Exceptions; 4 | using Language.AST; 5 | using System.Collections.Generic; 6 | using Type; 7 | 8 | public class ProvidedNonNullArguments : IValidationRule 9 | { 10 | public IEnumerable Validate(GraphQLDocument document, IGraphQLSchema schema) 11 | { 12 | var visitor = new ProvidedNonNullArgumentsVisitor(schema); 13 | visitor.Visit(document); 14 | 15 | return visitor.Errors; 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Validation/Rules/ScalarLeafs.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Validation.Rules 2 | { 3 | using Exceptions; 4 | using Language.AST; 5 | using System.Collections.Generic; 6 | using Type; 7 | 8 | public class ScalarLeafs : IValidationRule 9 | { 10 | public IEnumerable Validate(GraphQLDocument document, IGraphQLSchema schema) 11 | { 12 | var visitor = new ScalarLeafsVisitor(schema); 13 | visitor.Visit(document); 14 | 15 | return visitor.Errors; 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Validation/Rules/ScalarLeafsVisitor.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Validation.Rules 2 | { 3 | using Exceptions; 4 | using Language.AST; 5 | using System.Collections.Generic; 6 | using Type; 7 | 8 | public class ScalarLeafsVisitor : ValidationASTVisitor 9 | { 10 | public ScalarLeafsVisitor(IGraphQLSchema schema) : base(schema) 11 | { 12 | this.Errors = new List(); 13 | } 14 | 15 | public List Errors { get; private set; } 16 | 17 | public override GraphQLFieldSelection EndVisitFieldSelection(GraphQLFieldSelection selection) 18 | { 19 | var type = this.GetLastType(); 20 | 21 | if (type == null) 22 | return base.EndVisitFieldSelection(selection); 23 | 24 | if (type.IsLeafType && selection?.SelectionSet != null) 25 | { 26 | this.Errors.Add(new GraphQLException( 27 | this.NoScalarSubselection(selection.Name.Value, type), 28 | new[] { selection.SelectionSet })); 29 | } 30 | else if (!type.IsLeafType && selection?.SelectionSet == null) 31 | { 32 | this.Errors.Add(new GraphQLException( 33 | this.RequiredSubselectionMessage(selection.Name.Value, type), 34 | new[] { selection })); 35 | } 36 | 37 | return base.EndVisitFieldSelection(selection); 38 | } 39 | 40 | private string NoScalarSubselection(string fieldName, GraphQLBaseType type) 41 | { 42 | return $"Field \"{fieldName}\" must not have a selection since " + 43 | $"type \"{type}\" has no subfields."; 44 | } 45 | 46 | private string RequiredSubselectionMessage(string fieldName, GraphQLBaseType type) 47 | { 48 | return $"Field \"{fieldName}\" of type \"{type}\" must have a " + 49 | $"selection of subfields. Did you mean \"{fieldName} " + "{ ... }\"?"; 50 | } 51 | } 52 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Validation/Rules/SingleFieldSubscriptions.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Validation.Rules 2 | { 3 | using Exceptions; 4 | using Language.AST; 5 | using System.Collections.Generic; 6 | using Type; 7 | 8 | public class SingleFieldSubscriptions : IValidationRule 9 | { 10 | public IEnumerable Validate(GraphQLDocument document, IGraphQLSchema schema) 11 | { 12 | var visitor = new SingleFieldSubscriptionsVisitor(schema); 13 | visitor.Visit(document); 14 | 15 | return visitor.Errors; 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Validation/Rules/SingleFieldSubscriptionsVisitor.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Validation.Rules 2 | { 3 | using Exceptions; 4 | using Language.AST; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using Type; 8 | using Type.Complex; 9 | using Type.Directives; 10 | using Type.Translation; 11 | using Utils; 12 | 13 | public class SingleFieldSubscriptionsVisitor : ValidationASTVisitor 14 | { 15 | private ISchemaRepository schemaRepository; 16 | 17 | public SingleFieldSubscriptionsVisitor(IGraphQLSchema schema) : base(schema) 18 | { 19 | this.schemaRepository = schema.SchemaRepository; 20 | this.Errors = new List(); 21 | } 22 | 23 | public List Errors { get; private set; } 24 | 25 | public override GraphQLOperationDefinition BeginVisitOperationDefinition(GraphQLOperationDefinition definition) 26 | { 27 | if (definition.Operation == OperationType.Subscription) 28 | { 29 | if (definition.SelectionSet?.Selections?.Count() != 1) 30 | { 31 | this.Errors.Add(new GraphQLException( 32 | this.SingleFieldOnlyMessage(definition.Name?.Value), 33 | definition.SelectionSet.Selections.Skip(1).ToArray())); 34 | } 35 | } 36 | 37 | return definition; 38 | } 39 | 40 | private string SingleFieldOnlyMessage(string name) 41 | { 42 | return (string.IsNullOrWhiteSpace(name) ? "Anonymous Subscription" : $"Subscription \"{name}\"") + 43 | " must select only one top level field."; 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Validation/Rules/UniqueArguments.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Validation.Rules 2 | { 3 | using Exceptions; 4 | using Language.AST; 5 | using System.Collections.Generic; 6 | using Type; 7 | 8 | public class UniqueArguments : IValidationRule 9 | { 10 | public IEnumerable Validate(GraphQLDocument document, IGraphQLSchema schema) 11 | { 12 | var visitor = new UniqueArgumentsVisitor(schema); 13 | visitor.Visit(document); 14 | 15 | return visitor.Errors; 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Validation/Rules/UniqueArgumentsVisitor.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Validation.Rules 2 | { 3 | using Exceptions; 4 | using Language.AST; 5 | using System.Collections.Generic; 6 | using Type; 7 | 8 | public class UniqueArgumentsVisitor : ValidationASTVisitor 9 | { 10 | private Dictionary knownArgumentNames; 11 | 12 | public UniqueArgumentsVisitor(IGraphQLSchema schema) : base(schema) 13 | { 14 | this.Errors = new List(); 15 | } 16 | 17 | public List Errors { get; private set; } 18 | 19 | public override GraphQLFieldSelection BeginVisitFieldSelection(GraphQLFieldSelection selection) 20 | { 21 | this.knownArgumentNames = new Dictionary(); 22 | 23 | return base.BeginVisitFieldSelection(selection); 24 | } 25 | 26 | public override GraphQLDirective BeginVisitDirective(GraphQLDirective directive) 27 | { 28 | this.knownArgumentNames = new Dictionary(); 29 | 30 | return base.BeginVisitDirective(directive); 31 | } 32 | 33 | public override GraphQLArgument BeginVisitArgument(GraphQLArgument argument) 34 | { 35 | var argumentName = argument.Name.Value; 36 | 37 | if (this.knownArgumentNames.ContainsKey(argumentName)) 38 | this.ReportDuplicateArgumentsError(argumentName, new[] { this.knownArgumentNames[argumentName], argument.Name }); 39 | else 40 | this.knownArgumentNames.Add(argumentName, argument.Name); 41 | 42 | return base.BeginVisitArgument(argument); 43 | } 44 | 45 | private void ReportDuplicateArgumentsError(string argumentName, IEnumerable nodes) 46 | { 47 | this.Errors.Add(new GraphQLException($"There can be only one argument named \"{argumentName}\".", 48 | nodes)); 49 | } 50 | } 51 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Validation/Rules/UniqueDirectivesPerLocation.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Validation.Rules 2 | { 3 | using Exceptions; 4 | using Language.AST; 5 | using System.Collections.Generic; 6 | using Type; 7 | 8 | public class UniqueDirectivesPerLocation : IValidationRule 9 | { 10 | public IEnumerable Validate(GraphQLDocument document, IGraphQLSchema schema) 11 | { 12 | var visitor = new UniqueDirectivesPerLocationVisitor(); 13 | visitor.Visit(document); 14 | 15 | return visitor.Errors; 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Validation/Rules/UniqueDirectivesPerLocationVisitor.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Validation.Rules 2 | { 3 | using Exceptions; 4 | using Language; 5 | using Language.AST; 6 | using System.Collections.Generic; 7 | 8 | public class UniqueDirectivesPerLocationVisitor : GraphQLAstVisitor 9 | { 10 | public UniqueDirectivesPerLocationVisitor() 11 | { 12 | this.Errors = new List(); 13 | } 14 | 15 | public List Errors { get; private set; } 16 | 17 | private string DuplicateDirectiveMessage(string directiveName) 18 | { 19 | return $"The directive {directiveName} can only be used once at this location."; 20 | } 21 | 22 | public override ASTNode BeginVisitNode(ASTNode node) 23 | { 24 | var appliedDirectives = new Dictionary(); 25 | if (node is IWithDirectives) 26 | { 27 | var nodeWithDirectives = node as IWithDirectives; 28 | 29 | foreach (var directive in nodeWithDirectives.Directives) 30 | { 31 | var directiveName = directive.Name.Value; 32 | 33 | if (appliedDirectives.ContainsKey(directiveName)) 34 | { 35 | this.Errors.Add(new GraphQLException(this.DuplicateDirectiveMessage(directiveName), 36 | new[] { appliedDirectives[directiveName], directive })); 37 | } 38 | else 39 | { 40 | appliedDirectives.Add(directiveName, directive); 41 | } 42 | } 43 | } 44 | 45 | return base.BeginVisitNode(node); 46 | } 47 | } 48 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Validation/Rules/UniqueFragmentNames.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Validation.Rules 2 | { 3 | using Exceptions; 4 | using Language.AST; 5 | using System.Collections.Generic; 6 | using Type; 7 | 8 | public class UniqueFragmentNames : IValidationRule 9 | { 10 | public IEnumerable Validate(GraphQLDocument document, IGraphQLSchema schema) 11 | { 12 | var visitor = new UniqueFragmentNamesVisitor(schema); 13 | visitor.Visit(document); 14 | 15 | return visitor.Errors; 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/GraphQLCore/Validation/Rules/UniqueFragmentNamesVisitor.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Validation.Rules 2 | { 3 | using Exceptions; 4 | using Language.AST; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using Type; 8 | 9 | public class UniqueFragmentNamesVisitor : ValidationASTVisitor 10 | { 11 | private Dictionary knownFragmentNames = new Dictionary(); 12 | 13 | public UniqueFragmentNamesVisitor(IGraphQLSchema schema) : base(schema) 14 | { 15 | this.Errors = new List(); 16 | } 17 | 18 | public List Errors { get; private set; } 19 | 20 | public override GraphQLFragmentDefinition BeginVisitFragmentDefinition(GraphQLFragmentDefinition node) 21 | { 22 | var fragmentName = node.Name.Value; 23 | 24 | if (this.knownFragmentNames.ContainsKey(fragmentName)) 25 | this.Errors.Add(this.GetFragmentNameError(fragmentName, 26 | new ASTNode[] { this.knownFragmentNames[fragmentName], node.Name })); 27 | else 28 | this.knownFragmentNames.Add(node.Name.Value, node.Name); 29 | 30 | return base.BeginVisitFragmentDefinition(node); 31 | } 32 | 33 | private GraphQLException GetFragmentNameError(string variableName, IEnumerable nodes) 34 | { 35 | return new GraphQLException($"There can be only one fragment named \"{variableName}\".", nodes); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/GraphQLCore/Validation/Rules/UniqueInputFieldNames.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Validation.Rules 2 | { 3 | using Exceptions; 4 | using Language.AST; 5 | using System.Collections.Generic; 6 | using Type; 7 | 8 | public class UniqueInputFieldNames : IValidationRule 9 | { 10 | public IEnumerable Validate(GraphQLDocument document, IGraphQLSchema schema) 11 | { 12 | var visitor = new UniqueInputFieldNamesVisitor(schema); 13 | visitor.Visit(document); 14 | 15 | return visitor.Errors; 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Validation/Rules/UniqueInputFieldNamesVisitor.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Validation.Rules 2 | { 3 | using Exceptions; 4 | using Language.AST; 5 | using System.Collections.Generic; 6 | using Type; 7 | 8 | public class UniqueInputFieldNamesVisitor : ValidationASTVisitor 9 | { 10 | private Stack> knownNameStack = new Stack>(); 11 | private Dictionary knownNames = new Dictionary(); 12 | 13 | public UniqueInputFieldNamesVisitor(IGraphQLSchema schema) : base(schema) 14 | { 15 | this.Errors = new List(); 16 | } 17 | 18 | public List Errors { get; private set; } 19 | 20 | public override GraphQLObjectValue BeginVisitObjectValue(GraphQLObjectValue node) 21 | { 22 | this.knownNameStack.Push(this.knownNames); 23 | this.knownNames = new Dictionary(); 24 | 25 | return base.BeginVisitObjectValue(node); 26 | } 27 | 28 | public override GraphQLObjectValue EndVisitObjectValue(GraphQLObjectValue node) 29 | { 30 | this.knownNames = this.knownNameStack.Pop(); 31 | 32 | return base.EndVisitObjectValue(node); 33 | } 34 | 35 | public override GraphQLObjectField BeginVisitObjectField(GraphQLObjectField node) 36 | { 37 | var fieldName = node.Name.Value; 38 | 39 | if (this.knownNames.ContainsKey(fieldName)) 40 | this.Errors.Add(new GraphQLException(this.DuplicateInputFieldMessage(fieldName), 41 | new[] { this.knownNames[fieldName], node.Name })); 42 | else 43 | this.knownNames.Add(fieldName, node.Name); 44 | 45 | return base.BeginVisitObjectField(node); 46 | } 47 | 48 | private string DuplicateInputFieldMessage(string fieldName) 49 | { 50 | return $"There can be only one input field named \"{fieldName}\"."; 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Validation/Rules/UniqueOperationNames.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Validation.Rules 2 | { 3 | using Exceptions; 4 | using Language.AST; 5 | using System.Collections.Generic; 6 | using Type; 7 | 8 | public class UniqueOperationNames : IValidationRule 9 | { 10 | public IEnumerable Validate(GraphQLDocument document, IGraphQLSchema schema) 11 | { 12 | var visitor = new UniqueOperationNamesVisitor(schema); 13 | visitor.Visit(document); 14 | 15 | return visitor.Errors; 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Validation/Rules/UniqueOperationNamesVisitor.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Validation.Rules 2 | { 3 | using Exceptions; 4 | using Language.AST; 5 | using System.Collections.Generic; 6 | using Type; 7 | 8 | public class UniqueOperationNamesVisitor : ValidationASTVisitor 9 | { 10 | private Dictionary knownOperationNames = new Dictionary(); 11 | 12 | public UniqueOperationNamesVisitor(IGraphQLSchema schema) : base(schema) 13 | { 14 | this.Errors = new List(); 15 | } 16 | 17 | public List Errors { get; private set; } 18 | 19 | public override GraphQLOperationDefinition BeginVisitOperationDefinition(GraphQLOperationDefinition definition) 20 | { 21 | var operationName = definition?.Name?.Value; 22 | 23 | if (!string.IsNullOrWhiteSpace(operationName)) 24 | { 25 | if (this.knownOperationNames.ContainsKey(operationName)) 26 | this.ReportOperationNameError(operationName, new[] { this.knownOperationNames[operationName], definition.Name }); 27 | else 28 | this.knownOperationNames.Add(operationName, definition.Name); 29 | } 30 | 31 | return definition; 32 | } 33 | 34 | private void ReportOperationNameError(string operationName, IEnumerable nodes) 35 | { 36 | this.Errors.Add(new GraphQLException($"There can only be one operation named \"{operationName}\".", nodes)); 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Validation/Rules/UniqueVariableNames.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Validation.Rules 2 | { 3 | using Exceptions; 4 | using Language.AST; 5 | using System.Collections.Generic; 6 | using Type; 7 | 8 | public class UniqueVariableNames : IValidationRule 9 | { 10 | public IEnumerable Validate(GraphQLDocument document, IGraphQLSchema schema) 11 | { 12 | var visitor = new UniqueVariableNamesVisitor(schema); 13 | visitor.Visit(document); 14 | 15 | return visitor.Errors; 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Validation/Rules/UniqueVariableNamesVisitor.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Validation.Rules 2 | { 3 | using Exceptions; 4 | using Language.AST; 5 | using System.Collections.Generic; 6 | using Type; 7 | 8 | public class UniqueVariableNamesVisitor : ValidationASTVisitor 9 | { 10 | private Dictionary knownVariableNames; 11 | 12 | public UniqueVariableNamesVisitor(IGraphQLSchema schema) : base(schema) 13 | { 14 | this.Errors = new List(); 15 | } 16 | 17 | public List Errors { get; private set; } 18 | 19 | public override GraphQLOperationDefinition BeginVisitOperationDefinition(GraphQLOperationDefinition definition) 20 | { 21 | this.knownVariableNames = new Dictionary(); 22 | 23 | return base.BeginVisitOperationDefinition(definition); 24 | } 25 | 26 | public override GraphQLVariableDefinition BeginVisitVariableDefinition(GraphQLVariableDefinition node) 27 | { 28 | var variableName = node.Variable.Name.Value; 29 | 30 | if (this.knownVariableNames.ContainsKey(variableName)) 31 | this.ReportVariableNameError(variableName, 32 | new[] { this.knownVariableNames[variableName], node.Variable.Name }); 33 | else 34 | this.knownVariableNames.Add(variableName, node.Variable.Name); 35 | 36 | return base.BeginVisitVariableDefinition(node); 37 | } 38 | 39 | private void ReportVariableNameError(string variableName, IEnumerable nodes) 40 | { 41 | this.Errors.Add(new GraphQLException($"There can be only one variable named \"{variableName}\".", nodes)); 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Validation/Rules/VariablesAreInputTypes.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Validation.Rules 2 | { 3 | using Exceptions; 4 | using Language.AST; 5 | using System.Collections.Generic; 6 | using Type; 7 | 8 | public class VariablesAreInputTypes : IValidationRule 9 | { 10 | public IEnumerable Validate(GraphQLDocument document, IGraphQLSchema schema) 11 | { 12 | var visitor = new VariablesAreInputTypesVisitor(schema); 13 | visitor.Visit(document); 14 | 15 | return visitor.Errors; 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Validation/Rules/VariablesAreInputTypesVisitor.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Validation.Rules 2 | { 3 | using Abstract; 4 | using Exceptions; 5 | using Language.AST; 6 | using System.Collections.Generic; 7 | using Type; 8 | 9 | public class VariablesAreInputTypesVisitor : VariableValidationVisitor 10 | { 11 | public VariablesAreInputTypesVisitor(IGraphQLSchema schema) : base(schema) 12 | { 13 | this.Errors = new List(); 14 | } 15 | 16 | public List Errors { get; private set; } 17 | 18 | public override GraphQLVariableDefinition BeginVisitVariableDefinition(GraphQLVariableDefinition variableDefinition) 19 | { 20 | var variableName = variableDefinition.Variable.Name.Value; 21 | var inputType = this.GetOutputType(variableDefinition.Type); 22 | 23 | if (inputType != null) 24 | this.Errors.Add(new GraphQLException($"Variable \"${variableName}\" cannot be non-input type \"{variableDefinition.Type}\".", 25 | new[] { variableDefinition.Type })); 26 | 27 | return variableDefinition; 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Validation/Rules/VariablesInAllowedPositions.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Validation.Rules 2 | { 3 | using Exceptions; 4 | using Language.AST; 5 | using System.Collections.Generic; 6 | using Type; 7 | 8 | public class VariablesInAllowedPositions : IValidationRule 9 | { 10 | public IEnumerable Validate(GraphQLDocument document, IGraphQLSchema schema) 11 | { 12 | var visitor = new VariablesInAllowedPositionsVisitor(schema); 13 | visitor.Visit(document); 14 | 15 | return visitor.Errors; 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Validation/ValidationContext.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Validation 2 | { 3 | using Exceptions; 4 | using Language.AST; 5 | using Rules; 6 | using System.Collections.Generic; 7 | using Type; 8 | 9 | public class ValidationContext 10 | { 11 | public GraphQLException[] Validate( 12 | GraphQLDocument document, 13 | IGraphQLSchema schema, 14 | IValidationRule[] validationRules) 15 | { 16 | var errors = new List(); 17 | 18 | foreach (var rule in validationRules) 19 | errors.AddRange(rule.Validate(document, schema)); 20 | 21 | return errors.ToArray(); 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /src/GraphQLCore/Validation/VariableUsage.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Validation 2 | { 3 | using Language.AST; 4 | using Type; 5 | 6 | public class VariableUsage 7 | { 8 | public GraphQLBaseType ArgumentType { get; set; } 9 | public GraphQLVariable Variable { get; set; } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/GraphQLCore/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1.0.0-beta-*", 3 | 4 | "dependencies": { 5 | "NETStandard.Library": "1.6.0", 6 | "System.Linq.Expressions": "4.1.0", 7 | "System.Dynamic.Runtime": "4.0.11", 8 | "System.Runtime": "4.1.0", 9 | "System.Collections": "4.0.11", 10 | "Microsoft.CSharp": "4.0.1", 11 | "StyleCop.Analyzers": { 12 | "version": "1.0.0", 13 | "type": "build" 14 | }, 15 | "System.Linq": "4.1.0", 16 | "Newtonsoft.Json": "10.0.2" 17 | }, 18 | "buildOptions": { 19 | "additionalArguments": [ "/ruleset:ruleset.ruleset", "/additionalfile:stylecop.json" ] 20 | }, 21 | "frameworks": { 22 | "netstandard1.6": { 23 | "imports": "dnxcore50" 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /src/GraphQLCore/stylecop.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json", 3 | "settings": { 4 | "documentationRules": { 5 | "fileNamingConvention" : "metadata" 6 | }, 7 | "readabilityRules": { 8 | }, 9 | "orderingRules": { 10 | "usingDirectivesPlacement": "preserve", 11 | "systemUsingDirectivesFirst": false 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /test/GraphQLCore.Tests/Execution/VariableResolverTests.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Tests.Execution 2 | { 3 | using GraphQLCore.Execution; 4 | using GraphQLCore.Language.AST; 5 | using GraphQLCore.Type.Translation; 6 | using NSubstitute; 7 | using NUnit.Framework; 8 | using System.Collections.Generic; 9 | using System.Dynamic; 10 | 11 | public class VariableResolverTests 12 | { 13 | private GraphQLNamedType intNamedType; 14 | private ISchemaRepository schemaRepository; 15 | private VariableResolver variableResolver; 16 | 17 | [Test] 18 | public void GetValue_ScalarIntVariable_CallsTypeTranslatorWithCorrectType() 19 | { 20 | object value = this.variableResolver.GetValue("scalarIntVariable"); 21 | 22 | this.schemaRepository.Received().GetSchemaInputTypeByName(this.intNamedType.Name.Value); 23 | } 24 | 25 | [SetUp] 26 | public void SetUp() 27 | { 28 | dynamic variables = new ExpandoObject(); 29 | variables.scalarIntVariable = "1"; 30 | 31 | this.intNamedType = GetIntNamedType(); 32 | this.schemaRepository = Substitute.For(); 33 | this.variableResolver = new VariableResolver(variables, this.schemaRepository, this.GetVariableDefinitions()); 34 | } 35 | 36 | private static GraphQLNamedType GetIntNamedType() 37 | { 38 | return new GraphQLNamedType() 39 | { 40 | Name = new GraphQLName() 41 | { 42 | Value = "Int" 43 | }, 44 | }; 45 | } 46 | 47 | private IEnumerable GetVariableDefinitions() 48 | { 49 | var definitions = new List(); 50 | 51 | definitions.Add(new GraphQLVariableDefinition() 52 | { 53 | Type = this.intNamedType, 54 | Variable = new GraphQLVariable() 55 | { 56 | Name = new GraphQLName() 57 | { 58 | Value = "scalarIntVariable" 59 | } 60 | } 61 | }); 62 | 63 | return definitions; 64 | } 65 | } 66 | } -------------------------------------------------------------------------------- /test/GraphQLCore.Tests/GraphQLCore.Tests.v3.ncrunchproject: -------------------------------------------------------------------------------- 1 |  2 | 3 | True 4 | 5 | -------------------------------------------------------------------------------- /test/GraphQLCore.Tests/GraphQLCore.Tests.xproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 14.0 5 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 6 | 7 | 8 | 9 | 6b63bcc0-2884-4515-9a92-e408acf4c98e 10 | GraphQLCore.Tests 11 | .\obj 12 | .\bin\ 13 | v4.5.2 14 | 15 | 16 | 2.0 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /test/GraphQLCore.Tests/Language/SourceTests.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Tests.Language 2 | { 3 | using GraphQLCore.Language; 4 | using NUnit.Framework; 5 | 6 | [TestFixture] 7 | public class SourceTests 8 | { 9 | [Test] 10 | public void CreateSourceFromString_BodyEqualsToProvidedSource() 11 | { 12 | var source = new Source("somesrc"); 13 | 14 | Assert.AreEqual("somesrc", source.Body); 15 | } 16 | 17 | [Test] 18 | public void CreateSourceFromString_SourceNameEqualsToGraphQL() 19 | { 20 | var source = new Source("somesrc"); 21 | 22 | Assert.AreEqual("GraphQL", source.Name); 23 | } 24 | 25 | [Test] 26 | public void CreateSourceFromStringWithName_SourceNameEqualsToProvidedName() 27 | { 28 | var source = new Source("somesrc", "somename"); 29 | 30 | Assert.AreEqual("somename", source.Name); 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /test/GraphQLCore.Tests/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyConfiguration("")] 8 | [assembly: AssemblyCompany("")] 9 | [assembly: AssemblyProduct("GraphQLCore.Tests")] 10 | [assembly: AssemblyTrademark("")] 11 | 12 | // Setting ComVisible to false makes the types in this assembly not visible 13 | // to COM components. If you need to access a type in this assembly from 14 | // COM, set the ComVisible attribute to true on that type. 15 | [assembly: ComVisible(false)] 16 | 17 | // The following GUID is for the ID of the typelib if this project is exposed to COM 18 | [assembly: Guid("6b63bcc0-2884-4515-9a92-e408acf4c98e")] -------------------------------------------------------------------------------- /test/GraphQLCore.Tests/Type/IDTests.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Tests.Type 2 | { 3 | using GraphQLCore.Type.Scalar; 4 | using NUnit.Framework; 5 | 6 | [TestFixture] 7 | public class IDTests 8 | { 9 | [Test] 10 | public void ID_FromStringToString_ReturnsCorrectValue() 11 | { 12 | ID id = "123"; 13 | 14 | string idToString = id; 15 | Assert.AreEqual("123", idToString); 16 | } 17 | 18 | [Test] 19 | public void ID_FromIntToString_ReturnsCorrectValue() 20 | { 21 | ID id = 123; 22 | 23 | string idToString = id; 24 | Assert.AreEqual("123", idToString); 25 | } 26 | 27 | [Test] 28 | public void ID_FromInt64ToString_ReturnsCorrectValue() 29 | { 30 | ID id = 123456789012345; 31 | 32 | string idToString = id; 33 | Assert.AreEqual("123456789012345", idToString); 34 | } 35 | 36 | [Test] 37 | public void ID_EqualsIDWithSameValue() 38 | { 39 | ID id1 = 123; 40 | ID id2 = "123"; 41 | 42 | Assert.AreEqual(id1, id2); 43 | Assert.AreEqual(id2, id1); 44 | } 45 | 46 | [Test] 47 | public void ID_EqualsStringWithSameValue() 48 | { 49 | ID id = "123"; 50 | 51 | Assert.IsTrue(id == "123"); 52 | Assert.IsTrue("123" == id); 53 | } 54 | 55 | [Test] 56 | public void ID_DoesNotEqualIDWithDifferentValue() 57 | { 58 | ID id1 = 123; 59 | ID id2 = "456"; 60 | 61 | Assert.AreNotEqual(id1, id2); 62 | } 63 | 64 | [Test] 65 | public void ID_ToString_ReturnsValue() 66 | { 67 | ID id = "123"; 68 | 69 | Assert.AreEqual("123", id.ToString()); 70 | } 71 | 72 | [Test] 73 | public void ID_ReturnsNullWhenUnassigned() 74 | { 75 | ID id = null; 76 | 77 | Assert.IsNull((string)id); 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /test/GraphQLCore.Tests/Type/Scalars/GraphQLIntTests.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Tests.Type 2 | { 3 | using GraphQLCore.Type.Scalar; 4 | using NUnit.Framework; 5 | 6 | [TestFixture] 7 | public class GraphQLIntTests 8 | { 9 | private GraphQLInt type; 10 | 11 | [Test] 12 | public void Description_HasCorrectDescription() 13 | { 14 | Assert.AreEqual("The `Int` scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1.", 15 | type.Description); 16 | } 17 | 18 | [Test] 19 | public void Name_HasCorrectName() 20 | { 21 | Assert.AreEqual("Int", type.Name); 22 | } 23 | 24 | [SetUp] 25 | public void SetUp() 26 | { 27 | this.type = new GraphQLInt(); 28 | } 29 | 30 | [Test] 31 | public void ToString_ReturnsName() 32 | { 33 | Assert.AreEqual("Int", type.ToString()); 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /test/GraphQLCore.Tests/Utils/ReflectionUtilsTests.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Tests.Utils 2 | { 3 | using GraphQLCore.Type; 4 | using GraphQLCore.Utils; 5 | using NUnit.Framework; 6 | using System; 7 | using System.Collections.Generic; 8 | 9 | [TestFixture] 10 | public class ReflectionUtilsTests 11 | { 12 | [Test] 13 | public void InputVariable_TypeInt32_ReturnsCorrectly() 14 | { 15 | Int64 inputVariable = 123456789; 16 | var result = ReflectionUtilities.ChangeValueType(inputVariable, typeof(Int32)); 17 | 18 | Assert.AreEqual(inputVariable, result); 19 | } 20 | 21 | [Test] 22 | public void InputVariable_TypeInt32TooLarge_ReturnsNull() 23 | { 24 | Int64 inputVariable = Int64.MaxValue; 25 | var result = ReflectionUtilities.ChangeValueType(inputVariable, typeof(Int32)); 26 | 27 | Assert.IsNull(result); 28 | } 29 | 30 | [Test] 31 | public void ChangeValueType_NonEnumerableToEnumerable_ReturnsNull() 32 | { 33 | var result = ReflectionUtilities.ChangeValueType(1, typeof(int[])); 34 | var result2 = ReflectionUtilities.ChangeValueType("test", typeof(List)); 35 | 36 | Assert.IsNull(result); 37 | Assert.IsNull(result2); 38 | } 39 | 40 | [Test] 41 | public void CreateNonNullableType_ReturnsCorrectType() 42 | { 43 | var result = ReflectionUtilities.CreateNonNullableType(typeof(string)); 44 | var result2 = ReflectionUtilities.CreateNonNullableType(typeof(int)); 45 | 46 | Assert.AreEqual(typeof(NonNullable), result); 47 | Assert.AreEqual(typeof(int), result2); 48 | } 49 | 50 | [Test] 51 | public void IsNullable_ReturnsCorrectValue() 52 | { 53 | var result = ReflectionUtilities.IsNullable(typeof(int?)); 54 | var result2 = ReflectionUtilities.IsNullable(typeof(int)); 55 | 56 | Assert.IsTrue(result); 57 | Assert.IsFalse(result2); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /test/GraphQLCore.Tests/Validation/ErrorAssert.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Tests.Validation 2 | { 3 | using System.Collections; 4 | using GraphQLCore.Exceptions; 5 | using GraphQLCore.Language; 6 | using NUnit.Framework; 7 | using System.Linq; 8 | 9 | public static class ErrorAssert 10 | { 11 | public static void AreEqual(string message, GraphQLException actual, int line, int column, IEnumerable path = null) 12 | { 13 | Assert.AreEqual(message, actual.Message); 14 | 15 | var singleLocation = actual.Locations.Single(); 16 | AssertLocation(line, column, singleLocation); 17 | 18 | if (path != null) 19 | AssertPath(path, actual.Path); 20 | } 21 | 22 | public static void StartsWith(string message, GraphQLException actual, int line, int column, IEnumerable path = null) 23 | { 24 | Assert.IsTrue(actual.Message.StartsWith(message)); 25 | 26 | var singleLocation = actual.Locations.Single(); 27 | AssertLocation(line, column, singleLocation); 28 | } 29 | 30 | public static void AreEqual(string message, GraphQLException actual, params int[][] locations) 31 | { 32 | Assert.AreEqual(message, actual.Message); 33 | 34 | if (locations != null) 35 | AssertLocations(locations, actual.Locations); 36 | } 37 | 38 | private static void AssertLocation(int line, int column, Location actual) 39 | { 40 | Assert.AreEqual(line, actual.Line); 41 | Assert.AreEqual(column, actual.Column); 42 | } 43 | 44 | private static void AssertLocations(int[][] locations, Location[] actual) 45 | { 46 | Assert.AreEqual(locations, actual.Select(e => new[] { e.Line, e.Column }).ToArray()); 47 | } 48 | 49 | private static void AssertPath(IEnumerable expected, IEnumerable actual) 50 | { 51 | foreach (var element in actual) 52 | Assert.IsTrue(element is string || element is int); 53 | 54 | Assert.AreEqual(expected, actual); 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /test/GraphQLCore.Tests/Validation/Rules/KnownTypeNamesTests.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Tests.Validation.Rules 2 | { 3 | using NUnit.Framework; 4 | using System.Linq; 5 | 6 | [TestFixture] 7 | public class KnownTypeNamesTests : ValidationTestBase 8 | { 9 | [Test] 10 | public void UnknownTypeNamesAreInvalid() 11 | { 12 | var errors = this.Validate(@" 13 | query Foo($var: JumbledUpLetters) { 14 | complicatedArgs { 15 | intArgField 16 | complicatedObjectArgField { ... on Badger { name }, ...complFields } 17 | } 18 | } 19 | fragment complFields on ComplicatedObjectTypeee { 20 | booleanField 21 | } 22 | "); 23 | 24 | var jumbledUpLettersError = errors.ElementAt(0); 25 | var badgerError = errors.ElementAt(1); 26 | var complicatedObjectArgFieldddddddError = errors.ElementAt(2); 27 | 28 | ErrorAssert.StartsWith("Unknown type \"JumbledUpLetters\".", 29 | jumbledUpLettersError, 2, 31); 30 | ErrorAssert.StartsWith("Unknown type \"Badger\".", 31 | badgerError, 5, 54); 32 | ErrorAssert.StartsWith("Unknown type \"ComplicatedObjectTypeee\". Did you mean \"ComplicatedObjectType\"", 33 | complicatedObjectArgFieldddddddError, 8, 39); 34 | } 35 | 36 | [Test] 37 | public void IgnoresTypeDefinitions() 38 | { 39 | var errors = this.Validate(@" 40 | type NotInTheSchema { 41 | field: FooBar 42 | } 43 | interface FooBar { 44 | field: NotInTheSchema 45 | } 46 | union U = A | B 47 | input Blob { 48 | field: UnknownType 49 | } 50 | query Foo($var: NotInTheSchema) { 51 | user(id: $var) { 52 | id 53 | } 54 | }"); 55 | 56 | ErrorAssert.AreEqual("Unknown type \"NotInTheSchema\".", errors.Single(), 12, 33); 57 | } 58 | } 59 | } -------------------------------------------------------------------------------- /test/GraphQLCore.Tests/Validation/Rules/LoneAnonymousOperationTests.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Tests.Validation.Rules 2 | { 3 | using NUnit.Framework; 4 | using System.Linq; 5 | 6 | public class LoneAnonymousOperationTests : ValidationTestBase 7 | { 8 | [Test] 9 | public void AnonymousOperationWithFragment() 10 | { 11 | var errors = this.Validate(@" 12 | { 13 | ...Foo 14 | } 15 | fragment Foo on QueryRoot { 16 | field { foo } 17 | }"); 18 | 19 | Assert.IsEmpty(errors); 20 | } 21 | 22 | [Test] 23 | public void MultipleAnonymousOperations() 24 | { 25 | var errors = this.Validate(@" 26 | { 27 | field { foo } 28 | } 29 | { 30 | field { foo } 31 | }"); 32 | 33 | Assert.AreEqual(2, errors.Count()); 34 | 35 | ErrorAssert.AreEqual("This anonymous operation must be the only defined operation.", errors.ElementAt(0), 2, 13); 36 | ErrorAssert.AreEqual("This anonymous operation must be the only defined operation.", errors.ElementAt(1), 5, 13); 37 | } 38 | 39 | [Test] 40 | public void AnonymousOperationWithMutation() 41 | { 42 | var errors = this.Validate(@" 43 | { 44 | field { foo } 45 | } 46 | mutation Foo { 47 | field 48 | }"); 49 | 50 | ErrorAssert.AreEqual("This anonymous operation must be the only defined operation.", errors.Single(), 2, 13); 51 | } 52 | 53 | [Test] 54 | public void AnonymousOperationWithSubscription() 55 | { 56 | var errors = this.Validate(@" 57 | { 58 | field { foo } 59 | } 60 | subscription Foo { 61 | field { foo } 62 | }"); 63 | 64 | ErrorAssert.AreEqual("This anonymous operation must be the only defined operation.", errors.Single(), 2, 13); 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /test/GraphQLCore.Tests/Validation/Rules/UniqueFragmentNamesTest.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Tests.Validation.Rules 2 | { 3 | using NUnit.Framework; 4 | using System.Linq; 5 | 6 | [TestFixture] 7 | public class UniqueFragmentNamesTest : ValidationTestBase 8 | { 9 | [Test] 10 | public void UniqueFragmentNames() 11 | { 12 | var errors = this.Validate(@" 13 | fragment Foo on SimpleObjectType { 14 | booleanField 15 | } 16 | fragment Bar on SimpleObjectType { 17 | booleanField 18 | } 19 | "); 20 | Assert.IsEmpty(errors); 21 | } 22 | 23 | [Test] 24 | public void DuplicateFragmentNames() 25 | { 26 | var errors = this.Validate(@" 27 | fragment Foo on SimpleObjectType { 28 | booleanField 29 | } 30 | fragment Foo on SimpleObjectType { 31 | booleanField 32 | } 33 | "); 34 | 35 | ErrorAssert.AreEqual("There can be only one fragment named \"Foo\".", 36 | errors.Single(), new[] { 2, 26 }, new[] { 5, 26 }); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /test/GraphQLCore.Tests/Validation/Rules/UniqueVariableNamesTests.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Tests.Validation.Rules 2 | { 3 | using NUnit.Framework; 4 | using System.Linq; 5 | 6 | [TestFixture] 7 | public class UniqueVariableNamesTests : ValidationTestBase 8 | { 9 | [Test] 10 | public void UniqueVariableNames() 11 | { 12 | var errors = this.Validate(@" 13 | query A($x: Int, $y: String) { __typename } 14 | query B($x: String, $y: Int) { __typename }"); 15 | 16 | Assert.IsEmpty(errors); 17 | } 18 | 19 | [Test] 20 | public void DuplicateVariableNames() 21 | { 22 | var errors = this.Validate(@" 23 | query A($x: Int, $x: Int, $x: String) { __typename } 24 | query B($x: String, $x: Int) { __typename } 25 | query C($x: Int, $x: Int) { __typename }"); 26 | 27 | Assert.AreEqual(4, errors.Count()); 28 | 29 | ErrorAssert.AreEqual("There can be only one variable named \"x\".", 30 | errors.ElementAt(0), new[] { 2, 22 }, new[] { 2, 31 }); 31 | ErrorAssert.AreEqual("There can be only one variable named \"x\".", 32 | errors.ElementAt(1), new[] { 2, 22 }, new[] { 2, 40 }); 33 | ErrorAssert.AreEqual("There can be only one variable named \"x\".", 34 | errors.ElementAt(2), new[] { 3, 22 }, new[] { 3, 34 }); 35 | ErrorAssert.AreEqual("There can be only one variable named \"x\".", 36 | errors.ElementAt(3), new[] { 4, 22 }, new[] { 4, 31 }); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /test/GraphQLCore.Tests/Validation/Rules/VariablesAreInputTypesTests.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Tests.Validation.Rules 2 | { 3 | using GraphQLCore.Exceptions; 4 | using GraphQLCore.Validation.Rules; 5 | using NUnit.Framework; 6 | using System.Linq; 7 | 8 | [TestFixture] 9 | public class VariablesAreInputTypesTests : ValidationTestBase 10 | { 11 | [Test] 12 | public void InputTypesAreValid() 13 | { 14 | var errors = Validate(@" 15 | query Foo($a: String, $b: [Boolean!]!, $c: ComplicatedInputObjectType) { 16 | field(a: $a, b: $b, c: $c) { foo } 17 | } 18 | "); 19 | 20 | Assert.IsEmpty(errors); 21 | } 22 | 23 | [Test] 24 | public void OutputTypesAreInvalid() 25 | { 26 | var errors = Validate(@" 27 | query Foo($a: ComplicatedObjectType, $b: [[ComplicatedObjectType!]]!, $c: ComplicatedInterfaceType) { 28 | field(a: $a, b: $b, c: $c) { foo } 29 | } 30 | "); 31 | 32 | Assert.AreEqual(3, errors.Count()); 33 | 34 | ErrorAssert.AreEqual("Variable \"$a\" cannot be non-input type \"ComplicatedObjectType\".", 35 | errors.ElementAt(0), 2, 27); 36 | ErrorAssert.AreEqual("Variable \"$b\" cannot be non-input type \"[[ComplicatedObjectType!]]!\".", 37 | errors.ElementAt(1), 2, 54); 38 | ErrorAssert.AreEqual("Variable \"$c\" cannot be non-input type \"ComplicatedInterfaceType\".", 39 | errors.ElementAt(2), 2, 87); 40 | } 41 | 42 | protected override GraphQLException[] Validate(string body) 43 | { 44 | return validationContext.Validate( 45 | GetAst(body), 46 | this.validationTestSchema, 47 | new IValidationRule[] 48 | { 49 | new VariablesAreInputTypes(), 50 | }); 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /test/GraphQLCore.Tests/Validation/ValidationTestBase.cs: -------------------------------------------------------------------------------- 1 | namespace GraphQLCore.Tests.Validation 2 | { 3 | using GraphQLCore.Exceptions; 4 | using GraphQLCore.Language; 5 | using GraphQLCore.Language.AST; 6 | using GraphQLCore.Validation; 7 | using GraphQLCore.Validation.Rules; 8 | using NUnit.Framework; 9 | using Schemas; 10 | 11 | public class ValidationTestBase 12 | { 13 | protected ValidationContext validationContext; 14 | protected TestSchema validationTestSchema; 15 | 16 | [SetUp] 17 | public void SetUp() 18 | { 19 | this.validationTestSchema = new TestSchema(); 20 | this.validationContext = new ValidationContext(); 21 | } 22 | 23 | protected static GraphQLDocument GetAst(string body) 24 | { 25 | return new Parser(new Lexer()).Parse(new Source(body)); 26 | } 27 | 28 | protected virtual GraphQLException[] Validate(string body) 29 | { 30 | return validationContext.Validate( 31 | GetAst(body), 32 | this.validationTestSchema, 33 | new IValidationRule[] 34 | { 35 | new NoUndefinedVariables(), 36 | new DefaultValuesOfCorrectType(), 37 | new VariablesInAllowedPositions(), 38 | new LoneAnonymousOperation(), 39 | new UniqueInputFieldNames(), 40 | new UniqueArguments(), 41 | new UniqueVariableNames(), 42 | new UniqueOperationNames(), 43 | new UniqueFragmentNames(), 44 | new KnownTypeNames(), 45 | new PossibleFragmentSpreads(), 46 | new VariablesAreInputTypes(), 47 | new ProvidedNonNullArguments(), 48 | new ScalarLeafs(), 49 | new ArgumentsOfCorrectType(), 50 | new KnownDirectives(), 51 | new FragmentsOnCompositeTypes(), 52 | new UniqueDirectivesPerLocation(), 53 | new OverlappingFieldsCanBeMerged() 54 | }); 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /test/GraphQLCore.Tests/coverage.cmd: -------------------------------------------------------------------------------- 1 | %USERPROFILE%\AppData\Local\Apps\OpenCover\OpenCover.Console.exe -oldstyle -target:"C:\Program Files\dotnet\dotnet.exe" -targetargs:"test" -output:coverage.xml -register:user 2 | %USERPROFILE%\.nuget\packages\ReportGenerator\2.4.5\tools\ReportGenerator.exe -reports:coverage.xml -targetdir:coverage -------------------------------------------------------------------------------- /test/GraphQLCore.Tests/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1.0.0-*", 3 | 4 | "dependencies": { 5 | "NETStandard.Library": "1.6.0", 6 | "NSubstitute": "2.0.0-*", 7 | "NUnit": "3.4.0", 8 | "dotnet-test-nunit": "3.4.0-beta-1", 9 | "System.Diagnostics.TraceSource": "4.0.0", 10 | "System.Linq": "4.1.0", 11 | "ReportGenerator": "2.4.5", 12 | "GraphQLCore": "1.0.0-*" 13 | }, 14 | "frameworks": { 15 | "netcoreapp1.0": { 16 | "dependencies": { 17 | "Microsoft.NETCore.App": { 18 | "type": "platform", 19 | "version": "1.0.0" 20 | } 21 | }, 22 | "imports": ["dnxcore50", "portable-net45+win8"] 23 | } 24 | }, 25 | "tools": { 26 | "Microsoft.DotNet.Watcher.Tools": "1.0.0-preview2-final" 27 | }, 28 | "testRunner": "nunit" 29 | } -------------------------------------------------------------------------------- /test/GraphQLCore.Tests/watch.cmd: -------------------------------------------------------------------------------- 1 | dotnet watch --command test -- 2 | --------------------------------------------------------------------------------